<?php

/*
 * This file is part of the Valkyrja framework.
 *
 * (c) Melech Mizrachi
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Valkyrja\Container;

use Valkyrja\Application;
use Valkyrja\Container\Annotations\ContainerAnnotations;
use Valkyrja\Container\Events\ServiceMade;
use Valkyrja\Container\Events\ServiceMadeSingleton;
use Valkyrja\Container\Events\ServiceMake;
use Valkyrja\Container\Exceptions\EndlessContextLoopException;
use Valkyrja\Container\Exceptions\InvalidContextException;
use Valkyrja\Container\Exceptions\InvalidServiceIdException;
use Valkyrja\Support\Providers\ProvidersAwareTrait;

/**
 * Class Container.
 *
 * @author Melech Mizrachi
 */
class NativeContainer implements Container
{
    use ProvidersAwareTrait;

    /**
     * The application.
     *
     * @var \Valkyrja\Application
     */
    protected $app;

    /**
     * Whether the container has been setup.
     *
     * @var bool
     */
    protected static $setup = false;

    /**
     * The aliases.
     *
     * @var string[]
     */
    protected static $aliases = [];

    /**
     * The services.
     *
     * @var \Valkyrja\Container\Service[]
     */
    protected static $services = [];

    /**
     * The singletons.
     *
     * @var array
     */
    protected static $singletons = [];

    /**
     * Container constructor.
     *
     * @param Application $application The application
     */
    public function __construct(Application $application)
    {
        $this->app = $application;
    }

    /**
     * Set an alias to the container.
     *
     * @param string $alias     The alias
     * @param string $serviceId The service to return
     *
     * @return void
     */
    public function alias(string $alias, string $serviceId): void
    {
        self::$aliases[$alias] = $serviceId;
    }

    /**
     * Bind a service to the container.
     *
     * @param Service $service The service model
     * @param bool    $verify  [optional] Whether to verify the service
     *
     * @throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException
     *
     * @return void
     */
    public function bind(Service $service, bool $verify = true): void
    {
        // If there is no id
        if (null === $service->getId()) {
            // Throw a new exception
            throw new InvalidServiceIdException('Invalid service id provided.');
        }

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

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

    /**
     * Bind a context to the container.
     *
     * @param ServiceContext $serviceContext The context service
     *
     * @throws \Valkyrja\Container\Exceptions\InvalidContextException
     * @throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
     * @throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException
     *
     * @return void
     */
    public function context(ServiceContext $serviceContext): void
    {
        $context        = $serviceContext->getClass()
            ?? $serviceContext->getFunction();
        $member         = $serviceContext->getMethod()
            ?? $serviceContext->getProperty();
        $contextContext = $serviceContext->getContextClass()
            ?? $serviceContext->getContextFunction();

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

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

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

        $this->bind($service);
    }

    /**
     * Get a service model from a context model.
     *
     * @param ServiceContext $serviceContext The service context
     * @param string         $context        [optional] The context
     *                                       class or function
     * @param string         $member         [optional] The member
     *
     * @return Service
     */
    protected function getServiceFromContext(
        ServiceContext $serviceContext,
        string $context = null,
        string $member = null
    ): Service {
        $service   = new Service();
        $serviceId = $this->contextServiceId(
            $serviceContext->getId(),
            $context,
            $member
        );

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

        return $service;
    }

    /**
     * Bind a singleton to the container.
     *
     * @param string $serviceId The service
     * @param mixed  $singleton The singleton
     */
    public function singleton(string $serviceId, $singleton): void
    {
        self::$singletons[$serviceId] = $singleton;
    }

    /**
     * Check whether a given service exists.
     *
     * @param string $serviceId The service
     *
     * @return bool
     */
    public function has(string $serviceId): bool
    {
        return isset(self::$services[$serviceId]) || isset(self::$aliases[$serviceId]);
    }

    /**
     * Check whether a given service has context.
     *
     * @param string $serviceId The service
     * @param string $context   The context
     *                          class name || function name || variable name
     * @param string $member    [optional] The context member
     *                          method name || property name
     *
     * @return bool
     */
    public function hasContext(string $serviceId, string $context, string $member = null): bool
    {
        $contextIndex = $this->contextServiceId($serviceId, $context, $member);

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

    /**
     * Check whether a given service is an alias.
     *
     * @param string $serviceId The service
     *
     * @return bool
     */
    public function isAlias(string $serviceId): bool
    {
        return isset(self::$aliases[$serviceId]);
    }

    /**
     * Check whether a given service is a singleton.
     *
     * @param string $serviceId The service
     *
     * @return bool
     */
    public function isSingleton(string $serviceId): bool
    {
        return isset(self::$singletons[$serviceId]);
    }

    /**
     * Get a service from the container.
     *
     * @param string $serviceId The service
     * @param array  $arguments [optional] The arguments
     * @param string $context   [optional] The context
     *                          class name || function name || variable name
     * @param string $member    [optional] The context member
     *                          method name || property name
     *
     * @return mixed
     */
    public function get(string $serviceId, array $arguments = null, string $context = null, string $member = null)
    {
        // If there is a context set for this context and member combination
        if (
            null !== $context
            && $this->hasContext(
                $serviceId,
                $context,
                $member
            )
        ) {
            // Return that context
            return $this->get(
                $this->contextServiceId($serviceId, $context, $member),
                $arguments
            );
        }

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

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

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

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

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

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

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

    /**
     * Make a service.
     *
     * @param string     $serviceId The service id
     * @param array|null $arguments [optional] The arguments
     *
     * @return mixed
     */
    public function make(string $serviceId, array $arguments = null)
    {
        $service   = self::$services[$serviceId];
        $arguments = $service->getDefaults() ?? $arguments;

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

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

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

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

        return $made;
    }

    /**
     * Get a singleton from the container.
     *
     * @param string $serviceId The service
     *
     * @return mixed
     */
    public function getSingleton(string $serviceId)
    {
        // If the service isn't a singleton but is provided
        if (! $this->isSingleton($serviceId) && $this->isProvided($serviceId)) {
            // Initialize the provided service
            $this->initializeProvided($serviceId);
        }

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

    /**
     * Get a provided service from the container.
     *
     * @param string $serviceId The service
     * @param array  $arguments [optional] The arguments
     * @param string $context   [optional] The context
     *                          class name || function name || variable name
     * @param string $member    [optional] The context member
     *                          method name || property name
     *
     * @return mixed
     */
    public function getProvided(
        string $serviceId,
        array $arguments = null,
        string $context = null,
        string $member = null
    ) {
        $this->initializeProvided($serviceId);

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

    /**
     * Get the context service id.
     *
     * @param string $serviceId The service
     * @param string $context   [optional] The context
     *                          class name || function name || variable name
     * @param string $member    [optional] The context member
     *                          method name || property name
     *
     * @return string
     */
    public function contextServiceId(string $serviceId, string $context = null, string $member = null): string
    {
        $index = $serviceId . '@' . ($context ?? '');

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

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

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

    /**
     * Setup the container.
     *
     * @param bool $force    [optional] Whether to force setup
     * @param bool $useCache [optional] Whether to use cache
     *
     * @throws \Valkyrja\Container\Exceptions\InvalidContextException
     * @throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
     * @throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException
     *
     * @return void
     */
    public function setup(bool $force = false, bool $useCache = true): void
    {
        if (self::$setup && ! $force) {
            return;
        }

        self::$setup = true;

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

            // Then return out of setup
            return;
        }

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

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

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

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

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

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

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

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

    /**
     * Setup annotations.
     *
     * @throws \Valkyrja\Container\Exceptions\InvalidContextException
     * @throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
     * @throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException
     *
     * @return void
     */
    protected function setupAnnotations(): void
    {
        /** @var ContainerAnnotations $containerAnnotations */
        $containerAnnotations = $this->getSingleton(
            ContainerAnnotations::class
        );

        // Get all the annotated services from the list of controllers
        $services = $containerAnnotations->getServices(
            ...$this->app->config()['container']['services']
        );

        // Iterate through the services
        foreach ($services as $service) {
            // Set the service
            $this->bind($service);
        }

        // Get all the annotated services from the list of controllers
        $contextServices = $containerAnnotations->getContextServices(
            ...$this->app->config()['container']['contextServices']
        );

        // Iterate through the services
        foreach ($contextServices as $context) {
            // Set the service
            $this->context($context);
        }

        // Get all the annotated services from the list of classes
        $aliasServices = $containerAnnotations->getAliasServices(
            ...$this->app->config()['container']['services']
        );

        // Iterate through the services
        foreach ($aliasServices as $alias) {
            // Set the service
            $this->alias($alias->getName(), $alias->getId());
        }
    }

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

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

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

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

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

    /**
     * Get a cacheable representation of the service container.
     *
     * @throws \Valkyrja\Container\Exceptions\InvalidContextException
     * @throws \Valkyrja\Container\Exceptions\EndlessContextLoopException
     * @throws \Valkyrja\Container\Exceptions\InvalidServiceIdException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidClosureException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidDispatchCapabilityException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidFunctionException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidMethodException
     * @throws \Valkyrja\Dispatcher\Exceptions\InvalidPropertyException
     *
     * @return array
     */
    public function getCacheable(): array
    {
        $this->setup(true, false);

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

    /**
     * Get the application.
     *
     * @return \Valkyrja\Application
     */
    protected function getApplication(): Application
    {
        return $this->app;
    }
}


<?php namespace Ordercloud\Entities\Addresses;

use JsonSerializable;

class Address implements JsonSerializable
{
    /** @var string */
    private $streetNumber;
    /** @var string */
    private $streetName;
    /** @var string */
    private $complex;
    /** @var string */
    private $suburb;
    /** @var string */
    private $city;
    /** @var string */
    private $postalCode;

    /**
     * @param string $streetNumber
     * @param string $streetName
     * @param string $complex
     * @param string $suburb
     * @param string $city
     * @param string $postalCode
     */
    public function __construct($streetNumber, $streetName, $complex, $suburb, $city, $postalCode)
    {
        $this->streetNumber = $streetNumber;
        $this->streetName = $streetName;
        $this->complex = $complex;
        $this->suburb = $suburb;
        $this->city = $city;
        $this->postalCode = $postalCode;
    }

    /**
     * @return string
     */
    public function getStreetNumber()
    {
        return $this->streetNumber;
    }

    /**
     * @return string
     */
    public function getStreetName()
    {
        return $this->streetName;
    }

    /**
     * @return string
     */
    public function getComplex()
    {
        return $this->complex;
    }

    /**
     * @return string
     */
    public function getSuburb()
    {
        return $this->suburb;
    }

    /**
     * @return string
     */
    public function getCity()
    {
        return $this->city;
    }

    /**
     * @return string
     */
    public function getPostalCode()
    {
        return $this->postalCode;
    }

    /**
     * Returns an array of address lines.
     *
     * @return array|string[]
     */
    public function getAddressLines()
    {
        return array_filter([
            $this->getComplex(),
            implode(' ', array_filter([$this->getStreetNumber(), $this->getStreetName()])),
            $this->getSuburb(),
            $this->getCity(),
            $this->getPostalCode()
        ]);
    }

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        return [
            'streetNumber' => $this->streetNumber,
            'streetName' => $this->streetName,
            'complex' => $this->complex,
            'suburb' => $this->suburb,
            'city' => $this->city,
            'postalCode' => $this->postalCode,
        ];
    }
}


<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Filter
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Gz.php 24593 2012-01-05 20:35:02Z matthew $
 */

/**
 * @see Zend_Filter_Compress_CompressAbstract
 */

/**
 * Compression adapter for Gzip (ZLib)
 *
 * @category   Zend
 * @package    Zend_Filter
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Filter_Compress_Gz extends Zend_Filter_Compress_CompressAbstract
{
    /**
     * Compression Options
     * array(
     *     'level'    => Compression level 0-9
     *     'mode'     => Compression mode, can be 'compress', 'deflate'
     *     'archive'  => Archive to use
     * )
     *
     * @var array
     */
    protected $_options = array(
        'level'   => 9,
        'mode'    => 'compress',
        'archive' => null,
    );

    /**
     * Class constructor
     *
     * @param array|Zend_Config|null $options (Optional) Options to set
     */
    public function __construct($options = null)
    {
        if (!extension_loaded('zlib')) {

            throw new Zend_Filter_Exception('This filter needs the zlib extension');
        }
        parent::__construct($options);
    }

    /**
     * Returns the set compression level
     *
     * @return integer
     */
    public function getLevel()
    {
        return $this->_options['level'];
    }

    /**
     * Sets a new compression level
     *
     * @param integer $level
     * @return Zend_Filter_Compress_Gz
     */
    public function setLevel($level)
    {
        if (($level < 0) || ($level > 9)) {

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

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

    /**
     * Returns the set compression mode
     *
     * @return string
     */
    public function getMode()
    {
        return $this->_options['mode'];
    }

    /**
     * Sets a new compression mode
     *
     * @param string $mode Supported are 'compress', 'deflate' and 'file'
     */
    public function setMode($mode)
    {
        if (($mode != 'compress') && ($mode != 'deflate')) {

            throw new Zend_Filter_Exception('Given compression mode not supported');
        }

        $this->_options['mode'] = $mode;
        return $this;
    }

    /**
     * Returns the set archive
     *
     * @return string
     */
    public function getArchive()
    {
        return $this->_options['archive'];
    }

    /**
     * Sets the archive to use for de-/compression
     *
     * @param string $archive Archive to use
     * @return Zend_Filter_Compress_Gz
     */
    public function setArchive($archive)
    {
        $this->_options['archive'] = (string) $archive;
        return $this;
    }

    /**
     * Compresses the given content
     *
     * @param  string $content
     * @return string
     */
    public function compress($content)
    {
        $archive = $this->getArchive();
        if (!empty($archive)) {
            $file = gzopen($archive, 'w' . $this->getLevel());
            if (!$file) {

                throw new Zend_Filter_Exception("Error opening the archive '" . $this->_options['archive'] . "'");
            }

            gzwrite($file, $content);
            gzclose($file);
            $compressed = true;
        } else if ($this->_options['mode'] == 'deflate') {
            $compressed = gzdeflate($content, $this->getLevel());
        } else {
            $compressed = gzcompress($content, $this->getLevel());
        }

        if (!$compressed) {

            throw new Zend_Filter_Exception('Error during compression');
        }

        return $compressed;
    }

    /**
     * Decompresses the given content
     *
     * @param  string $content
     * @return string
     */
    public function decompress($content)
    {
        $archive = $this->getArchive();
        $mode    = $this->getMode();
        if (file_exists($content)) {
            $archive = $content;
        }

        if (file_exists($archive)) {
            $handler = fopen($archive, "rb");
            if (!$handler) {

                throw new Zend_Filter_Exception("Error opening the archive '" . $archive . "'");
            }

            fseek($handler, -4, SEEK_END);
            $packet = fread($handler, 4);
            $bytes  = unpack("V", $packet);
            $size   = end($bytes);
            fclose($handler);

            $file       = gzopen($archive, 'r');
            $compressed = gzread($file, $size);
            gzclose($file);
        } else if ($mode == 'deflate') {
            $compressed = gzinflate($content);
        } else {
            $compressed = gzuncompress($content);
        }

        if (!$compressed) {

            throw new Zend_Filter_Exception('Error during compression');
        }

        return $compressed;
    }

    /**
     * Returns the adapter name
     *
     * @return string
     */
    public function toString()
    {
        return 'Gz';
    }
}


<?php

namespace Reaction\Routes;

use React\Promise\PromiseInterface;
use Reaction;
use Reaction\Annotations\CtrlAction;
use Reaction\Annotations\CtrlActionValidatorInterface;
use Reaction\Base\Component;
use Reaction\Base\ViewContextInterface;
use Reaction\Exceptions\Exception;
use Reaction\Exceptions\Http\ForbiddenException;
use Reaction\Exceptions\Http\NotFoundException;
use Reaction\Exceptions\HttpException;
use Reaction\Exceptions\HttpExceptionInterface;
use Reaction\Helpers\ArrayHelper;
use Reaction\Helpers\Inflector;
use Reaction\Helpers\ReflectionHelper;
use Reaction\Helpers\StringHelper;
use Reaction\Promise\ExtendedPromiseInterface;
use function Reaction\Promise\resolve;
use function Reaction\Promise\reject;
use function Reaction\Promise\all;
use Reaction\RequestApplicationInterface;
use Reaction\Web\Response;
use Reaction\Web\ResponseBuilderInterface;

/**
 * Class Controller
 * @package Reaction\Routes
 */
class Controller extends Component implements ControllerInterface, ViewContextInterface
{
    /**
     * @var string Base view files folder path
     */
    public $baseViewPath;
    /**
     * @var string Layout file path
     */
    public $layout;
    /**
     * @var string Default controller action
     */
    public $defaultAction = 'index';
    /**
     * @var string default controller action
     */
    public static $_defaultAction = 'index';

    /**
     * @var string View files folder path without alias
     */
    protected $_viewPath;
    /**
     * @var string[] Actions list
     */
    protected $_actions;

    /**
     * Routes description
     *
     * Example return:
     * [
     *      [
     *          'method' => ['GET', 'POST'],
     *          'route' => 'test/{id:\d+}',
     *          'handler' => 'actionTest',
     *      ]
     * ]
     *
     * @return array
     */
    public function routes()
    {
        return [];
    }

    /**
     * Get route group name, if empty no grouping
     * @return string
     */
    public function group()
    {
        return '';
    }

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

    /**
     * Get current action
     * @param RequestApplicationInterface|null $app
     * @return string|null
     */
    public function getCurrentAction(RequestApplicationInterface $app = null)
    {
        return $app !== null ? $app->getRoute()->getAction() : null;
    }

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

    /**
     * @return string the view path that may be prefixed to a relative view name.
     */
    public function getViewPath()
    {
        if (!isset($this->_viewPath)) {
            $baseViewPath = isset($this->baseViewPath) ? $this->baseViewPath : Reaction::$app->getViewPath();
            try {
                $reflection = new \ReflectionClass($this);
                $shortName = $reflection->getShortName();
            } catch (\ReflectionException $e) {
                $shortNameExp = explode('\\', static::class);
                $shortName = end($shortNameExp);
            }
            if (strlen($shortName) > 10 && StringHelper::endsWith($shortName, 'Controller')) {
                $shortName = substr($shortName, 0, -10);
            }
            return $baseViewPath . DIRECTORY_SEPARATOR . lcfirst($shortName);
        }
        return $this->_viewPath;
    }

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

    /**
     * Resolve error
     * @param RequestApplicationInterface $app
     * @param \Throwable                  $exception
     * @param bool                        $asPlainText
     * @return ExtendedPromiseInterface|ResponseBuilderInterface
     */
    public function resolveError(RequestApplicationInterface $app, \Throwable $exception, $asPlainText = false)
    {
        $app->view->context = $this;
        if ($asPlainText) {
            return $this->resolveErrorAsPlainText($app, $exception);
        }
        $format = $app->response->format;
        switch ($format) {
            case Response::FORMAT_RAW:
            case Response::FORMAT_HTML:
                return $this->resolveErrorAsHtml($app, $exception);
            default:
                return $this->resolveErrorAsArray($app, $exception);
        }
    }

    /**
     * This method is invoked right before an action is executed.
     *
     * The method will trigger the [[EVENT_BEFORE_ACTION]] event. The return value of the method
     * will determine whether the action should continue to run.
     *
     * In case the action should not run, the request should be handled inside of the `beforeAction` code
     * by either providing the necessary output or redirecting the request. Otherwise the response will be empty.
     *
     * If you override this method, your code should look like the following:
     *
     * ```php
     * public function beforeAction($action)
     * {
     *     // your custom code here, if you want the code to run before action filters,
     *     // which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl
     *
     *     if (!parent::beforeAction($action)) {
     *         return false;
     *     }
     *
     *     // other custom code here
     *
     *     return true; // or false to not run the action
     * }
     * ```
     *
     * @param string $actionId the action to be executed.
     * @return bool whether the action should continue to run.
     */
    public function beforeAction($actionId)
    {
        $isValid = true;
        $this->emit(self::EVENT_BEFORE_ACTION, [&$this, $actionId, &$isValid]);
        return $isValid;
    }

    /**
     * This method is invoked right after an action is executed.
     *
     * The method will trigger the [[EVENT_AFTER_ACTION]] event. The return value of the method
     * will be used as the action return value.
     *
     * If you override this method, your code should look like the following:
     *
     * ```php
     * public function afterAction($action, $result)
     * {
     *     $result = parent::afterAction($action, $result);
     *     // your custom code here
     *     return $result;
     * }
     * ```
     *
     * @param string $actionId the action just executed.
     * @param mixed  $result the action return result.
     * @return mixed the processed action result.
     */
    public function afterAction($actionId, $result = null)
    {
        $this->emit(self::EVENT_AFTER_ACTION, [&$this, $actionId, &$result]);
        return $result;
    }

    /**
     * Render view
     * @param RequestApplicationInterface $app
     * @param string                      $viewName
     * @param array                       $params
     * @param bool                        $asResponse
     * @return \Reaction\Web\ResponseBuilderInterface|string
     */
    public function render(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        return $this->renderInLayout($app, $viewName, $params, $asResponse);
    }

    /**
     * Render view partially
     * @param RequestApplicationInterface $app
     * @param string                      $viewName
     * @param array                       $params
     * @param bool                        $asResponse
     * @return \Reaction\Web\ResponseBuilderInterface|string
     */
    public function renderPartial(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        return $this->renderInternal($app, $viewName, $params, false, $asResponse);
    }

    /**
     * Render for AJAX request
     * @param RequestApplicationInterface $app
     * @param string                      $viewName
     * @param array                       $params
     * @param bool                        $asResponse
     * @return \Reaction\Web\ResponseBuilderInterface|string
     */
    public function renderAjax(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        return $this->renderInternal($app, $viewName, $params, true, $asResponse);
    }

    /**
     * Get path of action (Caution! With possible RegEx)
     * @param string $action
     * @return null|string
     */
    public function getActionPath($action)
    {
        try {
            $action = $this->normalizeActionName($action);
        } catch (NotFoundException $e) {
            return null;
        }
        $annotations = Reaction::$annotations->getMethod($action, $this);
        if (isset($annotations[CtrlAction::class])) {
            /** @var CtrlAction $actionAnnotation */
            $actionAnnotation = $annotations[CtrlAction::class];
            return $actionAnnotation->path;
        } else {
            $routes = ArrayHelper::map($this->routes(), 'handler', 'route');
            if (isset($routes[$action])) {
                return $routes[$action];
            }
        }
        return null;
    }

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

    /**
     * Check that controller has action with given ID
     * @param string $actionId
     * @return bool
     */
    public function hasAction($actionId)
    {
        $actions = $this->actions();
        return in_array($actionId, $actions);
    }

    /**
     * Render view in layout
     * @param RequestApplicationInterface $app
     * @param string                      $viewName
     * @param array                       $params
     * @param bool                        $asResponse
     * @return \Reaction\Web\ResponseBuilderInterface|string
     */
    protected function renderInLayout(RequestApplicationInterface $app, $viewName, $params = [], $asResponse = false)
    {
        $view = $app->view;
        if (isset($this->layout)) {
            $layoutFile = $view->findViewFile($this->layout, $this);
        } else {
            $layoutFile = $view->findViewFile($view->layout, $this);
        }
        $content = $this->renderInternal($app, $viewName, $params, false, false);
        $rendered = $this->renderFile($app, $layoutFile, ['content' => $content]);
        if (!$asResponse) {
            return $rendered;
        }
        $app->response->setBody($rendered);
        return $app->response;
    }

    /**
     * Render view internal function
     * @param RequestApplicationInterface $app
     * @param string                      $viewName
     * @param array                       $params
     * @param bool                        $ajax
     * @param bool                        $asResponse
     * @return \Reaction\Web\ResponseBuilderInterface|string
     */
    protected function renderInternal(RequestApplicationInterface $app, $viewName, $params = [], $ajax = false, $asResponse = false)
    {
        $view = $app->view;
        $rendered = $ajax ? $view->renderAjax($viewName, $params, $this) : $view->render($viewName, $params, $this);
        if (!$asResponse) {
            return $rendered;
        }
        $app->response->setBody($rendered);
        return $app->response;
    }

    /**
     * Render file
     * @param RequestApplicationInterface $app
     * @param string                      $file
     * @param array                       $params
     * @return string
     */
    protected function renderFile(RequestApplicationInterface $app, $file, $params = [])
    {
        return $app->view->renderFile($file, $params, $this);
    }

    /**
     * Normalize action name
     * @param string $actionMethod
     * @param bool   $throwException
     * @return string|null
     * @throws NotFoundException
     */
    protected function normalizeActionName($actionMethod, $throwException = true)
    {
        if (!StringHelper::startsWith($actionMethod, 'action')) {
            $actionMethod = static::getActionMethod($actionMethod);
        }

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

        return $actionMethod;
    }

    /**
     * Resolve error as rendered html
     * @param RequestApplicationInterface $app
     * @param \Throwable                  $exception
     * @return ResponseBuilderInterface|ExtendedPromiseInterface
     * @throws NotFoundException
     */
    protected function resolveErrorAsHtml(RequestApplicationInterface $app, \Throwable $exception)
    {
        $actions = ['actionError'];
        if ($exception instanceof HttpException) {
            $actions[] = 'actionErrorHttp';
            $actions[] = 'actionErrorHttp' . $exception->statusCode;
        }
        $action = null;
        foreach ($actions as $possibleAction) {
            $action = $this->normalizeActionName($possibleAction, false);
            if (isset($action)) {
                break;
            }
        }
        if (!isset($action)) {
            return $this->resolveErrorAsPlainText($app, $exception);
        }
        return Reaction::$di->invoke([$this, $action], [$app, $exception]);
    }

    /**
     * Resolve error as array formatted
     * @param RequestApplicationInterface $app
     * @param \Throwable                  $exception
     * @return ResponseBuilderInterface
     */
    protected function resolveErrorAsArray(RequestApplicationInterface $app, \Throwable $exception)
    {
        $data = $this->getErrorData($exception);
        $responseData = ['error' => $data];
        $app->response->setBody($responseData)->setStatusCodeByException($exception);
        return $app->response;
    }

    /**
     * Resolve error as pain text
     * @param RequestApplicationInterface $app
     * @param \Throwable                  $exception
     * @return ResponseBuilderInterface
     */
    protected function resolveErrorAsPlainText(RequestApplicationInterface $app, \Throwable $exception)
    {
        $data = $this->getErrorData($exception);
        $responseData = ['error' => $data];
        $app->response->setBody(print_r($responseData, true))
            ->setStatusCodeByException($exception)
            ->setFormat(Response::FORMAT_RAW);
        return $app->response;
    }

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

    /**
     * Get name of exception
     * @param \Throwable $exception
     * @return string
     */
    protected function getExceptionName($exception)
    {
        if ($exception instanceof Exception) {
            return $exception->getName();
        } else {
            $classNameExp = explode('\\', get_class($exception));
            return end($classNameExp);
        }
    }

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

    /**
     * Convert controller action method name to it's ID
     * @param string $actionMethod
     * @return string
     */
    public static function getActionId($actionMethod)
    {
        if (strpos($actionMethod, 'action') === 0) {
            $actionMethod = substr($actionMethod, 6);
        }
        return Inflector::camel2id($actionMethod, '-');
    }

    /**
     * Convert controller action ID to method name
     * @param string $actionId
     * @return string
     */
    public static function getActionMethod($actionId = '')
    {
        if ($actionId === '') {
            $actionId = static::$_defaultAction;
        }
        $actionMethod = Inflector::id2camel($actionId, '-');
        return 'action' . $actionMethod;
    }
}


<?php
/**
 * This file is part of the Hephaistos project management API.
 *
 * As each files provides by the CSCFA, this file is licensed
 * under the MIT license.
 *
 * PHP version 5.6
 *
 * @category Compiler
 * @package  Hephaistos
 * @author   matthieu vallance <matthieu.vallance@cscfa.fr>
 * @license  MIT <https://opensource.org/licenses/MIT>
 * @link     http://cscfa.fr
 */
namespace CSDT\CollectionsBundle\CollectionHelper\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Manager compiler
 *
 * This class is used to process
 * the container for the casters
 * import into the manager.
 *
 * @category Compiler
 * @package  Hephaistos
 * @author   matthieu vallance <matthieu.vallance@cscfa.fr>
 * @license  MIT <https://opensource.org/licenses/MIT>
 * @link     http://cscfa.fr
 */
class ManagerCompiler implements CompilerPassInterface
{

    /**
     * Process
     *
     * This method process the container
     * to inject the casters into the
     * caster manager.
     *
     * @param ContainerBuilder $container The application container builder
     *
     * @return void
     */
    public function process(ContainerBuilder $container)
    {
        $manager = 'collection.helper.manager';
        $caster = 'collection.helper.caster';
        $method = 'addCaster';

        $taggedManager = $container->findTaggedServiceIds($manager);
        foreach ($taggedManager as $managerId => $tags) {
            $managerDefinition = $container->findDefinition($managerId);

            $taggedServices = $container->findTaggedServiceIds($caster);

            foreach ($taggedServices as $id => $tags) {
                $managerDefinition->addMethodCall(
                    $method,
                    array(new Reference($id))
                );
            }
        }
    }

}


<?php
namespace Li;

class Route
{
    private static $__route;

    private $_rules=array();
    private $_scriptUrl;
    private $_requestUri;
    private $_pathInfoOri;
    private $_pathInfo;
    private $_hostInfo;
    private $_baseUrl;
    private $_urlFormat='get';

    public $caseSensitive = true;

    function __construct()
    {
        if(isset(App::app()->config['route']['rules']))
        {
            $this->_rules = App::app()->config['route']['rules'];
        }
    }

    public static function instance()
    {
        if(!(self::$__route instanceof self))
        {
            self::$__route = new self();
        }

        return self::$__route;
    }

    public function init()
    {
        if(isset(App::app()->config['route']['urlFormat'])) {
            $this->_urlFormat = App::app()->config['route']['urlFormat'];
        }
        $this->_pathInfo = $this->parseUrl();
        return $this->_pathInfo;
    }

    public function parseUrl()
    {
        if($this->_pathInfo === null)
        {
            if($this->_urlFormat == 'path') {
                $this->_pathInfoOri = $this->getPathInfo();
            } else {
                $this->_pathInfoOri = '/';
                if(isset($_GET['r'])) {
                    $this->_pathInfoOri = $_GET['r'];
                }
            }
            $this->_pathInfo = $this->parseRegular($this->_pathInfoOri);
        }

        return $this->_pathInfo;
    }

    /**
     * 支持正则
     * @param  [type] $pathInfo [description]
     * @return [type]           [description]
     */
    function parseRegular($pathInfo)
    {
        if($this->caseSensitive === null || $this->caseSensitive)
            $case = '';
        else
            $case = 'i';

        foreach($this->_rules as $pattern => $v)
        {
            preg_match('@'.$pattern.'@'.$case, $pathInfo, $match);
            if(!empty($match))
            {
                $len = count($match);
                for($i=1;$i<$len;$i++) {
                    $v = str_replace('$'.$i, $match[$i], $v);
                }
                $pathInfo = $v;
                break;
            }
        }

        return $pathInfo;
    }

    public function parseActionParams($pathInfo)
    {
        if($pathInfo == '')
            return;
        $segs=explode('/',$pathInfo.'/');
        $n=count($segs);
        for($i=0;$i<$n-1;$i+=2)
        {
            $key=$segs[$i];
            if($key==='') continue;
            $value=$segs[$i+1];
            if(($pos=strpos($key,'['))!==false && ($m=preg_match_all('/\[(.*?)\]/',$key,$matches))>0)
            {
                $name=substr($key,0,$pos);
                for($j=$m-1;$j>=0;--$j)
                {
                    if($matches[1][$j]==='')
                        $value=array($value);
                    else
                        $value=array($matches[1][$j]=>$value);
                }
                if(isset($_GET[$name]) && is_array($_GET[$name]))
                    $value=CMap::mergeArray($_GET[$name],$value);
                $_REQUEST[$name]=$_GET[$name]=$value;
            }
            else
                $_REQUEST[$key]=$_GET[$key]=$value;
        }
    }

    public function getPathInfo()
    {
        if($this->_pathInfo === null)
        {
            $pathInfo = $this->getRequestUri();

            if(($pos = strpos($pathInfo,'?')) !== false)
                $pathInfo = substr($pathInfo, 0, $pos);

            $scriptUrl = $this->getScriptUrl();
            if(strpos($pathInfo,$scriptUrl) === 0) {
                $pathInfo = substr($pathInfo, strlen($scriptUrl));
            }
            elseif(strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) {
                $pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl));
            }
            else {
                throw new Exception('CHttpRequest is unable to determine the path info of the request.');
            }

            $this->_pathInfo = trim($pathInfo,'/');
        }
        return $this->_pathInfo;
    }

    function getRequestUri()
    {
        if($this->_requestUri===null)
        {
            if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS
                $this->_requestUri=$_SERVER['HTTP_X_REWRITE_URL'];
            elseif(isset($_SERVER['REQUEST_URI']))
            {
                $this->_requestUri=$_SERVER['REQUEST_URI'];
                if(!empty($_SERVER['HTTP_HOST']))
                {
                    if(strpos($this->_requestUri,$_SERVER['HTTP_HOST'])!==false)
                        $this->_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',$this->_requestUri);
                }
                else
                    $this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',$this->_requestUri);
            }
            elseif(isset($_SERVER['ORIG_PATH_INFO']))  // IIS 5.0 CGI
            {
                $this->_requestUri=$_SERVER['ORIG_PATH_INFO'];
                if(!empty($_SERVER['QUERY_STRING']))
                    $this->_requestUri.='?'.$_SERVER['QUERY_STRING'];
            }
            else
            {
               throw new Exception('CHttpRequest is unable to determine the request URI.');
            }
        }

        return $this->_requestUri;
    }

    public function getScriptUrl()
    {
        if($this->_scriptUrl === null)
        {
            $scriptName=basename($_SERVER['SCRIPT_FILENAME']);
            if(basename($_SERVER['SCRIPT_NAME'])===$scriptName)
                $this->_scriptUrl=$_SERVER['SCRIPT_NAME'];
            elseif(basename($_SERVER['PHP_SELF'])===$scriptName)
                $this->_scriptUrl=$_SERVER['PHP_SELF'];
            elseif(isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME'])===$scriptName)
                $this->_scriptUrl=$_SERVER['ORIG_SCRIPT_NAME'];
            elseif(($pos=strpos($_SERVER['PHP_SELF'],'/'.$scriptName))!==false)
                $this->_scriptUrl=substr($_SERVER['SCRIPT_NAME'],0,$pos).'/'.$scriptName;
            elseif(isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===0)
                $this->_scriptUrl=str_replace('\\','/',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME']));
            else
                throw new Exception('CHttpRequest is unable to determine the entry script URL.');
        }
        return $this->_scriptUrl;
    }

    public function getIsSecureConnection()
    {
        return isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'],'on')===0 || $_SERVER['HTTPS']==1)
            || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'],'https')===0;
    }

    public function getHostInfo()
    {
        if($this->_hostInfo === null) {
            if($secure=$this->getIsSecureConnection())
                    $http='https';
                else
                    $http='http';

            if(isset($_SERVER['HTTP_HOST'])) {
                $this->_hostInfo=$http . '://' . $_SERVER['HTTP_HOST'];
            } else {
                $this->_hostInfo=$http . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'];
            }
        }

        return $this->_hostInfo;
    }

    public function getBaseUrl($absolute=false)
    {
        if($this->_baseUrl === null) {
            $this->_baseUrl = rtrim(dirname($this->getScriptUrl()),'\\/');
        }

        return $absolute ? $this->getHostInfo() . $this->_baseUrl : $this->_baseUrl;
    }

    public function createUrl($route, $absolute=false)
    {
        $route = trim($route, '/');

        if(empty($route)) {
            return $this->getBaseUrl($absolute);
        }

        if($this->_urlFormat == 'path') {
            return $this->getBaseUrl($absolute) . '/' . $route;
        } else {
            if($absolute) {
                return $this->getHostInfo() . $this->getScriptUrl() . '?r=' . $route;
            } else {
                return $this->getScriptUrl() . '?r=' . $route;
            }
        }
    }
}


<?php

/*
 * This file is part of the Valkyrja framework.
 *
 * (c) Melech Mizrachi
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Valkyrja\Console\Commands;

use Valkyrja\Console\CommandHandler;
use Valkyrja\Console\Support\ProvidesCommand;

/**
 * Class ConsoleCommands.
 *
 * @author Melech Mizrachi
 */
class CommandsListForBashCommand extends CommandHandler
{
    use ProvidesCommand;

    /**
     * The command.
     */
    public const COMMAND           = 'console:commandsForBash';
    public const PATH              = self::COMMAND . ' valkyrja[ {commandTyped:[a-zA-Z0-9\:]+}]';
    public const SHORT_DESCRIPTION = 'List all the commands for bash auto complete';

    /**
     * Run the command.
     *
     * @param string $commandTyped The command typed
     *
     * @return int
     */
    public function run(string $commandTyped = null): int
    {
        $allCommands = array_keys(console()->getNamedCommands());

        if ($commandTyped) {
            $colonAt          = strpos($commandTyped, ':');
            $possibleCommands = [];

            foreach ($allCommands as $command) {
                // Return command in result if it starts with $commandTyped
                if (strpos($command, $commandTyped) === 0) {
                    // Colons acts as separators in bash, so return only second
                    // part if colon is in commandTyped.
                    $possibleCommands[] =
                        $colonAt ? substr($command, $colonAt + 1) : $command;
                }
            }
        } else {
            // Nothing typed, return all
            $possibleCommands = $allCommands;
        }

        output()->writeMessage(implode(' ', $possibleCommands));

        return 0;
    }
}


<?php namespace Ordercloud\Entities\Addresses;

use JsonSerializable;

class NamedCoordinatedAddress extends Address implements JsonSerializable
{
    /**
     * @var GeoCoordinates
     */
    private $coordinates;
    /**
     * @var string
     */
    private $name;

    /**
     * @param string $streetNumber
     * @param string $streetName
     * @param string $complex
     * @param string $suburb
     * @param string $city
     * @param string $postalCode
     * @param string $name
     * @param string $latitude
     * @param string $longitude
     */
    public function __construct($streetNumber, $streetName, $complex, $suburb, $city, $postalCode, $name, $latitude, $longitude)
    {
        parent::__construct($streetNumber, $streetName, $complex, $suburb, $city, $postalCode);
        $this->coordinates = new GeoCoordinates($latitude, $longitude);
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return GeoCoordinates
     */
    public function getCoordinates()
    {
        return $this->coordinates;
    }

    /**
     * @return string
     */
    public function getLatitude()
    {
        return $this->coordinates->getLatitude();
    }

    /**
     * @return string
     */
    public function getLongitude()
    {
        return $this->coordinates->getLongitude();
    }

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        $json = parent::jsonSerialize();

        $json['name'] = $this->getName();
        $json['latitude'] = $this->getCoordinates()->getLatitude();
        $json['longitude'] = $this->getCoordinates()->getLongitude();

        return $json;
    }
}


<?php

/**
* Jin Framework
* Diatem
*/

namespace Jin2\Utils;

/**
 * Boite à outils pour les couleurs
 */
class ColorTools
{

  /**
   * X11 color names and their RGB value
   * @var array
   */
  public static $x11 = array(
      'aliceblue'             => array('red' => 240,  'green' => 248, 'blue' => 255),
      'antiquewhite'          => array('red' => 250,  'green' => 235, 'blue' => 215),
      'aqua'                  => array('red' => 0,    'green' => 255, 'blue' => 255),
      'aquamarine'            => array('red' => 127,  'green' => 255, 'blue' => 212),
      'azure'                 => array('red' => 240,  'green' => 255, 'blue' => 255),
      'beige'                 => array('red' => 245,  'green' => 245, 'blue' => 220),
      'bisque'                => array('red' => 255,  'green' => 228, 'blue' => 196),
      'black'                 => array('red' => 0,    'green' => 0,   'blue' => 0),
      'blanchedalmond'        => array('red' => 255,  'green' => 235, 'blue' => 205),
      'blue'                  => array('red' => 0,    'green' => 0,   'blue' => 255),
      'blueviolet'            => array('red' => 138,  'green' => 43,  'blue' => 226),
      'brown'                 => array('red' => 165,  'green' => 42,  'blue' => 42),
      'burlywood'             => array('red' => 222,  'green' => 184, 'blue' => 135),
      'cadetblue'             => array('red' => 95,   'green' => 158, 'blue' => 160),
      'chartreuse'            => array('red' => 127,  'green' => 255, 'blue' => 0),
      'chocolate'             => array('red' => 210,  'green' => 105, 'blue' => 30),
      'coral'                 => array('red' => 255,  'green' => 127, 'blue' => 80),
      'cornflowerblue'        => array('red' => 100,  'green' => 149, 'blue' => 237),
      'cornsilk'              => array('red' => 255,  'green' => 248, 'blue' => 220),
      'crimson'               => array('red' => 220,  'green' => 20,  'blue' => 60),
      'cyan'                  => array('red' => 0,    'green' => 255, 'blue' => 255),
      'darkblue'              => array('red' => 0,    'green' => 0,   'blue' => 139),
      'darkcyan'              => array('red' => 0,    'green' => 139, 'blue' => 139),
      'darkgoldenrod'         => array('red' => 184,  'green' => 134, 'blue' => 11),
      'darkgray'              => array('red' => 169,  'green' => 169, 'blue' => 169),
      'darkgreen'             => array('red' => 0,    'green' => 100, 'blue' => 0),
      'darkkhaki'             => array('red' => 189,  'green' => 183, 'blue' => 107),
      'darkmagenta'           => array('red' => 139,  'green' => 0,   'blue' => 139),
      'darkolivegreen'        => array('red' => 85,   'green' => 107, 'blue' => 47),
      'darkorange'            => array('red' => 255,  'green' => 140, 'blue' => 0),
      'darkorchid'            => array('red' => 153,  'green' => 50,  'blue' => 204),
      'darkred'               => array('red' => 139,  'green' => 0,   'blue' => 0),
      'darksalmon'            => array('red' => 233,  'green' => 150, 'blue' => 122),
      'darkseagreen'          => array('red' => 143,  'green' => 188, 'blue' => 143),
      'darkslateblue'         => array('red' => 72,   'green' => 61,  'blue' => 139),
      'darkslategray'         => array('red' => 47,   'green' => 79,  'blue' => 79),
      'darkturquoise'         => array('red' => 0,    'green' => 206, 'blue' => 209),
      'darkviolet'            => array('red' => 148,  'green' => 0,   'blue' => 211),
      'deeppink'              => array('red' => 255,  'green' => 20,  'blue' => 147),
      'deepskyblue'           => array('red' => 0,    'green' => 191, 'blue' => 255),
      'dimgray'               => array('red' => 105,  'green' => 105, 'blue' => 105),
      'dodgerblue'            => array('red' => 30,   'green' => 144, 'blue' => 255),
      'firebrick'             => array('red' => 178,  'green' => 34,  'blue' => 34),
      'floralwhite'           => array('red' => 255,  'green' => 250, 'blue' => 240),
      'forestgreen'           => array('red' => 34,   'green' => 139, 'blue' => 34),
      'fuchsia'               => array('red' => 255,  'green' => 0,   'blue' => 255),
      'gainsboro'             => array('red' => 220,  'green' => 220, 'blue' => 220),
      'ghostwhite'            => array('red' => 248,  'green' => 248, 'blue' => 255),
      'gold'                  => array('red' => 255,  'green' => 215, 'blue' => 0),
      'goldenrod'             => array('red' => 218,  'green' => 165, 'blue' => 32),
      'gray'                  => array('red' => 128,  'green' => 128, 'blue' => 128),
      'green'                 => array('red' => 0,    'green' => 128, 'blue' => 0),
      'greenyellow'           => array('red' => 173,  'green' => 255, 'blue' => 47),
      'honeydew'              => array('red' => 240,  'green' => 255, 'blue' => 240),
      'hotpink'               => array('red' => 255,  'green' => 105, 'blue' => 180),
      'indianred'             => array('red' => 205,  'green' => 92,  'blue' => 92),
      'indigo'                => array('red' => 75,   'green' => 0,   'blue' => 130),
      'ivory'                 => array('red' => 255,  'green' => 255, 'blue' => 240),
      'khaki'                 => array('red' => 240,  'green' => 230, 'blue' => 140),
      'lavender'              => array('red' => 230,  'green' => 230, 'blue' => 250),
      'lavenderblush'         => array('red' => 255,  'green' => 240, 'blue' => 245),
      'lawngreen'             => array('red' => 124,  'green' => 252, 'blue' => 0),
      'lemonchiffon'          => array('red' => 255,  'green' => 250, 'blue' => 205),
      'lightblue'             => array('red' => 173,  'green' => 216, 'blue' => 230),
      'lightcoral'            => array('red' => 240,  'green' => 128, 'blue' => 128),
      'lightcyan'             => array('red' => 224,  'green' => 255, 'blue' => 255),
      'lightgoldenrodyellow'  => array('red' => 250,  'green' => 250, 'blue' => 210),
      'lightgreen'            => array('red' => 144,  'green' => 238, 'blue' => 144),
      'lightgrey'             => array('red' => 211,  'green' => 211, 'blue' => 211),
      'lightpink'             => array('red' => 255,  'green' => 182, 'blue' => 193),
      'lightsalmon'           => array('red' => 255,  'green' => 160, 'blue' => 122),
      'lightseagreen'         => array('red' => 32,   'green' => 178, 'blue' => 170),
      'lightskyblue'          => array('red' => 135,  'green' => 206, 'blue' => 250),
      'lightslategray'        => array('red' => 119,  'green' => 136, 'blue' => 153),
      'lightsteelblue'        => array('red' => 176,  'green' => 196, 'blue' => 222),
      'lightyellow'           => array('red' => 255,  'green' => 255, 'blue' => 224),
      'lime'                  => array('red' => 0,    'green' => 255, 'blue' => 0),
      'limegreen'             => array('red' => 50,   'green' => 205, 'blue' => 50),
      'linen'                 => array('red' => 250,  'green' => 240, 'blue' => 230),
      'magenta'               => array('red' => 255,  'green' => 0,   'blue' => 255),
      'maroon'                => array('red' => 128,  'green' => 0,   'blue' => 0),
      'mediumaquamarine'      => array('red' => 102,  'green' => 205, 'blue' => 170),
      'mediumblue'            => array('red' => 0,    'green' => 0,   'blue' => 205),
      'mediumorchid'          => array('red' => 186,  'green' => 85,  'blue' => 211),
      'mediumpurple'          => array('red' => 147,  'green' => 112, 'blue' => 219),
      'mediumseagreen'        => array('red' => 60,   'green' => 179, 'blue' => 113),
      'mediumslateblue'       => array('red' => 123,  'green' => 104, 'blue' => 238),
      'mediumspringgreen'     => array('red' => 0,    'green' => 250, 'blue' => 154),
      'mediumturquoise'       => array('red' => 72,   'green' => 209, 'blue' => 204),
      'mediumvioletred'       => array('red' => 199,  'green' => 21,  'blue' => 133),
      'midnightblue'          => array('red' => 25,   'green' => 25,  'blue' => 112),
      'mintcream'             => array('red' => 245,  'green' => 255, 'blue' => 250),
      'mistyrose'             => array('red' => 255,  'green' => 228, 'blue' => 225),
      'moccasin'              => array('red' => 255,  'green' => 228, 'blue' => 181),
      'navajowhite'           => array('red' => 255,  'green' => 222, 'blue' => 173),
      'navy'                  => array('red' => 0,    'green' => 0,   'blue' => 128),
      'oldlace'               => array('red' => 253,  'green' => 245, 'blue' => 230),
      'olive'                 => array('red' => 128,  'green' => 128, 'blue' => 0),
      'olivedrab'             => array('red' => 107,  'green' => 142, 'blue' => 35),
      'orange'                => array('red' => 255,  'green' => 165, 'blue' => 0),
      'orangered'             => array('red' => 255,  'green' => 69,  'blue' => 0),
      'orchid'                => array('red' => 218,  'green' => 112, 'blue' => 214),
      'palegoldenrod'         => array('red' => 238,  'green' => 232, 'blue' => 170),
      'palegreen'             => array('red' => 152,  'green' => 251, 'blue' => 152),
      'paleturquoise'         => array('red' => 175,  'green' => 238, 'blue' => 238),
      'palevioletred'         => array('red' => 219,  'green' => 112, 'blue' => 147),
      'papayawhip'            => array('red' => 255,  'green' => 239, 'blue' => 213),
      'peachpuff'             => array('red' => 255,  'green' => 218, 'blue' => 185),
      'peru'                  => array('red' => 205,  'green' => 133, 'blue' => 63),
      'pink'                  => array('red' => 255,  'green' => 192, 'blue' => 203),
      'plum'                  => array('red' => 221,  'green' => 160, 'blue' => 221),
      'powderblue'            => array('red' => 176,  'green' => 224, 'blue' => 230),
      'purple'                => array('red' => 128,  'green' => 0,   'blue' => 128),
      'red'                   => array('red' => 255,  'green' => 0,   'blue' => 0),
      'rosybrown'             => array('red' => 188,  'green' => 143, 'blue' => 143),
      'royalblue'             => array('red' => 65,   'green' => 105, 'blue' => 225),
      'saddlebrown'           => array('red' => 139,  'green' => 69,  'blue' => 19),
      'salmon'                => array('red' => 250,  'green' => 128, 'blue' => 114),
      'sandybrown'            => array('red' => 244,  'green' => 164, 'blue' => 96),
      'seagreen'              => array('red' => 46,   'green' => 139, 'blue' => 87),
      'seashell'              => array('red' => 255,  'green' => 245, 'blue' => 238),
      'sienna'                => array('red' => 160,  'green' => 82,  'blue' => 45),
      'silver'                => array('red' => 192,  'green' => 192, 'blue' => 192),
      'skyblue'               => array('red' => 135,  'green' => 206, 'blue' => 235),
      'slateblue'             => array('red' => 106,  'green' => 90,  'blue' => 205),
      'slategray'             => array('red' => 112,  'green' => 128, 'blue' => 144),
      'snow'                  => array('red' => 255,  'green' => 250, 'blue' => 250),
      'springgreen'           => array('red' => 0,    'green' => 255, 'blue' => 127),
      'steelblue'             => array('red' => 70,   'green' => 130, 'blue' => 180),
      'tan'                   => array('red' => 210,  'green' => 180, 'blue' => 140),
      'teal'                  => array('red' => 0,    'green' => 128, 'blue' => 128),
      'thistle'               => array('red' => 216,  'green' => 191, 'blue' => 216),
      'tomato'                => array('red' => 255,  'green' => 99,  'blue' => 71),
      'turquoise'             => array('red' => 64,   'green' => 224, 'blue' => 208),
      'violet'                => array('red' => 238,  'green' => 130, 'blue' => 238),
      'wheat'                 => array('red' => 245,  'green' => 222, 'blue' => 179),
      'white'                 => array('red' => 255,  'green' => 255, 'blue' => 255),
      'whitesmoke'            => array('red' => 245,  'green' => 245, 'blue' => 245),
      'yellow'                => array('red' => 255,  'green' => 255, 'blue' => 0),
      'yellowgreen'           => array('red' => 154,  'green' => 205, 'blue' => 50)
  );

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

  /**
   * Change a color format to RGB
   *
   * @param  mixed $color Color
   * @return array        An [red, green, blue] associative array
   */
  public static function toRGB($color)
  {
    $color = static::toRGBA($color);
    unset($color['alpha']);
    return $color;
  }

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

  /**
   * Change a color format to the HTML rgb() one
   *
   * @param  mixed $color Color
   * @return string       rgb(red, green, blue)
   */
  public static function toHTMLRGB($color)
  {
    $color = static::toRGB($color);
    return 'rgb('.$color['red'].', '.$color['green'].', '.$color['blue'].')';
  }

  /**
   * Change a color format to the HTML rgb() one
   *
   * @param  mixed $color Color
   * @return string       rgba(red, green, blue, alpha)
   */
  public static function toHTMLRGBA($color)
  {
    $color = static::toRGBA($color);
    return 'rgba('.$color['red'].', '.$color['green'].', '.$color['blue'].', '.$color['alpha'].')';
  }

  /**
   * Return the dominant color for an image
   *
   * @param  string   $src        Image path/url
   * @param  integer $granularity Search's granularity (Ex. default value : 30/40.)
   * @return mixed                An [red, green, blue] associative array
   */
  public static function imageDominant($src, $granularity = 1)
  {
    $granularity = max(1, abs((int)$granularity));
    $channels = array(
      'red' => 0,
      'green' => 0,
      'blue' => 0
    );
    $size = @getimagesize($src);
    if ($size === false) {
      user_error("Unable to get image size data: ".$src);
      return false;
    }
    $img = @imagecreatefromstring(@file_get_contents($src));
    if (!$img) {
      user_error("Unable to open image file: ".$src);
      return false;
    }
    for($x = 0; $x < $size[0]; $x += $granularity) {
      for($y = 0; $y < $size[1]; $y += $granularity) {
        $thisColor = imagecolorat($img, $x, $y);
        $rgb = imagecolorsforindex($img, $thisColor);
        $channels['red'] += $rgb['red'];
        $channels['green'] += $rgb['green'];
        $channels['blue'] += $rgb['blue'];
      }
    }
    $nbPixels = ceil($size[0] / $granularity) * ceil($size[1] / $granularity);
    $channels['red'] = round($channels['red'] / $nbPixels);
    $channels['green'] = round($channels['green'] / $nbPixels);
    $channels['blue'] = round($channels['blue'] / $nbPixels);
    return $channels;
  }

  /**
   * Return a visible color over another one (eg. #ffffee is not visible over #ffffff)
   *
   * @param  mixed   $color     Background color
   * @param  boolean $greyscale Should output color be grey?
   * @return mixed              An [red, green, blue] associative array
   */
  public static function visibleOver($color, $greyscale = false)
  {
    $color = static::toRGBA($color);
    if ($greyscale) {
      $median = 255 - ($color['red'] + $color['green'] + $color['blue']) / 3;
      return array(
        'red' => $median,
        'green' => $median,
        'blue' => $median
      );
    }
    return array(
      'red' => 255 - $color['red'],
      'green' => 255 - $color['green'],
      'blue' => 255 - $color['blue']
    );
  }

}


<?php

namespace Ekyna\Bundle\CoreBundle;

use Ekyna\Bundle\CoreBundle\DependencyInjection\Compiler\ResolveDoctrineTargetEntitiesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class AbstractBundle
 * @package Ekyna\Bundle\CoreBundle
 * @author Étienne Dauvergne <contact@ekyna.com>
 */
abstract class AbstractBundle extends Bundle
{
    /**
     * {@inheritdoc}
     */
    public function build(ContainerBuilder $container)
    {
        $interfaces = $this->getModelInterfaces();
        if (!empty($interfaces)) {
            $container->addCompilerPass(
                new ResolveDoctrineTargetEntitiesPass($interfaces)
            );
        }
    }

    /**
     * Target entities resolver configuration (Interface - Model).
     *
     * @return array
     */
    protected function getModelInterfaces()
    {
        return [];
    }
}


<?php namespace Ordercloud\Entities\Delivery;

use JsonSerializable;
use Ordercloud\Entities\Organisations\OrganisationShort;
use Ordercloud\Entities\Users\UserShort;

class DeliveryAgent implements JsonSerializable
{
    /** @var integer */
    private $id;
    /** @var UserShort */
    private $user;
    /** @var OrganisationShort */
    private $organisation;
    /** @var float */
    private $minBalance;
    /** @var float */
    private $maxBalance;
    /** @var boolean */
    private $enabled;
    /** @var DeliveryAgentStatus */
    private $status;
    /**
     * @var string
     * The MASKED account number. Only shows the last 6 digits.
     */
    private $accountNo;
    /**
     * @var string
     * The MASKED card number. Only shows the last 4 digits.
     */
    private $cardNo;

    public function __construct($id, UserShort $user, OrganisationShort $organisation, $minBalance, $maxBalance, $enabled, DeliveryAgentStatus $status, $accountNo, $cardNo)
    {
        $this->id = $id;
        $this->user = $user;
        $this->organisation = $organisation;
        $this->minBalance = $minBalance;
        $this->maxBalance = $maxBalance;
        $this->enabled = $enabled;
        $this->status = $status;
        $this->accountNo = $accountNo;
        $this->cardNo = $cardNo;
    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return UserShort
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @return OrganisationShort
     */
    public function getOrganisation()
    {
        return $this->organisation;
    }

    /**
     * @return float
     */
    public function getMinBalance()
    {
        return $this->minBalance;
    }

    /**
     * @return float
     */
    public function getMaxBalance()
    {
        return $this->maxBalance;
    }

    /**
     * @return boolean
     */
    public function isEnabled()
    {
        return $this->enabled;
    }

    /**
     * @return DeliveryAgentStatus
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * @return string
     */
    public function getAccountNo()
    {
        return $this->accountNo;
    }

    /**
     * @return string
     */
    public function getCardNo()
    {
        return $this->cardNo;
    }

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        return [
            'id' => $this->getId(),
            'user' => $this->getUser(),
            'organisation' => $this->getOrganisation(),
            'minBalance' => $this->getMinBalance(),
            'maxBalance' => $this->getMaxBalance(),
            'enabled' => $this->isEnabled(),
            'status' => $this->getStatus(),
            'accountNo' => $this->getAccountNo(),
            'cardNo' => $this->getCardNo(),
        ];
    }
}


<?php
/**
 * OpenWebPresence Support Library - openwebpresence.com
 *
 * @copyright 2001 - 2017, Brian Tafoya.
 * @package   OwpConfig
 * @author    Brian Tafoya <btafoya@briantafoya.com>
 * @version   1.0
 * @license   MIT
 * @license   https://opensource.org/licenses/MIT The MIT License
 * @category  OpenWebPresence_Support_Library
 * @link      http://openwebpresence.com OpenWebPresence
 *
 * Copyright (c) 2017, Brian Tafoya
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * This class provides configuration information.
 */
class OwpConfig
{

    /**
     * GetConfigItem
     *
     * @method mixed GetConfigItem($subjectName,$itemName) Get configuration setting
     * @access public
     *
     * @param string $subjectName Subject Data Array Name
     * @param string $itemName    Subject Data Array Key Name
     *
     * @return mixed Array value
     *
     * @throws InvalidArgumentException Config data does not exist, code 20
     *
     * @author  Brian Tafoya <btafoya@briantafoya.com>
     * @version 1.0
     */
    static public function GetConfigItem($subjectName,$itemName)
    {
        $includePath = ROOT_PATH."config".DIRECTORY_SEPARATOR.$subjectName.".php";

        if(!file_exists($includePath)) {
            throw new InvalidArgumentException($subjectName." include not found.", 20);
        }

        include $includePath;

        if(!empty($$subjectName) && array_key_exists($itemName, $$subjectName)) {
            $response = $$subjectName;
            return $response[$itemName];
        } else {
            throw new InvalidArgumentException($subjectName."->".$itemName." does not exist.", 20);
        }

    }//end GetConfigItem()
}