protected function validateObject(&$value, array $field, Validation $validation) {
        if (!is_array($value) || isset($value[0])) {
            return false;
        } elseif (isset($field['properties'])) {
            $path = array_select(['path', 'name'], $field);
            // Validate the data against the internal schema.
            $this->isValidInternal($value, $field['properties'], $validation, $path.'.');
        }
        return true;
    }

Validate an object.

@param mixed &$value The value to validate.
@param array $field The field definition.
@param Validation $validation The validation results to add.
@return bool Returns true if {@link $value} is valid or false otherwise.


protected function validateRequired(&$value, array $field, Validation $validation) {
        $required = val('required', $field, false);
        $type = $field['type'];

        if ($value === '' || $value === null) {
            if (!$required) {
                $value = null;
                return true;
            }

            switch ($type) {
                case 'boolean':
                    $value = false;
                    return true;
                case 'string':
                    if (val('minLength', $field, 1) == 0) {
                        $value = '';
                        return true;
                    }
            }
            $validation->addError('missing_field', $field);
            return false;
        }
        return null;
    }

protected function validateRequired ( & $ value , array $ field , Validation $ validation ) { $ required = val ( 'required' , $ field , false ) ; $ type = $ field [ 'type' ] ; if ( $ value === '' || $ value === null ) { if ( ! $ required ) { $ value = null ; return true ; } switch ( $ type ) { case 'boolean' : $ value = false ; return true ; case 'string' : if ( val ( 'minLength' , $ field , 1 ) == 0 ) { $ value = '' ; return true ; } } $ validation -> addError ( 'missing_field' , $ field ) ; return false ; } return null ; }

Validate a required field.

@param mixed &$value The field value.
@param array $field The field definition.
@param Validation $validation A {@link Validation} object to collect errors.
@return bool|null Returns one of the following:
- null: The field is not required.
- true: The field is required and {@link $value} is not empty.
- false: The field is required and {@link $value} is empty.


protected function validateString(&$value, array $field, Validation $validation) {
        if (is_string($value)) {
            $validType = true;
        } elseif (is_numeric($value)) {
            $value = (string)$value;
            $validType = true;
        } else {
            $validType = false;
        }
        return $validType;
    }

protected function validateString ( & $ value , array $ field , Validation $ validation ) { if ( is_string ( $ value ) ) { $ validType = true ; } elseif ( is_numeric ( $ value ) ) { $ value = ( string ) $ value ; $ validType = true ; } else { $ validType = false ; } return $ validType ; }

Validate a string.

@param mixed &$value The value to validate.
@param array $field The field definition.
@param Validation $validation The validation results to add.
@return bool Returns true if {@link $value} is valid or false otherwise.


protected function validateTimestamp(&$value, array $field, Validation $validation) {
        $validType = true;
        if (is_numeric($value)) {
            $value = (int)$value;
        } elseif (is_string($value) && $ts = strtotime($value)) {
            $value = $ts;
        } else {
            $validType = false;
        }
        return $validType;
    }

protected function validateTimestamp ( & $ value , array $ field , Validation $ validation ) { $ validType = true ; if ( is_numeric ( $ value ) ) { $ value = ( int ) $ value ; } elseif ( is_string ( $ value ) && $ ts = strtotime ( $ value ) ) { $ value = $ ts ; } else { $ validType = false ; } return $ validType ; }

Validate a unix timestamp.

@param mixed &$value The value to validate.
@param array $field The field definition.
@param Validation $validation The validation results to add.
@return bool Returns true if {@link $value} is valid or false otherwise.


public static function all($addon_key = null, $key = null) {
        if (self::$all === null) {
            self::$all = static::cacheGet('addons-all', array(get_class(), 'scanAddons'));
        }

        // The array should be built now return the addon.
        if ($addon_key === null) {
            return self::$all;
        } else {
            $addon = val(strtolower($addon_key), self::$all);
            if ($addon && $key) {
                return val($key, $addon);
            } elseif ($addon) {
                return $addon;
            } else {
                return null;
            }
        }
    }

Get all of the available addons or a single addon from the available list.

@param string $addon_key If you supply an addon key then only that addon will be returned.
@param string $key Supply one of the Addons::K_* constants to get a specific key from the addon.
@return array Returns the addon with the given key or all available addons if no key is passed.

Get all of the available addons or a single addon from the available list .


public static function bootstrap($enabled_addons = null) {
        // Load the addons from the config if they aren't passed in.
        if (!is_array($enabled_addons)) {
            $enabled_addons = config('addons', array());
        }
        // Reformat the enabled array into the form: array('addon_key' => 'addon_key')
        $enabled_keys = array_keys(array_change_key_case(array_filter($enabled_addons)));
        $enabled_keys = array_combine($enabled_keys, $enabled_keys);
        self::$enabledKeys = $enabled_keys;
        self::$classMap = null; // invalidate so it will rebuild

        // Enable the addon autoloader.
        spl_autoload_register(array(get_class(), 'autoload'), true, true);

        // Bind all of the addon plugin events now.
        foreach (self::enabled() as $addon) {
            if (!isset($addon[self::K_CLASSES])) {
                continue;
            }

            foreach ($addon[self::K_CLASSES] as $class_name => $class_path) {
                if (str_ends($class_name, 'plugin')) {
                    Event::bindClass($class_name);
                } elseif (str_ends($class_name, 'hooks')) {
                    // Vanilla 2 used hooks files for themes and applications.
                    $basename = ucfirst(rtrim_substr($class_name, 'hooks'));
                    deprecated($basename.'Hooks', $basename.'Plugin');
                    Event::bindClass($class_name);
                }
            }
        }

        Event::bind('bootstrap', function () {
            // Start each of the enabled addons.
            foreach (self::enabled() as $key => $value) {
                static::startAddon($key);
            }
        });
    }

Start up the addon framework.

@param array $enabled_addons An array of enabled addons.


protected static function cacheGet($key, callable $cache_cb) {
        // Salt the cache with the root path so that it will invalidate if the app is moved.
        $salt = substr(md5(static::baseDir()), 0, 10);

        $cache_path = PATH_ROOT."/cache/$key-$salt.json.php";
        if (file_exists($cache_path)) {
            $result = array_load($cache_path);
            return $result;
        } else {
            $result = $cache_cb();
            array_save($result, $cache_path);
        }
        return $result;
    }

Get the cached file or hydrate the cache with a callback.

@param string $key The cache key to get.
@param callable $cache_cb The function to run when hydrating the cache.
@return array Returns the cached array.

Get the cached file or hydrate the cache with a callback .


public static function classMap($classname = null) {
        if (self::$classMap === null) {
            // Loop through the enabled addons and grab their classes.
            $class_map = array();
            foreach (static::enabled() as $addon) {
                if (isset($addon[self::K_CLASSES])) {
                    $class_map = array_replace($class_map, $addon[self::K_CLASSES]);
                }
            }
            self::$classMap = $class_map;
        }

        // Now that the class map has been built return the result.
        if ($classname !== null) {
            if (strpos($classname, '\\') === false) {
                $basename = strtolower($classname);
            } else {
                $basename = strtolower(trim(strrchr($classname, '\\'), '\\'));
            }

            $row = val($basename, self::$classMap);

            if ($row === null) {
                return ['', ''];
            } elseif (is_string($row)) {
                return [$classname, $row];
            } elseif (is_array($row)) {
                return  $row;
            } else {
                return ['', ''];
            }
        } else {
            return self::$classMap;
        }
    }

A an array that maps class names to physical paths.

@param string $classname An optional class name to get the path of.
@return array Returns an array in the form `[fullClassname, classPath]`.
If no {@link $classname} is passed then the entire class map is returned.
@throws \Exception Throws an exception if the class map is corrupt.

A an array that maps class names to physical paths .


public static function enabled($addon_key = null, $key = null) {
        // Lazy build the enabled array.
        if (self::$enabled === null) {
            // Make sure the enabled addons have been added first.
            if (self::$enabledKeys === null) {
                throw new \Exception("Addons::boostrap() must be called before Addons::enabled() can be called.", 500);
            }

            if (self::$all !== null || self::$sharedEnvironment) {
                // Build the enabled array by filtering the all array.
                self::$enabled = array();
                foreach (self::all() as $key => $row) {
                    if (isset($key, self::$enabledKeys)) {
                        self::$enabled[$key] = $row;
                    }
                }
            } else {
                // Build the enabled array by walking the addons.
                self::$enabled = static::cacheGet('addons-enabled', function () {
                    return static::scanAddons(null, self::$enabledKeys);
                });
            }
        }

        // The array should be built now return the addon.
        if ($addon_key === null) {
            return self::$enabled;
        } else {
            $addon = val(strtolower($addon_key), self::$enabled);
            if ($addon && $key) {
                return val($key, $addon);
            } elseif ($addon) {
                return $addon;
            } else {
                return null;
            }
        }
    }

Get all of the enabled addons or a single addon from the enabled list.

@param string $addon_key If you supply an addon key then only that addon will be returned.
@param string $key Supply one of the Addons::K_* constants to get a specific key from the addon.
@return array Returns the addon with the given key or all enabled addons if no key is passed.
@throws \Exception Throws an exception if {@link Addons::bootstrap()} hasn't been called yet.

Get all of the enabled addons or a single addon from the enabled list .


public static function info($addon_key) {
        $addon_key = strtolower($addon_key);

        // Check the enabled array first so that we don't load all addons if we don't have to.
        if (isset(self::$enabledKeys[$addon_key])) {
            return static::enabled($addon_key, self::K_INFO);
        } else {
            return static::all($addon_key, self::K_INFO);
        }
    }

Return the info array for an addon.

@param string $addon_key The addon key.
@return array|null Returns the addon's info array or null if the addon wasn't found.


protected static function scanAddonRecursive($dir, &$addons, $enabled = null) {
        $dir = rtrim($dir, '/');
        $addonKey = strtolower(basename($dir));

        // Scan the addon if it is enabled.
        if ($enabled === null || in_array($addonKey, $enabled)) {
            list($addonKey, $addon) = static::scanAddon($dir);
        } else {
            $addon = null;
        }

        // Add the addon to the collection array if one was supplied.
        if ($addon !== null) {
            $addons[$addonKey] = $addon;
        }

        // Recurse.
        $addon_subdirs = array('/addons');
        foreach ($addon_subdirs as $addon_subdir) {
            if (is_dir($dir.$addon_subdir)) {
                static::scanAddons($dir.$addon_subdir, $enabled, $addons);
            }
        }

        return array($addonKey, $addon);
    }

Scan an addon directory for information.

@param string $dir The addon directory to scan.
@param array &$addons The addons array.
@param array $enabled An array of enabled addons or null to scan all addons.
@return array Returns an array in the form [addonKey, addonInfo].

Scan an addon directory for information .


protected static function scanAddon($dir) {
        $dir = rtrim($dir, '/');
        $addon_key = strtolower(basename($dir));

        // Look for the addon info array.
        $info_path = $dir.'/addon.json';
        $info = false;
        if (file_exists($info_path)) {
            $info = json_decode(file_get_contents($info_path), true);
        }
        if (!$info) {
            $info = array();
        }
        array_touch('name', $info, $addon_key);
        array_touch('version', $info, '0.0');

        // Look for the bootstrap.
        $bootstrap = $dir.'/bootstrap.php';
        if (!file_exists($dir.'/bootstrap.php')) {
            $bootstrap = null;
        }

        // Scan the appropriate subdirectories  for classes.
        $subdirs = array('', '/library', '/controllers', '/models', '/modules', '/settings');
        $classes = array();
        foreach ($subdirs as $subdir) {
            // Get all of the php files in the subdirectory.
            $paths = glob($dir.$subdir.'/*.php');
            foreach ($paths as $path) {
                $decls = static::scanFile($path);
                foreach ($decls as $namespace_row) {
                    if (isset($namespace_row['namespace']) && $namespace_row) {
                        $namespace = rtrim($namespace_row['namespace'], '\\').'\\';
                        $namespace_classes = $namespace_row['classes'];
                    } else {
                        $namespace = '';
                        $namespace_classes = $namespace_row;
                    }

                    foreach ($namespace_classes as $class_row) {
                        $classes[strtolower($class_row['name'])] = [$namespace.$class_row['name'], $path];
                    }
                }
            }
        }

        $addon = array(
            self::K_BOOTSTRAP => $bootstrap,
            self::K_CLASSES => $classes,
            self::K_DIR => $dir,
            self::K_INFO => $info
        );

        return array($addon_key, $addon);
    }

Scan an individual addon directory and return the information about that addon.

@param string $dir The path to the addon.
@return array An array in the form of `[$addon_key, $addon_row]` or `[$addon_key, null]` if the directory doesn't
represent an addon.

Scan an individual addon directory and return the information about that addon .


protected static function scanAddons($dir = null, $enabled = null, &$addons = null) {
        if (!$dir) {
            $dir = static::$baseDir;
        }
        if ($addons === null) {
            $addons = array();
        }

        /* @var \DirectoryIterator */
        foreach (new \DirectoryIterator($dir) as $subdir) {
            if ($subdir->isDir() && !$subdir->isDot()) {
//                echo $subdir->getPathname().$subdir->isDir().$subdir->isDot().'<br />';
                static::scanAddonRecursive($subdir->getPathname(), $addons, $enabled);
            }
        }
        return $addons;
    }

Scan a directory for addons.

@param string $dir The directory to scan.
@param array $enabled An array of enabled addons in the form `[addonKey => enabled, ...]`.
@param array &$addons The addons will fill this array.
@return array Returns all of the addons.


public static function startAddon($addon_key) {
        $addon = static::enabled($addon_key);
        if (!$addon) {
            return false;
        }

        // Run the class' bootstrap.
        if ($bootstrap_path = val(self::K_BOOTSTRAP, $addon)) {
            include_once $bootstrap_path;
        }
        return true;
    }

public
static
function
startAddon
(
$
addon_key
)
{
$
addon
=
static
::
enabled
(
$
addon_key
)
;
if
(
!
$
addon
)
{
return
false
;
}
// Run the class' bootstrap.
if
(
$
bootstrap_path
=
val
(
self
::
K_BOOTSTRAP
,
$
addon
)
)
{
include_once
$
bootstrap_path
;
}
return
true
;
}

Start an addon.

This function does the following:

1. Make the addon available in the autoloader.
2. Run the addon's bootstrap.php if it exists.

@param string $addon_key The key of the addon to enable.
@return bool Returns true if the addon was enabled. False otherwise.


public function getHeaders() {
        $result = [];
        foreach ($this->context as $key => $value) {
            if (stripos($key, 'http_') === 0) {
                $key = Response::normalizeHeader(ltrim_substr($key, 'http_'));
                $result[$key] = $value;
            }
        }
        return $result;
    }

public function getHeaders ( ) { $ result = [ ] ; foreach ( $ this -> context as $ key => $ value ) { if ( stripos ( $ key , 'http_' ) === 0 ) { $ key = Response :: normalizeHeader ( ltrim_substr ( $ key , 'http_' ) ) ; $ result [ $ key ] = $ value ; } } return $ result ; }

Gets the response headers that were set on the exception.

@return array Returns the headers for this exception.

Gets the response headers that were set on the exception .


public static function callUserFuncArray($callback, $args = []) {
        // Figure out the event name from the callback.
        $event_name = static::getEventname($callback);
        if (!$event_name) {
            return call_user_func_array($callback, $args);
        }

        // The events could have different args because the event handler can take the object as the first parameter.
        $event_args = $args;
        // If the callback is an object then it gets passed as the first argument.
        if (is_array($callback) && is_object($callback[0])) {
            array_unshift($event_args, $callback[0]);
        }

        // Fire before events.
        self::fireArray($event_name.'_before', $event_args);

        // Call the function.
        if (static::hasHandler($event_name)) {
            // The callback was overridden so fire it.
            $result = static::fireArray($event_name, $event_args);
        } else {
            // The callback was not overridden so just call the passed callback.
            $result = call_user_func_array($callback, $args);
        }

        // Fire after events.
        self::fireArray($event_name.'_after', $event_args);

        return $result;
    }

Call a callback with an array of parameters, checking for events to be called with the callback.

This method is similar to {@link call_user_func_array()} but it will fire events that can happen
before and/or after the callback and can call an event instead of the callback itself to override it.

In order to use events with this method they must be bound with a particular naming convention.

**Modify a function**

- functionname_before
- functionname
- functionname_after

**Modify a method call**

- classname_methodname_before
- classname_methodname
- classname_methodname_after

@param callable $callback The {@link callable} to be called.
@param array $args The arguments to be passed to the callback, as an indexed array.
@return mixed Returns the return value of the callback.

Call a callback with an array of parameters checking for events to be called with the callback .


public static function bind($event, $callback, $priority = Event::PRIORITY_NORMAL) {
        $event = strtolower($event);
        self::$handlers[$event][$priority][] = $callback;
        self::$toSort[$event] = true;
    }

public static function bind ( $ event , $ callback , $ priority = Event :: PRIORITY_NORMAL ) { $ event = strtolower ( $ event ) ; self :: $ handlers [ $ event ] [ $ priority ] [ ] = $ callback ; self :: $ toSort [ $ event ] = true ; }

Bind an event handler to an event.

@param string $event The naame of the event to bind to.
@param callback $callback The callback of the event.
@param int $priority The priority of the event.


public static function bindClass($class, $priority = Event::PRIORITY_NORMAL) {
        $method_names = get_class_methods($class);

        // Grab an instance of the class so there is something to bind to.
        if (is_string($class)) {
            if (method_exists($class, 'instance')) {
                // TODO: Make the instance lazy load.
                $instance = call_user_func(array($class, 'instance'));
            } else {
                throw new \InvalidArgumentException('Event::bindClass(): The class for argument #1 must have an instance() method or be passed as an object.', 422);
            }
        } else {
            $instance = $class;
        }

        foreach ($method_names as $method_name) {
            if (strpos($method_name, '_') === false) {
                continue;
            }

            $parts = explode('_', strtolower($method_name));
            switch (end($parts)) {
                case 'handler':
                case 'create':
                case 'override':
                    array_pop($parts);
                    $event_name = implode('_', $parts);
                    break;
                case 'before':
                case 'after':
                default:
                    $event_name = implode('_', $parts);
                    break;
            }
            // Bind the event if we have one.
            if ($event_name) {
                static::bind($event_name, array($instance, $method_name), $priority);
            }
        }
    }

Bind a class' declared event handlers.

Plugin classes declare event handlers in the following way:

```
// Bind to a normal event.
public function eventname_handler($arg1, $arg2, ...) { ... }

// Add/override a method called with Event::callUserFuncArray().
public function ClassName_methodName($sender, $arg1, $arg2) { ... }
public function ClassName_methodName_create($sender, $arg1, $arg2) { ... } // deprecated

// Call the handler before or after a method called with Event::callUserFuncArray().
public function ClassName_methodName_before($sender, $arg1, $arg2) { ... }
public function ClassName_methodName_after($sender, $arg1, $arg2) { ... }
```

@param mixed $class The class name or an object instance.
@param int $priority The priority of the event.
@throws \InvalidArgumentException Throws an exception when binding to a class name with no `instance()` method.


public static function dumpHandlers() {
        $result = [];

        foreach (self::$handlers as $event_name => $nested) {
            $handlers = call_user_func_array('array_merge', static::getHandlers($event_name));
            $result[$event_name] = array_map('format_callback', $handlers);
        }

        return $result;
    }

public static function dumpHandlers ( ) { $ result = [ ] ; foreach ( self :: $ handlers as $ event_name => $ nested ) { $ handlers = call_user_func_array ( 'array_merge' , static :: getHandlers ( $ event_name ) ) ; $ result [ $ event_name ] = array_map ( 'format_callback' , $ handlers ) ; } return $ result ; }

Dumps all of the bound handlers.

This method is meant for debugging.

@return array Returns an array of all handlers indexed by event name.


public static function fire($event) {
        $handlers = self::getHandlers($event);
        if (!$handlers) {
            return null;
        }

        // Grab the handlers and call them.
        $args = array_slice(func_get_args(), 1);
        $result = null;
        foreach ($handlers as $callbacks) {
            foreach ($callbacks as $callback) {
                $result = call_user_func_array($callback, $args);
            }
        }
        return $result;
    }

public
static
function
fire
(
$
event
)
{
$
handlers
=
self
::
getHandlers
(
$
event
)
;
if
(
!
$
handlers
)
{
return
;
}
// Grab the handlers and call them.
$
args
=
array_slice
(
func_get_args
(
)
,
1
)
;
$
result
=
;
foreach
(
$
handlers
as
$
callbacks
)
{
foreach
(
$
callbacks
as
$
callback
)
{
$
result
=
call_user_func_array
(
$
callback
,
$
args
)
;
}
}
return
$
result
;
}

Fire an event.

@param string $event The name of the event.
@return mixed Returns the result of the last event handler.


public static function fireArray($event, $args = []) {
        $handlers = self::getHandlers($event);
        if (!$handlers) {
            return null;
        }

        // Grab the handlers and call them.
        $result = null;
        foreach ($handlers as $callbacks) {
            foreach ($callbacks as $callback) {
                $result = call_user_func_array($callback, $args);
            }
        }
        return $result;
    }

public
static
function
fireArray
(
$
event
,
$
args
=
[
]
)
{
$
handlers
=
self
::
getHandlers
(
$
event
)
;
if
(
!
$
handlers
)
{
return
;
}
// Grab the handlers and call them.
$
result
=
;
foreach
(
$
handlers
as
$
callbacks
)
{
foreach
(
$
callbacks
as
$
callback
)
{
$
result
=
call_user_func_array
(
$
callback
,
$
args
)
;
}
}
return
$
result
;
}

Fire an event with an array of arguments.

This method is to {@link Event::fire()} as {@link call_user_func_array()} is to {@link call_user_funct()}.
The main purpose though is to allow you to have event handlers that can take references.

@param string $event The name of the event.
@param array $args The arguments for the event handlers.
@return mixed Returns the result of the last event handler.

Fire an event with an array of arguments .


public static function fireFilter($event, $value) {
        $handlers = self::getHandlers($event);
        if (!$handlers) {
            return $value;
        }

        $args = array_slice(func_get_args(), 1);
        foreach ($handlers as $callbacks) {
            foreach ($callbacks as $callback) {
                $value = call_user_func_array($callback, $args);
                $args[0] = $value;
            }
        }
        return $value;
    }

public static function fireFilter ( $ event , $ value ) { $ handlers = self :: getHandlers ( $ event ) ; if ( ! $ handlers ) { return $ value ; } $ args = array_slice ( func_get_args ( ) , 1 ) ; foreach ( $ handlers as $ callbacks ) { foreach ( $ callbacks as $ callback ) { $ value = call_user_func_array ( $ callback , $ args ) ; $ args [ 0 ] = $ value ; } } return $ value ; }

Chain several event handlers together.

This method will fire the first handler and pass its result as the first argument
to the next event handler and so on. A chained event handler can have more than one parameter,
but must have at least one parameter.

@param string $event The name of the event to fire.
@param mixed $value The value to pass into the filter.
@return mixed The result of the chained event or `$value` if there were no handlers.


public static function functionExists($function_name, $only_events = false) {
        if (!$only_events && function_exists($function_name)) {
            return true;
        } else {
            return static::hasHandler($function_name);
        }
    }

public static function functionExists ( $ function_name , $ only_events = false ) { if ( ! $ only_events && function_exists ( $ function_name ) ) { return true ; } else { return static :: hasHandler ( $ function_name ) ; } }

Checks if a function exists or there is a replacement event for it.

@param string $function_name The function name.
@param bool $only_events Whether or not to only check events.
@return boolean Returns `true` if the function given by `function_name` has been defined, `false` otherwise.
@see http://ca1.php.net/manual/en/function.function-exists.php

Checks if a function exists or there is a replacement event for it .


protected static function getEventname($callback) {
        if (is_string($callback)) {
            return strtolower($callback);
        } elseif (is_array($callback)) {
            if (is_string($callback[0])) {
                $classname = $callback[0];
            } else {
                $classname = get_class($callback[0]);
            }
            $eventclass = trim(strrchr($classname, '\\'), '\\');
            if (!$eventclass) {
                $eventclass = $classname;
            }
            return strtolower($eventclass.'_'.$callback[1]);
        }
        return '';
    }

protected static function getEventname ( $ callback ) { if ( is_string ( $ callback ) ) { return strtolower ( $ callback ) ; } elseif ( is_array ( $ callback ) ) { if ( is_string ( $ callback [ 0 ] ) ) { $ classname = $ callback [ 0 ] ; } else { $ classname = get_class ( $ callback [ 0 ] ) ; } $ eventclass = trim ( strrchr ( $ classname , '\\' ) , '\\' ) ; if ( ! $ eventclass ) { $ eventclass = $ classname ; } return strtolower ( $ eventclass . '_' . $ callback [ 1 ] ) ; } return '' ; }

Get the event name for a callback.

@param string|array|callable $callback The callback or an array in the form of a callback.
@return string The name of the callback.


public static function getHandlers($name) {
        $name = strtolower($name);

        if (!isset(self::$handlers[$name])) {
            return [];
        }

        // See if the handlers need to be sorted.
        if (isset(self::$toSort[$name])) {
            ksort(self::$handlers[$name]);
            unset(self::$toSort[$name]);
        }

        return self::$handlers[$name];
    }

Get all of the handlers bound to an event.

@param string $name The name of the event.
@return array Returns the handlers that are watching {@link $name}.

Get all of the handlers bound to an event .


public static function hasHandler($event) {
        $event = strtolower($event);
        return array_key_exists($event, self::$handlers) && !empty(self::$handlers[$event]);
    }

public static function hasHandler ( $ event ) { $ event = strtolower ( $ event ) ; return array_key_exists ( $ event , self :: $ handlers ) && ! empty ( self :: $ handlers [ $ event ] ) ; }

Checks if an event has a handler.

@param string $event The name of the event.
@return bool Returns `true` if the event has at least one handler, `false` otherwise.


public static function methodExists($object, $method_name, $only_events = false) {
        if (!$only_events && method_exists($object, $method_name)) {
            return true;
        } else {
            // Check to see if there is an event bound to the method.
            $event_name = self::getEventname([$object, $method_name]);
            return static::hasHandler($event_name);
        }
    }

Checks if a class method exists or there is a replacement event for it.

@param mixed $object An object instance or a class name.
@param string $method_name The method name.
@param bool $only_events Whether or not to only check events.
@return boolean Returns `true` if the method given by method_name has been defined for the given object,
`false` otherwise.
@see http://ca1.php.net/manual/en/function.method-exists.php

Checks if a class method exists or there is a replacement event for it .


public function getValue($driver = 'default') {
        $driver = $this->normalizeKey($driver);

        if (isset($this->driverValues[$driver])) {
            return $this->driverValues[$driver];
        } elseif (isset($this->driverValues['default'])) {
            return $this->driverValues['default'];
        } else {
            return 'null';
        }
    }

public function getValue ( $ driver = 'default' ) { $ driver = $ this -> normalizeKey ( $ driver ) ; if ( isset ( $ this -> driverValues [ $ driver ] ) ) { return $ this -> driverValues [ $ driver ] ; } elseif ( isset ( $ this -> driverValues [ 'default' ] ) ) { return $ this -> driverValues [ 'default' ] ; } else { return 'null' ; } }

Get the literal value.

@param string $driver The name of the database driver to fetch the literal for.
@return string Returns the value for the specific driver, the default literal, or "null" if there is no default.


public function setValue($value, $driver = 'default') {
        $driver = $this->normalizeKey($driver);
        $this->driverValues[$driver] = $value;
        return $this;
    }

public function setValue ( $ value , $ driver = 'default' ) { $ driver = $ this -> normalizeKey ( $ driver ) ; $ this -> driverValues [ $ driver ] = $ value ; return $ this ; }

Set the literal value.

@param string $value The new value to set.
@param string $driver The name of the database driver to set the value for.
@return Literal Returns $this for fluent calls.


public function splitSalt($hash) {
        // The hash is in the form: <32 char hash><salt>.
        $salt_length = strlen($hash) - 32;
        $salt = trim(substr($hash, -$salt_length, $salt_length));
        $stored_hash = substr($hash, 0, strlen($hash) - $salt_length);

        return [$stored_hash, $salt];
    }

Split the salt and hash from a single hash.

@param string $hash The hash to split.
@return array An array in the form `[$hash, $salt]`.

Split the salt and hash from a single hash .


public static function defaultPath($value = '') {
        if ($value) {
            self::$defaultPath = $value;
        } elseif (!self::$defaultPath) {
            self::$defaultPath = PATH_ROOT.'/conf/config.json.php';
        }
        return self::$defaultPath;
    }

public static function defaultPath ( $ value = '' ) { if ( $ value ) { self :: $ defaultPath = $ value ; } elseif ( ! self :: $ defaultPath ) { self :: $ defaultPath = PATH_ROOT . '/conf/config.json.php' ; } return self :: $ defaultPath ; }

Get or set the default path.

@param string $value Pass a value to set a new default path.
@return string Returns the current default path.


public static function get($key, $default = null) {
        if (array_key_exists($key, self::$data)) {
            return self::$data[$key];
        } else {
            return $default;
        }
    }

public static function get ( $ key , $ default = null ) { if ( array_key_exists ( $ key , self :: $ data ) ) { return self :: $ data [ $ key ] ; } else { return $ default ; } }

Get a setting from the config.

@param string $key The config key.
@param mixed $default The default value if the config file doesn't exist.
@return mixed The value at {@link $key} or {@link $default} if the key isn't found.
@see \config()


public static function load($path = '', $underlay = false, $php_var = 'config') {
        if (!$path) {
            $path = self::$defaultPath;
        }

        $loaded = array_load($path, $php_var);

        if (empty($loaded)) {
            return;
        }

        if (!is_array(self::$data)) {
            self::$data = [];
        }

        if ($underlay) {
            self::$data = array_replace($loaded, self::$data);
        } else {
            self::$data = array_replace(self::$data, $loaded);
        }
    }

public static function load ( $ path = '' , $ underlay = false , $ php_var = 'config' ) { if ( ! $ path ) { $ path = self :: $ defaultPath ; } $ loaded = array_load ( $ path , $ php_var ) ; if ( empty ( $ loaded ) ) { return ; } if ( ! is_array ( self :: $ data ) ) { self :: $ data = [ ] ; } if ( $ underlay ) { self :: $ data = array_replace ( $ loaded , self :: $ data ) ; } else { self :: $ data = array_replace ( self :: $ data , $ loaded ) ; } }

Load configuration data from a file.

@param string $path An optional path to load the file from.
@param string $path If true the config will be put under the current config, not over it.
@param string $php_var The name of the php variable to load from if using the php file type.


public static function save($data, $path = null, $php_var = 'config') {
        if (!is_array($data)) {
            throw new \InvalidArgumentException('Config::save(): Argument #1 is not an array.', 400);
        }

        if (!$path) {
            $path = static::defaultPath();
        }

        // Load the current config information so we know what to replace.
        $config = array_load($path, $php_var);
        // Merge the new config into the current config.
        $config = array_replace($config, $data);
        // Remove null config values.
        $config = array_filter($config, function ($value) {
            return $value !== null;
        });

        ksort($config, SORT_NATURAL | SORT_FLAG_CASE);

        $result = array_save($config, $path, $php_var);
        return $result;
    }

Save data to the config file.

@param array $data The config data to save.
@param string $path An optional path to save the data to.
@param string $php_var The name of the php variable to load from if using the php file type.
@return bool Returns true if the save was successful or false otherwise.
@throws \InvalidArgumentException Throws an exception when the saved data isn't an array.


public function matchRoutes(Request $request) {
        $result = array();

        foreach ($this->routes as $route) {
            $matches = $route->matches($request, $this);
            if ($matches) {
                $result[] = array($route, $matches);
            }
        }
        return $result;
    }

public function matchRoutes ( Request $ request ) { $ result = array ( ) ; foreach ( $ this -> routes as $ route ) { $ matches = $ route -> matches ( $ request , $ this ) ; if ( $ matches ) { $ result [ ] = array ( $ route , $ matches ) ; } } return $ result ; }

Get all of the matched routes for a request.

@param Request $request The {@link Request} to match against.
@return array An array of arrays corresponding to matching routes and their args.

Get all of the matched routes for a request .


public function route($pathOrRoute, $callback = null) {
        if (is_object($pathOrRoute) && $pathOrRoute instanceof Route) {
            $route = $pathOrRoute;
        } elseif (is_string($pathOrRoute) && $callback !== null) {
            $route = Route::create($pathOrRoute, $callback);
        } else {
            throw new \InvalidArgumentException("Argument #1 must be either a Garden\\Route or a string.", 500);
        }
        $this->routes[] = $route;
        return $route;
    }

Add a new route.

@param string|Route $pathOrRoute The path to the route or the {@link Route} object itself.
@param callable|string|null $callback Either a callback to map the route to or a string representing
a format for {@link sprintf()}.
@return Route Returns the route that was added.
@throws \InvalidArgumentException Throws an exceptio if {@link $path} isn't a string or {@link Route}.


protected function finalize($result) {
        $response = Response::create($result);
        $response->meta(['request' => $this->request], true);
        $response->contentTypeFromAccept($this->request->getEnv('HTTP_ACCEPT'));
        $response->contentAsset($this->request->getEnv('HTTP_X_ASSET'));

        $contentType = $response->contentType();

        if ($this->request->getMethod() === Request::METHOD_HEAD) {
            $response->flushHeaders();
            return null;
        }

        // Check for known response types.
        switch ($contentType) {
            case 'application/internal':
                if ($result instanceof \Exception) {
                    throw $result;
                }

                if ($response->contentAsset() === 'response') {
                    return $response;
                } else {
                    return $response->jsonSerialize();
                }
                // No break because everything returns.
            case 'application/json':
                $response->flushHeaders();
                echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
                break;
            default:
                $data = $response->data();
                if (is_string($data)) {
                    $response->flushHeaders();
                    echo $data;
                } else {
                    $response->status(415);
                    $response->flushHeaders();
                    echo "Unsupported response type: $contentType";
                }
                break;
        }
        return null;
    }

Finalize the result from a dispatch.

@param mixed $result The result of the dispatch.
@return mixed Returns relevant debug data or processes the response.
@throws \Exception Throws an exception when finalizing internal content types and the result is an exception.


protected function actionExists($object, $action, $method = '', $special = false) {
        if ($special && in_array($action, self::$specialActions)) {
            return '';
        }

        // Short circuit on a badly named action.
        if (!$this->isIdentifier($action)) {
            return '';
        }

        if ($method && $method !== $action) {
            $calledAction = $method.$action;
            if (Event::methodExists($object, $calledAction)) {
                return $calledAction;
            }
        }
        $calledAction = $action;
        if (Event::methodExists($object, $calledAction)) {
            return $calledAction;
        }
        return '';
    }

Tests whether a controller action exists.

@param object $object The controller object that the method should be on.
@param string $action The name of the action.
@param string $method The http method.
@param bool $special Whether or not to blacklist the special methods.
@return string Returns the name of the action method or an empty string if it doesn't exist.

Tests whether a controller action exists .


protected function allowedMethods($object, $action) {
        $allMethods = [
            Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_DELETE,
            Request::METHOD_PATCH, Request::METHOD_PUT,
            Request::METHOD_HEAD, Request::METHOD_OPTIONS
        ];

        // Special actions should not be considered.
        if (in_array($action, self::$specialActions)) {
            return [];
        }

        if (Event::methodExists($object, $action)) {
            // The controller has the named action and thus supports all methods.
            return $allMethods;
        }

        // Loop through all the methods and check to see if they exist in the form $method.$action.
        $allowed = [];
        foreach ($allMethods as $method) {
            if (Event::methodExists($object, $method.$action)) {
                $allowed[] = $method;
            }
        }
        return $allowed;
    }

Find the allowed http methods on a controller object.

@param object $object The object to test.
@param string $action The action to test.
@return array Returns an array of allowed http methods.

Find the allowed http methods on a controller object .


public function matches(Request $request, Application $app) {
        if (!$this->matchesMethods($request)) {
            return null;
        }

        if ($this->getMatchFullPath()) {
            $path = $request->getFullPath();
        } else {
            $path = $request->getPath();
        }

        // If this route is off of a root then check that first.
        if ($root = $this->pattern()) {
            if (stripos($path, $root) === 0) {
                // Strip the root off the path that we are examining.
                $path = substr($path, strlen($root));
            } else {
                return null;
            }
        }

        $pathParts = explode('/', trim($path, '/'));

        $controller = array_shift($pathParts);
        if (!$controller) {
            return null;
        }

        // Check to see if a class exists with the desired controller name.
        // If a controller is found then it is responsible for the route, regardless of any other parameters.
        $basename = sprintf($this->controllerPattern, ucfirst($controller));
        if (class_exists('\Garden\Addons', false)) {
            list($classname) = Addons::classMap($basename);

            // TODO: Optimize this second check.
            if (!$classname && class_exists($basename)) {
                $classname = $basename;
            }
        } elseif (class_exists($basename)) {
            $classname = $basename;
        } else {
            $classname = '';
        }

        if (!$classname) {
            return null;
        }

        $result = array(
            'controller' => $classname,
            'method' => $request->getMethod(),
            'path' => $path,
            'pathArgs' => $pathParts,
            'query' => $request->getQuery()
        );
        return $result;
    }

Try matching a route to a request.

@param Request $request The request to match the route with.
@param Application $app The application instantiating the route.
@return array|null Whether or not the route matches the request.
If the route matches an array of args is returned, otherwise the function returns null.


protected function failsCondition($name, $value) {
        $name = strtolower($name);
        if (isset($this->conditions[$name])) {
            $regex = $this->conditions[$name];
            return !preg_match("`^$regex$`", $value);
        }

        if (isset(self::$globalConditions[$name])) {
            $regex = self::$globalConditions[$name];
            return !preg_match("`^$regex$`", $value);
        }

        return null;
    }

protected function failsCondition ( $ name , $ value ) { $ name = strtolower ( $ name ) ; if ( isset ( $ this -> conditions [ $ name ] ) ) { $ regex = $ this -> conditions [ $ name ] ; return ! preg_match ( "`^$regex$`" , $ value ) ; } if ( isset ( self :: $ globalConditions [ $ name ] ) ) { $ regex = self :: $ globalConditions [ $ name ] ; return ! preg_match ( "`^$regex$`" , $ value ) ; } return null ; }

Tests whether an argument fails against a condition.

@param string $name The name of the parameter.
@param string $value The value of the argument.
@return bool|null Returns one of the following:
- true: The condition fails.
- false: The condition passes.
- null: There is no condition.

Tests whether an argument fails against a condition .


public static function current(Response $response = null) {
        if ($response !== null) {
            self::$current = $response;
        } elseif (self::$current === null) {
            self::$current = new Response();
        }

        return self::$current;
    }

public static function current ( Response $ response = null ) { if ( $ response !== null ) { self :: $ current = $ response ; } elseif ( self :: $ current === null ) { self :: $ current = new Response ( ) ; } return self :: $ current ; }

Gets or sets the response that is currently being processed.

@param Response|null $response Set a new response or pass null to get the current response.
@return Response Returns the current response.

Gets or sets the response that is currently being processed .


public static function create($result) {
        if ($result instanceof Response) {
            return $result;
        } elseif ($result instanceof Exception\ResponseException) {
            /* @var Exception\ResponseException $result */
            return $result->getResponse();
        }

        $response = new Response();

        if ($result instanceof Exception\ClientException) {
            /* @var Exception\ClientException $cex */
            $cex = $result;
            $response->status($cex->getCode());
            $response->headers($cex->getHeaders());
            $response->data($cex->jsonSerialize());
        } elseif ($result instanceof \Exception) {
            /* @var \Exception $ex */
            $ex = $result;
            $response->status($ex->getCode());
            $response->data([
                'exception' => $ex->getMessage(),
                'code' => $ex->getCode()
            ]);
        } elseif (is_array($result)) {
            if (count($result) === 3 && isset($result[0], $result[1], $result[2])) {
                // This is a rack style response in the form [code, headers, body].
                $response->status($result[0]);
                $response->headers($result[1]);
                $response->data($result[2]);
            } elseif (array_key_exists('response', $result)) {
                $resultResponse = $result['response'];
                if (!$resultResponse) {
                    $response->data($result['body']);
                } else {
                    // This is a dispatched response.
                    $response = static::create($resultResponse);
                }

                // Set the rest of the result to the response context.
                unset($result['response']);
                $response->meta($result, true);
            } else {
                $response->data($result);
            }
        } else {
            $response->status(422);
            $response->data([
                'exception' => "Unknown result type for response.",
                'code' => $response->status()
            ]);
        }
        return $response;
    }

Create a Response from a variety of data.

@param mixed $result The result to create the response from.
@return Response Returns a {@link Response} object.

Create a Response from a variety of data .


public function contentType($value = null) {
        if ($value === null) {
            return $this->headers('Content-Type');
        }

        return $this->headers('Content-Type', $value);
    }

public function contentType ( $ value = null ) { if ( $ value === null ) { return $ this -> headers ( 'Content-Type' ) ; } return $ this -> headers ( 'Content-Type' , $ value ) ; }

Gets or sets the content type.

@param string|null $value The new content type or null to get the current content type.
@return Response|string Returns the current content type or `$this` for fluent calls.


public function contentAsset($asset = null) {
        if ($asset !== null) {
            $this->contentAsset = $asset;
            return $this;
        }

        return $this->contentAsset;
    }

public function contentAsset ( $ asset = null ) { if ( $ asset !== null ) { $ this -> contentAsset = $ asset ; return $ this ; } return $ this -> contentAsset ; }

Gets or sets the asset that will be rendered in the response.

@param string $asset Set a new value or pass `null` to get the current value.
@return Response|string Returns the current content asset or `$this` when settings.

Gets or sets the asset that will be rendered in the response .


public function contentTypeFromAccept($accept) {
        if (!empty($this->headers['Content-Type'])) {
            return;
        }

        $accept = strtolower($accept);
        if (strpos($accept, ',') === false) {
            list($contentType) = explode(';', $accept);
        } elseif (strpos($accept, 'text/html') !== false) {
            $contentType = 'text/html';
        } elseif (strpos($accept, 'application/rss+xml' !== false)) {
            $contentType = 'application/rss+xml';
        } elseif (strpos($accept, 'text/plain')) {
            $contentType = 'text/plain';
        } else {
            $contentType = 'text/html';
        }
        $this->contentType($contentType);
        return $this;
    }

public function contentTypeFromAccept ( $ accept ) { if ( ! empty ( $ this -> headers [ 'Content-Type' ] ) ) { return ; } $ accept = strtolower ( $ accept ) ; if ( strpos ( $ accept , ',' ) === false ) { list ( $ contentType ) = explode ( ';' , $ accept ) ; } elseif ( strpos ( $ accept , 'text/html' ) !== false ) { $ contentType = 'text/html' ; } elseif ( strpos ( $ accept , 'application/rss+xml' !== false ) ) { $ contentType = 'application/rss+xml' ; } elseif ( strpos ( $ accept , 'text/plain' ) ) { $ contentType = 'text/plain' ; } else { $ contentType = 'text/html' ; } $ this -> contentType ( $ contentType ) ; return $ this ; }

Set the content type from an accept header.

@param string $accept The value of the accept header.
@return Response $this Returns `$this` for fluent calls.

Set the content type from an accept header .


public static function statusMessage($statusCode, $header = false) {
        $message = val($statusCode, self::$messages, 'Unknown');

        if ($header) {
            return "HTTP/1.1 $statusCode $message";
        } else {
            return $message;
        }
    }

public
static
function
statusMessage
(
$
statusCode
,
$
header
=
false
)
{
$
message
=
val
(
$
statusCode
,
self
::
$
messages
,
'Unknown'
)
;
if
(
$
header
)
{
return
"HTTP/1.1 $statusCode $message"
;
}
else
{
return
$
message
;
}
}

Translate an http code to its corresponding status message.

@param int $statusCode The http status code.
@param bool $header Whether or not the result should be in a form that can be passed to {@link header}.
@return string Returns the status message corresponding to {@link $code}.

Translate an http code to its corresponding status message .


public function cookies($name, $value = false, $expires = 0, $path = null, $domain = null, $secure = false, $httponly = false) {
        if ($value === false) {
            return val($name, $this->cookies);
        }

        $this->cookies[$name] = [$value, $expires, $path, $domain, $secure, $httponly];
        return $this;
    }

public function cookies ( $ name , $ value = false , $ expires = 0 , $ path = null , $ domain = null , $ secure = false , $ httponly = false ) { if ( $ value === false ) { return val ( $ name , $ this -> cookies ) ; } $ this -> cookies [ $ name ] = [ $ value , $ expires , $ path , $ domain , $ secure , $ httponly ] ; return $ this ; }

Gets or sets a cookie.

@param string $name The name of the cookie.
@param bool $value The value of the cookie. This value is stored on the clients computer; do not store sensitive information.
@param int $expires The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch.
@param string $path The path on the server in which the cookie will be available on.
If set to '/', the cookie will be available within the entire {@link $domain}.
@param string $domain The domain that the cookie is available to.
@param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.
@param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol.
@return $this|mixed Returns the cookie settings at {@link $name} or `$this` when setting a cookie for fluent calls.


public static function globalCookies($name = null, $value = false, $expires = 0, $path = null, $domain = null, $secure = false, $httponly = false) {
        if (self::$globalCookies === null) {
            self::$globalCookies = [];
        }

        if ($name === null) {
            return self::$globalCookies;
        }

        if ($value === false) {
            return val($name, self::$globalCookies);
        }

        self::$globalCookies[$name] = [$value, $expires, $path, $domain, $secure, $httponly];
        return null;
    }

public static function globalCookies ( $ name = null , $ value = false , $ expires = 0 , $ path = null , $ domain = null , $ secure = false , $ httponly = false ) { if ( self :: $ globalCookies === null ) { self :: $ globalCookies = [ ] ; } if ( $ name === null ) { return self :: $ globalCookies ; } if ( $ value === false ) { return val ( $ name , self :: $ globalCookies ) ; } self :: $ globalCookies [ $ name ] = [ $ value , $ expires , $ path , $ domain , $ secure , $ httponly ] ; return null ; }

Gets or sets a global cookie.

Global cookies are used when you want to set a cookie, but a {@link Response} has not been created yet.

@param string $name The name of the cookie.
@param bool $value The value of the cookie. This value is stored on the clients computer; do not store sensitive information.
@param int $expires The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch.
@param string $path The path on the server in which the cookie will be available on.
If set to '/', the cookie will be available within the entire {@link $domain}.
@param string $domain The domain that the cookie is available to.
@param bool $secure Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.
@param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol.
@return mixed|null Returns the cookie settings at {@link $name} or `null` when setting a cookie.


public function meta($meta = null, $merge = false) {
        if ($meta !== null) {
            if ($merge) {
                $this->meta = array_merge($this->meta, $meta);
            } else {
                $this->meta = $meta;
            }
            return $this;
        } else {
            return $this->meta;
        }
    }

public function meta ( $ meta = null , $ merge = false ) { if ( $ meta !== null ) { if ( $ merge ) { $ this -> meta = array_merge ( $ this -> meta , $ meta ) ; } else { $ this -> meta = $ meta ; } return $ this ; } else { return $ this -> meta ; } }

Get or set the meta data for the response.

The meta is an array of data that is unrelated to the response data.

@param array|null $meta Pass a new meta data value or `null` to get the current meta array.
@param bool $merge Whether or not to merge new data with the current data when setting.
@return $this|array Returns either the meta or `$this` when setting the meta data.

Get or set the meta data for the response .


public function data($data = null, $merge = false) {
        if ($data !== null) {
            if ($merge) {
                $this->data = array_merge($this->data, $data);
            } else {
                $this->data = $data;
            }
            return $this;
        } else {
            return $this->data;
        }
    }

public function data ( $ data = null , $ merge = false ) { if ( $ data !== null ) { if ( $ merge ) { $ this -> data = array_merge ( $ this -> data , $ data ) ; } else { $ this -> data = $ data ; } return $ this ; } else { return $ this -> data ; } }

Get or set the data for the response.

@param array|null $data Pass a new data value or `null` to get the current data array.
@param bool $merge Whether or not to merge new data with the current data when setting.
@return Response|array Returns either the data or `$this` when setting the data.


public function headers($name, $value = null, $replace = true) {
        $headers = static::splitHeaders($name, $value);

        if (is_string($headers)) {
            return val($headers, $this->headers);
        }

        foreach ($headers as $name => $value) {
            if ($replace || !isset($this->headers[$name])) {
                $this->headers[$name] = $value;
            } else {
                $this->headers[$name] = array_merge((array)$this->headers, [$value]);
            }
        }
        return $this;
    }

public function headers ( $ name , $ value = null , $ replace = true ) { $ headers = static :: splitHeaders ( $ name , $ value ) ; if ( is_string ( $ headers ) ) { return val ( $ headers , $ this -> headers ) ; } foreach ( $ headers as $ name => $ value ) { if ( $ replace || ! isset ( $ this -> headers [ $ name ] ) ) { $ this -> headers [ $ name ] = $ value ; } else { $ this -> headers [ $ name ] = array_merge ( ( array ) $ this -> headers , [ $ value ] ) ; } } return $ this ; }

Gets or sets headers.

@param string|array $name The name of the header or an array of headers.
@param string|null $value A new value for the header or null to get the current header.
@param bool $replace Whether or not to replace the current header or append.
@return Response|string Returns the value of the header or `$this` for fluent calls.


public static function globalHeaders($name = null, $value = null, $replace = true) {
        if (self::$globalHeaders === null) {
            self::$globalHeaders = [
                'P3P' => 'CP="CAO PSA OUR"'
            ];
        }

        if ($name === null) {
            return self::$globalHeaders;
        }

        $headers = static::splitHeaders($name, $value);

        if (is_string($headers)) {
            return val($headers, self::$globalHeaders);
        }

        foreach ($headers as $name => $value) {
            if ($replace || !isset(self::$globalHeaders[$name])) {
                self::$globalHeaders[$name] = $value;
            } else {
                self::$globalHeaders[$name] = array_merge((array)self::$globalHeaders, [$value]);
            }
        }
        return null;
    }

public
static
function
globalHeaders
(
$
name
=
,
$
value
=
,
$
replace
=
true
)
{
if
(
self
::
$
globalHeaders
===
)
{
self
::
$
globalHeaders
=
[
'P3P'
=>
'CP="CAO PSA OUR"'
]
;
}
if
(
$
name
===
)
{
return
self
::
$
globalHeaders
;
}
$
headers
=
static
::
splitHeaders
(
$
name
,
$
value
)
;
if
(
is_string
(
$
headers
)
)
{
return
val
(
$
headers
,
self
::
$
globalHeaders
)
;
}
foreach
(
$
headers
as
$
name
=>
$
value
)
{
if
(
$
replace
||
!
isset
(
self
::
$
globalHeaders
[
$
name
]
)
)
{
self
::
$
globalHeaders
[
$
name
]
=
$
value
;
}
else
{
self
::
$
globalHeaders
[
$
name
]
=
array_merge
(
(
array
)
self
::
$
globalHeaders
,
[
$
value
]
)
;
}
}
return
;
}

Gets or sets global headers.

The global headers exist to allow code to queue up headers before the response has been constructed.

@param string|array|null $name The name of the header or an array of headers.
@param string|null $value A new value for the header or null to get the current header.
@param bool $replace Whether or not to replace the current header or append.
@return string|array Returns one of the following:
- string|array: Returns the current value of the header at {@link $name}.
- array: Returns the entire global headers array when {@link $name} is not passed.
- null: Returns `null` when setting a global header.


public static function normalizeHeader($name) {
        static $special = [
            'etag' => 'ETag', 'p3p' => 'P3P', 'www-authenticate' => 'WWW-Authenticate',
            'x-ua-compatible' => 'X-UA-Compatible'
        ];

        $name = str_replace(['-', '_'], ' ', strtolower($name));
        if (isset($special[$name])) {
            $name = $special[$name];
        } else {
            $name = str_replace(' ', '-', ucwords($name));
        }
        return $name;
    }

public
static
function
normalizeHeader
(
$
name
)
{
static
$
special
=
[
'etag'
=>
'ETag'
,
'p3p'
=>
'P3P'
,
'www-authenticate'
=>
'WWW-Authenticate'
,
'x-ua-compatible'
=>
'X-UA-Compatible'
]
;
$
name
=
str_replace
(
[
'-'
,
'_'
]
,
' '
,
strtolower
(
$
name
)
)
;
if
(
isset
(
$
special
[
$
name
]
)
)
{
$
name
=
$
special
[
$
name
]
;
}
else
{
$
name
=
str_replace
(
' '
,
'-'
,
ucwords
(
$
name
)
)
;
}
return
$
name
;
}

Normalize a header key to the proper casing.

Example:

```
echo static::normalizeHeader('CONTENT_TYPE');

// Content-Type
```

@param string $name The name of the header.
@return string Returns the normalized header name.

Normalize a header key to the proper casing .


public function flushHeaders($global = true) {
        if (headers_sent()) {
            return;
        }

        if ($global) {
            $cookies = array_replace(static::globalCookies(), $this->cookies);
            $headers = array_replace(static::globalHeaders(), $this->headers);
        } else {
            $cookies = $this->cookies;
            $headers = $this->headers;
        }

        // Set the cookies first.
        foreach ($cookies as $name => $value) {
            setcookie(
                $name,
                $value[0],
                $value[1],
                $value[2] !== null ? $value[2] : $this->defaultCookiePath,
                $value[3] !== null ? $value[3] : $this->defaultCookieDomain,
                $value[4],
                $value[5]
            );
        }

        // Set the response code.
        header(static::statusMessage($this->status, true), true, $this->status);

        $headers = array_filter($headers);

        // The content type is a special case.
        if (isset($headers['Content-Type'])) {
            $contentType = (array)$headers['Content-Type'];
            header('Content-Type: '.reset($contentType).'; charset=utf8', true);
            unset($headers['Content-Type']);
        }

        // Flush the rest of the headers.
        foreach ($headers as $name => $value) {
            foreach ((array)$value as $hvalue) {
                header("$name: $hvalue", false);
            }
        }
    }

public
function
flushHeaders
(
$
global
=
true
)
{
if
(
headers_sent
(
)
)
{
return
;
}
if
(
$
global
)
{
$
cookies
=
array_replace
(
static
::
globalCookies
(
)
,
$
this
->
cookies
)
;
$
headers
=
array_replace
(
static
::
globalHeaders
(
)
,
$
this
->
headers
)
;
}
else
{
$
cookies
=
$
this
->
cookies
;
$
headers
=
$
this
->
headers
;
}
// Set the cookies first.
foreach
(
$
cookies
as
$
name
=>
$
value
)
{
setcookie
(
$
name
,
$
value
[
0
]
,
$
value
[
1
]
,
$
value
[
2
]
!==
$
value
[
2
]
:
$
this
->
defaultCookiePath
,
$
value
[
3
]
!==
$
value
[
3
]
:
$
this
->
defaultCookieDomain
,
$
value
[
4
]
,
$
value
[
5
]
)
;
}
// Set the response code.
header
(
static
::
statusMessage
(
$
this
->
status
,
true
)
,
true
,
$
this
->
status
)
;
$
headers
=
array_filter
(
$
headers
)
;
// The content type is a special case.
if
(
isset
(
$
headers
[
'Content-Type'
]
)
)
{
$
contentType
=
(
array
)
$
headers
[
'Content-Type'
]
;
header
(
'Content-Type: '
.
reset
(
$
contentType
)
.
'; charset=utf8'
,
true
)
;
unset
(
$
headers
[
'Content-Type'
]
)
;
}
// Flush the rest of the headers.
foreach
(
$
headers
as
$
name
=>
$
value
)
{
foreach
(
(
array
)
$
value
as
$
hvalue
)
{
header
(
"$name: $hvalue"
,
false
)
;
}
}
}

Flush the headers to the browser.

@param bool $global Whether or not to merge the global headers with this response.


protected function alterTableMigrate($tablename, array $alterDef, array $options = []) {
        $currentDef = $this->getTableDef($tablename);

        // Merge the table definitions if we aren't dropping stuff.
        if (!val(Db::OPTION_DROP, $options)) {
            $tableDef = $this->mergeTableDefs($currentDef, $alterDef);
        } else {
            $tableDef = $alterDef['def'];
        }

        // Drop all of the indexes on the current table.
        foreach (val('indexes', $currentDef, []) as $indexDef) {
            if (val('type', $indexDef, Db::INDEX_IX) === Db::INDEX_IX) {
                $this->dropIndex($indexDef['name']);
            }
        }

        $tmpTablename = $tablename.'_'.time();

        // Rename the current table.
        $this->renameTable($tablename, $tmpTablename);

        // Create the new table.
        $this->createTable($tablename, $tableDef, $options);

        // Figure out the columns that we can insert.
        $columns = array_keys(array_intersect_key($tableDef['columns'], $currentDef['columns']));

        // Build the insert/select statement.
        $sql = 'insert into '.$this->backtick($this->px.$tablename)."\n".
            $this->bracketList($columns, '`')."\n".
            $this->buildSelect($tmpTablename, [], ['columns' => $columns]);

        $this->query($sql, Db::QUERY_WRITE);

        // Drop the temp table.
        $this->dropTable($tmpTablename);
    }

Alter a table by creating a new table and copying the old table's data to it.

@param string $tablename The table to alter.
@param array $alterDef The new definition.
@param array $options An array of options for the migration.

Alter a table by creating a new table and copying the old table s data to it .


protected function renameTable($oldname, $newname) {
        $renameSql = 'alter table '.
            $this->backtick($this->px.$oldname).
            ' rename to '.
            $this->backtick($this->px.$newname);
        $this->query($renameSql, Db::QUERY_WRITE);
    }

protected
function
renameTable
(
$
oldname
,
$
newname
)
{
$
renameSql
=
'alter table '
.
$
this
->
backtick
(
$
this
->
px
.
$
oldname
)
.
' rename to '
.
$
this
->
backtick
(
$
this
->
px
.
$
newname
)
;
$
this
->
query
(
$
renameSql
,
Db
::
QUERY_WRITE
)
;
}

Rename a table.

@param string $oldname The old name of the table.
@param string $newname The new name of the table.


protected function dropIndex($indexName) {
        $sql = 'drop index if exists '.
            $this->backtick($indexName);
        $this->query($sql, Db::QUERY_DEFINE);
    }

protected
function
dropIndex
(
$
indexName
)
{
$
sql
=
'drop index if exists '
.
$
this
->
backtick
(
$
indexName
)
;
$
this
->
query
(
$
sql
,
Db
::
QUERY_DEFINE
)
;
}

Drop an index.

@param string $indexName The name of the index to drop.


public function createIndex($tablename, array $indexDef, $options = []) {
        $sql = 'create '.
            (val('type', $indexDef) === Db::INDEX_UNIQUE ? 'unique ' : '').
            'index '.
            (val(Db::OPTION_IGNORE, $options) ? 'if not exists ' : '').
            $this->buildIndexName($tablename, $indexDef).
            ' on '.
            $this->backtick($this->px.$tablename).
            $this->bracketList($indexDef['columns'], '`');

        $this->query($sql, Db::QUERY_DEFINE);
    }

public
function
createIndex
(
$
tablename
,
array
$
indexDef
,
$
options
=
[
]
)
{
$
sql
=
'create '
.
(
val
(
'type'
,
$
indexDef
)
===
Db
::
INDEX_UNIQUE
'unique '
:
''
)
.
'index '
.
(
val
(
Db
::
OPTION_IGNORE
,
$
options
)
'if not exists '
:
''
)
.
$
this
->
buildIndexName
(
$
tablename
,
$
indexDef
)
.
' on '
.
$
this
->
backtick
(
$
this
->
px
.
$
tablename
)
.
$
this
->
bracketList
(
$
indexDef
[
'columns'
]
,
'`'
)
;
$
this
->
query
(
$
sql
,
Db
::
QUERY_DEFINE
)
;
}

Create an index.

@param string $tablename The name of the table to create the index on.
@param array $indexDef The index definition.
@param array $options Additional options for the index creation.


protected function forceType($value, $type) {
        $type = strtolower($type);

        if ($type === 'null') {
            return null;
        } elseif (in_array($type, ['int', 'integer', 'tinyint', 'smallint',
            'mediumint', 'bigint', 'unsigned big int', 'int2', 'int8', 'boolean'])) {
            return force_int($value);
        } elseif (in_array($type, ['real', 'double', 'double precision', 'float',
            'numeric', 'decimal(10,5)'])) {
            return floatval($value);
        } else {
            return (string)$value;
        }
    }

protected
function
forceType
(
$
value
,
$
type
)
{
$
type
=
strtolower
(
$
type
)
;
if
(
$
type
===
'null'
)
{
return
;
}
elseif
(
in_array
(
$
type
,
[
'int'
,
'integer'
,
'tinyint'
,
'smallint'
,
'mediumint'
,
'bigint'
,
'unsigned big int'
,
'int2'
,
'int8'
,
'boolean'
]
)
)
{
return
force_int
(
$
value
)
;
}
elseif
(
in_array
(
$
type
,
[
'real'
,
'double'
,
'double precision'
,
'float'
,
'numeric'
,
'decimal(10,5)'
]
)
)
{
return
floatval
(
$
value
)
;
}
else
{
return
(
string
)
$
value
;
}
}

Force a value into the appropriate php type based on its Sqlite type.

@param mixed $value The value to force.
@param string $type The sqlite type name.
@return mixed Returns $value cast to the appropriate type.

Force a value into the appropriate php type based on its Sqlite type .


protected function getPKValue($tablename, array $row, $quick = false) {
        if ($quick && isset($row[$tablename.'ID'])) {
            return [$tablename.'ID' => $row[$tablename.'ID']];
        }

        $tdef = $this->getTableDef($tablename);
        if (isset($tdef['indexes'][Db::INDEX_PK]['columns'])) {
            $pkColumns = array_flip($tdef['indexes'][Db::INDEX_PK]['columns']);
            $cols = array_intersect_key($row, $pkColumns);
            if (count($cols) === count($pkColumns)) {
                return $cols;
            }
        }

        return null;
    }

protected function getPKValue ( $ tablename , array $ row , $ quick = false ) { if ( $ quick && isset ( $ row [ $ tablename . 'ID' ] ) ) { return [ $ tablename . 'ID' => $ row [ $ tablename . 'ID' ] ] ; } $ tdef = $ this -> getTableDef ( $ tablename ) ; if ( isset ( $ tdef [ 'indexes' ] [ Db :: INDEX_PK ] [ 'columns' ] ) ) { $ pkColumns = array_flip ( $ tdef [ 'indexes' ] [ Db :: INDEX_PK ] [ 'columns' ] ) ; $ cols = array_intersect_key ( $ row , $ pkColumns ) ; if ( count ( $ cols ) === count ( $ pkColumns ) ) { return $ cols ; } } return null ; }

Get the primary or secondary keys from the given rows.

@param string $tablename The name of the table.
@param array $row The row to examine.
@param bool $quick Whether or not to quickly look for <tablename>ID for the primary key.
@return array|null Returns the primary keys and values from {@link $rows} or null if the primary key isn't found.

Get the primary or secondary keys from the given rows .


protected function getTablenames() {
        // Get the table names.
        $tables = (array)$this->get(
            'sqlite_master',
            [
                'type' => 'table',
                'name' => [Db::OP_LIKE => addcslashes($this->px, '_%').'%']
            ],
            [
                'columns' => ['name'],
                'escapeTable' => false
            ]
        );

        // Strip the table prefixes.
        $tables = array_map(function ($name) {
            return ltrim_substr($name, $this->px);
        }, array_column($tables, 'name'));

        return $tables;
    }

protected
function
getTablenames
(
)
{
// Get the table names.
$
tables
=
(
array
)
$
this
->
get
(
'sqlite_master'
,
[
'type'
=>
'table'
,
'name'
=>
[
Db
::
OP_LIKE
=>
addcslashes
(
$
this
->
px
,
'_%'
)
.
'%'
]
]
,
[
'columns'
=>
[
'name'
]
,
'escapeTable'
=>
false
]
)
;
// Strip the table prefixes.
$
tables
=
array_map
(
function
(
$
name
)
{
return
ltrim_substr
(
$
name
,
$
this
->
px
)
;
}
,
array_column
(
$
tables
,
'name'
)
)
;
return
$
tables
;
}

Get the all of tablenames in the database.

@return array Returns an array of table names with prefixes stripped.

Get the all of tablenames in the database .


public static function create($pattern, $callback) {
        if (is_callable($callback)) {
            $route = new CallbackRoute($pattern, $callback);
        } else {
            $route = new ResourceRoute($pattern, $callback);
        }
        return $route;
    }

public static function create ( $ pattern , $ callback ) { if ( is_callable ( $ callback ) ) { $ route = new CallbackRoute ( $ pattern , $ callback ) ; } else { $ route = new ResourceRoute ( $ pattern , $ callback ) ; } return $ route ; }

Create and return a new route.

@param string $pattern The pattern for the route.
@param callable|string $callback Either a callback to map the route to or a string representing
a format for {@link sprintf()}.
@return \Garden\Route Returns the new route.


public function conditions($conditions = null) {
        if ($this->conditions === null) {
            $this->conditions = [];
        }

        if (is_array($conditions)) {
            $conditions = array_change_key_case($conditions);

            $this->conditions = array_replace(
                $this->conditions,
                $conditions
            );
            return $this;
        }

        return $this->conditions;
    }

public function conditions ( $ conditions = null ) { if ( $ this -> conditions === null ) { $ this -> conditions = [ ] ; } if ( is_array ( $ conditions ) ) { $ conditions = array_change_key_case ( $ conditions ) ; $ this -> conditions = array_replace ( $ this -> conditions , $ conditions ) ; return $ this ; } return $ this -> conditions ; }

Gets or sets the route's conditions.

@param array|null $conditions An array of conditions to set.
@return Route|array


public function methods($methods = null) {
        if ($methods === null) {
            return $this->methods;
        }

        $this->methods = array_map('strtoupper', (array)$methods);
        return $this;
    }

public function methods ( $ methods = null ) { if ( $ methods === null ) { return $ this -> methods ; } $ this -> methods = array_map ( 'strtoupper' , ( array ) $ methods ) ; return $ this ; }

Gets or sets the allowed http methods for this route.

@param array|string|null $methods Set a new set of allowed methods or pass null to get the current methods.
@return Route|array Returns the current methods or `$this` for fluent calls.

Gets or sets the allowed http methods for this route .


public function mappings($mappings = null) {
        if ($this->mappings === null) {
            $this->mappings = [];
        }

        if (is_array($mappings)) {
            $mappings = array_change_key_case($mappings);

            $this->mappings = array_replace(
                $this->mappings,
                $mappings
            );
            return $this;
        }

        return $this->mappings;
    }

public function mappings ( $ mappings = null ) { if ( $ this -> mappings === null ) { $ this -> mappings = [ ] ; } if ( is_array ( $ mappings ) ) { $ mappings = array_change_key_case ( $ mappings ) ; $ this -> mappings = array_replace ( $ this -> mappings , $ mappings ) ; return $ this ; } return $ this -> mappings ; }

Gets or sets the mappings array that maps parameter names to mappings.

@param array|null $mappings An array of mappings to set.
@return Route|array Returns the current mappings or `$this` for fluent calls.

Gets or sets the mappings array that maps parameter names to mappings .


public static function globalMappings($mappings = null) {
        if (self::$globalMappings === null) {
            self::$globalMappings = [];
        }

        if (is_array($mappings)) {
            $mappings = array_change_key_case($mappings);

            self::$globalMappings = array_replace(
                self::$globalMappings,
                $mappings
            );
        }

        return self::$globalMappings;
    }

public static function globalMappings ( $ mappings = null ) { if ( self :: $ globalMappings === null ) { self :: $ globalMappings = [ ] ; } if ( is_array ( $ mappings ) ) { $ mappings = array_change_key_case ( $ mappings ) ; self :: $ globalMappings = array_replace ( self :: $ globalMappings , $ mappings ) ; } return self :: $ globalMappings ; }

Gets or sets the global mappings array that maps parameter names to mappings.

@param array|null $mappings An array of mappings to set.
@return array Returns the current global mappings.

Gets or sets the global mappings array that maps parameter names to mappings .


protected function isMapped($name) {
        $name = strtolower($name);
        return isset($this->mappings[$name]) || isset(self::$globalMappings[$name]);
    }

protected function isMapped ( $ name ) { $ name = strtolower ( $ name ) ; return isset ( $ this -> mappings [ $ name ] ) || isset ( self :: $ globalMappings [ $ name ] ) ; }

Determine whether or not a parameter is mapped to special request data.

@param string $name The name of the parameter to check.
@return bool Returns true if the parameter is mapped, false otherwise.

Determine whether or not a parameter is mapped to special request data .


protected function mappedData($name, Request $request) {
        $name = strtolower($name);

        if (isset($this->mappings[$name])) {
            $mapping = $this->mappings[$name];
        } elseif (isset(self::$globalMappings[$name])) {
            $mapping = self::$globalMappings[$name];
        } else {
            return null;
        }

        switch (strtolower($mapping)) {
            case self::MAP_DATA:
                $result = $request->getData();
                break;
            case self::MAP_INPUT:
                $result = $request->getInput();
                break;
            case self::MAP_QUERY:
                $result = $request->getQuery();
                break;
            default:
                return null;
        }
        return $result;
    }

protected function mappedData ( $ name , Request $ request ) { $ name = strtolower ( $ name ) ; if ( isset ( $ this -> mappings [ $ name ] ) ) { $ mapping = $ this -> mappings [ $ name ] ; } elseif ( isset ( self :: $ globalMappings [ $ name ] ) ) { $ mapping = self :: $ globalMappings [ $ name ] ; } else { return null ; } switch ( strtolower ( $ mapping ) ) { case self :: MAP_DATA : $ result = $ request -> getData ( ) ; break ; case self :: MAP_INPUT : $ result = $ request -> getInput ( ) ; break ; case self :: MAP_QUERY : $ result = $ request -> getQuery ( ) ; break ; default : return null ; } return $ result ; }

Get the mapped data for a parameter.

@param string $name The name of the parameter.
@param Request $request The {@link Request} to get the data from.
@return array|null Returns the mapped data or null if there is no data.


protected function matchesMethods(Request $request) {
        if (empty($this->methods)) {
            return true;
        }
        return in_array($request->getMethod(), $this->methods);
    }

protected function matchesMethods ( Request $ request ) { if ( empty ( $ this -> methods ) ) { return true ; } return in_array ( $ request -> getMethod ( ) , $ this -> methods ) ; }

Tests whether or not a route matches the allowed methods for this route.

@param Request $request The request to test.
@return bool Returns `true` if the route allows the method, otherwise `false`.

Tests whether or not a route matches the allowed methods for this route .


public function pattern($pattern = null) {
        if ($pattern !== null) {
            $this->pattern = '/'.ltrim($pattern, '/');
        }
        return $this->pattern;
    }

public function pattern ( $ pattern = null ) { if ( $ pattern !== null ) { $ this -> pattern = '/' . ltrim ( $ pattern , '/' ) ; } return $ this -> pattern ; }

Gets or sets the route pattern.

@param string|null $pattern The route pattern.
@return string Returns the pattern.


public function dispatch(Request $request, array &$args) {
        $callback = $args['callback'];
        $callback_args = reflect_args($callback, $args['args']);

        $result = call_user_func_array($callback, $callback_args);
        return $result;
    }

public function dispatch ( Request $ request , array & $ args ) { $ callback = $ args [ 'callback' ] ; $ callback_args = reflect_args ( $ callback , $ args [ 'args' ] ) ; $ result = call_user_func_array ( $ callback , $ callback_args ) ; return $ result ; }

Dispatch the matched route and call its callback.

@param Request $request The request to dispatch.
@param array &$args The arguments returned from {@link CallbackRoute::dispatch()}.
@return mixed Returns the result of the callback.

Dispatch the matched route and call its callback .


protected function getPatternRegex($pattern) {
        $result = preg_replace_callback('`{([^}]+)}`i', function ($match) {
            if (preg_match('`(.*?)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(.*?)`', $match[1], $matches)) {
                $before = preg_quote($matches[1], '`');
                $param = $matches[2];
                $after = preg_quote($matches[3], '`');
            } else {
                throw new \Exception("Invalid route parameter: $match[1].", 500);
            }

            $param_pattern = val($param, $this->conditions, val($param, self::$globalConditions, '[^/]+?'));
            $result = "(?<$param>$before{$param_pattern}$after)";

            return $result;
        }, $pattern);

        $result = '`^'.$result.'$`i';
        return $result;
    }

Convert a path pattern into its regex.

@param string $pattern The route pattern to convert into a regular expression.
@return string Returns the regex pattern for the route.


public function query($sql, $type = Db::QUERY_READ, $options = []) {
        $mode = val(Db::OPTION_MODE, $options, $this->mode);

        if ($mode & Db::MODE_ECHO) {
            echo trim($sql, "\n;").";\n\n";
        }
        if ($mode & Db::MODE_SQL) {
            return $sql;
        }

        $result = null;
        if ($mode & Db::MODE_EXEC) {
            $result = $this->pdo()->query($sql);

            if ($type == Db::QUERY_READ) {
                $result->setFetchMode(PDO::FETCH_ASSOC);
                $result = $result->fetchAll();
                $this->rowCount = count($result);
            } elseif (is_object($result) && method_exists($result, 'rowCount')) {
                $this->rowCount = $result->rowCount();
                $result = $this->rowCount;
            }
        } elseif ($mode & Db::MODE_PDO) {
            /* @var \PDOStatement $result */
            $result = $this->pdo()->prepare($sql);
        }

        return $result;
    }

public
function
query
(
$
sql
,
$
type
=
Db
::
QUERY_READ
,
$
options
=
[
]
)
{
$
mode
=
val
(
Db
::
OPTION_MODE
,
$
options
,
$
this
->
mode
)
;
if
(
$
mode
&
Db
::
MODE_ECHO
)
{
echo
trim
(
$
sql
,
"\n;"
)
.
";\n\n"
;
}
if
(
$
mode
&
Db
::
MODE_SQL
)
{
return
$
sql
;
}
$
result
=
;
if
(
$
mode
&
Db
::
MODE_EXEC
)
{
$
result
=
$
this
->
pdo
(
)
->
query
(
$
sql
)
;
if
(
$
type
==
Db
::
QUERY_READ
)
{
$
result
->
setFetchMode
(
PDO
::
FETCH_ASSOC
)
;
$
result
=
$
result
->
fetchAll
(
)
;
$
this
->
rowCount
=
count
(
$
result
)
;
}
elseif
(
is_object
(
$
result
)
&&
method_exists
(
$
result
,
'rowCount'
)
)
{
$
this
->
rowCount
=
$
result
->
rowCount
(
)
;
$
result
=
$
this
->
rowCount
;
}
}
elseif
(
$
mode
&
Db
::
MODE_PDO
)
{
/* @var \PDOStatement $result */
$
result
=
$
this
->
pdo
(
)
->
prepare
(
$
sql
)
;
}
return
$
result
;
}

Execute a query on the database.

@param string $sql The sql query to execute.
@param string $type One of the Db::QUERY_* constants.

Db::QUERY_READ
: The query reads from the database.

Db::QUERY_WRITE
: The query writes to the database.

Db::QUERY_DEFINE
: The query alters the structure of the datbase.

@param array $options Additional options for the query.

Db::OPTION_MODE
: Override {@link Db::$mode}.

@return array|string|PDOStatement|int Returns the result of the query.

array
: Returns an array when reading from the database and the mode is {@link Db::MODE_EXEC}.
string
: Returns the sql query when the mode is {@link Db::MODE_SQL}.
PDOStatement
: Returns a {@link \PDOStatement} when the mode is {@link Db::MODE_PDO}.
int
: Returns the number of rows affected when performing an update or an insert.


public function buildSelect($table, array $where, array $options = []) {
        $sql = '';

        // Build the select clause.
        if (isset($options['columns'])) {
            $columns = array();
            foreach ($options['columns'] as $value) {
                $columns[] = $this->backtick($value);
            }
            $sql .= 'select '.implode(', ', $columns);
        } else {
            $sql .= "select *";
        }

        // Build the from clause.
        if (val('escapeTable', $options, true)) {
            $sql .= "\nfrom ".$this->backtick($this->px.$table);
        } else {
            $sql .= "\nfrom $table";
        }

        // Build the where clause.
        $whereString = $this->buildWhere($where, Db::OP_AND);
        if ($whereString) {
            $sql .= "\nwhere ".$whereString;
        }

        // Build the order.
        if (isset($options['order'])) {
            $order = array_quick($options['order'], Db::ORDER_ASC);
            $orders = array();
            foreach ($order as $key => $value) {
                switch ($value) {
                    case Db::ORDER_ASC:
                    case Db::ORDER_DESC:
                        $orders[] = $this->backtick($key)." $value";
                        break;
                    default:
                        trigger_error("Invalid sort direction '$value' for column '$key'.", E_USER_WARNING);
                }
            }

            $sql .= "\norder by ".implode(', ', $orders);
        }

        // Build the limit, offset.
        $limit = 10;
        if (isset($options['limit'])) {
            $limit = (int)$options['limit'];
            $sql .= "\nlimit $limit";
        }

        if (isset($options['offset'])) {
            $sql .= ' offset '.((int)$options['offset']);
        } elseif (isset($options['page'])) {
            $offset = $limit * ($options['page'] - 1);
            $sql .= ' offset '.$offset;
        }

        return $sql;
    }

Build a sql select statement.

@param string $table The name of the main table.
@param array $where The where filter.
@param array $options An array of additional query options.
@return string Returns the select statement as a string.
@see Db::get()


public function bracketList($row, $quote = "'") {
        switch ($quote) {
            case "'":
                $row = array_map([$this->pdo(), 'quote'], $row);
                $quote = '';
                break;
            case '`':
                $row = array_map([$this, 'backtick'], $row);
                $quote = '';
                break;
        }

        return "($quote".implode("$quote, $quote", $row)."$quote)";
    }

public
function
bracketList
(
$
row
,
$
quote
=
"'"
)
{
switch
(
$
quote
)
{
case
"'"
:
$
row
=
array_map
(
[
$
this
->
pdo
(
)
,
'quote'
]
,
$
row
)
;
$
quote
=
''
;
break
;
case
'`'
:
$
row
=
array_map
(
[
$
this
,
'backtick'
]
,
$
row
)
;
$
quote
=
''
;
break
;
}
return
"($quote"
.
implode
(
"$quote, $quote"
,
$
row
)
.
"$quote)"
;
}

Convert an array into a bracketed list suitable for MySQL clauses.

@param array $row The row to expand.
@param string $quote The quotes to surroud the items with. There are two special cases.
' (single quote)
: The row will be passed through {@link PDO::quote()}.
` (backticks)
: The row will be passed through {@link MySqlDb::backtick()}.
@return string Returns the bracket list.

Convert an array into a bracketed list suitable for MySQL clauses .


protected function buildInsert($tablename, array $row, $quotevals = true, $options = []) {
        if (val(Db::OPTION_UPSERT, $options)) {
            return $this->buildUpsert($tablename, $row, $quotevals, $options);
        } elseif (val(Db::OPTION_IGNORE, $options)) {
            $sql = 'insert ignore ';
        } elseif (val(Db::OPTION_REPLACE, $options)) {
            $sql = 'replace ';
        } else {
            $sql = 'insert ';
        }
        $sql .= $this->backtick($this->px.$tablename);

        // Add the list of values.
        $sql .=
            "\n".$this->bracketList(array_keys($row), '`').
            "\nvalues".$this->bracketList($row, $quotevals ? "'" : '');

        return $sql;
    }

protected
function
buildInsert
(
$
tablename
,
array
$
row
,
$
quotevals
=
true
,
$
options
=
[
]
)
{
if
(
val
(
Db
::
OPTION_UPSERT
,
$
options
)
)
{
return
$
this
->
buildUpsert
(
$
tablename
,
$
row
,
$
quotevals
,
$
options
)
;
}
elseif
(
val
(
Db
::
OPTION_IGNORE
,
$
options
)
)
{
$
sql
=
'insert ignore '
;
}
elseif
(
val
(
Db
::
OPTION_REPLACE
,
$
options
)
)
{
$
sql
=
'replace '
;
}
else
{
$
sql
=
'insert '
;
}
$
sql
.=
$
this
->
backtick
(
$
this
->
px
.
$
tablename
)
;
// Add the list of values.
$
sql
.=
"\n"
.
$
this
->
bracketList
(
array_keys
(
$
row
)
,
'`'
)
.
"\nvalues"
.
$
this
->
bracketList
(
$
row
,
$
quotevals
"'"
:
''
)
;
return
$
sql
;
}

Build an insert statement.

@param string $tablename The name of the table to insert to.
@param array $row The row to insert.
@param bool $quotevals Whether or not to quote the values.
@param array $options An array of options for the insert. See {@link Db::insert} for the options.
@return string Returns the the sql string of the insert statement.


protected function buildUpsert($tablename, array $row, $quotevals = true, $options = []) {
        // Build the initial insert statement first.
        unset($options[Db::OPTION_UPSERT]);
        $sql = $this->buildInsert($tablename, $row, $quotevals, $options);

        // Add the duplicate key stuff.
        $updates = [];
        foreach ($row as $key => $value) {
            $updates[] = $this->backtick($key).' = values('.$this->backtick($key).')';
        }
        $sql .= "\non duplicate key update ".implode(', ', $updates);

        return $sql;
    }

Build an upsert statement.

An upsert statement is an insert on duplicate key statement in MySQL.

@param string $tablename The name of the table to update.
@param array $row The row to insert or update.
@param bool $quotevals Whether or not to quote the values in the row.
@param array $options An array of additional query options.
@return string Returns the upsert statement as a string.


protected function columnDefString($name, array $def) {
        $result = $this->backtick($name).' '.$this->columnTypeString($def['type']);

        if (val('required', $def)) {
            $result .= ' not null';
        }

        if (isset($def['default'])) {
            $result .= ' default '.$this->quoteVal($def['default']);
        }

        if (val('autoincrement', $def)) {
            $result .= ' auto_increment';
        }

        return $result;
    }

protected
function
columnDefString
(
$
name
,
array
$
def
)
{
$
result
=
$
this
->
backtick
(
$
name
)
.
' '
.
$
this
->
columnTypeString
(
$
def
[
'type'
]
)
;
if
(
val
(
'required'
,
$
def
)
)
{
$
result
.=
' not null'
;
}
if
(
isset
(
$
def
[
'default'
]
)
)
{
$
result
.=
' default '
.
$
this
->
quoteVal
(
$
def
[
'default'
]
)
;
}
if
(
val
(
'autoincrement'
,
$
def
)
)
{
$
result
.=
' auto_increment'
;
}
return
$
result
;
}

Construct a column definition string from an array defintion.

@param string $name The name of the column.
@param array $def The column definition.
@return string Returns a string representing the column definition.

Construct a column definition string from an array defintion .


protected function indexDefString($tablename, array $def) {
        $indexName = $this->backtick($this->buildIndexName($tablename, $def));
        switch (val('type', $def, Db::INDEX_IX)) {
            case Db::INDEX_IX:
                return "index $indexName ".$this->bracketList($def['columns'], '`');
            case Db::INDEX_UNIQUE:
                return "unique $indexName ".$this->bracketList($def['columns'], '`');
            case Db::INDEX_PK:
                return "primary key ".$this->bracketList($def['columns'], '`');
        }
        return null;
    }

protected
function
indexDefString
(
$
tablename
,
array
$
def
)
{
$
indexName
=
$
this
->
backtick
(
$
this
->
buildIndexName
(
$
tablename
,
$
def
)
)
;
switch
(
val
(
'type'
,
$
def
,
Db
::
INDEX_IX
)
)
{
case
Db
::
INDEX_IX
:
return
"index $indexName "
.
$
this
->
bracketList
(
$
def
[
'columns'
]
,
'`'
)
;
case
Db
::
INDEX_UNIQUE
:
return
"unique $indexName "
.
$
this
->
bracketList
(
$
def
[
'columns'
]
,
'`'
)
;
case
Db
::
INDEX_PK
:
return
"primary key "
.
$
this
->
bracketList
(
$
def
[
'columns'
]
,
'`'
)
;
}
return
;
}

Return the SDL string that defines an index.

@param string $tablename The name of the table that the index is on.
@param array $def The index defintion. This definition should have the following keys.

columns
: An array of columns in the index.
type
: One of "index", "unique", or "primary".
@return null|string Returns the index string or null if the index is not correct.

Return the SDL string that defines an index .


protected function getColumnOrders($cdefs) {
        $orders = array_flip(array_keys($cdefs));

        $prev = ' first';
        foreach ($orders as $cname => &$value) {
            $value = $prev;
            $prev = ' after '.$this->backtick($cname);
        }
        return $orders;
    }

protected
function
getColumnOrders
(
$
cdefs
)
{
$
orders
=
array_flip
(
array_keys
(
$
cdefs
)
)
;
$
prev
=
' first'
;
foreach
(
$
orders
as
$
cname
=>
&
$
value
)
{
$
value
=
$
prev
;
$
prev
=
' after '
.
$
this
->
backtick
(
$
cname
)
;
}
return
$
orders
;
}

Get an array of column orders so that added columns can be slotted into their correct spot.

@param array $cdefs An array of column definitions.
@return array Returns an array of column orders suitable for an `alter table` statement.

Get an array of column orders so that added columns can be slotted into their correct spot .


protected function getFormatsFromDb($db) {
        $tables = $db->tables(true);
        $formats = $this->fixFormats($tables);
        return $formats;
    }

protected function getFormatsFromDb ( $ db ) { $ tables = $ db -> tables ( true ) ; $ formats = $ this -> fixFormats ( $ tables ) ; return $ formats ; }

Get the translation format from the database.

@param Db $db
@return type

Get the translation format from the database .


protected function translateRow($row, $format) {
        // Apply the row filter.
        if (isset($format['rowfilter'])) {
            call_user_func_array($format['rowfilter'], array(&$row));
        }

        $result = array();
        foreach ($format['columns'] as $key => $cdef) {
            if (array_key_exists($cdef['sourcecolumn'], $row))
                $value = $row[$cdef['sourcecolumn']];
            else
                $value = $cdef['default'];

            if (isset($cdef['filter'])) {
                $value = call_user_func($cdef['filter'], $value, $key, $row);
            }

            $result[$cdef[0]] = $value;
        }
        return $result;
    }

protected
function
translateRow
(
$
row
,
$
format
)
{
// Apply the row filter.
if
(
isset
(
$
format
[
'rowfilter'
]
)
)
{
call_user_func_array
(
$
format
[
'rowfilter'
]
,
array
(
&
$
row
)
)
;
}
$
result
=
array
(
)
;
foreach
(
$
format
[
'columns'
]
as
$
key
=>
$
cdef
)
{
if
(
array_key_exists
(
$
cdef
[
'sourcecolumn'
]
,
$
row
)
)
$
value
=
$
row
[
$
cdef
[
'sourcecolumn'
]
]
;
else
$
value
=
$
cdef
[
'default'
]
;
if
(
isset
(
$
cdef
[
'filter'
]
)
)
{
$
value
=
call_user_func
(
$
cdef
[
'filter'
]
,
$
value
,
$
key
,
$
row
)
;
}
$
result
[
$
cdef
[
0
]
]
=
$
value
;
}
return
$
result
;
}

Translate a row from one row format to another.

@param array $row The data to translate.
@param array $format The translation format.
@return array The translated row.

Translate a row from one row format to another .


public function verify($password, $hash) {
        if (strlen($hash) == 34) {
            return ($this->cryptPrivate($password, $hash) === $hash) ? true : false;
        }

        return (md5($password) === $hash) ? true : false;
    }

public function verify ( $ password , $ hash ) { if ( strlen ( $ hash ) == 34 ) { return ( $ this -> cryptPrivate ( $ password , $ hash ) === $ hash ) ? true : false ; } return ( md5 ( $ password ) === $ hash ) ? true : false ; }

Check for a correct password.

@param string $password The password in plain text.
@param string $hash The stored password hash.
@return bool Returns true if the password is correct, false if not.