<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\web;

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;

/**
 * Session provides session data management and the related configurations.
 *
 * Session is a Web application component that can be accessed via `Yii::$app->session`.
 *
 * To start the session, call [[open()]]; To complete and send out session data, call [[close()]];
 * To destroy the session, call [[destroy()]].
 *
 * Session can be used like an array to set and get session data. For example,
 *
 * ```php
 * $session = new Session;
 * $session->open();
 * $value1 = $session['name1'];  // get session variable 'name1'
 * $value2 = $session['name2'];  // get session variable 'name2'
 * foreach ($session as $name => $value) // traverse all session variables
 * $session['name3'] = $value3;  // set session variable 'name3'
 * ```
 *
 * Session can be extended to support customized session storage.
 * To do so, override [[useCustomStorage]] so that it returns true, and
 * override these methods with the actual logic about using custom storage:
 * [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
 * [[destroySession()]] and [[gcSession()]].
 *
 * Session also supports a special type of session data, called *flash messages*.
 * A flash message is available only in the current request and the next request.
 * After that, it will be deleted automatically. Flash messages are particularly
 * useful for displaying confirmation messages. To use flash messages, simply
 * call methods such as [[setFlash()]], [[getFlash()]].
 *
 * @property array $allFlashes Flash messages (key => message or key => [message1, message2]). This property
 * is read-only.
 * @property array $cookieParams The session cookie parameters. This property is read-only.
 * @property integer $count The number of session variables. This property is read-only.
 * @property string $flash The key identifying the flash message. Note that flash messages and normal session
 * variables share the same name space. If you have a normal session variable using the same name, its value will
 * be overwritten by this method. This property is write-only.
 * @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is
 * started on every session initialization, defaults to 1 meaning 1% chance.
 * @property boolean $hasSessionId Whether the current request has sent the session ID.
 * @property string $id The current session ID.
 * @property boolean $isActive Whether the session has started. This property is read-only.
 * @property SessionIterator $iterator An iterator for traversing the session variables. This property is
 * read-only.
 * @property string $name The current session name.
 * @property string $savePath The current session save path, defaults to '/tmp'.
 * @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up.
 * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
 * @property boolean|null $useCookies The value indicating whether cookies should be used to store session
 * IDs.
 * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
 * @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to
 * false.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable
{
    /**
     * @var string the name of the session variable that stores the flash message data.
     */
    public $flashParam = '__flash';
    /**
     * @var \SessionHandlerInterface|array an object implementing the SessionHandlerInterface or a configuration array. If set, will be used to provide persistency instead of build-in methods.
     */
    public $handler;

    /**
     * @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function
     * Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httponly'
     * @see http://www.php.net/manual/en/function.session-set-cookie-params.php
     */
    private $_cookieParams = ['httponly' => true];

    /**
     * Initializes the application component.
     * This method is required by IApplicationComponent and is invoked by application.
     */
    public function init()
    {
        parent::init();
        register_shutdown_function([$this, 'close']);
        if ($this->getIsActive()) {
            Yii::warning("Session is already started", __METHOD__);
        }
    }

    /**
     * Returns a value indicating whether to use custom session storage.
     * This method should be overridden to return true by child classes that implement custom session storage.
     * To implement custom session storage, override these methods: [[openSession()]], [[closeSession()]],
     * [[readSession()]], [[writeSession()]], [[destroySession()]] and [[gcSession()]].
     * @return boolean whether to use custom storage.
     */
    public function getUseCustomStorage()
    {
        return false;
    }

    /**
     * Starts the session.
     */
    public function open()
    {
        if ($this->getIsActive()) {
            return;
        }

        $this->registerSessionHandler();

        $this->setCookieParamsInternal();

        @session_start();

        if ($this->getIsActive()) {
            Yii::info('Session started', __METHOD__);
            $this->updateFlashCounters();
        } else {
            $error = error_get_last();
            $message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
            Yii::error($message, __METHOD__);
        }
    }

    /**
     * Registers session handler.
     * @throws \yii\base\InvalidConfigException
     */
    protected function registerSessionHandler()
    {
        if ($this->handler !== null) {
            if (!is_object($this->handler)) {
                $this->handler = Yii::createObject($this->handler);
            }
            if (!$this->handler instanceof \SessionHandlerInterface) {
                throw new InvalidConfigException('"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.');
            }
            @session_set_save_handler($this->handler, false);
        } elseif ($this->getUseCustomStorage()) {
            @session_set_save_handler(
                [$this, 'openSession'],
                [$this, 'closeSession'],
                [$this, 'readSession'],
                [$this, 'writeSession'],
                [$this, 'destroySession'],
                [$this, 'gcSession']
            );
        }
    }

    /**
     * Ends the current session and store session data.
     */
    public function close()
    {
        if ($this->getIsActive()) {
            @session_write_close();
        }
    }

    /**
     * Frees all session variables and destroys all data registered to a session.
     */
    public function destroy()
    {
        if ($this->getIsActive()) {
            @session_unset();
            @session_destroy();
        }
    }

    /**
     * @return boolean whether the session has started
     */
    public function getIsActive()
    {
        return session_status() == PHP_SESSION_ACTIVE;
    }

    private $_hasSessionId;

    /**
     * Returns a value indicating whether the current request has sent the session ID.
     * The default implementation will check cookie and $_GET using the session name.
     * If you send session ID via other ways, you may need to override this method
     * or call [[setHasSessionId()]] to explicitly set whether the session ID is sent.
     * @return boolean whether the current request has sent the session ID.
     */
    public function getHasSessionId()
    {
        if ($this->_hasSessionId === null) {
            $name = $this->getName();
            $request = Yii::$app->getRequest();
            if (!empty($_COOKIE[$name]) && ini_get('session.use_cookies')) {
                $this->_hasSessionId = true;
            } elseif (!ini_get('session.use_only_cookies') && ini_get('session.use_trans_sid')) {
                $this->_hasSessionId = $request->get($name) != '';
            } else {
                $this->_hasSessionId = false;
            }
        }

        return $this->_hasSessionId;
    }

    /**
     * Sets the value indicating whether the current request has sent the session ID.
     * This method is provided so that you can override the default way of determining
     * whether the session ID is sent.
     * @param boolean $value whether the current request has sent the session ID.
     */
    public function setHasSessionId($value)
    {
        $this->_hasSessionId = $value;
    }

    /**
     * Gets the session ID.
     * This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
     * @return string the current session ID
     */
    public function getId()
    {
        return session_id();
    }

    /**
     * Sets the session ID.
     * This is a wrapper for [PHP session_id()](http://php.net/manual/en/function.session-id.php).
     * @param string $value the session ID for the current session
     */
    public function setId($value)
    {
        session_id($value);
    }

    /**
     * Updates the current session ID with a newly generated one .
     * Please refer to <http://php.net/session_regenerate_id> for more details.
     * @param boolean $deleteOldSession Whether to delete the old associated session file or not.
     */
    public function regenerateID($deleteOldSession = false)
    {
        // add @ to inhibit possible warning due to race condition
        // https://github.com/yiisoft/yii2/pull/1812
        @session_regenerate_id($deleteOldSession);
    }

    /**
     * Gets the name of the current session.
     * This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
     * @return string the current session name
     */
    public function getName()
    {
        return session_name();
    }

    /**
     * Sets the name for the current session.
     * This is a wrapper for [PHP session_name()](http://php.net/manual/en/function.session-name.php).
     * @param string $value the session name for the current session, must be an alphanumeric string.
     * It defaults to "PHPSESSID".
     */
    public function setName($value)
    {
        session_name($value);
    }

    /**
     * Gets the current session save path.
     * This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
     * @return string the current session save path, defaults to '/tmp'.
     */
    public function getSavePath()
    {
        return session_save_path();
    }

    /**
     * Sets the current session save path.
     * This is a wrapper for [PHP session_save_path()](http://php.net/manual/en/function.session-save-path.php).
     * @param string $value the current session save path. This can be either a directory name or a path alias.
     * @throws InvalidParamException if the path is not a valid directory
     */
    public function setSavePath($value)
    {
        $path = Yii::getAlias($value);
        if (is_dir($path)) {
            session_save_path($path);
        } else {
            throw new InvalidParamException("Session save path is not a valid directory: $value");
        }
    }

    /**
     * @return array the session cookie parameters.
     * @see http://php.net/manual/en/function.session-get-cookie-params.php
     */
    public function getCookieParams()
    {
        return array_merge(session_get_cookie_params(), array_change_key_case($this->_cookieParams));
    }

    /**
     * Sets the session cookie parameters.
     * The cookie parameters passed to this method will be merged with the result
     * of `session_get_cookie_params()`.
     * @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httponly`.
     * @throws InvalidParamException if the parameters are incomplete.
     * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
     */
    public function setCookieParams(array $value)
    {
        $this->_cookieParams = $value;
    }

    /**
     * Sets the session cookie parameters.
     * This method is called by [[open()]] when it is about to open the session.
     * @throws InvalidParamException if the parameters are incomplete.
     * @see http://us2.php.net/manual/en/function.session-set-cookie-params.php
     */
    private function setCookieParamsInternal()
    {
        $data = $this->getCookieParams();
        extract($data);
        if (isset($lifetime, $path, $domain, $secure, $httponly)) {
            session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
        } else {
            throw new InvalidParamException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httponly.');
        }
    }

    /**
     * Returns the value indicating whether cookies should be used to store session IDs.
     * @return boolean|null the value indicating whether cookies should be used to store session IDs.
     * @see setUseCookies()
     */
    public function getUseCookies()
    {
        if (ini_get('session.use_cookies') === '0') {
            return false;
        } elseif (ini_get('session.use_only_cookies') === '1') {
            return true;
        } else {
            return null;
        }
    }

    /**
     * Sets the value indicating whether cookies should be used to store session IDs.
     * Three states are possible:
     *
     * - true: cookies and only cookies will be used to store session IDs.
     * - false: cookies will not be used to store session IDs.
     * - null: if possible, cookies will be used to store session IDs; if not, other mechanisms will be used (e.g. GET parameter)
     *
     * @param boolean|null $value the value indicating whether cookies should be used to store session IDs.
     */
    public function setUseCookies($value)
    {
        if ($value === false) {
            ini_set('session.use_cookies', '0');
            ini_set('session.use_only_cookies', '0');
        } elseif ($value === true) {
            ini_set('session.use_cookies', '1');
            ini_set('session.use_only_cookies', '1');
        } else {
            ini_set('session.use_cookies', '1');
            ini_set('session.use_only_cookies', '0');
        }
    }

    /**
     * @return float the probability (percentage) that the GC (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
     */
    public function getGCProbability()
    {
        return (float) (ini_get('session.gc_probability') / ini_get('session.gc_divisor') * 100);
    }

    /**
     * @param float $value the probability (percentage) that the GC (garbage collection) process is started on every session initialization.
     * @throws InvalidParamException if the value is not between 0 and 100.
     */
    public function setGCProbability($value)
    {
        if ($value >= 0 && $value <= 100) {
            // percent * 21474837 / 2147483647 ≈ percent * 0.01
            ini_set('session.gc_probability', floor($value * 21474836.47));
            ini_set('session.gc_divisor', 2147483647);
        } else {
            throw new InvalidParamException('GCProbability must be a value between 0 and 100.');
        }
    }

    /**
     * @return boolean whether transparent sid support is enabled or not, defaults to false.
     */
    public function getUseTransparentSessionID()
    {
        return ini_get('session.use_trans_sid') == 1;
    }

    /**
     * @param boolean $value whether transparent sid support is enabled or not.
     */
    public function setUseTransparentSessionID($value)
    {
        ini_set('session.use_trans_sid', $value ? '1' : '0');
    }

    /**
     * @return integer the number of seconds after which data will be seen as 'garbage' and cleaned up.
     * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
     */
    public function getTimeout()
    {
        return (int) ini_get('session.gc_maxlifetime');
    }

    /**
     * @param integer $value the number of seconds after which data will be seen as 'garbage' and cleaned up
     */
    public function setTimeout($value)
    {
        ini_set('session.gc_maxlifetime', $value);
    }

    /**
     * Session open handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @param string $savePath session save path
     * @param string $sessionName session name
     * @return boolean whether session is opened successfully
     */
    public function openSession($savePath, $sessionName)
    {
        return true;
    }

    /**
     * Session close handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @return boolean whether session is closed successfully
     */
    public function closeSession()
    {
        return true;
    }

    /**
     * Session read handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @param string $id session ID
     * @return string the session data
     */
    public function readSession($id)
    {
        return '';
    }

    /**
     * Session write handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @param string $id session ID
     * @param string $data session data
     * @return boolean whether session write is successful
     */
    public function writeSession($id, $data)
    {
        return true;
    }

    /**
     * Session destroy handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @param string $id session ID
     * @return boolean whether session is destroyed successfully
     */
    public function destroySession($id)
    {
        return true;
    }

    /**
     * Session GC (garbage collection) handler.
     * This method should be overridden if [[useCustomStorage]] returns true.
     * Do not call this method directly.
     * @param integer $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
     * @return boolean whether session is GCed successfully
     */
    public function gcSession($maxLifetime)
    {
        return true;
    }

    /**
     * Returns an iterator for traversing the session variables.
     * This method is required by the interface [[\IteratorAggregate]].
     * @return SessionIterator an iterator for traversing the session variables.
     */
    public function getIterator()
    {
        $this->open();
        return new SessionIterator;
    }

    /**
     * Returns the number of items in the session.
     * @return integer the number of session variables
     */
    public function getCount()
    {
        $this->open();
        return count($_SESSION);
    }

    /**
     * Returns the number of items in the session.
     * This method is required by [[\Countable]] interface.
     * @return integer number of items in the session.
     */
    public function count()
    {
        return $this->getCount();
    }

    /**
     * Returns the session variable value with the session variable name.
     * If the session variable does not exist, the `$defaultValue` will be returned.
     * @param string $key the session variable name
     * @param mixed $defaultValue the default value to be returned when the session variable does not exist.
     * @return mixed the session variable value, or $defaultValue if the session variable does not exist.
     */
    public function get($key, $defaultValue = null)
    {
        $this->open();
        return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
    }

    /**
     * Adds a session variable.
     * If the specified name already exists, the old value will be overwritten.
     * @param string $key session variable name
     * @param mixed $value session variable value
     */
    public function set($key, $value)
    {
        $this->open();
        $_SESSION[$key] = $value;
    }

    /**
     * Removes a session variable.
     * @param string $key the name of the session variable to be removed
     * @return mixed the removed value, null if no such session variable.
     */
    public function remove($key)
    {
        $this->open();
        if (isset($_SESSION[$key])) {
            $value = $_SESSION[$key];
            unset($_SESSION[$key]);

            return $value;
        } else {
            return null;
        }
    }

    /**
     * Removes all session variables
     */
    public function removeAll()
    {
        $this->open();
        foreach (array_keys($_SESSION) as $key) {
            unset($_SESSION[$key]);
        }
    }

    /**
     * @param mixed $key session variable name
     * @return boolean whether there is the named session variable
     */
    public function has($key)
    {
        $this->open();
        return isset($_SESSION[$key]);
    }

    /**
     * Updates the counters for flash messages and removes outdated flash messages.
     * This method should only be called once in [[init()]].
     */
    protected function updateFlashCounters()
    {
        $counters = $this->get($this->flashParam, []);
        if (is_array($counters)) {
            foreach ($counters as $key => $count) {
                if ($count > 0) {
                    unset($counters[$key], $_SESSION[$key]);
                } elseif ($count == 0) {
                    $counters[$key]++;
                }
            }
            $_SESSION[$this->flashParam] = $counters;
        } else {
            // fix the unexpected problem that flashParam doesn't return an array
            unset($_SESSION[$this->flashParam]);
        }
    }

    /**
     * Returns a flash message.
     * @param string $key the key identifying the flash message
     * @param mixed $defaultValue value to be returned if the flash message does not exist.
     * @param boolean $delete whether to delete this flash message right after this method is called.
     * If false, the flash message will be automatically deleted in the next request.
     * @return mixed the flash message or an array of messages if addFlash was used
     * @see setFlash()
     * @see addFlash()
     * @see hasFlash()
     * @see getAllFlashes()
     * @see removeFlash()
     */
    public function getFlash($key, $defaultValue = null, $delete = false)
    {
        $counters = $this->get($this->flashParam, []);
        if (isset($counters[$key])) {
            $value = $this->get($key, $defaultValue);
            if ($delete) {
                $this->removeFlash($key);
            } elseif ($counters[$key] < 0) {
                // mark for deletion in the next request
                $counters[$key] = 1;
                $_SESSION[$this->flashParam] = $counters;
            }

            return $value;
        } else {
            return $defaultValue;
        }
    }

    /**
     * Returns all flash messages.
     *
     * You may use this method to display all the flash messages in a view file:
     *
     * ```php
     * <?php
     * foreach (Yii::$app->session->getAllFlashes() as $key => $message) {
     *     echo '<div class="alert alert-' . $key . '">' . $message . '</div>';
     * } ?>
     * ```
     *
     * With the above code you can use the [bootstrap alert][] classes such as `success`, `info`, `danger`
     * as the flash message key to influence the color of the div.
     *
     * Note that if you use [[addFlash()]], `$message` will be an array, and you will have to adjust the above code.
     *
     * [bootstrap alert]: http://getbootstrap.com/components/#alerts
     *
     * @param boolean $delete whether to delete the flash messages right after this method is called.
     * If false, the flash messages will be automatically deleted in the next request.
     * @return array flash messages (key => message or key => [message1, message2]).
     * @see setFlash()
     * @see addFlash()
     * @see getFlash()
     * @see hasFlash()
     * @see removeFlash()
     */
    public function getAllFlashes($delete = false)
    {
        $counters = $this->get($this->flashParam, []);
        $flashes = [];
        foreach (array_keys($counters) as $key) {
            if (array_key_exists($key, $_SESSION)) {
                $flashes[$key] = $_SESSION[$key];
                if ($delete) {
                    unset($counters[$key], $_SESSION[$key]);
                } elseif ($counters[$key] < 0) {
                    // mark for deletion in the next request
                    $counters[$key] = 1;
                }
            } else {
                unset($counters[$key]);
            }
        }

        $_SESSION[$this->flashParam] = $counters;

        return $flashes;
    }

    /**
     * Sets a flash message.
     * A flash message will be automatically deleted after it is accessed in a request and the deletion will happen
     * in the next request.
     * If there is already an existing flash message with the same key, it will be overwritten by the new one.
     * @param string $key the key identifying the flash message. Note that flash messages
     * and normal session variables share the same name space. If you have a normal
     * session variable using the same name, its value will be overwritten by this method.
     * @param mixed $value flash message
     * @param boolean $removeAfterAccess whether the flash message should be automatically removed only if
     * it is accessed. If false, the flash message will be automatically removed after the next request,
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
     * it is accessed.
     * @see getFlash()
     * @see addFlash()
     * @see removeFlash()
     */
    public function setFlash($key, $value = true, $removeAfterAccess = true)
    {
        $counters = $this->get($this->flashParam, []);
        $counters[$key] = $removeAfterAccess ? -1 : 0;
        $_SESSION[$key] = $value;
        $_SESSION[$this->flashParam] = $counters;
    }

    /**
     * Adds a flash message.
     * If there are existing flash messages with the same key, the new one will be appended to the existing message array.
     * @param string $key the key identifying the flash message.
     * @param mixed $value flash message
     * @param boolean $removeAfterAccess whether the flash message should be automatically removed only if
     * it is accessed. If false, the flash message will be automatically removed after the next request,
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
     * it is accessed.
     * @see getFlash()
     * @see setFlash()
     * @see removeFlash()
     */
    public function addFlash($key, $value = true, $removeAfterAccess = true)
    {
        $counters = $this->get($this->flashParam, []);
        $counters[$key] = $removeAfterAccess ? -1 : 0;
        $_SESSION[$this->flashParam] = $counters;
        if (empty($_SESSION[$key])) {
            $_SESSION[$key] = [$value];
        } else {
            if (is_array($_SESSION[$key])) {
                $_SESSION[$key][] = $value;
            } else {
                $_SESSION[$key] = [$_SESSION[$key], $value];
            }
        }
    }

    /**
     * Removes a flash message.
     * @param string $key the key identifying the flash message. Note that flash messages
     * and normal session variables share the same name space.  If you have a normal
     * session variable using the same name, it will be removed by this method.
     * @return mixed the removed flash message. Null if the flash message does not exist.
     * @see getFlash()
     * @see setFlash()
     * @see addFlash()
     * @see removeAllFlashes()
     */
    public function removeFlash($key)
    {
        $counters = $this->get($this->flashParam, []);
        $value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null;
        unset($counters[$key], $_SESSION[$key]);
        $_SESSION[$this->flashParam] = $counters;

        return $value;
    }

    /**
     * Removes all flash messages.
     * Note that flash messages and normal session variables share the same name space.
     * If you have a normal session variable using the same name, it will be removed
     * by this method.
     * @see getFlash()
     * @see setFlash()
     * @see addFlash()
     * @see removeFlash()
     */
    public function removeAllFlashes()
    {
        $counters = $this->get($this->flashParam, []);
        foreach (array_keys($counters) as $key) {
            unset($_SESSION[$key]);
        }
        unset($_SESSION[$this->flashParam]);
    }

    /**
     * Returns a value indicating whether there are flash messages associated with the specified key.
     * @param string $key key identifying the flash message type
     * @return boolean whether any flash messages exist under specified key
     */
    public function hasFlash($key)
    {
        return $this->getFlash($key) !== null;
    }

    /**
     * This method is required by the interface [[\ArrayAccess]].
     * @param mixed $offset the offset to check on
     * @return boolean
     */
    public function offsetExists($offset)
    {
        $this->open();

        return isset($_SESSION[$offset]);
    }

    /**
     * This method is required by the interface [[\ArrayAccess]].
     * @param integer $offset the offset to retrieve element.
     * @return mixed the element at the offset, null if no element is found at the offset
     */
    public function offsetGet($offset)
    {
        $this->open();

        return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
    }

    /**
     * This method is required by the interface [[\ArrayAccess]].
     * @param integer $offset the offset to set element
     * @param mixed $item the element value
     */
    public function offsetSet($offset, $item)
    {
        $this->open();
        $_SESSION[$offset] = $item;
    }

    /**
     * This method is required by the interface [[\ArrayAccess]].
     * @param mixed $offset the offset to unset element
     */
    public function offsetUnset($offset)
    {
        $this->open();
        unset($_SESSION[$offset]);
    }
}


<?php

namespace CoRex\Support\System\Console;

class Style
{
    private static $styles = [
        'normal' => ['foreground' => 'white', 'background' => ''],
        'error' => ['foreground' => 'white', 'background' => 'red'],
        'warning' => ['foreground' => 'cyan', 'background' => ''],
        'info' => ['foreground' => 'green', 'background' => ''],
        'comment' => ['foreground' => 'green', 'background' => ''],
        'title' => ['foreground' => 'yellow', 'background' => '']
    ];

    /**
     * Set style.
     *
     * @param string $style
     * @param string $foreground
     * @param string $background
     */
    public static function setStyle($style, $foreground, $background)
    {
        self::$styles[$style] = [
            'foreground' => $foreground,
            'background' => $background
        ];
    }

    /**
     * Get foreground color.
     *
     * @param string $style
     * @return string
     */
    public static function getForeground($style)
    {
        return self::get($style, 'foreground');
    }

    /**
     * Get background color.
     *
     * @param string $style
     * @return string
     */
    public static function getBackground($style)
    {
        return self::get($style, 'background');
    }

    /**
     * Apply foreground and background color.
     *
     * @param string $text
     * @param string $foreground Default ''.
     * @param string $background Default ''.
     * @return string
     */
    public static function apply($text, $foreground = '', $background = '')
    {
        try {
            $style = new OutputFormatterStyle();
            if ($foreground != '') {
                $style->setForeground($foreground);
            }
            if ($background != '') {
                $style->setBackground($background);
            }
            return $style->apply($text);
        } catch (\Exception $e) {
            return $text;
        }
    }

    /**
     * Apply style.
     *
     * @param string $text
     * @param string $style
     * @return string
     */
    public static function applyStyle($text, $style)
    {
        $foreground = self::getForeground($style);
        $background = self::getBackground($style);
        return self::apply($text, $foreground, $background);
    }

    /**
     * Get style setting.
     *
     * @param string $style
     * @param string $setting
     * @param string $defaultValue Default ''.
     * @return string
     */
    private static function get($style, $setting, $defaultValue = '')
    {
        if (isset(self::$styles[$style])) {
            $style = self::$styles[$style];
            if (isset($style[$setting])) {
                return $style[$setting];
            }
        }
        return $defaultValue;
    }
}


<?php
namespace LunixREST\Server\Router\Endpoint\ResourceEndpoint;

use LunixREST\Server\APIResponse\APIResponseData;
use LunixREST\Server\Router\Endpoint\ResourceEndpoint\Exceptions\UnableToCreateAPIResponseDataException;

/**
 * abstract class ResourceAPIResponseDataFactory
 * @package LunixREST\Server\Router\Endpoint\ResourceEndpoint
 */
abstract class ResourceAPIResponseDataFactory {

    /**
     * @param null|Resource $resource
     * @return APIResponseData
     * @throws UnableToCreateAPIResponseDataException
     */
    abstract public function toAPIResponseData(?Resource $resource): APIResponseData;

    /**
     * Uses above method for each resource, extracting the data into an array, creating a new APIResponseData from that array.
     * @param null|Resource[] $resources
     * @return APIResponseData
     * @throws UnableToCreateAPIResponseDataException
     */
    public function multipleToAPIResponseData(?array $resources): APIResponseData
    {
        if(is_null($resources)) {
            return $this->toAPIResponseData(null);
        }

        return new APIResponseData(array_map(function(Resource $resource) {
            return $this->toAPIResponseData($resource)->getData();
        }, $resources));
    }
}


<?php
/**
 * SclSocket Module (https://github.com/SCLInternet/SclSocket)
 *
 * @link https://github.com/SCLInternet/SclSocket for the canonical source repository
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
 */
namespace SclSocket;

/**
 * The socket class which provides read and write access to a socket.
 *
 * @author Tom Oram <tom@x2k.co.uk>
 */
class Socket implements SocketInterface
{
    /**
     * The time in seconds for the connection to timeout
     *
     * @var int
     */
    private $connectionTimeout = 10;

    /**
     * The time in seconds for a read action to timeout
     *
     * @var int
     */
    private $readTimeout = 20;

    /**
     * Sets whether the socket blocks
     *
     * @var boolean
     */
    private $blocking = true;

    /**
     * Connection error number
     *
     * @var int
     */
    private $connectionErrorNo = 0;

    /**
     * Connection error message
     *
     * @var string
     */
    private $connectionError = '';

    /**
     * The socket resource.
     *
     * @var resource
     */
    private $socket = null;

    /**
     * {@inheritDoc}
     *
     * @param int $seconds
     *
     * @return SocketInterface
     */
    public function setConnectTimeout($seconds)
    {
        $this->connectionTimeout = (int) $seconds;
        return $this;
    }

    /**
     * {@inheritDoc}
     *
     * @param int $seconds
     *
     * @return SocketInterface
     */
    public function setReadTimeout($seconds)
    {
        $this->readTimeout = (int) $seconds;
        return $this;
    }

    /**
     * {@inheritDoc}
     *
     * @param boolean $blocking
     *
     * @return SocketInterface
     */
    public function setBlocking($blocking = true)
    {
        $this->blocking = (boolean) $blocking;
    }

    /**
     * {@inheritDoc}
     *
     * @param string  $host
     * @param string  $port
     * @param boolean $secure
     *
     * @return boolean
     */
    public function connect($host, $port, $secure = false)
    {
        $this->connectionError = '';
        $this->connectionErrorNo = 0;

        $host = $secure ? 'ssl://' . $host : $host;

        $this->socket = fsockopen(
            $host,
            $port,
            $this->connectionErrorNo,
            $this->connectionError,
            $this->connectionTimeout
        );

        if (!$this->socket) {
            return false;
        }

        socket_set_blocking($this->socket, $this->blocking);
        stream_set_timeout($this->socket, $this->readTimeout);

        return true;
    }

    /**
     * {@inheritDoc}
     *
     * @param string $data
     *
     * @return int|false Number of bytes written or false.
     */
    public function write($data)
    {
        return fputs($this->socket, (string) $data);
    }

    /**
     * {@inheritDoc}
     *
     * @param int $length
     *
     * @return string|false
     */
    public function read($length = 1024)
    {
        return fgets($this->socket, $length);
    }

    /**
     * {@inheritDoc}
     *
     * @return boolean
     */
    public function closed()
    {
        return !$this->socket || feof($this->socket);
    }

    /**
     * {@inheritDoc}
     *
     * @return void
     */
    public function disconnect()
    {
        if (null === $this->socket) {
            return;
        }

        fclose($this->socket);
        $this->socket = null;
    }

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

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


<?php
/**
 * Phossa Project
 *
 * PHP version 5.4
 *
 * @category  Library
 * @package   Phossa\Query
 * @author    Hong Zhang <phossa@126.com>
 * @copyright 2015 phossa.com
 * @license   http://mit-license.org/ MIT License
 * @link      http://www.phossa.com/
 */
/*# declare(strict_types=1); */

namespace Phossa\Query\Clause;

/**
 * HavingTrait
 *
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     HavingInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait HavingTrait
{
    /**
     * HAVINGs
     *
     * @var    array
     * @access protected
     */
    protected $clause_having = [];

    /**
     * {@inheritDoc}
     */
    public function having(
        /*# string */ $col,
        /*# string */ $operator = ClauseInterface::NO_OPERATOR,
        /*# string */ $value  = ClauseInterface::NO_VALUE,
        /*# bool */ $logicAnd = true
    ) {
        return $this->where(
            $col, $operator, $value, $logicAnd, false, false, 'having'
        );
    }

    /**
     * {@inheritDoc}
     */
    public function orHaving(
        /*# string */ $col,
        /*# string */ $operator = ClauseInterface::NO_OPERATOR,
        /*# string */ $value = ClauseInterface::NO_VALUE
    ) {
        return $this->having($col, $operator, $value, false);
    }

    /**
     * {@inheritDoc}
     */
    public function havingRaw(/*# string */ $having)
    {
        return $this->having($having);
    }

    /**
     * {@inheritDoc}
     */
    public function orHavingRaw(/*# string */ $having)
    {
        return $this->having($having, ClauseInterface::NO_OPERATOR,
            ClauseInterface::NO_VALUE, false);
    }

    /**
     * Build HAVING
     *
     * @return array
     * @access protected
     */
    protected function buildHaving()/*# : array */
    {
        return $this->buildWhere('having');
    }

    abstract public function where(
        $col,
        $operator = ClauseInterface::NO_OPERATOR,
        $value    = ClauseInterface::NO_VALUE,
        /*# bool */ $logicAnd = true,
        /*# bool */ $whereNot = false,
        /*# bool */ $rawMode  = false,
        /*# string */ $clause = 'where'
    );

    abstract protected function buildWhere(/*# string */ $clause = 'where');
}


<?php

namespace Dhii\Data\Object;

use ArrayObject;
use InvalidArgumentException;
use stdClass;
use Dhii\Util\String\StringableInterface as Stringable;
use Exception as RootException;

/**
 * Functionality for data store creation.
 *
 * @since [*next-version*]
 */
trait CreateDataStoreCapableTrait
{
    /**
     * Creates a new data store.
     *
     * @since [*next-version*]
     *
     * @param stdClass|array|null $data The data for the store, if any.
     *
     * @throws InvalidArgumentException If the type of data for the store is invalid.
     *
     * @return ArrayObject The new data store.
     */
    protected function _createDataStore($data = null)
    {
        // Default
        if (is_null($data)) {
            $data = [];
        }

        try {
            // Constructor already throws in PHP 5+, but doesn't supply the value.
            return new ArrayObject($data);
        } catch (InvalidArgumentException $e) {
            throw $this->_createInvalidArgumentException(
                $this->__('Invalid type of store data'),
                null,
                $e,
                $data
            );
        }
    }

    /**
     * Creates a new invalid argument exception.
     *
     * @since [*next-version*]
     *
     * @param string|Stringable|null $message  The error message, if any.
     * @param int|null               $code     The error code, if any.
     * @param RootException|null     $previous The inner exception for chaining, if any.
     * @param mixed|null             $argument The invalid argument, if any.
     *
     * @return InvalidArgumentException The new exception.
     */
    abstract protected function _createInvalidArgumentException(
        $message = null,
        $code = null,
        RootException $previous = null,
        $argument = null
    );

    /**
     * Translates a string, and replaces placeholders.
     *
     * @since [*next-version*]
     * @see sprintf()
     *
     * @param string $string  The format string to translate.
     * @param array  $args    Placeholder values to replace in the string.
     * @param mixed  $context The context for translation.
     *
     * @return string The translated string.
     */
    abstract protected function __($string, $args = [], $context = null);
}


<?php
namespace LunixREST;

use LunixREST\RequestFactory\Exceptions\UnableToCreateRequestException;
use LunixREST\Server\APIResponse\APIResponse;
use LunixREST\Server\Exceptions\UnableToHandleRequestException;
use LunixREST\RequestFactory\RequestFactory;
use LunixREST\Server\Server;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;

/**
 * A class that interfaces PSR-7 with our APIRequests and uses a Server to handle the APIRequest. Handles the PSR-7 response building as well.
 * Class HTTPServer
 * @package LunixREST
 */
class HTTPServer
{
    use LoggerAwareTrait;

    /**
     * @var Server
     */
    protected $server;
    /**
     * @var RequestFactory
     */
    protected $requestFactory;

    /**
     * HTTPServer constructor.
     * @param Server $server
     * @param RequestFactory $requestFactory
     * @param LoggerInterface $logger
     */
    public function __construct(Server $server, RequestFactory $requestFactory, LoggerInterface $logger)
    {
        $this->server = $server;
        $this->requestFactory = $requestFactory;
        $this->logger = $logger;
    }

    /**
     * Clones a response, changing contents based on the handling of a given request.
     * Taking in a response allows us not to define a specific response implementation to create.
     * @param ServerRequestInterface $serverRequest
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    public function handleRequest(ServerRequestInterface $serverRequest, ResponseInterface $response): ResponseInterface
    {
        $response = $response->withProtocolVersion($serverRequest->getProtocolVersion());

        try {
            try {
                $APIRequest = $this->requestFactory->create($serverRequest);
            } catch (UnableToCreateRequestException $exception) {
                return $this->handleRequestFactoryException($exception, $response);
            }

            try {
                $APIResponse = $this->server->handleRequest($APIRequest);
            } catch (UnableToHandleRequestException $exception) {
                return $this->handleServerException($exception, $response);
            }

            return $this->buildResponse($APIResponse, $response);
        } catch (\Throwable $e) {
            $this->logCaughtThrowableResultingInHTTPCode(500, $e, LogLevel::CRITICAL);
            return $response->withStatus(500, "Internal Server Error");
        }
    }

    /**
     * Takes an APIResponse and builds a PSR-7 Response
     * @param APIResponse $APIResponse
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    protected function buildResponse(APIResponse $APIResponse, ResponseInterface $response): ResponseInterface
    {
        $response = $response->withStatus(200, "200 OK");
        $response = $response->withAddedHeader("Content-Type", $APIResponse->getMIMEType());
        $response = $response->withAddedHeader("Content-Length", $APIResponse->getAsDataStream()->getSize());
        $this->logger->debug("Responding to request successfully");
        return $response->withBody($APIResponse->getAsDataStream());
    }

    /**
     * @param UnableToCreateRequestException $exception
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    protected function handleRequestFactoryException(UnableToCreateRequestException $exception, ResponseInterface $response): ResponseInterface
    {
        $this->logCaughtThrowableResultingInHTTPCode(400, $exception, LogLevel::INFO);
        return $response->withStatus(400, "Bad Request");
    }

    /**
     * @param UnableToHandleRequestException $exception
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    protected function handleServerException(UnableToHandleRequestException $exception, ResponseInterface $response): ResponseInterface
    {
        $this->logCaughtThrowableResultingInHTTPCode(500, $exception, LogLevel::CRITICAL);
        return $response->withStatus(500, "Internal Server Error");
    }

    /**
     * Dumps a PSR-7 ResponseInterface to the SAPI.
     * @param ResponseInterface $response
     */
    public static function dumpResponse(ResponseInterface $response)
    {
        $statusLine = sprintf(
            "HTTP/%s %d %s",
            $response->getProtocolVersion(),
            $response->getStatusCode(),
            $response->getReasonPhrase()
        );

        header($statusLine, true, $response->getStatusCode());

        foreach ($response->getHeaders() as $name => $values) {
            foreach ($values as $value) {
                header(sprintf('%s: %s', $name, $value), false);
            }
        }

        $body = $response->getBody();
        while(!$body->eof()) {
            echo $body->read(1024);
        }
    }

    /**
     * @param int $code
     * @param \Throwable $exception
     * @param $level
     */
    protected function logCaughtThrowableResultingInHTTPCode(int $code, \Throwable $exception, $level): void
    {
        $this->logger->log($level, "Returning HTTP {code}: {message}", ["code" => $code, "message" => $exception->getMessage()]);
    }
}


<?php
/*
 * Copyright (c) 2014 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.0
 */
namespace Peach\Markup;
use Peach\Util\ArrayMap;
use Peach\Util\Values;

/**
 * 既存の Component をラップして, ノードツリーの構築を簡略化・省力化するための糖衣構文を備えたクラスです.
 * 主に (MVC フレームワークで言うところの) View の範囲で使用されることを想定しています.
 */
class HelperObject implements Container
{
    /**
     * このオブジェクトを生成した Helper オブジェクトです.
     * このオブジェクトの prototype を生成する場合などに使用されます.
     * @var Helper
     */
    private $helper;

    /**
     * このオブジェクトがラップしている Component です.
     * @var Component
     */
    private $node;

    /**
     * 指定された Helper オブジェクトに紐付けられた新しいインスタンスを構築します.
     * このコンストラクタは {@link Helper::tag()} から呼び出されます.
     * 通常は, エンドユーザーがコンストラクタを直接呼び出す機会はありません.
     *
     * @param Helper $helper
     * @param mixed $var このオブジェクトがラップする値 (テキスト, Component など)
     */
    public function __construct(Helper $helper, $var)
    {
        $this->helper = $helper;
        $this->node   = $this->createNode($var, $helper);
    }

    /**
     * 引数の値をノードに変換します.
     * 返り値は, 引数によって以下のようになります.
     *
     * - {@link Node} 型オブジェクトの場合: 引数自身
     * - {@link NodeList} 型オブジェクトの場合: 引数自身
     * - {@link HelperObject} 型オブジェクトの場合: 引数のオブジェクトがラップしているノード
     * - 文字列の場合: 引数の文字列を要素名に持つ新しい {@link Element}
     * - null または空文字列の場合: 空の {@link NodeList}
     * - 上記に当てはまらない場合: 引数の文字列表現をあらわす {@link Text} ノード
     *
     * @param  mixed $var     変換対象の値
     * @param  Helper $helper ノードの生成に利用する Helper オブジェクト
     * @return Component      変換後のノード
     */
    private function createNode($var, Helper $helper)
    {
        if ($var instanceof Node) {
            return $var;
        }
        if ($var instanceof NodeList) {
            return $var;
        }
        if ($var instanceof HelperObject) {
            return $var->getNode();
        }
        if (is_string($var) && strlen($var)) {
            return $helper->createElement($var);
        }
        $nodeName = Values::stringValue($var);
        return strlen($nodeName) ? new Text($nodeName) : new NodeList();
    }

    /**
     * このオブジェクトがラップしているノードを返します.
     * @return Component
     */
    public function getNode()
    {
        return $this->node;
    }

    /**
     * このオブジェクトの子ノードとして, 指定された値を追加します.
     * このオブジェクトがラップしているオブジェクトが Container でない場合は何もしません.
     *
     * @param  mixed $var   追加される値
     */
    public function appendNode($var)
    {
        $node = $this->node;
        if ($node instanceof Container) {
            $appendee = ($var instanceof HelperObject) ? $var->getNode() : $var;
            $node->appendNode($appendee);
        }
    }

    /**
     * このオブジェクトの子ノードとして, 指定された値を追加して, 最後に自分自身を返します.
     * メソッドチェーンを可能にするための appendNode() のシンタックスシュガーです.
     *
     * @param  mixed $var   追加される値
     * @return HelperObject 自分自身
     */
    public function append($var)
    {
        $this->appendNode($var);
        return $this;
    }

    /**
     * 指定された Container にこのオブジェクトを追加します.
     * 以下の 2 つのコードは, どちらも $obj2 の中に $obj1 を追加しています.
     * <code>
     * $obj1->appendTo($obj2);
     * $obj2->append($obj1);
     * </code>
     * {@link HelperObject::append()}
     * との違いは, 返り値が $obj1 になるか $obj2 になるかという点にあります.
     *
     * @param  Container    $container 追加先の Container
     * @return HelperObject            自分自身
     */
    public function appendTo(Container $container)
    {
        $container->appendNode($this->getNode());
        return $this;
    }

    /**
     * 指定された文字列を整形済コードとして追加します.
     *
     * @param  string|Code $code 追加対象の整形済文字列
     * @return HelperObject      このオブジェクト自身
     */
    public function appendCode($code)
    {
        if (!($code instanceof Code)) {
            return $this->appendCode(new Code($code));
        }

        return $this->append($code);
    }

    /**
     * {@link Element::setAttribute()}
     * および
     * {@link Element::setAttributes()}
     * の糖衣構文です.
     * 引数が配列の場合は setAttributes() を実行し,
     * 引数が 1 つ以上の文字列の場合は setAttribute() を実行します.
     * もしもこのオブジェクトがラップしているノードが Element ではなかった場合,
     * このメソッドは何も行いません.
     *
     * jQuery のようなメソッドチェインを実現するため, このオブジェクト自身を返します.
     *
     * @param  string|array|ArrayMap $var セットする属性
     * @return HelperObject               このオブジェクト自身
     */
    public function attr()
    {
        $node  = $this->node;
        if (!($node instanceof Element)) {
            return $this;
        }

        $count = func_num_args();
        if (!$count) {
            return $this;
        }

        $args  = func_get_args();
        $first = $args[0];
        if (($first instanceof ArrayMap) || is_array($first)) {
            $node->setAttributes($first);
        } else {
            $second = (1 < $count) ? $args[1] : null;
            $node->setAttribute($first, $second);
        }
        return $this;
    }

    /**
     * このオブジェクトの子ノード一覧をあらわす HelperObject を返します.
     * @return HelperObject
     */
    public function children()
    {
        if ($this->node instanceof NodeList) {
            return $this;
        }

        $result = $this->helper->tag(null);
        if ($this->node instanceof Container) {
            $result->append($this->node->getChildNodes());
        }
        return $result;
    }

    /**
     * この HelperObject をレンダリングします.
     *
     * @return mixed 出力結果. デフォルトではマークアップされた結果の文字列
     */
    public function write()
    {
        return $this->helper->write($this);
    }

    /**
     * この HelperObject をデバッグ出力します.
     * @return string
     */
    public function debug()
    {
        static $debug = null;
        if ($debug === null) {
           $debug = new DebugBuilder();
        }
        return $debug->build($this);
    }

    /**
     * この HelperObject がラップしている要素の属性をコピーして, 新しい要素を生成します.
     * もしもラップしているオブジェクトが Element ではなかった場合は
     * 空の NodeList をラップする HelperObject を返します.
     *
     * @return HelperObject コピーされた要素をラップする HelperObject
     */
    public function prototype()
    {
        return $this->helper->tag($this->createPrototype());
    }

    /**
     * このオブジェクトをプロトタイプとして, 新しい HelperObject を生成します.
     *
     * @return Element
     */
    private function createPrototype()
    {
        $original = $this->node;
        if ($original instanceof ContainerElement) {
            $node = new ContainerElement($original->getName());
            $node->setAttributes($original->getAttributes());
            return $node;
        }
        if ($original instanceof EmptyElement) {
            $node = new EmptyElement($original->getName());
            $node->setAttributes($original->getAttributes());
            return $node;
        }

        return null;
    }

    /**
     * このオブジェクトがラップしているノードの accept() を呼び出します.
     * @param Context $context
     */
    public function accept(Context $context)
    {
        $this->node->accept($context);
    }

    /**
     * このオブジェクトの子ノードの一覧を取得します.
     * もしもこのオブジェクトがラップしているノードが {@link Container Container}
     * だった場合は, そのオブジェクトの子ノードの一覧を返します.
     * それ以外は空の配列を返します.
     * @return array
     */
    public function getChildNodes()
    {
        $node = $this->node;
        return ($node instanceof Container) ? $node->getChildNodes() : array();
    }

    /**
     * このオブジェクトがラップしているノードの getApendee() の結果を返します.
     *
     * @return NodeList
     */
    public function getAppendee()
    {
        return $this->node->getAppendee();
    }
}


<?php

namespace Spiffy\View\Twig;

use Spiffy\View;

class TwigStrategy implements View\ViewStrategy
{
    /**
     * @var \Spiffy\View\ViewRenderer
     */
    protected $renderer;

    /**
     * @var \Spiffy\View\ViewResolver
     */
    protected $resolver;

    /**
     * @param \Spiffy\View\Twig\TwigRenderer $renderer
     * @param \Spiffy\View\Twig\TwigResolver $resolver
     */
    public function __construct(TwigRenderer $renderer, TwigResolver $resolver)
    {
        $this->renderer = $renderer;
        $this->resolver = $resolver;
    }

    /**
     * {@inheritDoc}
     */
    public function render($nameOrModel, array $variables = [])
    {
        return $this->renderer->render($nameOrModel, $variables);
    }

    /**
     * {@inheritDoc}
     */
    public function canRender($nameOrModel)
    {
        if (!$nameOrModel instanceof View\ViewModel) {
            return false;
        }

        try {
            $this->resolver->resolve($nameOrModel);
        } catch (\Twig_Error_Loader $e) {
            return false;
        }
        return true;
    }
}


<?php

namespace FiveSay\Laravel\Model;

/*
|--------------------------------------------------------------------------
| 特性：模型拓展
|--------------------------------------------------------------------------
| 自动注册模型观察者
|--------------------------------------------------------------------------
| 创建与更新数据前，自动校验请求数据
|--------------------------------------------------------------------------
|
*/

use Illuminate\Foundation\Validation\ValidatesRequests;

trait ExtTrait
{
    use ValidatesRequests;

    /**
     * 数据校验规则
     * @var array
     */
    // public $rules = [];

    /**
     * boot this trait
     *
     * @return void
     */
    public static function bootExtTrait()
    {
        self::registerObserve();
        self::registerValidater();
    }

    /**
     * 注册 Observer 命名空间下，与当前模型同名的模型观察者
     *
     * @return void
     */
    private static function registerObserve()
    {
        $className        = 'Observer\\'.get_called_class();
        $observableEvents = [
            'creating', 'created', 'updating', 'updated',
            'deleting', 'deleted', 'saving', 'saved',
            'restoring', 'restored',
        ];

        if (class_exists($className)) {
            $priority = 0;
            foreach ($observableEvents as $event) {
                if (method_exists($className, $event)) {
                    static::registerModelEvent($event, $className.'@'.$event, $priority);
                }
            }
        }
    }

    /**
     * 注册数据校验
     *
     * @return void
     */
    private static function registerValidater()
    {
        // 提高优先级，确保在模型观察者之前执行
        $priority = 1;

        // 创建数据前
        static::registerModelEvent('creating', function ($model) {

            if (! $model->rules) return;

            // 针对所有数据进行校验
            $modelRules = $model->rules;
            $rules      = [];
            $messages   = [];

            foreach ($modelRules as $key => $value) {
                // 构造验证规则
                $rules[$key] = implode('|', array_keys($value));

                // 构造错误信息
                array_walk($value, function ($v, $k) use ($key, &$messages) {
                    $k = explode(':', $k);
                    $messages[$key.'.'.$k[0]] = $v;
                });
            }

            // 对请求的数据进行校验
            $input = array_merge($model->attributes, request()->all());
            request()->replace($input);
            $model->validate(request(), $rules, $messages);

        }, $priority);

        // 更新数据前
        static::registerModelEvent('updating', function ($model) {

            if (! $model->rules) return;

            // 仅针对脏数据进行校验
            $modelRules = array_intersect_key($model->rules, $model->getDirty());
            $rules      = [];
            $messages   = [];

            foreach ($modelRules as $key => $value) {
                // 构造验证规则
                $rules[$key] = implode('|', array_keys($value));

                // 构造错误信息
                array_walk($value, function ($v, $k) use ($key, &$messages) {
                    $k = explode(':', $k);
                    $messages[$key.'.'.$k[0]] = $v;
                });
            }

            // 对请求的数据进行校验
            $input = array_merge($model->attributes, request()->all());
            request()->replace($input);
            $model->validate(request(), $rules, $messages);

        }, $priority);
    }

    /**
     * 移除指定的验证规则
     * @param  string $ruleStr 规则名称字符串（例如：password.read_only）
     * @param  string $event   事件名称（creating 或 updating）
     * @return void
     */
    public function removeRule($ruleStr, $event)
    {
        $ruleArr = explode('.', $ruleStr);

        // 提高优先级，确保在数据校验之前执行
        $priority = 2;

        static::registerModelEvent($event, function ($model) use ($ruleArr) {
            switch (count($ruleArr)) {
                case 1:
                    unset($model->rules[$ruleArr[0]]);
                    break;

                case 2:
                    unset($model->rules[$ruleArr[0]][$ruleArr[1]]);
                    break;
            }
        }, $priority);
    }

    /**
     * 变更指定的验证规则
     * @param  string $ruleStr 规则名称字符串（例如：password.read_only）
     * @param  mixed  $value   具体赋值
     * @param  string $event   事件名称（creating 或 updating）
     * @return void
     */
    public function changeRule($ruleStr, $value, $event)
    {
        $ruleArr = explode('.', $ruleStr);

        // 提高优先级，确保在数据校验之前执行
        $priority = 2;

        static::registerModelEvent($event, function ($model) use ($ruleArr, $value) {
            switch (count($ruleArr)) {
                case 1:
                    $model->rules[$ruleArr[0]] = $value;
                    break;

                case 2:
                    $model->rules[$ruleArr[0]][$ruleArr[1]] = $value;
                    break;
            }
        }, $priority);
    }

}


<?php

namespace sndsgd\fs;

/**
 * Temp file and directory utility methods
 *
 * Note: the creation of both directores and files is done from this class
 * so any created paths can be registered for deletion. Otherwise you would
 * be able to register any filesystem entity to be deleted on script exit.
 */
class Temp
{
    /**
     * The directory to use as the temp directory
     *
     * @var string
     */
    private static $dir = "";

    /**
     * All created paths are added here for easy removal at script exit
     *
     * @var array<string,\sndsgd\fs\entity\EntityInterface>
     */
    private static $entities = [];

    /**
     * Set the root temp directory (overrides use of the system temp directory)
     *
     * @param string $path
     * @return void
     * @throws InvalidArgumentException If the provided path isn't usable
     */
    public static function setDir(string $path = "")
    {
        if ($path !== "") {
            $dir = new entity\DirEntity($path);
            if (!$dir->test(\sndsgd\Fs::READABLE | \sndsgd\Fs::WRITABLE)) {
                throw new \InvalidArgumentException(
                    "invalid value provided for 'path'; ".$dir->getError()
                );
            }
        }
        self::$dir = $path;
    }

    /**
     * Get the root temp directory
     *
     * @return string
     */
    public static function getDir(): string
    {
        return (self::$dir === "") ? sys_get_temp_dir() : self::$dir;
    }

    /**
     * Create a temp directory
     *
     * @param string $prefix A directory name prefix
     * @param int $mode The permissions for the new directory
     * @param int $maxAttempts The max number of times to call mkdir
     * @return \sndsgd\fs\entity\DirEntity
     */
    public static function createDir(
        string $prefix = "tmp",
        int $mode = 0777,
        int $maxAttempts = 10
    ): entity\DirEntity
    {
        $tmpdir = static::getDir();
        $prefix = \sndsgd\Fs::sanitizeName($prefix);
        $attempts = 0;
        do {
            $attempts++;
            if ($attempts > $maxAttempts) {
                throw new \RuntimeException(
                    "failed to create temp directory; ".
                    "reached max number ($maxAttempts) of attempts"
                );
            }
            $rand = \sndsgd\Str::random(10);
            $path = "$tmpdir/$prefix-$rand";
        }
        while (@mkdir($path, $mode) === false);

        $dir = new entity\DirEntity($path);
        static::registerEntity($dir);
        return $dir;
    }

    /**
     * Create a temp file
     *
     * @param string $name The name to use in the temp file
     * @param int $maxAttempts The max number of times to attempt the create
     * @return \sndsgd\fs\entity\FileEntity
     */
    public static function createFile(
        string $name,
        int $maxAttempts = 10
    ): entity\FileEntity
    {
        $tmpdir = static::getDir();
        $name = \sndsgd\Fs::sanitizeName($name);
        $pos = strrpos($name, ".");
        if ($pos === false) {
            $extension = "";
        } else {
            $extension = substr($name, $pos);
            $name = substr($name, 0, $pos);
        }

        $attempts = 1;
        do {
            if ($attempts > $maxAttempts) {
                throw new \RuntimeException(
                    "failed to create temp file; ".
                    "reached max number ($maxAttempts) of attempts"
                );
            }
            $rand = \sndsgd\Str::random(10);
            $path = "$tmpdir/$name-$rand$extension";
            $attempts++;
        }
        while (file_exists($path));
        touch($path);
        $file = new entity\FileEntity($path);
        static::registerEntity($file);
        return $file;
    }

    /**
     * Register an entity to be deleted when the script exits
     *
     * @param \sndsgd\fs\entity\EntityInterface $entity
     */
    protected static function registerEntity(entity\EntityInterface $entity)
    {
        if (count(self::$entities) === 0) {
            register_shutdown_function("sndsgd\\fs\\Temp::cleanup");
        }
        self::$entities[$entity->getPath()] = $entity;
    }

    /**
     * Remove all temp files & directories created since script start
     *
     * @return bool Indicates whether all files were successfully removed
     */
    public static function cleanup(): bool
    {
        $ret = true;
        foreach (self::$entities as $path => $entity) {
            if (!$entity->remove()) {
                $ret = false;
            }
        }
        self::$entities = [];
        return $ret;
    }
}


<?php

declare(strict_types=1);

namespace Rancoud\Database;

use PDO;
use PDOException;

/**
 * Class Configurator.
 */
class Configurator
{
    /** @var string */
    protected $engine;

    /** @var string */
    protected $host;

    /** @var string */
    protected $user;

    /** @var string */
    protected $password;

    /** @var string */
    protected $database;

    /** @var array */
    protected $parameters = [];

    /** @var bool */
    protected $saveQueries = false;

    /** @var bool */
    protected $permanentConnection = false;

    /** @var string */
    protected $reportError = 'exception';

    /** @var string */
    protected $charset = 'utf8';

    /** @var string[] */
    protected $keySettings = [
        'engine',
        'host',
        'user',
        'password',
        'database',
        'save_queries',
        'permanent_connection',
        'report_error',
        'charset',
        'parameters'
    ];

    /**
     * DatabaseConfigurator constructor.
     *
     * @param array $settings
     *
     * @throws DatabaseException
     */
    public function __construct(array $settings)
    {
        $this->verifySettings($settings);

        $this->setMandatorySettings($settings);

        $this->setOptionnalsParameters($settings);
    }

    /**
     * @param array $settings
     *
     * @throws DatabaseException
     */
    protected function verifySettings(array $settings): void
    {
        foreach ($settings as $key => $value) {
            if (!\in_array($key, $this->keySettings, true)) {
                throw new DatabaseException('"' . $key . '" settings is not recognized');
            }
        }
    }

    /**
     * @param array $settings
     *
     * @throws DatabaseException
     */
    protected function setMandatorySettings(array $settings): void
    {
        $props = ['engine', 'host', 'user', 'password', 'database'];
        foreach ($props as $prop) {
            if (!isset($settings[$prop]) || !\is_string($settings[$prop])) {
                throw new DatabaseException('"' . $prop . '" settings is not defined or not a string');
            }

            $this->{'set' . \ucfirst($prop)}($settings[$prop]);
        }
    }

    /**
     * @param array $settings
     *
     * @throws DatabaseException
     */
    protected function setOptionnalsParameters(array $settings): void
    {
        if (\array_key_exists('save_queries', $settings)) {
            $this->saveQueries = (bool) $settings['save_queries'];
        }

        if (\array_key_exists('permanent_connection', $settings)) {
            $this->permanentConnection = (bool) $settings['permanent_connection'];
        }

        if (\array_key_exists('report_error', $settings)) {
            $this->setReportError($settings['report_error']);
        }

        if (\array_key_exists('charset', $settings)) {
            $this->setCharset($settings['charset']);
        }

        if (\array_key_exists('parameters', $settings)) {
            $this->setParameters($settings['parameters']);
        }
    }

    /**
     * @return string
     */
    public function getEngine(): string
    {
        return $this->engine;
    }

    /**
     * @param string $engine
     *
     * @throws DatabaseException
     */
    public function setEngine(string $engine): void
    {
        $enginesAvailables = PDO::getAvailableDrivers();
        if (!\in_array($engine, $enginesAvailables, true)) {
            throw new DatabaseException('The engine "' . $engine . '" is not available for PDO');
        }

        $this->engine = $engine;
    }

    /**
     * @return string
     */
    public function getHost(): string
    {
        return $this->host;
    }

    /**
     * @param string $host
     */
    public function setHost(string $host): void
    {
        $this->host = $host;
    }

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

    /**
     * @param string $user
     */
    public function setUser(string $user): void
    {
        $this->user = $user;
    }

    /**
     * @return string
     */
    public function getPassword(): string
    {
        return $this->password;
    }

    /**
     * @param string $password
     */
    public function setPassword(string $password): void
    {
        $this->password = $password;
    }

    /**
     * @return string
     */
    public function getDatabase(): string
    {
        return $this->database;
    }

    /**
     * @param string $database
     */
    public function setDatabase(string $database): void
    {
        $this->database = $database;
    }

    /**
     * @return array
     */
    public function getParameters(): array
    {
        return $this->parameters;
    }

    /**
     * @param mixed $key
     * @param mixed $value
     */
    public function setParameter($key, $value): void
    {
        $this->parameters[$key] = $value;
    }

    /**
     * @param array $parameters
     */
    public function setParameters(array $parameters): void
    {
        $this->parameters = $parameters;
    }

    /**
     * @return array
     */
    public function getParametersForPDO(): array
    {
        $parameters = $this->getParameters();

        if ($this->getEngine() === 'mysql') {
            $parameters[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $this->getCharset();
        }

        if ($this->getReportError() === 'silent') {
            $parameters[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT;
        } elseif ($this->getReportError() === 'exception') {
            $parameters[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
        }

        $parameters[PDO::ATTR_PERSISTENT] = $this->permanentConnection;

        return $parameters;
    }

    /**
     * @return bool
     */
    public function hasSaveQueries(): bool
    {
        return $this->saveQueries;
    }

    public function enableSaveQueries(): void
    {
        $this->saveQueries = true;
    }

    public function disableSaveQueries(): void
    {
        $this->saveQueries = false;
    }

    /**
     * @return bool
     */
    public function hasPermanentConnection(): bool
    {
        return $this->permanentConnection;
    }

    public function enablePermanentConnection(): void
    {
        $this->permanentConnection = true;
    }

    public function disablePermanentConnection(): void
    {
        $this->permanentConnection = false;
    }

    /**
     * @return string
     */
    public function getReportError(): string
    {
        return $this->reportError;
    }

    /**
     * @param string $reportError
     *
     * @throws DatabaseException
     */
    public function setReportError(string $reportError): void
    {
        if (!\in_array($reportError, ['silent', 'exception'], true)) {
            throw new DatabaseException('The report error "' . $reportError . '" is incorrect. (silent , exception)');
        }

        $this->reportError = $reportError;
    }

    /**
     * @return bool
     */
    public function hasThrowException(): bool
    {
        return $this->reportError === 'exception';
    }

    /**
     * @return string
     */
    public function getCharset(): string
    {
        return $this->charset;
    }

    /**
     * @param string $charset
     */
    public function setCharset(string $charset): void
    {
        $this->charset = $charset;
    }

    /**
     * @return string
     */
    public function getDsn(): string
    {
        $engine = $this->getEngine();
        $host = $this->getHost();
        $database = $this->getDatabase();

        $dsn = $engine . ':host=' . $host . ';dbname=' . $database;
        if ($engine === 'sqlite') {
            $dsn = 'sqlite:' . $database;
        }

        return $dsn;
    }

    /**
     * @throws DatabaseException
     *
     * @return PDO
     */
    public function createPDOConnection(): PDO
    {
        $user = $this->getUser();
        $password = $this->getPassword();
        $parameters = $this->getParametersForPDO();
        $dsn = $this->getDsn();

        try {
            if ($this->getEngine() !== 'sqlite') {
                return new PDO($dsn, $user, $password, $parameters);
            }

            return new PDO($dsn, null, null, $parameters);
        } catch (PDOException $e) {
            throw new DatabaseException($e->getMessage());
        }
    }
}


<?php declare(strict_types=1);

namespace Identity\Events;

use GeneralForm\EventException;
use GeneralForm\IEvent;
use GeneralForm\IEventContainer;
use Identity\IIdentityModel;
use Nette\Application\UI\InvalidLinkException;
use Nette\Application\UI\Presenter;
use Nette\SmartObject;

/**
 * Class ForgottenStep1Event
 *
 * @author  geniv
 * @package Identity\Events
 */
class ForgottenStep1Event implements IEvent
{
    use SmartObject;

    /** @var string */
    private $validate, $destination;
    /** @var IIdentityModel */
    private $identityModel;

    /**
     * ForgottenStep1Event constructor.
     *
     * @param string         $validate
     * @param string         $destination
     * @param IIdentityModel $identityModel
     */
    public function __construct(string $validate, string $destination, IIdentityModel $identityModel)
    {
        $this->setValidate($validate);
        $this->setDestination($destination);
        $this->identityModel = $identityModel;
    }

    /**
     * Set validate.
     *
     * @param string $validate
     */
    public function setValidate(string $validate)
    {
        $this->validate = $validate;
    }

    /**
     * Set destination.
     *
     * @param string $destination
     */
    public function setDestination(string $destination)
    {
        $this->destination = $destination;
    }

    /**
     * Update.
     *
     * @param IEventContainer $eventContainer
     * @param array           $values
     * @throws EventException
     * @throws InvalidLinkException
     */
    public function update(IEventContainer $eventContainer, array $values)
    {
        $user = $this->identityModel->getByEmail($values['email']);
        if ($user) {
            $hash = $this->identityModel->getEncodeHash($user['id'], $user['login'], $this->validate);

            /** @var Presenter $component */
            $component = $eventContainer->getComponent();
            $eventContainer->addValues($user->toArray());
            $eventContainer->addValues(['approve_link' => $component->presenter->link($this->destination, $hash)]);
        } else {
            throw new EventException('User does not exist or not active!');
        }
    }
}


<?php
/**
 * WIKI
 *
 *
 * @author	Jason Medland<jason.medland@gmail.com>
 * @package	JCORE\SERVICE\UI
 *
 */

namespace JCORE\SERVICE\UI;

use JCORE\TRANSPORT\SOA\SOA_BASE as SOA_BASE;
use JCORE\DAO\DAO as DAO;

/**
 * Class WIKI
 *
 * @package JCORE\SERVICE\UI
*/
class WIKI {
	/**
	*
	*/
	protected $serviceRequest = null;
	/**
	*
	*/
	public $serviceResponse = null;
	/**
	*
	*/
	public $error = null;
	/**
	*
	*/
	public $params = array();
	/**
	*
	*/
	public $changeList = array();

	/**
	* DESCRIPTOR: an empty constructor, the service MUST be called with
	* the service name and the service method name specified in the
	* in the method property of the JSONRPC request in this format
	* 		""method":"AJAX_STUB.aServiceMethod"
	*
	* @param param
	* @return return
	*/
	public function __construct($args=null){
		#$this->parentTable = 'blackwatch_advertiser';
		$section = 'JUST_CORE';
		if(isset($args["section"])){
			$section = $args["section"];
		}

		$this->cfg = $GLOBALS["CONFIG_MANAGER"]->getSetting($section,'WIKI_ROUTES');
		return;
	}
	/**
	* DESCRIPTOR: an example namespace call
	* @param param
	* @return return
	*/
	public function init($args){
		$this->params = $args;
		return;
	}

	/**
	* DESCRIPTOR: an example namespace call
	* @param param
	* @return return
	*/
	public function isWIKIPage($args = null){
		#echo __METHOD__.'@'.__LINE__.'$GLOBALS["route"]
['.var_export($GLOBALS["route"], true).']
'.'
'.PHP_EOL;
		$segments = explode('/',$GLOBALS["route"]);
		#echo __METHOD__.'@'.__LINE__.'$segments
['.var_export($segments, true).']
'.'
'.PHP_EOL;
		if('WIKI' == $segments[0] || 'HOME' == $segments[0] ){
			return true;
		}

		return false;
	}
	/**
	* DESCRIPTOR: an example namespace call
	* @param param
	* @return return
	*/
	public function loadWIKIPage($args = null){
		if(!isset($args["namespace"])){

		}
		#echo __METHOD__.'@'.__LINE__.'$GLOBALS["route"]
['.var_export($GLOBALS["route"], true).']
'.'
'.PHP_EOL;
		$segments = explode('/',$GLOBALS["route"]);
		/**
		echo __METHOD__.'@'.__LINE__.'$segments
['.var_export($segments, true).']
'.'
'.PHP_EOL;
		echo __METHOD__.'@'.__LINE__.'$this->cfg
['.var_export($this->cfg, true).']
'.'
'.PHP_EOL;
		*/

		if( isset($segments[1]) ){
			//$subSegments = explode(':',$segments[1]);
			if(isset($this->cfg[$segments[0]]["FILE_MAP"][$segments[1]])){

				$parsePath = $this->cfg[$segments[0]]["BASE_PATH"].$this->cfg[$segments[0]]["FILE_MAP"][$segments[1]];
				#echo '$parsePath['.$parsePath.']'.PHP_EOL;
				$markdown = file_get_contents($parsePath);

				$Parsedown = new \Parsedown();

				return $Parsedown->text($markdown);

			}
			echo __METHOD__.'@'.__LINE__.'$this->cfg['.$segments[0].']["FILE_MAP"]
['.var_export($this->cfg[$segments[0]]["FILE_MAP"], true).']
'.'
'.PHP_EOL;
			$index = array_search($segments[1],$this->cfg[$segments[0]]["FILE_MAP"]);
			if(false != $index ){
				$index = $this->cfg[$segments[0]]["FILE_MAP"][$index];
				echo __METHOD__.'@'.__LINE__.'$index
['.var_export($index, true).']
'.'
'.PHP_EOL;
			}
		}
		return false;
	}

}

?>


<?php

namespace FernleafSystems\Integrations\Paypal_Freeagent\Reconciliation\Bridge;

use FernleafSystems\ApiWrappers\Freeagent\Entities;
use FernleafSystems\Integrations\Freeagent;
use FernleafSystems\Integrations\Paypal_Freeagent\Consumers\PaypalMerchantApiConsumer;
use PayPal\PayPalAPI\GetTransactionDetailsReq;
use PayPal\PayPalAPI\GetTransactionDetailsRequestType;

abstract class PaypalBridge implements Freeagent\Reconciliation\Bridge\BridgeInterface {

	use PaypalMerchantApiConsumer;

	/**
	 * This needs to be extended to add the Invoice Item details.
	 * @param string $sTxnID a Stripe Charge ID
	 * @return Freeagent\DataWrapper\ChargeVO
	 * @throws \Exception
	 */
	public function buildChargeFromTransaction( $sTxnID ) {
		$oCharge = new Freeagent\DataWrapper\ChargeVO();

		try {
			$oDets = $this->getTxnChargeDetails( $sTxnID );

			$oCharge->setId( $sTxnID )
					->setGateway( 'paypalexpress' )
					->setPaymentTerms( 1 )
					->setAmount_Gross( $oDets->GrossAmount->value )
					->setAmount_Fee( $oDets->FeeAmount->value )
					->setAmount_Net( $oDets->GrossAmount->value - $oDets->FeeAmount->value )
					->setDate( strtotime( $oDets->PaymentDate ) )
					->setCurrency( $oDets->GrossAmount->currencyID );
		}
		catch ( \Exception $oE ) {
		}

		return $oCharge;
	}

	/**
	 * This isn't applicable to PayPal
	 * @param string $sRefundId
	 * @return Freeagent\DataWrapper\RefundVO
	 */
	public function buildRefundFromId( $sRefundId ) {
		return null;
	}

	/**
	 * With Paypal, the Transaction and the Payout are essentially the same thing.
	 * @param string $sPayoutId
	 * @return Freeagent\DataWrapper\PayoutVO
	 */
	public function buildPayoutFromId( $sPayoutId ) {
		$oPayout = new Freeagent\DataWrapper\PayoutVO();
		$oPayout->setId( $sPayoutId );

		try {
			$oDets = $this->getTxnChargeDetails( $sPayoutId );
			$oPayout->setDateArrival( strtotime( $oDets->PaymentDate ) )
					->setCurrency( $oDets->GrossAmount->currencyID );

			$oPayout->addCharge(
				$this->buildChargeFromTransaction( $sPayoutId )
			);
		}
		catch ( \Exception $oE ) {
		}

		return $oPayout;
	}

	/**
	 * @param string $sTxnID
	 * @return \PayPal\EBLBaseComponents\PaymentInfoType
	 * @throws \Exception
	 */
	protected function getTxnChargeDetails( $sTxnID ) {
		$oReqType = new GetTransactionDetailsRequestType();
		$oReqType->TransactionID = $sTxnID;

		$oReq = new GetTransactionDetailsReq();
		$oReq->GetTransactionDetailsRequest = $oReqType;

		return $this->getPaypalMerchantApi()
					->api()
					->GetTransactionDetails( $oReq )->PaymentTransactionDetails->PaymentInfo;
	}
}


<?php

namespace Telesto\VendorExt\Symfony\Form\Utils;

use Symfony\Component\Form\FormInterface;

abstract class CommonUtil
{
    /**
     * Type checking method for forms. Type checking includes the parent types.
     *
     * @param   FormInterface       $form
     * @param   string|string[]     $typeName   Type name or array of type names
     *
     * @return  true
     */
    public static function isTypeOf(FormInterface $form, $typeName)
    {
        $typeNames = (array) $typeName;
        $type = $form->getConfig()->getType();

        while ($type) {
            $actualTypeName = $type->getName();

            if (in_array($actualTypeName, $typeNames, true)) {
                return true;
            }

            $type = $type->getParent();
        }

        return false;
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: claudio
 * Date: 03-04-16
 * Time: 23:50
 */

namespace AscensoDigital\PerfilBundle\DataFixtures\ORM;

use AscensoDigital\PerfilBundle\Entity\Menu;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;

class LoadMenuData extends Fixture implements DependentFixtureInterface
{

    /**
     * Load data fixtures with the passed EntityManager
     *
     * @param ObjectManager $manager
     */
    public function load(ObjectManager $manager)
    {
        $mnMapa= new Menu();
        $mnMapa->setOrden(100)
            ->setDescripcion('Mapa del Sitio según perfil')
            ->setNombre('Mapa del Sitio')
            ->setRoute('ad_perfil_mapa_sitio')
            ->setColor($this->getReference('clr-verde'))
            ->setIcono('fa fa-sitemap')
            ->setPermiso($this->getReference('per-mapa-sitio-index'));
        $manager->persist($mnMapa);

        $mnConfig= new Menu();
        $mnConfig->setOrden(99)
            ->setDescripcion('Inicializar el sistema de menu y permisos')
            ->setNombre('Configuración')
            ->setColor($this->getReference('clr-negro'))
            ->setIcono('fa fa-cogs')
            ->setPermiso($this->getReference('per-config-index'));
        $manager->persist($mnConfig);

        $perNew= new Menu();
        $perNew->setMenuSuperior($mnConfig)
            ->setOrden(1)
            ->setDescripcion('Crear Permisos y asociar a los perfiles')
            ->setNombre('Crear Permiso')
            ->setRoute('ad_perfil_permiso_new')
            ->setColor($this->getReference('clr-verde'))
            ->setIcono('fa fa-unlock-alt')
            ->setPermiso($this->getReference('per-per-new'));
        $manager->persist($perNew);

        $perList= new Menu();
        $perList->setMenuSuperior($mnConfig)
            ->setOrden(2)
            ->setDescripcion('Listar los permisos asignados')
            ->setNombre('Listar Permisos')
            ->setRoute('ad_perfil_permiso_list')
            ->setColor($this->getReference('clr-rosado'))
            ->setIcono('fa fa-list-ul')
            ->setPermiso($this->getReference('per-per-list'));
        $manager->persist($perList);

        $perEditPermiso= new Menu();
        $perEditPermiso->setMenuSuperior($perList)
            ->setOrden(1)
            ->setVisible(false)
            ->setDescripcion('Editar los roles que pueden utilizar el permiso')
            ->setNombre('Editar Perfiles por Permiso')
            ->setRoute('ad_perfil_permiso_edit')
            ->setColor($this->getReference('clr-celeste'))
            ->setIcono('fa fa-edit')
            ->setPermiso($this->getReference('per-per-edit'));
        $manager->persist($perEditPermiso);

        $perEditPerfil= new Menu();
        $perEditPerfil->setMenuSuperior($perList)
            ->setOrden(2)
            ->setVisible(false)
            ->setDescripcion('Editar los permisos de un perfil')
            ->setNombre('Editar Permisos por Perfil')
            ->setRoute('ad_perfil_permiso_edit_perfil')
            ->setColor($this->getReference('clr-celeste'))
            ->setIcono('fa fa-edit')
            ->setPermiso($this->getReference('per-per-edit'));
        $manager->persist($perEditPerfil);

        $mnNew= new Menu();
        $mnNew->setMenuSuperior($mnConfig)
            ->setOrden(3)
            ->setDescripcion('Permite agregar un menu invisible a los principales')
            ->setNombre('Crear Menu')
            ->setRoute('ad_perfil_menu_new')
            ->setColor($this->getReference('clr-celeste'))
            ->setIcono('fa fa-navicon')
            ->setPermiso($this->getReference('per-menu-new'));
        $manager->persist($mnNew);

        $mnRepo= new Menu();
        $mnRepo->setOrden(98)
            ->setDescripcion('Listado de los descargables del sistema')
            ->setNombre('Reportes')
            ->setColor($this->getReference('clr-gris'))
            ->setIcono('fa fa-file-excel-o')
            ->setPermiso($this->getReference('per-rep-list'));
        $manager->persist($mnRepo);

        $repList= new Menu();
        $repList->setMenuSuperior($mnRepo)
            ->setOrden(1)
            ->setDescripcion('Listar los reportes disponibles')
            ->setNombre('Listar Reportes')
            ->setRoute('ad_perfil_reportes')
            ->setColor($this->getReference('clr-amarillo'))
            ->setIcono('fa fa-list-ul')
            ->setPermiso($this->getReference('per-rep-list'));
        $manager->persist($repList);

        $repNew= new Menu();
        $repNew->setMenuSuperior($mnRepo)
            ->setOrden(2)
            ->setDescripcion('Permite configurar un nuevo reporte de PerfilBundle')
            ->setNombre('Crear Reporte')
            ->setRoute('ad_perfil_reporte_new')
            ->setColor($this->getReference('clr-celeste'))
            ->setIcono('fa fa-plus')
            ->setPermiso($this->getReference('per-rep-new'));
        $manager->persist($repNew);

        $repEdit= new Menu();
        $repEdit->setMenuSuperior($repList)
            ->setVisible(false)
            ->setOrden(1)
            ->setDescripcion('Permite editar la configuración de un reporte de PerfilBundle')
            ->setNombre('Editar Reporte')
            ->setRoute('ad_perfil_reporte_edit')
            ->setColor($this->getReference('clr-cafe'))
            ->setIcono('fa fa-pencil-square-o')
            ->setPermiso($this->getReference('per-rep-edit'));
        $manager->persist($repEdit);

        $repLoad= new Menu();
        $repLoad->setMenuSuperior($repList)
            ->setVisible(false)
            ->setOrden(2)
            ->setDescripcion('Permite dejar estatico un reporte de PerfilBundle')
            ->setNombre('Cargar Reporte Estático')
            ->setRoute('ad_perfil_reporte_load_estatico')
            ->setColor($this->getReference('clr-rojo'))
            ->setIcono('fa fa-link')
            ->setPermiso($this->getReference('per-rep-load'));
        $manager->persist($repLoad);

        $manager->flush();
    }

    public function getDependencies()
    {
        return [LoadColorData::class,
            LoadPermisoData::class];
    }
}


<?php
/*
 * WellCommerce Open-Source E-Commerce Platform
 *
 * This file is part of the WellCommerce package.
 *
 * (c) Adam Piotrowski <adam@wellcommerce.org>
 *
 * For the full copyright and license information,
 * please view the LICENSE file that was distributed with this source code.
 */

namespace WellCommerce\Bundle\ProductStatusBundle\DataSet\Front;

use Doctrine\ORM\QueryBuilder;
use WellCommerce\Bundle\CoreBundle\DataSet\AbstractDataSet;
use WellCommerce\Bundle\ProductStatusBundle\Entity\ProductStatus;
use WellCommerce\Bundle\ProductStatusBundle\Entity\ProductStatusTranslation;
use WellCommerce\Component\DataSet\Cache\CacheOptions;
use WellCommerce\Component\DataSet\Configurator\DataSetConfiguratorInterface;

/**
 * Class ProductStatusDataSet
 *
 * @author Adam Piotrowski <adam@wellcommerce.org>
 */
class ProductStatusDataSet extends AbstractDataSet
{
    /**
     * {@inheritdoc}
     */
    public function configureOptions(DataSetConfiguratorInterface $configurator)
    {
        $configurator->setColumns([
            'id'        => 'product_status.id',
            'name'      => 'product_status_translation.name',
            'route'     => 'IDENTITY(product_status_translation.route)',
            'css_class' => 'product_status_translation.cssClass',
            'symbol'    => 'product_status.symbol',
        ]);

        $configurator->setColumnTransformers([
            'route' => $this->manager->createTransformer('route'),
        ]);

        $configurator->setCacheOptions(new CacheOptions(true, 3600, [
            ProductStatus::class,
            ProductStatusTranslation::class,
        ]));
    }

    protected function createQueryBuilder(): QueryBuilder
    {
        $queryBuilder = $this->repository->getQueryBuilder();
        $queryBuilder->groupBy('product_status.id');
        $queryBuilder->leftJoin('product_status.translations', 'product_status_translation');

        return $queryBuilder;
    }
}


<?php
/*
 * WellCommerce Open-Source E-Commerce Platform
 *
 * This file is part of the WellCommerce package.
 *
 * (c) Adam Piotrowski <adam@wellcommerce.org>
 *
 * For the full copyright and license information,
 * please view the LICENSE file that was distributed with this source code.
 */

namespace WellCommerce\Bundle\ProductBundle\Manager;

use Symfony\Component\Validator\Exception\ValidatorException;
use WellCommerce\Bundle\CoreBundle\Manager\AbstractManager;
use WellCommerce\Bundle\ProductBundle\Entity\ProductInterface;
use WellCommerce\Bundle\ProductBundle\Exception\ProductNotFoundException;

/**
 * Class ProductManager
 *
 * @author  Adam Piotrowski <adam@wellcommerce.org>
 */
class ProductManager extends AbstractManager
{
    /**
     * Updates the product data
     *
     * @param int   $id
     * @param array $data
     */
    public function quickUpdateProduct(int $id, array $data)
    {
        $product       = $this->findProduct($id);
        $entityManager = $this->getDoctrineHelper()->getEntityManager();

        $product->setSku($data['sku']);
        $product->setWeight($data['weight']);
        $product->setStock($data['stock']);
        $product->getSellPrice()->setGrossAmount($data['grossAmount']);

        $errors = $this->getValidatorHelper()->validate($product);
        if ($errors->count()) {
            throw new ValidatorException('Product data is not valid: ' . (string)$errors);
        }

        $entityManager->flush();
    }

    /**
     * Returns the product entity by its identifier
     *
     * @param int $id
     *
     * @return ProductInterface
     */
    protected function findProduct(int $id) : ProductInterface
    {
        $product = $this->repository->find($id);
        if (!$product instanceof ProductInterface) {
            throw new ProductNotFoundException($id);
        }

        return $product;
    }
}


<?php

/*
 * This file is part of the kaloa/util package.
 *
 * For full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

namespace Kaloa\Util\Tree;

use Closure;

/**
 * A simple tree structure
 *
 * There will always be a single distinct root node
 */
final class Node
{
    private $content  = null;
    private $children = array();
    private $parent   = null;

    public function __construct($value)
    {
        $this->content = $value;
    }

    public function addChild(Node $child)
    {
        $this->children[] = $child;
        $child->setParent($this);
    }

    public function hasChildren()
    {
        return (count($this->children) > 0);
    }

    public function setParent(Node $node)
    {
        $this->parent = $node;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function getChildren()
    {
        return $this->children;
    }

    public function getContent()
    {
        return $this->content;
    }

    /**
     * Displays all elements from a tree in hierarchic order
     *
     * @param int $level Current level of indentation
     */
    public function display($level = 0)
    {
        $value = $this->getContent();

        if (null === $value) {
            $value = 'null';
        } elseif (is_object($value)) {
            $value = get_class($value);
        } elseif (is_array($value)) {
            $value = 'Array';
        }

        $ret = str_repeat(' ', $level * 4) . $value . "\n";

        $children = $this->getChildren();

        foreach ($children as $child) {
            $ret .= $child->display($level + 1);
        }

        return $ret;
    }

    /**
     *
     * @param Closure $expr
     * @return array
     */
    public function getNodesByFilter(Closure $expr)
    {
        $nodes = array();

        foreach ($this->children as $child) {
            if ($expr($child->getContent())) {
                $nodes[] = $child;
            }

            foreach ($child->getNodesByFilter($expr) as $node) {
                $nodes[] = $node;
            }
        }

        return $nodes;
    }
}