<?php
declare(strict_types=1);
namespace Viserio\Component\Log\DataCollector;

use ErrorException;
use Monolog\Logger as MonologLogger;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Viserio\Bridge\Monolog\Processor\DebugProcessor;
use Viserio\Component\Contract\Profiler\Exception\RuntimeException;
use Viserio\Component\Contract\Profiler\Exception\UnexpectedValueException;
use Viserio\Component\Contract\Profiler\PanelAware as PanelAwareContract;
use Viserio\Component\Contract\Profiler\TooltipAware as TooltipAwareContract;
use Viserio\Component\Log\Logger;
use Viserio\Component\Profiler\DataCollector\AbstractDataCollector;

class LoggerDataCollector extends AbstractDataCollector implements
    TooltipAwareContract,
    PanelAwareContract
{
    /**
     * Monolog logger instance.
     *
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * Create a new logs data collector instance.
     *
     * @param \Monolog\Logger|\Viserio\Component\Log\Logger $logger
     *
     * @throws \Viserio\Component\Contract\Profiler\Exception\UnexpectedValueException if wrong class is given
     * @throws \Viserio\Component\Contract\Profiler\Exception\RuntimeException
     */
    public function __construct($logger)
    {
        if ($logger instanceof MonologLogger) {
            $this->logger = $logger;
        } elseif ($logger instanceof Logger) {
            $this->logger = $logger->getMonolog();
        } else {
            throw new UnexpectedValueException(\sprintf(
                'Class [%s] or [%s] is required; Instance of [%s] given.',
                MonologLogger::class,
                Logger::class,
                (\is_object($logger) ? \get_class($logger) : \gettype($logger))
            ));
        }

        if ($this->getDebugLogger() === null) {
            throw new RuntimeException(\sprintf('Processor %s is missing from %s', DebugProcessor::class, \get_class($logger)));
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getMenu(): array
    {
        $status = '';

        if ($this->getCountedErrors() !== 0) {
            $status = 'status-red';
        } elseif ($this->getCountedWarnings() !== 0 || $this->getCountedDeprecations() !== 0) {
            $status = 'status-yellow';
        }

        return [
            'class' => $status,
            'label' => 'Logs',
            'icon'  => 'ic_library_books_white_24px.svg',
            'value' => $this->data['counted'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getTooltip(): string
    {
        return $this->createTooltipGroup([
            'Errors'       => $this->getCountedErrors(),
            'Warnings'     => $this->getCountedWarnings(),
            'Deprecations' => $this->getCountedDeprecations(),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function getPanel(): string
    {
        $tableHeaders = ['Level', 'Channel', 'Message'];

        $logs = $this->groupLogLevels();

        return $this->createTabs([
            [
                'name'    => 'Info. & Errors ' . \count($logs['info_error']) . '',
                'content' => $this->createTable(
                    $logs['info_error'],
                    [
                        'headers'   => $tableHeaders,
                        'vardumper' => false,
                    ]
                ),
            ], [
                'name'    => 'Deprecations ' . $this->getCountedDeprecations() . '',
                'content' => $this->createTable(
                    $logs['deprecation'],
                    [
                        'headers'   => $tableHeaders,
                        'vardumper' => false,
                    ]
                ),
            ], [
                'name'    => 'Debug ' . \count($logs['debug']) . '',
                'content' => $this->createTable(
                    $logs['debug'],
                    [
                        'headers'   => $tableHeaders,
                        'vardumper' => false,
                    ]
                ),
            ], [
                'name'    => 'Silenced PHP Notices ' . \count($logs['silenced']) . '',
                'content' => $this->createTable(
                    $logs['silenced'],
                    [
                        'headers'   => $tableHeaders,
                        'vardumper' => false,
                    ]
                ),
            ],
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function collect(ServerRequestInterface $serverRequest, ResponseInterface $response): void
    {
        $data = $this->getComputedErrorsCount();

        $data['logs']    = $this->sanitizeLogs($this->getLogs());
        $data['counted'] = \count($data['logs']);

        $this->data = $data;
    }

    /**
     * Get log error priorities.
     *
     * @return array
     */
    public function getPriorities(): array
    {
        return $this->data['priorities'] ?? [];
    }

    /**
     * Get counted errors.
     *
     * @return int
     */
    public function getCountedErrors(): int
    {
        return $this->data['error_count'] ?? 0;
    }

    /**
     * Get counted deprecations.
     *
     * @return int
     */
    public function getCountedDeprecations(): int
    {
        return $this->data['deprecation_count'] ?? 0;
    }

    /**
     * Get counted warnings.
     *
     * @return int
     */
    public function getCountedWarnings(): int
    {
        return $this->data['warning_count'] ?? 0;
    }

    /**
     * Get counted screams.
     *
     * @return int
     */
    public function getCountedScreams(): int
    {
        return $this->data['scream_count'] ?? 0;
    }

    /**
     * Get counted logs.
     *
     * @return int
     */
    public function getCountedLogs(): int
    {
        return $this->data['counted'] ?? 0;
    }

    /**
     * Returns collected logs.
     *
     * @return array
     */
    public function getLogs(): array
    {
        if ($logger = $this->getDebugLogger()) {
            return $logger->getLogs();
        }

        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function reset(): void
    {
        if (($logger = $this->getDebugLogger()) && \method_exists($logger, 'reset')) {
            $logger->reset();
        }
    }

    /**
     * Returns a DebugProcessor instance if one is registered with this logger.
     *
     * @return null|\Viserio\Bridge\Monolog\Processor\DebugProcessor
     */
    private function getDebugLogger(): ?DebugProcessor
    {
        foreach ($this->logger->getProcessors() as $processor) {
            if ($processor instanceof DebugProcessor) {
                return $processor;
            }
        }

        return null;
    }

    /**
     * Undocumented function.
     *
     * @param array $logs
     *
     * @return array
     */
    private function sanitizeLogs(array $logs): array
    {
        $sanitizedLogs = [];

        foreach ($logs as $log) {
            if (! $this->isSilencedOrDeprecationErrorLog($log)) {
                $sanitizedLogs[] = $log;

                continue;
            }

            $exception = $log['context']['exception'];
            $errorId   = \md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$log['message']}", true);

            if (isset($sanitizedLogs[$errorId])) {
                $sanitizedLogs[$errorId]['errorCount']++;
            } else {
                $log += [
                    'errorCount' => 1,
                    'scream'     => $exception instanceof SilencedErrorContext,
                ];

                $sanitizedLogs[$errorId] = $log;
            }
        }

        return \array_values($sanitizedLogs);
    }

    /**
     * Find silenced or deprecation in error log.
     *
     * @param array $log
     *
     * @return bool
     */
    private function isSilencedOrDeprecationErrorLog(array $log): bool
    {
        if (! isset($log['context']['exception'])) {
            return false;
        }

        $exception = $log['context']['exception'];

        if ($exception instanceof SilencedErrorContext) {
            return true;
        }

        if ($exception instanceof ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], true)) {
            return true;
        }

        return false;
    }

    /**
     * Get computed log error levels.
     *
     * @return array
     */
    private function getComputedErrorsCount(): array
    {
        $errorCount = 0;

        if ($logger = $this->getDebugLogger()) {
            $errorCount = $logger->countErrors();
        }

        $count = [
            'error_count'       => $errorCount,
            'deprecation_count' => 0,
            'warning_count'     => 0,
            'scream_count'      => 0,
            'priorities'        => [],
        ];

        foreach ($this->getLogs() as $log) {
            if (isset($count['priorities'][$log['priority']])) {
                $count['priorities'][$log['priority']]['count']++;
            } else {
                $count['priorities'][$log['priority']] = [
                    'count' => 1,
                    'name'  => $log['priorityName'],
                ];
            }

            if ('WARNING' === $log['priorityName']) {
                $count['warning_count']++;
            }

            if ($this->isSilencedOrDeprecationErrorLog($log)) {
                if ($log['context']['exception'] instanceof SilencedErrorContext) {
                    $count['scream_count']++;
                } else {
                    $count['deprecation_count']++;
                }
            }
        }

        \ksort($count['priorities']);

        return $count;
    }

    /**
     * Group log level together.
     *
     * @return array
     */
    private function groupLogLevels(): array
    {
        $deprecationLogs  = [];
        $debugLogs        = [];
        $infoAndErrorLogs = [];
        $silencedLogs     = [];

        $formatLog = function ($log) {
            return[
                $log['priorityName'] . '
' . '
' . \date('H:i:s', $log['timestamp']) . '
',
                $log['channel'],
                $log['message'] . '
' . (\count($log['context']) !== 0 ? $this->cloneVar($log['context']) : ''),
            ];
        };

        foreach ((array) $this->data['logs'] as $log) {
            if (isset($log['priority'])) {
                if (\in_array($log['priority'], [Logger::ERROR, Logger::INFO], true)) {
                    $infoAndErrorLogs[] = $formatLog($log);
                } elseif ($log['priority'] === Logger::DEBUG) {
                    $debugLogs[] = $formatLog($log);
                }
            } elseif ($this->isSilencedOrDeprecationErrorLog($log)) {
                if (isset($log['context']) && $log['context']['exception'] instanceof SilencedErrorContext) {
                    $silencedLogs[] = $formatLog($log);
                } else {
                    $deprecationLogs[] = $formatLog($log);
                }
            }
        }

        return [
            'deprecation' => $deprecationLogs,
            'debug'       => $debugLogs,
            'info_error'  => $infoAndErrorLogs,
            'silenced'    => $silencedLogs,
        ];
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Console\Provider;

use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Viserio\Component\Console\Application;
use Viserio\Component\Contract\OptionsResolver\ProvidesDefaultOptions as ProvidesDefaultOptionsContract;
use Viserio\Component\Contract\OptionsResolver\RequiresComponentConfig as RequiresComponentConfigContract;
use Viserio\Component\OptionsResolver\Traits\OptionsResolverTrait;

class LazilyCommandsServiceProvider implements
    ServiceProviderInterface,
    RequiresComponentConfigContract,
    ProvidesDefaultOptionsContract
{
    use OptionsResolverTrait;

    /**
     * {@inheritdoc}
     */
    public function getFactories(): array
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function getExtensions(): array
    {
        return [
            Application::class => [self::class, 'extendConsole'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public static function getDimensions(): array
    {
        return ['viserio', 'console'];
    }

    /**
     * {@inheritdoc}
     */
    public static function getDefaultOptions(): array
    {
        return [
            'lazily_commands' => [],
        ];
    }

    /**
     * Extend viserio console with commands.
     *
     * @param \Psr\Container\ContainerInterface           $container
     * @param null|\Viserio\Component\Console\Application $console
     *
     * @return null|\Viserio\Component\Console\Application
     */
    public static function extendConsole(ContainerInterface $container, ?Application $console = null): ?Application
    {
        if ($console !== null) {
            $options = self::resolveOptions($container->get('config'));

            $console->setCommandLoader(new ContainerCommandLoader($container, $options['lazily_commands']));
        }

        return $console;
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Pagination\Presenter;

use Viserio\Component\Contract\Pagination\Paginator as PaginatorContract;
use Viserio\Component\Contract\Pagination\Presenter as PresenterContract;

class Bootstrap4 implements PresenterContract
{
    /**
     * Paginator instance.
     *
     * @var \Viserio\Component\Contract\Pagination\Paginator
     */
    protected $paginator;

    /**
     * Create a new Bootstrap 4 presenter.
     *
     * @param \Viserio\Component\Contract\Pagination\Paginator $paginator
     */
    public function __construct(PaginatorContract $paginator)
    {
        $this->paginator = $paginator;
    }

    /**
     * {@inheritdoc}
     */
    public function render(): string
    {
        $paginator = $this->paginator;

        if ($paginator->hasPages()) {
            $pagination = '
';

            // Previous Page Link
            if ($paginator->onFirstPage()) {
                $pagination .= '
«
';
            } else {
                $pagination .= '
getPreviousPageUrl() . '" rel="prev">«
';
            }

            if (\method_exists($paginator, 'getElements')) {
                $this->getPaginationsLinks($paginator->getElements(), $pagination);
            }

            // Next Page Link
            if ($paginator->hasMorePages()) {
                $pagination .= '
getNextPageUrl() . '" rel="next">»
';
            } else {
                $pagination .= '
»
';
            }

            $pagination .= '
';

            return $pagination;
        }

        return '';
    }

    /**
     * Get all paginations page links.
     *
     * @param array  $items
     * @param string $pagination
     */
    private function getPaginationsLinks(array $items, $pagination): void
    {
        foreach ($items as $item) {
            if (\is_string($item)) {
                $pagination .= '
' . $item . '
';
            }

            // Array Of Links
            if (\is_array($item)) {
                foreach ($item as $page => $url) {
                    if ($this->paginator->getCurrentPage() === $page) {
                        $pagination .= '
' . $page . '
';
                    } else {
                        $pagination .= '
' . $page . '
';
                    }
                }
            }
        }
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Events;

use Closure;
use Viserio\Component\Contract\Events\EventManager as EventManagerContract;

class ListenerPattern
{
    /**
     * The event priority.
     *
     * @var int
     */
    protected $priority;

    /**
     * The regex for the event.
     *
     * @var string
     */
    protected $regex;

    /**
     * The event.
     *
     * @var mixed
     */
    protected $listener;

    /**
     * The listener provider.
     *
     * @var mixed
     */
    protected $provider;

    /**
     * Pattern for the event.
     *
     * @var string
     */
    protected $eventPattern;

    /**
     * All added events.
     *
     * @var array
     */
    protected $events = [];

    /**
     * Wildcards separators.
     *
     * @var array
     */
    private static $wildcardsSeparators = [
        // Trailing single-wildcard with separator prefix
        '/\\\\\.\\\\\*$/'     => '(?:\.\w+)?',
        // Single-wildcard with separator prefix
        '/\\\\\.\\\\\*/'      => '(?:\.\w+)',
        // Single-wildcard without separator prefix
        '/(?<!\\\\\.)\\\\\*/' => '(?:\w+)',
        // Multi-wildcard with separator prefix
        '/\\\\\.#/'           => '(?:\.\w+)*',
        // Multi-wildcard without separator prefix
        '/(?<!\\\\\.)#/'      => '(?:|\w+(?:\.\w+)*)',
    ];

    /**
     * Create a new listener pattern instance.
     *
     * @param string $eventPattern
     * @param mixed  $listener
     * @param int    $priority
     */
    public function __construct(string $eventPattern, $listener, int $priority = 0)
    {
        if ($listener instanceof Closure ||
            \is_string($listener) ||
            \is_array($listener) ||
            \is_callable($listener)
        ) {
            $this->provider = $listener;
        } else {
            $this->provider = static function () use ($listener) {
                return $listener;
            };
        }

        $this->eventPattern = $eventPattern;
        $this->priority     = $priority;
        $this->regex        = $this->createRegex($eventPattern);
    }

    /**
     * Get the listener.
     *
     * @return mixed
     */
    public function getListener()
    {
        if ($this->listener === null && $this->provider !== null) {
            $this->listener = $this->provider;
            $this->provider = null;
        }

        return $this->listener;
    }

    /**
     * Get the event pattern.
     *
     * @return string
     */
    public function getEventPattern(): string
    {
        return $this->eventPattern;
    }

    /**
     * Adds this pattern's listener to an event.
     *
     * @param \Viserio\Component\Contract\Events\EventManager $dispatcher
     * @param string                                          $eventName
     *
     * @return void
     */
    public function bind(EventManagerContract $dispatcher, string $eventName): void
    {
        if (isset($this->events[$eventName])) {
            return;
        }

        $dispatcher->attach($eventName, $this->getListener(), $this->priority);
        $this->events[$eventName] = true;
    }

    /**
     * Removes this pattern's listener from all events to which it was
     * previously added.
     *
     * @param \Viserio\Component\Contract\Events\EventManager $dispatcher
     *
     * @return void
     */
    public function unbind(EventManagerContract $dispatcher): void
    {
        foreach ($this->events as $eventName => $value) {
            $dispatcher->detach($eventName, $this->getListener());
        }

        $this->events = [];
    }

    /**
     * Tests if this pattern matches and event name.
     *
     * @param string $eventName
     *
     * @return bool
     */
    final public function test(string $eventName): bool
    {
        return (bool) \preg_match($this->regex, $eventName);
    }

    /**
     * Transforms an event pattern into a regular expression.
     *
     * @param string $eventPattern
     *
     * @return string
     */
    private function createRegex(string $eventPattern): string
    {
        return \sprintf('/^%s$/i', \preg_replace(
            \array_keys(self::$wildcardsSeparators),
            \array_values(self::$wildcardsSeparators),
            \str_replace('\#', '#', \preg_quote($eventPattern, '/'))
        ));
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Parser\Parser;

use Viserio\Component\Contract\Parser\Exception\ParseException;
use Viserio\Component\Contract\Parser\Exception\RuntimeException;
use Viserio\Component\Contract\Parser\Parser as ParserContract;
use Yosymfony\Toml\Exception\ParseException as TomlParseException;
use Yosymfony\Toml\Toml as YosymfonyToml;

class TomlParser implements ParserContract
{
    /**
     * Create a new Toml parser.
     *
     * @throws \Viserio\Component\Contract\Parser\Exception\RuntimeException
     *
     * @codeCoverageIgnore
     */
    public function __construct()
    {
        if (! \class_exists(YosymfonyToml::class)) {
            throw new RuntimeException('Unable to read toml, the Toml Parser is not installed.');
        }
    }

    /**
     * {@inheritdoc}
     */
    public function parse(string $payload): array
    {
        try {
            return YosymfonyToml::parse($payload);
        } catch (TomlParseException $exception) {
            throw new ParseException([
                'message' => 'Unable to parse the TOML string.',
                'line'    => $exception->getParsedLine(),
            ]);
        }
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Config;

use ArrayIterator;
use IteratorAggregate;
use Narrowspark\Arr\Arr;
use Viserio\Component\Contract\Config\Exception\FileNotFoundException;
use Viserio\Component\Contract\Config\ParameterProcessor as ParameterProcessorContract;
use Viserio\Component\Contract\Config\Repository as RepositoryContract;
use Viserio\Component\Contract\Parser\Traits\ParserAwareTrait;

class Repository implements RepositoryContract, IteratorAggregate
{
    use ParserAwareTrait;

    /**
     * Config folder path.
     *
     * @var string
     */
    protected $path;

    /**
     * Storage array of values.
     *
     * @var array
     */
    protected $data = [];

    /**
     * Array of all processors.
     *
     * @var \Viserio\Component\Contract\Config\ParameterProcessor[]
     */
    protected $parameterProcessors = [];

    /**
     * {@inheritdoc}
     */
    public function getParameterProcessors(): array
    {
        return $this->parameterProcessors;
    }

    /**
     * {@inheritdoc}
     */
    public function addParameterProcessor(ParameterProcessorContract $parameterProcessor): RepositoryContract
    {
        $this->parameterProcessors[$parameterProcessor::getReferenceKeyword()] = $parameterProcessor;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function import(string $filePath, array $options = null): RepositoryContract
    {
        if ($this->loader === null && \pathinfo($filePath, \PATHINFO_EXTENSION) === 'php') {
            if (! \file_exists($filePath)) {
                throw new FileNotFoundException(\sprintf('File [%s] not found.', $filePath));
            }

            $config = (array) require \str_replace(['\\', '/'], '/', $filePath);
        } else {
            $config = $this->getLoader()->load($filePath, $options);
        }

        $this->setArray($config);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function set(string $key, $value): RepositoryContract
    {
        $this->offsetSet($key, $value);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function get(string $key, $default = null)
    {
        if (! $this->offsetExists($key)) {
            return $default;
        }

        return $this->offsetGet($key);
    }

    /**
     * {@inheritdoc}
     */
    public function has(string $key): bool
    {
        return $this->offsetExists($key);
    }

    /**
     * {@inheritdoc}
     */
    public function delete(string $key): RepositoryContract
    {
        $this->offsetUnset($key);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setArray(array $values = []): RepositoryContract
    {
        $this->data = Arr::merge($this->data, $values);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getAll(): array
    {
        return $this->data;
    }

    /**
     * {@inheritdoc}
     */
    public function getAllProcessed(): array
    {
        return $this->processParameters($this->data);
    }

    /**
     * {@inheritdoc}
     */
    public function getAllFlat(): array
    {
        return Arr::flatten($this->data, '.');
    }

    /**
     * {@inheritdoc}
     */
    public function getKeys(): array
    {
        return \array_keys(Arr::flatten($this->data, '.'));
    }

    /**
     * Get a value from a nested array based on a separated key.
     *
     * @param string $key
     *
     * @return mixed
     */
    public function offsetGet($key)
    {
        $value = Arr::get($this->data, $key);

        if (\is_array($value)) {
            $value = $this->processParameters($value);
        } else {
            $value = $this->processParameter($value);
        }

        return $value;
    }

    /**
     * Set nested array values based on a separated key.
     *
     * @param string $key
     * @param mixed  $value
     *
     * @return $this
     */
    public function offsetSet($key, $value): self
    {
        $this->data = Arr::set($this->data, $key, $value);

        return $this;
    }

    /**
     * Check an array has a value based on a separated key.
     *
     * @param string $key
     *
     * @return bool
     */
    public function offsetExists($key): bool
    {
        return Arr::has($this->data, $key);
    }

    /**
     * Remove nested array value based on a separated key.
     *
     * @param string $key
     *
     * @return \Viserio\Component\Contract\Config\Repository
     */
    public function offsetUnset($key): RepositoryContract
    {
        Arr::forget($this->data, $key);

        return $this;
    }

    /**
     * Get an ArrayIterator for the stored items.
     *
     * @return \ArrayIterator
     */
    public function getIterator(): ArrayIterator
    {
        return new ArrayIterator($this->getAll());
    }

    /**
     * Process array through all parameter processors.
     *
     * @param array $data
     *
     * @return array
     */
    private function processParameters(array $data): array
    {
        \array_walk_recursive($data, function (&$parameter): void {
            // @codeCoverageIgnoreStart
            if (\is_array($parameter)) {
                $parameter = $this->processParameters($parameter);
            // @codeCoverageIgnoreEnd
            } else {
                $parameter = $this->processParameter($parameter);
            }
        });

        return $data;
    }

    /**
     * Process through all parameter processors.
     *
     * @param mixed $parameter
     *
     * @return mixed
     */
    private function processParameter($parameter)
    {
        foreach ($this->parameterProcessors as $processor) {
            if ($processor->supports((string) $parameter)) {
                return $processor->process($parameter);
            }
        }

        return $parameter;
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Exception\Console;

use ErrorException;
use Throwable;
use Viserio\Component\Contract\Exception\ConsoleHandler;
use Viserio\Component\Contract\Exception\ConsoleOutput as ConsoleOutputContract;
use Viserio\Component\Exception\ErrorHandler;
use Viserio\Component\Exception\Traits\DetermineErrorLevelTrait;
use Viserio\Component\Exception\Traits\RegisterAndUnregisterTrait;

class Handler extends ErrorHandler implements ConsoleHandler
{
    use DetermineErrorLevelTrait;
    use RegisterAndUnregisterTrait;

    /**
     * The number of frames if no verbosity is specified.
     *
     * @var int
     */
    private const VERBOSITY_NORMAL_FRAMES = 1;

    /**
     * Render an exception to the console.
     *
     * @param \Viserio\Component\Contract\Exception\ConsoleOutput $output
     * @param \Throwable                                          $exception
     *
     * @return void
     */
    public function render(ConsoleOutputContract $output, Throwable $exception): void
    {
        $exceptionMessage = $exception->getMessage();
        $exceptionName    = \get_class($exception);

        $output->writeln('');
        $output->writeln(\sprintf(
            '<bg=red;options=bold>%s</> : <comment>%s</>',
            $exceptionName,
            $exceptionMessage
        ));
        $output->writeln('');

        $this->renderEditor($output, $exception);
        $this->renderTrace($output, $exception);
    }

    /**
     * Renders the editor containing the code that was the
     * origin of the exception.
     *
     * @param \Viserio\Component\Contract\Exception\ConsoleOutput $output
     * @param \Throwable                                          $exception
     *
     * @return void
     */
    private function renderEditor(ConsoleOutputContract $output, Throwable $exception): void
    {
        $output->writeln(\sprintf(
            'at <fg=green>%s</>' . ':<fg=green>%s</>',
            $exception->getFile(),
            $exception->getLine()
        ));

        $range = self::getFileLines(
            $exception->getFile(),
            $exception->getLine() - 5,
            10
        );

        foreach ($range as $k => $code) {
            $line = $k + 1;
            $code = $exception->getLine() === $line ? \sprintf('<bg=red>%s</>', $code) : $code;
            $output->writeln(\sprintf('%s: %s', $line, $code));
        }

        $output->writeln('');
    }

    /**
     * Renders the trace of the exception.
     *
     * @param \Viserio\Component\Contract\Exception\ConsoleOutput $output
     * @param \Throwable                                          $exception
     *
     * @return void
     */
    private function renderTrace(ConsoleOutputContract $output, Throwable $exception): void
    {
        $output->writeln('<comment>Exception trace:</comment>');
        $output->writeln('');

        $count = 0;

        foreach ($this->getFrames($exception) as $i => $frame) {
            if ($i > static::VERBOSITY_NORMAL_FRAMES &&
                $output->getVerbosity() < ConsoleOutputContract::VERBOSITY_VERBOSE
            ) {
                $output->writeln('');
                $output->writeln(
                    '<info>Please use the argument <fg=red>-v</> to see all trace.</info>'
                );

                break;
            }

            $class    = isset($frame['class']) ? $frame['class'] . '::' : '';
            $function = $frame['function'] ?? '';

            if ($class !== '' && $function !== '') {
                $output->writeln(\sprintf(
                    '<comment><fg=cyan>%s</>%s%s(%s)</comment>',
                    \str_pad((string) ((int) $i + 1), 4, ' '),
                    $class,
                    $function,
                    isset($frame['args']) ? self::formatsArgs($frame['args']) : ''
                ));
            }

            if (isset($frame['file'], $frame['line'])) {
                $output->writeln(\sprintf(
                    '    <fg=green>%s</>:<fg=green>%s</>',
                    $frame['file'],
                    $frame['line']
                ));
            }

            if ($count !== 4) {
                $output->writeln('');
            }

            $count++;
        }
    }

    /**
     * Gets the backtrace from an exception.
     *
     * If xdebug is installed
     *
     * @param \Throwable $exception
     *
     * @return array
     */
    private function getTrace(Throwable $exception): array
    {
        $traces = $exception->getTrace();

        // Get trace from xdebug if enabled, failure exceptions only trace to the shutdown handler by default
        if (! $exception instanceof ErrorException) {
            return $traces;
        }

        if (! self::isLevelFatal($exception->getSeverity())) {
            return $traces;
        }

        if (! \extension_loaded('xdebug') || ! \xdebug_is_enabled()) {
            return [];
        }

        // Use xdebug to get the full stack trace and remove the shutdown handler stack trace
        $stack  = \array_reverse(\xdebug_get_function_stack());
        $trace  = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);

        return \array_diff_key($stack, $trace);
    }

    /**
     * Returns an iterator for the inspected exception's
     * frames.
     *
     * @param \Throwable $exception
     *
     * @return array
     */
    private function getFrames(Throwable $exception): array
    {
        $frames = $this->getTrace($exception);

        // Fill empty line/file info for call_user_func_array usages (PHP Bug #44428)
        foreach ($frames as $k => $frame) {
            if (empty($frame['file'])) {
                // Default values when file and line are missing
                $file      = '[internal]';
                $line      = 0;
                $nextFrame = \count($frames[$k + 1]) !== 0 ? $frames[$k + 1] : [];

                if ($this->isValidNextFrame($nextFrame)) {
                    $file = $nextFrame['file'];
                    $line = $nextFrame['line'];
                }

                $frames[$k]['file'] = $file;
                $frames[$k]['line'] = $line;
            }

            $frames['function'] = $frame['function'] ?? '';
        }

        // Find latest non-error handling frame index ($i) used to remove error handling frames
        $i = 0;

        foreach ($frames as $k => $frame) {
            if (isset($frame['file'], $frame['line']) &&
                $frame['file'] === $exception->getFile() &&
                $frame['line'] === $exception->getLine()
            ) {
                $i = $k;
            }
        }

        // Remove error handling frames
        if ($i > 0) {
            \array_splice($frames, 0, $i);
        }

        \array_unshift($frames, $this->getFrameFromException($exception));

        // show the last 5 frames
        return \array_slice($frames, 0, 5);
    }

    /**
     * Given an exception, generates an array in the format
     * generated by Exception::getTrace().
     *
     * @param \Throwable $exception
     *
     * @return array
     */
    private function getFrameFromException(Throwable $exception): array
    {
        return [
            'file'     => $exception->getFile(),
            'line'     => $exception->getLine(),
            'class'    => \get_class($exception),
            'function' => '__construct',
            'args'     => [
                $exception->getMessage(),
            ],
        ];
    }

    /**
     * Determine if the frame can be used to fill in previous frame's missing info
     * happens for call_user_func and call_user_func_array usages (PHP Bug #44428).
     *
     * @param array $frame
     *
     * @return bool
     */
    private function isValidNextFrame(array $frame): bool
    {
        if (empty($frame['file']) || empty($frame['line'])) {
            return false;
        }

        if (empty($frame['function']) || \stripos($frame['function'], 'call_user_func') === false) {
            return false;
        }

        return true;
    }

    /**
     * Format the given function args to a string.
     *
     * @param array $arguments
     * @param bool  $recursive
     *
     * @return string
     */
    private static function formatsArgs(array $arguments, bool $recursive = true): string
    {
        $result = [];

        foreach ($arguments as $argument) {
            switch (true) {
                case \is_string($argument):
                    $result[] = '"' . $argument . '"';

                    break;
                case \is_array($argument):
                    $associative = \array_keys($argument) !== \range(0, \count($argument) - 1);

                    if ($recursive && $associative && \count($argument) <= 5) {
                        $result[] = '[' . self::formatsArgs($argument, false) . ']';
                    }

                    break;
                case \is_object($argument):
                    $class    = \get_class($argument);
                    $result[] = "Object(${class})";

                    break;
            }
        }

        return \implode(', ', $result);
    }

    /**
     * Returns the contents of the file for this frame as an
     * array of lines, and optionally as a clamped range of lines.
     *
     * @param string $filePath
     * @param int    $start
     * @param int    $length
     *
     * @return null|string[]
     */
    private static function getFileLines(string $filePath, int $start, int $length): ?array
    {
        if (($contents = self::getFileContents($filePath)) !== null) {
            $lines = \explode("\n", $contents);

            if ($start < 0) {
                $start = 0;
            }

            return \array_slice($lines, $start, $length, true);
        }
    }

    /**
     * Returns the full contents of the file for this frame,
     * if it's known.
     *
     * @param string $filePath
     *
     * @return null|string
     */
    private static function getFileContents(string $filePath): ?string
    {
        // Leave the stage early when 'Unknown' is passed
        // this would otherwise raise an exception when
        // open_basedir is enabled.
        if ($filePath === 'Unknown') {
            return null;
        }

        // Return null if the file doesn't actually exist.
        if (! \is_file($filePath)) {
            return null;
        }

        return \file_get_contents($filePath);
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\View\Traits;

use Viserio\Component\Contract\View\Finder as FinderContract;

trait NormalizeNameTrait
{
    /**
     * Normalize a view name.
     *
     * @param string $name
     *
     * @return string
     */
    protected function normalizeName(string $name): string
    {
        $delimiter = FinderContract::HINT_PATH_DELIMITER;

        if (\mb_strpos($name, $delimiter) === false) {
            return \str_replace('/', '.', $name);
        }

        [$namespace, $name] = \explode($delimiter, $name);

        return $namespace . $delimiter . \str_replace('/', '.', $name);
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\StaticalProxy\Bootstrap;

use Viserio\Component\Contract\Foundation\BootstrapState as BootstrapStateContract;
use Viserio\Component\Contract\Foundation\Kernel as KernelContract;
use Viserio\Component\Contract\StaticalProxy\AliasLoader as AliasLoaderContract;
use Viserio\Component\Foundation\Bootstrap\LoadServiceProvider;
use Viserio\Component\StaticalProxy\StaticalProxy;

class RegisterStaticalProxies implements BootstrapStateContract
{
    /**
     * {@inheritdoc}
     */
    public static function getPriority(): int
    {
        return 32;
    }

    /**
     * {@inheritdoc}
     */
    public static function getType(): string
    {
        return BootstrapStateContract::TYPE_AFTER;
    }

    /**
     * {@inheritdoc}
     */
    public static function getBootstrapper(): string
    {
        return LoadServiceProvider::class;
    }

    /**
     * {@inheritdoc}
     */
    public static function bootstrap(KernelContract $kernel): void
    {
        $container = $kernel->getContainer();

        StaticalProxy::clearResolvedInstances();
        StaticalProxy::setContainer($container);

        $container->get(AliasLoaderContract::class)->register();
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Container;

use Closure;
use ReflectionClass;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionParameter;
use Viserio\Component\Contract\Container\Exception\BindingResolutionException;
use Viserio\Component\Contract\Container\Exception\CyclicDependencyException;

class ContainerResolver
{
    /**
     * The stack of concretions currently being built.
     *
     * @var array
     */
    protected $buildStack = [];

    /**
     * Resolves an entry by its name. If given a class name, it will return a new instance of that class.
     *
     * @param mixed $subject
     * @param array $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     * @throws \ReflectionException
     *
     * @return mixed|object
     */
    public function resolve($subject, array $parameters = [])
    {
        if ($this->isClass($subject)) {
            return $this->resolveClass($subject, $parameters);
        }

        if ($this->isMethod($subject)) {
            return $this->resolveMethod($subject, $parameters);
        }

        if ($this->isFunction($subject)) {
            return $this->resolveFunction($subject, $parameters);
        }

        $subject = \is_object($subject) ? \get_class($subject) : $subject;

        throw new BindingResolutionException(\sprintf(
            '[%s] is not resolvable. Build stack : [%s]',
            $subject,
            \implode(', ', $this->buildStack)
        ));
    }

    /**
     * Resolve a class.
     *
     * @param string $class
     * @param array  $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     * @throws \ReflectionException
     *
     * @return object
     */
    public function resolveClass(string $class, array $parameters = []): object
    {
        $reflectionClass = new ReflectionClass($class);

        if (! $reflectionClass->isInstantiable()) {
            throw new BindingResolutionException(
                \sprintf(
                    'Unable to reflect on the class [%s], does the class exist and is it properly autoloaded?',
                    $class
                )
            );
        }

        if (\in_array($class, $this->buildStack, true)) {
            $this->buildStack[] = $class;

            throw new CyclicDependencyException($class, $this->buildStack);
        }

        $reflectionMethod   = $reflectionClass->getConstructor();
        $this->buildStack[] = $reflectionClass->name;

        if ($reflectionMethod) {
            $reflectionParameters = $reflectionMethod->getParameters();
            $parameters           = $this->resolveParameters($reflectionParameters, $parameters);
        }

        \array_pop($this->buildStack);

        return $reflectionClass->newInstanceArgs($parameters);
    }

    /**
     * Resolve a method.
     *
     * @param array|string $method
     * @param array        $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     * @throws \ReflectionException
     *
     * @return mixed
     */
    public function resolveMethod($method, array $parameters = [])
    {
        $reflectionMethod     = $this->getMethodReflector($method);
        $reflectionParameters = $reflectionMethod->getParameters();
        $this->buildStack[]   = $reflectionMethod->name;
        $resolvedParameters   = $this->resolveParameters($reflectionParameters, $parameters);

        \array_pop($this->buildStack);

        return $method(...$resolvedParameters);
    }

    /**
     * Resolve a closure / function.
     *
     * @param callable|string $function
     * @param array           $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     * @throws \ReflectionException
     *
     * @return mixed
     */
    public function resolveFunction($function, array $parameters = [])
    {
        $reflectionFunction   = new ReflectionFunction($function);
        $reflectionParameters = $reflectionFunction->getParameters();
        $this->buildStack[]   = $reflectionFunction->name;
        $resolvedParameters   = $this->resolveParameters($reflectionParameters, $parameters);

        \array_pop($this->buildStack);

        return $reflectionFunction->invokeArgs($resolvedParameters);
    }

    /**
     * @codeCoverageIgnore
     *
     * Get the reflection object for something.
     *
     * @param mixed $subject
     *
     * @throws \ReflectionException
     *
     * @return null|\ReflectionClass|\ReflectionFunction|\ReflectionMethod
     */
    public function getReflector($subject)
    {
        if ($this->isClass($subject)) {
            return new ReflectionClass($subject);
        }

        if ($this->isMethod($subject)) {
            return $this->getMethodReflector($subject);
        }

        if ($this->isFunction($subject)) {
            return new ReflectionFunction($subject);
        }

        return null;
    }

    /**
     * Resolve a parameter.
     *
     * @param \ReflectionParameter $parameter
     * @param array                $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     *
     * @return mixed
     */
    protected function resolveParameter(ReflectionParameter $parameter, array $parameters = [])
    {
        $name  = $parameter->name;
        $index = $parameter->getPosition();

        if (isset($parameters[$name])) {
            return $parameters[$name];
        }

        if (isset($parameters[$index])) {
            return $parameters[$index];
        }

        if ($class = $parameter->getClass()) {
            return $this->resolve($class->name);
        }

        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }

        throw new BindingResolutionException(\sprintf(
            'Unresolvable dependency resolving [%s] in [%s]',
            $parameter,
            \end($this->buildStack)
        ));
    }

    /**
     * Resolve an array of \ReflectionParameter parameters.
     *
     * @param array $reflectionParameters
     * @param array $parameters
     *
     * @throws \Viserio\Component\Contract\Container\Exception\BindingResolutionException
     * @throws \Viserio\Component\Contract\Container\Exception\CyclicDependencyException
     *
     * @return array
     */
    protected function resolveParameters(array $reflectionParameters, array $parameters = []): array
    {
        $dependencies = [];

        foreach ($reflectionParameters as $key => $parameter) {
            $dependencies[] = $this->resolveParameter($parameter, $parameters);
        }

        return $this->mergeParameters($dependencies, $parameters);
    }

    /**
     * Get the reflection object for a method.
     *
     * @param array|string $method
     *
     * @throws \ReflectionException
     *
     * @return \ReflectionMethod
     */
    protected function getMethodReflector($method): ReflectionMethod
    {
        if (\is_string($method)) {
            return new ReflectionMethod($method);
        }

        return new ReflectionMethod($method[0], $method[1]);
    }

    /**
     * Check if something is a class.
     *
     * @param mixed $value
     *
     * @return bool
     */
    protected function isClass($value): bool
    {
        return \is_string($value) && \class_exists($value);
    }

    /**
     * Check if something is a method.
     *
     * @param mixed $value
     *
     * @return bool
     */
    protected function isMethod($value): bool
    {
        return \is_callable($value) && ! $this->isFunction($value);
    }

    /**
     * Check if something is a function.
     *
     * @param mixed $value
     *
     * @return bool
     */
    protected function isFunction($value): bool
    {
        return \is_callable($value) && ($value instanceof Closure || (\is_string($value) && \function_exists($value)));
    }

    /**
     * Merge some dynamically resolved parameters with some others provided parameters by the user.
     *
     * @param array $rootParameters
     * @param array $parameters
     *
     * @return array
     */
    private function mergeParameters(array $rootParameters, array $parameters = []): array
    {
        foreach ($parameters as $key => $value) {
            if (\is_int($key) && ! isset($rootParameters[$key])) {
                $rootParameters[$key] = $value;
            }
        }

        return $rootParameters;
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Filesystem\Encryption;

use ParagonIE\Halite\Alerts\FileAccessDenied;
use ParagonIE\Halite\Alerts\FileModified;
use ParagonIE\Halite\File;
use ParagonIE\Halite\Symmetric\EncryptionKey;
use Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException;
use Viserio\Component\Contract\Filesystem\Exception\FileModifiedException;
use Viserio\Component\Contract\Filesystem\Exception\RuntimeException;
use Viserio\Component\Contract\Filesystem\Filesystem as FilesystemContract;

class EncryptionWrapper
{
    /**
     * Filesystem instance.
     *
     * @var \Viserio\Component\Contract\Filesystem\Filesystem
     */
    protected $adapter;

    /**
     * Encryption key instance.
     *
     * @var \ParagonIE\Halite\Symmetric\EncryptionKey
     */
    private $key;

    /**
     * Create a new encryption wrapper instance.
     *
     * @param \Viserio\Component\Contract\Filesystem\Filesystem $adapter
     * @param \ParagonIE\Halite\Symmetric\EncryptionKey         $key
     */
    public function __construct(FilesystemContract $adapter, EncryptionKey $key)
    {
        $this->adapter = $adapter;
        $this->key     = $key;
    }

    /**
     * Hide this from var_dump(), etc.
     *
     * @return array
     */
    public function __debugInfo(): array
    {
        return [
            'key' => 'private',
        ];
    }

    /**
     * Calls adapter functions.
     *
     * @param string $method
     * @param array  $arguments
     *
     * @throws \BadMethodCallException
     *
     * @return mixed
     *
     * @codeCoverageIgnore
     */
    public function __call(string $method, array $arguments)
    {
        return $this->adapter->{$method}(...$arguments);
    }

    /**
     * Read a file.
     *
     * @param string $path the path to the file
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return bool|string the file contents or false on failure
     */
    public function read(string $path)
    {
        if (($result = $this->adapter->read($path)) === false) {
            return false;
        }

        return $this->decryptString($result);
    }

    /**
     * Retrieves a read-stream for a path.
     *
     * @param string $path the path to the file
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     *
     * @return resource
     */
    public function readStream(string $path)
    {
        return $this->decryptStream($this->adapter->readStream($path));
    }

    /**
     * Write a new file.
     *
     * @param string $path     the path of the new file
     * @param string $contents the file contents
     * @param array  $config   an optional configuration array
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     *
     * @return bool true on success, false on failure
     */
    public function write(string $path, $contents, array $config = []): bool
    {
        $contents = $this->encryptString($contents);

        return $this->adapter->write($path, $contents, $config);
    }

    /**
     * Write a new file using a stream.
     *
     * @param string   $path
     * @param resource $resource
     * @param array    $config   an optional configuration array
     *
     * @throws FileModifiedException
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     *
     * @return bool
     */
    public function writeStream(string $path, $resource, array $config = []): bool
    {
        $resource = $this->encryptStream($resource);

        return $this->adapter->writeStream($path, $resource, $config);
    }

    /**
     * Write the contents of a file.
     *
     * @param string          $path
     * @param resource|string $contents
     * @param array           $config   an optional configuration array
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return bool
     */
    public function put(string $path, $contents, array $config = []): bool
    {
        if (\is_resource($contents)) {
            $contents = $this->encryptStream($contents);
        } else {
            $contents = $this->encryptString($contents);
        }

        return $this->adapter->put($path, $contents, $config);
    }

    /**
     * Update an existing file.
     *
     * @param string $path     the path of the existing file
     * @param string $contents the file contents
     * @param array  $config   an optional configuration array
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return bool true on success, false on failure
     */
    public function update(string $path, string $contents, array $config = []): bool
    {
        $contents = $this->encryptString($contents);

        return $this->adapter->update($path, $contents, $config);
    }

    /**
     * Update a file using a stream.
     *
     * @param string   $path
     * @param resource $resource
     * @param array    $config
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return bool
     */
    public function updateStream(string $path, $resource, array $config = []): bool
    {
        $resource = $this->encryptStream($resource);

        return $this->adapter->updateStream($path, $resource, $config);
    }

    /**
     * Decrypts a stream.
     *
     * @param false|resource $resource the stream to decrypt
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return resource
     */
    private function decryptStream($resource)
    {
        $out = \fopen('php://memory', 'r+b');

        if ($resource !== false) {
            try {
                File::decrypt($resource, $out, $this->key);
            } catch (FileAccessDenied $exception) {
                throw new FileAccessDeniedException($exception->getMessage(), $exception->getCode(), $exception);
            } catch (FileModified $exception) {
                throw new FileModifiedException($exception->getMessage(), $exception->getCode(), $exception);
            }

            \rewind($out);
        }

        return $out;
    }

    /**
     * Encrypts a stream.
     *
     * @param false|resource $resource the stream to encrypt
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     *
     * @return resource
     */
    private function encryptStream($resource)
    {
        $out = \fopen('php://temp', 'w+b');

        if ($resource !== false) {
            try {
                File::encrypt($resource, $out, $this->key);
            } catch (FileAccessDenied $exception) {
                throw new FileAccessDeniedException($exception->getMessage(), $exception->getCode(), $exception);
            } catch (FileModified $exception) {
                throw new FileModifiedException($exception->getMessage(), $exception->getCode(), $exception);
            }

            \rewind($out);
        }

        return $out;
    }

    /**
     * Decrypts a string.
     *
     * @param string $contents the string to decrypt
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     *
     * @return string
     */
    private function decryptString(string $contents): string
    {
        $resource = $this->getStreamFromString($contents);

        return (string) \stream_get_contents($this->decryptStream($resource));
    }

    /**
     * Encrypts a string.
     *
     * @param string $contents the string to encrypt
     *
     * @throws \ParagonIE\Halite\Alerts\CannotPerformOperation
     * @throws \ParagonIE\Halite\Alerts\FileError
     * @throws \ParagonIE\Halite\Alerts\InvalidDigestLength
     * @throws \ParagonIE\Halite\Alerts\InvalidKey
     * @throws \ParagonIE\Halite\Alerts\InvalidMessage
     * @throws \ParagonIE\Halite\Alerts\InvalidType
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileModifiedException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     *
     * @return string
     */
    private function encryptString(string $contents): string
    {
        $resource = $this->getStreamFromString($contents);

        return (string) \stream_get_contents($this->encryptStream($resource));
    }

    /**
     * Returns a stream representation of a string.
     *
     * @param string $contents The string
     *
     * @throws \Viserio\Component\Contract\Filesystem\Exception\RuntimeException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException
     * @throws \Viserio\Component\Contract\Filesystem\Exception\FileAccessDeniedException
     *
     * @return resource
     */
    private function getStreamFromString(string $contents)
    {
        $path = \bin2hex(\random_bytes(16));

        $this->adapter->write($path, $contents);

        \sodium_memzero($contents);

        $streamContent = $this->adapter->readStream($path);

        $this->adapter->delete($path);

        if ($streamContent !== false) {
            return $streamContent;
        }

        throw new RuntimeException('Created file for string content cant be read.');
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Bus\Provider;

use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Viserio\Component\Bus\Dispatcher;
use Viserio\Component\Contract\Bus\Dispatcher as DispatcherContract;

class BusServiceProvider implements ServiceProviderInterface
{
    /**
     * {@inheritdoc}
     */
    public function getFactories(): array
    {
        return [
            DispatcherContract::class => [self::class, 'registerBusDispatcher'],
            Dispatcher::class         => static function (ContainerInterface $container) {
                return $container->get(DispatcherContract::class);
            },
            'bus' => static function (ContainerInterface $container) {
                return $container->get(DispatcherContract::class);
            },
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getExtensions(): array
    {
        return [];
    }

    /**
     * Create a new Bus instance.
     *
     * @param \Psr\Container\ContainerInterface $container
     *
     * @return \Viserio\Component\Contract\Bus\Dispatcher
     */
    public static function registerBusDispatcher(ContainerInterface $container): DispatcherContract
    {
        return new Dispatcher($container);
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Mail\Provider;

use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Viserio\Component\Contract\Events\EventManager as EventManagerContract;
use Viserio\Component\Contract\Mail\Mailer as MailerContract;
use Viserio\Component\Contract\Mail\QueueMailer as QueueMailerContract;
use Viserio\Component\Contract\View\Factory as ViewFactoryContract;
use Viserio\Component\Mail\MailManager;
use Viserio\Component\Mail\TransportFactory;

class MailServiceProvider implements ServiceProviderInterface
{
    /**
     * {@inheritdoc}
     */
    public function getFactories(): array
    {
        return [
            TransportFactory::class    => [self::class, 'createTransportFactory'],
            MailManager::class         => [self::class, 'createMailManager'],
            MailerContract::class      => [self::class, 'createMailer'],
            QueueMailerContract::class => static function (ContainerInterface $container) {
                return $container->get(MailerContract::class);
            },
            'mailer'                   => static function (ContainerInterface $container) {
                return $container->get(MailerContract::class);
            },
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getExtensions(): array
    {
        return [];
    }

    /**
     * Create a new transport factory.
     *
     * @param \Psr\Container\ContainerInterface $container
     *
     * @return \Viserio\Component\Mail\TransportFactory
     */
    public static function createTransportFactory(ContainerInterface $container): TransportFactory
    {
        $transport = new TransportFactory();

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

        return $transport;
    }

    /**
     * Create a new swift mailer manager.
     *
     * @param \Psr\Container\ContainerInterface $container
     *
     * @return \Viserio\Component\Mail\MailManager
     */
    public static function createMailManager(ContainerInterface $container): MailManager
    {
        $manager = new MailManager($container->get('config'), $container->get(TransportFactory::class));
        $manager->setContainer($container);

        if ($container->has(ViewFactoryContract::class)) {
            $manager->setViewFactory($container->get(ViewFactoryContract::class));
        }

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

        return $manager;
    }

    /**
     * @param \Psr\Container\ContainerInterface $container
     *
     * @return \Viserio\Component\Contract\Mail\Mailer
     */
    public static function createMailer(ContainerInterface $container): MailerContract
    {
        return $container->get(MailManager::class)->getConnection();
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Parser\Utils;

use DOMDocument;
use Viserio\Component\Contract\Parser\Exception\InvalidArgumentException;

final class XliffUtils
{
    /**
     * Private constructor; non-instantiable.
     *
     * @codeCoverageIgnore
     */
    private function __construct()
    {
    }

    /**
     * Validates and parses the given file into a DOMDocument.
     *
     * @param \DOMDocument $dom
     *
     * @throws \Viserio\Component\Contract\Parser\Exception\InvalidArgumentException
     *
     * @return array
     */
    public static function validateSchema(DOMDocument $dom): array
    {
        return XmlUtils::validateSchema($dom, self::getSchema(static::getVersionNumber($dom)));
    }

    /**
     * Gets xliff file version based on the root "version" attribute.
     * Defaults to 1.2 for backwards compatibility.
     *
     * @param \DOMDocument $dom
     *
     * @throws \Viserio\Component\Contract\Parser\Exception\InvalidArgumentException;
     *
     * @return string
     */
    public static function getVersionNumber(DOMDocument $dom): string
    {
        /** @var \DOMNode $xliff */
        foreach ($dom->getElementsByTagName('xliff') as $xliff) {
            if (($version = $xliff->attributes->getNamedItem('version')) !== null) {
                return $version->nodeValue;
            }

            if ($namespace = $xliff->attributes->getNamedItem('xmlns')) {
                if (\substr_compare('urn:oasis:names:tc:xliff:document:', $namespace, 0, 34) !== 0) {
                    throw new InvalidArgumentException(\sprintf('Not a valid XLIFF namespace [%s].', $namespace));
                }

                return \mb_substr($namespace, 34);
            }
        }

        return '1.2'; // Falls back to v1.2
    }

    /**
     * Get the right xliff schema from version.
     *
     * @param string $xliffVersion
     *
     * @throws \Viserio\Component\Contract\Parser\Exception\InvalidArgumentException;
     *
     * @return string
     */
    public static function getSchema(string $xliffVersion): string
    {
        if ($xliffVersion === '1.2') {
            $xmlUri       = 'http://www.w3.org/2001/xml.xsd';
            $schemaSource = \dirname(__DIR__, 1) . \DIRECTORY_SEPARATOR . 'Resource' . \DIRECTORY_SEPARATOR . 'schemas' . \DIRECTORY_SEPARATOR . 'xliff-core' . \DIRECTORY_SEPARATOR . 'xliff-core-1.2-strict.xsd';
        } elseif ($xliffVersion === '2.0') {
            $xmlUri       = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd';
            $schemaSource = \dirname(__DIR__, 1) . \DIRECTORY_SEPARATOR . 'Resource' . \DIRECTORY_SEPARATOR . 'schemas' . \DIRECTORY_SEPARATOR . 'xliff-core' . \DIRECTORY_SEPARATOR . 'xliff-core-2.0.xsd';
        } else {
            throw new InvalidArgumentException(\sprintf('No support implemented for loading XLIFF version [%s].', $xliffVersion));
        }

        return self::fixLocation(\file_get_contents($schemaSource), $xmlUri);
    }

    /**
     * Internally changes the URI of a dependent xsd to be loaded locally.
     *
     * @param string $schemaSource Current content of schema file
     * @param string $xmlUri       External URI of XML to convert to local
     *
     * @return string
     */
    private static function fixLocation(string $schemaSource, string $xmlUri): string
    {
        $newPath = \dirname(__DIR__, 1) . \DIRECTORY_SEPARATOR . 'Resource' . \DIRECTORY_SEPARATOR . 'schemas' . \DIRECTORY_SEPARATOR . 'xliff-core' . \DIRECTORY_SEPARATOR . 'xml.xsd';
        $parts   = \explode(\DIRECTORY_SEPARATOR, $newPath);

        if (\mb_stripos($newPath, 'phar://') === 0 && ($tmpFile = \tempnam(\sys_get_temp_dir(), 'narrowspark')) !== false) {
            \copy($newPath, $tmpFile);

            $parts = \explode(\DIRECTORY_SEPARATOR, $tmpFile);
        }

        $drive   = '\\' === \DIRECTORY_SEPARATOR ? \array_shift($parts) . '/' : '';
        $newPath = 'file:///' . $drive . \implode('/', \array_map('rawurlencode', $parts));

        return \str_replace($xmlUri, $newPath, $schemaSource);
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Filesystem;

use FilesystemIterator;
use League\Flysystem\Util;
use League\Flysystem\Util\MimeType;
use Spatie\Macroable\Macroable;
use Symfony\Component\Filesystem\Exception\FileNotFoundException as SymfonyFileNotFoundException;
use Symfony\Component\Filesystem\Exception\IOException as SymfonyIOException;
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
use Symfony\Component\Finder\Finder;
use Viserio\Component\Contract\Filesystem\Exception\FileNotFoundException;
use Viserio\Component\Contract\Filesystem\Exception\InvalidArgumentException;
use Viserio\Component\Contract\Filesystem\Exception\IOException as ViserioIOException;
use Viserio\Component\Contract\Filesystem\Filesystem as FilesystemContract;
use Viserio\Component\Filesystem\Traits\FilesystemExtensionTrait;
use Viserio\Component\Filesystem\Traits\FilesystemHelperTrait;

class Filesystem extends SymfonyFilesystem implements FilesystemContract
{
    use FilesystemHelperTrait;
    use FilesystemExtensionTrait;
    use Macroable;

    /**
     * @var array
     */
    protected $permissions = [
        'file' => [
            'public'  => 0744,
            'private' => 0700,
        ],
        'dir' => [
            'public'  => 0755,
            'private' => 0700,
        ],
    ];

    /**
     * {@inheritdoc}
     */
    public function has(string $path): bool
    {
        return $this->exists($path);
    }

    /**
     * {@inheritdoc}
     */
    public function read(string $path)
    {
        if ($this->isFile($path) && $this->has($path)) {
            return \file_get_contents($path);
        }

        throw new FileNotFoundException($path);
    }

    /**
     * {@inheritdoc}
     */
    public function readStream(string $path)
    {
        if (! $this->has($path)) {
            throw new FileNotFoundException($path);
        }

        return @\fopen($path, 'rb');
    }

    /**
     * {@inheritdoc}
     */
    public function write(string $path, string $contents, array $config = []): bool
    {
        $lock = isset($config['lock']) ? \LOCK_EX : 0;

        if (! \is_int(@\file_put_contents($path, $contents, $lock))) {
            return false;
        }

        if (isset($config['visibility'])) {
            $this->setVisibility($path, $config['visibility']);
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function writeStream(string $path, $resource, array $config = []): bool
    {
        Util::rewindStream($resource);

        $contents = \stream_get_contents($resource);

        return $this->write($path, $contents, $config);
    }

    /**
     * {@inheritdoc}
     */
    public function put(string $path, $contents, array $config = []): bool
    {
        $lock = isset($config['lock']) ? \LOCK_EX : 0;

        if (\is_resource($contents)) {
            return $this->writeStream($path, $contents, $config);
        }

        return \is_int(@\file_put_contents($path, $contents, $lock));
    }

    /**
     * {@inheritdoc}
     */
    public function append(string $path, string $contents, array $config = []): bool
    {
        if ($this->has($path)) {
            $config['flags'] = isset($config['flags']) ? $config['flags'] | \FILE_APPEND : \FILE_APPEND;

            return $this->update($path, $contents, $config);
        }

        return $this->write($path, $contents, $config);
    }

    /**
     * {@inheritdoc}
     */
    public function appendStream(string $path, $resource, array $config = []): bool
    {
        if ($this->has($path)) {
            $config['flags'] = isset($config['flags']) ? $config['flags'] | \FILE_APPEND : \FILE_APPEND;

            return $this->updateStream($path, $resource, $config);
        }

        return $this->writeStream($path, $resource, $config);
    }

    /**
     * {@inheritdoc}
     */
    public function update(string $path, string $contents, array $config = []): bool
    {
        if (! $this->exists($path)) {
            throw new FileNotFoundException($path);
        }

        $flags = $config['flags'] ?? 0;

        return \is_int(@\file_put_contents($path, $contents, $flags));
    }

    /**
     * {@inheritdoc}
     */
    public function updateStream(string $path, $resource, array $config = []): bool
    {
        Util::rewindStream($resource);

        $contents = \stream_get_contents($resource);

        return $this->update($path, $contents, $config);
    }

    /**
     * {@inheritdoc}
     */
    public function getVisibility(string $path): string
    {
        \clearstatcache(false, $path);
        $permissions = \octdec(\mb_substr(\sprintf('%o', \fileperms($path)), -4));

        return ($permissions & 0044) ?
            FilesystemContract::VISIBILITY_PUBLIC :
            FilesystemContract::VISIBILITY_PRIVATE;
    }

    /**
     * {@inheritdoc}
     */
    public function setVisibility(string $path, string $visibility): bool
    {
        $visibility = $this->parseVisibility($path, $visibility) ?: 0777;

        try {
            $this->chmod($path, $visibility);
        } catch (SymfonyIOException $exception) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function copy($originFile, $targetFile, $override = false): bool
    {
        try {
            parent::copy($originFile, $targetFile, $override);
        } catch (SymfonyFileNotFoundException $exception) {
            throw new FileNotFoundException(
                $exception->getMessage(),
                $exception->getCode(),
                $exception->getPrevious()
            );
        } catch (SymfonyIOException $exception) {
            throw new ViserioIOException(
                $exception->getMessage(),
                $exception->getCode(),
                $exception->getPrevious()
            );
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function move(string $from, string $to): bool
    {
        return \rename($from, $to);
    }

    /**
     * {@inheritdoc}
     */
    public function getSize(string $path)
    {
        return \filesize($path);
    }

    /**
     * {@inheritdoc}
     */
    public function getMimetype(string $path)
    {
        if (! $this->isFile($path) && ! $this->has($path)) {
            throw new FileNotFoundException($path);
        }

        $explode = \explode('.', $path);

        if ($extension = \end($explode)) {
            $extension = \mb_strtolower($extension);
        }

        return MimeType::detectByFileExtension($extension);
    }

    /**
     * {@inheritdoc}
     */
    public function getTimestamp(string $path)
    {
        if (! $this->isFile($path) && ! $this->has($path)) {
            throw new FileNotFoundException($path);
        }

        return \date('F d Y H:i:s', \filemtime($path));
    }

    /**
     * {@inheritdoc}
     */
    public function url(string $path): string
    {
        return $path;
    }

    /**
     * {@inheritdoc}
     */
    public function delete($paths): bool
    {
        $paths = (array) $paths;

        try {
            $this->remove($paths);
        } catch (SymfonyIOException $exception) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function files(string $directory): array
    {
        $files = \array_diff(\scandir($directory, \SCANDIR_SORT_ASCENDING), ['..', '.']);

        // To get the appropriate files, we'll simply scan the directory and filter
        // out any "files" that are not truly files so we do not end up with any
        // directories in our list, but only true files within the directory.
        return \array_filter($files, static function ($file) use ($directory) {
            return \filetype($directory . \DIRECTORY_SEPARATOR . $file) === 'file';
        });
    }

    /**
     * {@inheritdoc}
     */
    public function allFiles(string $directory, bool $showHiddenFiles = false): array
    {
        $files  = [];
        $finder = Finder::create()->files()->ignoreDotFiles(! $showHiddenFiles)->in($directory);

        /** @var \SplFileObject $dir */
        foreach ($finder as $dir) {
            $files[] = $dir->getPathname();
        }

        return $files;
    }

    /**
     * {@inheritdoc}
     */
    public function createDirectory(string $dirname, array $config = []): bool
    {
        $mode = $this->permissions['dir']['public'];

        if (isset($config['visibility'])) {
            $mode = $this->permissions['dir'][$config['visibility']];
        }

        try {
            $this->mkdir($dirname, $mode);
        } catch (SymfonyIOException $exception) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function directories(string $directory): array
    {
        $directories = [];

        /** @var \SplFileObject $dir */
        foreach (Finder::create()->in($directory)->directories()->depth(0) as $dir) {
            $directories[] = $dir->getPathname();
        }

        return $directories;
    }

    /**
     * {@inheritdoc}
     */
    public function allDirectories(string $directory): array
    {
        return \iterator_to_array(Finder::create()->directories()->in($directory), false);
    }

    /**
     * {@inheritdoc}
     */
    public function deleteDirectory(string $dirname): bool
    {
        if (! $this->isDirectory($dirname)) {
            return false;
        }

        $this->remove($dirname);

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function cleanDirectory(string $dirname): bool
    {
        if (! $this->isDirectory($dirname)) {
            return false;
        }

        $items = new FilesystemIterator($dirname);

        foreach ($items as $item) {
            if ($item->isDir() && ! $item->isLink()) {
                $this->cleanDirectory($item->getPathname());
            } else {
                try {
                    $this->remove($item->getPathname());
                } catch (SymfonyIOException $exception) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function isDirectory(string $dirname): bool
    {
        return \is_dir($dirname);
    }

    /**
     * {@inheritdoc}
     */
    public function copyDirectory(string $directory, string $destination, array $options = []): bool
    {
        if (! $this->isDirectory($directory)) {
            return false;
        }

        try {
            $this->mirror($directory, $destination, null, $options);
        } catch (SymfonyIOException $e) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function moveDirectory(string $directory, string $destination, array $options = []): bool
    {
        $overwrite = $options['overwrite'] ?? false;

        if ($overwrite && $this->isDirectory($destination) && ! $this->deleteDirectory($destination)) {
            return false;
        }

        return @\rename($directory, $destination);
    }

    /**
     * Get normalize or prefixed path.
     *
     * @param string $path
     *
     * @return string
     */
    protected function getTransformedPath(string $path): string
    {
        return $path;
    }

    /**
     * Parse the given visibility value.
     *
     * @param string      $path
     * @param null|string $visibility
     *
     * @throws \Viserio\Component\Contract\Filesystem\Exception\InvalidArgumentException
     *
     * @return null|int
     */
    private function parseVisibility(string $path, string $visibility = null): ?int
    {
        $type = '';

        if (\is_file($path)) {
            $type = 'file';
        } elseif (\is_dir($path)) {
            $type = 'dir';
        }

        if ($visibility === null || $type === '') {
            return null;
        }

        if ($visibility === FilesystemContract::VISIBILITY_PUBLIC) {
            return $this->permissions[$type]['public'];
        }

        if ($visibility === FilesystemContract::VISIBILITY_PRIVATE) {
            return $this->permissions[$type]['private'];
        }

        throw new InvalidArgumentException('Unknown visibility: ' . $visibility);
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Filesystem\Adapter;

use Aws\S3\S3Client;
use League\Flysystem\AdapterInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter as AwsS3v3;
use Viserio\Component\Contract\Filesystem\Connector as ConnectorContract;
use Viserio\Component\Contract\Filesystem\Exception\InvalidArgumentException;
use Viserio\Component\Contract\OptionsResolver\ProvidesDefaultOptions as ProvidesDefaultOptionsContract;
use Viserio\Component\Contract\OptionsResolver\RequiresConfig as RequiresConfigContract;
use Viserio\Component\Contract\OptionsResolver\RequiresMandatoryOptions as RequiresMandatoryOptionsContract;
use Viserio\Component\Contract\OptionsResolver\RequiresValidatedConfig as RequiresValidatedConfigContract;
use Viserio\Component\OptionsResolver\Traits\OptionsResolverTrait;

final class AwsS3Connector implements
    ConnectorContract,
    RequiresConfigContract,
    ProvidesDefaultOptionsContract,
    RequiresMandatoryOptionsContract,
    RequiresValidatedConfigContract
{
    use OptionsResolverTrait;

    /**
     * Resolved options.
     *
     * @var array
     */
    private $resolvedOptions;

    /**
     * Create a new AwsS3Connector instance.
     *
     * @param array $config
     */
    public function __construct(array $config)
    {
        $this->resolvedOptions = self::resolveOptions($config);
    }

    /**
     * {@inheritdoc}
     */
    public static function getMandatoryOptions(): array
    {
        return [
            'auth' => [
                'version',
                'region',
            ],
            'bucket',
        ];
    }

    /**
     * {@inheritdoc}
     */
    public static function getDefaultOptions(): array
    {
        return [
            'prefix'  => null,
            'options' => [],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public static function getOptionValidators(): array
    {
        return [
            'prefix'  => ['string', 'null'],
            'options' => ['array'],
            'bucket'  => ['string'],
            'auth'    => [
                'credentials' => static function ($value): void {
                    if (! \is_array($value)) {
                        throw new InvalidArgumentException('.');
                    }

                    if (! isset($value['key']) && ! isset($value['secret'])) {
                        throw new InvalidArgumentException('.');
                    }
                },
            ],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function connect(): AdapterInterface
    {
        $client = new S3Client($this->resolvedOptions['auth']);

        return new AwsS3v3($client, $this->resolvedOptions['bucket'], $this->resolvedOptions['prefix'], $this->resolvedOptions['options']);
    }
}


<?php
namespace Viserio\Component\Validation;

use Viserio\Component\Contract\Container\Traits\ContainerAwareTrait;
use Viserio\Component\Contract\Validation\Exception\InvalidArgumentException;

class Sanitizer
{
    use ContainerAwareTrait;

    /**
     * Array of registered sanitizers.
     *
     * @var array
     */
    protected $sanitizers = [];

    /**
     * Register a new sanitization method.
     *
     * @param string                    $name
     * @param callable|string|\Closure  $callback
     *
     * @return void
     */
    public function register(string $name, $callback): void
    {
        $this->sanitizers[$name] = $callback;
    }

    /**
     * Sanitize a dataset using rules.
     *
     * @param array $rules
     * @param array $data
     *
     * @return array
     */
    public function sanitize(array $rules, array $data): array
    {
        [$data, $rules] = $this->runGlobalSanitizers($rules, $data);

        $availableRules = \array_intersect_key($rules, \array_flip(array_keys($data)));

        foreach ($availableRules as $field => $ruleset) {
            $data[$field] = $this->sanitizeField($data, $field, $ruleset);
        }

        return $data;
    }

    /**
     * Apply global sanitizer rules.
     *
     * @param array $rules
     * @param array $data
     *
     * @return array
     */
    private function runGlobalSanitizers(array $rules, array $data): array
    {
        // Bail out if no global rules were found.
        if (! isset($rules['*'])) {
            return [$data, $rules];
        }

        // Get the global rules and remove them from the main ruleset.
        $globalRules = $rules['*'];

        unset($rules['*']);

        // Execute the global sanitiers on each field.
        foreach ($data as $field => $value) {
            $data[$field] = $this->sanitizeField($data, $field, $globalRules);
        }

        return [$data, $rules];
    }

    /**
     * Execute sanitization over a specific field.
     *
     * @param array        $data
     * @param string       $field
     * @param string|array $ruleset
     *
     * @return string
     */
    private function sanitizeField(array $data, string $field, $ruleset): string
    {
        if (! \is_string($ruleset) && ! \is_array($ruleset)) {
            throw new InvalidArgumentException(\sprintf(
                'The ruleset parameter must be of type string or array, [%s] given.',
                \is_object($ruleset) ? \get_class($ruleset) : \gettype($ruleset)
            ));
        }

        // If we have a piped ruleset, explode it.
        if (\is_string($ruleset)) {
            $ruleset = \explode('|', $ruleset);
        }

        // Get value from data array.
        $value = $data[$field];

        foreach ($ruleset as $rule) {
            $parametersSet = [];

            if (\strpos($rule, ':') !== false) {
                [$rule, $parameters] = \explode(':', $rule);

                $parametersSet = \explode(',', $parameters);
            }

            \array_unshift($parametersSet, $value);

            $sanitizers = $rule;

            // Retrieve a sanitizer by key.
            if (isset($this->sanitizers[$rule])) {
                $sanitizers = $this->sanitizers[$rule];
            }

            // Execute the sanitizer to mutate the value.
            $value = $this->executeSanitizer($sanitizers, $parametersSet);
        }

        return $value;
    }

    /**
     * Execute a sanitizer using the appropriate method.
     *
     * @param callable|string|\Closure $sanitizer
     * @param array                    $parameters
     *
     * @return string
     */
    private function executeSanitizer($sanitizer, array $parameters): string
    {
        if (\is_callable($sanitizer)) {
            return $sanitizer(...$parameters);
        }

        if ($this->container !== null) {
            // Transform a container resolution to a callback.
            $sanitizer = $this->resolveCallback($sanitizer);

            return $sanitizer(...$parameters);
        }

        // If the sanitizer can't be called, return the passed value.
        return $parameters[0];
    }

    /**
     * Resolve a callback from a class and method pair.
     *
     * @param string $callback
     *
     * @return array<object, string>
     */
    private function resolveCallback(string $callback): array
    {
        $segments = explode('@', $callback);
        $method = \count($segments) === 2 ? $segments[1] : 'sanitize';

        // Return the constructed callback.
        return [$this->container->get($segments[0]), $method];
    }
}


<?php
declare(strict_types=1);
namespace Viserio\Component\Profiler\DataCollector;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class PhpInfoDataCollector extends AbstractDataCollector
{
    /**
     * {@inheritdoc}
     */
    public function collect(ServerRequestInterface $serverRequest, ResponseInterface $response): void
    {
        $this->data = [
            'php_version'      => \PHP_VERSION,
            'php_architecture' => \PHP_INT_SIZE * 8,
            'php_timezone'     => \date_default_timezone_get(),
            'sapi_name'        => \PHP_SAPI,
        ];

        if (\preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
            // @codeCoverageIgnoreStart
            $this->data['php_version']       = $matches[1];
            $this->data['php_version_extra'] = $matches[2];
            // @codeCoverageIgnoreEnd
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getMenu(): array
    {
        return [
            'label' => 'PHP Version',
            'value' => $this->data['php_version'] . ($this->data['php_version_extra'] ?? ''),
        ];
    }

    /**
     * Gets the PHP version.
     *
     * @return null|string The PHP version
     */
    public function getPhpVersion(): ?string
    {
        return $this->data['php_version'];
    }

    /**
     * Gets the PHP version extra part.
     *
     * @return null|string The extra part
     */
    public function getPhpVersionExtra(): ?string
    {
        return $this->data['php_version_extra'] ?? null;
    }

    /**
     * The PHP architecture as number of bits (e.g. 32 or 64).
     *
     * @return null|int
     */
    public function getPhpArchitecture(): ?int
    {
        return $this->data['php_architecture'];
    }

    /**
     * @return string
     */
    public function getPhpTimezone(): ?string
    {
        return $this->data['php_timezone'];
    }
}