<?php
namespace Zodream\Http;

/**
 * Created by PhpStorm.
 * User: zx648
 * Date: 2016/7/16
 * Time: 17:26
 */
use Traversable;
use IteratorAggregate;
use ArrayIterator;
use Zodream\Infrastructure\Base\ZObject;
use Zodream\Infrastructure\Http\Request;

class Header extends ZObject implements IteratorAggregate {

    const COOKIES_ARRAY = 'array';

    const COOKIES_FLAT = 'flat';

    protected $headers = array();

    protected $cacheControl = array();

    protected $cookies = array();
    /**
     * @var array
     */
    protected $headerNames = array();

    public function __construct() {
        if (!isset($this->headers['cache-control'])) {
            $this->set('Cache-Control', '');
        }
    }

    public function setCookie(
        $cookie,
        $value = null,
        $expire = 0,
        $path = '/',
        $domain = null,
        $secure = false,
        $httpOnly = true) {
        if (!$cookie instanceof Cookie) {
            $cookie = new Cookie(
                $cookie,
                $value,
                $expire,
                $path,
                $domain,
                $secure,
                $httpOnly
            );
        }
        $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
        return $this;
    }

    public function removeCookie($name, $path = '/', $domain = null) {
        if (null === $path) {
            $path = '/';
        }

        unset($this->cookies[$domain][$path][$name]);

        if (empty($this->cookies[$domain][$path])) {
            unset($this->cookies[$domain][$path]);

            if (empty($this->cookies[$domain])) {
                unset($this->cookies[$domain]);
            }
        }
        return $this;
    }

    /**
     * Returns an array with all cookies.
     *
     * @param string $format
     *
     * @throws \InvalidArgumentException When the $format is invalid
     *
     * @return Cookie[]
     */
    public function getCookies($format = self::COOKIES_FLAT) {
        if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
            throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
        }

        if (self::COOKIES_ARRAY === $format) {
            return $this->cookies;
        }

        $flattenedCookies = array();
        foreach ($this->cookies as $path) {
            foreach ($path as $cookies) {
                foreach ($cookies as $cookie) {
                    $flattenedCookies[] = $cookie;
                }
            }
        }

        return $flattenedCookies;
    }

    /**
     * Clears a cookie in the browser.
     *
     * @param string $name
     * @param string $path
     * @param string $domain
     * @param bool $secure
     * @param bool $httpOnly
     * @return Header
     */
    public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true) {
        return $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly));
    }

    public function __toString() {
        $cookies = '';
        foreach ($this->getCookies() as $cookie) {
            $cookies .= 'Set-Cookie: '.$cookie."\r\n";
        }

        ksort($this->headerNames);
        if (!$this->headers) {
            return $cookies;
        }

        $max = max(array_map('strlen', array_keys($this->headers))) + 1;
        $content = '';
        ksort($this->headers);
        foreach ($this->headers as $name => $values) {
            $name = implode('-', array_map('ucfirst', explode('-', $name)));
            foreach ($values as $value) {
                $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
            }
        }

        return $content.$cookies;
    }

    public function all() {
        return $this->headers;
    }

    /**
     * Returns the parameter keys.
     *
     * @return array An array of parameter keys
     */
    public function keys() {
        return array_keys($this->headers);
    }

    public function replace(array $headers = array()) {
        $this->headers = array();
        return $this->add($headers);
    }

    /**
     * Adds new headers the current HTTP headers set.
     *
     * @param array $headers An array of HTTP headers
     * @return $this
     */
    public function add(array $headers) {
        foreach ($headers as $key => $values) {
            $this->set($key, $values);
        }
        return $this;
    }

    public function get($key, $default = null, $first = true) {
        $key = $this->filterKey($key);

        if (!array_key_exists($key, $this->headers)) {
            if (null === $default) {
                return $first ? null : array();
            }

            return $first ? $default : array($default);
        }

        if ($first) {
            return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
        }

        return $this->headers[$key];
    }

    public function set($key, $values, $replace = true) {
        $key = $this->filterKey($key);

        $values = array_values((array) $values);

        if (true === $replace || !isset($this->headers[$key])) {
            $this->headers[$key] = $values;
        } else {
            $this->headers[$key] = array_merge($this->headers[$key], $values);
        }

        if ('cache-control' === $key) {
            $this->cacheControl = $this->parseCacheControl($values[0]);
        }
        return $this;
    }

    protected function filterKey($key) {
        $key = str_replace(['_', '-'], [' ', ' '], strtolower($key));
        return str_replace(' ', '-', ucwords($key));
    }

    public function has($key) {
        return array_key_exists(str_replace('_', '-', strtolower($key)), $this->headers);
    }

    public function delete($tag) {
        $tag = str_replace('_', '-', strtolower($tag));
        unset($this->headers[$tag]);
        if ('cache-control' === $tag) {
            $this->cacheControl = array();
        }
        return $this;
    }

    protected function parseCacheControl($header) {
        $cacheControl = array();
        preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
        foreach ($matches as $match) {
            $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
        }

        return $cacheControl;
    }

    public function setRedirect($url, $time = 0) {
        if (empty($url)) {
            return $this;
        }
        if (empty($time)) {
            return $this->set('Location', (string)$url);
        }
        return $this->set('Refresh', $time.';url='.$url);
    }

    public function setXPoweredBy($name = 'PHP/5.6.12') {
        return $this->set('X-Powered-By', $name);
    }

    /**
     * WEB服务器名称
     * @param string $name
     * @return Header
     */
    public function setServer($name = 'Apache') {
        return $this->set('Server', $name);
    }

    public function setContentLanguage($language = 'zh-CN') {
        return $this->set('Content-language', $language);
    }

    /**
     * md5校验值
     * @param string $md5
     * @return Header
     */
    public function setContentMD5($md5) {
        return $this->set('Content-MD5', $md5);
    }

    /**
     * 缓存控制
     * @param string $option 默认禁止缓存
     * @return Header
     */
    public function setCacheControl(
        $option = 'no-cache, no-store, max-age=0, must-revalidate') {
        return $this->set('Cache-Control', $option);
    }

    /**
     * 实现特定指令
     * @param string $option
     * @return Header
     */
    public function setPragma($option) {
        return $this->set('Pragma', $option);
    }

    /**
     * 如果实体不可取，指定时间重试
     * @param integer $time
     * @return Header
     */
    public function setRetryAfter($time) {
        return $this->set('Retry-After', $time);
    }

    /**
     * 原始服务器发出时间
     * @param integer $time
     * @return Header
     */
    public function setDate($time) {
        return $this->set('Date', gmdate('D, d M Y H:i:s', $time).' GMT');
    }

    /**
     * 响应过期的时间
     * @param integer $time
     * @return Header
     */
    public function setExpires($time) {
        return $this->set('Expires', gmdate('D, d M Y H:i:s', $time).' GMT');
    }

    /**
     * 最后修改时间
     * @param integer $time
     * @return Header
     */
    public function setLastModified($time) {
        return $this->set('Last-Modified', gmdate('D, d M Y H:i:s', $time).' GMT');
    }

    /**
     * 大小
     * @param int|string $length
     * @return Header
     */
    public function setContentLength($length) {
        return $this->set('Content-Length', $length);
    }

    /**
     * 文件流的范围
     * @param integer $length
     * @param string $type
     * @return Header
     */
    public function setContentRange($length, $type = 'bytes') {
        return $this->set('Content-Range', $type.' '.$length);
    }

    /**
     * 下载文件是指定接受的单位
     * @param string $type
     * @return Header
     */
    public function setAcceptRanges($type = 'bytes') {
        return $this->set('Accept-Ranges', $type);
    }

    /**
     * 下载文件的文件名
     * @param string $filename
     * @return Header
     * @throws \Exception
     */
    public function setContentDisposition($filename) {
        if (strpos(app('request')->server('HTTP_USER_AGENT'), 'MSIE') !== false) {     //如果是IE浏览器
            $filename = preg_replace('/\./', '%2e', $filename, substr_count($filename, '.') - 1);
        }
        return $this->set('Content-Disposition', 'attachment; filename="'.$filename.'"');
    }

    /**
     * 设置强迫客户端认证 根据后两个参数判断 Basic、 Digest
     * @param string $realm
     * @param string $qop
     * @param string $nonce
     * @param string $opaque
     * @return Header
     */
    public function setWWWAuthenticate($realm, $qop = 'auth', $nonce = null, $opaque = null) {
        if (empty($nonce) && empty($opaque)) {
            $content = sprintf('Basic realm="%s"', $realm);
        } else {
            $content = sprintf('Digest realm="%s" qop="%s" nonce="%s" opaque="%s"',
                $realm, $qop, $nonce, $opaque);
        }
        return $this->set('WWW-Authenticate', $content);
    }

    /**
     * 文件传输编码
     * @param string $encoding
     * @return Header
     */
    public function setTransferEncoding($encoding = 'chunked') {
        return $this->set('Transfer-Encoding', $encoding);
    }

    /**
     * ajax 跨域响应，默认允许跨域
     * @param string $allowedOrigins
     * @param string $allowedMethods
     * @param string $allowedHeaders
     * @param int $maxAge
     * @param bool $supportsCredentials
     * @return Header
     */
    public function setCORS(
        $allowedOrigins = '*',
        $allowedMethods = '*',
        $allowedHeaders = '*',//'Authorization, Content-Type, X-Requested-With',
        $maxAge = 0,
        $supportsCredentials = false) {
        return $this->add([
            'Access-Control-Allow-Origin' => $allowedOrigins,
            'Access-Control-Allow-Credentials' => $supportsCredentials,
            'Access-Control-Allow-Methods' => $allowedMethods,
            'Access-Control-Max-Age' => $maxAge,
            'Access-Control-Allow-Headers' => $allowedHeaders
        ]);
    }

    /**
     * HTTP2 server push
     * @param $url
     * @param $as
     * @param null $type
     * @param bool $crossorigin
     * @param bool $nopush
     * @return Header
     */
    public function setLink($url, $as, $type = null, $crossorigin = false, $nopush = false) {
        $args = [
            sprintf('<%s>', $url),
            'rel=preload',
            'as='.$as
        ];
        if (!empty($type)) {
            $args[] = 'type='.$type;
        }
        if ($crossorigin) {
            $args[] = 'crossorigin';
        }
        if ($nopush) {
            $args[] = 'nopush';
        }
        return $this->set('Link', implode('; ', $args));
    }

    /**
     * 返回内容的MIME类型
     * @param string $type
     * @param string $option
     * @return Header
     */
    public function setContentType($type = 'html', $option = 'utf-8') {
        $type = strtolower($type);
        if ($type == 'image' || $type == 'img') {
            return $this->set('Content-Type', 'image/'.$option);
        }
        static $args = array(
            'ai'    => 'application/postscript',
            'aif'   => 'audio/x-aiff',
            'aifc'  => 'audio/x-aiff',
            'aiff'  => 'audio/x-aiff',
            'apk'   => 'application/vnd.android.package-archive',
            'atom'  => 'application/atom+xml',
            'avi'   => 'video/x-msvideo',
            'bin'   => 'application/macbinary',
            'bmp'   => 'image/bmp',
            'cpt'   => 'application/mac-compactpro',
            'css'   => 'text/css',
            'csv'   => 'text/x-comma-separated-values',
            'dcr'   => 'application/x-director',
            'dir'   => 'application/x-director',
            'doc'   => 'application/msword',
            'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'dvi'   => 'application/x-dvi',
            'dxr'   => 'application/x-director',
            'eml'   => 'message/rfc822',
            'eps'   => 'application/postscript',
            'exe'   => 'application/octet-stream',
            'flv'   => 'video/x-flv',
            'flash' => 'application/x-shockwave-flash',
            'gif'   => 'image/gif',
            'gtar'  => 'application/x-gtar',
            'gz'    => 'application/x-gzip',
            'hqx'   => 'application/mac-binhex40',
            'htm'   => 'text/html',
            'html'  => 'text/html',
            'ipa'   => 'application/iphone',
            'jpe'   => 'image/jpeg',
            'jpeg'  => 'image/jpeg',
            'jpg'   => 'image/jpeg',
            'js'    => 'application/x-javascript',
            'json'  => 'application/json',
            'log'   => 'text/plain',
            'm3u8'  => 'application/x-mpegURL',
            'mid'   => 'audio/midi',
            'midi'  => 'audio/midi',
            'mif'   => 'application/vnd.mif',
            'mov'   => 'video/quicktime',
            'movie' => 'video/x-sgi-movie',
            'mp2'   => 'audio/mpeg',
            'mp3'   => 'audio/mpeg',
            'mp4'   => 'video/mpeg',
            'mpe'   => 'video/mpeg',
            'mpeg'  => 'video/mpeg',
            'mpg'   => 'video/mpeg',
            'mpga'  => 'audio/mpeg',
            'oda'   => 'application/oda',
            'pdf'   => 'application/pdf',
            'php'   => 'application/x-httpd-php',
            'php3'  => 'application/x-httpd-php',
            'php4'  => 'application/x-httpd-php',
            'phps'  => 'application/x-httpd-php-source',
            'phtml' => 'application/x-httpd-php',
            'plist' => 'application/xml',
            'png'   => 'image/png',
            'ppt'   => 'application/powerpoint',
            'ps'    => 'application/postscript',
            'psd'   => 'application/x-photoshop',
            'qt'    => 'video/quicktime',
            'ra'    => 'audio/x-realaudio',
            'ram'   => 'audio/x-pn-realaudio',
            'rm'    => 'audio/x-pn-realaudio',
            'rpm'   => 'audio/x-pn-realaudio-plugin',
            'rss'   => 'application/rss+xml',
            'rtf'   => 'text/rtf',
            'rtx'   => 'text/richtext',
            'rv'    => 'video/vnd.rn-realvideo',
            'shtml' => 'text/html',
            'sit'   => 'application/x-stuffit',
            'smi'   => 'application/smil',
            'smil'  => 'application/smil',
            'swf'   => 'application/x-shockwave-flash',
            'tar'   => 'application/x-tar',
            'tgz'   => 'application/x-tar',
            'text'  => 'text/plain',
            'tif'   => 'image/tiff',
            'tiff'  => 'image/tiff',
            'ts'    => 'video/MP2T',
            'txt'   => 'text/plain',
            'wav'   => 'audio/x-wav',
            'wbxml' => 'application/wbxml',
            'wmlc'  => 'application/wmlc',
            'word'  => 'application/msword',
            'xht'   => 'application/xhtml+xml',
            'xhtml' => 'application/xhtml+xml',
            'xl'    => 'application/excel',
            'xls'   => 'application/excel',
            'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'xml'   => 'text/xml',
            'xsl'   => 'text/xml',
            'zip'   => 'application/x-zip'
        );
        if (!array_key_exists($type, $args)) {
            return $this->set('Content-type', $type);
        }
        $content = $args[$type];
        if (in_array($type, array('html', 'json', 'rss', 'xml'))) {
            $content .= ';charset='.$option;
        }
        return $this->set('Content-Type', $content);
    }

    /**
     * Retrieve an external iterator
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
     * @return Traversable An instance of an object implementing Iterator or
     * Traversable
     * @since 5.0.0
     */
    public function getIterator() {
        return new ArrayIterator($this->all());
    }

    public function parse($args) {
        return $this->replace($args);
    }

    public function toArray() {
        return $this->all();
    }
}


<?php namespace RestGalleries\APIs;

use Illuminate\Support\Fluent;
use RestGalleries\Http\RequestAdapter;
use RestGalleries\Http\Guzzle\GuzzleRequest;
use RestGalleries\Interfaces\GalleryAdapter;
use RestGalleries\Interfaces\PhotoAdapter;

/**
 * Normalizes all <API>\Gallery classes under one single interface, and simplifies the reuse of public methods.
 */
abstract class ApiGallery implements GalleryAdapter
{
    /**
     * Url to the API REST. the base for all requests.
     *
     * @var string
     */
    protected $endPoint;

    /**
     * It will store the plugins of request client, such as cache and auth.
     *
     * @var array
     */
    protected $plugins = [];

    /**
     * Returns all galleries currently available on the photos service.
     *
     * @return array|null
     */
    public function all()
    {
        return $this->getGalleries();
    }

    /**
     * Fetch gallery ids, and iterate them to get every gallery from its id.
     * Returns an ArrayObject-type with all new galleries obtained,
     *
     * @return array|null
     */
    protected function getGalleries()
    {
        if (! is_null($ids = $this->fetchIds())) {
            return array_map([$this, 'getGallery'], $ids);
        }
    }

    /**
     * Makes the request to get all current ids of galleries as an array and returns them.
     *
     * @return array|null
     */
    abstract protected function fetchIds();

    /**
     * Returns a particular gallery.
     *
     * @param  string $id
     * @return \Illuminate\Support\Fluent|null
     */
    public function find($id)
    {
        return $this->getGallery($id);
    }

    /**
     * Fetch a gallery as array and returns a object ArrayAccess-type with that data.
     *
     * @param  string $id
     * @return \Illuminate\Support\Fluent|null
     */
    protected function getGallery($id)
    {
        if (! is_null($gallery = $this->fetchGallery($id))) {
            return new Fluent($gallery);
        }

    }

    /**
     * This function makes the request to get an particular gallery and returns its data as an array.
     *
     * @param  string $id
     * @return array|null
     */
    abstract protected function fetchGallery($id);

    /**
     * Object builder to create and use the Http request client.
     * In this case, is set up as default Guzzle Http client.
     *
     * @param  \RestGalleries\Http\RequestAdapter $request
     * @return \RestGalleries\Http\RequestAdapter
     */
    public function newRequest(RequestAdapter $request = null)
    {
        if (empty($request)) {
            $request = new GuzzleRequest;
        }

        $request = $request::init($this->endPoint);

        if (! empty($this->plugins)) {
            array_walk($this->plugins, [$request, 'addPlugin']);
        }

        return $request;

    }

    /**
     * Object builder to create and use the Photo model of a specific service.
     *
     * @param  \RestGalleries\Interfaces\PhotoAdapter $photo
     * @return \RestGalleries\Interfaces\PhotoAdapter
     */
    public function newPhoto(PhotoAdapter $photo = null)
    {
        if (empty($photo)) {
            $class = $this->getChildClassNamespace() . '\\Photo';
            $photo = new $class;
        }

        if (! empty($this->plugins)) {
            array_walk($this->plugins, [$photo, 'addPlugin']);
        }

        return $photo;

    }

    /**
     * Returns the namespace of the child class (without the class name).
     *
     * @return string
     */
    protected function getChildClassNamespace()
    {
        return get_class_namespace($this);
    }

    /**
     * Stores the request plugins to add them to the request client.
     *
     * @param  \RestGalleries\Http\Plugins\RequestPluginAdapter $plugin
     * @return void
     */
    public function addPlugin($plugin)
    {
        $this->plugins[] = $plugin;
    }

}


<?php
/**
 * This source file is part of Xloit project.
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the MIT License that is bundled with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * <http://www.opensource.org/licenses/mit-license.php>
 * If you did not receive a copy of the license and are unable to obtain it through the world-wide-web,
 * please send an email to <license@xloit.com> so we can send you a copy immediately.
 *
 * @license   MIT
 * @link      http://xloit.com
 * @copyright Copyright (c) 2016, Xloit. All rights reserved.
 */

namespace Xloit\Bridge\Doctrine\ORM\Query;

use Doctrine\ORM\Query\Expr as DoctrineExpr;

/**
 * An {@link Expr} class.
 *
 * @package Xloit\Bridge\Doctrine\ORM\Query
 */
class Expr extends DoctrineExpr
{
    /**
     * Creates an instance of range, with the given argument.
     *
     * @param mixed $val Valued to be inspected by range values.
     * @param int   $x   Starting range value to be used.
     * @param int   $y   End point value to be used.
     *
     * @return DoctrineExpr\Andx
     */
    public function range($val, $x, $y)
    {
        return $this->andX($this->gt($val, $x), $this->lt($val, $y));
    }

    /**
     * Creates an instance of NOT BETWEEN() function, with the given argument.
     *
     * @param mixed $val Valued to be inspected by range values.
     * @param int   $x   Starting range value to be used in BETWEEN() function.
     * @param int   $y   End point value to be used in BETWEEN() function.
     *
     * @return string A NOT BETWEEN expression.
     */
    public function notBetween($val, $x, $y)
    {
        return $val . ' NOT BETWEEN ' . $x . ' AND ' . $y;
    }
}


<?php namespace Ordercloud\Support\ExceptionGenerators;

use Illuminate\Container\Container;
use Ordercloud\Requests\Exceptions\OrdercloudRequestException;
use Ordercloud\Requests\OrdercloudRequest;
use Ordercloud\Support\Http\OrdercloudHttpException;

class ChainedExceptionGeneratorService implements ExceptionGeneratorService
{
    /**
     * @var ExceptionGenerator
     */
    private $chain;

    public function __construct(Container $container, array $generators)
    {
        $this->chain = $this->buildChain($container, $generators);
    }

    /**
     * @param OrdercloudRequest       $request
     * @param OrdercloudHttpException $exception
     *
     * @return OrdercloudRequestException
     */
    public function generateException(OrdercloudRequest $request, OrdercloudHttpException $exception)
    {
        return $this->chain->generateException($request, $exception);
    }

    /**
     * @param Container $container
     * @param array     $generators
     *
     * @return ExceptionGenerator
     */
    protected function buildChain(Container $container, array $generators)
    {
        $chainBuilder = ExceptionGeneratorBuilder::create();

        foreach ($generators as $generator) {
            $chainBuilder->chain($container->make($generator));
        }

        return $chainBuilder->getChain();
    }
}


<?php

namespace Behavior;

use Think\Behavior;

/**
 * 模板内容输出替换
 */
final class ContentReplaceBehavior extends Behavior
{

    /**
     * 执行入口
     *
     * @param mixed $content
     */
    public function run(&$content)
    {
        $content = $this->templateContentReplace($content);
    }

    /**
     * 模板内容替换

     *
     * @param string $content 模板内容
     *
     * @return string
     */
    protected function templateContentReplace($content)
    {
        // 系统默认的特殊变量替换
        $replace = [
            '__APP__'        => __APP__,        // 当前应用地址
            '__MODULE__'     => __MODULE__,
            '__ACTION__'     => __ACTION__,     // 当前操作地址
            '__SELF__'       => htmlentities(__SELF__),       // 当前页面地址
            '__CONTROLLER__' => __CONTROLLER__,
            '__URL__'        => __CONTROLLER__,
            '__PUBLIC__'     => '/Public',// 站点公共目录
        ];
        // 允许用户自定义模板的字符串替换
        if (is_array(C('TMPL_PARSE_STRING'))) {
            $replace = array_merge($replace, C('TMPL_PARSE_STRING'));
        }

        return str_replace(array_keys($replace), array_values($replace), $content);
    }

}


<?php
/*
 * This file is part of the Skeetr package.
 *
 * (c) Máximo Cuadros <mcuadros@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Skeetr\Runtime\Overrides;

use Skeetr\Runtime\Override;

/**
 * PHP impementation of session support functions
 *
 * Built-in functions:
 * [+] session_cache_expire — Return current cache expire
 * [+] session_cache_limiter — Get and/or set the current cache limiter
 * [+] session_commit — Alias of session_write_close
 * [+] session_decode — Decodes session data from a session encoded string
 * [+] session_destroy — Destroys all data registered to a session
 * [+] session_encode — Encodes the current session data as a session encoded string
 * [+] session_get_cookie_params — Get the session cookie parameters
 * [+] session_id — Get and/or set the current session id
 * [*] session_is_registered — Find out whether a global variable is registered in a session
 * [ ] session_module_name — Get and/or set the current session module
 * [=] session_name — Get and/or set the current session name
 * [+] session_regenerate_id — Update the current session id with a newly generated one
 * [*] session_register_shutdown — Session shutdown function
 * [*] session_register — Register one or more global variables with the current session
 * [=] session_save_path — Get and/or set the current session save path
 * [+] session_set_cookie_params — Set the session cookie parameters
 * [ ] session_set_save_handler — Sets user-level session storage functions
 * [+] session_start — Start new or resume existing session
 * [+] session_status — Returns the current session status
 * [*] session_unregister — Unregister a global variable from the current session
 * [+] session_unset — Free all session variables
 * [+] session_write_close — Write session data and end session
 *
 * [+] = Implemented [=] = Original [*] = Deprecated [ ] = TODO
 * @link http://www.php.net/manual/en/ref.session.php
 *
 * Built-in ini settings:
 * [ ] session.auto_start
 * [i] session.bug_compat_42
 * [i] session.bug_compat_warn
 * [+] session.cache_expire
 * [+] session.cache_limiter
 * [+] session.cookie_domain
 * [+] session.cookie_httponly
 * [+] session.cookie_lifetime
 * [+] session.cookie_path
 * [+] session.cookie_secure
 * [i] session.entropy_file
 * [i] session.entropy_length
 * [ ] session.gc_divisor
 * [ ] session.gc_maxlifetime
 * [ ] session.gc_probability
 * [?] session.hash_bits_per_character
 * [ ] session.hash_function
 * [+] session.name
 * [?] session.referer_check
 * [i] session.save_handler
 * [+] session.save_path
 * [i] session.serialize_handler
 * [?] session.use_cookies
 * [?] session.use_only_cookies
 * [?] session.use_trans_sid
 *
 * [+] = Used [i] = Ignored [?] = What? [ ] = TODO
 * @link http://www.php.net/manual/en/session.configuration.php
 *
 * TODO:
 * Implements gc
 * Generate correct ID's
 * Serialization session style
 * Save handlers
 */
class Session extends Override
{
    private static $started;
    private static $file;
    private static $id;
    private static $limiter;
    private static $handler;

    /**
     * Start new or resume existing session
     *
     * @link http://www.php.net/manual/en/function.session-start.php
     */
    final public static function session_start()
    {
        if ( self::$started ) trigger_error('Session already started', E_USER_WARNING);

        self::$started = true;

        if ( isset($_COOKIE[session_name()]) ) {
            self::$id = $_COOKIE[session_name()];
        } else {
            self::$id = uniqid();

            $config = self::session_get_cookie_params();
            Cookie::setcookie(
                session_name(), self::$id,
                $config['lifetime'], $config['path'], $config['domain'],
                $config['secure'], $config['httponly']
            );
        }

        if ( !$savePath = session_save_path() ) $savePath = sys_get_temp_dir();
        if ( !is_dir($savePath) ) mkdir($savePath, 0777);

        self::$file = sprintf('%s/sess_%s', $savePath, self::$id);

        if (self::$handler) {
            self::$handler->open($savePath, session_name());
            self::$handler->read(self::$id);
        }

        if ( file_exists(self::$file) ) {
            $data = file_get_contents(self::$file);
            session_decode($data);
        }

        return true;
    }

    /**
     * Update the current session id with a newly generated one
     *
     * @link http://www.php.net/manual/en/function.session-regenerate-id.php
     *
     * @param  boolean $delete_old_session (optional) Whether to delete the old associated session file or not.
     * @return boolean
     */
    final public static function session_regenerate_id($delete_old_session = false)
    {
        if ( !self::$started ) return false;

        if ( $delete_old_session ) self::session_destroy();
        else {
            self::$started = null;
            self::$file = null;
            self::$id = null;
        }

        if ( isset($_COOKIE[session_name()]) ) unset($_COOKIE[session_name()]);
        return self::session_start();
    }

    /**
     * Get and/or set the current session id
     *
     * @link http://www.php.net/manual/en/function.session-id.php
     *
     * @param  boolean $id (optional) If id is specified, it will replace the current session id.
     * @return string  returns the session id for the current session or the empty string ("") if there is no current session
     */
    final public static function session_id($id = null)
    {
        if ( $id ) self::$id = $id;
        return self::$id;
    }

    /**
     * Write session data and end session
     *
     * @link http://www.php.net/manual/en/function.session-write-close.php
     */
    final public static function session_write_close()
    {
        if ( !self::$started ) return;

        if (self::$handler) {
            self::$handler->write(self::$id, self::session_encode());
            self::$handler->close();
        }

        self::$started = false;
        file_put_contents(self::$file, self::session_encode());
    }

   /**
     * Free all session variables
     *
     * @link http://www.php.net/manual/en/function.session-unset.php
     */
    final public static function session_unset()
    {
        if ( !isset($_SESSION) ) return false;

        foreach ($_SESSION as $key => $value) {
            unset($_SESSION[$key]);
        }
    }

    /**
     * Returns the current session status
     *
     * @link http://www.php.net/manual/en/function.session-status.php
     *
     * @return integer PHP_SESSION_NONE if sessions are enabled, but none exists and PHP_SESSION_ACTIVE if sessions are enabled, and one exists.
     */
    final public static function session_status()
    {
        if ( self::$started ) return PHP_SESSION_ACTIVE;
        return PHP_SESSION_NONE;
    }

    /**
     * Destroys all data registered to a session
     *
     * @link http://www.php.net/manual/en/function.session-destroy.php
     *
     * @return boolean
     */
    final public static function session_destroy()
    {
        if ( !self::$started ) return false;
        self::reset();

        if ( file_exists(self::$file) ) unlink(self::$file);
        return true;
    }

    /**
     * Encodes the current session data as a session encoded string
     *
     * @todo implement standard PHP session serailization
     * @link http://www.php.net/manual/en/function.session-encode.php
     *
     * @return string Returns the contents of the current session encoded.
     */
    final public static function session_encode()
    {
        return serialize($_SESSION);
    }

    /**
     * Decodes session data from a session encoded string
     *
     * @link http://www.php.net/manual/en/function.session-decode.php
     * @todo implement standard PHP session serailization
     *
     * @param  string  $data The encoded data to be stored.
     * @return boolean
     */
    final public static function session_decode($data)
    {
        if ( !$values = unserialize($data) ) return false;
        foreach ($values as $key => $value) {
            $_SESSION[$key] = $value;
        }

        return true;
    }

    /**
     * Get the session cookie parameters
     *
     * @link http://www.php.net/manual/en/function.session-get-cookie-params.php
     *
     * @return array Returns an array with the current session cookie information
     */
    final public static function session_get_cookie_params()
    {
        return array(
            'lifetime' => (int) ini_get('session.cookie_lifetime'),
            'path' => ini_get('session.cookie_path'),
            'domain' => ini_get('session.cookie_domain'),
            'secure' => (boolean) ini_get('session.cookie_secure'),
            'httponly' => (boolean) ini_get('session.cookie_httponly')
        );
    }

    /**
     * Defines a cookie to be sent along with the rest of the HTTP headers.
     *
     * @link http://www.php.net/manual/en/function.session-set-cookie-params.php
     *
     * @param  integer $lifetime (optional) Lifetime of the session cookie, defined in seconds.
     * @param  string  $path     (optional) The path on the server in which the cookie will be available on.
     * @param  string  $domain   (optional) The domain that the cookie is available to.
     * @param  boolean $secure   (optional) Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client.
     * @param  boolean $httponly (optional) When TRUE the cookie will be made accessible only through the HTTP protocol.
     * @return boolean
     */
    final public static function session_set_cookie_params(
        $lifetime = null, $path = null, $domain = null,
        $secure = null, $httponly = null
    ) {
        if ( $lifetime !== null ) ini_set('session.cookie_lifetime', (int) $lifetime);
        if ( $path !== null ) ini_set('session.cookie_path', (string) $path);
        if ( $domain !== null ) ini_set('session.cookie_domain', (string) $domain);
        if ( $secure !== null ) ini_set('session.cookie_secure', (boolean) $secure);
        if ( $httponly !== null ) ini_set('session.cookie_httponly', (boolean) $httponly);
    }

    /**
     * Get and/or set the current cache limiter
     *
     * @todo review if this is working, looks like not.
     * @link http://www.php.net/manual/en/function.session-cache-limiter.php
     *
     * @param  string $cache_limiter (optional) If cache_limiter is specified, the name of the current cache limiter is changed to the new value.
     * @return string Returns the name of the current cache limiter.
     */
    final public static function session_cache_limiter($cache_limiter = null)
    {
        if( !$cache_limiter ) return ini_get('session.cache_limiter');
        ini_set('session.cache_limiter', $cache_limiter);

        return $cache_limiter;
    }

    /**
     * Return current cache expire
     *
     * @todo review if this is working.
     * @link http://www.php.net/manual/en/function.session-cache-expire.php
     *
     * @param  string $new_cache_expire (optional) If new_cache_expire is given, the current cache expire is replaced with new_cache_expire.
     * @return string Returns the current setting of session.cache_expire. The value returned should be read in minutes, defaults to 180.
     */
    final public static function session_cache_expire($new_cache_expire = null)
    {
        if( !$new_cache_expire ) return (int) ini_get('session.cache_expire');
        ini_set('session.cache_expire', (int) $new_cache_expire);

        return (int) $new_cache_expire;
    }

    /**
     * Return current cache expire
     *
     * @todo Make 5.3 version
     * @link http://www.php.net/manual/en/function.session-set-save-handler.php
     *
     * @param  SessionHandlerInterface $sessionhandler    An instance of a class implementing SessionHandlerInterface, such as SessionHandler, to register as the session handler. Since PHP 5.4 only.
     * @param  boolean                 $register_shutdown (optional) Register session_write_close() as a register_shutdown_function() function.
     * @return boolean
     */
    final public static function session_set_save_handler($sessionhandler, $register_shutdown = true)
    {
        self::$handler = $sessionhandler;
    }

    /**
     * {@inheritdoc}
     */
    public static function values()
    {
        return get_class_vars(get_called_class());
    }

    /**
     * {@inheritdoc}
     */
    public static function reset()
    {
        self::$started = null;
        self::$file = null;
        self::$id = null;
        self::session_unset();

        $_SESSION = array();
    }
}


<?php

namespace Reaction\Base;

/**
 * StaticInstanceTrait provides methods to satisfy [[StaticInstanceInterface]] interface.
 *
 * @see StaticInstanceInterface
 */
trait StaticInstanceTrait
{
    /**
     * @var static[] static instances in format: `[className => object]`
     */
    private static $_instances = [];

    /**
     * Returns static class instance, which can be used to obtain meta information.
     * @param bool $refresh whether to re-create static instance even, if it is already cached.
     * @return static class instance.
     */
    public static function instance($refresh = false)
    {
        $className = get_called_class();
        if ($refresh || !isset(self::$_instances[$className])) {
            self::$_instances[$className] = \Reaction::create($className);
        }
        return self::$_instances[$className];
    }
}


<?php
/**
 * Pacific NM (https://www.pacificnm.com)
 *
 * @link https://github.com/pacificnm/pacificnm-controller for the canonical source repository
 * @copyright Copyright (c) 20011-2016 Pacific NM USA Inc. (https://www.pacificnm.com)
 * @license https://github.com/pacificnm/pacificnm-controller/blob/master/LICENSE.md
 */
namespace Pacificnm\Controller\Form;

use Zend\Form\Form as ZendForm;
use Zend\InputFilter\InputFilterProviderInterface;
use Pacificnm\Controller\Entity\Entity;
use Pacificnm\Controller\Hydrator\Hydrator;
use Pacificnm\Module\Service\ServiceInterface as ModuleServiceInterface;

class Form extends ZendForm implements InputFilterProviderInterface
{

    /**
     *
     * @var ModuleServiceInterface
     */
    protected $moduleService;

    /**
     *
     * @param ModuleServiceInterface $moduleService
     * @param string $name
     * @param array $options
     */
    public function __construct(ModuleServiceInterface $moduleService, $name = 'controller-form', $options = array())
    {
        parent::__construct($name, $options);

        $this->setHydrator(new Hydrator(false));

        $this->setObject(new Entity());

        $this->moduleService = $moduleService;

        // controllerId
        $this->add(array(
            'name' => 'controllerId',
            'type' => 'hidden',
            'attributes' => array(
                'id' => 'controllerId'
            )
        ));

        // moduleId
        $this->add(array(
            'type' => 'Select',
            'name' => 'moduleId',
            'options' => array(
                'label' => 'Module:',
                'value_options' => $this->getModuleOptions()
            ),
            'attributes' => array(
                'class' => 'form-control',
                'id' => 'moduleId'
            )
        ));

        // controllerName
        $this->add(array(
            'name' => 'controllerName',
            'type' => 'Text',
            'options' => array(
                'label' => 'Controller Name:'
            ),
            'attributes' => array(
                'class' => 'form-control',
                'id' => 'controllerName'
            )
        ));

        // submit
        $this->add(array(
            'name' => 'submit',
            'type' => 'button',
            'attributes' => array(
                'value' => 'Submit',
                'id' => 'submit',
                'class' => 'btn btn-primary btn-flat'
            )
        ));
    }

    /**
     *
     * {@inheritdoc}
     *
     * @see \Zend\InputFilter\InputFilterProviderInterface::getInputFilterSpecification()
     */
    public function getInputFilterSpecification()
    {
        return array();
    }

    /**
     * gets module options for select
     *
     * @return NULL[]
     */
    protected function getModuleOptions()
    {
        $entitys = $this->moduleService->getAll(array(
            'pagination' => 'off'
        ));

        $options = array();

        foreach ($entitys as $entity) {
            $options[$entity->getModuleId()] = $entity->getModuleName();
        }

        return $options;
    }
}


<?php
/**
 * This file is part of the Maths package.
 *
 * Copyright (c) 2014-2016 Pierre Cassat <me@e-piwi.fr> and contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The source code of this package is available online at
 * <http://github.com/atelierspierrot/maths>.
 */

namespace Maths\Algebra;

/**
 * Class Matrix
 *
 * Bidimensional array representation of a matrix.
 * Each matrix's item is indexed like `x,y` with first item indexed `1,1` (1 based).
 *
 * ## Iterate over items: the `WALK_` flags
 *
 * When iterating over a matrix, you can use one of the three `WALK_` flags to have following behaviors:
 *
 * -    `WALK_X` to iterate over lines (each item is the current line array of cells)
 * -    `WALK_Y` to iterate over columns (each item is the current column array of cells)
 * -    `WALK_XY` to iterate over cells (each item is the current cell)
 *
 * The default behavior uses the `WALK_XY` flag.
 *
 * ## Array access: the `ARRAY_` flags
 *
 * When using a matrix by direct array access (e.g. `$martrix[index]`), you can use one of the
 * `ARRAY_` flags to have the following behaviors:
 *
 * -    `ARRAY_XY` to use `$index` like a bidimensional offset (e.g. `x,y`)
 * -    `ARRAY_INT` to use `$index` as an integer representation of each cell position (e.g. `1,3` would by `4`)
 *
 * Using the positional offsets, indexes can be written as:
 *
 * -    `int` to set a `x` index
 * -    `,int` to set an `y` index
 * -    `int,int` to set a `x,y` index
 *
 * Using the integer access, you MUST keep in mind that the indexes are 0 based:
 *
 *      position `1,1` is index `0`
 *      position `1,3` is index `4`
 *      position `2,4` is index `7` (with 4 cells per line)
 *
 * The "positional" indexing can be forced in all cases using explicitly a string index with `matrix['x']`.
 *
 * @author  piwi <me@e-piwi.fr>
 */
class Matrix
    implements ArrayAccess, SeekableIterator, Countable, Serializable
{

    /**
     * Use this constant to use array access with indexes as positions
     *
     * A position can be used as: `x`, `,y` or `x,y`
     */
    const ARRAY_XY     = 1;

    /**
     * Use this constant to use array access with indexes as integers
     */
    const ARRAY_INT    = 2;

    /**
     * Use this constant to loop over lines
     */
    const WALK_X       = 1;

    /**
     * Use this constant to loop over columns
     */
    const WALK_Y       = 2;

    /**
     * Use this constant to loop over cells
     */
    const WALK_XY      = 4;

    /**
     * Character used to identify a full positional index, here like `x,y`
     */
    const XY_SEPARATOR  = ',';

    /**
     * @var     int     Current value of object iterations flag
     */
    protected $_walk_flag       = null;

    /**
     * @var     int     Current value of object array accesses flag
     */
    protected $_array_flag      = null;

    /**
     * @var     array   Original array passed to constructor
     * @see     self::reset()
     */
    protected $_cache   = array();

    /**
     * @var     mixed   Value of an empty cell (on 'unset' and padding) ; default is '0'
     */
    protected $_empty_cell = 0;

    /**
     * @var     array   Current matrix sizes: `_size[x]` for lines, `_size[y]` for columns & `_size[c]` for cells
     */
    public $_size          = array('x'=>0, 'y'=>0, 'c'=>0);

    /**
     * @var     array   Current matrix values 2D array
     */
    public $data           = array();

    /**
     * @var     int     Current `x` index value 1 based
     */
    public $x              = null;

    /**
     * @var     int     Current `y` index value 1 based
     */
    public $y              = null;

    /**
     * MATRIX constructor
     *
     * Any missing item in a sub-array will be replaced by `$empty_cell`.
     *
     * @param   array   $data
     * @param   int     $walk_flag
     * @param   int     $array_flag
     * @param   mixed   $empty_cell
     * @throws  InvalidArgumentException if `$data` is not a 2D array
     */
    public function __construct(
        array $data = null, $walk_flag = self::WALK_XY, $array_flag = self::ARRAY_XY, $empty_cell = 0
    ) {
        $this->setWalkFlag($walk_flag);
        $this->setArrayFlag($array_flag);
        $this->setEmptyCell($empty_cell);
        if (!is_null($data)) {
            try {
                $this->setData($data);
            } catch (InvalidArgumentException $e) {
                throw $e;
            }
        }
    }

    /**
     * Magic method to `echo $object` which returns a 2D representation of the matrix
     *
     * @return  string
     */
    public function __toString()
    {
        $str = '';
        foreach ($this->data as $i=>$cell) {
            $str .= join(' ', $cell).PHP_EOL;
        }
        return $str;
    }

// Setters & Getters

    /**
     * Reset object `$data` to its original state
     */
    public function reset()
    {
        $this->data = $this->_cache;
        $this->rewindXY();
    }

    /**
     * Get the matrix size
     *
     * @param   string  $which
     * @return  int|array
     */
    public function getSize($which = null)
    {
        if (!empty($which)) {
            return (isset($this->_size[$which]) ? $this->_size[$which] : null);
        } else {
            return $this->_size;
        }
    }

    /**
     * Define the object's walk flag
     *
     * @param   int     $flag
     * @param   bool    $auto_rewind
     * @return  $this
     */
    public function setWalkFlag($flag, $auto_rewind = true)
    {
        $this->_walk_flag = $flag;
        if (true==$auto_rewind) {
            $this->rewindXY();
        }
        return $this;
    }

    /**
     * Get the current object's walk flag
     *
     * @return  int
     */
    public function getWalkFlag()
    {
        return $this->_walk_flag;
    }

    /**
     * Define the object's array access flag
     *
     * @param   int     $flag
     * @param   bool    $auto_rewind
     * @return  $this
     */
    public function setArrayFlag($flag, $auto_rewind = true)
    {
        $this->_array_flag = $flag;
        if (true==$auto_rewind) {
            $this->rewindXY();
        }
        return $this;
    }

    /**
     * Get the current object's array access flag
     *
     * @return  int
     */
    public function getArrayFlag()
    {
        return $this->_array_flag;
    }

    /**
     * Set the empty cell value
     *
     * @param   mixed     $cell
     * @return  $this
     */
    public function setEmptyCell($cell)
    {
        $this->_empty_cell = $cell;
        return $this;
    }

    /**
     * Get the empty cell value
     *
     * @return  mixed
     */
    public function getEmptyCell()
    {
        return $this->_empty_cell;
    }

    /**
     * Set the matrix contents
     *
     * @param   array   $data
     * @return  void
     * @throws  InvalidArgumentException if `$data` is not a 2D array
     */
    public function setData(array $data = null)
    {
        $line_length = $column_length = 0;
        foreach ($data as $x=>$items) {
            if (!is_array($items)) {
                throw new InvalidArgumentException(
                    "Data parameter of matrix must be a 2 dimensional array (array of arrays)!"
                );
            }
            if (count($items)>$line_length) {
                $line_length = count($items) - 1;
            }
            foreach ($items as $subitems) {
                if (count($subitems)>$column_length) {
                    $column_length = count($subitems) - 1;
                }
            }
        }
        $this->_size = array(
            'x' => $line_length,
            'y' => $column_length,
            'c' => ($line_length * $column_length)
        );
        foreach ($data as $x=>$items) {
            $this->data[$x] = $this->_padLine($items);
        }
        $this->_cache = $this->data;
    }

    /**
     * Get the matrix as array
     *
     * @return  array|Traversable
     */
    public function getData()
    {
        return $this->data;
    }

// Matrix Setters / Getters

    /**
     * Get a cell value by index according to matrix's flags
     *
     * @param   string|int     $index
     * @return  mixed|null
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     * @see     self::getX()
     * @see     self::getY()
     * @see     self::getXY()
     * @see     self::getInt()
     */
    public function get($index)
    {
        try {
            if (is_string($index)) {
                if ($this->getWalkFlag() & self::WALK_X) {
                    $ret = $this->getX($index);
                } elseif ($this->getWalkFlag() & self::WALK_Y) {
                    $ret = $this->getY($index);
                } else {
                    $ret = $this->getXY($index);
                }
            } else {
                $ret = $this->getInt($index);
            }
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $ret;
    }

    /**
     * Get `x` value (line) by index
     *
     * @param   string|int     $index
     * @return  array
     * @throws  OutOfRangeException if the index is out of range
     */
    public function getX($index)
    {
        try {
            $ret = $this
                ->seekX($index)
                ->currentX();
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $ret;
    }

    /**
     * Get `y` value (column) by index
     *
     * @param   string|int     $index
     * @return  array
     * @throws  OutOfRangeException if the index is out of range
     */
    public function getY($index)
    {
        try {
            $ret = $this
                ->seekY($index)
                ->currentY();
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $ret;
    }

    /**
     * Get `x:y` value (cell) by positional index
     *
     * @param   string|int     $index
     * @return  mixed
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function getXY($index)
    {
        try {
            $ret = $this
                ->seekXY($index)
                ->currentXY();
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $ret;
    }

    /**
     * Get `x:y` value (cell) by integer index
     *
     * @param   int     $index
     * @return  mixed
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function getInt($index)
    {
        try {
            $ret = $this
                ->seekInt($index)
                ->currentXY();
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $ret;
    }

    /**
     * Set a value by index according to matrix's flags
     *
     * @param   string|int   $index
     * @param   mixed        $value
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     * @see     self::setX()
     * @see     self::setY()
     * @see     self::setXY()
     * @see     self::setInt()
     */
    public function set($index, $value)
    {
        try {
            if (is_string($index)) {
                if ($this->getWalkFlag() & self::WALK_X) {
                    $this->setX($index, $value);
                } elseif ($this->getWalkFlag() & self::WALK_Y) {
                    $this->setY($index, $value);
                } else {
                    $this->setXY($index, $value);
                }
            } else {
                $this->setInt($index, $value);
            }
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Set `x` value (line) by index
     *
     * @param   string|int  $index
     * @param   array       $value
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     */
    public function setX($index, array $value)
    {
        try {
            $this->seekX($index);
            $this->data[$this->keyX(true)] = $value;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Set `y` value (column) by index
     *
     * @param   string|int  $index
     * @param   array       $value
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     */
    public function setY($index, array $value)
    {
        try {
            $this->seekY($index);
            foreach ($this->data as $x=>$items) {
                $this->data[$x][$this->keyY(true)] = $value[$x];
            }
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Set `x:y` value (cell) by positional index
     *
     * @param   string      $index
     * @param   mixed       $value
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function setXY($index, $value)
    {
        try {
            $this->seekXY($index);
            $this->data[$this->keyX(true)][$this->keyY(true)] = $value;
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Set `x:y` value (cell) by integer index
     *
     * @param   int      $index
     * @param   mixed    $value
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function setInt($index, $value)
    {
        try {
            $this->seekInt($index);
            $this->data[$this->keyX(true)][$this->keyY(true)] = $value;
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

// Iterator Interface

    /**
     * Rewind a matrix according to its flag value
     *
     * @return  $this
     * @see     self::rewindX()
     * @see     self::rewindY()
     * @see     self::rewindXY()
     */
    public function rewind()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->rewindX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->rewindY();
        } else {
            return $this->rewindXY();
        }
    }

    /**
     * Rewind `x` index to position `1`
     *
     * @return  $this
     */
    public function rewindX()
    {
        $this->x = 1;
        return $this;
    }

    /**
     * Rewind `y` index to position `1`
     *
     * @return  $this
     */
    public function rewindY()
    {
        $this->y = 1;
        return $this;
    }

    /**
     * Rewind both `x` and `y` indexes to position `1,1`
     *
     * @return  $this
     */
    public function rewindXY()
    {
        $this->x = 1;
        $this->y = 1;
        return $this;
    }

    /**
     * Go to previous index according to matrix's flag value
     *
     * @return  $this
     * @see     self::previousX()
     * @see     self::previousY()
     * @see     self::previousXY()
     */
    public function previous()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->previousX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->previousY();
        } else {
            return $this->previousXY();
        }
    }

    /**
     * Seek to current `x` less 1
     *
     * @return  $this
     */
    public function previousX()
    {
        if ($this->previousXExists()) {
            $this->seekX($this->keyX()-1);
        } else {
            $this->x = null;
        }
        return $this;
    }

    /**
     * Test if current `x` less 1 exists
     *
     * @return  bool
     */
    public function previousXExists()
    {
        return (($this->keyX()-1)>0);
    }

    /**
     * Seek to current `y` less 1
     *
     * @return  $this
     */
    public function previousY()
    {
        if ($this->previousYExists()) {
            $this->seekY($this->keyY()-1);
        } else {
            $this->y = null;
        }
        return $this;
    }

    /**
     * Test if current `y` less 1 exists
     *
     * @return  bool
     */
    public function previousYExists()
    {
        return (($this->keyY()-1)>0);
    }

    /**
     * Seek to previous cell
     *
     * @return  $this
     */
    public function previousXY()
    {
        if (($this->keyY()-1)>0) {
            $this->seekY($this->keyY()-1);
        } else {
            if (($this->keyX()-1)>0) {
                $this->rewindY();
                $this->seekX($this->keyX()-1);
            } else {
                $this->x = null;
                $this->y = null;
            }
        }
        return $this;
    }

    /**
     * Go to next index according to matrix's flag value
     *
     * @return  $this
     * @see     self::nextX()
     * @see     self::nextY()
     * @see     self::nextXY()
     */
    public function next()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->nextX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->nextY();
        } else {
            return $this->nextXY();
        }
    }

    /**
     * Seek to current `x` plus 1
     *
     * @return  $this
     */
    public function nextX()
    {
        if ($this->nextXExists()) {
            $this->seekX($this->keyX()+1);
        } else {
            $this->x = null;
        }
        return $this;
    }

    /**
     * Test if current `x` plus 1 exists
     *
     * @return  bool
     */
    public function nextXExists()
    {
        return (($this->keyX()+1)<=$this->countX());
    }

    /**
     * Seek to current `y` plus 1
     *
     * @return  $this
     */
    public function nextY()
    {
        if ($this->nextYExists()) {
            $this->seekY($this->keyY()+1);
        } else {
            $this->y = null;
        }
        return $this;
    }

    /**
     * Test if current `y` plus 1 exists
     *
     * @return  bool
     */
    public function nextYExists()
    {
        return (($this->keyY()+1)<=$this->countY());
    }

    /**
     * Go to next cell
     *
     * @return  $this
     */
    public function nextXY()
    {
        if (($this->keyY()+1)<=$this->countY()) {
            $this->seekY($this->keyY()+1);
        } else {
            if (($this->keyX()+1)<=$this->countX()) {
                $this->rewindY();
                $this->seekX($this->keyX()+1);
            } else {
                $this->x = null;
                $this->y = null;
            }
        }
        return $this;
    }

    /**
     * Seek to index according to matrix's flag value
     *
     * @param   string  $index
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function seek($index)
    {
        try {
            if ($this->getWalkFlag() & self::WALK_X) {
                return $this->seekX($index);
            } elseif ($this->getWalkFlag() & self::WALK_Y) {
                return $this->seekY($index);
            } else {
                return $this->seekXY($index);
            }
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
    }

    /**
     * Seek to index for `x` (line)
     *
     * @param   int  $index
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     */
    public function seekX($index)
    {
        if ($index>0 && $index<=$this->countX()) {
            $this->x = $index;
        } else {
            throw new OutOfRangeException(
                "Index '{$index}' for scope 'x' is out of range of available data"
            );
        }
        return $this;
    }

    /**
     * Seek to index for `y` (column)
     *
     * @param   int  $index
     * @return  $this
     * @throws  OutOfRangeException if the index is out of range
     */
    public function seekY($index)
    {
        if ($index>0 && $index<=$this->countY()) {
            $this->y = $index;
        } else {
            throw new OutOfRangeException(
                "Index '{$index}' for scope 'y' is out of range of available data"
            );
        }
        return $this;
    }

    /**
     * Seek to index for `x,y` (cell)
     *
     * @param   string  $index  The index to go to, constructed like `x,y`
     * @return  $this
     * @throws  OutOfRangeException if the `x` index is out of range
     * @throws  OutOfRangeException if the `y` index is out of range
     * @throws  InvalidArgumentException if the argument is malformed
     */
    public function seekXY($index)
    {
        $parts = explode(self::XY_SEPARATOR, $index);
        if (false==strpos($index, self::XY_SEPARATOR) || count($parts)>2) {
            throw new InvalidArgumentException(
                sprintf("Cell index of a matrix must be set as 'x%sy'", self::XY_SEPARATOR)
            );
        }
        try {
            $this->seekX($parts[0]);
            $this->seekY($parts[1]);
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Go to index `x,y` represented as an integer (0 based)
     *
     * @param   int     $index
     * @return  $this
     * @throws  InvalidArgumentException if the argument is not an integer
     * @throws  OutOfRangeException if the integer is out of matrix's range
     */
    public function seekInt($index)
    {
        if (!is_integer($index)) {
            throw new InvalidArgumentException(
                sprintf("Cell index of a matrix for integer access must be an integer (%s given)", gettype($index))
            );
        }
        $line = $this->keyX();
        $cell = $this->keyY();
        $_index = $index + 1;
        if ($_index==1) {
            $line = 1;
            $cell = 1;
        } elseif ($_index==$this->countXY()) {
            $line = $this->countX();
            $cell = $this->countY();
        } elseif ($_index>0 && $_index<$this->countXY()) {
            if ($_index>$this->countX()) {
                $line = round(($index / $this->countX()), 0, PHP_ROUND_HALF_EVEN);
            } else {
                $line = 1;
            }
            $cell = $_index - (($line - 1) * $this->countY());
            if ($cell==($this->countY()+1)) {
                $line++;
                $cell = 1;
            }
        } else {
            throw new OutOfRangeException(
                "Index '{$index}' (as integer) is out of range of available data"
            );
        }
        $this->seekXY($line.self::XY_SEPARATOR.$cell);
        return $this;
    }

    /**
     * Get current value according to matrix's flag value
     *
     * @return  mixed|null
     * @see     self::currentX()
     * @see     self::currentY()
     * @see     self::currentXY()
     */
    public function current()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->currentX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->currentY();
        } else {
            return $this->currentXY();
        }
    }

    /**
     * Get current `x` value (line)
     *
     * @return array|null
     */
    public function currentX()
    {
        return ($this->validX() ? $this->data[$this->keyX(true)] : null);
    }

    /**
     * Get current `y` value (column)
     *
     * @return array|null
     */
    public function currentY()
    {
        $col = array();
        foreach ($this->data as $x=>$items) {
            $col[$x] = (isset($items[$this->keyY(true)]) ? $items[$this->keyY(true)] : null);
        }
        return $col;
    }

    /**
     * Get current `x:y` value (cell)
     *
     * @return mixed|null
     */
    public function currentXY()
    {
        return ($this->validXY() ? $this->data[$this->keyX(true)][$this->keyY(true)] : null);
    }

    /**
     * Get current index according to matrix's flag value
     *
     * @return  string|null
     * @see     self::keyX()
     * @see     self::keyY()
     * @see     self::keyXY()
     */
    public function key()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->keyX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->keyY();
        } else {
            return $this->keyXY();
        }
    }

    /**
     * Get current `x` index (line)
     *
     * @param   bool    $integer    Return an integer index (0 based) or a positional one (1 based)
     * @return  int|null
     */
    public function keyX($integer = false)
    {
        return ($integer==true ? ($this->x -1) : $this->x);
    }

    /**
     * Get current `y` index (column)
     *
     * @param   bool    $integer    Return an integer index (0 based) or a positional one (1 based)
     * @return  int|null
     */
    public function keyY($integer = false)
    {
        return ($integer==true ? ($this->y -1) : $this->y);
    }

    /**
     * Get current `x,y` index (cell)
     *
     * @param   bool    $integer    Return an integer index (0 based) or a positional one (1 based)
     * @return  string|null
     */
    public function keyXY($integer = false)
    {
        if ($integer==true) {
            return $this->keyInt();
        }
        return $this->x.self::XY_SEPARATOR.$this->y;
    }

    /**
     * Get current `x,y` index as an integer (0 based)
     *
     * @return  int
     */
    public function keyInt()
    {
        return ((($this->keyX() - 1) * $this->countY()) + $this->keyY() - 1);
    }

    /**
     * Test if current value is valid according to matrix's flag value
     *
     * @return  bool
     * @see     self::validX()
     * @see     self::validY()
     * @see     self::validXY()
     */
    public function valid()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->validX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->validY();
        } else {
            return $this->validXY();
        }
    }

    /**
     * Test if current `x` line is valid
     *
     * @return  bool
     */
    public function validX()
    {
        return (bool) (!is_null($this->keyX()) && isset($this->data[$this->keyX(true)]));
    }

    /**
     * Test if current `y` column is valid
     *
     * @return  bool
     */
    public function validY()
    {
        return (bool) ($this->validX() && !is_null($this->keyY()) && isset($this->data[$this->keyX(true)][$this->keyY(true)]));
    }

    /**
     * Test if current `x:y` cell is valid
     *
     * @return  bool
     */
    public function validXY()
    {
        return (bool) ($this->validX() && $this->validY());
    }

// Countable Interface

    /**
     * Count the number of values according to matrix's flag value
     *
     * @return  int
     * @see     self::countX()
     * @see     self::countY()
     * @see     self::countXY()
     */
    public function count()
    {
        if ($this->getWalkFlag() & self::WALK_X) {
            return $this->countX();
        } elseif ($this->getWalkFlag() & self::WALK_Y) {
            return $this->countY();
        } else {
            return $this->countXY();
        }
    }

    /**
     * Count the number of lines
     *
     * @return  int
     */
    public function countX()
    {
        return count($this->currentY());
    }

    /**
     * Count the number of columns
     *
     * @return  int
     */
    public function countY()
    {
        return count($this->currentX());
    }

    /**
     * Count the number of cells
     *
     * @return  int
     */
    public function countXY()
    {
        return ($this->countX() * $this->countY());
    }

// ArrayAccess Interface

    /**
     * Seek `x` and `y` to an offset
     *
     * @param   int/string   $offset
     * @return  $this
     * @throws  OutOfRangeException if the offset is out of range of matrix's indexes
     */
    public function seekToOffset($offset)
    {
        try {
            if (($this->getArrayFlag() & self::ARRAY_INT) && !is_string($offset)) {
                return $this->seekToOffsetInteger($offset);
            } else {
                return $this->seekToOffsetPositional($offset);
            }
        } catch (OutOfRangeException $e) {
            throw $e;
        }
    }

    /**
     * Seek `x` and `y` to an integer offset
     *
     * @param   int   $offset
     * @return  $this
     * @throws  OutOfRangeException if the offset is out of range of matrix's indexes
     */
    public function seekToOffsetInteger($offset)
    {
        $indexes = explode(self::XY_SEPARATOR, $offset);
        try {
            if (count($indexes)==2) {
                if ($indexes[0]=='') {
                    $this->seekY($indexes[1]);
                } else {
                    $this->seekXY($offset);
                }
            } else {
                $this->seekX($offset);
            }
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Seek `x` and `y` to a positional offset
     *
     * Offsets can be written as:
     *
     * -    `int` to set a `x` index
     * -    `,int` to set an `y` index
     * -    `int,int` to set a `x,y` index
     *
     * @param   int/string   $offset
     * @return  $this
     * @throws  OutOfRangeException if the offset is out of range of matrix's indexes
     */
    public function seekToOffsetPositional($offset)
    {
        $indexes = explode(self::XY_SEPARATOR, $offset);
        try {
            if (count($indexes)==2) {
                if ($indexes[0]=='') {
                    $this->seekY($indexes[1]);
                } else {
                    $this->seekXY($offset);
                }
            } else {
                $this->seekX($offset);
            }
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this;
    }

    /**
     * Test if an offset exists
     *
     * @param   int/string   $offset
     * @return  bool
     */
    public function offsetExists($offset)
    {
        try {
            $res = $this
                ->seekToOffset($offset)
                ->valid();
        } catch (OutOfRangeException $e) {
            $res = false;
        }
        return (bool) $res;
    }

    /**
     * Get an offset value
     *
     * @param   int/string   $offset
     * @return  mixed
     * @throws  Triggers a NOTICE message if the offset is out of range
     */
    public function offsetGet($offset)
    {
        try {
            $res = $this
                ->seekToOffset($offset)
                ->current();
        } catch (OutOfRangeException $e) {
            $res = null;
            trigger_error("Undefined offset: '$offset'", E_USER_NOTICE);
        }
        return $res;
    }

    /**
     * Set an offset value
     *
     * @param   int/string   $offset
     * @param   mixed       $value
     * @return  $this
     * @throws  Triggers a NOTICE message if the offset is out of range
     */
    public function offsetSet($offset, $value)
    {
        try {
            $this
                ->seekToOffset($offset)
                ->setInt($this->keyInt(), $value);
        } catch (OutOfRangeException $e) {
            trigger_error("Undefined offset: '$offset'", E_USER_NOTICE);
        }
        return $this;
    }

    /**
     * Unset an offset value (replacing it by '0')
     *
     * @param   int/string   $offset
     * @return  $this
     * @throws  Triggers a NOTICE message if the offset is out of range
     */
    public function offsetUnset($offset)
    {
        try {
            $this
                ->seekToOffset($offset)
                ->setInt($this->keyInt(), $this->getEmptyCell());
        } catch (OutOfRangeException $e) {
            trigger_error("Undefined offset: '$offset'", E_USER_NOTICE);
        }
        return $this;
    }

// Serializable Interface

    /**
     * Serialize a matrix: only `$data`, `$_cache` and `$flag` are stored
     *
     * @return string
     */
    public function serialize()
    {
        return serialize(array(
            'data'          =>$this->getData(),
            '_cache'        =>$this->_cache,
            '_walk_flag'     =>$this->getWalkFlag(),
            '_array_flag'    =>$this->getArrayFlag()
        ));
    }

    /**
     * Populate a matrix from a serialized array: only `$data`, `$_cache` and `$flag` are populated
     *
     * @param   string  $serialized
     * @return  void
     */
    public function unserialize($serialized)
    {
        $obj = unserialize($serialized);
        $this->data = $obj['data'];
        $this->_cache = $obj['_cache'];
        $this->setWalkFlag($obj['_walk_flag']);
        $this->setArrayFlag($obj['_array_flag']);
    }

// Lines & Columns

    /**
     * Get a line value (specifying an optional index)
     *
     * @param   int    $index
     * @return  array|null
     * @throws  OutOfRangeException
     */
    public function getLine($index = null)
    {
        if (is_null($index)) {
            $index = $this->keyX();
        }
        try {
            $this->seekX($index);
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this->currentX();
    }

    /**
     * Get a column value (specifying an optional index)
     *
     * @param   int    $index
     * @return  array|null
     * @throws  OutOfRangeException
     */
    public function getColumn($index = null)
    {
        if (is_null($index)) {
            $index = $this->keyY();
        }
        try {
            $this->seekY($index);
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this->currentY();
    }

    /**
     * Get a cell value (specifying an optional index)
     *
     * @param   string    $index
     * @return  mixed|null
     * @throws  OutOfRangeException
     * @throws  InvalidArgumentException
     */
    public function getCell($index = null)
    {
        if (is_null($index)) {
            $index = $this->keyXY();
        }
        try {
            $this->seekXY($index);
        } catch (InvalidArgumentException $e) {
            throw $e;
        } catch (OutOfRangeException $e) {
            throw $e;
        }
        return $this->current();
    }

// Specials

    /**
     * Test if a matrix is a square (number of lines = number of columns)
     *
     * @return bool
     */
    public function isSquareMatrix()
    {
        return (bool) ($this->countX()===$this->countY());
    }

    /**
     * Test if a matrix is a row vector (one single line)
     *
     * @return bool
     */
    public function isRowVector()
    {
        return (bool) ($this->countX()===1);
    }

    /**
     * Test if a matrix is a column vector (one single column)
     *
     * @return bool
     */
    public function isColumnVector()
    {
        return (bool) ($this->countY()===1);
    }

// Internals

    /**
     * @param   array $line
     * @return  array
     */
    protected function _padLine(array $line)
    {
        return array_pad($line, $this->getSize('x'), $this->getEmptyCell());
    }

    /**
     * @param   array $col
     * @return  array
     */
    protected function _padColumn(array $col)
    {
        return array_pad($col, $this->getSize('y'), $this->getEmptyCell());
    }

    /**
     * Special `__toString()` with infos
     *
     * @param   string  $property   An object variable to debug: x, y, xy, line, column, cell, flag or matrix (default)
     * @param   bool    $verbose    Include some info about current matrix
     * @return  string
     */
    public function __debug($property = null, $verbose = false)
    {
        $str = '';
        switch ($property) {
            case 'x':
                if ($verbose) {
                    $str .= "current 'x' index is: ";
                }
                $str .= $this->keyX();
                break;
            case 'y':
                if ($verbose) {
                    $str .= "current 'y' index is: ";
                }
                $str .= $this->keyY();
                break;
            case 'xy':
                if ($verbose) {
                    $str .= "current 'xy' index is: ";
                }
                $str .= $this->keyXY();
                break;
            case 'line':
                if ($verbose) {
                    $str .= "current line is: ";
                }
                $str .= $this->currentX();
                break;
            case 'column':
                if ($verbose) {
                    $str .= "current column is: ";
                }
                $str .= $this->currentY();
                break;
            case 'cell':
                if ($verbose) {
                    $str .= "current cell is: ";
                }
                $str .= $this->currentXY();
                break;
            case '_walk_flag':
                if ($verbose) {
                    $str .= "current walking flag is: "
                        .$this->getWalkFlag()
                        .' ('.(($this->getWalkFlag() & self::WALK_X) ? 'X' : (($this->getWalkFlag() & self::WALK_Y) ? 'Y' : 'XY')).')';
                } else {
                    $str .= $this->getWalkFlag();
                }
                break;
            case '_array_flag':
                if ($verbose) {
                    $str .= "current array access flag is: "
                        .$this->getArrayFlag()
                        .' ('.((($this->getArrayFlag() & self::ARRAY_INT) ? 'INT' : 'XY')).')';
                } else {
                    $str .= $this->getArrayFlag();
                }
                break;
            case 'matrix': default:
            if ($verbose) {
                $str .= "matrix of {$this->countX()} lines & {$this->countY()} columns"
                    ." ({$this->countXY()} cells)"
                    .PHP_EOL."walking flag is ".(($this->getWalkFlag() & self::WALK_X) ? 'X' : (($this->getWalkFlag() & self::WALK_Y) ? 'Y' : 'XY'))
                    .PHP_EOL."array access flag is ".(($this->getArrayFlag() & self::ARRAY_INT) ? 'INT' : 'XY')
                    .PHP_EOL."----------------".PHP_EOL;
            }
            foreach ($this->data as $x=>$cell) {
                foreach ($cell as $y=>$val) {
                    $str .= '['.($x+1).self::XY_SEPARATOR.($y+1).']'.$val.' ';
                }
                $str .= PHP_EOL;
            }
            break;
        }
        return $str;
    }
}


<?php
namespace FzyCommon\Service\Search;

use FzyCommon\Exception\Search\InvalidResultOffset;
use FzyCommon\Exception\Search\NoResultsToGet;
use FzyCommon\Exception\Search\NotFound;
use FzyCommon\Service\Base as BaseService;
use FzyCommon\Util\Page;
use FzyCommon\Util\Params;
use FzyCommon\Entity\BaseInterface;

abstract class Base extends BaseService implements ResultProviderInterface
{
    /**
     * @var int
     */
    protected $total;

    /**
     * @var int
     */
    protected $limit;

    /**
     * @var int
     */
    protected $offset;

    /**
     * @var array
     */
    protected $results;

    protected $drawNumber;

    /**
     * Resets any params or results currently in this object
     *
     * @return $this
     */
    public function reset()
    {
        unset($this->results);
        unset($this->drawNumber);

        return $this;
    }

    /**
     * Main lifecycle of this service;
     * Using the passed in $params value
     * @param  Params $params
     * @param  bool   $asEntity - keep result as entity
     * @return $this
     */
    public function search(Params $params, $asEntity = false)
    {
        // hook to prepare for search
        $this->prepareSearch($params);

        // set limit/offset
        $this->setMetaData($params);

        if ($this->isSingular($params)) {
            try {
                $result = array($this->identitySearch($params));
                $this->setTotal(1);
            } catch (NotFound $e) {
                // nothing found
                $result = array();
                $this->setTotal(0);
            }
        } else {
            $result = $this->querySearch($params);
        }

        $this->preProcess($params, $result);
        $processed = array();
        foreach ($result as $entity) {
            $processed[] = $this->process($entity, $params, $result, $asEntity);
        }

        $this->postProcess($params, $result, $processed);
        $this->results = $processed;

        return $this;
    }

    /**
     * @param  Param                                $params
     * @return \FzyCommon\Entity\BaseInterface
     * @throws \FzyCommon\Exception\Search\NotFound
     */
    public function identitySearch(Params $params)
    {
        if ($params->get($this->getIdParam()) == null) {
            throw new NotFound('Unable to locate this entity');
        }

        return $this->find($params->get($this->getIdParam()));
    }

    /**
     * This function is a hook which allows any inheriting class
     * to perform necessary setup functions before the singular/query
     * search is performed
     * @param Params $params
     */
    protected function prepareSearch(Params $params)
    {
    }

    /**
     * Returns whether, based on the Param values
     * the
     * @param  Params $params
     * @return bool
     */
    protected function isSingular(Params $params)
    {
        return $params->has($this->getIdParam());
    }

    /**
     * This function should return the value of
     * the param name used to identify this search class' repository
     *
     * Eg: if this is a User subclass, $this->getIdParam() ought to return 'userId'
     * so the param array can check if 'userId' was set and therefore
     * indicate a lookup rather than a general search
     *
     * @return mixed
     */
    abstract protected function getIdParam();

    /**
     * Performs a query based on the params for a collection
     * of objects to be returned. This function ought to
     * set the $total value
     * @param  Param              $params
     * @return array|\Traversable
     */
    abstract protected function querySearch(Params $params);

    /**
     * Sets the limit/offset metadata
     * @param  Params $params
     * @return $this
     */
    protected function setMetaData(Params $params)
    {
        $this->setLimit(Page::limit($params));
        $this->setOffset(Page::offset($params));
        $this->drawNumber = $params->get('draw');

        return $this;
    }

    /**
     * This function is a hook which allows any inheriting class
     * to perform necessary setup functions after the singular/query
     * search is performed, and before the results are processed
     * individually
     * @param Param              $params
     * @param array|\Traversable $result
     */
    protected function preProcess(Params $params, $result)
    {
    }

    /**
     * This is invoked on every result of the singular/query
     * search for uniformly transform the result set
     * @param $entity
     * @param  Param              $params
     * @param  array|\Traversable $results
     * @param  bool               $asEntity - Keep entity as entity
     * @return $entity
     */
    protected function process($entity, Params $params, $results, $asEntity = false)
    {
        return $asEntity ? $entity : (string) $entity;
    }

    /**
     * This function is a hook which allows any inheriting class
     * to perform necessary teardown/cleanup functions after the
     * singular/query search results have been processed
     * @param Param              $params
     * @param array|\Traversable $result
     * @param array              $processed
     */
    protected function postProcess(Params $params, $result, array $processed)
    {
    }

    /**
     * Finds an element in this domain which has the specified ID
     *
     * @param $id
     * @return BaseInterface
     * @throws \FzyCommon\Exception\Search\NotFound
     */
    abstract public function find($id);

    /**
     * Get the resulting set that matches the search
     * @return array|\Traversable
     */
    public function getResults()
    {
        return $this->results;
    }

    /**
     * Convenience method for retrieving a single result (defaults to return the first)
     * @param  int                                             $offset
     * @return mixed
     * @throws \FzyCommon\Exception\Search\NoResultsToGet
     * @throws \FzyCommon\Exception\Search\InvalidResultOffset
     */
    public function getResult($offset = 0)
    {
        if (!is_array($this->results)) {
            throw new NoResultsToGet('No results have been generated');
        }
        if (!isset($this->results[$offset])) {
            throw new InvalidResultOffset("Unable to get result at offset '$offset'");
        }

        return $this->results[$offset];
    }

    /**
     * Get the current page's limit
     * @return int
     */
    public function getLimit()
    {
        return $this->limit;
    }

    /**
     * @param $limit
     * @return $this
     */
    public function setLimit($limit)
    {
        $this->limit = $limit;

        return $this;
    }

    /**
     * Get the current page's offset
     * @return int
     */
    public function getOffset()
    {
        return $this->offset;
    }

    /**
     * @param $offset
     * @return $this
     */
    public function setOffset($offset)
    {
        $this->offset = $offset;

        return $this;
    }

    /**
     * Returns the reported total number of results available
     * @return int
     */
    public function getTotal()
    {
        return $this->total;
    }

    /**
     * @param $total
     * @return $this
     */
    public function setTotal($total)
    {
        $this->total = $total;

        return $this;
    }

    /**
     * Returns an identifying name for this type of search
     * (so pages with multiple paginated data sets can generate events
     * about this data set being updated/modified)
     * @return string
     */
    abstract public function getResultTag();

    /**
     * For use with datatables
     * @return int
     */
    public function getDrawNumber()
    {
        return $this->drawNumber;
    }
}


<?php

/**
 * Class Boolean.
 *
 * @author Jeremie Litzler
 * @copyright Copyright (c) 2015
 * @licence http://opensource.org/licenses/gpl-license.php GNU Public License
 * @link https://github.com/Puzzlout/Objects
 * @since Version 1.0.0
 * @package Boolean
 * @see http://php.net/manual/en/language.types.intro.php
 */

namespace Puzzlout\Objects\Types;

use Puzzlout\Exceptions\Classes\Core\InvalidArgumentException;
use Puzzlout\Exceptions\Codes\GeneralErrors;
use Puzzlout\Objects\Interfaces\IObject;
use Puzzlout\Objects\Interfaces\IBoolean;

class Boolean extends Object implements IObject, IBoolean {

    public function GetClass() {
        parent::GetClass();
    }

    public function GetType() {
        parent::GetType();
    }

    /**
     * Validates the property value.
     *
     * @return boolean The result
     * @throws InvalidArgumentException
     */
    public function IsValid() {
        if (!is_bool($this->value)) {
            $errorMsg = 'The $value property of the instance of ' . __CLASS__ . ' is not a boolean.';
            throw new InvalidArgumentException($errorMsg, Codes\GeneralErrors::VALUE_IS_NOT_OF_EXPECTED_TYPE, null);
        }

        return true;
    }

    /**
     * Compares if the current instance of Boolean class to another instance.
     * @param \Puzzlout\Objects\Types\Boolean $value
     * @return bool The result of the comparaison
     */
    public function Equals(Boolean $value) {
        return $this->value == $value;
    }

}


<?php

namespace tourze\Http\Exception;

use Exception;
use tourze\Base\Exception\BaseException;
use tourze\Http\Request;
use tourze\Http\Response;

/**
 * 基础的HTTP异常类
 *
 * @package tourze\Http\Exception
 */
class HttpException extends BaseException
{

    /**
     * 创建一个指定类型的HTTP异常类
     *
     * @param  int       $code      状态码
     * @param  string    $message   消息文本
     * @param  array     $variables 消息文本的翻译变量
     * @param  Exception $previous
     * @return HttpException
     */
    public static function factory($code, $message = null, array $variables = null, Exception $previous = null)
    {
        $class = 'tourze\Http\Exception\Http' . $code . 'Exception';

        return new $class($message, $variables, $previous);
    }

    /**
     * @var string
     */
    protected $_uri = '';

    /**
     * @var int HTTP状态码
     */
    protected $_code = 0;

    /**
     * @var Request 当前异常的请求实例
     */
    protected $_request;

    /**
     * @var Response Response对象
     */
    protected $_response;

    /**
     * {@inheritdoc}
     */
    public function __construct($message = "", array $variables = null, $code = 0, Exception $previous = null)
    {
        if ( ! $code)
        {
            $code = $this->_code;
        }
        parent::__construct($message, $variables, $code, $previous);

        // 准备一个response对象
        $this->_response = new Response;
        $this->_response->status = $this->_code;
    }

    /**
     * 保存当前请求对象
     *
     * @param  Request $request
     * @return HttpException
     */
    public function request(Request $request = null)
    {
        if (null === $request)
        {
            return $this->_request;
        }
        $this->_request = $request;
        return $this;
    }

    /**
     * 获取当前异常的输出
     */
    public function getResponse()
    {
        return BaseException::response($this);
    }

    /**
     * 异常抛出时跳转的地址
     *
     * @param string $uri
     * @return $this
     */
    public function location($uri = '')
    {
        $this->_uri = $uri;
        return $this;
    }

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

    /**
     * @param int $code
     */
    public function setStatusCode($code)
    {
        $this->_code = $code;
    }
}