<?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\HttpMessage;

use DateTime;
use Valkyrja\Http\Exceptions\InvalidSameSiteTypeException;

/**
 * Class Cookie.
 *
 * @author Melech Mizrachi
 */
class Cookie
{
    public const LAX    = 'lax';
    public const STRICT = 'strict';

    protected const DELETED = 'deleted';

    /**
     * The cookie name.
     *
     * @var string
     */
    protected $name;

    /**
     * The cookie value.
     *
     * @var string
     */
    protected $value;

    /**
     * The cookie expire time.
     *
     * @var int
     */
    protected $expire;

    /**
     * The cookie path.
     *
     * @var string
     */
    protected $path;

    /**
     * The cookie domain.
     *
     * @var string
     */
    protected $domain;

    /**
     * Whether the cookie is secure.
     *
     * @var bool
     */
    protected $secure;

    /**
     * Whether the cookie is http only.
     *
     * @var bool
     */
    protected $httpOnly;

    /**
     * Whether the cookie is raw.
     *
     * @var bool
     */
    protected $raw;

    /**
     * Whether the cookie will be available for cross-site requests.
     *
     * @var string
     */
    protected $sameSite;

    /**
     * Cookie constructor.
     *
     * @param string $name     The cookie's name
     * @param string $value    [optional] The cookie's value
     * @param int    $expire   [optional] The time the cookie should expire
     * @param string $path     [optional] The path the cookie is available to
     * @param string $domain   [optional] The domain the cookie is available to
     * @param bool   $secure   [optional] Whether the cookie should only be
     *                         transmitted over a secure HTTPS connection
     * @param bool   $httpOnly [optional] Whether the cookie will be made
     *                         accessible only through the HTTP protocol
     * @param bool   $raw      [optional] Whether the cookie value should be
     *                         sent with no url encoding
     * @param string $sameSite [optional] Whether the cookie will be available
     *                         for cross-site requests
     *
     * @throws \Valkyrja\Http\Exceptions\InvalidSameSiteTypeException
     */
    public function __construct(
        string $name,
        string $value = null,
        int $expire = 0,
        string $path = '/',
        string $domain = null,
        bool $secure = false,
        bool $httpOnly = true,
        bool $raw = false,
        string $sameSite = null
    ) {
        $this->name   = $name;
        $this->value  = $value;
        $this->expire = $expire;
        $this->path   = $path;
        $this->domain = $domain;
        $this->secure = $secure;
        $this->raw    = $raw;

        $this->setSameSite($sameSite);
    }

    /**
     * Returns the cookie as a string.
     *
     * @return string The cookie
     */
    public function __toString(): string
    {
        $str    = urlencode($this->name) . '=';
        $value  = $this->value ?? static::DELETED;
        $expire = $this->expire ?? 0;
        $maxAge = $this->getMaxAge();

        if ($value === static::DELETED) {
            $expire = time() - 31536001;
            $maxAge = -31536001;
        }

        $str .= urlencode($value);

        if ($expire !== 0) {
            $str .= '; expires='
                . gmdate(
                    DateTime::COOKIE,
                    $expire
                )
                . '; max-age=' . $maxAge;
        }

        if ($this->path) {
            $str .= '; path=' . $this->path;
        }

        if ($this->domain) {
            $str .= '; domain=' . $this->domain;
        }

        if (true === $this->secure) {
            $str .= '; secure';
        }

        if (true === $this->httpOnly) {
            $str .= '; httponly';
        }

        if (null !== $this->sameSite) {
            $str .= '; samesite=' . $this->sameSite;
        }

        return $str;
    }

    /**
     * Get the cookie's name.
     *
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * Set the cookie's name.
     *
     * @param string $name The name
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get the cookie's value.
     *
     * @return string
     */
    public function getValue(): string
    {
        return $this->value;
    }

    /**
     * Set the cookie's value.
     *
     * @param string $value The value
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setValue(string $value = null): self
    {
        $this->value = $value;

        return $this;
    }

    /**
     * Get expire time for the cookie.
     *
     * @return int
     */
    public function getExpire(): int
    {
        return $this->expire;
    }

    /**
     * Gets the max age of the cookie.
     *
     * @return int
     */
    public function getMaxAge(): int
    {
        return $this->expire > 0
            ? $this->expire - time()
            : 0;
    }

    /**
     * Set expire time for the cookie.
     *
     * @param int $expire The expire time
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setExpire(int $expire = null): self
    {
        $this->expire = $expire;

        return $this;
    }

    /**
     * Get the path the cookie is available to.
     *
     * @return string
     */
    public function getPath(): string
    {
        return $this->path;
    }

    /**
     * Set the path the cookie is available to.
     *
     * @param string $path The path
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setPath(string $path = null): self
    {
        $this->path = $path;

        return $this;
    }

    /**
     * Get the domain the cookie is available to.
     *
     * @return string
     */
    public function getDomain(): string
    {
        return $this->domain;
    }

    /**
     * Set the domain the cookie is available to.
     *
     * @param string $domain The domain
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setDomain(string $domain = null): self
    {
        $this->domain = $domain;

        return $this;
    }

    /**
     * Whether the cookie should only be transmitted over a secure HTTPS
     * connection.
     *
     * @return bool
     */
    public function isSecure(): bool
    {
        return $this->secure;
    }

    /**
     * Set whether the cookie should only be transmitted over a secure HTTPS
     * connection.
     *
     * @param bool $secure
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setSecure(bool $secure = null): self
    {
        $this->secure = $secure;

        return $this;
    }

    /**
     * Whether the cookie will be made accessible only through the HTTP
     * protocol.
     *
     * @return bool
     */
    public function isHttpOnly(): bool
    {
        return $this->httpOnly;
    }

    /**
     * Set whether the cookie will be made accessible only through the HTTP
     * protocol.
     *
     * @param bool $httpOnly
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setHttpOnly(bool $httpOnly = null): self
    {
        $this->httpOnly = $httpOnly;

        return $this;
    }

    /**
     * Whether the cookie value should be sent with no url encoding.
     *
     * @return bool
     */
    public function isRaw(): bool
    {
        return $this->raw;
    }

    /**
     * Set whether the cookie value should be sent with no url encoding.
     *
     * @param bool $raw
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setRaw(bool $raw = null): self
    {
        $this->raw = $raw;

        return $this;
    }

    /**
     * Get whether the cookie will be available for cross-site requests.
     *
     * @return string
     */
    public function getSameSite(): string
    {
        return $this->sameSite;
    }

    /**
     * Set whether the cookie will be available for cross-site requests.
     *
     * @param string $sameSite
     *
     * @throws \Valkyrja\Http\Exceptions\InvalidSameSiteTypeException
     *
     * @return \Valkyrja\HttpMessage\Cookie
     */
    public function setSameSite(string $sameSite = null): self
    {
        if (! \in_array($sameSite, [self::LAX, self::STRICT, null], true)) {
            throw new InvalidSameSiteTypeException(
                'The "sameSite" parameter value is not valid.'
            );
        }

        $this->sameSite = $sameSite;

        return $this;
    }
}


<?php namespace Ordercloud\Entities\Orders;

use JsonSerializable;
use Ordercloud\Entities\Delivery\DeliveryAgent;
use Ordercloud\Entities\OrderDiscount\OrderDiscount;
use Ordercloud\Entities\Organisations\OrganisationShort;
use Ordercloud\Entities\Payments\Payment;
use Ordercloud\Entities\Users\UserAddress;
use Ordercloud\Entities\Users\UserShort;

class Order implements JsonSerializable
{
    const DELIVERY_TYPE_SELFPICKUP = 'SELFPICKUP';
    const DELIVERY_TYPE_DELIVERY = 'DELIVERY';

    /** @var integer */
    private $id;
    /** @var string */
    private $reference;
    /** @var string */
    private $shortReference;
    /** @var string */
    private $dateCreated;
    /** @var string */
    private $lastUpdated;
    /** @var float */
    private $amount;
    /** @var OrderStatus */
    private $status;
    /**
     * @var array|OrderItem[]
     * @reflectType Ordercloud\Entities\Orders\OrderItem
     */
    private $items;
    /** @var UserShort */
    private $user;
    /**
     * @var UserAddress
     * @reflectName userGeo
     */
    private $userAddress;
    /** @var OrganisationShort */
    private $organisation;
    /** @var OrderPaymentStatus */
    private $paymentStatus;
    /**
     * @var array|Payment[]
     * @reflectType \Ordercloud\Entities\Payments\Payment
     */
    private $payments;
    /**
     * @var array|string[]
     */
    private $paymentMethods;
    /** @var string */
    private $deliveryType;
    /** @var DeliveryAgent */
    private $deliveryAgent;
    /** @var string */
    private $note;
    /** @var string */
    private $estimatedDeliveryTime;
    /** @var float */
    private $deliveryCost;
    /**
     * @var OrderSourceChannel
     */
    private $orderSourceChannel;
    /**
     * @var string
     */
    private $scheduledDate;
    /**
     * @var float
     */
    private $tip;
    /**
     * @var null|OrderDelivery
     */
    private $delivery;
    /**
     * @var float
     */
    private $adminFee;

    /**
     * @var array|orderDiscount
     * @reflectType Ordercloud\Entities\Orders\OrderDiscount
     */
    private $orderDiscount;

    //TODO add: delivery + statusHistory
    public function __construct(
        $id,
        $reference,
        $shortReference,
        $dateCreated,
        $lastUpdated,
        $amount,
        OrderStatus $status,
        array $items,
        UserShort $user,
        UserAddress $userAddress = null,
        OrganisationShort $organisation,
        OrderPaymentStatus $paymentStatus,
        array $payments,
        array $paymentMethods,
        $deliveryType,
        DeliveryAgent $deliveryAgent = null,
        $note,
        $estimatedDeliveryTime,
        $deliveryCost,
        OrderSourceChannel $orderSourceChannel = null,
        $scheduledDate = null,
        $tip,
        OrderDelivery $delivery = null,
        array $orderDiscount = null,
        $adminFee = 0
    )
    {
        $this->id = $id;
        $this->reference = $reference;
        $this->shortReference = $shortReference;
        $this->dateCreated = $dateCreated;
        $this->lastUpdated = $lastUpdated;
        $this->amount = $amount;
        $this->status = $status;
        $this->items = $items;
        $this->user = $user;
        $this->userAddress = $userAddress;
        $this->organisation = $organisation;
        $this->paymentStatus = $paymentStatus;
        $this->payments = $payments;
        $this->paymentMethods = $paymentMethods;
        $this->deliveryType = $deliveryType;
        $this->deliveryAgent = $deliveryAgent;
        $this->note = $note;
        $this->estimatedDeliveryTime = $estimatedDeliveryTime;
        $this->deliveryCost = $deliveryCost;
        $this->orderSourceChannel = $orderSourceChannel;
        $this->scheduledDate = $scheduledDate;
        $this->tip = $tip;
        $this->delivery = $delivery;
        $this->adminFee = $adminFee;
        $this->orderDiscount = $orderDiscount;
    }

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

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

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

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

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

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

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

    /**
     * @param string $status
     *
     * @return bool
     */
    public function isStatus($status)
    {
        return strcasecmp($this->getStatus(), $status) === 0;
    }

    /**
     * @return array|OrderItem[]
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * Returns all order items grouped by merchant
     *
     * @return array|MerchantItems[]
     */
    public function getMerchantItems()
    {
        return MerchantItems::createFromOrder($this);
    }

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

    /**
     * @return UserAddress
     */
    public function getUserAddress()
    {
        return $this->userAddress;
    }

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

    /**
     * @return OrderPaymentStatus
     */
    public function getPaymentStatus()
    {
        return $this->paymentStatus;
    }

    /**
     * @return array|\Ordercloud\Entities\Payments\Payment[]
     */
    public function getPayments()
    {
        return $this->payments;
    }

    /**
     * @return array|string[]
     */
    public function getPaymentMethods()
    {
        return $this->paymentMethods;
    }

    /**
     * @return bool
     */
    public function hasPaymentMethods()
    {
        return ! empty($this->paymentMethods);
    }

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

    /**
     * @param string $deliveryType
     *
     * @return bool
     */
    public function isDeliveryType($deliveryType)
    {
        return strcasecmp($this->getDeliveryType(), $deliveryType) === 0;
    }

    /**
     * @return DeliveryAgent
     */
    public function getDeliveryAgent()
    {
        return $this->deliveryAgent;
    }

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

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

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

    /**
     * @return OrderSourceChannel
     */
    public function getOrderSourceChannel()
    {
        return $this->orderSourceChannel;
    }

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

    public function getTip()
    {
        return $this->tip;
    }

    /**
     * @return null|OrderDelivery
     */
    public function getDelivery()
    {
        return $this->delivery;
    }

    /**
     * @return null|OrderDiscount
     */
    public function getOrderDiscount()
    {
        return $this->orderDiscount;
    }

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

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        return [
            'id' => $this->getId(),
            'reference' => $this->getReference(),
            'shortReference' => $this->getShortReference(),
            'dateCreated' => $this->getDateCreated(),
            'lastUpdated' => $this->getLastUpdated(),
            'amount' => $this->getAmount(),
            'status' => $this->getStatus(),
            'items' => $this->getItems(),
            'user' => $this->getUser(),
            'userGeo' => $this->getUserAddress(),
            'organisation' => $this->getOrganisation(),
            'paymentStatus' => $this->getPaymentStatus(),
            'payments' => $this->getPayments(),
            'paymentMethod' => $this->getPaymentMethods(),
            'deliveryType' => $this->getDeliveryType(),
            'deliveryAgent' => $this->getDeliveryAgent(),
            'delivery' => $this->getDelivery(),
            'note' => $this->getNote(),
            'estimatedDeliveryTime' => $this->getEstimatedDeliveryTime(),
            'deliveryCost' => $this->getDeliveryCost(),
            'orderSourceChannel' => $this->getOrderSourceChannel(),
            'scheduledDate' => $this->getScheduledDate(),
            'tip' => $this->getTip(),
            'adminFee' => $this->getAdminFee(),
            'orderDiscount' => $this->getOrderDiscount(),
        ];
    }
}


<?php

namespace Reaction\Helpers\Request;

use Reaction\Exceptions\InvalidArgumentException;

/**
 * Class ArrayHelper. Proxy to \Reaction\Helpers\ArrayHelper
 * @package Reaction\Helpers\Request
 */
class ArrayHelper extends RequestAppHelperProxy
{
    public $helperClass = 'Reaction\Helpers\ArrayHelper';

    /**
     * Converts an object or an array of objects into an array.
     * @param object|array|string $object the object to be converted into an array
     * @param array $properties a mapping from object class names to the properties that need to put into the resulting arrays.
     * The properties specified for each class is an array of the following format:
     *
     * ```php
     * [
     *     'App\Models\Post' => [
     *         'id',
     *         'title',
     *         // the key name in array result => property name
     *         'createTime' => 'created_at',
     *         // the key name in array result => anonymous function
     *         'length' => function ($post) {
     *             return strlen($post->content);
     *         },
     *     ],
     * ]
     * ```
     *
     * The result of `ArrayHelper::toArray($post, $properties)` could be like the following:
     *
     * ```php
     * [
     *     'id' => 123,
     *     'title' => 'test',
     *     'createTime' => '2013-01-01 12:00AM',
     *     'length' => 301,
     * ]
     * ```
     *
     * @param bool $recursive whether to recursively converts properties which are objects into arrays.
     * @return array the array representation of the object
     * @see \Reaction\Helpers\ArrayHelper::toArray()
     */
    public function toArray($object, $properties = [], $recursive = true)
    {
        return $this->proxy(__FUNCTION__, [$object, $properties, $recursive]);
    }

    /**
     * Merges two or more arrays into one recursively.
     * If each array has an element with the same string key value, the latter
     * will overwrite the former (different from array_merge_recursive).
     * Recursive merging will be conducted if both arrays have an element of array
     * type and are having the same key.
     * For integer-keyed elements, the elements from the latter array will
     * be appended to the former array.
     * You can use [[UnsetArrayValue]] object to unset value from previous array or
     * [[ReplaceArrayValue]] to force replace former value instead of recursive merging.
     * @param array $a array to be merged to
     * @param array $b array to be merged from. You can specify additional
     * arrays via third argument, fourth argument etc.
     * @return array the merged array (the original arrays are not changed.)
     * @see \Reaction\Helpers\ArrayHelper::merge()
     */
    public function merge($a, $b)
    {
        return $this->proxy(__FUNCTION__, func_get_args());
    }

    /**
     * Retrieves the value of an array element or object property with the given key or property name.
     * If the key does not exist in the array or object, the default value will be returned instead.
     *
     * The key may be specified in a dot format to retrieve the value of a sub-array or the property
     * of an embedded object. In particular, if the key is `x.y.z`, then the returned value would
     * be `$array['x']['y']['z']` or `$array->x->y->z` (if `$array` is an object). If `$array['x']`
     * or `$array->x` is neither an array nor an object, the default value will be returned.
     * Note that if the array already has an element `x.y.z`, then its value will be returned
     * instead of going through the sub-arrays. So it is better to be done specifying an array of key names
     * like `['x', 'y', 'z']`.
     *
     * Below are some usage examples,
     *
     * ```php
     * // working with array
     * $username = \Reaction\Helpers\ArrayHelper::getValue($_POST, 'username');
     * // working with object
     * $username = \Reaction\Helpers\ArrayHelper::getValue($user, 'username');
     * // working with anonymous function
     * $fullName = \Reaction\Helpers\ArrayHelper::getValue($user, function ($user, $defaultValue) {
     *     return $user->firstName . ' ' . $user->lastName;
     * });
     * // using dot format to retrieve the property of embedded object
     * $street = \Reaction\Helpers\ArrayHelper::getValue($users, 'address.street');
     * // using an array of keys to retrieve the value
     * $value = \Reaction\Helpers\ArrayHelper::getValue($versions, ['1.0', 'date']);
     * ```
     *
     * @param array|object $array array or object to extract value from
     * @param string|\Closure|array $key key name of the array element, an array of keys or property name of the object,
     * or an anonymous function returning the value. The anonymous function signature should be:
     * `function($array, $defaultValue)`.
     * The possibility to pass an array of keys is available since version 2.0.4.
     * @param mixed $default the default value to be returned if the specified array key does not exist. Not used when
     * getting value from an object.
     * @return mixed the value of the element if found, default value otherwise
     * @see \Reaction\Helpers\ArrayHelper::getValue()
     */
    public function getValue($array, $key, $default = null)
    {
        return $this->proxy(__FUNCTION__, [$array, $key, $default]);
    }

    /**
     * Writes a value into an associative array at the key path specified.
     * If there is no such key path yet, it will be created recursively.
     * If the key exists, it will be overwritten.
     *
     * ```php
     *  $array = [
     *      'key' => [
     *          'in' => [
     *              'val1',
     *              'key' => 'val'
     *          ]
     *      ]
     *  ];
     * ```
     *
     * The result of `ArrayHelper::setValue($array, 'key.in.0', ['arr' => 'val']);` will be the following:
     *
     * ```php
     *  [
     *      'key' => [
     *          'in' => [
     *              ['arr' => 'val'],
     *              'key' => 'val'
     *          ]
     *      ]
     *  ]
     *
     * ```
     *
     * The result of
     * `ArrayHelper::setValue($array, 'key.in', ['arr' => 'val']);` or
     * `ArrayHelper::setValue($array, ['key', 'in'], ['arr' => 'val']);`
     * will be the following:
     *
     * ```php
     *  [
     *      'key' => [
     *          'in' => [
     *              'arr' => 'val'
     *          ]
     *      ]
     *  ]
     * ```
     *
     * @param array $array the array to write the value to
     * @param string|array|null $path the path of where do you want to write a value to `$array`
     * the path can be described by a string when each key should be separated by a dot
     * you can also describe the path as an array of keys
     * if the path is null then `$array` will be assigned the `$value`
     * @param mixed $value the value to be written
     * @see \Reaction\Helpers\ArrayHelper::setValue()
     */
    public function setValue(&$array, $path, $value)
    {
        $this->proxy(__FUNCTION__, [&$array, $path, $value]);
    }

    /**
     * Removes an item from an array and returns the value. If the key does not exist in the array, the default value
     * will be returned instead.
     *
     * Usage examples,
     *
     * ```php
     * // $array = ['type' => 'A', 'options' => [1, 2]];
     * // working with array
     * $type = \Reaction\Helpers\ArrayHelper::remove($array, 'type');
     * // $array content
     * // $array = ['options' => [1, 2]];
     * ```
     *
     * @param array $array the array to extract value from
     * @param string $key key name of the array element
     * @param mixed $default the default value to be returned if the specified key does not exist
     * @return mixed|null the value of the element if found, default value otherwise
     * @see \Reaction\Helpers\ArrayHelper::remove()
     */
    public function remove(&$array, $key, $default = null)
    {
        return $this->proxy(__FUNCTION__, [&$array, $key, $default]);
    }

    /**
     * Removes items with matching values from the array and returns the removed items.
     *
     * Example,
     *
     * ```php
     * $array = ['Bob' => 'Dylan', 'Michael' => 'Jackson', 'Mick' => 'Jagger', 'Janet' => 'Jackson'];
     * $removed = \Reaction\Helpers\ArrayHelper::removeValue($array, 'Jackson');
     * // result:
     * // $array = ['Bob' => 'Dylan', 'Mick' => 'Jagger'];
     * // $removed = ['Michael' => 'Jackson', 'Janet' => 'Jackson'];
     * ```
     *
     * @param array $array the array where to look the value from
     * @param string $value the value to remove from the array
     * @return array the items that were removed from the array
     * @see \Reaction\Helpers\ArrayHelper::removeValue()
     */
    public function removeValue(&$array, $value)
    {
        return $this->proxy(__FUNCTION__, [&$array, $value]);
    }

    /**
     * Indexes and/or groups the array according to a specified key.
     * The input should be either multidimensional array or an array of objects.
     *
     * The $key can be either a key name of the sub-array, a property name of object, or an anonymous
     * function that must return the value that will be used as a key.
     *
     * $groups is an array of keys, that will be used to group the input array into one or more sub-arrays based
     * on keys specified.
     *
     * If the `$key` is specified as `null` or a value of an element corresponding to the key is `null` in addition
     * to `$groups` not specified then the element is discarded.
     *
     * For example:
     *
     * ```php
     * $array = [
     *     ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
     *     ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
     *     ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
     * ];
     * $result = ArrayHelper::index($array, 'id');
     * ```
     *
     * The result will be an associative array, where the key is the value of `id` attribute
     *
     * ```php
     * [
     *     '123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
     *     '345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
     *     // The second element of an original array is overwritten by the last element because of the same id
     * ]
     * ```
     *
     * An anonymous function can be used in the grouping array as well.
     *
     * ```php
     * $result = ArrayHelper::index($array, function ($element) {
     *     return $element['id'];
     * });
     * ```
     *
     * Passing `id` as a third argument will group `$array` by `id`:
     *
     * ```php
     * $result = ArrayHelper::index($array, null, 'id');
     * ```
     *
     * The result will be a multidimensional array grouped by `id` on the first level, by `device` on the second level
     * and indexed by `data` on the third level:
     *
     * ```php
     * [
     *     '123' => [
     *         ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
     *     ],
     *     '345' => [ // all elements with this index are present in the result array
     *         ['id' => '345', 'data' => 'def', 'device' => 'tablet'],
     *         ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
     *     ]
     * ]
     * ```
     *
     * The anonymous function can be used in the array of grouping keys as well:
     *
     * ```php
     * $result = ArrayHelper::index($array, 'data', [function ($element) {
     *     return $element['id'];
     * }, 'device']);
     * ```
     *
     * The result will be a multidimensional array grouped by `id` on the first level, by the `device` on the second one
     * and indexed by the `data` on the third level:
     *
     * ```php
     * [
     *     '123' => [
     *         'laptop' => [
     *             'abc' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
     *         ]
     *     ],
     *     '345' => [
     *         'tablet' => [
     *             'def' => ['id' => '345', 'data' => 'def', 'device' => 'tablet']
     *         ],
     *         'smartphone' => [
     *             'hgi' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
     *         ]
     *     ]
     * ]
     * ```
     *
     * @param array $array the array that needs to be indexed or grouped
     * @param string|\Closure|null $key the column name or anonymous function which result will be used to index the array
     * @param string|string[]|\Closure[]|null $groups the array of keys, that will be used to group the input array
     * by one or more keys. If the $key attribute or its value for the particular element is null and $groups is not
     * defined, the array element will be discarded. Otherwise, if $groups is specified, array element will be added
     * to the result array without any key.
     * @return array the indexed and/or grouped array
     * @see \Reaction\Helpers\ArrayHelper::index()
     */
    public function index($array, $key, $groups = [])
    {
        return $this->proxy(__FUNCTION__, [$array, $key, $groups]);
    }

    /**
     * Returns the values of a specified column in an array.
     * The input array should be multidimensional or an array of objects.
     *
     * For example,
     *
     * ```php
     * $array = [
     *     ['id' => '123', 'data' => 'abc'],
     *     ['id' => '345', 'data' => 'def'],
     * ];
     * $result = ArrayHelper::getColumn($array, 'id');
     * // the result is: ['123', '345']
     *
     * // using anonymous function
     * $result = ArrayHelper::getColumn($array, function ($element) {
     *     return $element['id'];
     * });
     * ```
     *
     * @param array $array
     * @param string|\Closure $name
     * @param bool $keepKeys whether to maintain the array keys. If false, the resulting array
     * will be re-indexed with integers.
     * @return array the list of column values
     * @see \Reaction\Helpers\ArrayHelper::getColumn()
     */
    public function getColumn($array, $name, $keepKeys = true)
    {
        return $this->proxy(__FUNCTION__, [$array, $name, $keepKeys]);
    }

    /**
     * Builds a map (key-value pairs) from a multidimensional array or an array of objects.
     * The `$from` and `$to` parameters specify the key names or property names to set up the map.
     * Optionally, one can further group the map according to a grouping field `$group`.
     *
     * For example,
     *
     * ```php
     * $array = [
     *     ['id' => '123', 'name' => 'aaa', 'class' => 'x'],
     *     ['id' => '124', 'name' => 'bbb', 'class' => 'x'],
     *     ['id' => '345', 'name' => 'ccc', 'class' => 'y'],
     * ];
     *
     * $result = ArrayHelper::map($array, 'id', 'name');
     * // the result is:
     * // [
     * //     '123' => 'aaa',
     * //     '124' => 'bbb',
     * //     '345' => 'ccc',
     * // ]
     *
     * $result = ArrayHelper::map($array, 'id', 'name', 'class');
     * // the result is:
     * // [
     * //     'x' => [
     * //         '123' => 'aaa',
     * //         '124' => 'bbb',
     * //     ],
     * //     'y' => [
     * //         '345' => 'ccc',
     * //     ],
     * // ]
     * ```
     *
     * @param array $array
     * @param string|\Closure $from
     * @param string|\Closure $to
     * @param string|\Closure $group
     * @return array
     * @see \Reaction\Helpers\ArrayHelper::map()
     */
    public function map($array, $from, $to, $group = null)
    {
        return $this->proxy(__FUNCTION__, [$array, $from, $to, $group]);
    }

    /**
     * Checks if the given array contains the specified key.
     * This method enhances the `array_key_exists()` function by supporting case-insensitive
     * key comparison.
     * @param string $key the key to check
     * @param array $array the array with keys to check
     * @param bool $caseSensitive whether the key comparison should be case-sensitive
     * @return bool whether the array contains the specified key
     * @see \Reaction\Helpers\ArrayHelper::keyExists()
     */
    public function keyExists($key, $array, $caseSensitive = true)
    {
        return $this->proxy(__FUNCTION__, [$key, $array, $caseSensitive]);
    }

    /**
     * Sorts an array of objects or arrays (with the same structure) by one or several keys.
     * @param array $array the array to be sorted. The array will be modified after calling this method.
     * @param string|\Closure|array $key the key(s) to be sorted by. This refers to a key name of the sub-array
     * elements, a property name of the objects, or an anonymous function returning the values for comparison
     * purpose. The anonymous function signature should be: `function($item)`.
     * To sort by multiple keys, provide an array of keys here.
     * @param int|array $direction the sorting direction. It can be either `SORT_ASC` or `SORT_DESC`.
     * When sorting by multiple keys with different sorting directions, use an array of sorting directions.
     * @param int|array $sortFlag the PHP sort flag. Valid values include
     * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, `SORT_LOCALE_STRING`, `SORT_NATURAL` and `SORT_FLAG_CASE`.
     * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php)
     * for more details. When sorting by multiple keys with different sort flags, use an array of sort flags.
     * @throws InvalidArgumentException if the $direction or $sortFlag parameters do not have
     * correct number of elements as that of $key.
     * @see \Reaction\Helpers\ArrayHelper::multisort()
     */
    public function multisort(&$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR)
    {
        $this->proxy(__FUNCTION__, [&$array, $key, $direction, $sortFlag]);
    }

    /**
     * Encodes special characters in an array of strings into HTML entities.
     * Only array values will be encoded by default.
     * If a value is an array, this method will also encode it recursively.
     * Only string values will be encoded.
     * @param array $data data to be encoded
     * @param bool $valuesOnly whether to encode array values only. If false,
     * both the array keys and array values will be encoded.
     * @param string $charset the charset that the data is using. If not set,
     * [[\app\run\Application::charset]] will be used.
     * @return array the encoded data
     * @see http://www.php.net/manual/en/function.htmlspecialchars.php
     * @see \Reaction\Helpers\ArrayHelper::htmlEncode()
     */
    public function htmlEncode($data, $valuesOnly = true, $charset = null)
    {
        return $this->proxyWithCharset(__FUNCTION__, [$data, $valuesOnly, $charset]);
    }

    /**
     * Decodes HTML entities into the corresponding characters in an array of strings.
     * Only array values will be decoded by default.
     * If a value is an array, this method will also decode it recursively.
     * Only string values will be decoded.
     * @param array $data data to be decoded
     * @param bool $valuesOnly whether to decode array values only. If false,
     * both the array keys and array values will be decoded.
     * @return array the decoded data
     * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
     * @see \Reaction\Helpers\ArrayHelper::htmlDecode()
     */
    public function htmlDecode($data, $valuesOnly = true)
    {
        return $this->proxy(__FUNCTION__, [$data, $valuesOnly]);
    }

    /**
     * Returns a value indicating whether the given array is an associative array.
     *
     * An array is associative if all its keys are strings. If `$allStrings` is false,
     * then an array will be treated as associative if at least one of its keys is a string.
     *
     * Note that an empty array will NOT be considered associative.
     *
     * @param array $array the array being checked
     * @param bool $allStrings whether the array keys must be all strings in order for
     * the array to be treated as associative.
     * @return bool whether the array is associative
     * @see \Reaction\Helpers\ArrayHelper::isAssociative()
     */
    public function isAssociative($array, $allStrings = true)
    {
        return $this->proxy(__FUNCTION__, [$array, $allStrings]);
    }

    /**
     * Returns a value indicating whether the given array is an indexed array.
     *
     * An array is indexed if all its keys are integers. If `$consecutive` is true,
     * then the array keys must be a consecutive sequence starting from 0.
     *
     * Note that an empty array will be considered indexed.
     *
     * @param array $array the array being checked
     * @param bool $consecutive whether the array keys must be a consecutive sequence
     * in order for the array to be treated as indexed.
     * @return bool whether the array is indexed
     * @see \Reaction\Helpers\ArrayHelper::isIndexed()
     */
    public function isIndexed($array, $consecutive)
    {
        return $this->proxy(__FUNCTION__, [$array, $consecutive]);
    }

    /**
     * Check whether an array or [[\Traversable]] contains an element.
     *
     * This method does the same as the PHP function [in_array()](http://php.net/manual/en/function.in-array.php)
     * but additionally works for objects that implement the [[\Traversable]] interface.
     * @param mixed $needle The value to look for.
     * @param array|\Traversable $haystack The set of values to search.
     * @param bool $strict Whether to enable strict (`===`) comparison.
     * @return bool `true` if `$needle` was found in `$haystack`, `false` otherwise.
     * @throws InvalidArgumentException if `$haystack` is neither traversable nor an array.
     * @see http://php.net/manual/en/function.in-array.php
     * @see \Reaction\Helpers\ArrayHelper::isIn()
     */
    public function isIn($needle, $haystack, $strict = false)
    {
        return $this->proxy(__FUNCTION__, [$needle, $haystack, $strict]);
    }

    /**
     * Checks whether a variable is an array or [[\Traversable]].
     *
     * This method does the same as the PHP function [is_array()](http://php.net/manual/en/function.is-array.php)
     * but additionally works on objects that implement the [[\Traversable]] interface.
     * @param mixed $var The variable being evaluated.
     * @return bool whether $var is array-like
     * @see http://php.net/manual/en/function.is-array.php
     * @see \Reaction\Helpers\ArrayHelper::isTraversable()
     */
    public function isTraversable($var)
    {
        return $this->proxy(__FUNCTION__, [$var]);
    }

    /**
     * Checks whether an array or [[\Traversable]] is a subset of another array or [[\Traversable]].
     *
     * This method will return `true`, if all elements of `$needles` are contained in
     * `$haystack`. If at least one element is missing, `false` will be returned.
     * @param array|\Traversable $needles The values that must **all** be in `$haystack`.
     * @param array|\Traversable $haystack The set of value to search.
     * @param bool $strict Whether to enable strict (`===`) comparison.
     * @throws InvalidArgumentException if `$haystack` or `$needles` is neither traversable nor an array.
     * @return bool `true` if `$needles` is a subset of `$haystack`, `false` otherwise.
     * @see \Reaction\Helpers\ArrayHelper::isSubset()
     */
    public function isSubset($needles, $haystack, $strict = false)
    {
        return $this->proxy(__FUNCTION__, [$needles, $haystack, $strict]);
    }

    /**
     * Filters array according to rules specified.
     *
     * For example:
     *
     * ```php
     * $array = [
     *     'A' => [1, 2],
     *     'B' => [
     *         'C' => 1,
     *         'D' => 2,
     *     ],
     *     'E' => 1,
     * ];
     *
     * $result = \Reaction\Helpers\ArrayHelper::filter($array, ['A']);
     * // $result will be:
     * // [
     * //     'A' => [1, 2],
     * // ]
     *
     * $result = \Reaction\Helpers\ArrayHelper::filter($array, ['A', 'B.C']);
     * // $result will be:
     * // [
     * //     'A' => [1, 2],
     * //     'B' => ['C' => 1],
     * // ]
     *
     * $result = \Reaction\Helpers\ArrayHelper::filter($array, ['B', '!B.C']);
     * // $result will be:
     * // [
     * //     'B' => ['D' => 2],
     * // ]
     * ```
     *
     * @param array $array Source array
     * @param array $filters Rules that define array keys which should be left or removed from results.
     * Each rule is:
     * - `var` - `$array['var']` will be left in result.
     * - `var.key` = only `$array['var']['key'] will be left in result.
     * - `!var.key` = `$array['var']['key'] will be removed from result.
     * @return array Filtered array
     * @see \Reaction\Helpers\ArrayHelper::filter()
     */
    public function filter($array, $filters)
    {
        return $this->proxy(__FUNCTION__, [$array, $filters]);
    }
}


<?php

/*
 * This file is part of the Crowdin library.
 *
 * (c) Julien Janvier
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Jjanvier\Library\Crowdin\Archive;

use Jjanvier\Library\Crowdin\Formatter\FormatterFactory;
use \SplFileInfo;

class Archive implements ArchiveInterface
{
    /**
     * @var array|\SplFileInfo
     */
    protected $files;

    /**
     * @var string path of the archive
     */
    protected $path;

    /**
     * @var string filename of the archive
     */
    protected $filename;

    /**
     * @var string path where the archive will be extracted
     */
    protected $extractPath;

    /**
     * @var bool tell if files of the archive should be cleaned after extraction
     */
    protected $clean;

    /**
     * @var string header to add to the files of the archive
     */
    protected $header;

    /**
     * Constructor
     *
     * @param string $path
     * @param string $extractPath
     * @param bool   $clean
     * @param string $header
     */
    public function __construct($path, $extractPath, $clean = false, $header = null)
    {
        $this->files = array();
        $this->path = realpath($path);
        $this->extractPath = realpath($extractPath);
        $this->header = $header;
        $this->clean = $clean;
    }

    /**
     * {@inheritdoc}
     */
    public function extract()
    {
        if (false === realpath($this->path)) {
            throw new \Exception(sprintf('Please provide a valid path instead of %s.', $this->path));
        }
        if (false === realpath($this->extractPath)) {
            throw new \Exception(sprintf('Please provide a valid path instead of %s.', $this->extractPath));
        }

        $zip = new \ZipArchive();

        if (null === $this->filename) {
            throw new \Exception('Impossible to extract an archive without a filename.');
        }

        $archive = sprintf('%s/%s', $this->path, $this->filename);
        if (true !== $zip->open($archive)) {
            throw new \Exception(sprintf('Impossible to open the archive %s.', $archive));
        }

        $zip->extractTo($this->extractPath);

        for ($i = 0; $i < $zip->numFiles; $i++) {
            $path = sprintf('%s/%s', $this->extractPath, $zip->getNameIndex($i));

            if (is_file($path)) {
                $this->files[] = new SplFileInfo($path);
            }
        }

        $zip->close();
        $this->cleanAndAddHeader();

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function remove()
    {
        if (null === $this->filename) {
            throw new \Exception('Impossible to remove an archive without a filename.');
        }

        unlink(sprintf('%s/%s', $this->path, $this->filename));

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getFiles()
    {
        return $this->files;
    }

    /**
     * {@inheritdoc}
     */
    public function getExtractPath()
    {
        return $this->extractPath;
    }

    /**
     * {@inheritdoc}
     */
    public function setExtractPath($extractPath)
    {
        $this->extractPath = $extractPath;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * {@inheritdoc}
     */
    public function setPath($path)
    {
        $this->path = $path;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function getFilename()
    {
        return $this->filename;
    }

    /**
     * Clean Crowdin translations and add a header
     */
    protected function cleanAndAddHeader()
    {
        if (true === $this->clean || null !== $this->header) {
            foreach ($this->files as $translation) {
                $formatter = FormatterFactory::getInstance($translation);

                if ($this->clean) {
                    $formatter->clean($translation);
                }

                if ($this->header) {
                    $formatter->addHeader($translation, $this->header);
                }
            }
        }
    }
}


<?php

namespace Oxygen\Data;

use Doctrine\ORM\EntityManager;
use Illuminate\Support\ServiceProvider;
use Oxygen\Data\Cache\CacheSettingsRepositoryInterface;
use Oxygen\Data\Cache\StubCacheSettingsRepository;
use Oxygen\Data\Pagination\Laravel\LaravelPaginationService;
use Oxygen\Data\Pagination\PaginationService;
use Oxygen\Data\Cache\CacheInvalidationSubscriber;
use Oxygen\Data\Validation\Laravel\LaravelValidationService;
use Oxygen\Data\Validation\ValidationSubscriber;

class DataServiceProvider extends BaseServiceProvider {

    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register() {
        $this->app->bind(PaginationService::class, LaravelPaginationService::class);

        $this->extendEntityManager(function($entities) {
            $entities->getEventManager()
                     ->addEventSubscriber(new ValidationSubscriber(new LaravelValidationService($this->app['validator'])));
            $entities->getEventManager()
                     ->addEventSubscriber(new CacheInvalidationSubscriber($this->app['events'], $this->app[CacheSettingsRepositoryInterface::class], $this->app['log']));
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides() {
        return [
            EntityManager::class,
            PaginationService::class
        ];
    }

}


<?php
declare(strict_types=1);

namespace icePHP;
/**
 * 跨页显示消息,通过Session保存
 * @author Ice
 *
 */
class Message
{
    //保存错误消息的SESSION,Key
    const ERROR = 'ICE_MESSAGE_ERROR';

    //保存成功消息的SESSION,Key
    const SUCCESS = 'ICE_MESSAGE_SUCCESS';

    //保存提示消息的SESSION,Key
    const INFORMATION = 'ICE_MESSAGE_INFO';

    //禁止实例化
    private function __construct()
    {
    }

    /**
     * 记录一条错误消息
     * @param string $err
     */
    static public function setError(string $err): void
    {
        $_SESSION[self::ERROR][] = $err;
    }

    /**
     * 记录一条成功消息
     * @param string $msg
     */
    static public function setSuccess(string $msg): void
    {
        $_SESSION[self::SUCCESS][] = $msg;
    }

    /**
     * 记录一条提示消息
     * @param string $info
     */
    static public function setInfo(string $info): void
    {
        $_SESSION[self::INFORMATION][] = $info;
    }

    /**
     * 获取所有错误消息
     * @return array
     */
    static public function getErrors(): array
    {
        //空
        if (!isset($_SESSION[self::ERROR])) {
            return [];
        }

        //用BR拼接
        $ret = $_SESSION[self::ERROR];

        //取出即销毁,下次就没了
        unset($_SESSION[self::ERROR]);
        return $ret;
    }

    /**
     * 取出所有成功的消息
     * @return array
     */
    static public function getSuccesses(): array
    {
        //空
        if (!isset($_SESSION[self::SUCCESS])) {
            return [];
        }

        //结果
        $ret = $_SESSION[self::SUCCESS];

        //销毁
        unset($_SESSION[self::SUCCESS]);
        return $ret;
    }

    /**
     * 取出所有提示消息
     * @return array
     */
    static public function getInfos(): array
    {
        //空
        if (!isset($_SESSION[self::INFORMATION])) {
            return [];
        }

        $ret = $_SESSION[self::INFORMATION];

        //销毁
        unset($_SESSION[self::INFORMATION]);
        return $ret;
    }

    /**
     * 检查是否有消息,任何类型
     * @return boolean
     */
    static public function has(): bool
    {
        return self::hasError() || self::hasInfo() || self::hasSuccess();
    }

    /**
     * 获取所有消息,任何类型
     * @return array
     */
    static public function getAll(): array
    {
        return array_merge(self::getErrors(), self::getInfos(), self::getSuccesses());
    }

    /**
     * 检查有没有错误消息
     * @return boolean
     */
    static public function hasError(): bool
    {
        if (!isset($_SESSION[self::ERROR])) {
            return false;
        }
        return count($_SESSION[self::ERROR]) > 0;
    }

    /**
     * 检查有没有成功消息
     * @return boolean
     */
    static public function hasSuccess(): bool
    {
        if (!isset($_SESSION[self::SUCCESS])) {
            return false;
        }
        return count($_SESSION[self::SUCCESS]) > 0;
    }

    /**
     * 检查有没有提示消息
     * @return boolean
     */
    static public function hasInfo(): bool
    {
        if (!isset($_SESSION[self::INFORMATION])) {
            return false;
        }
        return count($_SESSION[self::INFORMATION]) > 0;
    }
}


<?php

namespace Reaction\Helpers;

/**
 * Class ClassFinder
 * @package Reaction\Helpers
 */
class ClassFinderHelper
{
    const DS = DIRECTORY_SEPARATOR; //Directory separator
    const CS = '\\';                //Class namespace separator

    protected static $_loader;

    /**
     * Find class names inside given namespace
     * @param string|array $namespace
     * @param bool         $recursively Search recursively is namespace directory
     * @param bool         $withoutAutoload Do not check class names through 'class_exist(name, true)'
     * @return array
     */
    public static function findClassesPsr4($namespace, $recursively = false, $withoutAutoload = false) {
        $classNames = [];
        if(is_array($namespace)) {
            foreach ($namespace as $ns) {
                $classNames = ArrayHelper::merge($classNames, static::findClassesPsr4($ns, $recursively, $withoutAutoload));
            }
            return $classNames;
        }
        $namespace = trim($namespace, static::CS);
        list($nsPrefix, $namespacePaths) = static::getNamespacePaths($namespace);
        if (empty($namespacePaths)) {
            return [];
        }
        $files = [];
        $regEx = '/\.php$/';
        for ($i = 0; $i < count($namespacePaths); $i++) {
            $dir = $namespacePaths[$i];
            $dirIt = new \RecursiveDirectoryIterator($dir);
            $files = [];
            if($recursively) {
                foreach(new \RecursiveIteratorIterator($dirIt) as $file)
                {
                    $fileStr = (string)$file;
                    if (!preg_match($regEx, $fileStr)) {
                        continue;
                    }
                    $fileStr = substr($fileStr, strlen($dir) + 1, -4);
                    $files[] = $fileStr;
                }
            } else {
                $_files = glob($dir . static::DS . '*.php');
                for ($j = 0; $j < count($_files); $j++) {
                    $fileStr = $_files[$j];
                    $fileStr = substr($fileStr, strlen($dir) + 1, -4);
                    $files[] = $fileStr;
                }
            }
        }

        for ($i = 0; $i < count($files); $i++) {
            $fileStr = $files[$i];
            $className = $namespace . static::CS . str_replace(static::DS, static::CS, $fileStr);
            if ($withoutAutoload || class_exists($className, true)) {
                $classNames[] = $className;
            }
        }
        return $classNames;
    }

    /**
     * Get namespace directory path
     * @param string $namespace
     * @param bool $first
     * @return array|mixed|null|string
     */
    public static function getNamespacePath($namespace, $first = true)
    {
        $namespace = trim($namespace, static::CS);
        $nsPrefixes = static::getNamespacePrefixes($namespace);
        $loaderPrefixes = static::getLoaderPrefixes();
        $nsSuffix = '';
        foreach ($nsPrefixes as $prefix) {
            if (!isset($loaderPrefixes[$prefix])) {
                continue;
            }
            $nsSuffix = trim(mb_substr($namespace, mb_strlen($prefix)), static::CS);
            $paths = $loaderPrefixes[$prefix];
            break;
        }
        if (!isset($paths)) {
            return $first ? null : [];
        }
        $results = [];
        foreach ($paths as $path) {
            $result = $path . static::DS . str_replace('\\', static::DS, $nsSuffix);
            if (!file_exists($result) || !is_dir($result)) {
                continue;
            }
            if ($first) {
                return $result;
            }
            $results[] = $result;
        }
        return $results;
    }

    /**
     * Get possible namespace paths
     * @param string $namespace
     * @return array|mixed
     */
    protected static function getNamespacePaths($namespace) {
        $paths = [];
        $namespace = trim($namespace, static::CS);
        $nsPrefixes = static::getNamespacePrefixes($namespace);
        $nsPrefixesCount = count($nsPrefixes);
        $loaderPrefixes = static::getLoaderPrefixes();
        $nsPrefix = null;
        for ($i = 0; $i < $nsPrefixesCount; $i++) {
            $nsPrefix = $nsPrefixes[$i];
            if (!isset($loaderPrefixes[$nsPrefix])) {
                continue;
            }
            if ($nsPrefix === $namespace) {
                return $loaderPrefixes[$nsPrefix];
            }
            $nsSuffix = trim(substr($namespace, strlen($nsPrefix)), static::CS);
            $nsSuffix = str_replace(static::CS, static::DS, $nsSuffix);
            $loaderPaths = $loaderPrefixes[$nsPrefix];
            $loaderPathsCount = count($loaderPaths);
            for ($j = 0; $j < $loaderPathsCount; $j++) {
                $possiblePath = $loaderPaths[$j] . static::DS . $nsSuffix;
                if(file_exists($possiblePath) && is_dir($possiblePath)) { $paths[] = $possiblePath; }
            }
            if (!empty($paths)) {
                break;
            }
        }
        if (empty($paths)) {
            return [null, []];
        }

        return [$nsPrefix, $paths];
    }

    /**
     * Explode namespace to possible prefixes
     * @param string $namespace
     * @return array
     */
    protected static function getNamespacePrefixes($namespace) {
        $namespaceExp = explode(static::CS, trim($namespace, static::CS));
        $namespaceExpCount = count($namespaceExp);
        if ($namespaceExpCount === 1) {
            return $namespaceExp;
        }
        $prefixes = [];
        $currPrefix = '';
        for ($i = 0; $i < $namespaceExpCount; $i++) {
            $currPrefix .= static::CS . $namespaceExp[$i];
            $prefixes[] = trim($currPrefix, static::CS);
        }
        $prefixes = array_reverse($prefixes);
        return $prefixes;
    }

    /**
     * Get prefixes from loader
     * @return array
     */
    protected static function getLoaderPrefixes() {
        $loader = static::getLoader();
        $_prefixes = [
            [],
            $loader->getPrefixesPsr4(),
        ];
        $_prefixes = ArrayHelper::merge(...$_prefixes);
        $prefixes = [];
        foreach ($_prefixes as $prefix => $paths) {
            $prefix = trim($prefix, '\\');
            $_paths = [];
            for ($i = 0; $i < count($paths); $i++) { $_paths[] = realpath($paths[$i]); }
            $prefixes[$prefix] = $_paths;
        }
        return $prefixes;
    }

    /**
     * Get class loader
     * @return \Composer\Autoload\ClassLoader
     */
    protected static function getLoader() {
        if (!isset(static::$_loader)) {
            static::$_loader = \Reaction::$composer;
        }
        return static::$_loader;
    }

    /**
     * Set loader (composer)
     * @param \Composer\Autoload\ClassLoader $loader
     */
    public static function setLoader($loader)
    {
        static::$_loader = $loader;
    }
}


<?php

namespace Behavior;

use Think\Behavior;

/**
 * 页面Trace显示输出
 */
class ShowPageTraceBehavior extends Behavior
{
    protected $tracePageTabs = [
        'BASE'      => '基本',
        'FILE'      => '文件',
        'INFO'      => '流程',
        'ERR|NOTIC' => '错误',
        'SQL'       => 'SQL',
        'DEBUG'     => '调试',
    ];

    /**
     * 执行入口
     *
     * @param mixed $params
     */
    public function run(&$params)
    {
        if (!IS_AJAX && !IS_CLI && C('SHOW_PAGE_TRACE')) {
            echo $this->_showTrace();
        }
    }

    /**
     * 显示页面Trace信息

     */
    private function _showTrace()
    {
        // 系统默认显示信息
        $files = get_included_files();
        $info = [];
        foreach ($files as $file) {
            $info[] = $file.' ( '.number_format(filesize($file) / 1024, 2).' KB )';
        }
        $trace = [];
        $base = [
            '请求信息' => date(
                    'Y-m-d H:i:s',
                    $_SERVER['REQUEST_TIME']
                ).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__,
            '运行时间' => $this->showTime(),
            '吞吐率'  => number_format(1 / G('beginTime', 'viewEndTime'), 2).'req/s',
            '内存开销' => MEMORY_LIMIT_ON ? number_format(
                    (memory_get_usage() - $GLOBALS['_startUseMems']) / 1024,
                    2
                ).' kb' : '不支持',
//                '查询信息' => N('db_query') . ' queries ' . N('db_write') . ' writes ',
            '文件加载' => count(get_included_files()),
//                '缓存信息' => N('cache_read') . ' gets ' . N('cache_write') . ' writes ',
            '配置加载' => count(C()),
            '会话信息' => 'SESSION_ID='.session_id(),
        ];
        // 读取应用定义的Trace文件
        $traceFile = COMMON_PATH.'Conf/trace.php';
        if (is_file($traceFile)) {
            /** @noinspection PhpIncludeInspection */
            $base = array_merge($base, include $traceFile);
        }
        $debug = trace();
        $tabs = C('TRACE_PAGE_TABS', null, $this->tracePageTabs);
        foreach ($tabs as $name => $title) {
            switch (strtoupper($name)) {
                // 基本信息
                case 'BASE':
                    $trace[$title] = $base;
                    break;
                // 文件信息
                case 'FILE':
                    $trace[$title] = $info;
                    break;
                // 调试信息
                default:
                    $name = strtoupper($name);
                    // 多组信息
                    if (strpos($name, '|')) {
                        $names = explode('|', $name);
                        $result = [];
                        foreach ($names as $name) {
                            $result += isset($debug[$name]) ? $debug[$name] : [];
                        }
                        $trace[$title] = $result;
                    } else {
                        $trace[$title] = isset($debug[$name]) ? $debug[$name] : '';
                    }
            }
        }
        unset($files, $info, $base);
        // 调用Trace页面模板
        ob_start();
        /** @noinspection PhpIncludeInspection */
        include C('TMPL_TRACE_FILE') ? C('TMPL_TRACE_FILE') : __DIR__.'/../Resources/page_trace.tpl';

        return ob_get_clean();
    }

    /**
     * 获取运行时间
     */
    private function showTime()
    {
        // 显示运行时间
        G('beginTime', $GLOBALS['_beginTime']);
        G('viewEndTime');

        // 显示详细运行时间
        return G('beginTime', 'viewEndTime').'s ( Load:'.G('beginTime', 'loadTime').'s Init:'.G(
                'loadTime',
                'initTime'
            ).'s Exec:'.G('initTime', 'viewStartTime').'s Template:'.G('viewStartTime', 'viewEndTime').'s )';
    }
}


<?php

/*
 * (c) XM Media Inc. <dhein@xmmedia.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace XM\FilterBundle\Component;

use Doctrine\Common\Collections\ArrayCollection;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

/**
 * Provides a base for a service to help creating a filter form and record list.
 *
 * @author Darryl Hein, XM Media Inc. <dhein@xmmedia.com>
 */
abstract class FilterComponent
{
    /**
     * The block name from the form.
     * Used to generate the query string.
     *
     * @var string
     */
    const FORM_BLOCK_NAME = 'filter';

    /**
     * @var RequestStack
     */
    protected $request;

    /**
     * @var SessionInterface
     */
    protected $session;

    /**
     * @var FormFactoryInterface
     */
    protected $formFactory;

    /**
     * The form object after it's been built.
     *
     * @var \Symfony\Component\Form\FormInterface
     */
    protected $form;

    /**
     * The form type class.
     *
     * @var string
     */
    protected $formType = FormType::class;

    /**
     * @var PaginatorInterface
     */
    protected $paginator;

    /**
     * Where the key for the session storage.
     *
     * @var string
     */
    protected $sessionKey;

    /**
     * The record count per page.
     *
     * @var integer
     */
    protected $pageLimit = 20;

    /**
     * @param RequestStack $requestStack The request stack
     * @param SessionInterface $session
     * @param FormFactoryInterface $formFactory
     * @param PaginatorInterface $paginator
     * @throws \Exception
     */
    public function __construct(
        RequestStack $requestStack,
        SessionInterface $session,
        FormFactoryInterface $formFactory,
        PaginatorInterface $paginator
    ) {
        $this->request = $requestStack->getCurrentRequest();
        $this->session = $session;
        $this->formFactory = $formFactory;
        $this->paginator = $paginator;

        if (!$this->sessionKey) {
            throw new \Exception('The session key must be set');
        }
    }

    /**
     * Returns the default filters.
     *
     * @return array
     */
    abstract public function filterDefaults();

    /**
     * Returns the defaults for the session.
     *
     * @return array
     */
    public function sessionDefaults()
    {
        return [
            'filters' => [],
            'page' => null,
            'ids' => [],
        ];
    }

    /**
     * Sets the key in the session.
     * The filters are merged with the defaults as well as the data for
     * this "filter" in the session.
     */
    public function updateSession()
    {
        $existingSession = $this->getSession();
        if ($this->form) {
            $filters = $this->form->getData() + $this->filterDefaults();
        } else {
            $filters = $this->filterDefaults();
        }

        $currentValues = [
            'filters' => $filters,
            'page' => $this->pageFromQuery(),
        ];

        $newSession = array_merge($this->sessionDefaults(), $existingSession, $currentValues);

        $this->session->set($this->sessionKey, $newSession);
    }

    /**
     * Merges the passed array with the session data and updates the session.
     *
     * @param  array  $newValues The values in the session to replace.
     */
    public function mergeSession(array $newValues)
    {
        $existing = $this->getSession();

        $new = array_merge($existing, $newValues);

        $this->session->set($this->sessionKey, $new);
    }

    /**
     * Gets all or a single key from the session.
     *
     * @param  string $key The session key to retrieve or null for the entire session.
     *
     * @return mixed|null
     */
    public function getSession($key = null)
    {
        // merge the arrays, using the default values if not in the session
        $sessionData = (array) $this->session->get($this->sessionKey) + $this->sessionDefaults();

        if (null === $key) {
            return $sessionData;
        } else if (array_key_exists($key, $sessionData)) {
            return $sessionData[$key];
        } else {
            return null;
        }
    }

    /**
     * Returns the current page from the query.
     * If the page is not set, it will return page 1.
     *
     * @return int
     */
    public function pageFromQuery()
    {
        if ($this->request) {
            $page = $this->request->query->getInt('page');
        } else {
            $page = 0;
        }

        return ($page > 0) ? $page : 1;
    }

    /**
     * Returns the query string based on the filters and page in the session.
     *
     * @return string
     */
    public function query()
    {
        $queryData = [
            self::FORM_BLOCK_NAME => $this->getFiltersAsArray(),
            'page'                => $this->getSession('page'),
        ];

        return http_build_query($queryData);
    }

    /**
     * Retrieves the filters from the session as an array,
     * possibly multi dimensional.
     * It will try to
     *
     * @return array
     */
    protected function getFiltersAsArray()
    {
        $filters = $this->getSession('filters');

        foreach ($filters as $key => $value) {
            if ($value instanceof ArrayCollection) {
                $filters[$key] = $filters[$key]->map(
                    function ($entity) {
                        return $entity->getId();
                    }
                )->toArray();

            } else if (is_array($value)) {
                foreach ($value as $_key => $_value) {
                    if ($this->filterIsEntity($_value)) {
                        $filters[$key][$_key] = $_value->getId();
                    }
                }

            } else if ($this->filterIsEntity($value)) {
                $filters[$key] = $value->getId();
            }
        }

        return $filters;
    }

    /**
     * True when the value is an entity.
     * This means it's an object and has a method `getId()`.
     *
     * @param mixed $value
     *
     * @return bool
     */
    protected function filterIsEntity($value)
    {
        return (is_object($value) && method_exists($value, 'getId'));
    }

    /**
     * Creates the filter form and pulls the filter values from request.
     *
     * @param array $formOptions Options to pass to the form.
     * @return \Symfony\Component\Form\FormInterface
     */
    public function createForm(array $formOptions = [])
    {
        $defaults = $this->filterDefaults();

        $this->form = $this->formFactory->create(
            $this->formType,
            $defaults,
            $formOptions
        );
        if ($this->request) {
            $this->form->handleRequest($this->request);
        }

        return $this->form;
    }

    /**
     * Stores the full list of record IDs in the session.
     *
     * @param  \Doctrine\ORM\QueryBuilder $idOnlyQb The query builder
     *
     * @return void
     */
    public function storeResult($idOnlyQb)
    {
        $result = $idOnlyQb->getQuery()->getArrayResult();

        $resultIds = array_column($result, 'id');

        $this->mergeSession(['ids' => $resultIds]);
    }

    /**
     * Returns the configured KNP Paginator instance.
     *
     * @param  \Doctrine\ORM\Query $query The query
     *
     * @return \Knp\Component\Pager\Pagination\PaginationInterface
     */
    public function getPagination($query)
    {
        $pagination = $this->paginator->paginate(
            $query,
            $this->pageFromQuery(),
            $this->getPageLimit()
        );

        return $pagination;
    }

    /**
     * Finds the previous and next IDs in the record list.
     * Returns an array with the first key as the previous
     * and second key as the next system ID.
     * Either key can be NULL if there is no previous or next.
     *
     * @param  int $currentRecordId The current record ID
     *
     * @return array
     */
    public function prevNext($currentRecordId)
    {
        $recordIds = (array) $this->getSession('ids');
        $prevRecordId = $nextRecordId = null;

        $currentKey = array_search($currentRecordId, $recordIds);
        if (false !== $currentKey) {
            if ($currentKey > 0) {
                $prevRecordId = $recordIds[$currentKey - 1];
            }
            if ($currentKey < count($recordIds) - 1) {
                $nextRecordId = $recordIds[$currentKey + 1];
            }
        }

        return [$prevRecordId, $nextRecordId];
    }

    /**
     * Returns the data from the form.
     *
     * @return array
     */
    public function getFormData()
    {
        return $this->form->getData();
    }

    /**
     * Returns the page limit count.
     *
     * @return int
     */
    public function getPageLimit()
    {
        return $this->pageLimit;
    }
}


<?php
/*
 * Copyright (c) 2013 David Negrier
 *
 * See the file LICENSE.txt for copying permission.
 */

namespace Mouf\Utils\Common\Doctrine\Cache;

use Mouf\Installer\PackageInstallerInterface;
use Mouf\MoufManager;
use Mouf\Actions\InstallUtils;

/**
 * A Mouf installer for the cache system of Doctrine.
 */
class CacheInstaller implements PackageInstallerInterface {

	/**
	 * (non-PHPdoc)
	 * @see \Mouf\Installer\PackageInstallerInterface::install()
	 */
	public static function install(MoufManager $moufManager) {
		// Let's create the instances.
		$cacheInstance = InstallUtils::getOrCreateInstance('defaultDoctrineCache', null, $moufManager);
		$cacheInstance->setCode('// If DEBUG mode is on, let\'s just use an ArrayCache.
if (DEBUG) {
	$driver = new \\Doctrine\\Common\\Cache\\ArrayCache();
} else {
	// If APC is available, let\'s use APC
	if (extension_loaded("apcu")) {
		$driver = new \\Doctrine\\Common\\Cache\\ApcuCache();
	} else if (extension_loaded("apc")) {
		$driver = new \\Doctrine\\Common\\Cache\\ApcCache();
	} else {
		$driver = new \\Doctrine\\Common\\Cache\\PhpFileCache(sys_get_temp_dir().\'/doctrinecache\');
	}
}
$driver->setNamespace(SECRET);
return $driver;
');

		$cacheWrapperInstance = InstallUtils::getOrCreateInstance('doctrineMoufCache', 'Mouf\\Utils\\Common\\Doctrine\\Cache\\DoctrineCacheAdapter', $moufManager);
		$cacheWrapperInstance->getConstructorArgumentProperty('doctrineCache')->setValue($cacheInstance);

		// Let's rewrite the MoufComponents.php file to save the component
		$moufManager->rewriteMouf();
	}
}


<?php
/**
 * This file is part of the CarteBlanche PHP framework.
 *
 * (c) Pierre Cassat <me@e-piwi.fr> and contributors
 *
 * License Apache-2.0 <http://github.com/php-carteblanche/carteblanche/blob/master/LICENSE>
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CarteBlanche\Library\StorageEngine\DatabaseAdapter;

use \CarteBlanche\CarteBlanche;
use \CarteBlanche\App\Kernel;
use \CarteBlanche\Library\StorageEngine\DatabaseAdapter\AbstractDatabaseAdapter;
use \CarteBlanche\Library\StorageEngine\DatabaseAdapter\DatabaseAdapterInterface;
use \Library\Helper\Directory as DirectoryHelper;

/**
 * Database full driver
 *
 * SQLite DataBase driver
 *
 * @author  Piero Wbmstr <me@e-piwi.fr>
 */
class SqliteAdapter extends AbstractDatabaseAdapter implements DatabaseAdapterInterface
{

// ------------------------
// Properties
// ------------------------

    protected $db_name;
    protected $db_options;
    protected $database;
    protected $driver;

// ------------------------
// Construction
// ------------------------

    public function __construct(\CarteBlanche\Library\StorageEngine\Database $database, $db_name, array $db_options = null)
    {
        $container = CarteBlanche::getContainer();
        $db_path = $container->get('kernel')->getPath('db_dir');
        if (empty($db_path)) {
            $db_path = DirectoryHelper::slashDirname($container->get('kernel')->getPath('var_dir'))
                .'db'.DIRECTORY_SEPARATOR;
            $container->get('kernel')->addPath('db_dir', $db_path, true, true);
        }
//			$_altdb = $this->container->get('request')->getUrlArg('altdb');
//			return \AutoObject\AutoObjectMapper::getEntityManager( $_altdb );

        $this->database = $database;
        $this->db_name = $db_name;
        if (!empty($db_options) && is_array($db_options)) {
            $this->db_options = $db_options;
        } else {
            $this->db_options = array();
        }
        $this->db_options['path'] = $db_path;

    //		$this->entity_manager = \CarteBlanche\Library\AutoObject\AutoObjectMapper::getEntityManager('default');
        $this->driver = $this->_buildDriver('sqlite', array(
            $this->database, $this->db_name, $this->db_options
        ));
/*
        $dbname = getContainer()->get('request')->getUrlArg('altdb');
        if (empty($dbname)) $dbname = 'default';
        $dbfile = $this->kernel->registry->getStackEntry('db_name', $dbname.'_db', 'config');
        return new \Lib\Database( _ROOTPATH._DBDIR.$dbfile, 0666 );
*/
    }

// ------------------------
// Connexion
// ------------------------

    /**
     * Is the database installed
     *
     * @return bool
     */
    public function isInstalled($db_name)
    {
        if (empty($dbname)) $dbname='default';
        return file_exists(CarteBlanche::getFullPath('db_dir') . CarteBlanche::getConfig($dbname.'_database.db_name'));
    }

}

// Endfile


<?php

namespace Soluble\Db\Sql;

use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;
use Zend\Db\Sql\Predicate;
use Zend\Db\Sql\Select as ZendDbSqlSelect;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
use Zend\Db\ResultSet\ResultSet;

class Select extends ZendDbSqlSelect implements AdapterAwareInterface
{
    /**
     *
     * @var Adapter
     */
    protected $adapter;

    /**
     * Constructor
     *
     * @param Adapter $adapter
     * @param  null|string|array|\Zend\Db\Sql\TableIdentifier $table
     */
    public function __construct(Adapter $adapter = null, $table = null)
    {
        if ($adapter) {
            $this->setDbAdapter($adapter);
        }
        parent::__construct($table);
    }

    /**
     * Create an where clause with 'OR'
     *
     * @param  \Zend\Db\Sql\Where|\Closure|string|array|Predicate\PredicateInterface $predicate
     * @throws Zend\Db\Sql\Exception\InvalidArgumentException
     * @return Select
     */
    public function orWhere($predicate)
    {
        return $this->where($predicate, Predicate\PredicateSet::OP_OR);
    }

    /**
     * Add table prefixed columns, will automatically
     * quote table parts identifiers found in the column name.
     * It provides an alternative for defining columns from multiple/joined
     * table in one go.
     *
     * <code>
     * $select->from(array('p' =>'product')
     *        ->prefixedColumns(array('product_title' => 'p.title'));
     * </code>
     * Possible valid states:
     *   array(value, ...)
     *     value can be strings or Expression objects
     *
     *   array(string => value, ...)
     *     key string will be use as alias,
     *     value can be string or Expression objects
     *
     * @throws Exception\InvalidArgumentException when usage not correct
     * @param  array $columns
     * @return Select
     */
    public function prefixedColumns(array $columns)
    {
        $pf = $this->adapter->getPlatform();
        $identifierSeparator = $pf->getIdentifierSeparator();
        $names = [];
        $cols = [];
        foreach ($columns as $alias => $column) {
            if (is_string($column)) {
                if (strpos($column, self::SQL_STAR) !== false) {
                    $msg = __METHOD__ . " Invalid argument, prefixedColumn() does not accept sql * column specification";
                    throw new Exception\InvalidArgumentException($msg);
                }
                $parts = explode($identifierSeparator, $column);
                if (count($parts) > 1) {
                    $quotedParts = [];
                    foreach ($parts as $part) {
                        $quotedParts[] = $pf->quoteIdentifier($part);
                    }
                    // to remove PHPAnalyzer warnings
                    //var_dump($quotedParts[count($quotedParts)-1]);
                    //die();
                    $last_part = $parts[count($parts)-1];

                    if (!is_string($alias)) {
                        $alias = $last_part;
                    }

                    if (in_array($alias, $names)) {
                        $msg = __METHOD__ . ": Invalid argument, multiple columns have the same alias ($alias)";
                        throw new Exception\InvalidArgumentException($msg);
                    }
                    $names[] = $alias;

                    $cols[$alias] = new Expression(implode($identifierSeparator, $quotedParts));
                } else {
                    if (in_array($alias, $names)) {
                        $msg = __METHOD__ . ": Invalid argument, multiple columns have the same alias ($alias)";
                        throw new Exception\InvalidArgumentException($msg);
                    }

                    $cols[$alias] = $column;
                    $names[] = $alias;
                }
            } else {
                if (in_array($alias, $names)) {
                    $msg = __METHOD__ . ": Invalid argument, multiple columns have the same alias ($alias)";
                    throw new Exception\InvalidArgumentException($msg);
                }

                $cols[$alias] = $column;
                $names[] = $alias;
            }
        }
        $this->columns($cols);
        return $this;
    }

    /**
     * Set database adapter
     *
     * @param Adapter $adapter
     * @return Select
     */
    public function setDbAdapter(Adapter $adapter)
    {
        $this->adapter = $adapter;
        return $this;
    }

    /**
     * Return an sql string accordingly to the internat database adapter
     *
     * @throws Exception\InvalidUsageException
     * @return string
     */
    public function getSql()
    {
        if ($this->adapter === null) {
            $msg = __METHOD__ . ": Error, prior to use execute method you must provide a valid database adapter. See Select::setDbAdapter() method.";
            throw new Exception\InvalidUsageException($msg);
        }
        $sql = new Sql($this->adapter);
        return $sql->getSqlStringForSqlObject($this);
    }

    /**
     * Execute the query and return a Zend\Db\Resultset\ResultSet object
     *
     * @throws Exception\InvalidUsageException
     * @return \Zend\Db\ResultSet\ResultSet
     */
    public function execute()
    {
        if ($this->adapter === null) {
            $msg = __METHOD__ . ": Error, prior to use execute method you must provide a valid database adapter. See Select::setDbAdapter() method.";
            throw new Exception\InvalidUsageException($msg);
        }
        $sql = new Sql($this->adapter);
        $sql_string = $sql->getSqlStringForSqlObject($this);

        //return $this->adapter->createStatement($sql_string)->execute();
        //return $this->adapter->query($sql_string, Adapter::QUERY_MODE_EXECUTE);
        $result = $this->adapter->getDriver()->getConnection()->execute($sql_string);
        $resultset = new ResultSet();
        $resultset->initialize($result);
        return $resultset;
    }

    /**
     * Return an sql string accordingly to the internat database adapter
     *
     * @throws Exception\InvalidUsageException
     * @return string
     */
    public function __toString()
    {
        return $this->getSql();
    }
}


<?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\ORM;

use InvalidArgumentException;
use PDO;
use Valkyrja\Application;
use Valkyrja\ORM\Exceptions\InvalidEntityException;
use Valkyrja\ORM\QueryBuilder\NativeQueryBuilder;
use Valkyrja\ORM\Repositories\PDORepository;
use Valkyrja\Support\Providers\Provides;

/**
 * Class NativeEntityManager.
 */
class NativeEntityManager implements EntityManager
{
    use Provides;

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

    /**
     * Repositories.
     *
     * @var Repository[]
     */
    protected $repositories = [];

    /**
     * Stores.
     *
     * @var PDO[]
     */
    protected $stores = [];

    /**
     * The models awaiting to be committed for creation.
     *
     *
     *      [
     *          Model::class
     *      ]
     *
     *
     * @var Entity[]
     */
    protected $createModels = [];

    /**
     * The models awaiting to be committed for saving.
     *
     *
     *      [
     *          Model::class
     *      ]
     *
     *
     * @var \Valkyrja\ORM\Entity[]
     */
    protected $saveModels = [];

    /**
     * NativeEntityManager constructor.
     *
     * @param Application $app
     *
     * @throws InvalidArgumentException
     */
    public function __construct(Application $app)
    {
        $this->app = $app;

        $this->store()->beginTransaction();
    }

    /**
     * Get a store by the connection name.
     *
     * @param string|null $name
     *
     * @throws InvalidArgumentException If the name doesn't exist
     *
     * @return PDO
     */
    public function store(string $name = null): PDO
    {
        return $this->getStore($name);
    }

    /**
     * Get a new query builder instance.
     *
     * @return QueryBuilder
     */
    public function getQueryBuilder(): QueryBuilder
    {
        return new NativeQueryBuilder();
    }

    /**
     * Get a repository instance.
     *
     * @param string $entity
     *
     * @return Repository
     */
    public function getRepository(string $entity): Repository
    {
        if (isset($this->repositories[$entity])) {
            return $this->repositories[$entity];
        }

        /** @var Entity|string $entity */
        $repository = $entity::getRepository() ?? PDORepository::class;

        return $this->repositories[$entity] = new $repository($this, $entity, $entity::getTable());
    }

    /**
     * Initiate a transaction.
     *
     * @throws InvalidArgumentException
     *
     * @return bool
     */
    public function beginTransaction(): bool
    {
        return $this->store()->beginTransaction();
    }

    /**
     * Set a model for creation on transaction commit.
     *
     * @param \Valkyrja\ORM\Entity $entity
     *
     * @return void
     */
    public function create(Entity $entity): void
    {
        $id = spl_object_id($entity);

        $this->createModels[$id] = $entity;
    }

    /**
     * Set a model for saving on transaction commit.
     *
     * @param Entity $entity
     *
     * @return void
     */
    public function save(Entity $entity): void
    {
        $id = spl_object_id($entity);

        $this->saveModels[$id] = $entity;
    }

    /**
     * Remove a model previously set for creation or save.
     *
     * @param \Valkyrja\ORM\Entity $entity The entity instance to remove.
     *
     * @return bool
     */
    public function remove(Entity $entity): bool
    {
        // Get the id of the object
        $id = spl_object_id($entity);

        // If the model is set to be created
        if (isset($this->createModels[$id])) {
            // Unset it
            unset($this->createModels[$id]);

            return true;
        }

        // If the model is set to be saved
        if (isset($this->saveModels[$id])) {
            // Unset it
            unset($this->saveModels[$id]);

            return true;
        }

        // The model wasn't set for creation or saving
        return false;
    }

    /**
     * Commit all items in the transaction.
     *
     * @throws InvalidArgumentException
     * @throws InvalidEntityException
     *
     * @return bool
     */
    public function commit(): bool
    {
        // Iterate through the models awaiting creation
        foreach ($this->createModels as $cid => $createModel) {
            // Create the model
            $this->getRepository(\get_class($createModel))->create($createModel);
            // Unset the model
            unset($this->createModels[$cid]);
        }

        // Iterate through the models awaiting save
        foreach ($this->saveModels as $sid => $saveModel) {
            // Save the model
            $this->getRepository(\get_class($saveModel))->save($saveModel);
            // Unset the model
            unset($this->saveModels[$sid]);
        }

        return $this->store()->commit();
    }

    /**
     * Rollback the previous transaction.
     *
     * @throws InvalidArgumentException
     *
     * @return bool
     */
    public function rollback(): bool
    {
        return $this->store()->rollBack();
    }

    /**
     * Get a pdo store by name.
     *
     * @param string|null $name
     *
     * @throws InvalidArgumentException
     *
     * @return PDO
     */
    protected function getStore(string $name = null): PDO
    {
        $name = $name ?? $this->app->config()['database']['default'];

        if (isset($this->stores[$name])) {
            return $this->stores[$name];
        }

        $config = $this->getStoreConfig($name);

        return $this->stores[$name] = $this->getStoreFromConfig($config);
    }

    /**
     * Get the store config.
     *
     * @param string|null $name
     *
     * @throws InvalidArgumentException
     *
     * @return array
     */
    protected function getStoreConfig(string $name): array
    {
        $config = $this->app->config('database.connections.' . $name);

        if (null === $config) {
            throw new InvalidArgumentException('Invalid connection name specified: ' . $name);
        }

        return $config;
    }

    /**
     * Get the store from the config.
     *
     * @param array $config
     *
     * @return PDO
     */
    protected function getStoreFromConfig(array $config): PDO
    {
        $dsn = $config['driver']
            . ':host=' . $config['host']
            . ';port=' . $config['port']
            . ';dbname=' . $config['database']
            . ';charset=' . $config['charset'];

        return new PDO(
            $dsn,
            $config['username'],
            $config['password'],
            []
        );
    }

    /**
     * The items provided by this provider.
     *
     * @return array
     */
    public static function provides(): array
    {
        return [
            EntityManager::class,
        ];
    }

    /**
     * Publish the provider.
     *
     * @param Application $app The application
     *
     * @throws InvalidArgumentException
     *
     * @return void
     */
    public static function publish(Application $app): void
    {
        $app->container()->singleton(
            EntityManager::class,
            new static($app)
        );
    }
}


<?php
namespace Cake\Composer\Installer;

use Cake\Composer\Installer\ComponentInstallerConfigureTrait;
use Composer\Installer\LibraryInstaller;
use Composer\Script\Event;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;

class ComponentInstaller extends LibraryInstaller
{

    use ComponentInstallerConfigureTrait;

    public function supports($packageType)
    {
        $rootPackage = isset($this->composer) ? $this->composer->getPackage() : null;
        if (isset($rootPackage)) {
            while ($rootPackage instanceof AliasPackage) {
                $rootPackage = $rootPackage->getAliasOf();
            }
            if (method_exists($rootPackage, 'setScripts')) {
                $scripts = $rootPackage->getScripts();
                $scripts['post-autoload-dump']['component-installer'] = 'Cake\\Composer\\Installer\\ComponentInstaller::postAutoloadDump';
                $rootPackage->setScripts($scripts);
            }
        }
        return $packageType == 'component';
    }

    /**
     * Called whenever composer (re)generates the autoloader
     *
     * @param Event $event the composer event object
     * @return void
     */
    public static function postAutoloadDump(Event $event)
    {
        $composer = $event->getComposer();
        $config = $composer->getConfig();

        $vendorDir = realpath($config->get('vendor-dir'));
        if($config->has('component')){
            static::setConfig($config->get('component'));
        }

        $packages = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
        $components = static::determineComponents($packages);
        $webrootDir = dirname($vendorDir) . DIRECTORY_SEPARATOR . 'webroot';

        $config = static::processComponents($components, $vendorDir, $webrootDir);

        $configFile = static::configFile($vendorDir);
        static::writeConfigFile($configFile, $config);
    }

    public static function determineComponents($packages)
    {
        $components = [];

        foreach ($packages as $package) {
            if ($package->getType() !== 'component') {
                continue;
            }
            $extra = $package->getExtra();
            if(isset($extra['component'])){
                $components[$package->getName()] = $extra['component'];
            }
        }
        return $components;
    }

    public static function processComponents($components, $vendorDir = 'vendor', $webrootDir = 'webroot')
    {
        $config = [];
        $componentDir = static::$config['component-dir'];
        foreach($components as $name=>$component){
            //Set component name
            list($vendor, $vendorComponentName) = explode('/', $name);
            $componentName = $vendorComponentName;
            if(isset($component['name'])){
                $componentName = $component['name'];
            }
            $componentPath = $vendorDir . DIRECTORY_SEPARATOR . $vendor . DIRECTORY_SEPARATOR . $vendorComponentName;

            $files = array_merge(
                (isset($component['scripts']) ? $component['scripts'] : array()),
                (isset($component['styles']) ? $component['styles'] : array()),
                (isset($component['files']) ? $component['files'] : array())
            );
            $files = static::buildFilesList($files, $componentPath);

            foreach($files as $type=>$assets){
                $targetDir = $webrootDir . DIRECTORY_SEPARATOR . $type;
                if($componentDir !== false){
                    $targetDir .= DIRECTORY_SEPARATOR . $componentDir;
                }
                $targetDir .= DIRECTORY_SEPARATOR . $vendorComponentName;
                $config[$name][$type] = str_replace($webrootDir . DIRECTORY_SEPARATOR, '', $targetDir);
                foreach($assets as $file){
                    $source = $componentPath.DIRECTORY_SEPARATOR.$file;
                    $target = $targetDir . DIRECTORY_SEPARATOR . preg_replace('/^'.$type.'\\'.DIRECTORY_SEPARATOR.'/', '', $file);
                    $_targetDir = dirname($target);
                    if(!is_dir($_targetDir)){
                        mkdir($_targetDir, 0755, true);
                    }
                    if(file_exists($source)&&is_dir($_targetDir)){
                        copy($source, $target);
                    }
                }
            }
        }
        return $config;
    }

    protected static function buildFilesList($files, $componentPath)
    {
        $_files = [];
        $lastType = '';
        foreach($files as $file){
            if(strpos($file, '*')){
                $file = static::glob($componentPath.DIRECTORY_SEPARATOR.$file);
                foreach($file as $i=>$asset){
                    $file[$i] = str_replace($componentPath.DIRECTORY_SEPARATOR, '', $asset);
                }
            } else {
                $file = (array)$file;
            }

            foreach($file as $asset){
                if(static::excluded($asset)){
                    continue;
                }
                list($type) = explode('/', $asset);
                if(!array_keys(static::getSupportedTypes(), $type)){
                    $type = pathinfo($componentPath.DIRECTORY_SEPARATOR.$asset, PATHINFO_EXTENSION);
                    if($type == 'map'){
                        $type = $lastType;
                    } else {
                        foreach(static::getSupportedTypes() as $_type=>$extensions){
                            if(in_array($type, $extensions)){
                                $type = $_type;
                                break;
                            }
                        }
                    }
                }
                if(!isset($_files[$type])){
                    $_files[$type] = [];
                }
                $_files[$type][] = $asset;
                $lastType = $type;
            }
        }
        return $_files;
    }

    protected static function excluded($path)
    {
        $exclude = static::getConfigParam('exclude');
        if(empty($exclude)){
            return false;
        }
        if(empty($path)){
            return true;
        }
        foreach($exclude as $regex){
            if(preg_match("/".$regex."/i", $path)){
                return true;
            }
        }
        return false;
    }

    protected static function glob($pattern, $flags = 0)
    {
        $files = glob($pattern, $flags);
        if (strpos($pattern, '**')) {
            $dirs = glob(dirname($pattern).DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR|GLOB_NOSORT);
            if ($dirs) {
                foreach ($dirs as $dir) {
                    $files = array_merge($files, static::glob($dir.DIRECTORY_SEPARATOR.basename($pattern), $flags));
                }
            }
        }
        return array_filter($files, 'is_file');
    }

}


<?php

declare(strict_types=1);

namespace Ruwork\ObjectStore\Type;

use Ruwork\ObjectStore\Configurator\StoreConfiguratorInterface;
use Ruwork\ObjectStore\Storage\SymfonySessionStorage;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class SymfonySessionStoreType implements StoreTypeInterface
{
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    /**
     * {@inheritdoc}
     */
    public static function getRequiredTypes(): iterable
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver
            ->setRequired('session_key')
            ->setAllowedTypes('session_key', 'string');
    }

    /**
     * {@inheritdoc}
     */
    public function configureStore(StoreConfiguratorInterface $configurator, array $options): void
    {
        $configurator->setStorage(new SymfonySessionStorage($this->session, $options['session_key']));
    }
}