public function save($messages, $filePath = null)
    {
        if (false === ($fileHandle = @fopen($filePath, 'wb'))) {
            throw new Exception('Unable to write file "' . $filePath . '".');
        }
        if (false === @flock($fileHandle, LOCK_EX)) {
            throw new Exception('Unable to lock file "' . $filePath . '" for reading.');
        }

        // magic
        if ($this->useBigEndian) {
            $this->writeBytes($fileHandle, pack('c*', 0x95, 0x04, 0x12, 0xde)); // -107
        } else {
            $this->writeBytes($fileHandle, pack('c*', 0xde, 0x12, 0x04, 0x95)); // -34
        }

        // revision
        $this->writeInteger($fileHandle, 0);

        // message count
        $messageCount = count($messages);
        $this->writeInteger($fileHandle, $messageCount);

        // offset of source message table
        $offset = 28;
        $this->writeInteger($fileHandle, $offset);
        $offset += $messageCount * 8;
        $this->writeInteger($fileHandle, $offset);

        // hashtable size, omitted
        $this->writeInteger($fileHandle, 0);
        $offset += $messageCount * 8;
        $this->writeInteger($fileHandle, $offset);

        // length and offsets for source messages
        foreach (array_keys($messages) as $id) {
            $length = strlen($id);
            $this->writeInteger($fileHandle, $length);
            $this->writeInteger($fileHandle, $offset);
            $offset += $length + 1;
        }

        // length and offsets for target messages
        foreach ($messages as $message) {
            $length = strlen($message);
            $this->writeInteger($fileHandle, $length);
            $this->writeInteger($fileHandle, $offset);
            $offset += $length + 1;
        }

        // source messages
        foreach (array_keys($messages) as $id) {
            $this->writeString($fileHandle, $id);
        }

        // target messages
        foreach ($messages as $message) {
            $this->writeString($fileHandle, $message);
        }

        @flock($fileHandle, LOCK_UN);
        @fclose($fileHandle);
    }

Saves messages to an MO file.
@param array       $messages message translations. Array keys are source messages and array values are
translated messages: source message => translated message. Note if the message has a context,
the message ID must be prefixed with the context with chr(4) as the separator.
@param string|null $filePath file path
@throws Exception if unable to save the MO file


public static function find($list, $value, $delimiter = ',')
  {
    return ArrayTools::find(static::toArray($list, $delimiter), $value);
  }

public static function find ( $ list , $ value , $ delimiter = ',' ) { return ArrayTools :: find ( static :: toArray ( $ list , $ delimiter ) , $ value ) ; }

Recherche la position d'une valeur dans la liste

@param  string $list       Liste source
@param  string $value      Valeur à rechercher
@param  string $delimiter  Séparateur
@return int|boolean        Position dans la liste

Recherche la position d une valeur dans la liste


public function findWith($with, &$models)
    {
        $primaryModel = reset($models);
        if (!$primaryModel instanceof ActiveRecordInterface) {
            /* @var $modelClass ActiveRecordInterface */
            $modelClass = $this->modelClass;
            $primaryModel = $modelClass::instance();
        }
        $relations = $this->normalizeRelations($primaryModel, $with);
        /* @var $relation ActiveQuery */
        $promises = [];
        foreach ($relations as $name => $relation) {
            if ($relation->asArray === null) {
                // inherit asArray from primary query
                $relation->asArray($this->asArray);
            }
            $promises[] = $relation->populateRelation($name, $models);
        }
        return !empty($promises) ? all($promises) : resolve(true);
    }

Finds records corresponding to one or multiple relations and populates them into the primary models.
@param array                         $with a list of relations that this query should be performed with. Please
refer to [[with()]] for details about specifying this parameter.
@param array|ActiveRecordInterface[] $models the primary models (can be either AR instances or arrays)
@return \Reaction\Promise\ExtendedPromiseInterface

Finds records corresponding to one or multiple relations and populates them into the primary models .


public function read()
    {
        $this->next();
        if (!$this->valid()) {
            return false;
        }
        /** @var array|false $fetched */
        $fetched = $this->_command->fetchResultsRow($this->_row, CommandInterface::FETCH_ROW, $this->_fetchMode);
        return $fetched;
    }

public
function
read
(
)
{
$
this
->
next
(
)
;
if
(
!
$
this
->
valid
(
)
)
{
return
false
;
}
/** @var array|false $fetched */
$
fetched
=
$
this
->
_command
->
fetchResultsRow
(
$
this
->
_row
,
CommandInterface
::
FETCH_ROW
,
$
this
->
_fetchMode
)
;
return
$
fetched
;
}

Advances the reader to the next row in a result set.
@return array|false the current row, false if no more row available

Advances the reader to the next row in a result set .


public function readColumn($columnIndex)
    {
        $this->next();
        if (!$this->valid()) {
            return false;
        }
        return $this->_command->fetchResultsRow($this->_row, CommandInterface::FETCH_FIELD, CommandInterface::FETCH_MODE_ASSOC, $columnIndex);
    }

public function readColumn ( $ columnIndex ) { $ this -> next ( ) ; if ( ! $ this -> valid ( ) ) { return false ; } return $ this -> _command -> fetchResultsRow ( $ this -> _row , CommandInterface :: FETCH_FIELD , CommandInterface :: FETCH_MODE_ASSOC , $ columnIndex ) ; }

Returns a single column from the next row of a result set.
@param int $columnIndex zero-based column index
@return mixed the column of the current row, false if no more rows available

Returns a single column from the next row of a result set .


public function readObject($className = 'stdClass', $fields = [])
    {
        $this->next();
        if (!$this->valid()) {
            return false;
        }
        $obj = new $className($fields);
        foreach ($this->_row as $key => $value) {
            $obj->{$key} = $value;
        }
        return $obj;
    }

public function readObject ( $ className = 'stdClass' , $ fields = [ ] ) { $ this -> next ( ) ; if ( ! $ this -> valid ( ) ) { return false ; } $ obj = new $ className ( $ fields ) ; foreach ( $ this -> _row as $ key => $ value ) { $ obj -> { $ key } = $ value ; } return $ obj ; }

Returns an object populated with the next row of data.
@param string $className class name of the object to be created and populated
@param array $fields Elements of this array are passed to the constructor
@return mixed the populated object, false if no more row of data available

Returns an object populated with the next row of data .


public function readAll()
    {
        /** @var array $fetched */
        $fetched = $this->_command->fetchResults($this->_results, CommandInterface::FETCH_ALL, $this->_fetchMode);
        return $fetched;
    }

public
function
readAll
(
)
{
/** @var array $fetched */
$
fetched
=
$
this
->
_command
->
fetchResults
(
$
this
->
_results
,
CommandInterface
::
FETCH_ALL
,
$
this
->
_fetchMode
)
;
return
$
fetched
;
}

Reads the whole result set into an array.
@return array the result set (each array element represents a row of data).
An empty array will be returned if the result contains no row.

Reads the whole result set into an array .


public function getColumnCount()
    {
        if (empty($this->_results)) {
            return 0;
        }
        $results = $this->_results;
        $firstRow = reset($results);
        return count($firstRow);
    }

public function getColumnCount ( ) { if ( empty ( $ this -> _results ) ) { return 0 ; } $ results = $ this -> _results ; $ firstRow = reset ( $ results ) ; return count ( $ firstRow ) ; }

Returns the number of columns in the result set.
Note, even there's no row in the reader, this still gives correct column number.
@return int the number of columns in the result set.

Returns the number of columns in the result set . Note even there s no row in the reader this still gives correct column number .


protected function findConstraints(&$table)
    {
        $tableName = $this->quoteValue($table->name);
        $tableSchema = $this->quoteValue($table->schemaName);

        //We need to extract the constraints de hard way since:
        //http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us

        $sql = <<<SQL
select
    ct.conname as constraint_name,
    a.attname as column_name,
    fc.relname as foreign_table_name,
    fns.nspname as foreign_table_schema,
    fa.attname as foreign_column_name
from
    (SELECT ct.conname, ct.conrelid, ct.confrelid, ct.conkey, ct.contype, ct.confkey, generate_subscripts(ct.conkey, 1) AS s
       FROM pg_constraint ct
    ) AS ct
    inner join pg_class c on c.oid=ct.conrelid
    inner join pg_namespace ns on c.relnamespace=ns.oid
    inner join pg_attribute a on a.attrelid=ct.conrelid and a.attnum = ct.conkey[ct.s]
    left join pg_class fc on fc.oid=ct.confrelid
    left join pg_namespace fns on fc.relnamespace=fns.oid
    left join pg_attribute fa on fa.attrelid=ct.confrelid and fa.attnum = ct.confkey[ct.s]
where
    ct.contype='f'
    and c.relname={$tableName}
    and ns.nspname={$tableSchema}
order by
    fns.nspname, fc.relname, a.attnum
SQL;

        return $this->db->createCommand($sql)->queryAll()->then(
            function($_constraints) use (&$table) {
                $constraints = [];
                foreach ($_constraints as $constraint) {
                    if ($constraint['foreign_table_schema'] !== $this->defaultSchema) {
                        $foreignTable = $constraint['foreign_table_schema'] . '.' . $constraint['foreign_table_name'];
                    } else {
                        $foreignTable = $constraint['foreign_table_name'];
                    }
                    $name = $constraint['constraint_name'];
                    if (!isset($constraints[$name])) {
                        $constraints[$name] = [
                            'tableName' => $foreignTable,
                            'columns' => [],
                        ];
                    }
                    $constraints[$name]['columns'][$constraint['column_name']] = $constraint['foreign_column_name'];
                }

                foreach ($constraints as $name => $constraint) {
                    $table->foreignKeys[$name] = array_merge([$constraint['tableName']], $constraint['columns']);
                }
                return $table;
            }
        );
    }

Collects the foreign key column details for the given table.
@param TableSchema $table the table metadata
@return ExtendedPromiseInterface with TableSchema

Collects the foreign key column details for the given table .


protected function getServerVersionPromised() {
        $sql = "SELECT VERSION()";
        return $this->db->createCommand($sql)->queryScalar()->then(
            function($result) {
                $version = preg_match('/PostgreSQL\s?([\d\.\w]+)/', $result, $matches) ? $matches[1] : null;
                $this->_serverVersion = $version;
                return $version;
            }
        );
    }

protected
function
getServerVersionPromised
(
)
{
$
sql
=
"SELECT VERSION()"
;
return
$
this
->
db
->
createCommand
(
$
sql
)
->
queryScalar
(
)
->
then
(
function
(
$
result
)
{
$
version
=
preg_match
(
'/PostgreSQL\s?([\d\.\w]+)/'
,
$
result
,
$
matches
)
$
matches
[
1
]
:
;
$
this
->
_serverVersion
=
$
version
;
return
$
version
;
}
)
;
}

Get server version promised
@return ExtendedPromiseInterface


protected function publishRoutes() {
        $routes = $this->routes;
        $this->parseRoutesData();
        $this->dispatcher = $this->createDispatcher(function(\FastRoute\RouteCollector $r) use ($routes) {
            foreach ($routes as $routeRow) {
                $r->addRoute($routeRow['httpMethod'], $routeRow['route'], $routeRow['handler']);
            }
        });
    }

protected function publishRoutes ( ) { $ routes = $ this -> routes ; $ this -> parseRoutesData ( ) ; $ this -> dispatcher = $ this -> createDispatcher ( function ( \ FastRoute \ RouteCollector $ r ) use ( $ routes ) { foreach ( $ routes as $ routeRow ) { $ r -> addRoute ( $ routeRow [ 'httpMethod' ] , $ routeRow [ 'route' ] , $ routeRow [ 'handler' ] ) ; } } ) ; }

Register all defined routes in dispatcher


protected function parseRoutesData() {
        $routes = $this->routes;
        foreach ($routes as $routeData) {
            $path = $routeData['route'];
            $this->buildPathExpressions($path, true);
        }
        foreach ($this->_routePaths as &$routePaths) {
            $prevCnt = 0;
            ArrayHelper::multisort($routePaths, function($row) use (&$prevCnt) {
                return count($row['params']);
            }, SORT_DESC);
        }
    }

protected function parseRoutesData ( ) { $ routes = $ this -> routes ; foreach ( $ routes as $ routeData ) { $ path = $ routeData [ 'route' ] ; $ this -> buildPathExpressions ( $ path , true ) ; } foreach ( $ this -> _routePaths as & $ routePaths ) { $ prevCnt = 0 ; ArrayHelper :: multisort ( $ routePaths , function ( $ row ) use ( & $ prevCnt ) { return count ( $ row [ 'params' ] ) ; } , SORT_DESC ) ; } }

Parse routes data to obtain path expressions, those used for URL building

Parse routes data to obtain path expressions those used for URL building


protected function buildPathExpressions($path, $store = false) {
        $segments = $this->routeParser->parse($path);
        $expressions = [];
        foreach ($segments as $segmentGroup) {
            $expression = '';
            $params = [];
            $staticPart = '/';
            $staticPartEnded = false;
            foreach ($segmentGroup as $segment) {
                if (is_string($segment)) {
                    $expression .= $segment;
                    if (!$staticPartEnded) {
                        $staticPart .= $segment;
                    }
                } elseif (is_array($segment)) {
                    $staticPartEnded = true;
                    $expression .= '{' . $segment[0] . '}';
                    $params[] = $segment[0];
                }
            }
            $staticPart = '/' . trim($staticPart, '/');
            if ($store && !empty($params)) {
                $row = [
                    'exp' => $expression,
                    'params' => $params,
                ];
                $this->_routePaths[$staticPart] = isset($this->_routePaths[$staticPart]) ? $this->_routePaths[$staticPart] : [];
                $this->_routePaths[$staticPart][] = $row;
            }
            $expressions[$expression] = [
                'expression' => $expression,
                'prefix' => $staticPart,
                'params' => $params,
            ];
        }

        return $expressions;
    }

protected function buildPathExpressions ( $ path , $ store = false ) { $ segments = $ this -> routeParser -> parse ( $ path ) ; $ expressions = [ ] ; foreach ( $ segments as $ segmentGroup ) { $ expression = '' ; $ params = [ ] ; $ staticPart = '/' ; $ staticPartEnded = false ; foreach ( $ segmentGroup as $ segment ) { if ( is_string ( $ segment ) ) { $ expression .= $ segment ; if ( ! $ staticPartEnded ) { $ staticPart .= $ segment ; } } elseif ( is_array ( $ segment ) ) { $ staticPartEnded = true ; $ expression .= '{' . $ segment [ 0 ] . '}' ; $ params [ ] = $ segment [ 0 ] ; } } $ staticPart = '/' . trim ( $ staticPart , '/' ) ; if ( $ store && ! empty ( $ params ) ) { $ row = [ 'exp' => $ expression , 'params' => $ params , ] ; $ this -> _routePaths [ $ staticPart ] = isset ( $ this -> _routePaths [ $ staticPart ] ) ? $ this -> _routePaths [ $ staticPart ] : [ ] ; $ this -> _routePaths [ $ staticPart ] [ ] = $ row ; } $ expressions [ $ expression ] = [ 'expression' => $ expression , 'prefix' => $ staticPart , 'params' => $ params , ] ; } return $ expressions ; }

Build path expression from router path
@param string $path
@param bool $store
@return array


public function alias(string $alias, string $serviceId): void
    {
        self::$aliases[$alias] = $serviceId;
    }

public function alias ( string $ alias , string $ serviceId ) : void { self :: $ aliases [ $ alias ] = $ serviceId ; }

Set an alias to the container.

@param string $alias     The alias
@param string $serviceId The service to return

@return void


public function bind(Service $service, bool $verify = true): void
    {
        // If there is no id
        if (null === $service->getId()) {
            // Throw a new exception
            throw new InvalidServiceIdException('Invalid service id provided.');
        }

        // If we should verify the dispatch
        if ($verify) {
            // Then verify it
            $this->app->dispatcher()->verifyDispatch($service);
        }

        self::$services[$service->getId()] = $service;
    }

public
function
bind
(
Service
$
service
,
bool
$
verify
=
true
)
:
void
{
// If there is no id
if
(
===
$
service
->
getId
(
)
)
{
// Throw a new exception
throw
new
InvalidServiceIdException
(
'Invalid service id provided.'
)
;
}
// If we should verify the dispatch
if
(
$
verify
)
{
// Then verify it
$
this
->
app
->
dispatcher
(
)
->
verifyDispatch
(
$
service
)
;
}
self
::
$
services
[
$
service
->
getId
(
)
]
=
$
service
;
}

Bind a service to the container.

@param Service $service The service model
@param bool    $verify  [optional] Whether to verify the service

@throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException

@return void


public function context(ServiceContext $serviceContext): void
    {
        $context        = $serviceContext->getClass()
            ?? $serviceContext->getFunction();
        $member         = $serviceContext->getMethod()
            ?? $serviceContext->getProperty();
        $contextContext = $serviceContext->getContextClass()
            ?? $serviceContext->getContextFunction();

        // If the context index is null then there's no context
        if (null === $context || null === $serviceContext->getId()) {
            throw new InvalidContextException('Invalid context.');
        }

        // If the context is the same as the end service dispatch and the
        // dispatch isn't static throw an error to disallow this kind of
        // context as it will create an endless loop where the dispatcher
        // will attempt to create the callable with the dependencies and the
        // hasContext check in Container::get() will keep catching it
        if ($context === $contextContext && ! $serviceContext->isStatic()) {
            throw new EndlessContextLoopException(
                'This kind of context will create'
                . 'an endless loop where the dispatcher will attempt to create the '
                . 'callable with the dependencies and the hasContext check in '
                . 'Container::get() will keep catching it: '
                . $this->contextServiceId(
                    $serviceContext->getId(),
                    $context,
                    $member
                )
            );
        }

        $service = $this->getServiceFromContext(
            $serviceContext,
            $context,
            $member
        );

        $this->bind($service);
    }

Bind a context to the container.

@param ServiceContext $serviceContext The context service

@throws \Valkyrja\Container\Exceptions\InvalidContextException
@throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
@throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException

@return void


protected function getServiceFromContext(
        ServiceContext $serviceContext,
        string $context = null,
        string $member = null
    ): Service {
        $service   = new Service();
        $serviceId = $this->contextServiceId(
            $serviceContext->getId(),
            $context,
            $member
        );

        $service
            ->setId($serviceId)
            ->setSingleton($serviceContext->isSingleton())
            ->setDefaults($serviceContext->getDefaults())
            ->setName($serviceContext->getName())
            ->setClass($serviceContext->getContextClass())
            ->setProperty($serviceContext->getContextProperty())
            ->setMethod($serviceContext->getContextMethod())
            ->setFunction($serviceContext->getContextFunction())
            ->setClosure($serviceContext->getContextClosure())
            ->setArguments($serviceContext->getArguments())
            ->setDependencies($serviceContext->getDependencies())
            ->setStatic($serviceContext->isStatic());

        return $service;
    }

protected function getServiceFromContext ( ServiceContext $ serviceContext , string $ context = null , string $ member = null ) : Service { $ service = new Service ( ) ; $ serviceId = $ this -> contextServiceId ( $ serviceContext -> getId ( ) , $ context , $ member ) ; $ service -> setId ( $ serviceId ) -> setSingleton ( $ serviceContext -> isSingleton ( ) ) -> setDefaults ( $ serviceContext -> getDefaults ( ) ) -> setName ( $ serviceContext -> getName ( ) ) -> setClass ( $ serviceContext -> getContextClass ( ) ) -> setProperty ( $ serviceContext -> getContextProperty ( ) ) -> setMethod ( $ serviceContext -> getContextMethod ( ) ) -> setFunction ( $ serviceContext -> getContextFunction ( ) ) -> setClosure ( $ serviceContext -> getContextClosure ( ) ) -> setArguments ( $ serviceContext -> getArguments ( ) ) -> setDependencies ( $ serviceContext -> getDependencies ( ) ) -> setStatic ( $ serviceContext -> isStatic ( ) ) ; return $ service ; }

Get a service model from a context model.

@param ServiceContext $serviceContext The service context
@param string         $context        [optional] The context
class or function
@param string         $member         [optional] The member

@return Service

Get a service model from a context model .


public function has(string $serviceId): bool
    {
        return isset(self::$services[$serviceId]) || isset(self::$aliases[$serviceId]);
    }

public function has ( string $ serviceId ) : bool { return isset ( self :: $ services [ $ serviceId ] ) || isset ( self :: $ aliases [ $ serviceId ] ) ; }

Check whether a given service exists.

@param string $serviceId The service

@return bool


public function hasContext(string $serviceId, string $context, string $member = null): bool
    {
        $contextIndex = $this->contextServiceId($serviceId, $context, $member);

        return isset(self::$services[$contextIndex]);
    }

public function hasContext ( string $ serviceId , string $ context , string $ member = null ) : bool { $ contextIndex = $ this -> contextServiceId ( $ serviceId , $ context , $ member ) ; return isset ( self :: $ services [ $ contextIndex ] ) ; }

Check whether a given service has context.

@param string $serviceId The service
@param string $context   The context
class name || function name || variable name
@param string $member    [optional] The context member
method name || property name

@return bool

Check whether a given service has context .


public function get(string $serviceId, array $arguments = null, string $context = null, string $member = null)
    {
        // If there is a context set for this context and member combination
        if (
            null !== $context
            && $this->hasContext(
                $serviceId,
                $context,
                $member
            )
        ) {
            // Return that context
            return $this->get(
                $this->contextServiceId($serviceId, $context, $member),
                $arguments
            );
        }

        // If there is a context set for this context only
        if (null !== $context && $this->hasContext($serviceId, $context)) {
            // Return that context
            return $this->get(
                $this->contextServiceId($serviceId, $context),
                $arguments
            );
        }

        // If the service is a singleton
        if ($this->isSingleton($serviceId)) {
            // Return the singleton
            return $this->getSingleton($serviceId);
        }

        // If this service is an alias
        if ($this->isAlias($serviceId)) {
            // Return the appropriate service
            return $this->get(
                self::$aliases[$serviceId],
                $arguments,
                $context,
                $member
            );
        }

        // If the service is in the container
        if ($this->has($serviceId)) {
            // Return the made service
            return $this->make($serviceId, $arguments);
        }

        // Check if the service id is provided by a deferred service provider
        if ($this->isProvided($serviceId)) {
            return $this->getProvided(
                $serviceId,
                $arguments,
                $context,
                $member
            );
        }

        // If there are no argument return a new object
        if (null === $arguments) {
            return new $serviceId();
        }

        // Return a new object with the arguments
        return new $serviceId(...$arguments);
    }

Get a service from the container.

@param string $serviceId The service
@param array  $arguments [optional] The arguments
@param string $context   [optional] The context
class name || function name || variable name
@param string $member    [optional] The context member
method name || property name

@return mixed


public function make(string $serviceId, array $arguments = null)
    {
        $service   = self::$services[$serviceId];
        $arguments = $service->getDefaults() ?? $arguments;

        // Dispatch before make event
        $this->app->events()->trigger(
            ServiceMake::class,
            [$serviceId, $service, $arguments]
        );

        // Make the object by dispatching the service
        $made =
            $this->app->dispatcher()->dispatchCallable($service, $arguments);

        // Dispatch after make event
        $this->app->events()->trigger(ServiceMade::class, [$serviceId, $made]);

        // If the service is a singleton
        if ($service->isSingleton()) {
            $this->app->events()->trigger(
                ServiceMadeSingleton::class,
                [$serviceId, $made]
            );
            // Set singleton
            $this->singleton($serviceId, $made);
        }

        return $made;
    }

Make a service.

@param string     $serviceId The service id
@param array|null $arguments [optional] The arguments

@return mixed


public function getSingleton(string $serviceId)
    {
        // If the service isn't a singleton but is provided
        if (! $this->isSingleton($serviceId) && $this->isProvided($serviceId)) {
            // Initialize the provided service
            $this->initializeProvided($serviceId);
        }

        return self::$singletons[$serviceId];
    }

Get a singleton from the container.

@param string $serviceId The service

@return mixed


public function getProvided(
        string $serviceId,
        array $arguments = null,
        string $context = null,
        string $member = null
    ) {
        $this->initializeProvided($serviceId);

        return $this->get($serviceId, $arguments, $context, $member);
    }

public function getProvided ( string $ serviceId , array $ arguments = null , string $ context = null , string $ member = null ) { $ this -> initializeProvided ( $ serviceId ) ; return $ this -> get ( $ serviceId , $ arguments , $ context , $ member ) ; }

Get a provided service from the container.

@param string $serviceId The service
@param array  $arguments [optional] The arguments
@param string $context   [optional] The context
class name || function name || variable name
@param string $member    [optional] The context member
method name || property name

@return mixed

Get a provided service from the container .


public function contextServiceId(string $serviceId, string $context = null, string $member = null): string
    {
        $index = $serviceId . '@' . ($context ?? '');

        // If there is a method
        if (null !== $member) {
            // If there is a class
            if (null !== $context) {
                // Add the double colon to separate the method name and class
                $index .= '::';
            }

            // Append the method/function to the string
            $index .= $member;
        }

        // service@class
        // service@method
        // service@class::method
        return $index;
    }

Get the context service id.

@param string $serviceId The service
@param string $context   [optional] The context
class name || function name || variable name
@param string $member    [optional] The context member
method name || property name

@return string


public function setup(bool $force = false, bool $useCache = true): void
    {
        if (self::$setup && ! $force) {
            return;
        }

        self::$setup = true;

        // If the application should use the container cache files
        if ($useCache && $this->app->config()['container']['useCache']) {
            $this->setupFromCache();

            // Then return out of setup
            return;
        }

        self::$registered = [];
        self::$services   = [];
        self::$provided   = [];

        $useAnnotations     = $this->app->config(
            'container.useAnnotations',
            false
        );
        $annotationsEnabled = $this->app->config(
            'annotations.enabled',
            false
        );
        $onlyAnnotations    = $this->app->config(
            'container.useAnnotationsExclusively',
            false
        );

        // Setup service providers
        $this->setupServiceProviders();

        // If annotations are enabled and the container should use annotations
        if ($useAnnotations && $annotationsEnabled) {
            // Setup annotated services, contexts, and aliases
            $this->setupAnnotations();

            // If only annotations should be used
            if ($onlyAnnotations) {
                // Return to avoid loading container file
                return;
            }
        }

        // Include the container file
        // NOTE: Included if annotations are set or not due to possibility of
        // container items being defined within the classes as well as within
        // the container file
        require $this->app->config()['container']['filePath'];
    }

Setup the container.

@param bool $force    [optional] Whether to force setup
@param bool $useCache [optional] Whether to use cache

@throws \Valkyrja\Container\Exceptions\InvalidContextException
@throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
@throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException

@return void


protected function setupFromCache(): void
    {
        // Set the application container with said file
        $cache = $this->app->config()['cache']['container']
            ?? require $this->app->config()['container']['cacheFilePath'];

        self::$services = unserialize(
            base64_decode($cache['services'], true),
            [
                'allowed_classes' => [
                    Service::class,
                ],
            ]
        );
        self::$provided = $cache['provided'];
        self::$aliases  = $cache['aliases'];
    }

Setup the container from cache.

@return void


protected function setupServiceProviders(): void
    {
        /** @var array $providers */
        $providers = $this->app->config()['container']['providers'];

        // Iterate through all the providers
        foreach ($providers as $provider) {
            $this->register($provider);
        }

        // If this is not a dev environment
        if (! $this->app->debug()) {
            return;
        }

        /** @var array $devProviders */
        $devProviders = $this->app->config()['container']['devProviders'];

        // Iterate through all the providers
        foreach ($devProviders as $provider) {
            $this->register($provider);
        }
    }

protected
function
setupServiceProviders
(
)
:
void
{
/** @var array $providers */
$
providers
=
$
this
->
app
->
config
(
)
[
'container'
]
[
'providers'
]
;
// Iterate through all the providers
foreach
(
$
providers
as
$
provider
)
{
$
this
->
register
(
$
provider
)
;
}
// If this is not a dev environment
if
(
!
$
this
->
app
->
debug
(
)
)
{
return
;
}
/** @var array $devProviders */
$
devProviders
=
$
this
->
app
->
config
(
)
[
'container'
]
[
'devProviders'
]
;
// Iterate through all the providers
foreach
(
$
devProviders
as
$
provider
)
{
$
this
->
register
(
$
provider
)
;
}
}


public function getCacheable(): array
    {
        $this->setup(true, false);

        return [
            'services' => base64_encode(serialize(self::$services)),
            'aliases'  => self::$aliases,
            'provided' => self::$provided,
        ];
    }

public function getCacheable ( ) : array { $ this -> setup ( true , false ) ; return [ 'services' => base64_encode ( serialize ( self :: $ services ) ) , 'aliases' => self :: $ aliases , 'provided' => self :: $ provided , ] ; }

Get a cacheable representation of the service container.

@throws \Valkyrja\Container\Exceptions\InvalidContextException
@throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
@throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
@throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException

@return array

Get a cacheable representation of the service container .


public function getAddressLines()
    {
        return array_filter([
            $this->getComplex(),
            implode(' ', array_filter([$this->getStreetNumber(), $this->getStreetName()])),
            $this->getSuburb(),
            $this->getCity(),
            $this->getPostalCode()
        ]);
    }

public
function
getAddressLines
(
)
{
return
array_filter
(
[
$
this
->
getComplex
(
)
,
implode
(
' '
,
array_filter
(
[
$
this
->
getStreetNumber
(
)
,
$
this
->
getStreetName
(
)
]
)
)
,
$
this
->
getSuburb
(
)
,
$
this
->
getCity
(
)
,
$
this
->
getPostalCode
(
)
]
)
;
}

Returns an array of address lines.

@return array|string[]


public function setLevel($level)
    {
        if (($level < 0) || ($level > 9)) {

            throw new Zend_Filter_Exception('Level must be between 0 and 9');
        }

        $this->_options['level'] = (int) $level;
        return $this;
    }

public
function
setLevel
(
$
level
)
{
if
(
(
$
level
<
0
)
||
(
$
level
>
9
)
)
{
throw
new
Zend_Filter_Exception
(
'Level must be between 0 and 9'
)
;
}
$
this
->
_options
[
'level'
]
=
(
int
)
$
level
;
return
$
this
;
}

Sets a new compression level

@param integer $level
@return Zend_Filter_Compress_Gz


public function getUniqueId()
    {
        $group = $this->group();
        if ($group !== "") {
            return $group;
        }
        $classNameArray = explode('\\', static::class);
        $className = substr(array_pop($classNameArray), 0, -10);
        return Inflector::camel2id($className);
    }

public function getUniqueId ( ) { $ group = $ this -> group ( ) ; if ( $ group !== "" ) { return $ group ; } $ classNameArray = explode ( '\\' , static :: class ) ; $ className = substr ( array_pop ( $ classNameArray ) , 0 , - 10 ) ; return Inflector :: camel2id ( $ className ) ; }


public function registerInRouter(Router $router)
    {
        $routes = $this->routes();
        $group = $this->group();
        if (empty($routes)) {
            return;
        }
        foreach ($routes as $row) {
            $method = $row['method'];
            $route = $group . $row['route'];
            $handlerName = $row['handler'];
            $router->addRoute($method, $route, [$this, $handlerName]);
        }
    }

public function registerInRouter ( Router $ router ) { $ routes = $ this -> routes ( ) ; $ group = $ this -> group ( ) ; if ( empty ( $ routes ) ) { return ; } foreach ( $ routes as $ row ) { $ method = $ row [ 'method' ] ; $ route = $ group . $ row [ 'route' ] ; $ handlerName = $ row [ 'handler' ] ; $ router -> addRoute ( $ method , $ route , [ $ this , $ handlerName ] ) ; } }

Register controller actions in router
@param Router $router


public function resolveAction(RequestApplicationInterface $app, string $action, ...$params)
    {
        $action = $this->normalizeActionName($action);
        $actionId = static::getActionId($action);
        if (!in_array($app, $params)) {
            array_unshift($params, $app);
        }
        $self = $this;
        return $this->validateAction($action, $app)->then(
            function() use (&$app, &$self, $action, $actionId, $params) {
                if ($this->beforeAction($actionId)) {
                    $app->view->context = $self;
                    return Reaction::$di->invoke([$self, $action], $params);
                } else {
                    throw new Exception("Before action error");
                }
            },
            function($error) {
                if (!$error instanceof \Throwable) {
                    $error = new ForbiddenException('You can not perform this action');
                }
                throw $error;
            }
        )->then(
            function($result = null) use ($actionId) {
                return $this->afterAction($actionId, $result);
            }
        );
    }

public
function
resolveAction
(
RequestApplicationInterface
$
app
,
string
$
action
,
...
$
params
)
{
$
action
=
$
this
->
normalizeActionName
(
$
action
)
;
$
actionId
=
static
::
getActionId
(
$
action
)
;
if
(
!
in_array
(
$
app
,
$
params
)
)
{
array_unshift
(
$
params
,
$
app
)
;
}
$
self
=
$
this
;
return
$
this
->
validateAction
(
$
action
,
$
app
)
->
then
(
function
(
)
use
(
&
$
app
,
&
$
self
,
$
action
,
$
actionId
,
$
params
)
{
if
(
$
this
->
beforeAction
(
$
actionId
)
)
{
$
app
->
view
->
context
=
$
self
;
return
Reaction
::
$
di
->
invoke
(
[
$
self
,
$
action
]
,
$
params
)
;
}
else
{
throw
new
Exception
(
"Before action error"
)
;
}
}
,
function
(
$
error
)
{
if
(
!
$
error
instanceof
\
Throwable
)
{
$
error
=
new
ForbiddenException
(
'You can not perform this action'
)
;
}
throw
$
error
;
}
)
->
then
(
function
(
$
result
=
)
use
(
$
actionId
)
{
return
$
this
->
afterAction
(
$
actionId
,
$
result
)
;
}
)
;
}

Resolve controller action
@param string                      $action
@param RequestApplicationInterface $app
@param mixed                       ...$params
@return mixed
@throws NotFoundException


public function beforeAction($actionId)
    {
        $isValid = true;
        $this->emit(self::EVENT_BEFORE_ACTION, [&$this, $actionId, &$isValid]);
        return $isValid;
    }

public function beforeAction ( $ actionId ) { $ isValid = true ; $ this -> emit ( self :: EVENT_BEFORE_ACTION , [ & $ this , $ actionId , & $ isValid ] ) ; return $ isValid ; }

This method is invoked right before an action is executed.

The method will trigger the [[EVENT_BEFORE_ACTION]] event. The return value of the method
will determine whether the action should continue to run.

In case the action should not run, the request should be handled inside of the `beforeAction` code
by either providing the necessary output or redirecting the request. Otherwise the response will be empty.

If you override this method, your code should look like the following:

```php
public function beforeAction($action)
{
// your custom code here, if you want the code to run before action filters,
// which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl

if (!parent::beforeAction($action)) {
return false;
}

// other custom code here

return true; // or false to not run the action
}
```

@param string $actionId the action to be executed.
@return bool whether the action should continue to run.

This method is invoked right before an action is executed .


public function afterAction($actionId, $result = null)
    {
        $this->emit(self::EVENT_AFTER_ACTION, [&$this, $actionId, &$result]);
        return $result;
    }

public function afterAction ( $ actionId , $ result = null ) { $ this -> emit ( self :: EVENT_AFTER_ACTION , [ & $ this , $ actionId , & $ result ] ) ; return $ result ; }

This method is invoked right after an action is executed.

The method will trigger the [[EVENT_AFTER_ACTION]] event. The return value of the method
will be used as the action return value.

If you override this method, your code should look like the following:

```php
public function afterAction($action, $result)
{
$result = parent::afterAction($action, $result);
// your custom code here
return $result;
}
```

@param string $actionId the action just executed.
@param mixed  $result the action return result.
@return mixed the processed action result.

This method is invoked right after an action is executed .


public function renderPartial(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        return $this->renderInternal($app, $viewName, $params, false, $asResponse);
    }

public function renderPartial ( RequestApplicationInterface $ app , $ viewName , $ params = [ ] , $ asResponse = false ) { return $ this -> renderInternal ( $ app , $ viewName , $ params , false , $ asResponse ) ; }

Render view partially
@param RequestApplicationInterface $app
@param string                      $viewName
@param array                       $params
@param bool                        $asResponse
@return \Reaction\Web\ResponseBuilderInterface|string


public function renderAjax(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        return $this->renderInternal($app, $viewName, $params, true, $asResponse);
    }

public function renderAjax ( RequestApplicationInterface $ app , $ viewName , $ params = [ ] , $ asResponse = false ) { return $ this -> renderInternal ( $ app , $ viewName , $ params , true , $ asResponse ) ; }

Render for AJAX request
@param RequestApplicationInterface $app
@param string                      $viewName
@param array                       $params
@param bool                        $asResponse
@return \Reaction\Web\ResponseBuilderInterface|string


public function actions()
    {
        if (!isset($this->_actions)) {
            $reflection = ReflectionHelper::getClassReflection($this);
            $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
            $actions = [];
            foreach ($methods as $method) {
                $name = $method->getName();
                if ($name !== 'actions' && !$method->isStatic() && strncmp($name, 'action', 6) === 0) {
                    $actions[] = static::getActionId($name);
                }
            }
            $this->_actions = $actions;
        }
        return $this->_actions;
    }

public function actions ( ) { if ( ! isset ( $ this -> _actions ) ) { $ reflection = ReflectionHelper :: getClassReflection ( $ this ) ; $ methods = $ reflection -> getMethods ( \ ReflectionMethod :: IS_PUBLIC ) ; $ actions = [ ] ; foreach ( $ methods as $ method ) { $ name = $ method -> getName ( ) ; if ( $ name !== 'actions' && ! $ method -> isStatic ( ) && strncmp ( $ name , 'action' , 6 ) === 0 ) { $ actions [ ] = static :: getActionId ( $ name ) ; } } $ this -> _actions = $ actions ; } return $ this -> _actions ; }


protected function renderInLayout(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        $view = $app->view;
        if (isset($this->layout)) {
            $layoutFile = $view->findViewFile($this->layout, $this);
        } else {
            $layoutFile = $view->findViewFile($view->layout, $this);
        }
        $content = $this->renderInternal($app, $viewName, $params, false, false);
        $rendered = $this->renderFile($app, $layoutFile, ['content' => $content]);
        if (!$asResponse) {
            return $rendered;
        }
        $app->response->setBody($rendered);
        return $app->response;
    }

protected function renderInLayout ( RequestApplicationInterface $ app , $ viewName , $ params = [ ] , $ asResponse = false ) { $ view = $ app -> view ; if ( isset ( $ this -> layout ) ) { $ layoutFile = $ view -> findViewFile ( $ this -> layout , $ this ) ; } else { $ layoutFile = $ view -> findViewFile ( $ view -> layout , $ this ) ; } $ content = $ this -> renderInternal ( $ app , $ viewName , $ params , false , false ) ; $ rendered = $ this -> renderFile ( $ app , $ layoutFile , [ 'content' => $ content ] ) ; if ( ! $ asResponse ) { return $ rendered ; } $ app -> response -> setBody ( $ rendered ) ; return $ app -> response ; }

Render view in layout
@param RequestApplicationInterface $app
@param string                      $viewName
@param array                       $params
@param bool                        $asResponse
@return \Reaction\Web\ResponseBuilderInterface|string


protected function renderInternal(RequestApplicationInterface $app, $viewName, $params = [], $ajax = false, $asResponse = false)
    {
        $view = $app->view;
        $rendered = $ajax ? $view->renderAjax($viewName, $params, $this) : $view->render($viewName, $params, $this);
        if (!$asResponse) {
            return $rendered;
        }
        $app->response->setBody($rendered);
        return $app->response;
    }

protected function renderInternal ( RequestApplicationInterface $ app , $ viewName , $ params = [ ] , $ ajax = false , $ asResponse = false ) { $ view = $ app -> view ; $ rendered = $ ajax ? $ view -> renderAjax ( $ viewName , $ params , $ this ) : $ view -> render ( $ viewName , $ params , $ this ) ; if ( ! $ asResponse ) { return $ rendered ; } $ app -> response -> setBody ( $ rendered ) ; return $ app -> response ; }

Render view internal function
@param RequestApplicationInterface $app
@param string                      $viewName
@param array                       $params
@param bool                        $ajax
@param bool                        $asResponse
@return \Reaction\Web\ResponseBuilderInterface|string


protected function normalizeActionName($actionMethod, $throwException = true)
    {
        if (!StringHelper::startsWith($actionMethod, 'action')) {
            $actionMethod = static::getActionMethod($actionMethod);
        }

        if (!method_exists($this, $actionMethod)) {
            if ($throwException) {
                throw new NotFoundException('Page not found');
            } else {
                return null;
            }
        }

        return $actionMethod;
    }

protected
function
normalizeActionName
(
$
actionMethod
,
$
throwException
=
true
)
{
if
(
!
StringHelper
::
startsWith
(
$
actionMethod
,
'action'
)
)
{
$
actionMethod
=
static
::
getActionMethod
(
$
actionMethod
)
;
}
if
(
!
method_exists
(
$
this
,
$
actionMethod
)
)
{
if
(
$
throwException
)
{
throw
new
NotFoundException
(
'Page not found'
)
;
}
else
{
return
;
}
}
return
$
actionMethod
;
}

Normalize action name
@param string $actionMethod
@param bool   $throwException
@return string|null
@throws NotFoundException


protected function resolveErrorAsHtml(RequestApplicationInterface $app, \Throwable $exception)
    {
        $actions = ['actionError'];
        if ($exception instanceof HttpException) {
            $actions[] = 'actionErrorHttp';
            $actions[] = 'actionErrorHttp' . $exception->statusCode;
        }
        $action = null;
        foreach ($actions as $possibleAction) {
            $action = $this->normalizeActionName($possibleAction, false);
            if (isset($action)) {
                break;
            }
        }
        if (!isset($action)) {
            return $this->resolveErrorAsPlainText($app, $exception);
        }
        return Reaction::$di->invoke([$this, $action], [$app, $exception]);
    }

protected function resolveErrorAsHtml ( RequestApplicationInterface $ app , \ Throwable $ exception ) { $ actions = [ 'actionError' ] ; if ( $ exception instanceof HttpException ) { $ actions [ ] = 'actionErrorHttp' ; $ actions [ ] = 'actionErrorHttp' . $ exception -> statusCode ; } $ action = null ; foreach ( $ actions as $ possibleAction ) { $ action = $ this -> normalizeActionName ( $ possibleAction , false ) ; if ( isset ( $ action ) ) { break ; } } if ( ! isset ( $ action ) ) { return $ this -> resolveErrorAsPlainText ( $ app , $ exception ) ; } return Reaction :: $ di -> invoke ( [ $ this , $ action ] , [ $ app , $ exception ] ) ; }

Resolve error as rendered html
@param RequestApplicationInterface $app
@param \Throwable                  $exception
@return ResponseBuilderInterface|ExtendedPromiseInterface
@throws NotFoundException


protected function resolveErrorAsArray(RequestApplicationInterface $app, \Throwable $exception)
    {
        $data = $this->getErrorData($exception);
        $responseData = ['error' => $data];
        $app->response->setBody($responseData)->setStatusCodeByException($exception);
        return $app->response;
    }

protected function resolveErrorAsArray ( RequestApplicationInterface $ app , \ Throwable $ exception ) { $ data = $ this -> getErrorData ( $ exception ) ; $ responseData = [ 'error' => $ data ] ; $ app -> response -> setBody ( $ responseData ) -> setStatusCodeByException ( $ exception ) ; return $ app -> response ; }

Resolve error as array formatted
@param RequestApplicationInterface $app
@param \Throwable                  $exception
@return ResponseBuilderInterface


protected function getErrorData(\Throwable $exception)
    {
        $data = [
            'message' => $exception->getMessage(),
            'code' => $exception instanceof HttpExceptionInterface ? $exception->statusCode : $exception->getCode(),
            'name' => $this->getExceptionName($exception),
        ];
        if (Reaction::isDebug() || Reaction::isDev()) {
            $data['file'] = $exception->getFile();
            $data['line'] = $exception->getLine();
            $data['trace'] = $exception->getTraceAsString();
        }
        return $data;
    }

protected function getErrorData ( \ Throwable $ exception ) { $ data = [ 'message' => $ exception -> getMessage ( ) , 'code' => $ exception instanceof HttpExceptionInterface ? $ exception -> statusCode : $ exception -> getCode ( ) , 'name' => $ this -> getExceptionName ( $ exception ) , ] ; if ( Reaction :: isDebug ( ) || Reaction :: isDev ( ) ) { $ data [ 'file' ] = $ exception -> getFile ( ) ; $ data [ 'line' ] = $ exception -> getLine ( ) ; $ data [ 'trace' ] = $ exception -> getTraceAsString ( ) ; } return $ data ; }

Get error data as array
@param \Throwable $exception
@return array


protected function getExceptionName($exception)
    {
        if ($exception instanceof Exception) {
            return $exception->getName();
        } else {
            $classNameExp = explode('\\', get_class($exception));
            return end($classNameExp);
        }
    }

protected function getExceptionName ( $ exception ) { if ( $ exception instanceof Exception ) { return $ exception -> getName ( ) ; } else { $ classNameExp = explode ( '\\' , get_class ( $ exception ) ) ; return end ( $ classNameExp ) ; } }

Get name of exception
@param \Throwable $exception
@return string


protected function validateAction($action, RequestApplicationInterface $app)
    {
        $annotationsCtrl = Reaction::$annotations->getClass($this);
        $annotationsAction = Reaction::$annotations->getMethod($action, $this);
        $annotations = ArrayHelper::merge(array_values($annotationsCtrl), array_values($annotationsAction));
        $promises = [];
        if (!empty($annotations)) {
            foreach ($annotations as $annotation) {
                if (!$annotation instanceof CtrlActionValidatorInterface) {
                    continue;
                }
                $promise = $annotation->validate($app);
                if (!$promise instanceof PromiseInterface) {
                    $promise = !empty($promise) ? resolve(true) : reject(false);
                    Reaction::warning("Controller validator '{class}' returned NOT a promise", [
                        'class' => get_class($annotation),
                    ]);
                }
                $promises[] = $promise;
                $promises[] = \Reaction\Promise\resolve(true);
            }
        }
        if (empty($promises)) {
            return resolve(true);
        }
        $all = \Reaction\Promise\all($promises);
        return $all;
    }

Validate that user can perform that action
@param string $action
@param RequestApplicationInterface $app
@return ExtendedPromiseInterface


public static function getActionId($actionMethod)
    {
        if (strpos($actionMethod, 'action') === 0) {
            $actionMethod = substr($actionMethod, 6);
        }
        return Inflector::camel2id($actionMethod, '-');
    }

public static function getActionId ( $ actionMethod ) { if ( strpos ( $ actionMethod , 'action' ) === 0 ) { $ actionMethod = substr ( $ actionMethod , 6 ) ; } return Inflector :: camel2id ( $ actionMethod , '-' ) ; }

Convert controller action method name to it's ID
@param string $actionMethod
@return string

Convert controller action method name to it s ID


public static function getActionMethod($actionId = '')
    {
        if ($actionId === '') {
            $actionId = static::$_defaultAction;
        }
        $actionMethod = Inflector::id2camel($actionId, '-');
        return 'action' . $actionMethod;
    }

public static function getActionMethod ( $ actionId = '' ) { if ( $ actionId === '' ) { $ actionId = static :: $ _defaultAction ; } $ actionMethod = Inflector :: id2camel ( $ actionId , '-' ) ; return 'action' . $ actionMethod ; }

Convert controller action ID to method name
@param string $actionId
@return string


public static function toHex($color)
  {
    // Check it it's a RGB color
    if (is_array($color)) {
      if ((count($color) == 3 && array_keys($color) === range(0, 2))
       || (count($color) == 4 && array_keys($color) === range(0, 3))) {
        $red = $color[0];
        $green = $color[1];
        $blue = $color[2];
      } else {
        $red = isset($color['red']) ?: (isset($color['r']) ?: 0);
        $red = isset($color['red'])
          ? $color['red']
          : (isset($color['r']) ? $color['r'] : 0);
        $green = isset($color['green'])
          ? $color['green']
          : (isset($color['g']) ? $color['g'] : 0);
        $blue = isset($color['blue'])
          ? $color['blue']
          : (isset($color['b']) ? $color['b'] : 0);
      }
      return '#'
        .substr('00' . dechex($red), -2)
        .substr('00' . dechex($green), -2)
        .substr('00' . dechex($blue), -2);
    }
    if (is_string($color)) {
      $color = strtolower($color);
      // Check if it's a X11 color
      if (array_key_exists($color, self::$x11) !== false) {
        return static::toHex(self::$x11[$color]);
      }
      // Check if it's an 3-hexadecimal color
      if (preg_match('/^#[\da-f]{3}$/i', $color)) {
        $color = preg_replace('/([\da-f])/i', '$1$1', $color);
      }
      if (preg_match('/^#[\da-f]{6}$/i', $color)) {
        return $color;
      }
    }
    return '#000000';
  }

Change a color format to hexadecimal

@param  mixed $color Color
@return array        An 6-hexadecimal color prefixed by an hash


public static function toRGBA($color)
  {
    // Check it it's already a RGB color
    if (is_array($color)) {
      if (count($color) == 3 && array_keys($color) === range(0, 2)) {
        return array(
          'red' => $color[0],
          'green' => $color[1],
          'blue' => $color[2],
          'alpha' => 1
        );
      }
      if (count($color) == 4 && array_keys($color) === range(0, 3)) {
        return array(
          'red' => $color[0],
          'green' => $color[1],
          'blue' => $color[2],
          'alpha' => $color[3]
        );
      }
      return array(
        'red' => isset($color['red'])
          ? $color['red']
          : (isset($color['r']) ? $color['r'] : 0),
        'green' => isset($color['green'])
          ? $color['green']
          : (isset($color['g']) ? $color['g'] : 0),
        'blue' => isset($color['blue'])
          ? $color['blue']
          : (isset($color['b']) ? $color['b'] : 0),
        'alpha' => isset($color['alpha'])
          ? $color['alpha']
          : 1
      );
    }
    if (is_string($color)) {
      $color = strtolower($color);
      // Check if it's a X11 color
      if (array_key_exists($color, self::$x11) !== false) {
        $color = self::$x11[$color];
        $color['alpha'] = 1;
        return $color;
      }
      // Check if it's an hexadecimal color
      if (preg_match('/^#[\da-f]{3}$/i', $color)) {
        $color = preg_replace('/([\da-f])/i', '$1$1', $color);
      }
      if (preg_match('/^#[\da-f]{6}$/i', $color)) {
        list($red, $green, $blue) = sscanf($color, "#%02x%02x%02x");
        return array(
          'red' => $red,
          'green' => $green,
          'blue' => $blue,
          'alpha' => 1
        );
      }
    }
    return array('red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 1);
  }

public
static
function
toRGBA
(
$
color
)
{
// Check it it's already a RGB color
if
(
is_array
(
$
color
)
)
{
if
(
count
(
$
color
)
==
3
&&
array_keys
(
$
color
)
===
range
(
0
,
2
)
)
{
return
array
(
'red'
=>
$
color
[
0
]
,
'green'
=>
$
color
[
1
]
,
'blue'
=>
$
color
[
2
]
,
'alpha'
=>
1
)
;
}
if
(
count
(
$
color
)
==
4
&&
array_keys
(
$
color
)
===
range
(
0
,
3
)
)
{
return
array
(
'red'
=>
$
color
[
0
]
,
'green'
=>
$
color
[
1
]
,
'blue'
=>
$
color
[
2
]
,
'alpha'
=>
$
color
[
3
]
)
;
}
return
array
(
'red'
=>
isset
(
$
color
[
'red'
]
)
$
color
[
'red'
]
:
(
isset
(
$
color
[
'r'
]
)
$
color
[
'r'
]
:
0
)
,
'green'
=>
isset
(
$
color
[
'green'
]
)
$
color
[
'green'
]
:
(
isset
(
$
color
[
'g'
]
)
$
color
[
'g'
]
:
0
)
,
'blue'
=>
isset
(
$
color
[
'blue'
]
)
$
color
[
'blue'
]
:
(
isset
(
$
color
[
'b'
]
)
$
color
[
'b'
]
:
0
)
,
'alpha'
=>
isset
(
$
color
[
'alpha'
]
)
$
color
[
'alpha'
]
:
1
)
;
}
if
(
is_string
(
$
color
)
)
{
$
color
=
strtolower
(
$
color
)
;
// Check if it's a X11 color
if
(
array_key_exists
(
$
color
,
self
::
$
x11
)
!==
false
)
{
$
color
=
self
::
$
x11
[
$
color
]
;
$
color
[
'alpha'
]
=
1
;
return
$
color
;
}
// Check if it's an hexadecimal color
if
(
preg_match
(
'/^#[\da-f]{3}$/i'
,
$
color
)
)
{
$
color
=
preg_replace
(
'/([\da-f])/i'
,
'$1$1'
,
$
color
)
;
}
if
(
preg_match
(
'/^#[\da-f]{6}$/i'
,
$
color
)
)
{
list
(
$
red
,
$
green
,
$
blue
)
=
sscanf
(
$
color
,
"#%02x%02x%02x"
)
;
return
array
(
'red'
=>
$
red
,
'green'
=>
$
green
,
'blue'
=>
$
blue
,
'alpha'
=>
1
)
;
}
}
return
array
(
'red'
=>
0
,
'green'
=>
0
,
'blue'
=>
0
,
'alpha'
=>
1
)
;
}

Change a color format to RGBA

@param  mixed $color Color
@return array        An [red, green, blue, alpha] associative array


public static function imageDominant($src, $granularity = 1)
  {
    $granularity = max(1, abs((int)$granularity));
    $channels = array(
      'red' => 0,
      'green' => 0,
      'blue' => 0
    );
    $size = @getimagesize($src);
    if ($size === false) {
      user_error("Unable to get image size data: ".$src);
      return false;
    }
    $img = @imagecreatefromstring(@file_get_contents($src));
    if (!$img) {
      user_error("Unable to open image file: ".$src);
      return false;
    }
    for($x = 0; $x < $size[0]; $x += $granularity) {
      for($y = 0; $y < $size[1]; $y += $granularity) {
        $thisColor = imagecolorat($img, $x, $y);
        $rgb = imagecolorsforindex($img, $thisColor);
        $channels['red'] += $rgb['red'];
        $channels['green'] += $rgb['green'];
        $channels['blue'] += $rgb['blue'];
      }
    }
    $nbPixels = ceil($size[0] / $granularity) * ceil($size[1] / $granularity);
    $channels['red'] = round($channels['red'] / $nbPixels);
    $channels['green'] = round($channels['green'] / $nbPixels);
    $channels['blue'] = round($channels['blue'] / $nbPixels);
    return $channels;
  }

public
static
function
imageDominant
(
$
src
,
$
granularity
=
1
)
{
$
granularity
=
max
(
1
,
abs
(
(
int
)
$
granularity
)
)
;
$
channels
=
array
(
'red'
=>
0
,
'green'
=>
0
,
'blue'
=>
0
)
;
$
size
=
@
getimagesize
(
$
src
)
;
if
(
$
size
===
false
)
{
user_error
(
"Unable to get image size data: "
.
$
src
)
;
return
false
;
}
$
img
=
@
imagecreatefromstring
(
@
file_get_contents
(
$
src
)
)
;
if
(
!
$
img
)
{
user_error
(
"Unable to open image file: "
.
$
src
)
;
return
false
;
}
for
(
$
x
=
0
;
$
x
<
$
size
[
0
]
;
$
x
+=
$
granularity
)
{
for
(
$
y
=
0
;
$
y
<
$
size
[
1
]
;
$
y
+=
$
granularity
)
{
$
thisColor
=
imagecolorat
(
$
img
,
$
x
,
$
y
)
;
$
rgb
=
imagecolorsforindex
(
$
img
,
$
thisColor
)
;
$
channels
[
'red'
]
+=
$
rgb
[
'red'
]
;
$
channels
[
'green'
]
+=
$
rgb
[
'green'
]
;
$
channels
[
'blue'
]
+=
$
rgb
[
'blue'
]
;
}
}
$
nbPixels
=
ceil
(
$
size
[
0
]
/
$
granularity
)
*
ceil
(
$
size
[
1
]
/
$
granularity
)
;
$
channels
[
'red'
]
=
round
(
$
channels
[
'red'
]
/
$
nbPixels
)
;
$
channels
[
'green'
]
=
round
(
$
channels
[
'green'
]
/
$
nbPixels
)
;
$
channels
[
'blue'
]
=
round
(
$
channels
[
'blue'
]
/
$
nbPixels
)
;
return
$
channels
;
}

Return the dominant color for an image

@param  string   $src        Image path/url
@param  integer $granularity Search's granularity (Ex. default value : 30/40.)
@return mixed                An [red, green, blue] associative array


public static function stdin($raw = false)
    {
        $promise = new Promise(function($r, $c) use ($raw) {
            static::getStdInStream()->once('data', function($chunk) use ($r, $raw) {
                if (!$raw) {
                    $chunk = rtrim($chunk, PHP_EOL);
                }
                $r($chunk);
            });
        });
        return $promise;
    }

public static function stdin ( $ raw = false ) { $ promise = new Promise ( function ( $ r , $ c ) use ( $ raw ) { static :: getStdInStream ( ) -> once ( 'data' , function ( $ chunk ) use ( $ r , $ raw ) { if ( ! $ raw ) { $ chunk = rtrim ( $ chunk , PHP_EOL ) ; } $ r ( $ chunk ) ; } ) ; } ) ; return $ promise ; }

Gets input from STDIN and returns a string right-trimmed for EOLs.

@param bool $raw If set to true, returns the raw string without trimming
@return ExtendedPromiseInterface with string the string read from stdin

Gets input from STDIN and returns a string right - trimmed for EOLs .


public static function select($prompt, $options = [])
    {
        $helpText = '';
        foreach ($options as $key => $value) {
            $helpText .= " $key - $value\n";
        }
        $helpText .= ' ? - Show help';
        $promptText = "$prompt [" . implode(',', array_keys($options)) . ',?]: ';
        $promptOptions = [
            'required' => true,
            'validator' => function($input, &$error) use($options, $helpText) {
                $input = trim($input);
                if ($input === '?') {
                    $error = $helpText;
                    return false;
                }
                if (array_key_exists($input, $options)) {
                    return true;
                }

                $error = "Invalid input, please enter '?' for help";
                return false;
            }
        ];
        return static::prompt($promptText, $promptOptions);
    }

Gives the user an option to choose from. Giving '?' as an input will show
a list of options to choose from and their explanations.

@param string $prompt the prompt message
@param array $options Key-value array of options to choose from. Key is what is inputed and used, value is
what's displayed to end user by help command.

@return ExtendedPromiseInterface with string An option character the user chose

Gives the user an option to choose from . Giving ? as an input will show a list of options to choose from and their explanations .


protected function _appendFileToPaths(array $paths, $file)
    {
        if (!$this->_isAtom($file)) {
            return [$file];
        }

        $appendFile = function($path) use($file) {
            return $this->_joinPaths($path, $file);
        };

        return array_map($appendFile, $paths);
    }

protected function _appendFileToPaths ( array $ paths , $ file ) { if ( ! $ this -> _isAtom ( $ file ) ) { return [ $ file ] ; } $ appendFile = function ( $ path ) use ( $ file ) { return $ this -> _joinPaths ( $ path , $ file ) ; } ; return array_map ( $ appendFile , $ paths ) ; }

Append the filename to the array of paths.

@param array $paths The paths to append to.
@param string $file The filename.
@return array The paths with the file name appended.

Append the filename to the array of paths .


protected function getPgClient() {
        if (!isset($this->_pgClient)) {
            $config = [
                'dbCredentials' => [
                    'host' => $this->host,
                    'port' => $this->port,
                    'user' => $this->username,
                    'password' => $this->password,
                    'database' => $this->database,
                ],
                //'autoDisconnect' => true,
                //'maxConnections' => 5,
                'loop' => Reaction::$app->loop
            ];
            $this->_pgClient = new PgClient($config);
        }
        return $this->_pgClient;
    }

protected
function
getPgClient
(
)
{
if
(
!
isset
(
$
this
->
_pgClient
)
)
{
$
config
=
[
'dbCredentials'
=>
[
'host'
=>
$
this
->
host
,
'port'
=>
$
this
->
port
,
'user'
=>
$
this
->
username
,
'password'
=>
$
this
->
password
,
'database'
=>
$
this
->
database
,
]
,
//'autoDisconnect' => true,
//'maxConnections' => 5,
'loop'
=>
Reaction
::
$
app
->
loop
]
;
$
this
->
_pgClient
=
new
PgClient
(
$
config
)
;
}
return
$
this
->
_pgClient
;
}


public function executeSql($sql, $params = [], $lazy = true) {
        list($sql, $params) = $this->convertSqlToIndexed($sql, $params);
        $promiseResolver = function($r, $c) use ($sql, $params) {
            $result = [];
            $this->getPgClient()->executeStatement($sql, $params)->subscribe(
                function($row) use (&$result) {
                    $result[] = $row;
                },
                function($error = null) use (&$c) {
                    $c($error);
                },
                function() use (&$r, &$result) {
                    $r($result);
                }
            );
        };
        if (!$lazy) {
            return new Promise($promiseResolver);
        }
        $promiseCreator = function() use (&$promiseResolver) {
            return new Promise($promiseResolver);
        };
        return new LazyPromise($promiseCreator);
    }

public function executeSql ( $ sql , $ params = [ ] , $ lazy = true ) { list ( $ sql , $ params ) = $ this -> convertSqlToIndexed ( $ sql , $ params ) ; $ promiseResolver = function ( $ r , $ c ) use ( $ sql , $ params ) { $ result = [ ] ; $ this -> getPgClient ( ) -> executeStatement ( $ sql , $ params ) -> subscribe ( function ( $ row ) use ( & $ result ) { $ result [ ] = $ row ; } , function ( $ error = null ) use ( & $ c ) { $ c ( $ error ) ; } , function ( ) use ( & $ r , & $ result ) { $ r ( $ result ) ; } ) ; } ; if ( ! $ lazy ) { return new Promise ( $ promiseResolver ) ; } $ promiseCreator = function ( ) use ( & $ promiseResolver ) { return new Promise ( $ promiseResolver ) ; } ; return new LazyPromise ( $ promiseCreator ) ; }

Execute SQL statement string
@param string $sql Statement SQL string
@param array  $params Statement parameters
@param bool   $lazy Use lazy promise
@return ExtendedPromiseInterface|LazyPromiseInterface


protected function writeStream(string $path): void
    {
        // Attempt to open the path specified
        $handle = fopen($path, 'wb+');

        // If the handler failed to open
        if (false === $handle) {
            // Throw a runtime exception
            throw new RuntimeException(
                'Unable to write to designated path'
            );
        }

        // Get the stream
        $stream = $this->getStream();
        // Rewind the stream
        $stream->rewind();

        // While the end of file hasn't been reached
        while (! $stream->eof()) {
            // Write the stream's contents to the handler
            fwrite($handle, $stream->read(4096));
        }

        // Close the file path
        fclose($handle);
    }

Write the stream to a path.

@param string $path The path to write the stream to

@throws \RuntimeException
@throws \Valkyrja\HttpMessage\Exceptions\InvalidStream

@return void


public static function fromGlobals(
        array $server = null,
        array $query = null,
        array $body = null,
        array $cookies = null,
        array $files = null
    ): ServerRequest {
        $server  = static::normalizeServer($server ?: $_SERVER);
        $files   = static::normalizeFiles($files ?: $_FILES);
        $headers = static::marshalHeaders($server);

        if (null === $cookies && array_key_exists('cookie', $headers)) {
            $cookies = self::parseCookieHeader($headers['cookie']);
        }

        return new NativeServerRequest(
            static::marshalUriFromServer($server, $headers),
            static::get('REQUEST_METHOD', $server, RequestMethod::GET),
            new NativeStream('php://input'),
            $headers,
            $server,
            $cookies ?? $_COOKIE,
            $query ?? $_GET,
            $body ?? $_POST,
            $files,
            static::marshalProtocolVersion($server)
        );
    }

public static function fromGlobals ( array $ server = null , array $ query = null , array $ body = null , array $ cookies = null , array $ files = null ) : ServerRequest { $ server = static :: normalizeServer ( $ server ? : $ _SERVER ) ; $ files = static :: normalizeFiles ( $ files ? : $ _FILES ) ; $ headers = static :: marshalHeaders ( $ server ) ; if ( null === $ cookies && array_key_exists ( 'cookie' , $ headers ) ) { $ cookies = self :: parseCookieHeader ( $ headers [ 'cookie' ] ) ; } return new NativeServerRequest ( static :: marshalUriFromServer ( $ server , $ headers ) , static :: get ( 'REQUEST_METHOD' , $ server , RequestMethod :: GET ) , new NativeStream ( 'php://input' ) , $ headers , $ server , $ cookies ?? $ _COOKIE , $ query ?? $ _GET , $ body ?? $ _POST , $ files , static :: marshalProtocolVersion ( $ server ) ) ; }

Create a request from the supplied superglobal values.

If any argument is not supplied, the corresponding superglobal value will
be used.

The ServerRequest created is then passed to the fromServer() method in
order to marshal the request URI and headers.

@see fromServer()

@param array $server  $_SERVER superglobal
@param array $query   $_GET superglobal
@param array $body    $_POST superglobal
@param array $cookies $_COOKIE superglobal
@param array $files   $_FILES superglobal

@throws \InvalidArgumentException
@throws \UnexpectedValueException
@throws \Valkyrja\HttpMessage\Exceptions\InvalidUploadedFile
@throws \Valkyrja\HttpMessage\Exceptions\InvalidStream
@throws \Valkyrja\HttpMessage\Exceptions\InvalidScheme
@throws \Valkyrja\HttpMessage\Exceptions\InvalidQuery
@throws \Valkyrja\HttpMessage\Exceptions\InvalidProtocolVersion
@throws \Valkyrja\HttpMessage\Exceptions\InvalidPort
@throws \Valkyrja\HttpMessage\Exceptions\InvalidPath
@throws \Valkyrja\HttpMessage\Exceptions\InvalidMethod

@return ServerRequest

Create a request from the supplied superglobal values .


public static function getHeader(string $header, array $headers, $default = null): string
    {
        $header  = strtolower($header);
        $headers = array_change_key_case($headers, CASE_LOWER);
        if (array_key_exists($header, $headers)) {
            $value = \is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];

            return $value;
        }

        return $default;
    }

public
static
function
getHeader
(
string
$
header
,
array
$
headers
,
$
default
=
)
:
string
{
$
header
=
strtolower
(
$
header
)
;
$
headers
=
array_change_key_case
(
$
headers
,
CASE_LOWER
)
;
if
(
array_key_exists
(
$
header
,
$
headers
)
)
{
$
value
=
\
is_array
(
$
headers
[
$
header
]
)
implode
(
', '
,
$
headers
[
$
header
]
)
:
$
headers
[
$
header
]
;
return
$
value
;
}
return
$
default
;
}

Search for a header value.

Does a case-insensitive search for a matching header.

If found, it is returned as a string, using comma concatenation.

If not, the $default is returned.

@param string $header
@param array  $headers
@param mixed  $default

@return string


public static function stripQueryString(string $path): string
    {
        if (($queryPos = strpos($path, '?')) !== false) {
            return substr($path, 0, $queryPos);
        }

        return $path;
    }

public static function stripQueryString ( string $ path ) : string { if ( ( $ queryPos = strpos ( $ path , '?' ) ) !== false ) { return substr ( $ path , 0 , $ queryPos ) ; } return $ path ; }

Strip the query string from a path.

@param string $path

@return string


private static function marshalHostAndPortFromHeader(stdClass $accumulator, $host): void
    {
        if (\is_array($host)) {
            $host = implode(', ', $host);
        }

        $accumulator->host = $host;
        $accumulator->port = null;

        // Works for regname, IPv4 & IPv6
        if (preg_match('|\:(\d+)$|', $accumulator->host, $matches)) {
            $accumulator->host = substr($accumulator->host, 0, -1 * (\strlen($matches[1]) + 1));
            $accumulator->port = (int) $matches[1];
        }
    }

private
static
function
marshalHostAndPortFromHeader
(
stdClass
$
accumulator
,
$
host
)
:
void
{
if
(
\
is_array
(
$
host
)
)
{
$
host
=
implode
(
', '
,
$
host
)
;
}
$
accumulator
->
host
=
$
host
;
$
accumulator
->
port
=
;
// Works for regname, IPv4 & IPv6
if
(
preg_match
(
'|\:(\d+)$|'
,
$
accumulator
->
host
,
$
matches
)
)
{
$
accumulator
->
host
=
substr
(
$
accumulator
->
host
,
0
,
1
*
(
\
strlen
(
$
matches
[
1
]
)
+
1
)
)
;
$
accumulator
->
port
=
(
int
)
$
matches
[
1
]
;
}
}

Marshal the host and port from the request header.

@param stdClass     $accumulator
@param string|array $host

@return void

Marshal the host and port from the request header .


private static function normalizeNestedFileSpec(array $files = []): array
    {
        $normalizedFiles = [];

        foreach (array_keys($files['tmp_name']) as $key) {
            $spec                  = [
                'tmp_name' => $files['tmp_name'][$key],
                'size'     => $files['size'][$key],
                'error'    => $files['error'][$key],
                'name'     => $files['name'][$key],
                'type'     => $files['type'][$key],
            ];
            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
        }

        return $normalizedFiles;
    }

private static function normalizeNestedFileSpec ( array $ files = [ ] ) : array { $ normalizedFiles = [ ] ; foreach ( array_keys ( $ files [ 'tmp_name' ] ) as $ key ) { $ spec = [ 'tmp_name' => $ files [ 'tmp_name' ] [ $ key ] , 'size' => $ files [ 'size' ] [ $ key ] , 'error' => $ files [ 'error' ] [ $ key ] , 'name' => $ files [ 'name' ] [ $ key ] , 'type' => $ files [ 'type' ] [ $ key ] , ] ; $ normalizedFiles [ $ key ] = self :: createUploadedFileFromSpec ( $ spec ) ; } return $ normalizedFiles ; }

Normalize an array of file specifications.

Loops through all nested files and returns a normalized array of
UploadedFileInterface instances.

@param array $files

@throws \InvalidArgumentException

@return UploadedFile[]

Normalize an array of file specifications .


public static function endsWith($needle, $str)
    {
        $end = substr($str, -1*strlen($needle));

        return $end == $needle;
    }

public static function endsWith ( $ needle , $ str ) { $ end = substr ( $ str , - 1 * strlen ( $ needle ) ) ; return $ end == $ needle ; }

Checks if string ends with another string
@param  string  $needle Supposed end
@param  string  $str    Tested string
@return boolean TRUE if string ends with another string, FALSE
otherwise


Returns a random string
@param int    $charsAmount String's length
@param string $chars       Chars in the random string. Default is a-z,
digits and "_" (underscore)
@return string Random string with specified length


private function createEdges(Graph $graph, $className)
    {
        $migrationsAnnotations = $this->reader->getClassMigrationMethodInfo($className);

        $parentVertex = $graph->hasVertex($className) ? $graph->getVertex($className) : $graph->createVertex(
            $className
        );

        foreach ($migrationsAnnotations as $migrationsAnnotation) {
            if ($migrationsAnnotation->annotation->from) {
                $fromClass = $migrationsAnnotation->annotation->from;
                $fromVertex = $graph->hasVertex($fromClass) ? $graph->getVertex($fromClass) : $graph->createVertex(
                    $fromClass
                );

                if (!$parentVertex->hasEdgeTo($fromVertex)) {
                    $edge = $fromVertex->createEdgeTo($parentVertex);
                    $this->annotations[$this->getEdgeId($edge)] = $migrationsAnnotation;
                    $this->createEdges($graph, $fromClass);
                }
            }

            if ($migrationsAnnotation->annotation->to) {
                $toClass = $migrationsAnnotation->annotation->to;
                $fromVertex = $graph->hasVertex($toClass) ? $graph->getVertex($toClass) : $graph->createVertex(
                    $toClass
                );

                if (!$parentVertex->hasEdgeTo($fromVertex)) {
                    $edge = $parentVertex->createEdgeTo($fromVertex);
                    $this->annotations[$this->getEdgeId($edge)] = $migrationsAnnotation;
                    $this->createEdges($graph, $toClass);
                }
            }
        }
    }

private function createEdges ( Graph $ graph , $ className ) { $ migrationsAnnotations = $ this -> reader -> getClassMigrationMethodInfo ( $ className ) ; $ parentVertex = $ graph -> hasVertex ( $ className ) ? $ graph -> getVertex ( $ className ) : $ graph -> createVertex ( $ className ) ; foreach ( $ migrationsAnnotations as $ migrationsAnnotation ) { if ( $ migrationsAnnotation -> annotation -> from ) { $ fromClass = $ migrationsAnnotation -> annotation -> from ; $ fromVertex = $ graph -> hasVertex ( $ fromClass ) ? $ graph -> getVertex ( $ fromClass ) : $ graph -> createVertex ( $ fromClass ) ; if ( ! $ parentVertex -> hasEdgeTo ( $ fromVertex ) ) { $ edge = $ fromVertex -> createEdgeTo ( $ parentVertex ) ; $ this -> annotations [ $ this -> getEdgeId ( $ edge ) ] = $ migrationsAnnotation ; $ this -> createEdges ( $ graph , $ fromClass ) ; } } if ( $ migrationsAnnotation -> annotation -> to ) { $ toClass = $ migrationsAnnotation -> annotation -> to ; $ fromVertex = $ graph -> hasVertex ( $ toClass ) ? $ graph -> getVertex ( $ toClass ) : $ graph -> createVertex ( $ toClass ) ; if ( ! $ parentVertex -> hasEdgeTo ( $ fromVertex ) ) { $ edge = $ parentVertex -> createEdgeTo ( $ fromVertex ) ; $ this -> annotations [ $ this -> getEdgeId ( $ edge ) ] = $ migrationsAnnotation ; $ this -> createEdges ( $ graph , $ toClass ) ; } } } }

Create edges between versions graph

@param Graph  $graph
@param string $className


public function find($fromClassName, $toClassName)
    {
        $annotations = array();

        $graph = new Graph();

        $this->createEdges($graph, $fromClassName);
        $this->createEdges($graph, $toClassName);

        try {
            $breadFirst = new BreadthFirst($graph->getVertex($fromClassName));
            $edges = $breadFirst->getEdgesTo($graph->getVertex($toClassName));
            /** @var Directed $edge */
            foreach ($edges as $edge) {
                $annotations[] = $this->annotations[$this->getEdgeId($edge)];
            }
        } catch (OutOfBoundsException $e) {
            return null;
        }

        return $annotations;
    }

public
function
find
(
$
fromClassName
,
$
toClassName
)
{
$
annotations
=
array
(
)
;
$
graph
=
new
Graph
(
)
;
$
this
->
createEdges
(
$
graph
,
$
fromClassName
)
;
$
this
->
createEdges
(
$
graph
,
$
toClassName
)
;
try
{
$
breadFirst
=
new
BreadthFirst
(
$
graph
->
getVertex
(
$
fromClassName
)
)
;
$
edges
=
$
breadFirst
->
getEdgesTo
(
$
graph
->
getVertex
(
$
toClassName
)
)
;
/** @var Directed $edge */
foreach
(
$
edges
as
$
edge
)
{
$
annotations
[
]
=
$
this
->
annotations
[
$
this
->
getEdgeId
(
$
edge
)
]
;
}
}
catch
(
OutOfBoundsException
$
e
)
{
return
;
}
return
$
annotations
;
}

Find shortest path between versions

@param string $fromClassName
@param string $toClassName

@return MethodInfo[]


public function create($data)
    {
        $data = $this->sanitizeData((array)$data);
        return $this->getRepository()->create($data);
    }

public function create ( $ data ) { $ data = $ this -> sanitizeData ( ( array ) $ data ) ; return $ this -> getRepository ( ) -> create ( $ data ) ; }

Create a resource

@param  mixed $data
@return ApiProblem|mixed


public function fetchAll($params = array())
    {
        $criteria = $params->get('query', []);
        $orderBy = $params->get('order_by', []);

        $adapter = $this->getRepository()->getPaginatorAdapter($criteria, $orderBy);
        return new $this->collectionClass($adapter);
    }

public function fetchAll ( $ params = array ( ) ) { $ criteria = $ params -> get ( 'query' , [ ] ) ; $ orderBy = $ params -> get ( 'order_by' , [ ] ) ; $ adapter = $ this -> getRepository ( ) -> getPaginatorAdapter ( $ criteria , $ orderBy ) ; return new $ this -> collectionClass ( $ adapter ) ; }

Fetch all or a subset of resources

@param  array $params
@return ApiProblem|mixed


public function update($id, $data)
    {
        $data = $this->sanitizeData((array)$data);
        return $this->getRepository()->update($id, $data);
    }

public function update ( $ id , $ data ) { $ data = $ this -> sanitizeData ( ( array ) $ data ) ; return $ this -> getRepository ( ) -> update ( $ id , $ data ) ; }

Update a resource

@param  mixed $id
@param  mixed $data
@return ApiProblem|mixed


public function setStatusCode(int $code, string $text = null): Response
    {
        $this->statusCode = $code;

        // Check if the status code is valid
        if ($this->isInvalid()) {
            throw new InvalidStatusCodeException(
                sprintf('The HTTP status code "%s" is not valid.', $code)
            );
        }

        // If no text was supplied
        if (null === $text) {
            // Set the status text from the status texts array
            $this->statusText = StatusCode::TEXTS[$code] ?? 'unknown status';

            return $this;
        }

        $this->statusText = $text;

        return $this;
    }

Sets the response status code.

@param int    $code HTTP status code
@param string $text [optional] HTTP status text

If the status text is null it will be automatically populated for the
known status codes and left empty otherwise.

@throws \Valkyrja\Http\Exceptions\InvalidStatusCodeException

@return \Valkyrja\Http\Response


public function setHeaders(array $headers = []): Response
    {
        // If the headers have no been set yet
        if (null === $this->headers) {
            // Set them to a new Headers collection
            $this->headers = new Headers();
        }

        // Set all the headers with the array provided
        $this->headers->setAll($headers);

        // If there is no cache control header
        if (! $this->headers->has('Cache-Control')) {
            // Set it to an empty string
            $this->headers->set('Cache-Control', '');
        }

        return $this;
    }

Set response headers.

@param array $headers [optional] The headers to set

@return \Valkyrja\Http\Response


public function getDateHeader(): DateTime
    {
        if (! $this->headers->has('Date')) {
            $this->setDateHeader(DateTime::createFromFormat('U', time()));
        }

        return $this->headers->get('Date');
    }

public function getDateHeader ( ) : DateTime { if ( ! $ this -> headers -> has ( 'Date' ) ) { $ this -> setDateHeader ( DateTime :: createFromFormat ( 'U' , time ( ) ) ) ; } return $ this -> headers -> get ( 'Date' ) ; }

Returns the Date header as a DateTime instance.

@throws \RuntimeException When the header is not parseable

@return DateTime A DateTime instance

Returns the Date header as a DateTime instance .


public function setDateHeader(DateTime $date): Response
    {
        $date->setTimezone(new DateTimeZone('UTC'));
        $this->headers->set('Date', $date->format('D, d M Y H:i:s') . ' GMT');

        return $this;
    }

public
function
setDateHeader
(
DateTime
$
date
)
:
Response
{
$
date
->
setTimezone
(
new
DateTimeZone
(
'UTC'
)
)
;
$
this
->
headers
->
set
(
'Date'
,
$
date
->
format
(
'D, d M Y H:i:s'
)
.
' GMT'
)
;
return
$
this
;
}

Sets the Date header.

@param DateTime $date A DateTime instance

@return \Valkyrja\Http\Response


public function addCacheControl(string $name, string $value = null): Response
    {
        $this->cacheControl[$name] = $value;

        return $this;
    }

public function addCacheControl ( string $ name , string $ value = null ) : Response { $ this -> cacheControl [ $ name ] = $ value ; return $ this ; }

Set a response cache control.

@param string $name  Cache control name
@param string $value [optional] Cache control value

@return \Valkyrja\Http\Response


public function getCacheControl(string $name): string
    {
        return $this->hasCacheControl($name)
            ? $this->cacheControl[$name]
            : false;
    }

public function getCacheControl ( string $ name ) : string { return $ this -> hasCacheControl ( $ name ) ? $ this -> cacheControl [ $ name ] : false ; }

Get a response cache control.

@param string $name Cache control name

@return string


public function removeCacheControl(string $name): Response
    {
        if (! $this->hasCacheControl($name)) {
            return $this;
        }

        unset($this->cacheControl[$name]);

        return $this;
    }

public function removeCacheControl ( string $ name ) : Response { if ( ! $ this -> hasCacheControl ( $ name ) ) { return $ this ; } unset ( $ this -> cacheControl [ $ name ] ) ; return $ this ; }

Remove a response cache control.

@param string $name Cache control name

@return \Valkyrja\Http\Response


public function isCacheable(): bool
    {
        if (! \in_array(
            $this->statusCode,
            [
                StatusCode::OK,
                StatusCode::NON_AUTHORITATIVE_INFORMATION,
                StatusCode::MULTIPLE_CHOICES,
                StatusCode::MOVED_PERMANENTLY,
                StatusCode::FOUND,
                StatusCode::NOT_FOUND,
                StatusCode::GONE,
            ],
            true
        )
        ) {
            return false;
        }

        if (
            $this->hasCacheControl('no-store')
            || $this->hasCacheControl('private')
        ) {
            return false;
        }

        return $this->isValidateable() || $this->isFresh();
    }

public function isCacheable ( ) : bool { if ( ! \ in_array ( $ this -> statusCode , [ StatusCode :: OK , StatusCode :: NON_AUTHORITATIVE_INFORMATION , StatusCode :: MULTIPLE_CHOICES , StatusCode :: MOVED_PERMANENTLY , StatusCode :: FOUND , StatusCode :: NOT_FOUND , StatusCode :: GONE , ] , true ) ) { return false ; } if ( $ this -> hasCacheControl ( 'no-store' ) || $ this -> hasCacheControl ( 'private' ) ) { return false ; } return $ this -> isValidateable ( ) || $ this -> isFresh ( ) ; }

Returns true if the response is worth caching under any circumstance.

Responses marked "private" with an explicit Cache-Control directive are
considered uncacheable.

Responses with neither a freshness lifetime (Expires, max-age) nor cache
validator (Last-Modified, ETag) are considered uncacheable.

@throws \RuntimeException

@return bool true if the response is worth caching, false otherwise

Returns true if the response is worth caching under any circumstance .


public function getAge(): int
    {
        if (null !== $age = $this->headers->get('Age')) {
            return $age;
        }

        return max(
            time() - date('U', strtotime($this->getDateHeader())),
            0
        );
    }

public function getAge ( ) : int { if ( null !== $ age = $ this -> headers -> get ( 'Age' ) ) { return $ age ; } return max ( time ( ) - date ( 'U' , strtotime ( $ this -> getDateHeader ( ) ) ) , 0 ) ; }

Returns the age of the response.

@throws \RuntimeException

@return int The age of the response in seconds


public function expire(): Response
    {
        if ($this->isFresh()) {
            $this->headers->set('Age', $this->getMaxAge());
        }

        return $this;
    }

public function expire ( ) : Response { if ( $ this -> isFresh ( ) ) { $ this -> headers -> set ( 'Age' , $ this -> getMaxAge ( ) ) ; } return $ this ; }

Marks the response stale by setting the Age header to be equal to the
maximum age of the response.

@throws \RuntimeException

@return \Valkyrja\Http\Response

Marks the response stale by setting the Age header to be equal to the maximum age of the response .


public function getExpires(): DateTime
    {
        try {
            return $this->headers->get('Expires');
        } catch (\RuntimeException $e) {
            // according to RFC 2616 invalid date formats (e.g. "0" and "-1")
            // must be treated as in the past
            return DateTime::createFromFormat(
                DATE_RFC2822,
                'Sat, 01 Jan 00 00:00:00 +0000'
            );
        }
    }

Returns the value of the Expires header as a DateTime instance.

@return DateTime A DateTime instance or null if the header does not exist

Returns the value of the Expires header as a DateTime instance .


public function getMaxAge(): int
    {
        if ($this->hasCacheControl('s-maxage')) {
            return $this->getCacheControl('s-maxage');
        }

        if ($this->hasCacheControl('max-age')) {
            return $this->getCacheControl('max-age');
        }

        if (null !== $this->getExpires()) {
            return date('U', strtotime($this->getExpires())) - date(
                    'U',
                    strtotime(
                        $this->getDateHeader()
                    )
                );
        }

        return 0;
    }

public function getMaxAge ( ) : int { if ( $ this -> hasCacheControl ( 's-maxage' ) ) { return $ this -> getCacheControl ( 's-maxage' ) ; } if ( $ this -> hasCacheControl ( 'max-age' ) ) { return $ this -> getCacheControl ( 'max-age' ) ; } if ( null !== $ this -> getExpires ( ) ) { return date ( 'U' , strtotime ( $ this -> getExpires ( ) ) ) - date ( 'U' , strtotime ( $ this -> getDateHeader ( ) ) ) ; } return 0 ; }

Returns the number of seconds after the time specified in the response's
Date header when the response should no longer be considered fresh.

First, it checks for a s-maxage directive, then a max-age directive, and
then it falls back on an expires header. It returns null when no maximum
age can be established.

@throws \RuntimeException

@return int Number of seconds

Returns the number of seconds after the time specified in the response s Date header when the response should no longer be considered fresh .


public function setSharedMaxAge(int $value): Response
    {
        $this->setPublic();
        $this->addCacheControl('s-maxage', $value);

        return $this;
    }

public function setSharedMaxAge ( int $ value ) : Response { $ this -> setPublic ( ) ; $ this -> addCacheControl ( 's-maxage' , $ value ) ; return $ this ; }

Sets the number of seconds after which the response should no longer be
considered fresh by shared caches.

This methods sets the Cache-Control s-maxage directive.

@param int $value Number of seconds

@return \Valkyrja\Http\Response

Sets the number of seconds after which the response should no longer be considered fresh by shared caches .


public function setTtl(int $seconds): Response
    {
        $this->setSharedMaxAge($this->getAge() + $seconds);

        return $this;
    }

public function setTtl ( int $ seconds ) : Response { $ this -> setSharedMaxAge ( $ this -> getAge ( ) + $ seconds ) ; return $ this ; }

Sets the response's time-to-live for shared caches.

This method adjusts the Cache-Control/s-maxage directive.

@param int $seconds Number of seconds

@throws \RuntimeException

@return \Valkyrja\Http\Response

Sets the response s time - to - live for shared caches .


public function setNotModified(): Response
    {
        $this->setStatusCode(StatusCode::NOT_MODIFIED);
        $this->setContent(null);
        $this->headers
            ->remove('Allow')
            ->remove('Content-Encoding')
            ->remove('Content-Language')
            ->remove('Content-Length')
            ->remove('Content-MD5')
            ->remove('Content-Type')
            ->remove('Last-Modified');

        return $this;
    }

public function setNotModified ( ) : Response { $ this -> setStatusCode ( StatusCode :: NOT_MODIFIED ) ; $ this -> setContent ( null ) ; $ this -> headers -> remove ( 'Allow' ) -> remove ( 'Content-Encoding' ) -> remove ( 'Content-Language' ) -> remove ( 'Content-Length' ) -> remove ( 'Content-MD5' ) -> remove ( 'Content-Type' ) -> remove ( 'Last-Modified' ) ; return $ this ; }

Modifies the response so that it conforms to the rules defined for a 304
status code.

This sets the status, removes the body, and discards any headers
that MUST NOT be included in 304 responses.

@throws \InvalidArgumentException

@return \Valkyrja\Http\Response

@see http://tools.ietf.org/html/rfc2616#section-10.3.5

Modifies the response so that it conforms to the rules defined for a 304 status code .


public function isInvalid(): bool
    {
        return $this->statusCode < StatusCode::CONTINUE
            || $this->statusCode >= StatusCode::NETWORK_AUTHENTICATION_REQUIRED;
    }

public function isInvalid ( ) : bool { return $ this -> statusCode < StatusCode :: CONTINUE || $ this -> statusCode >= StatusCode :: NETWORK_AUTHENTICATION_REQUIRED ; }

Is response invalid?

@return bool

@see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html


public function isInformational(): bool
    {
        return $this->statusCode >= StatusCode::CONTINUE
            && $this->statusCode < StatusCode::OK;
    }

public function isInformational ( ) : bool { return $ this -> statusCode >= StatusCode :: CONTINUE && $ this -> statusCode < StatusCode :: OK ; }


public function isSuccessful(): bool
    {
        return $this->statusCode >= StatusCode::OK
            && $this->statusCode < StatusCode::MULTIPLE_CHOICES;
    }

public function isSuccessful ( ) : bool { return $ this -> statusCode >= StatusCode :: OK && $ this -> statusCode < StatusCode :: MULTIPLE_CHOICES ; }


public function isRedirection(): bool
    {
        return $this->statusCode >= StatusCode::MULTIPLE_CHOICES
            && $this->statusCode < StatusCode::BAD_REQUEST;
    }

public function isRedirection ( ) : bool { return $ this -> statusCode >= StatusCode :: MULTIPLE_CHOICES && $ this -> statusCode < StatusCode :: BAD_REQUEST ; }

Is the response a redirect?

@return bool


public function isClientError(): bool
    {
        return $this->statusCode >= StatusCode::BAD_REQUEST
            && $this->statusCode < StatusCode::INTERNAL_SERVER_ERROR;
    }

public function isClientError ( ) : bool { return $ this -> statusCode >= StatusCode :: BAD_REQUEST && $ this -> statusCode < StatusCode :: INTERNAL_SERVER_ERROR ; }


public function isRedirect(string $location = null): bool
    {
        return \in_array(
                $this->statusCode,
                [
                    StatusCode::CREATED,
                    StatusCode::MOVED_PERMANENTLY,
                    StatusCode::FOUND,
                    StatusCode::SEE_OTHER,
                    StatusCode::TEMPORARY_REDIRECT,
                    StatusCode::PERMANENT_REDIRECT,
                ],
                true
            )
            && (null === $location
                ?: $location === $this->headers->get('Location'));
    }

public function isRedirect ( string $ location = null ) : bool { return \ in_array ( $ this -> statusCode , [ StatusCode :: CREATED , StatusCode :: MOVED_PERMANENTLY , StatusCode :: FOUND , StatusCode :: SEE_OTHER , StatusCode :: TEMPORARY_REDIRECT , StatusCode :: PERMANENT_REDIRECT , ] , true ) && ( null === $ location ? : $ location === $ this -> headers -> get ( 'Location' ) ) ; }

Is the response a redirect of some form?

@param string $location [optional] Redirect location

@return bool


public function isEmpty(): bool
    {
        return \in_array(
            $this->statusCode,
            [
                StatusCode::NO_CONTENT,
                StatusCode::NOT_MODIFIED,
            ],
            true
        );
    }

public function isEmpty ( ) : bool { return \ in_array ( $ this -> statusCode , [ StatusCode :: NO_CONTENT , StatusCode :: NOT_MODIFIED , ] , true ) ; }