public static function extendEngineResolver(
        ContainerInterface $container,
        ?EngineResolver $engines = null
    ): ?EngineResolver {
        if ($engines !== null) {
            // @var EngineResolver $engines
            $engines->register('twig', static function () use ($container) {
                return $container->get(TwigEngine::class);
            });
        }

        return $engines;
    }

public
static
function
extendEngineResolver
(
ContainerInterface
$
container
,
EngineResolver
$
engines
=
)
:
EngineResolver
{
if
(
$
engines
!==
)
{
// @var EngineResolver $engines
$
engines
->
register
(
'twig'
,
static
function
(
)
use
(
$
container
)
{
return
$
container
->
get
(
TwigEngine
::
class
)
;
}
)
;
}
return
$
engines
;
}

Extend EngineResolver with twig extension.

@param \Psr\Container\ContainerInterface                  $container
@param null|\Viserio\Component\View\Engine\EngineResolver $engines

@return null|\Viserio\Component\View\Engine\EngineResolver

Extend EngineResolver with twig extension .


public static function createTwigEnvironment(ContainerInterface $container): TwigEnvironment
    {
        $options     = self::resolveOptions($container->get('config'));
        $twigOptions = $options['engines']['twig']['options'];

        $twig = new TwigEnvironment(
            $container->get(LoaderInterface::class),
            $twigOptions
        );

        if ($container->has(Lexer::class)) {
            $twig->setLexer($container->get(Lexer::class));
        }

        return $twig;
    }

public static function createTwigEnvironment ( ContainerInterface $ container ) : TwigEnvironment { $ options = self :: resolveOptions ( $ container -> get ( 'config' ) ) ; $ twigOptions = $ options [ 'engines' ] [ 'twig' ] [ 'options' ] ; $ twig = new TwigEnvironment ( $ container -> get ( LoaderInterface :: class ) , $ twigOptions ) ; if ( $ container -> has ( Lexer :: class ) ) { $ twig -> setLexer ( $ container -> get ( Lexer :: class ) ) ; } return $ twig ; }

Create a twig environment.

@param \Psr\Container\ContainerInterface $container

@return \Twig\Environment


public static function createTwigLoader(ContainerInterface $container): LoaderInterface
    {
        $options = self::resolveOptions($container->get('config'));

        $loaders     = [];
        $twigOptions = $options['engines']['twig'];
        $loader      = new TwigLoader($container->get(FinderContract::class));

        if (isset($twigOptions['file_extension'])) {
            $loader->setExtension($twigOptions['file_extension']);
        }

        $loaders[] = $loader;

        if (isset($twigOptions['templates']) && \is_array($twigOptions['templates'])) {
            $loaders[] = new ArrayLoader($twigOptions['templates']);
        }

        if (isset($twigOptions['loaders']) && \is_array($twigOptions['loaders'])) {
            $loaders = \array_merge($loaders, $twigOptions['loaders']);
        }

        return new ChainLoader($loaders);
    }

public static function createTwigLoader ( ContainerInterface $ container ) : LoaderInterface { $ options = self :: resolveOptions ( $ container -> get ( 'config' ) ) ; $ loaders = [ ] ; $ twigOptions = $ options [ 'engines' ] [ 'twig' ] ; $ loader = new TwigLoader ( $ container -> get ( FinderContract :: class ) ) ; if ( isset ( $ twigOptions [ 'file_extension' ] ) ) { $ loader -> setExtension ( $ twigOptions [ 'file_extension' ] ) ; } $ loaders [ ] = $ loader ; if ( isset ( $ twigOptions [ 'templates' ] ) && \ is_array ( $ twigOptions [ 'templates' ] ) ) { $ loaders [ ] = new ArrayLoader ( $ twigOptions [ 'templates' ] ) ; } if ( isset ( $ twigOptions [ 'loaders' ] ) && \ is_array ( $ twigOptions [ 'loaders' ] ) ) { $ loaders = \ array_merge ( $ loaders , $ twigOptions [ 'loaders' ] ) ; } return new ChainLoader ( $ loaders ) ; }

Create a twig bridge loader.

@param \Psr\Container\ContainerInterface $container

@return \Twig\Loader\LoaderInterface


protected function parseData(array $data): array
    {
        $newData = [];

        foreach ($data as $key => $value) {
            if (\is_array($value)) {
                return $this->parseData($value);
            }
            $newData[$key] = $value;
        }

        return $newData;
    }

protected function parseData ( array $ data ) : array { $ newData = [ ] ; foreach ( $ data as $ key => $ value ) { if ( \ is_array ( $ value ) ) { return $ this -> parseData ( $ value ) ; } $ newData [ $ key ] = $ value ; } return $ newData ; }

Parse the data array.

@param array $data

@return array


protected function createRule($rules): RespectValidator
    {
        $notRules      = [];
        $optionalRules = [];

        if (\is_string($rules)) {
            // remove duplicate
            $rules = \array_unique(\explode('|', $rules));
        }

        foreach ($rules as $key => $rule) {
            if (\mb_strpos($rule, '!') !== false) {
                $notRules[] = $rule;

                unset($rules[$key]);
            } elseif (\mb_strpos($rule, '?') !== false) {
                $optionalRules[] = $rule;

                unset($rules[$key]);
            }
        }

        // reset keys
        $rules     = \array_values($rules);
        $validator = $this->createValidator($rules, $notRules, $optionalRules);

        return $this->createChainableValidators($validator, $rules);
    }

protected
function
createRule
(
$
rules
)
:
RespectValidator
{
$
notRules
=
[
]
;
$
optionalRules
=
[
]
;
if
(
\
is_string
(
$
rules
)
)
{
// remove duplicate
$
rules
=
\
array_unique
(
\
explode
(
'|'
,
$
rules
)
)
;
}
foreach
(
$
rules
as
$
key
=>
$
rule
)
{
if
(
\
mb_strpos
(
$
rule
,
'!'
)
!==
false
)
{
$
notRules
[
]
=
$
rule
;
unset
(
$
rules
[
$
key
]
)
;
}
elseif
(
\
mb_strpos
(
$
rule
,
'?'
)
!==
false
)
{
$
optionalRules
[
]
=
$
rule
;
unset
(
$
rules
[
$
key
]
)
;
}
}
// reset keys
$
rules
=
\
array_values
(
$
rules
)
;
$
validator
=
$
this
->
createValidator
(
$
rules
,
$
notRules
,
$
optionalRules
)
;
return
$
this
->
createChainableValidators
(
$
validator
,
$
rules
)
;
}

Create a rule object.

@param array|string $rules

@return \Respect\Validation\Validator


protected function createNegativeOrOptionalValidator(string $filter, array $rules): RespectValidator
    {
        [$method, $parameters] = $this->parseStringRule($rules[0]);

        unset($rules[0]);

        $method    = \str_replace($filter, '', $method);
        $validator = RespectValidator::$method(...$parameters);

        if ($filter === '!') {
            return RespectValidator::not($this->createChainableValidators($validator, $rules));
        }

        return RespectValidator::optional($this->createChainableValidators($validator, $rules));
    }

protected function createNegativeOrOptionalValidator ( string $ filter , array $ rules ) : RespectValidator { [ $ method , $ parameters ] = $ this -> parseStringRule ( $ rules [ 0 ] ) ; unset ( $ rules [ 0 ] ) ; $ method = \ str_replace ( $ filter , '' , $ method ) ; $ validator = RespectValidator :: $ method ( ... $ parameters ) ; if ( $ filter === '!' ) { return RespectValidator :: not ( $ this -> createChainableValidators ( $ validator , $ rules ) ) ; } return RespectValidator :: optional ( $ this -> createChainableValidators ( $ validator , $ rules ) ) ; }

Create a negative or optional validator instance.

@param string $filter
@param array  $rules

@return \Respect\Validation\Validator

Create a negative or optional validator instance .


protected function createChainableValidators(RespectValidator $class, array $rules): RespectValidator
    {
        // reset keys
        $rules = \array_values($rules);

        if (\count($rules) !== 0) {
            $chain = '';

            foreach ($rules as $rule) {
                if ($rules[0] === $rule) {
                    $chain .= $rule;
                } else {
                    $chain .= '.' . $rule;
                }
            }

            return \array_reduce(\explode('.', $chain), function (object $validator, string $method) {
                [$method, $parameters] = $this->parseStringRule($method);
                $method                = \str_replace(['!', '?'], '', $method);

                return $validator->{$method}(...$parameters);
            }, $class);
        }

        return $class;
    }

protected
function
createChainableValidators
(
RespectValidator
$
class
,
array
$
rules
)
:
RespectValidator
{
// reset keys
$
rules
=
\
array_values
(
$
rules
)
;
if
(
\
count
(
$
rules
)
!==
0
)
{
$
chain
=
''
;
foreach
(
$
rules
as
$
rule
)
{
if
(
$
rules
[
0
]
===
$
rule
)
{
$
chain
.=
$
rule
;
}
else
{
$
chain
.=
'.'
.
$
rule
;
}
}
return
\
array_reduce
(
\
explode
(
'.'
,
$
chain
)
,
function
(
object
$
validator
,
string
$
method
)
{
[
$
method
,
$
parameters
]
=
$
this
->
parseStringRule
(
$
method
)
;
$
method
=
\
str_replace
(
[
'!'
,
'?'
]
,
''
,
$
method
)
;
return
$
validator
->
{
$
method
}
(
...
$
parameters
)
;
}
,
$
class
)
;
}
return
$
class
;
}

Chain validator to a chained validator object.

@param \Respect\Validation\Validator $class
@param array                         $rules

@return \Respect\Validation\Validator

Chain validator to a chained validator object .


protected function parseStringRule(string $rules): array
    {
        $parameters = [];

        // The format for specifying validation rules and parameters follows an
        // easy {rule}:{parameters} formatting convention. For instance the
        // rule "Min:3" states that the value may only be three letters.
        if (\mb_strpos($rules, ':') !== false) {
            [$rules, $parameter] = \explode(':', $rules, 2);

            $parameters = $this->parseParameters($rules, $parameter);
        }

        return [\trim($rules), $parameters];
    }

Parse a string based rule.

@param string $rules

@return array


protected function parseParameters(string $rule, string $parameter): array
    {
        if (\mb_strtolower($rule) === 'regex') {
            return [$parameter];
        }

        return \str_getcsv($parameter);
    }

protected function parseParameters ( string $ rule , string $ parameter ) : array { if ( \ mb_strtolower ( $ rule ) === 'regex' ) { return [ $ parameter ] ; } return \ str_getcsv ( $ parameter ) ; }

Parse a parameter list.

@param string $rule
@param string $parameter

@return array


public static function start(WebServerConfig $config, string $pidFile = null): int
    {
        $pidFile = $pidFile ?? self::getDefaultPidFile();

        if (self::isRunning($pidFile)) {
            throw new RuntimeException(\sprintf('A process is already listening on http://%s.', $config->getAddress()));
        }

        $pid = pcntl_fork();

        if ($pid < 0) {
            throw new RuntimeException('Unable to start the server process.');
        }

        if ($pid > 0) {
            return self::STARTED;
        }

        if (posix_setsid() < 0) {
            throw new RuntimeException('Unable to set the child process as session leader.');
        }

        $process = self::createServerProcess($config);
        $process->disableOutput();
        $process->start();

        if (! $process->isRunning()) {
            throw new RuntimeException('Unable to start the server process.');
        }

        \file_put_contents($pidFile, $config->getAddress());

        // stop the web server when the lock file is removed
        while ($process->isRunning()) {
            if (! \file_exists($pidFile)) {
                $process->stop();
            }

            \sleep(1);
        }

        return self::STOPPED;
    }

Starts a local web server in the background.

@param \Viserio\Component\WebServer\WebServerConfig $config
@param null|string                                  $pidFile

@return int

Starts a local web server in the background .


public static function stop(string $pidFile = null): void
    {
        $pidFile = $pidFile ?? self::getDefaultPidFile();

        if (! \file_exists($pidFile)) {
            throw new RuntimeException('No web server is listening.');
        }

        \unlink($pidFile);
    }

public
static
function
stop
(
string
$
pidFile
=
)
:
void
{
$
pidFile
=
$
pidFile
??
self
::
getDefaultPidFile
(
)
;
if
(
!
\
file_exists
(
$
pidFile
)
)
{
throw
new
RuntimeException
(
'No web server is listening.'
)
;
}
\
unlink
(
$
pidFile
)
;
}

Stop a running web server.

@param null|string $pidFile

@return void


public static function getAddress(string $pidFile = null)
    {
        $pidFile = $pidFile ?? self::getDefaultPidFile();

        if (! \file_exists($pidFile)) {
            return false;
        }

        return \file_get_contents($pidFile);
    }

public static function getAddress ( string $ pidFile = null ) { $ pidFile = $ pidFile ?? self :: getDefaultPidFile ( ) ; if ( ! \ file_exists ( $ pidFile ) ) { return false ; } return \ file_get_contents ( $ pidFile ) ; }

Get the address from the pid file.

@param null|string $pidFile

@return bool|string


public static function isRunning(string $pidFile = null): bool
    {
        $pidFile = $pidFile ?? self::getDefaultPidFile();

        if (! \file_exists($pidFile)) {
            return false;
        }

        $address  = \file_get_contents($pidFile);
        $pos      = \mb_strrpos($address, ':');
        $hostname = \mb_substr($address, 0, $pos);
        $port     = \mb_substr($address, $pos + 1);

        if (false !== $fp = @fsockopen($hostname, (int) $port, $errno, $errstr, 1)) {
            fclose($fp);

            return true;
        }

        \unlink($pidFile);

        return false;
    }

public static function isRunning ( string $ pidFile = null ) : bool { $ pidFile = $ pidFile ?? self :: getDefaultPidFile ( ) ; if ( ! \ file_exists ( $ pidFile ) ) { return false ; } $ address = \ file_get_contents ( $ pidFile ) ; $ pos = \ mb_strrpos ( $ address , ':' ) ; $ hostname = \ mb_substr ( $ address , 0 , $ pos ) ; $ port = \ mb_substr ( $ address , $ pos + 1 ) ; if ( false !== $ fp = @ fsockopen ( $ hostname , ( int ) $ port , $ errno , $ errstr , 1 ) ) { fclose ( $ fp ) ; return true ; } \ unlink ( $ pidFile ) ; return false ; }

Check if a server is running.

@param null|string $pidFile

@return bool


private static function createServerProcess(WebServerConfig $config): Process
    {
        $finder = new PhpExecutableFinder();

        if (($binary = $finder->find(false)) === false) {
            throw new RuntimeException('Unable to find the PHP binary.');
        }

        $xdebugArgs = [];

        if ($config->hasXdebug() && \extension_loaded('xdebug')) {
            $xdebugArgs = ['-dxdebug.profiler_enable_trigger=1'];
        }

        $process = new Process(\array_merge([$binary], $finder->findArguments(), $xdebugArgs, ['-dvariables_order=EGPCS', '-S', $config->getAddress(), $config->getRouter()]));
        $process->setWorkingDirectory($config->getDocumentRoot());
        $process->setTimeout(null);

        return $process;
    }

private
static
function
createServerProcess
(
WebServerConfig
$
config
)
:
Process
{
$
finder
=
new
PhpExecutableFinder
(
)
;
if
(
(
$
binary
=
$
finder
->
find
(
false
)
)
===
false
)
{
throw
new
RuntimeException
(
'Unable to find the PHP binary.'
)
;
}
$
xdebugArgs
=
[
]
;
if
(
$
config
->
hasXdebug
(
)
&&
\
extension_loaded
(
'xdebug'
)
)
{
$
xdebugArgs
=
[
'-dxdebug.profiler_enable_trigger=1'
]
;
}
$
process
=
new
Process
(
\
array_merge
(
[
$
binary
]
,
$
finder
->
findArguments
(
)
,
$
xdebugArgs
,
[
'-dvariables_order=EGPCS'
,
'-S'
,
$
config
->
getAddress
(
)
,
$
config
->
getRouter
(
)
]
)
)
;
$
process
->
setWorkingDirectory
(
$
config
->
getDocumentRoot
(
)
)
;
$
process
->
setTimeout
(
)
;
return
$
process
;
}

Create a new server command process.

@param \Viserio\Component\WebServer\WebServerConfig $config

@return \Symfony\Component\Process\Process


public function getListeners(string $eventName = null): array
    {
        if ($eventName === null) {
            foreach ($this->listeners as $name => $eventListeners) {
                if (! isset($this->sorted[$name])) {
                    $this->sortListeners($name);
                }
            }

            return \array_filter($this->sorted);
        }

        $this->validateEventName($eventName);

        $this->bindPatterns($eventName);

        if (! isset($this->listeners[$eventName])) {
            return [];
        }

        if (! isset($this->sorted[$eventName])) {
            $this->sortListeners($eventName);
        }

        return $this->sorted[$eventName];
    }

public function getListeners ( string $ eventName = null ) : array { if ( $ eventName === null ) { foreach ( $ this -> listeners as $ name => $ eventListeners ) { if ( ! isset ( $ this -> sorted [ $ name ] ) ) { $ this -> sortListeners ( $ name ) ; } } return \ array_filter ( $ this -> sorted ) ; } $ this -> validateEventName ( $ eventName ) ; $ this -> bindPatterns ( $ eventName ) ; if ( ! isset ( $ this -> listeners [ $ eventName ] ) ) { return [ ] ; } if ( ! isset ( $ this -> sorted [ $ eventName ] ) ) { $ this -> sortListeners ( $ eventName ) ; } return $ this -> sorted [ $ eventName ] ; }

Returns the list of listeners for an event.

The list is returned as an array, and the list of events are sorted by
their priority.

@param null|string $eventName

@return array

@internal

Returns the list of listeners for an event .


protected function removeListenerPattern(string $eventPattern, $listener): void
    {
        if (empty($this->patterns[$eventPattern])) {
            return;
        }

        /** @var ListenerPattern $pattern */
        foreach ($this->patterns[$eventPattern] as $key => $pattern) {
            if ($listener === $pattern->getListener()) {
                $pattern->unbind($this);

                unset($this->patterns[$eventPattern][$key]);
            }
        }
    }

protected
function
removeListenerPattern
(
string
$
eventPattern
,
$
listener
)
:
void
{
if
(
empty
(
$
this
->
patterns
[
$
eventPattern
]
)
)
{
return
;
}
/** @var ListenerPattern $pattern */
foreach
(
$
this
->
patterns
[
$
eventPattern
]
as
$
key
=>
$
pattern
)
{
if
(
$
listener
===
$
pattern
->
getListener
(
)
)
{
$
pattern
->
unbind
(
$
this
)
;
unset
(
$
this
->
patterns
[
$
eventPattern
]
[
$
key
]
)
;
}
}
}

Removes an event listener from any events to which it was applied due to
pattern matching.

This method cannot be used to remove a listener from a pattern that was
never registered.

@param string $eventPattern
@param mixed  $listener

@return void

Removes an event listener from any events to which it was applied due to pattern matching .


private function hasWildcards(string $subject): bool
    {
        return \mb_strpos($subject, '*') !== false || \mb_strpos($subject, '#') !== false;
    }

private function hasWildcards ( string $ subject ) : bool { return \ mb_strpos ( $ subject , '*' ) !== false || \ mb_strpos ( $ subject , '#' ) !== false ; }

Checks whether a string contains any wildcard characters.

@param string $subject

@return bool

Checks whether a string contains any wildcard characters .


private function addListenerPattern(ListenerPattern $pattern): void
    {
        $this->patterns[$pattern->getEventPattern()][] = $pattern;

        foreach ($this->syncedEvents as $eventName => $value) {
            if ($pattern->test($eventName)) {
                unset($this->syncedEvents[$eventName]);
            }
        }
    }

private function addListenerPattern ( ListenerPattern $ pattern ) : void { $ this -> patterns [ $ pattern -> getEventPattern ( ) ] [ ] = $ pattern ; foreach ( $ this -> syncedEvents as $ eventName => $ value ) { if ( $ pattern -> test ( $ eventName ) ) { unset ( $ this -> syncedEvents [ $ eventName ] ) ; } } }

Adds an event listener for all events matching the specified pattern.

This method will lazily register the listener when a matching event is
dispatched.

@param \Viserio\Component\Events\ListenerPattern $pattern

@return void

Adds an event listener for all events matching the specified pattern .


protected function readMandatoryOption(string $className, array $dimensions, array $mandatoryOptions): array
    {
        $options = [];

        foreach ($mandatoryOptions as $key => $mandatoryOption) {
            if (! \is_scalar($mandatoryOption)) {
                $options[$key] = $this->readMandatoryOption($className, $dimensions, $mandatoryOptions[$key]);

                continue;
            }

            $options[$mandatoryOption] = null;
        }

        return $options;
    }

protected function readMandatoryOption ( string $ className , array $ dimensions , array $ mandatoryOptions ) : array { $ options = [ ] ; foreach ( $ mandatoryOptions as $ key => $ mandatoryOption ) { if ( ! \ is_scalar ( $ mandatoryOption ) ) { $ options [ $ key ] = $ this -> readMandatoryOption ( $ className , $ dimensions , $ mandatoryOptions [ $ key ] ) ; continue ; } $ options [ $ mandatoryOption ] = null ; } return $ options ; }

Read the mandatory options.

@param string $className
@param array  $dimensions
@param array  $mandatoryOptions

@return array


private function buildMultidimensionalArray(array $dimensions, $value): array
    {
        $config = [];
        $index  = \array_shift($dimensions);

        if (! isset($dimensions[0])) {
            $config[$index] = $value;
        } else {
            $config[$index] = $this->buildMultidimensionalArray($dimensions, $value);
        }

        return $config;
    }

private function buildMultidimensionalArray ( array $ dimensions , $ value ) : array { $ config = [ ] ; $ index = \ array_shift ( $ dimensions ) ; if ( ! isset ( $ dimensions [ 0 ] ) ) { $ config [ $ index ] = $ value ; } else { $ config [ $ index ] = $ this -> buildMultidimensionalArray ( $ dimensions , $ value ) ; } return $ config ; }

Builds a multidimensional config array.

@param array $dimensions
@param mixed $value

@return array

Builds a multidimensional config array .


protected function getPreparedResponse(
        ?ServerRequestInterface $request,
        Throwable $exception,
        Throwable $transformed
    ): ResponseInterface {
        try {
            $response = $this->getResponse(
                $request,
                $exception,
                $transformed
            );
        } catch (Throwable $exception) {
            $this->report($exception);

            $response = $this->responseFactory->createResponse();
            $response = $response->withStatus(500, HttpStatus::getReasonPhrase(500));
            $response = $response->withHeader('content-type', 'text/plain');
        }

        return $response;
    }

protected function getPreparedResponse ( ? ServerRequestInterface $ request , Throwable $ exception , Throwable $ transformed ) : ResponseInterface { try { $ response = $ this -> getResponse ( $ request , $ exception , $ transformed ) ; } catch ( Throwable $ exception ) { $ this -> report ( $ exception ) ; $ response = $ this -> responseFactory -> createResponse ( ) ; $ response = $ response -> withStatus ( 500 , HttpStatus :: getReasonPhrase ( 500 ) ) ; $ response = $ response -> withHeader ( 'content-type' , 'text/plain' ) ; } return $ response ; }

Get a prepared response with the transformed exception.

@param null|\Psr\Http\Message\ServerRequestInterface $request
@param \Throwable                                    $exception
@param \Throwable                                    $transformed

@return \Psr\Http\Message\ResponseInterface

Get a prepared response with the transformed exception .


protected function getResponse(
        ?ServerRequestInterface $request,
        Throwable $exception,
        Throwable $transformed
    ): ResponseInterface {
        $id        = ExceptionIdentifier::identify($exception);
        $flattened = FlattenException::create($exception);
        $code      = $flattened->getStatusCode();
        $headers   = $flattened->getHeaders();

        return $this->getDisplayer(
            $request,
            $exception,
            $transformed,
            $code
        )->display($transformed, $id, $code, $headers);
    }

protected function getResponse ( ? ServerRequestInterface $ request , Throwable $ exception , Throwable $ transformed ) : ResponseInterface { $ id = ExceptionIdentifier :: identify ( $ exception ) ; $ flattened = FlattenException :: create ( $ exception ) ; $ code = $ flattened -> getStatusCode ( ) ; $ headers = $ flattened -> getHeaders ( ) ; return $ this -> getDisplayer ( $ request , $ exception , $ transformed , $ code ) -> display ( $ transformed , $ id , $ code , $ headers ) ; }

Create a response for the given exception.

@param null|\Psr\Http\Message\ServerRequestInterface $request
@param \Throwable                                    $exception
@param \Throwable                                    $transformed

@return \Psr\Http\Message\ResponseInterface

Create a response for the given exception .


protected function getDisplayer(
        ?ServerRequestInterface $request,
        Throwable $original,
        Throwable $transformed,
        int $code
    ): DisplayerContract {
        $sortedDisplayers = [];

        \ksort($this->displayers);

        \array_walk_recursive($this->displayers, static function ($displayers, $key) use (&$sortedDisplayers): void {
            $sortedDisplayers[$key] = $displayers;
        });

        if ($request !== null) {
            $filtered = $this->getFiltered($sortedDisplayers, $request, $original, $transformed, $code);

            if (\count($filtered) !== 0) {
                return $this->sortedFilter($filtered, $request);
            }
        }

        return $sortedDisplayers[$this->resolvedOptions['http']['displayer']['default']];
    }

protected function getDisplayer ( ? ServerRequestInterface $ request , Throwable $ original , Throwable $ transformed , int $ code ) : DisplayerContract { $ sortedDisplayers = [ ] ; \ ksort ( $ this -> displayers ) ; \ array_walk_recursive ( $ this -> displayers , static function ( $ displayers , $ key ) use ( & $ sortedDisplayers ) : void { $ sortedDisplayers [ $ key ] = $ displayers ; } ) ; if ( $ request !== null ) { $ filtered = $ this -> getFiltered ( $ sortedDisplayers , $ request , $ original , $ transformed , $ code ) ; if ( \ count ( $ filtered ) !== 0 ) { return $ this -> sortedFilter ( $ filtered , $ request ) ; } } return $ sortedDisplayers [ $ this -> resolvedOptions [ 'http' ] [ 'displayer' ] [ 'default' ] ] ; }

Get the displayer instance.

@param null|\Psr\Http\Message\ServerRequestInterface $request
@param \Throwable                                    $original
@param \Throwable                                    $transformed
@param int                                           $code

@return \Viserio\Component\Contract\Exception\Displayer


protected function getFiltered(
        array $displayers,
        ServerRequestInterface $request,
        Throwable $original,
        Throwable $transformed,
        int $code
    ): array {
        /** @var \Viserio\Component\Contract\Exception\Filter[] $sortedFilters */
        $sortedFilters = [];

        \ksort($this->filters);

        \array_walk_recursive($this->filters, static function ($filter, $key) use (&$sortedFilters): void {
            $sortedFilters[$key] = $filter;
        });

        foreach ($sortedFilters as $filter) {
            $displayers = $filter->filter($displayers, $request, $original, $transformed, $code);
        }

        return \array_values($displayers);
    }

Get the filtered list of displayers.

@param \Viserio\Component\Contract\Exception\Displayer[] $displayers
@param \Psr\Http\Message\ServerRequestInterface          $request
@param \Throwable                                        $original
@param \Throwable                                        $transformed
@param int                                               $code

@return \Viserio\Component\Contract\Exception\Displayer[]


private function sortedFilter(array $filtered, ServerRequestInterface $request): DisplayerContract
    {
        $accepts = self::getHeaderValuesFromString($request->getHeaderLine('Accept'));

        foreach ($accepts as $accept) {
            foreach ($filtered as $filter) {
                if ($filter->getContentType() === $accept) {
                    return $filter;
                }
            }
        }

        return $filtered[0];
    }

private function sortedFilter ( array $ filtered , ServerRequestInterface $ request ) : DisplayerContract { $ accepts = self :: getHeaderValuesFromString ( $ request -> getHeaderLine ( 'Accept' ) ) ; foreach ( $ accepts as $ accept ) { foreach ( $ filtered as $ filter ) { if ( $ filter -> getContentType ( ) === $ accept ) { return $ filter ; } } } return $ filtered [ 0 ] ; }

Sort displayer after the first found accept header.

@param array                                    $filtered
@param \Psr\Http\Message\ServerRequestInterface $request

@return \Viserio\Component\Contract\Exception\Displayer

Sort displayer after the first found accept header .


protected function addLookups(RouteContract $route): void
    {
        // If the route has a name, we will add it to the name look-up table so that we
        // will quickly be able to find any route associate with a name and not have
        // to iterate through every route every time we need to perform a look-up.
        $action = $route->getAction();

        if (isset($action['as'])) {
            $this->nameList[$action['as']] = $route;
        }

        // When the route is routing to a controller we will also store the action that
        // is used by the route. This will let us reverse route to controllers while
        // processing a request and easily generate URLs to the given controllers.
        if (isset($action['controller'])) {
            $this->actionList[\trim($action['controller'], '\\')] = $route;
        }
    }

Add the route to any look-up tables if necessary.

@param \Viserio\Component\Contract\Routing\Route $route

@return void

Add the route to any look - up tables if necessary .


protected function addAddresses($address, string $name, string $type): void
    {
        if (\is_array($address)) {
            $set = \sprintf('set%s', $type);
            $this->swift->{$set}($address, $name);

            return;
        }

        $add = \sprintf('add%s', $type);
        $this->swift->{$add}($address, $name);
    }

protected function addAddresses ( $ address , string $ name , string $ type ) : void { if ( \ is_array ( $ address ) ) { $ set = \ sprintf ( 'set%s' , $ type ) ; $ this -> swift -> { $ set } ( $ address , $ name ) ; return ; } $ add = \ sprintf ( 'add%s' , $ type ) ; $ this -> swift -> { $ add } ( $ address , $ name ) ; }

Add a recipient to the message.

@param array|string $address
@param string       $name
@param string       $type

@return void


public static function createAssetsRenderer(ContainerInterface $container): AssetsRenderer
    {
        $options = self::resolveOptions($container->get('config'));

        return new AssetsRenderer($options['jquery_is_used'], $options['path']);
    }

public static function createAssetsRenderer ( ContainerInterface $ container ) : AssetsRenderer { $ options = self :: resolveOptions ( $ container -> get ( 'config' ) ) ; return new AssetsRenderer ( $ options [ 'jquery_is_used' ] , $ options [ 'path' ] ) ; }

Create a new AssetsRenderer instance.

@param \Psr\Container\ContainerInterface $container

@return \Viserio\Component\Profiler\AssetsRenderer


protected static function registerBaseCollectors(
        ContainerInterface $container,
        ProfilerContract $profiler,
        array $options
    ): void {
        if ($options['collector']['time']) {
            $profiler->addCollector(new TimeDataCollector(
                $container->get(ServerRequestInterface::class)
            ));
        }

        if ($options['collector']['memory']) {
            $profiler->addCollector(new MemoryDataCollector());
        }

        if ($options['collector']['ajax']) {
            $profiler->addCollector(new AjaxRequestsDataCollector());
        }

        if ($options['collector']['phpinfo']) {
            $profiler->addCollector(new PhpInfoDataCollector());
        }
    }

protected static function registerBaseCollectors ( ContainerInterface $ container , ProfilerContract $ profiler , array $ options ) : void { if ( $ options [ 'collector' ] [ 'time' ] ) { $ profiler -> addCollector ( new TimeDataCollector ( $ container -> get ( ServerRequestInterface :: class ) ) ) ; } if ( $ options [ 'collector' ] [ 'memory' ] ) { $ profiler -> addCollector ( new MemoryDataCollector ( ) ) ; } if ( $ options [ 'collector' ] [ 'ajax' ] ) { $ profiler -> addCollector ( new AjaxRequestsDataCollector ( ) ) ; } if ( $ options [ 'collector' ] [ 'phpinfo' ] ) { $ profiler -> addCollector ( new PhpInfoDataCollector ( ) ) ; } }

Register base collectors.

@param \Psr\Container\ContainerInterface             $container
@param \Viserio\Component\Contract\Profiler\Profiler $profiler
@param array                                         $options

@return void


private static function registerCollectorsFromConfig(
        ContainerInterface $container,
        ProfilerContract $profiler,
        array $options
    ): void {
        if ($collectors = $options['collectors']) {
            foreach ($collectors as $collector) {
                $profiler->addCollector($container->get($collector));
            }
        }
    }

private static function registerCollectorsFromConfig ( ContainerInterface $ container , ProfilerContract $ profiler , array $ options ) : void { if ( $ collectors = $ options [ 'collectors' ] ) { foreach ( $ collectors as $ collector ) { $ profiler -> addCollector ( $ container -> get ( $ collector ) ) ; } } }

Register all found collectors in config.

@param \Psr\Container\ContainerInterface             $container
@param \Viserio\Component\Contract\Profiler\Profiler $profiler
@param array                                         $options

@return void

Register all found collectors in config .


public static function extendEventManager(
        ContainerInterface $container,
        ?EventManagerContract $eventManager = null
    ): ?EventManagerContract {
        if ($eventManager !== null) {
            $eventManager->attach(TerminableContract::TERMINATE, static function (EventContract $event): void {
                /** @var StoreContract $driver */
                $driver = $event->getTarget()->getContainer()->get(SessionManager::class)->getDriver();

                if (! $driver->getHandler() instanceof CookieSessionHandler) {
                    $driver->save();
                }
            });
        }

        return $eventManager;
    }

public
static
function
extendEventManager
(
ContainerInterface
$
container
,
EventManagerContract
$
eventManager
=
)
:
EventManagerContract
{
if
(
$
eventManager
!==
)
{
$
eventManager
->
attach
(
TerminableContract
::
TERMINATE
,
static
function
(
EventContract
$
event
)
:
void
{
/** @var StoreContract $driver */
$
driver
=
$
event
->
getTarget
(
)
->
getContainer
(
)
->
get
(
SessionManager
::
class
)
->
getDriver
(
)
;
if
(
!
$
driver
->
getHandler
(
)
instanceof
CookieSessionHandler
)
{
$
driver
->
save
(
)
;
}
}
)
;
}
return
$
eventManager
;
}

Extend viserio events with data collector.

@param \Psr\Container\ContainerInterface                    $container
@param null|\Viserio\Component\Contract\Events\EventManager $eventManager

@return null|\Viserio\Component\Contract\Events\EventManager

Extend viserio events with data collector .


public static function createSessionManager(ContainerInterface $container): SessionManager
    {
        $manager = new SessionManager($container->get('config'));

        if ($container->has(CacheManagerContract::class)) {
            $manager->setCacheManager($container->get(CacheManagerContract::class));
        }

        if ($container->has(JarContract::class)) {
            $manager->setCookieJar($container->get(JarContract::class));
        }

        return $manager;
    }

public static function createSessionManager ( ContainerInterface $ container ) : SessionManager { $ manager = new SessionManager ( $ container -> get ( 'config' ) ) ; if ( $ container -> has ( CacheManagerContract :: class ) ) { $ manager -> setCacheManager ( $ container -> get ( CacheManagerContract :: class ) ) ; } if ( $ container -> has ( JarContract :: class ) ) { $ manager -> setCookieJar ( $ container -> get ( JarContract :: class ) ) ; } return $ manager ; }

Create new session manager instance.

@param \Psr\Container\ContainerInterface $container

@return \Viserio\Component\Session\SessionManager


public static function createRouteDispatcher(
        ContainerInterface $container,
        ?callable $getPrevious = null
    ): DispatcherContract {
        // @codeCoverageIgnoreStart
        if (\is_callable($getPrevious)) {
            $dispatcher = $getPrevious();
        } elseif (\class_exists(Pipeline::class)) {
            $dispatcher = new MiddlewareBasedDispatcher();
        } else {
            $dispatcher = new SimpleDispatcher();
        }
        // @codeCoverageIgnoreStop

        if ($container->has(EventManagerContract::class)) {
            $dispatcher->setEventManager($container->get(EventManagerContract::class));
        }

        return $dispatcher;
    }

public
static
function
createRouteDispatcher
(
ContainerInterface
$
container
,
callable
$
getPrevious
=
)
:
DispatcherContract
{
// @codeCoverageIgnoreStart
if
(
\
is_callable
(
$
getPrevious
)
)
{
$
dispatcher
=
$
getPrevious
(
)
;
}
elseif
(
\
class_exists
(
Pipeline
::
class
)
)
{
$
dispatcher
=
new
MiddlewareBasedDispatcher
(
)
;
}
else
{
$
dispatcher
=
new
SimpleDispatcher
(
)
;
}
// @codeCoverageIgnoreStop
if
(
$
container
->
has
(
EventManagerContract
::
class
)
)
{
$
dispatcher
->
setEventManager
(
$
container
->
get
(
EventManagerContract
::
class
)
)
;
}
return
$
dispatcher
;
}

Create a route dispatcher instance.

@param \Psr\Container\ContainerInterface $container
@param null|callable                     $getPrevious

@return \Viserio\Component\Contract\Routing\Dispatcher


public static function createRouter(ContainerInterface $container): RouterContract
    {
        $router = new Router($container->get(DispatcherContract::class));

        $router->setContainer($container);

        return $router;
    }

public static function createRouter ( ContainerInterface $ container ) : RouterContract { $ router = new Router ( $ container -> get ( DispatcherContract :: class ) ) ; $ router -> setContainer ( $ container ) ; return $ router ; }

Create a router instance.

@param \Psr\Container\ContainerInterface $container

@return \Viserio\Component\Contract\Routing\Router


public static function createUrlGenerator(ContainerInterface $container): ?UrlGeneratorContract
    {
        if (! $container->has(UriFactoryInterface::class)) {
            return null;
        }

        return new UrlGenerator(
            $container->get(RouterContract::class)->getRoutes(),
            $container->get(ServerRequestInterface::class),
            $container->get(UriFactoryInterface::class)
        );
    }

public static function createUrlGenerator ( ContainerInterface $ container ) : ? UrlGeneratorContract { if ( ! $ container -> has ( UriFactoryInterface :: class ) ) { return null ; } return new UrlGenerator ( $ container -> get ( RouterContract :: class ) -> getRoutes ( ) , $ container -> get ( ServerRequestInterface :: class ) , $ container -> get ( UriFactoryInterface :: class ) ) ; }

Create a url generator instance.

@param \Psr\Container\ContainerInterface $container

@return null|\Viserio\Component\Contract\Routing\UrlGenerator


protected function detectConsoleEnvironment(Closure $callback, array $args): string
    {
        // First we will check if an environment argument was passed via console arguments
        // and if it was that automatically overrides as the environment. Otherwise, we
        // will check the environment as a "web" request like a typical HTTP request.
        $value = $this->getEnvironmentArgument($args);

        if ($value !== null) {
            $arr = \array_slice(\explode('=', $value), 1);

            return \reset($arr);
        }

        return $this->detectWebEnvironment($callback);
    }

Set the application environment from command-line arguments.

@param \Closure $callback
@param array    $args

@return string

Set the application environment from command - line arguments .


protected function getEnvironmentArgument(array $args): ?string
    {
        $callback = static function ($v) {
            return self::startsWith($v, '--env');
        };

        foreach ($args as $key => $value) {
            if ($callback($value)) {
                return $value;
            }
        }

        return null;
    }

protected function getEnvironmentArgument ( array $ args ) : ? string { $ callback = static function ( $ v ) { return self :: startsWith ( $ v , '--env' ) ; } ; foreach ( $ args as $ key => $ value ) { if ( $ callback ( $ value ) ) { return $ value ; } } return null ; }

Get the environment argument from the console.

@param array $args

@return null|string

Get the environment argument from the console .


public function js(): ResponseInterface
    {
        $renderer = $this->profiler->getAssetsRenderer();

        $stream = $this->streamFactory->createStream(
            $renderer->dumpAssetsToString('js')
        );

        $response = $this->responseFactory->createResponse();
        $response = $response->withHeader('content-type', 'text/js');

        return $response->withBody($stream);
    }

public function js ( ) : ResponseInterface { $ renderer = $ this -> profiler -> getAssetsRenderer ( ) ; $ stream = $ this -> streamFactory -> createStream ( $ renderer -> dumpAssetsToString ( 'js' ) ) ; $ response = $ this -> responseFactory -> createResponse ( ) ; $ response = $ response -> withHeader ( 'content-type' , 'text/js' ) ; return $ response -> withBody ( $ stream ) ; }

Return the javascript for the Debugbar.

@return \Psr\Http\Message\ResponseInterface

Return the javascript for the Debugbar .


private function fromArray(array $data, TomlBuilder $builder, string $parent = ''): TomlBuilder
    {
        foreach ($data as $key => $value) {
            if (\is_array($value)) {
                if ($this->hasStringKeys($value)) {
                    $key = $parent !== '' ? "${parent}.${key}" : $key;

                    if (\mb_strpos($key, '.') !== false) {
                        $builder->addTable($key);
                    }

                    $builder = $this->fromArray($value, $builder, $key);
                } elseif ($this->onlyArrays($value)) {
                    $builder = $this->processArrayOfArrays($value, $key, $builder);
                } else {
                    // Plain array.
                    $builder->addValue($key, $value);
                }
            } else {
                // Simple key/value.
                $builder->addValue($key, $value);
            }
        }

        return $builder;
    }

private
function
fromArray
(
array
$
data
,
TomlBuilder
$
builder
,
string
$
parent
=
''
)
:
TomlBuilder
{
foreach
(
$
data
as
$
key
=>
$
value
)
{
if
(
\
is_array
(
$
value
)
)
{
if
(
$
this
->
hasStringKeys
(
$
value
)
)
{
$
key
=
$
parent
!==
''
"${parent}.${key}"
:
$
key
;
if
(
\
mb_strpos
(
$
key
,
'.'
)
!==
false
)
{
$
builder
->
addTable
(
$
key
)
;
}
$
builder
=
$
this
->
fromArray
(
$
value
,
$
builder
,
$
key
)
;
}
elseif
(
$
this
->
onlyArrays
(
$
value
)
)
{
$
builder
=
$
this
->
processArrayOfArrays
(
$
value
,
$
key
,
$
builder
)
;
}
else
{
// Plain array.
$
builder
->
addValue
(
$
key
,
$
value
)
;
}
}
else
{
// Simple key/value.
$
builder
->
addValue
(
$
key
,
$
value
)
;
}
}
return
$
builder
;
}

Build toml file from given array.

@param array                       $data
@param \Yosymfony\Toml\TomlBuilder $builder
@param string                      $parent

@return \Yosymfony\Toml\TomlBuilder


private function processArrayOfArrays(array $values, string $parent, TomlBuilder $builder): TomlBuilder
    {
        $array = [];

        foreach ($values as $value) {
            if ($this->hasStringKeys($value)) {
                $builder->addArrayOfTable($parent);

                foreach ($value as $key => $val) {
                    if (\is_array($val)) {
                        $builder = $this->processArrayOfArrays($val, "${parent}.${key}", $builder);
                    } else {
                        $builder->addValue($key, $val);
                    }
                }
            } else {
                $array[] = $value;
            }
        }

        if (\count($array) !== 0) {
            $builder->addValue($parent, $array);
        }

        return $builder;
    }

private function processArrayOfArrays ( array $ values , string $ parent , TomlBuilder $ builder ) : TomlBuilder { $ array = [ ] ; foreach ( $ values as $ value ) { if ( $ this -> hasStringKeys ( $ value ) ) { $ builder -> addArrayOfTable ( $ parent ) ; foreach ( $ value as $ key => $ val ) { if ( \ is_array ( $ val ) ) { $ builder = $ this -> processArrayOfArrays ( $ val , "${parent}.${key}" , $ builder ) ; } else { $ builder -> addValue ( $ key , $ val ) ; } } } else { $ array [ ] = $ value ; } } if ( \ count ( $ array ) !== 0 ) { $ builder -> addValue ( $ parent , $ array ) ; } return $ builder ; }

Run through all arrays.

@param array                       $values
@param string                      $parent
@param \Yosymfony\Toml\TomlBuilder $builder

@return \Yosymfony\Toml\TomlBuilder


private function getPrettyMetadata(string $type, object $entity): string
    {
        if ($type === 'tests') {
            return '';
        }

        try {
            $meta = $this->getMetadata($type, $entity);

            if ($meta === null) {
                return '(unknown?)';
            }
        } catch (UnexpectedValueException $e) {
            return ' <error>' . $e->getMessage() . '</error>';
        }

        if ($type === 'globals') {
            if (\is_object($meta)) {
                return ' = object(' . \get_class($meta) . ')';
            }

            return ' = ' . \mb_substr(@\json_encode($meta), 0, 50);
        }

        if ($type === 'functions') {
            return '(' . \implode(', ', $meta) . ')';
        }

        if ($type === 'filters') {
            return \is_array($meta) ? '(' . \implode(', ', $meta) . ')' : '';
        }

        return '';
    }

private
function
getPrettyMetadata
(
string
$
type
,
object
$
entity
)
:
string
{
if
(
$
type
===
'tests'
)
{
return
''
;
}
try
{
$
meta
=
$
this
->
getMetadata
(
$
type
,
$
entity
)
;
if
(
$
meta
===
)
{
return
'(unknown?)'
;
}
}
catch
(
UnexpectedValueException
$
e
)
{
return
' <error>'
.
$
e
->
getMessage
(
)
.
'</error>'
;
}
if
(
$
type
===
'globals'
)
{
if
(
\
is_object
(
$
meta
)
)
{
return
' = object('
.
\
get_class
(
$
meta
)
.
')'
;
}
return
' = '
.
\
mb_substr
(
@
\
json_encode
(
$
meta
)
,
0
,
50
)
;
}
if
(
$
type
===
'functions'
)
{
return
'('
.
\
implode
(
', '
,
$
meta
)
.
')'
;
}
if
(
$
type
===
'filters'
)
{
return
\
is_array
(
$
meta
)
'('
.
\
implode
(
', '
,
$
meta
)
.
')'
:
''
;
}
return
''
;
}

Transform metadata.

@param string $type
@param object $entity

@return string


private function getLoaderPaths(Environment $twig): array
    {
        /** @var \Twig\Loader\FilesystemLoader $loader */
        $loader = $twig->getLoader();

        if (! $loader instanceof FilesystemLoader) {
            return [];
        }

        $loaderPaths = [];

        foreach ($loader->getNamespaces() as $namespace) {
            $paths = $loader->getPaths($namespace);

            if (FilesystemLoader::MAIN_NAMESPACE === $namespace) {
                $namespace = '(None)';
            } else {
                $namespace = '@' . $namespace;
            }

            $loaderPaths[$namespace] = $paths;
        }

        return $loaderPaths;
    }

Get the loader paths.

@param \Twig\Environment $twig

@return array


private function buildTableRows(array $loaderPaths): array
    {
        $rows             = [];
        $firstNamespace   = true;
        $prevHasSeparator = false;

        foreach ($loaderPaths as $namespace => $paths) {
            if (! $firstNamespace && ! $prevHasSeparator && \count($paths) > 1) {
                $rows[] = ['', ''];
            }

            $firstNamespace = false;

            foreach ($paths as $path) {
                $rows[]    = [$namespace, '- ' . $path];
                $namespace = '';
            }

            if (\count($paths) > 1) {
                $rows[]           = ['', ''];
                $prevHasSeparator = true;
            } else {
                $prevHasSeparator = false;
            }
        }

        if ($prevHasSeparator) {
            \array_pop($rows);
        }

        return $rows;
    }

private
function
buildTableRows
(
array
$
loaderPaths
)
:
array
{
$
rows
=
[
]
;
$
firstNamespace
=
true
;
$
prevHasSeparator
=
false
;
foreach
(
$
loaderPaths
as
$
namespace
=>
$
paths
)
{
if
(
!
$
firstNamespace
&&
!
$
prevHasSeparator
&&
\
count
(
$
paths
)
>
1
)
{
$
rows
[
]
=
[
''
,
''
]
;
}
$
firstNamespace
=
false
;
foreach
(
$
paths
as
$
path
)
{
$
rows
[
]
=
[
$
namespace
,
'- '
.
$
path
]
;
$
namespace
=
''
;
}
if
(
\
count
(
$
paths
)
>
1
)
{
$
rows
[
]
=
[
''
,
''
]
;
$
prevHasSeparator
=
true
;
}
else
{
$
prevHasSeparator
=
false
;
}
}
if
(
$
prevHasSeparator
)
{
\
array_pop
(
$
rows
)
;
}
return
$
rows
;
}

Build configured path table.

@param array $loaderPaths

@return array


private function getWhoops(): Whoops
    {
        $whoops = new Whoops();
        $whoops->allowQuit(false);
        $whoops->writeToOutput(false);
        $whoops->pushHandler($this->getHandler());

        return $whoops;
    }

private function getWhoops ( ) : Whoops { $ whoops = new Whoops ( ) ; $ whoops -> allowQuit ( false ) ; $ whoops -> writeToOutput ( false ) ; $ whoops -> pushHandler ( $ this -> getHandler ( ) ) ; return $ whoops ; }

Returns the whoops instance.

@return Whoops


protected function addWhereClausesToRoute(RouteContract $route): void
    {
        $where   = $route->getAction()['where'] ?? [];
        $pattern = \array_merge($this->patterns, $where);

        foreach ($pattern as $name => $value) {
            $route->where($name, $value);
        }
    }

protected function addWhereClausesToRoute ( RouteContract $ route ) : void { $ where = $ route -> getAction ( ) [ 'where' ] ?? [ ] ; $ pattern = \ array_merge ( $ this -> patterns , $ where ) ; foreach ( $ pattern as $ name => $ value ) { $ route -> where ( $ name , $ value ) ; } }

Add the necessary where clauses to the route based on its initial registration.

@param \Viserio\Component\Contract\Routing\Route $route

@return void

Add the necessary where clauses to the route based on its initial registration .


protected function mergeGroupAttributesIntoRoute(RouteContract $route): void
    {
        $action = $this->mergeWithLastGroup($route->getAction());

        $route->setAction($action);
    }

protected function mergeGroupAttributesIntoRoute ( RouteContract $ route ) : void { $ action = $ this -> mergeWithLastGroup ( $ route -> getAction ( ) ) ; $ route -> setAction ( $ action ) ; }

Merge the group stack with the controller action.

@param \Viserio\Component\Contract\Routing\Route $route

@return void

Merge the group stack with the controller action .


protected function convertToControllerAction($action): array
    {
        if (\is_string($action)) {
            $action = ['uses' => $action];
        }

        if ($this->hasGroupStack()) {
            $action['uses'] = $this->prependGroupNamespace($action['uses']);
        }

        $action['controller'] = $action['uses'];

        return $action;
    }

protected function convertToControllerAction ( $ action ) : array { if ( \ is_string ( $ action ) ) { $ action = [ 'uses' => $ action ] ; } if ( $ this -> hasGroupStack ( ) ) { $ action [ 'uses' ] = $ this -> prependGroupNamespace ( $ action [ 'uses' ] ) ; } $ action [ 'controller' ] = $ action [ 'uses' ] ; return $ action ; }

Add a controller based route action to the action array.

@param array|string $action

@return array

Add a controller based route action to the action array .


protected function prependGroupNamespace(string $uses): string
    {
        $group = \end($this->groupStack);

        return isset($group['namespace']) && \strpos($uses, '\\') !== 0 ?
            $group['namespace'] . '\\' . $uses :
            $uses;
    }

protected function prependGroupNamespace ( string $ uses ) : string { $ group = \ end ( $ this -> groupStack ) ; return isset ( $ group [ 'namespace' ] ) && \ strpos ( $ uses , '\\' ) !== 0 ? $ group [ 'namespace' ] . '\\' . $ uses : $ uses ; }

Prepend the last group uses onto the use clause.

@param string $uses

@return string

Prepend the last group uses onto the use clause .


protected function prefix(string $uri): string
    {
        $trimmed = \trim($this->getLastGroupPrefix(), '/') . '/' . \trim($uri, '/');

        if (! $trimmed) {
            return '/';
        }

        if (\strpos($trimmed, '/') === 0) {
            return $trimmed;
        }

        return '/' . $trimmed;
    }

protected function prefix ( string $ uri ) : string { $ trimmed = \ trim ( $ this -> getLastGroupPrefix ( ) , '/' ) . '/' . \ trim ( $ uri , '/' ) ; if ( ! $ trimmed ) { return '/' ; } if ( \ strpos ( $ trimmed , '/' ) === 0 ) { return $ trimmed ; } return '/' . $ trimmed ; }

Prefix the given URI with the last prefix.

@param string $uri

@return string

Prefix the given URI with the last prefix .


protected function updateGroupStack(array $attributes): void
    {
        if ($this->hasGroupStack()) {
            $attributes = RouteGroup::merge($attributes, \end($this->groupStack));
        }

        $this->groupStack[] = $attributes;
    }

protected function updateGroupStack ( array $ attributes ) : void { if ( $ this -> hasGroupStack ( ) ) { $ attributes = RouteGroup :: merge ( $ attributes , \ end ( $ this -> groupStack ) ) ; } $ this -> groupStack [ ] = $ attributes ; }

Update the group stack with the given attributes.

@param array $attributes

@return void

Update the group stack with the given attributes .


public static function createSanitizer(ContainerInterface $container): Sanitizer
    {
        $sanitizer = new Sanitizer();
        $sanitizer->setContainer($container);

        return $sanitizer;
    }

public static function createSanitizer ( ContainerInterface $ container ) : Sanitizer { $ sanitizer = new Sanitizer ( ) ; $ sanitizer -> setContainer ( $ container ) ; return $ sanitizer ; }

Create a sanitizer instance.

@param \Psr\Container\ContainerInterface $container

@return \Viserio\Component\Validation\Sanitizer


public function addBeforeBootstrapping(string $bootstrapper, callable $callback): void
    {
        $key = 'bootstrapping: ' . \str_replace('\\', '', $bootstrapper);

        $this->bootstrappingCallbacks[$key][] = $callback;
    }

public
function
addBeforeBootstrapping
(
string
$
bootstrapper
,
callable
$
callback
)
:
void
{
$
key
=
'bootstrapping: '
.
\
str_replace
(
'\\'
,
''
,
$
bootstrapper
)
;
$
this
->
bootstrappingCallbacks
[
$
key
]
[
]
=
$
callback
;
}

Register a callback to run before a bootstrapper.

@param string   $bootstrapper
@param callable $callback

@return void

Register a callback to run before a bootstrapper .


public function addAfterBootstrapping(string $bootstrapper, callable $callback): void
    {
        $key = 'bootstrapped: ' . \str_replace('\\', '', $bootstrapper);

        $this->bootstrappedCallbacks[$key][] = $callback;
    }

public
function
addAfterBootstrapping
(
string
$
bootstrapper
,
callable
$
callback
)
:
void
{
$
key
=
'bootstrapped: '
.
\
str_replace
(
'\\'
,
''
,
$
bootstrapper
)
;
$
this
->
bootstrappedCallbacks
[
$
key
]
[
]
=
$
callback
;
}

Register a callback to run after a bootstrapper.

@param string   $bootstrapper
@param callable $callback

@return void

Register a callback to run after a bootstrapper .


public function bootstrapWith(array $bootstraps): void
    {
        foreach ($bootstraps as $bootstrap) {
            $this->callCallbacks(
                $this->bootstrappingCallbacks,
                $this->kernel,
                'bootstrapping: ',
                $bootstrap
            );

            $bootstrap::bootstrap($this->kernel);

            $this->callCallbacks(
                $this->bootstrappedCallbacks,
                $this->kernel,
                'bootstrapped: ',
                $bootstrap
            );
        }

        $this->hasBeenBootstrapped = true;
    }

public
function
bootstrapWith
(
array
$
bootstraps
)
:
void
{
foreach
(
$
bootstraps
as
$
bootstrap
)
{
$
this
->
callCallbacks
(
$
this
->
bootstrappingCallbacks
,
$
this
->
kernel
,
'bootstrapping: '
,
$
bootstrap
)
;
$
bootstrap
::
bootstrap
(
$
this
->
kernel
)
;
$
this
->
callCallbacks
(
$
this
->
bootstrappedCallbacks
,
$
this
->
kernel
,
'bootstrapped: '
,
$
bootstrap
)
;
}
$
this
->
hasBeenBootstrapped
=
true
;
}

Run the given array of bootstrap classes.

@param array $bootstraps

@return void

Run the given array of bootstrap classes .


private function callCallbacks(array $bootCallbacks, KernelContract $kernel, string $type, string $bootstrap): void
    {
        foreach ($bootCallbacks as $name => $callbacks) {
            if ($type . \str_replace('\\', '', $bootstrap) === $name) {
                /** @var callable $callback */
                foreach ($callbacks as $callback) {
                    $callback($kernel);
                }
            }
        }
    }

private
function
callCallbacks
(
array
$
bootCallbacks
,
KernelContract
$
kernel
,
string
$
type
,
string
$
bootstrap
)
:
void
{
foreach
(
$
bootCallbacks
as
$
name
=>
$
callbacks
)
{
if
(
$
type
.
\
str_replace
(
'\\'
,
''
,
$
bootstrap
)
===
$
name
)
{
/** @var callable $callback */
foreach
(
$
callbacks
as
$
callback
)
{
$
callback
(
$
kernel
)
;
}
}
}
}

Calls callbacks on bootstrap name.

@param array                                         $bootCallbacks
@param \Viserio\Component\Contract\Foundation\Kernel $kernel
@param string                                        $type
@param string                                        $bootstrap

@return void


protected function generateSessionId(): string
    {
        return \hash('ripemd160', \uniqid(Str::random(23), true) . Str::random(25) . \microtime(true));
    }

protected function generateSessionId ( ) : string { return \ hash ( 'ripemd160' , \ uniqid ( Str :: random ( 23 ) , true ) . Str :: random ( 25 ) . \ microtime ( true ) ) ; }

Get a new, random session ID.

@return string


private function mergeNewFlashes(array $keys): void
    {
        $values = \array_unique(\array_merge($this->get('_flash.new', []), $keys));

        $this->set('_flash.new', $values);
    }

private function mergeNewFlashes ( array $ keys ) : void { $ values = \ array_unique ( \ array_merge ( $ this -> get ( '_flash.new' , [ ] ) , $ keys ) ) ; $ this -> set ( '_flash.new' , $ values ) ; }

Merge new flash keys into the new flash array.

@param array $keys

@return void

Merge new flash keys into the new flash array .


private function loadSession(): bool
    {
        $values = $this->readFromHandler();

        if (\count($values) === 0) {
            return false;
        }

        $metadata = $values[self::METADATA_NAMESPACE];

        $this->firstTrace        = $metadata['firstTrace'];
        $this->lastTrace         = $metadata['lastTrace'];
        $this->regenerationTrace = $metadata['regenerationTrace'];
        $this->requestsCount     = $metadata['requestsCount'];
        $this->fingerprint       = $metadata['fingerprint'];

        $this->values = \array_merge($this->values, $values);

        return true;
    }

private function loadSession ( ) : bool { $ values = $ this -> readFromHandler ( ) ; if ( \ count ( $ values ) === 0 ) { return false ; } $ metadata = $ values [ self :: METADATA_NAMESPACE ] ; $ this -> firstTrace = $ metadata [ 'firstTrace' ] ; $ this -> lastTrace = $ metadata [ 'lastTrace' ] ; $ this -> regenerationTrace = $ metadata [ 'regenerationTrace' ] ; $ this -> requestsCount = $ metadata [ 'requestsCount' ] ; $ this -> fingerprint = $ metadata [ 'fingerprint' ] ; $ this -> values = \ array_merge ( $ this -> values , $ values ) ; return true ; }

Load the session data from the handler.

@return bool

Load the session data from the handler .


private function readFromHandler(): array
    {
        $data = $this->handler->read($this->id);

        if ($data === '') {
            return [];
        }

        return $this->prepareForReadFromHandler($data);
    }

private function readFromHandler ( ) : array { $ data = $ this -> handler -> read ( $ this -> id ) ; if ( $ data === '' ) { return [ ] ; } return $ this -> prepareForReadFromHandler ( $ data ) ; }

Read the session data from the handler.

@return array

Read the session data from the handler .


private function writeToHandler(): void
    {
        $values = $this->values;

        $values[self::METADATA_NAMESPACE] = [
            'firstTrace'        => $this->firstTrace,
            'lastTrace'         => $this->lastTrace,
            'regenerationTrace' => $this->regenerationTrace,
            'requestsCount'     => $this->requestsCount,
            'fingerprint'       => $this->fingerprint,
        ];

        $value = \json_encode($values, \JSON_PRESERVE_ZERO_FRACTION);

        $this->handler->write(
            $this->id,
            $this->prepareForWriteToHandler($value)
        );
    }

private function writeToHandler ( ) : void { $ values = $ this -> values ; $ values [ self :: METADATA_NAMESPACE ] = [ 'firstTrace' => $ this -> firstTrace , 'lastTrace' => $ this -> lastTrace , 'regenerationTrace' => $ this -> regenerationTrace , 'requestsCount' => $ this -> requestsCount , 'fingerprint' => $ this -> fingerprint , ] ; $ value = \ json_encode ( $ values , \ JSON_PRESERVE_ZERO_FRACTION ) ; $ this -> handler -> write ( $ this -> id , $ this -> prepareForWriteToHandler ( $ value ) ) ; }


protected function resolveCurrentPage(): int
    {
        $query = $this->request->getQueryParams();

        if (\array_key_exists($this->pageName, $query)) {
            $query = $this->secureInput($query);
            $page  = $query[$this->pageName];

            if ((int) $page >= 1 && \filter_var($page, \FILTER_VALIDATE_INT) !== false) {
                return (int) $page;
            }
        }

        return 1;
    }

protected function resolveCurrentPage ( ) : int { $ query = $ this -> request -> getQueryParams ( ) ; if ( \ array_key_exists ( $ this -> pageName , $ query ) ) { $ query = $ this -> secureInput ( $ query ) ; $ page = $ query [ $ this -> pageName ] ; if ( ( int ) $ page >= 1 && \ filter_var ( $ page , \ FILTER_VALIDATE_INT ) !== false ) { return ( int ) $ page ; } } return 1 ; }

Resolve the current page or return the default value.

@return int

Resolve the current page or return the default value .


private function secureInput(array $query): array
    {
        $secure = static function (&$v): void {
            if (! \is_string($v) && ! \is_numeric($v)) {
                $v = '';
            } elseif (\mb_strpos($v, "\0") !== false) {
                $v = '';
            } elseif (! \mb_check_encoding($v, 'UTF-8')) {
                $v = '';
            }
        };

        \array_walk_recursive($query, $secure);

        return $query;
    }

private function secureInput ( array $ query ) : array { $ secure = static function ( & $ v ) : void { if ( ! \ is_string ( $ v ) && ! \ is_numeric ( $ v ) ) { $ v = '' ; } elseif ( \ mb_strpos ( $ v , "\0" ) !== false ) { $ v = '' ; } elseif ( ! \ mb_check_encoding ( $ v , 'UTF-8' ) ) { $ v = '' ; } } ; \ array_walk_recursive ( $ query , $ secure ) ; return $ query ; }

At least check if the input string does not have null-byte
and is a UTF-8 valid string.

@param array $query

@return array

At least check if the input string does not have null - byte and is a UTF - 8 valid string .


public static function extendEventManager(
        ContainerInterface $container,
        ?EventManager $eventManager = null
    ): ?TraceableEventManager {
        if ($eventManager !== null) {
            $options = self::resolveOptions($container->get('config'));

            if ($options['collector']['events']) {
                $eventManager = new TraceableEventManager($eventManager, $container->get(Stopwatch::class));

                if ($container->has(LoggerInterface::class)) {
                    $eventManager->setLogger($container->get(LoggerInterface::class));
                }
            }
        }

        return $eventManager;
    }

public static function extendEventManager ( ContainerInterface $ container , ? EventManager $ eventManager = null ) : ? TraceableEventManager { if ( $ eventManager !== null ) { $ options = self :: resolveOptions ( $ container -> get ( 'config' ) ) ; if ( $ options [ 'collector' ] [ 'events' ] ) { $ eventManager = new TraceableEventManager ( $ eventManager , $ container -> get ( Stopwatch :: class ) ) ; if ( $ container -> has ( LoggerInterface :: class ) ) { $ eventManager -> setLogger ( $ container -> get ( LoggerInterface :: class ) ) ; } } } return $ eventManager ; }

Extend viserio events manager with a new event.

@param \Psr\Container\ContainerInterface           $container
@param null|\Viserio\Component\Events\EventManager $eventManager

@return null|\Viserio\Component\Contract\Events\EventManager|\Viserio\Component\Events\DataCollector\TraceableEventManager

Extend viserio events manager with a new event .


protected function getFiles(array $files, array $directories): array
    {
        $foundFiles = [];

        /** @var \SplFileInfo $file */
        foreach ($this->getFinder($directories) as $file) {
            if (\count($files) !== 0 && ! \in_array($file->getFilename(), $files, true)) {
                continue;
            }

            $foundFiles[] = $file->getRealPath();
        }

        return $foundFiles;
    }

protected
function
getFiles
(
array
$
files
,
array
$
directories
)
:
array
{
$
foundFiles
=
[
]
;
/** @var \SplFileInfo $file */
foreach
(
$
this
->
getFinder
(
$
directories
)
as
$
file
)
{
if
(
\
count
(
$
files
)
!==
0
&&
!
\
in_array
(
$
file
->
getFilename
(
)
,
$
files
,
true
)
)
{
continue
;
}
$
foundFiles
[
]
=
$
file
->
getRealPath
(
)
;
}
return
$
foundFiles
;
}

Gets an array of files to lint.

@param array $files       array of files to check
@param array $directories array of directories to get the files from

@return array


protected function getFinder(array $paths): iterable
    {
        $foundFiles = [];
        $baseDir    = (array) $this->argument('dir');

        foreach ($baseDir as $dir) {
            if (\count($paths) !== 0) {
                foreach ($paths as $path) {
                    $this->findTwigFiles($dir . \DIRECTORY_SEPARATOR . $path, $foundFiles);
                }
            } else {
                $this->findTwigFiles($dir, $foundFiles);
            }
        }

        return $foundFiles;
    }

protected function getFinder ( array $ paths ) : iterable { $ foundFiles = [ ] ; $ baseDir = ( array ) $ this -> argument ( 'dir' ) ; foreach ( $ baseDir as $ dir ) { if ( \ count ( $ paths ) !== 0 ) { foreach ( $ paths as $ path ) { $ this -> findTwigFiles ( $ dir . \ DIRECTORY_SEPARATOR . $ path , $ foundFiles ) ; } } else { $ this -> findTwigFiles ( $ dir , $ foundFiles ) ; } } return $ foundFiles ; }

Get a finder instance of Twig files in the specified directories.

@param array $paths paths to search for files in

@return iterable

Get a finder instance of Twig files in the specified directories .


protected function validate(string $template, string $file): array
    {
        $realLoader = $this->environment->getLoader();

        try {
            $temporaryLoader = new ArrayLoader([$file => $template]);

            $this->environment->setLoader($temporaryLoader);
            $nodeTree = $this->environment->parse($this->environment->tokenize(new Source($template, $file)));

            $this->environment->compile($nodeTree);
            $this->environment->setLoader($realLoader);
        } catch (Error $exception) {
            $this->environment->setLoader($realLoader);

            return [
                'template'  => $template,
                'file'      => $file,
                'valid'     => false,
                'exception' => $exception,
            ];
        }

        return [
            'template' => $template,
            'file'     => $file,
            'valid'    => true,
        ];
    }

protected function validate ( string $ template , string $ file ) : array { $ realLoader = $ this -> environment -> getLoader ( ) ; try { $ temporaryLoader = new ArrayLoader ( [ $ file => $ template ] ) ; $ this -> environment -> setLoader ( $ temporaryLoader ) ; $ nodeTree = $ this -> environment -> parse ( $ this -> environment -> tokenize ( new Source ( $ template , $ file ) ) ) ; $ this -> environment -> compile ( $ nodeTree ) ; $ this -> environment -> setLoader ( $ realLoader ) ; } catch ( Error $ exception ) { $ this -> environment -> setLoader ( $ realLoader ) ; return [ 'template' => $ template , 'file' => $ file , 'valid' => false , 'exception' => $ exception , ] ; } return [ 'template' => $ template , 'file' => $ file , 'valid' => true , ] ; }

Validate the template.

@param string $template twig template
@param string $file

@return array


protected function display(array $details, string $format = 'txt'): int
    {
        $verbose = $this->getOutput()->isVerbose();

        switch ($format) {
            case 'txt':
                return $this->displayText($details, $verbose);
            case 'json':
                return $this->displayJson($details);

            default:
                throw new InvalidArgumentException(\sprintf('The format [%s] is not supported.', $format));
        }
    }

protected
function
display
(
array
$
details
,
string
$
format
=
'txt'
)
:
int
{
$
verbose
=
$
this
->
getOutput
(
)
->
isVerbose
(
)
;
switch
(
$
format
)
{
case
'txt'
:
return
$
this
->
displayText
(
$
details
,
$
verbose
)
;
case
'json'
:
return
$
this
->
displayJson
(
$
details
)
;
default
:
throw
new
InvalidArgumentException
(
\
sprintf
(
'The format [%s] is not supported.'
,
$
format
)
)
;
}
}

Output the results of the linting.

@param array  $details validation results from all linted files
@param string $format  Format to output the results in. Supports txt or json.

@throws \InvalidArgumentException thrown for an unknown format

@return int


protected function displayText(array $details, bool $verbose = false): int
    {
        $errors = 0;

        foreach ($details as $info) {
            if ($verbose && $info['valid']) {
                $file = ' in ' . $info['file'];
                $this->line('<info>OK</info>' . $file);
            } elseif (! $info['valid']) {
                $errors++;
                $this->renderException($info);
            }
        }

        if ($errors === 0) {
            $this->comment(\sprintf('All %d Twig files contain valid syntax.', \count($details)));
        } else {
            $this->warn(\sprintf('%d Twig files have valid syntax and %d contain errors.', \count($details) - $errors, $errors));
        }

        return \min($errors, 1);
    }

Output the results as text.

@param array $details validation results from all linted files
@param bool  $verbose

@return int


protected static function parseMiddlewareGroup(
        string $name,
        array $map,
        array $middlewareGroups,
        array $disabledMiddleware
    ): array {
        $results = [];

        foreach ($middlewareGroups[$name] as $middleware) {
            $name = \is_object($middleware) ? \get_class($middleware) : $middleware;

            if (isset($disabledMiddleware[$name]) || \in_array($name, $disabledMiddleware, true)) {
                continue;
            }

            // If the middleware is another middleware group we will pull in the group and
            // merge its middleware into the results. This allows groups to conveniently
            // reference other groups without needing to repeat all their middleware.
            if (\is_string($middleware) && isset($middlewareGroups[$middleware])) {
                $results = \array_merge(
                    $results,
                    self::parseMiddlewareGroup($middleware, $map, $middlewareGroups, $disabledMiddleware)
                );

                continue;
            }

            // If this middleware is actually a route middleware, we will extract the full
            // class name out of the middleware list now. Then we'll add the parameters
            // back onto this class' name so the pipeline will properly extract them.
            if (isset($map[$name])) {
                $middleware = $map[$name];
            }

            $results[] = $middleware;
        }

        return $results;
    }

Parse the middleware group and format it for usage.

@param string $name
@param array  $map
@param array  $middlewareGroups
@param array  $disabledMiddleware

@return array

Parse the middleware group and format it for usage .


private static function checkMandatoryOptions(
        string $configClass,
        array $mandatoryOptions,
        $config,
        array $interfaces
    ): void {
        foreach ($mandatoryOptions as $key => $mandatoryOption) {
            $useRecursion = ! \is_scalar($mandatoryOption);

            if (! $useRecursion && \array_key_exists($mandatoryOption, (array) $config)) {
                continue;
            }

            if ($useRecursion && isset($config[$key])) {
                self::checkMandatoryOptions($configClass, $mandatoryOption, $config[$key], $interfaces);

                return;
            }

            throw new MandatoryOptionNotFoundException(
                isset($interfaces[RequiresComponentConfigContract::class]) ? $configClass::getDimensions() : [],
                $useRecursion ? $key : $mandatoryOption
            );
        }
    }

private static function checkMandatoryOptions ( string $ configClass , array $ mandatoryOptions , $ config , array $ interfaces ) : void { foreach ( $ mandatoryOptions as $ key => $ mandatoryOption ) { $ useRecursion = ! \ is_scalar ( $ mandatoryOption ) ; if ( ! $ useRecursion && \ array_key_exists ( $ mandatoryOption , ( array ) $ config ) ) { continue ; } if ( $ useRecursion && isset ( $ config [ $ key ] ) ) { self :: checkMandatoryOptions ( $ configClass , $ mandatoryOption , $ config [ $ key ] , $ interfaces ) ; return ; } throw new MandatoryOptionNotFoundException ( isset ( $ interfaces [ RequiresComponentConfigContract :: class ] ) ? $ configClass :: getDimensions ( ) : [ ] , $ useRecursion ? $ key : $ mandatoryOption ) ; } }

Checks if a mandatory param is missing, supports recursion.

@param string             $configClass
@param array              $mandatoryOptions
@param array|\ArrayAccess $config
@param array              $interfaces

@throws \Viserio\Component\Contract\OptionsResolver\Exception\MandatoryOptionNotFoundException

@return void

Checks if a mandatory param is missing supports recursion .


private static function getConfigurationDimensions(
        array $dimensions,
        $config,
        string $configClass,
        array $interfaces,
        ?string $configId
    ) {
        foreach ($dimensions as $dimension) {
            if ((array) $config !== $config && ! $config instanceof ArrayAccess) {
                throw new UnexpectedValueException($dimensions, $dimension);
            }

            if (! isset($config[$dimension])) {
                if (! isset($interfaces[RequiresMandatoryOptionsContract::class]) &&
                    isset($interfaces[ProvidesDefaultOptionsContract::class])
                ) {
                    break;
                }

                throw new OptionNotFoundException($configClass, $dimension, $configId);
            }

            $config = $config[$dimension];
        }

        return $config;
    }

private static function getConfigurationDimensions ( array $ dimensions , $ config , string $ configClass , array $ interfaces , ? string $ configId ) { foreach ( $ dimensions as $ dimension ) { if ( ( array ) $ config !== $ config && ! $ config instanceof ArrayAccess ) { throw new UnexpectedValueException ( $ dimensions , $ dimension ) ; } if ( ! isset ( $ config [ $ dimension ] ) ) { if ( ! isset ( $ interfaces [ RequiresMandatoryOptionsContract :: class ] ) && isset ( $ interfaces [ ProvidesDefaultOptionsContract :: class ] ) ) { break ; } throw new OptionNotFoundException ( $ configClass , $ dimension , $ configId ) ; } $ config = $ config [ $ dimension ] ; } return $ config ; }

Get configuration for provided dimensions.

@param array              $dimensions
@param array|\ArrayAccess $config
@param string             $configClass
@param null|string        $configId
@param array              $interfaces

@throws \Viserio\Component\Contract\OptionsResolver\Exception\OptionNotFoundException
@throws \Viserio\Component\Contract\OptionsResolver\Exception\UnexpectedValueException

@return array|\ArrayAccess

Get configuration for provided dimensions .


private static function validateOptions(array $validators, $config, string $configClass): void
    {
        foreach ($validators as $key => $values) {
            if (! \array_key_exists($key, (array) $config)) {
                continue;
            }

            if (\is_array($values) && isset($values[0]) && \is_string($values[0])) {
                $hasError = false;

                foreach ($values as $check) {
                    if ($hasError === false && \array_key_exists($check, self::$defaultTypeMap)) {
                        $fn       = self::$defaultTypeMap[$check];
                        $hasError = $fn($config[$key]);
                    }
                }

                if (! $hasError) {
                    throw InvalidArgumentException::invalidType($key, $config[$key], $values, $configClass);
                }

                continue;
            }

            if (\is_callable($values)) {
                $values($config[$key], $key);

                continue;
            }

            if (! \is_array($values) && ! \is_callable($values)) {
                throw new InvalidValidatorException(\sprintf(
                    'The validator must be of type callable or string[]; [%s] given, in [%s].',
                    \is_object($values) ? \get_class($values) : \gettype($values),
                    $configClass
                ));
            }

            self::validateOptions((array) $values, $config[$key], $configClass);
        }
    }

Run a validator against given config.

@param array<string => array<int => string>, string => callback> $validators
@param array|\ArrayAccess                                        $config
@param string                                                    $configClass

@throws \Viserio\Component\Contract\OptionsResolver\Exception\InvalidValidatorException

@return void


private static function checkDeprecatedOptions(string $configClass, array $deprecatedOptions, $config): void
    {
        foreach ($deprecatedOptions as $key => $deprecationMessage) {
            if (\is_array($deprecationMessage)) {
                self::checkDeprecatedOptions($configClass, $deprecationMessage, $config[$key]);

                continue;
            }

            if (\is_int($key)) {
                $key                = $deprecationMessage;
                $deprecationMessage = 'The option [%s] is deprecated.';
            }

            if (! \array_key_exists($key, (array) $config)) {
                throw new InvalidArgumentException(\sprintf(
                    'Option [%s] cant be deprecated, because it does not exist, in [%s].',
                    $key,
                    $configClass
                ));
            }

            if (! \is_string($deprecationMessage)) {
                throw new InvalidArgumentException(\sprintf(
                    'Invalid deprecation message value provided for [%s]; Expected [string], but got [%s], in [%s].',
                    $key,
                    (\is_object($deprecationMessage) ? \get_class($deprecationMessage) : \gettype($deprecationMessage)),
                    $configClass
                ));
            }

            if (empty($deprecationMessage)) {
                throw new InvalidArgumentException(\sprintf(
                    'Deprecation message cant be empty, for option [%s], in [%s].',
                    $key,
                    $configClass
                ));
            }

            @\trigger_error(\sprintf($deprecationMessage, $key), \E_USER_DEPRECATED);
        }
    }

Checks if a deprecation exists and triggers a deprecation error.

@param string             $configClass
@param array              $deprecatedOptions
@param array|\ArrayAccess $config

@throws \Viserio\Component\Contract\OptionsResolver\Exception\InvalidArgumentException If deprecation message cant be found or
the key don't exists in the config array

@return void

Checks if a deprecation exists and triggers a deprecation error .


public function register(string $name, string $controller, array $options = []): void
    {
        if (isset($options['parameters']) && \count($this->parameters) === 0) {
            $this->parameters = (array) $options['parameters'];
        }

        // If the resource name contains a slash, we will assume the developer wishes to
        // register these resource routes with a prefix so we will set that up out of
        // the box so they don't have to mess with it. Otherwise, we will continue.
        if (\strpos($name, '/') !== false) {
            $this->prefixedResource($name, $controller, $options);

            return;
        }

        // We need to extract the base resource from the resource name.
        $baseResource = \explode('.', $name);
        $resource     = \end($baseResource);

        // Wildcards for a single or nested resource may be overridden using the wildcards option.
        // Overrides are performed by matching the wildcards key with the resource name. If a key
        // matches a resource name, the value of the wildcard is used instead of the resource name.
        if (isset($options['wildcards'][$resource])) {
            $resource = $options['wildcards'][$resource];
        }

        // Nested resources are supported in the framework, but we need to know what
        // name to use for a place-holder on the route wildcards, which should be
        // the base resources.
        $base = $this->getResourceWildcard($resource);

        $defaults = self::$resourceDefaults;

        foreach ($this->getResourceMethods($defaults, $options) as $m) {
            $this->{'addResource' . \ucfirst($m)}($name, $base, $controller, $options);
        }
    }

Route a resource to a controller.

@param string $name
@param string $controller
@param array  $options

@return void


public function getResourceUri(string $resource, array $options): string
    {
        if (\strpos($resource, '.') === false) {
            return $resource;
        }

        // Once we have built the base URI, we'll remove the parameter holder for this
        // base resource name so that the individual route adders can suffix these
        // paths however they need to, as some do not have any parameters at all.
        $segments = \explode('.', $resource);

        $uri = $this->getNestedResourceUri($segments, $options);

        $resource = \end($segments);

        if (isset($options['wildcards'][$resource])) {
            $resource = $options['wildcards'][$resource];
        }

        return \str_replace('/{' . $this->getResourceWildcard($resource) . '}', '', $uri);
    }

Get the base resource URI for a given resource.

@param string $resource
@param array  $options

@return string

Get the base resource URI for a given resource .


public function getResourceWildcard(string $value): string
    {
        if (isset($this->parameters[$value])) {
            $value = $this->parameters[$value];
        } elseif (isset(static::$parameterMap[$value])) {
            $value = static::$parameterMap[$value];
        } elseif (static::$singularParameters || \array_search('singular', $this->parameters, true) !== false) {
            $value = Str::singular($value);
        }

        return \str_replace('-', '_', $value);
    }

public function getResourceWildcard ( string $ value ) : string { if ( isset ( $ this -> parameters [ $ value ] ) ) { $ value = $ this -> parameters [ $ value ] ; } elseif ( isset ( static :: $ parameterMap [ $ value ] ) ) { $ value = static :: $ parameterMap [ $ value ] ; } elseif ( static :: $ singularParameters || \ array_search ( 'singular' , $ this -> parameters , true ) !== false ) { $ value = Str :: singular ( $ value ) ; } return \ str_replace ( '-' , '_' , $ value ) ; }

Format a resource parameter for usage.

@param string $value

@return string


protected function getResourcePrefix(string $name): array
    {
        $segments = \explode('/', $name);

        // To get the prefix, we will take all of the name segments and implode them on
        // a slash. This will generate a proper URI prefix for us. Then we take this
        // last segment, which will be considered the final resources name we use.
        $prefix = \implode('/', \array_slice($segments, 0, -1));

        return [\end($segments), $prefix];
    }

Extract the resource and prefix from a resource name.

@param string $name

@return array

Extract the resource and prefix from a resource name .


protected function addResourceDestroy(string $name, string $base, string $controller, array $options): RouteContract
    {
        $uri = $this->getResourceUri($name, $options) . '/{' . $base . '}';

        $action = $this->getResourceAction($name, $controller, 'destroy', $options);

        return $this->router->delete($uri, $action);
    }

protected function addResourceDestroy ( string $ name , string $ base , string $ controller , array $ options ) : RouteContract { $ uri = $ this -> getResourceUri ( $ name , $ options ) . '/{' . $ base . '}' ; $ action = $ this -> getResourceAction ( $ name , $ controller , 'destroy' , $ options ) ; return $ this -> router -> delete ( $ uri , $ action ) ; }

Add the destroy method for a resourceful route.

@param string $name
@param string $base
@param string $controller
@param array  $options

@return Route

Add the destroy method for a resourceful route .


protected function getNestedResourceUri(array $segments, array $options): string
    {
        // We will spin through the segments and create a place-holder for each of the
        // resource segments, as well as the resource itself. Then we should get an
        // entire string for the resource URI that contains all nested resources.
        return \implode('/', \array_map(function ($s) use ($options) {
            $wildcard = $s;

            //If a wildcard for a resource has been set to be overridden
            if (isset($options['wildcards'][$s])) {
                $wildcard = $options['wildcards'][$s];
            }

            return $s . '/{' . $this->getResourceWildcard($wildcard) . '}';
        }, $segments));
    }

Get the URI for a nested resource segment array.

@param array $segments
@param array $options

@return string

Get the URI for a nested resource segment array .


protected function getResourceAction(string $resource, string $controller, string $method, array $options): array
    {
        $name = $this->getResourceRouteName($resource, $method, $options);

        $action = ['as' => $name, 'uses' => $controller . '@' . $method];

        if (isset($options['middleware'])) {
            $action['middleware'] = $options['middleware'];
        }

        if (isset($options['bypass'])) {
            $action['bypass'] = $options['bypass'];
        }

        return $action;
    }

protected function getResourceAction ( string $ resource , string $ controller , string $ method , array $ options ) : array { $ name = $ this -> getResourceRouteName ( $ resource , $ method , $ options ) ; $ action = [ 'as' => $ name , 'uses' => $ controller . '@' . $ method ] ; if ( isset ( $ options [ 'middleware' ] ) ) { $ action [ 'middleware' ] = $ options [ 'middleware' ] ; } if ( isset ( $ options [ 'bypass' ] ) ) { $ action [ 'bypass' ] = $ options [ 'bypass' ] ; } return $ action ; }

Get the action array for a resource route.

@param string $resource
@param string $controller
@param string $method
@param array  $options

@return array

Get the action array for a resource route .


protected function getResourceRouteName(string $resource, string $method, array $options): string
    {
        $name = $resource;

        // If the names array has been provided to us we will check for an entry in the
        // array first. We will also check for the specific method within this array
        // so the names may be specified on a more "granular" level using methods.
        if (isset($options['names'])) {
            if (\is_string($options['names'])) {
                $name = $options['names'];
            } elseif (isset($options['names'][$method])) {
                return $options['names'][$method];
            }
        }

        // If a global prefix has been assigned to all names for this resource, we will
        // grab that so we can prepend it onto the name when we create this name for
        // the resource action. Otherwise we'll just use an empty string for here.
        $prefix = isset($options['as']) ? $options['as'] . '.' : '';

        return \trim(\sprintf('%s%s.%s', $prefix, $name, $method), '.');
    }

Get the name for a given resource.

@param string $resource
@param string $method
@param array  $options

@return string


protected function sliceThroughContainer($traveler, $stack, string $stage)
    {
        [$name, $parameters] = $this->parseStageString($stage);
        $parameters          = \array_merge([$traveler, $stack], $parameters);
        $class               = null;

        if ($this->container->has($name)) {
            $class = $this->container->get($name);
        } elseif ($this->container instanceof FactoryContract) {
            $class = $this->container->resolve($name);
        } else {
            throw new RuntimeException(\sprintf('Class [%s] is not being managed by the container.', $name));
        }

        return $this->getInvoker()->call([$class, $this->method], $parameters);
    }

Resolve from container.

@param mixed  $traveler
@param mixed  $stack
@param string $stage

@throws \Viserio\Component\Contract\Routing\Exception\RuntimeException

@return mixed


private function getRequestHandlerMiddleware(callable $middleware): RequestHandlerInterface
    {
        return new class($middleware) implements RequestHandlerInterface {
            /**
             * @var callable
             */
            private $middleware;

            /**
             * Create a new delegate callable middleware instance.
             *
             * @param callable $middleware
             */
            public function __construct(callable $middleware)
            {
                $this->middleware = $middleware;
            }

            /**
             * {@inheritdoc}
             */
            public function handle(ServerRequestInterface $request): ResponseInterface
            {
                return \call_user_func($this->middleware, $request);
            }
        };
    }

/**
             * @var callable
             */

/**
             * {@inheritdoc}
             */

Private delegate callable middleware for the pipe.

@param callable $middleware

@return \Psr\Http\Server\RequestHandlerInterface

Private delegate callable middleware for the pipe .


protected function findArgumentFiles(array $paths, array $searchDirectories, array $files): array
    {
        $search = [];

        foreach ($files as $fileName) {
            if (\count($searchDirectories) !== 0) {
                /** @var \SplFileObject $file */
                foreach ($this->getFinder($searchDirectories, $fileName) as $file) {
                    $search[] = $file->getRealPath();
                }
            } else {
                /** @var \SplFileObject $file */
                foreach ($this->getFinder($paths, $fileName) as $file) {
                    $search[] = $file->getRealPath();
                }
            }
        }

        return $search;
    }

protected
function
findArgumentFiles
(
array
$
paths
,
array
$
searchDirectories
,
array
$
files
)
:
array
{
$
search
=
[
]
;
foreach
(
$
files
as
$
fileName
)
{
if
(
\
count
(
$
searchDirectories
)
!==
0
)
{
/** @var \SplFileObject $file */
foreach
(
$
this
->
getFinder
(
$
searchDirectories
,
$
fileName
)
as
$
file
)
{
$
search
[
]
=
$
file
->
getRealPath
(
)
;
}
}
else
{
/** @var \SplFileObject $file */
foreach
(
$
this
->
getFinder
(
$
paths
,
$
fileName
)
as
$
file
)
{
$
search
[
]
=
$
file
->
getRealPath
(
)
;
}
}
}
return
$
search
;
}

Gets an array of argument files to lint.

@param array $paths
@param array $searchDirectories
@param array $files

@return array

Gets an array of argument files to lint .


public function getIpAddress(): ?string
    {
        $ipAddress    = null;
        $request      = $this->serverRequest;
        $serverParams = $request->getServerParams();

        // direct IP address
        if (isset($serverParams['REMOTE_ADDR']) && $this->isValidIpAddress($serverParams['REMOTE_ADDR'])) {
            $ipAddress = $serverParams['REMOTE_ADDR'];
        }

        foreach (self::$headersToInspect as $header) {
            if ($request->hasHeader($header)) {
                $ip = $this->getFirstIpAddressFromHeader($request, $header);

                if ($this->isValidIpAddress($ip)) {
                    $ipAddress = $ip;

                    break;
                }
            }
        }

        return $ipAddress;
    }

public
function
getIpAddress
(
)
:
string
{
$
ipAddress
=
;
$
request
=
$
this
->
serverRequest
;
$
serverParams
=
$
request
->
getServerParams
(
)
;
// direct IP address
if
(
isset
(
$
serverParams
[
'REMOTE_ADDR'
]
)
&&
$
this
->
isValidIpAddress
(
$
serverParams
[
'REMOTE_ADDR'
]
)
)
{
$
ipAddress
=
$
serverParams
[
'REMOTE_ADDR'
]
;
}
foreach
(
self
::
$
headersToInspect
as
$
header
)
{
if
(
$
request
->
hasHeader
(
$
header
)
)
{
$
ip
=
$
this
->
getFirstIpAddressFromHeader
(
$
request
,
$
header
)
;
if
(
$
this
->
isValidIpAddress
(
$
ip
)
)
{
$
ipAddress
=
$
ip
;
break
;
}
}
}
return
$
ipAddress
;
}

Returns client IP address.

@return null|string


private function isValidIpAddress(string $ip): bool
    {
        return (bool) \filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4 | \FILTER_FLAG_IPV6);
    }

private function isValidIpAddress ( string $ ip ) : bool { return ( bool ) \ filter_var ( $ ip , \ FILTER_VALIDATE_IP , \ FILTER_FLAG_IPV4 | \ FILTER_FLAG_IPV6 ) ; }

Check that a given string is a valid IP address.

@param string $ip

@return bool

Check that a given string is a valid IP address .


private function getFirstIpAddressFromHeader(ServerRequestInterface $serverRequest, string $header): string
    {
        $items       = \explode(',', $serverRequest->getHeaderLine($header));
        $headerValue = \trim(\reset($items));

        if (\ucfirst($header) === 'Forwarded') {
            foreach (\explode(';', $headerValue) as $headerPart) {
                if (\mb_strtolower(\mb_substr($headerPart, 0, 4)) === 'for=') {
                    $for         = \explode(']', $headerPart);
                    $headerValue = \trim(\mb_substr(\reset($for), 4), " \t\n\r\0\x0B" . '"[]');

                    break;
                }
            }
        }

        return $headerValue;
    }

private
function
getFirstIpAddressFromHeader
(
ServerRequestInterface
$
serverRequest
,
string
$
header
)
:
string
{
$
items
=
\
explode
(
','
,
$
serverRequest
->
getHeaderLine
(
$
header
)
)
;
$
headerValue
=
\
trim
(
\
reset
(
$
items
)
)
;
if
(
\
ucfirst
(
$
header
)
===
'Forwarded'
)
{
foreach
(
\
explode
(
';'
,
$
headerValue
)
as
$
headerPart
)
{
if
(
\
mb_strtolower
(
\
mb_substr
(
$
headerPart
,
0
,
4
)
)
===
'for='
)
{
$
for
=
\
explode
(
']'
,
$
headerPart
)
;
$
headerValue
=
\
trim
(
\
mb_substr
(
\
reset
(
$
for
)
,
4
)
,
" \t\n\r\0\x0B"
.
'"[]'
)
;
break
;
}
}
}
return
$
headerValue
;
}

Find out the client's IP address from the headers available to us.

@param \Psr\Http\Message\ServerRequestInterface $serverRequest
@param string                                   $header        Header name

@return string

Find out the client s IP address from the headers available to us .


public function setDomain(string $domain): self
    {
        $this->url = $this->baseUrl . '/v3/' . $domain . '/messages.mime';

        $this->domain = $domain;

        return $this;
    }

public function setDomain ( string $ domain ) : self { $ this -> url = $ this -> baseUrl . '/v3/' . $ domain . '/messages.mime' ; $ this -> domain = $ domain ; return $ this ; }

Set the domain being used by the transport.

@param string $domain

@return $this

Set the domain being used by the transport .


protected function validateInput($middleware): void
    {
        if (\is_array($middleware) || \is_string($middleware) || \is_object($middleware)) {
            return;
        }

        throw new UnexpectedValueException(\sprintf(
            'Expected string, object or array; received [%s].',
            \gettype($middleware)
        ));
    }

Check if given input is a string, object or array.

@param array|object|string $middleware

@throws \Viserio\Component\Contract\Routing\Exception\UnexpectedValueException

@return void

Check if given input is a string object or array .


protected function validateMiddleware($middleware): void
    {
        $middleware = $this->getMiddlewareClassName($middleware);
        $interfaces = \class_implements($middleware);

        if (! isset($interfaces[MiddlewareInterface::class])) {
            throw new UnexpectedValueException(
                \sprintf('%s is not implemented in [%s].', MiddlewareInterface::class, $middleware)
            );
        }
    }

protected
function
validateMiddleware
(
$
middleware
)
:
void
{
$
middleware
=
$
this
->
getMiddlewareClassName
(
$
middleware
)
;
$
interfaces
=
\
class_implements
(
$
middleware
)
;
if
(
!
isset
(
$
interfaces
[
MiddlewareInterface
::
class
]
)
)
{
throw
new
UnexpectedValueException
(
\
sprintf
(
'%s is not implemented in [%s].'
,
MiddlewareInterface
::
class
,
$
middleware
)
)
;
}
}

Validates if given object or string has a middleware interface.

@param \Psr\Http\Server\MiddlewareInterface|string $middleware

@throws \Viserio\Component\Contract\Routing\Exception\UnexpectedValueException if \Psr\Http\Server\MiddlewareInterface was not found

@return void

Validates if given object or string has a middleware interface .