<?php

namespace beacon;

use beacon\widget\WidgetInterface;

/**
 * Created by PhpStorm.
 * User: wj008
 * Date: 2017/12/14
 * Time: 14:05
 */

/**
 * 字段类
 * @property $value
 * @property $boxName string
 * @property $boxId string
 *
 * @property $dataValRule array  验证规则
 * @property $dataValMessage array  验证提示
 * @property $dataValDefault string  验证默认信息
 * @property $dataValCorrect string  验证正确信息
 * @property $dataValError string  验证初始返回错误信息
 * @property $dataValDisabled bool  关闭验证
 * @property $dataValOutput string 输出html节点jq选择
 * @property $header
 * //容器中用到的字段
 * @property $plugName string 插件类名
 * @property $mode string 模式
 * @property $skin int 皮肤索引
 * @property $skinName string 皮肤
 * @property $childError array 子元素错误
 *
 * @property $names array 多个名称
 * @property $itemType string 子项数据类型
 * @property $hideBox bool  隐藏输入
 * @property $autoSave bool
 * @property $dataDynamic array
 * @property $encodeValue string 密码框需要的字段
 * @property $viewHide bool 隐藏行
 *
 *  @property $options array
 */
class Field
{

    private static $instance = [];
    /**
     * 所在表单
     * @var Form|null
     */
    private $form = null;

    /**
     * 输入框属性
     * @var array
     */
    private $_attr = [
        'id' => '',
        'name' => ''
    ];
    /**
     * 绑定数据
     * @var array
     */
    private $_data = [];

    /**
     * 视图数据
     * @var array
     */
    private $_view = [];

    /**
     * 扩展函数
     * @var array
     */
    private $_func = [];

    /**
     * 字段属性扩展
     * @var array
     */
    private $_extends = [];

    //-----------------------------------------------------------
    private $_value = null;         //值
    public $default = null;         //默认值
    public $forceDefault = false;   //如果值为空强制默认值
    public $label = '';             //标题
    public $name = '';              //字段名
    public $error = null;           //错误信息
    public $close = false;          //关闭控件
    public $offEdit = false;        //禁止编辑
    public $offSave = false;        //禁止保存
    public $type = 'text';          //字段类型
    public $varType = 'string';     //值类型
    public $dynamic = null;         //动态控制数据
    //视图属性
    public $tabIndex = '';          //所在标签名称,如果为空,所有标签都会出现
    public $viewClose = false;      //关闭视图
    public $viewMerge = 0;      //关闭视图

    /**
     * @var Field
     */
    public $next = null;
    /**
     * @var Field
     */
    public $prev = null;
    //----------------------------------------------------------------
    private $_ref = null;

    public function __construct(Form $form = null, array $field = [])
    {
        $this->_ref = new \ReflectionClass(get_class($this));
        $this->form = $form;
        if ($field == null) {
            $field = [];
        }
        foreach ($field as $key => $value) {
            $key = Utils::attrToCamel($key);
            if (empty($key)) {
                continue;
            }
            if (preg_match('@^(.*)Func$@', $key, $m)) {
                $this->regFunc($m[1], $value);
                continue;
            }
            if ($value instanceof \Closure) {
                $value = call_user_func($value, $this);
            }
            $this->set($key, $value, true);
        }
        //设置默认值
        $config = Config::get('form.field_default', []);
        foreach ($config as $key => $value) {
            $key = Utils::attrToCamel($key);
            if (empty($key)) {
                continue;
            }
            if (preg_match('@Func$@', $key)) {
                continue;
            }
            $cur_value = $this->get($key, true);
            if (!($cur_value === null || $cur_value === '')) {
                continue;
            }
            if ($value instanceof \Closure) {
                $value = call_user_func($value, $this);
            }
            $this->set($key, $value, true);
        }
        if (empty($this->_attr['id'])) {
            $this->_attr['id'] = $this->name;
        }
        if (empty($this->_attr['name'])) {
            $this->_attr['name'] = $this->name;
        }
    }

    /**
     * 设置属性值
     * @param string $name
     * @param $value
     * @param bool $p 包括原有属性
     */
    private function set(string $name, $value, $p = false)
    {
        if (empty($name)) {
            return;
        }
        if ($p && $this->_ref->hasProperty($name)) {
            $prop = $this->_ref->getProperty($name);
            if ($prop->isPublic()) {
                $prop->setValue($this, $value);
            }
        } else if ($name[0] == 'b' && preg_match('@^box([A-Z].*)$@', $name, $m)) {
            $name = Utils::camelToAttr($m[1]);
            $this->_attr[$name] = $value;
        } else if ($name[0] == 'd' && preg_match('@^data([A-Z].*)$@', $name)) {
            $name = Utils::camelToAttr($name);
            $this->_data[$name] = $value;
        } else if ($name[0] == 'v' && preg_match('@^view([A-Z].*)$@', $name)) {
            $this->_view[$name] = $value;
        } else if ($name == 'value') {
            $this->_value = $value;
        } else {
            $this->_extends[$name] = $value;
        }
    }

    /**
     * 获取属性值
     * @param $name
     * @param bool $p 包括原有属性
     * @return mixed|null
     */
    private function get($name, $p = false)
    {
        if ($p && $this->_ref->hasProperty($name)) {
            $prop = $this->_ref->getProperty($name);
            if ($prop->isPublic()) {
                return $prop->getValue($this);
            }
        } else if ($name[0] == 'b' && preg_match('@^box([A-Z].*)$@', $name, $m)) {
            $name = Utils::camelToAttr($m[1]);
            return isset($this->_attr[$name]) ? $this->_attr[$name] : null;
        } else if ($name[0] == 'd' && preg_match('@^data([A-Z].*)$@', $name)) {
            $name = Utils::camelToAttr($name);
            return isset($this->_data[$name]) ? $this->_data[$name] : null;
        } else if ($name[0] == 'v' && preg_match('@^view([A-Z].*)$@', $name)) {
            return isset($this->_view[$name]) ? $this->_view[$name] : null;
        } else if ($name == 'value') {
            if ($this->_value !== null || $this->form == null || $this->form->getType() != 'add' || $this->default === null || $this->default === '') {
                return $this->_value;
            } else {
                return $this->default;
            }
        } else {
            return isset($this->_extends[$name]) ? $this->_extends[$name] : null;
        }
    }

    /**
     * 注册函数
     * @param string $name
     * @param $func
     */
    public function regFunc(string $name, $func)
    {
        $this->_func[$name] = $func;
    }

    /**
     * 获取函数
     * @param string $name
     * @return mixed|null
     */
    public function getFunc(string $name)
    {
        return isset($this->_func[$name]) ? $this->_func[$name] : null;
    }

    /**
     * 属性赋值
     * @param $name
     * @param $value
     */
    public function __set($name, $value)
    {
        $this->set($name, $value);
    }

    /**
     * 获取属性
     * @param $name
     * @return false|int|mixed|null|string
     */
    public function __get($name)
    {
        return $this->get($name);
    }

    /**
     * 判断属性存在
     * @param $name
     * @return bool
     */
    public function __isset($name)
    {
        if ($name[0] == 'b' && preg_match('@^box([A-Z].*)$@', $name, $m)) {
            $name = Utils::camelToAttr($m[1]);
            return isset($this->_attr[$name]);
        } else if ($name[0] == 'd' && preg_match('@^data([A-Z].*)$@', $name)) {
            $name = Utils::camelToAttr($name);
            return isset($this->_data[$name]);
        } else if ($name[0] == 'v' && preg_match('@^view([A-Z].*)$@', $name)) {
            return isset($this->_view[$name]);
        } else if ($name == 'value') {
            return true;
        } else {
            return isset($this->_extends[$name]);
        }
    }

    /**
     * 删除属性
     * @param $name
     * @return mixed
     */
    public function __unset($name)
    {
        if ($name[0] == 'b' && preg_match('@^box([A-Z].*)$@', $name, $m)) {
            $name = Utils::camelToAttr($m[1]);
            unset($this->_attr[$name]);
        } else if ($name[0] == 'd' && preg_match('@^data([A-Z].*)$@', $name)) {
            $name = Utils::camelToAttr($name);
            unset($this->_data[$name]);
        } else if ($name[0] == 'v' && preg_match('@^view([A-Z].*)$@', $name)) {
            unset($this->_view[$name]);
        } else if ($name == 'value') {
            return;
        } else {
            unset($this->_extends[$name]);
        }
    }

    /**
     * 获取表单
     * @return Form|null
     */
    public function getForm()
    {
        return $this->form;
    }

    /**
     * 获取输入框属性
     */
    public function getAttributes()
    {
        $attr = array_merge($this->_attr, $this->_data);
        $attr = array_filter($attr, function ($v) {
            return $v !== null && $v !== '';
        });
        if ($this->form != null && $this->form->getType() == 'edit') {
            if ($this->offEdit) {
                $attr['disabled'] = 'disabled';
            }
        }
        if ($this->value !== null) {
            $attr['value'] = $this->value;
        }
        return $attr;
    }

    /**
     * 获取插件显示的代码
     * @param null $attr
     * @return mixed|string|void
     * @throws \Exception
     */
    public function code($attr = null)
    {
        if ($attr === null || !is_array($attr)) {
            $attr = [];
        }
        try {
            if ($this->form != null) {
                $this->form->createDynamic($this);
            }
            $box = self::getInstance($this->type);
            if ($box === null) {
                throw new \Exception('Unsupported input box type:' . $this->type);
            }
            if (!empty($this->viewTemplate)) {
                $template = $this->viewTemplate;
                $this->viewTemplate = null;
                $view = new View();
                $view->assign('form', $this->form);
                $view->assign('field', $this);
                $view->assign('attr', $attr);
                $data = $view->fetch($template);
                return $data;
            }
            return $box->code($this, $attr);
        } catch (\Exception $exception) {
            throw $exception;
        }
    }

    /**
     * 获取插件实例
     * @param string $type
     * @return WidgetInterface
     * @throws \ReflectionException
     */
    public static function getInstance(string $type)
    {
        if (empty($type)) {
            return null;
        }
        if (isset(self::$instance[$type])) {
            return self::$instance[$type];
        }
        $class = '\\beacon\\widget\\' . Utils::toCamel($type);
        //  Logger::log($class);
        if (!class_exists($class)) {
            return null;
        }
        $reflect = new \ReflectionClass($class);
        if (!$reflect->implementsInterface(WidgetInterface::class)) {
            return null;
        }
        self::$instance[$type] = new $class();
        return self::$instance[$type];
    }

}


<?php
/**
 * This file is part of the Koriym.DevPdoStatement
 *
 * @license http://opensource.org/licenses/MIT MIT
 */
declare(strict_types=1);

namespace Koriym\DevPdoStatement;

final class DevPdoStatement extends \PdoStatement
{
    /**
     * Bound parameters
     *
     * @var array
     */
    private $params = [];

    /**
     * Interpolate Query
     *
     * @var string
     */
    public $interpolateQuery;

    /**
     * @var \PDO
     */
    private $pdo;

    /**
     * @var LoggerInterface
     */
    private $logger;

    protected function __construct(\PDO $db, LoggerInterface $logger)
    {
        $this->pdo = $db;
        $this->logger = $logger;
    }

    /**
     * {@inheritdoc}
     */
    public function bindValue($parameter, $value, $dataType = \PDO::PARAM_STR)
    {
        $this->params[$parameter] = $value;
        parent::bindValue($parameter, $value, $dataType);
    }

    /**
     * {@inheritdoc}
     */
    public function bindParam($paramno, &$param, $dataType = \PDO::PARAM_STR, $length = null, $driverOptions = null)
    {
        $this->params[$paramno] = &$param;
        parent::bindParam($paramno, $param, $dataType, (int) $length, $driverOptions);
    }

    /**
     * {@inheritdoc}
     */
    public function execute($bountInputParameters = null)
    {
        $start = microtime(true);
        parent::execute($bountInputParameters);
        $time = microtime(true) - $start;
        $this->interpolateQuery = $this->interpolateQuery($this->queryString, $this->params);
        list($explain, $warnings) = $this->getExplain($this->interpolateQuery);
        $this->logger->logQuery($this->interpolateQuery, $time, $explain, $warnings);
    }

    /**
     * Replaces any parameter placeholders in a query with the value of that
     * parameter. Useful for debugging. Assumes anonymous parameters from
     * $params are are in the same order as specified in $query
     *
     * @param string $query  The sql query with parameter placeholders
     * @param array  $params The array of substitution parameters
     *
     * @return string The interpolated query
     *
     * @link http://stackoverflow.com/a/8403150
     * thanks
     */
    private function interpolateQuery($query, $params)
    {
        $keys = [];
        $values = $params;
        # build a regular expression for each parameter
        foreach ($params as $key => $value) {
            $keys[] = is_string($key) ? '/' . $key . '/' : '/[?]/';
            if (is_string($value)) {
                $values[$key] = "'" . $value . "'";
            }
            if (is_array($value)) {
                $values[$key] = "'" . implode("','", $value) . "'";
            }
            if (is_null($value)) {
                $values[$key] = 'null';
            }
        }
        $query = preg_replace($keys, $values, $query, 1);

        return $query;
    }

    /**
     * @param string $interpolateQuery
     *
     * @return array
     */
    private function getExplain($interpolateQuery)
    {
        $explainSql = sprintf('EXPLAIN %s', $interpolateQuery);
        try {
            $sth = $this->pdo->query($explainSql);
            $explain = $sth->fetchAll(\PDO::FETCH_ASSOC);
            $sth = $this->pdo->query('SHOW WARNINGS');
            $sth instanceof \PDOStatement ? $warnings = $sth->fetchAll(\PDO::FETCH_ASSOC) : $warnings = [];
        } catch (\PDOException $e) {
            return [[], []];
        }

        return [$explain, $warnings];
    }
}


<?php
/**
 * Created by IntelliJ IDEA.
 * User: Miles
 * Date: 7/16/17
 * Time: 5:19 PM
 */

namespace CarbonPHP\Error;

/**
 * Class PublicAlert
 * @package Modules\Helpers\Error
 *
 * The public alert class is designed to be used with the carbon.js extra.
 * If the java script method Carbon() is not defiend in the html document head, or
 * if Carbon.js is not included  PublicAlert  may result in runtime errors.
 * This class prints warning to the browser using this javascript
 *      <script>Carbon(() => $.fn.bootstrapAlert(\"$message\", \"$level\"))</script>
 *
 * Public alerts should only be thrown when wrapped in a try catch block.
 * The alerts will be handled in the view class.
 *
 * I assume you use bootstrap (particularly AdminLTE) and carbon.js for the rest of
 * this file.
 */

class PublicAlert extends CustomException {

    public static function JsonAlert($message, $title, $type = 'danger', $icon = null, $status = 500, $intercept = true, $stack = true) : void
    {
        global $json;

        if (!\is_array($json)) {
            $json = [];
        } elseif ($stack) {
            $json = [
                'previous_json' => $json,
                'sql' => [],
                'status' => $status,
            ];
        } else {
            $json['status'] = $status;
        }

        if (!\in_array($type, ['default', 'info', 'success', 'warning', 'danger', 'error', 'input', 'custom'])) {
            $message .= " The React Alert type given `$type` is not supported.";
            $type = 'danger';
        }

        if ($title === null) {
            $title = 'Danger!';
        }

        $json['alert'][] = [
            'message' => $message,
            'type' => $type,
            'title' => $title,
            'icon' => $icon,
            'intercept' => $intercept
        ];
    }

    /** Add an alert to the array. If the view is not executed, CarbonPHP will not
     * handle the global alert.
     * @param string $message the message to be stored in the alert variable
     * @param string $code you may choose between success, info, danger, or warning
     */
    private static function alert(string $message, string $code) {
        global $json;
        if ($code !== 'success' && $code !== 'info') {
            $message .= ' Contact us if problem persists.';
        }
        $json['alert'][$code][] = $message;
    }

    /**
     * @param string $message results in a green alert box
     */
    public static function success(string $message)
    {
        global $json;
        $json['alert']['success'][] = $message;
    }

    /**
     * @param string $message results in a blue alert box
     */
    public static function info(string $message)
    {
        global $json;
        $json['alert']['info'][] = $message;
    }

    /**
     * @param string $message results in a red alert box
     */
    public static function danger(string $message)
    {
        global $json;
        $json['alert']['danger'][] = $message;

    }

    /**
     * @param string $message results in a yellow alert box
     */
    public static function warning(string $message)
    {
        global $json;
        $json['alert']['warning'][] = $message;
    }

    /**
     * PublicAlert constructor.
     * @param null $message
     * @param string $code
     */
    public function __construct($message = null, $code = 'warning')
    {
        if (!empty($message)) {
            static::alert($message, $code);
        }
        parent::__construct($message, 0);
    }

    /** Allow for even more customization alerts on runtime.
     * @link http://php.net/manual/en/language.oop5.overloading.php#object.call
     *
     * If a methods is run that does not exist in this scope,
     * pass the method name as our alert level.
     *
     * $this->superDaner($message);
     *
     * would set: $GLOBALS['alert']['superDaner']=$message;
     *
     * @param null $code
     * @param $message
     */
    public function __call($code = null, $message)
    {
        static::alert( $message[0], $code );
    }

    /** The same as __call() but in a static context.
     * PublicAlert::superDaner($message); ...
     *
     * @link http://php.net/manual/en/language.oop5.overloading.php#object.call
     * @param null $code
     * @param $message
     */
    public static function __callStatic($code = null, $message)
    {
        static::alert( $message[0], $code );
    }

}


<?php
/**
 * Ongr_Sniffs_ControlStructures_SwitchDeclarationSniff.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * Ongr_Sniffs_ControlStructures_SwitchDeclarationSniff.
 *
 * Ensures all the breaks and cases are aligned correctly according to their
 * parent switch's alignment and enforces other switch formatting.
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class Ongr_Sniffs_ControlStructures_SwitchDeclarationSniff implements PHP_CodeSniffer_Sniff
{

    /**
     * A list of tokenizers this sniff supports.
     *
     * @var array
     */
    public $supportedTokenizers = array(
        'PHP',
        'JS',
    );

    /**
     * The number of spaces code should be indented.
     *
     * @var int
     */
    public $indent = 4;

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return array(T_SWITCH);

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token in the
     *                                        stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();

        // We can't process SWITCH statements unless we know where they start and end.
        if (isset($tokens[$stackPtr]['scope_opener']) === false
            || isset($tokens[$stackPtr]['scope_closer']) === false
        ) {
            return;
        }

        // Ongr checks whitespaces around switch condition.
        $switchBracket = $phpcsFile->findNext([T_OPEN_CURLY_BRACKET], ($stackPtr));
        $whitespaceLengthBefore = $tokens[$stackPtr + 1]['length'];
        $whitespaceLengthAfter = $tokens[$switchBracket - 1]['length'];
        if (
            ($tokens[$stackPtr + 1]['type'] !== 'T_WHITESPACE' || $whitespaceLengthBefore !== 1) ||
            ($tokens[$switchBracket - 1]['type'] !== 'T_WHITESPACE' || $whitespaceLengthAfter !== 1))
        {
            $phpcsFile->addError(
                'There should a be single whitespace around the switch condition.', $stackPtr, 'SwitchWhitespace'
            );
        }

        $switch        = $tokens[$stackPtr];
        $nextCase      = $stackPtr;
        $caseAlignment = ($switch['column'] + $this->indent);
        $caseCount     = 0;
        $foundDefault  = false;

        while (($nextCase = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), ($nextCase + 1), $switch['scope_closer'])) !== false) {
            // Skip nested SWITCH statements; they are handled on their own.
            if ($tokens[$nextCase]['code'] === T_SWITCH) {
                $nextCase = $tokens[$nextCase]['scope_closer'];
                continue;
            }

            if ($tokens[$nextCase]['code'] === T_DEFAULT) {
                $type         = 'Default';
                $foundDefault = true;
            } else {
                $type = 'Case';
                $caseCount++;
            }

            if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) {
                $expected = strtolower($tokens[$nextCase]['content']);
                $error    = strtoupper($type).' keyword must be lowercase; expected "%s" but found "%s"';
                $data     = array(
                    $expected,
                    $tokens[$nextCase]['content'],
                );

                $fix = $phpcsFile->addFixableError($error, $nextCase, $type.'NotLower', $data);
                if ($fix === true) {
                    $phpcsFile->fixer->replaceToken($nextCase, $expected);
                }
            }

            if ($tokens[$nextCase]['column'] !== $caseAlignment) {
                $error = strtoupper($type).' keyword must be indented '.$this->indent.' spaces from SWITCH keyword';
                $fix   = $phpcsFile->addFixableError($error, $nextCase, $type.'Indent');

                if ($fix === true) {
                    $padding = str_repeat(' ', ($caseAlignment - 1));
                    if ($tokens[$nextCase]['column'] === 1
                        || $tokens[($nextCase - 1)]['code'] !== T_WHITESPACE
                    ) {
                        $phpcsFile->fixer->addContentBefore($nextCase, $padding);
                    } else {
                        $phpcsFile->fixer->replaceToken(($nextCase - 1), $padding);
                    }
                }
            }

            if ($type === 'Case'
                && ($tokens[($nextCase + 1)]['type'] !== 'T_WHITESPACE'
                    || $tokens[($nextCase + 1)]['content'] !== ' ')
            ) {
                $error = 'CASE keyword must be followed by a single space';
                $fix   = $phpcsFile->addFixableError($error, $nextCase, 'SpacingAfterCase');
                if ($fix === true) {
                    if ($tokens[($nextCase + 1)]['type'] !== 'T_WHITESPACE') {
                        $phpcsFile->fixer->addContent($nextCase, ' ');
                    } else {
                        $phpcsFile->fixer->replaceToken(($nextCase + 1), ' ');
                    }
                }
            }

            if (isset($tokens[$nextCase]['scope_opener']) === false) {
                $error = 'Possible parse error: CASE missing opening colon';
                $phpcsFile->addWarning($error, $nextCase, 'MissingColon');
                continue;
            }

            $opener = $tokens[$nextCase]['scope_opener'];
            if ($tokens[($opener - 1)]['type'] === 'T_WHITESPACE') {
                $error = 'There must be no space before the colon in a '.strtoupper($type).' statement';
                $fix   = $phpcsFile->addFixableError($error, $nextCase, 'SpaceBeforeColon'.$type);
                if ($fix === true) {
                    $phpcsFile->fixer->replaceToken(($opener - 1), '');
                }
            }

            $nextBreak = $tokens[$nextCase]['scope_closer'];
            if ($tokens[$nextBreak]['code'] === T_BREAK
                || $tokens[$nextBreak]['code'] === T_RETURN
                || $tokens[$nextBreak]['code'] === T_CONTINUE
                || $tokens[$nextBreak]['code'] === T_THROW
                || $tokens[$nextBreak]['code'] === T_EXIT
            ) {
                if ($tokens[$nextBreak]['scope_condition'] === $nextCase) {
                    // Only need to check a couple of things once, even if the
                    // break is shared between multiple case statements, or even
                    // the default case.

                    //ONGR we use +4 spaces indentation for case breaking statement
                    if ($tokens[$nextBreak]['column'] !== $caseAlignment + $this->indent) {
                        $error = 'Case breaking statement must be indented '.$this->indent.' spaces from SWITCH keyword';
                        $fix   = $phpcsFile->addFixableError($error, $nextBreak, 'BreakIndent');

                        if ($fix === true) {
                            $padding = str_repeat(' ', ($caseAlignment - 1));
                            if ($tokens[$nextBreak]['column'] === 1
                                || $tokens[($nextBreak - 1)]['code'] !== T_WHITESPACE
                            ) {
                                $phpcsFile->fixer->addContentBefore($nextBreak, $padding);
                            } else {
                                $phpcsFile->fixer->replaceToken(($nextBreak - 1), $padding);
                            }
                        }
                    }

                    $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($nextBreak - 1), $stackPtr, true);
                    // ONGR Return statements must have blank line before them otherwise there should be no blank lines.
                    if ($tokens[$prev]['line'] !== ($tokens[$nextBreak]['line'] - 1) && $tokens[$nextBreak]['code'] !== T_RETURN) {
                        $error = 'Blank lines are not allowed before case breaking statements';
                        $phpcsFile->addError($error, $nextBreak, 'SpacingBeforeBreak');
                    }

                    $breakLine = $tokens[$nextBreak]['line'];
                    $nextLine  = $tokens[$tokens[$stackPtr]['scope_closer']]['line'];
                    $semicolon = $phpcsFile->findNext(T_SEMICOLON, $nextBreak);
                    for ($i = ($semicolon + 1); $i < $tokens[$stackPtr]['scope_closer']; $i++) {
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                            $nextLine = $tokens[$i]['line'];
                            break;
                        }
                    }
                    if ($type === 'Case') {
                        // Ensure the BREAK statement is followed by
                        // a single blank line, or the end switch brace.
                        if ($nextLine !== ($tokens[$semicolon]['line'] + 1) && $i !== $tokens[$stackPtr]['scope_closer']) {
                            $error = 'Case breaking statements must be followed without blank lines';
                            $fix   = $phpcsFile->addFixableError($error, $nextBreak, 'SpacingAfterBreak');
                            #TODO Adapt fixing to use case statements without spaces
//                            if ($fix === true) {
//                                $phpcsFile->fixer->beginChangeset();
//                                for ($i = ($semicolon + 1); $i <= $tokens[$stackPtr]['scope_closer']; $i++) {
//                                    if ($tokens[$i]['line'] === $nextLine) {
//                                        $phpcsFile->fixer->addNewlineBefore($i);
//                                        break;
//                                    }
//
//                                    if ($tokens[$i]['line'] === $tokens[$semicolon]['line']) {
//                                        continue;
//                                    }
//
//                                    $phpcsFile->fixer->replaceToken($i, '');
//                                }
//
//                                $phpcsFile->fixer->endChangeset();
//                            }
                        }//end if
                    } else {
                        // Ensure the BREAK statement is not followed by a blank line.
                        if ($nextLine !== ($breakLine + 1)) {
                            $error = 'Blank lines are not allowed after the DEFAULT case\'s breaking statement';
                            $phpcsFile->addError($error, $nextBreak, 'SpacingAfterDefaultBreak');
                        }
                    }//end if

                    $caseLine = $tokens[$nextCase]['line'];
                    $nextLine = $tokens[$nextBreak]['line'];
                    for ($i = ($opener + 1); $i < $nextBreak; $i++) {
                        if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                            $nextLine = $tokens[$i]['line'];
                            break;
                        }
                    }

                    if ($nextLine !== ($caseLine + 1)) {
                        $error = 'Blank lines are not allowed after '.strtoupper($type).' statements';
                        $phpcsFile->addError($error, $nextCase, 'SpacingAfter'.$type);
                    }
                }//end if

                if ($tokens[$nextBreak]['code'] === T_BREAK) {
                    if ($type === 'Case') {
                        // Ensure empty CASE statements are not allowed.
                        // They must have some code content in them. A comment is not enough.
                        // But count RETURN statements as valid content if they also
                        // happen to close the CASE statement.
                        $foundContent = false;
                        for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) {
                            if ($tokens[$i]['code'] === T_CASE) {
                                $i = $tokens[$i]['scope_opener'];
                                continue;
                            }

                            if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
                                $foundContent = true;
                                break;
                            }
                        }

                        if ($foundContent === false) {
                            $error = 'Empty CASE statements are not allowed';
                            $phpcsFile->addError($error, $nextCase, 'EmptyCase');
                        }
                    } else {
                        // Ensure empty DEFAULT statements are not allowed.
                        // They must (at least) have a comment describing why
                        // the default case is being ignored.
                        $foundContent = false;
                        for ($i = ($tokens[$nextCase]['scope_opener'] + 1); $i < $nextBreak; $i++) {
                            if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                                $foundContent = true;
                                break;
                            }
                        }

                        if ($foundContent === false) {
                            $error = 'Comment required for empty DEFAULT case';
                            $phpcsFile->addError($error, $nextCase, 'EmptyDefault');
                        }
                    }//end if
                }//end if
            } else if ($type === 'Default') {
                $error = 'DEFAULT case must have a breaking statement';
                $phpcsFile->addError($error, $nextCase, 'DefaultNoBreak');
            }//end if
        }//end while

        if ($foundDefault === false) {
            $error = 'All SWITCH statements must contain a DEFAULT case';
            $phpcsFile->addError($error, $stackPtr, 'MissingDefault');
        }

        if ($tokens[$switch['scope_closer']]['column'] !== $switch['column']) {
            $error = 'Closing brace of SWITCH statement must be aligned with SWITCH keyword';
            $phpcsFile->addError($error, $switch['scope_closer'], 'CloseBraceAlign');
        }

        if ($caseCount === 0) {
            $error = 'SWITCH statements must contain at least one CASE statement';
            $phpcsFile->addError($error, $stackPtr, 'MissingCase');
        }

    }//end process()

}//end class


<?php

namespace beacon;

/**
 * Created by PhpStorm.
 * User: wj008
 * Date: 2017/12/12
 * Time: 15:56
 */
class Config
{

    private static $configPath = null;
    private static $global = []; //全局的
    private static $loaded = []; //已经加载过的

    /**
     * 从配置文件目录中加载
     * @param $name
     * @param bool $overwrite
     * @return mixed|null
     */
    public static function load($name, $overwrite = false)
    {
        if (is_array($name)) {
            $data = [];
            foreach ($name as $value) {
                $temp = self::load($value);
                $data = array_merge($data, $temp);
            }
            return $data;
        }

        //如果应用目录下存在配置文件夹使用应用目录下面的配置文件
        $appPath = Route::getPath();
        if (!empty($appPath)) {
            $filePath = Utils::path($appPath, 'config', $name . '.config.php');
            if (file_exists($filePath)) {
                $loadData = require($filePath);
                if (is_array($loadData)) {
                    foreach ($loadData as $key => $val) {
                        if ($overwrite) {
                            self::$global[$name . '.' . $key] = $val;
                        } else {
                            if (!isset(self::$global[$name . '.' . $key])) {
                                self::$global[$name . '.' . $key] = $val;
                            }
                        }
                    }
                }
                self::$loaded[$name] = 1;
                return $loadData;
            }
        }
        //使用根目录下的配置文件
        if (empty(self::$configPath)) {
            self::$configPath = Utils::path(ROOT_DIR, 'config');
        }
        $filePath = Utils::path(self::$configPath, $name . '.config.php');
        if (file_exists($filePath)) {
            $loadData = require($filePath);
            if (is_array($loadData)) {
                foreach ($loadData as $key => $val) {
                    if ($overwrite) {
                        self::$global[$name . '.' . $key] = $val;
                    } else {
                        if (!isset(self::$global[$name . '.' . $key])) {
                            self::$global[$name . '.' . $key] = $val;
                        }
                    }
                }
            }
            self::$loaded[$name] = 1;
            return $loadData;
        }
        return [];
    }

    /**
     * 指定绝对路径加载
     * @param $file
     * @return mixed|null
     */
    public static function loadFile(string $file)
    {
        $path = Utils::path($file);
        if (is_file($path)) {
            return require($path);
        }
        return [];
    }

    /**
     * 设置配置项
     * @param string $key
     * @param $value
     */
    public static function set(string $key, $value)
    {
        self::$global[$key] = $value;
    }

    /**
     * 获取配置项
     * @param string $key
     * @param string $def 默认值
     * @return mixed|string
     */
    public static function get(string $key = null, $def = null)
    {
        if ($key == null) {
            return self::$global;
        }
        if (preg_match('@^(\w+)\.(.+)$@', $key, $m)) {
            $name = trim($m[1]);
            if (!isset(self::$loaded[$name])) {
                self::load($name);
            }
            if (trim($m[2]) == '*') {
                return self::getSection($name);
            }
        }
        return isset(self::$global[$key]) ? self::$global[$key] : $def;
    }

    /**
     * 获取一栏配置项
     * @param string $name
     * @return array
     */
    public static function getSection(string $name)
    {
        $section = [];
        if (!isset(self::$loaded[$name])) {
            self::load($name);
        }
        foreach (self::$global as $key => $val) {
            if (preg_match('@^' . preg_quote($name, '@') . '\.(.+)$@', $key, $m)) {
                $section[$m[1]] = $val;
            }
        }
        return $section;
    }

    /**
     * 设置一栏配置项
     * @param string $name
     * @param array $data
     */
    public static function setSection(string $name, array $data)
    {
        foreach ($data as $key => $val) {
            self::$global[$name . '.' . $key] = $val;
        }
    }
}


<?php
/**
 * Created by IntelliJ IDEA.
 * User: richardmiles
 * Date: 2/3/19
 * Time: 7:03 PM
 */

namespace CarbonPHP\Programs;

use CarbonPHP\Error\PublicAlert;
use CarbonPHP\Interfaces\iCommand;

class CLI implements iCommand
{

    private $CONFIG;
    private $programs;

    public function __construct($CONFIG)
    {
        $this->CONFIG = $CONFIG;
        $this->programList();
    }

    public function programList() {

        $program = array_diff(scandir(CARBON_ROOT . 'programs', null), array('.', '..'));

        $clean = function (&$program) {
            $program = strtolower(basename($program, '.php'));
        };

        if (!array_walk($program, $clean)) {
            throw new PublicAlert('array_walk failed in Cli::run()');
        }

        $this->programs = $program;
    }

    /** Command Line Interface. Use
     *  I pass the php array to this function
     *  for reporting purposes.
     * php index.php [command]
     * @param $argv
     * @return mixed
     */
    public function run($argv)
    {
        $PHP = $this->CONFIG;

        // I do this so the I can pass the argvs correctly to the php executables
        print "\nIt's a powerful " . array_shift($argv) . ", hu?\n\n";

        $program = strtolower(array_shift($argv));

        foreach ($this->programs as $name) {
            // I prefer this loop so I catch
            if ($program !== $name) {
                continue;
            }

            /** @noinspection PhpIncludeInspection */
            if (false === include $name . '.php') {
                die('Failed loading file "' . $name . '.php". Please no syntax errors exist in this file.');
            }

            $classes = get_declared_classes();

            $class = end($classes);

            if (!class_exists($class)) {
                die('Failed to load the class ("' . $class . '")');
            }

            $imp = class_implements($class);

            if (!array_key_exists(iCommand::class, $imp)) {
                die('The program class should also implement iCommand. '. print_r($imp, true));
            }

            // We're only using this closure to reinforce our iCommand // type hint
            $run = function (iCommand $cmd) use ($argv) {
                return $cmd->run($argv) and $cmd->cleanUp($argv);
            };

            exit($run(new $class($PHP)));
        }

        switch ($program) {
            case 'minify':
                    print "\n\nminify\n\n";
                break;
            case 'check':
                $cmd = 'netstat -a -n -o | find "' . ($PHP['SOCKET']['PORT'] ?? 8888) . '\"';
                print PHP_EOL . $cmd . PHP_EOL;
                print shell_exec($cmd);
                break;
            case 'test':
                print PHP_EOL;
                print shell_exec('phpunit --bootstrap vendor/autoload.php --testdox  tests');
                print PHP_EOL;
                break;
            case 'php':
                print 'Starting PHP Websocket' . PHP_EOL;
                $CMD = 'php ' . CARBON_ROOT . 'Server.php ' . APP_ROOT . ' ' . $PHP['SITE']['CONFIG'];
                print `$CMD`;
                break;
            case 'help':
            default:
                $this->usage();
        }
        return 0;
    }

    public function usage()
    {
        // common knowledge tabs do not work well across os
        $this->programs = implode("\n                        ", $this->programs);

        print <<<END
          Available CarbonPHP CLI Commands

          User Defined Commands ::

                        $this->programs

          CarbonPHP Built-in commands ::

                        help                          - This list of options
                        [command] -help               - display a list of options for each sub command
                        test                          - Run PHPUnit tests
                        rest                          - auto generate rest api from mysqldump
                        php                           - start a HTTP 5 web socket server written in PHP
                        go                            - start a HTTP 5 web socket server written in Google Go

          While CarbonPHP displays this in the cli, it does not exit here. Custom functions may
          be written after the CarbonPHP invocation. The CLI execution will however, stop the
          routing of HTTP(S) request normally invoked through the (index.php). <-- Which could really
          be any file run in CLI with CarbonPHP invoked.\n\n
END;
    }

    public function cleanUp($PHP) : int
    {
        return 0;
    }
}


<?php
/**
 * Created by IntelliJ IDEA.
 * User: Miles
 * Date: 9/2/17
 * Time: 8:54 AM
 */

namespace CarbonPHP\Helpers;

class Fork
{

    /** If a callable function is passes the interpreter will attempt to
     * fork using the pncl library and then execute the desired closure.
     * If no arguments are passed than the current execution environment
     * will become "Demonized". All masks will be set to 0 and the new
     * working environment will be the root dir. This can be exceptionally
     * dangerous and should only be used if your absolutely
     * sure you know whats going on.
     * @param callable|null $call
     * @return int
     * @throws \Exception
     */
    public static function become_daemon(callable $call = null) : int        // do not use this unless you know what you are doing
    {
        if (!\extension_loaded('pcntl')) {
            print 'You must have the PCNTL extencion installed. See Carbon PHP for documentation.' and die;
        }

        if ($pid = pcntl_fork()) {  // Parent
            if (\is_callable($call)) {
                return 1;
            }
            exit;
        }
        if ($pid < 0) {
            throw new \RuntimeException('Failed to fork');
        }

        \define('FORK', TRUE);

        /* child becomes our daemon */
        posix_setsid();

        chdir('/');   // What does this do ?

        umask(0);        // Give access to nothing

        register_shutdown_function(function () {
            session_abort();
            posix_kill(posix_getpid(), SIGHUP);
            exit(1);
        });

        if (\is_callable($call)) {
            $call();
            exit(1);
        }

        return posix_getpid();
    }

    /** This will safely execute a passed closure if the pncl library in not
     * found in the environment. This should only be used when the callable
     * function does not access or modify the database or session. Carbon uses
     * this when realtime communication using named pipe is requested. It only
     * speeds up execution, however it is not required and will never throw an
     * error.
     * @param callable|null $closure
     * @return int
     * @throws \Exception
     */
    public static function safe(callable $closure = null) : int
    {
        if (!\extension_loaded('pcntl')) {
            if ($closure !== null) {
                $closure();
            }
            return 0;
        }
        if ($pid = pcntl_fork()) {    // return child id for parent and 0 for child
            return $pid;             // Parent
        }
        if ($pid < 0) {
            throw new \RuntimeException('Failed to fork');
        }
        \define('FORK', true);
        // Database::resetConnection();
        // fclose(STDIN); -- unset
        register_shutdown_function(function () {
            session_abort();
            posix_kill(posix_getpid(), SIGHUP);
            exit(1);
        });

        if ($closure !== null) {
            $closure();
        }
        exit;
    }

}


<?php

namespace beacon;

/**
 * Created by PhpStorm.
 * User=> wj008
 * Date: 2017/12/14
 * Time: 0:26
 */
class Validate
{
    /**
     * 默认消息
     * @var array
     */
    private static $default_errors = null;

    /**
     * 代理短写
     * @var array
     */
    private static $alias = [
        'r' => 'required',
        'i' => 'integer',
        'int' => 'integer',
        'num' => 'number',
        'minlen' => 'minlength',
        'maxlen' => 'maxlength',
        'eqto' => 'equalto',
        'eq' => 'equal',
        'neq' => 'notequal'
    ];

    private static $staticFunc = [];

    private $remoteFunc = [];
    private $func = [];
    private $def_errors = [];

    /**
     * 字符串格式化输出
     * @param string $str
     * @param array $args
     * @return mixed|string
     */
    private static function format(string $str, $args = null)
    {
        if ($args === null) {
            return $str;
        }
        if (!is_array($args)) {
            $args = [$args];
        }
        if (strlen($str) == 0 || count($args) == 0) {
            return $str;
        }
        return preg_replace_callback('@\{(\d+)\}@', function ($m) use ($args) {
            $index = intval($m[1]);
            return isset($args[$index]) ? $args[$index] : '';
        }, $str);
    }

    public static function __callStatic($name, $args)
    {
        if (preg_match('@^test_(\w+)$@', $name, $match)) {
            $func = self::getFunc($match[1]);
            if ($func !== null) {
                $out = call_user_func_array($func, $args);
                return $out;
            }
        }
        throw new \Exception('Error Method!');
    }

    /**
     * @param $type
     * @return null|string
     */
    public static function getFunc($type)
    {
        $rtype = self::getRealType($type);
        if (method_exists(self::class, 'test_' . $rtype)) {
            return self::class . '::' . 'test_' . $rtype;
        }
        if (isset(self::$staticFunc[$rtype])) {
            return self::$staticFunc[$rtype];
        }
        return null;
    }

    /**
     * @param $type
     * @return mixed
     */
    public static function getRealType($type)
    {
        if (isset(self::$alias[$type])) {
            return self::$alias[$type];
        }
        return $type;
    }

    /**
     * @param $type
     * @param $func
     * @param string $error
     */
    public static function regFnuc($type, $func, $error = '格式错误')
    {
        if (is_string($func)) {
            $func = self::getRealType($func);
            self::$alias[$type] = $func;
            return;
        }
        self::$default_errors[$type] = $error;
        self::$staticFunc[$type] = $func;
    }

    /**
     * 判断是否为空
     * @param string $val
     * @return boolean
     */
    public static function test_required($val)
    {
        if (is_array($val)) {
            return count($val) != 0;
        }
        return $val !== null && $val !== '';
    }

    /**
     * 判断是否是邮箱
     * @param $val
     * @return int
     */
    public static function test_email($val)
    {
        return !!preg_match('/^(\w+[-_\.]?)*\w+@(\w+[-_\.]?)*\w+\.\w{2,6}([\.]\w{2,6})?$/', $val);
    }

    /**
     * 判断url
     * @param $val
     * @param bool $dc
     * @return bool
     */
    public static function test_url($val, $dc = false)
    {
        if ($dc && $val == '#') {
            return true;
        }
        return !!preg_match('/^(http|https|ftp):\/\/\w+\.\w+/i', $val);
    }

    /**
     * 判断值相等
     * @param $val
     * @param $str
     * @return bool
     */
    public static function test_equal($val, $str)
    {
        return strval($val) == strval($str);
    }

    /**
     * 判断值不相等
     * @param $val
     * @param $str
     * @return bool
     */
    public static function test_notequal($val, $str)
    {
        return strval($val) != strval($str);
    }

    /**
     * 判断与比较的id相等
     * @param $val
     * @param $key
     * @return bool
     */
    public static function test_equalto($val, $key)
    {
        if (!empty($key) && preg_match('/^#?(\w+)/i', $key, $m) != 0) {
            $name = isset($m[1]) ? $m[1] : '';
            if (!empty($name)) {
                $str = Request::param($name . ':s');
                if (!empty($str)) {
                    return strval($val) == $str;
                }
            }
        }
        return true;
    }

    /**
     * 判断手机号码
     * @param $val
     * @return bool
     */
    public static function test_mobile($val)
    {
        return !!preg_match('/^1[34578]\d{9}$/', $val);
    }

    /**
     * 判断身份证
     * @param $val
     * @return bool
     */
    public static function test_idcard($val)
    {
        return !!preg_match('/^[1-9]\d{5}(19|20)\d{2}(((0[13578]|1[02])([0-2]\d|30|31))|((0[469]|11)([0-2]\d|30))|(02[0-2][0-9]))\d{3}(\d|X|x)$/', $val);
    }

    /**
     * 判断字母开头的用户名
     * @param $val
     * @return bool
     */
    public static function test_user($val)
    {
        return !!preg_match('/^[a-z]\w*$/i', $val);
    }

    /**
     * 正则校验
     * @param $val
     * @param $re
     * @return bool
     */
    public static function test_regex($val, $re)
    {
        $str = '#' . str_replace('#', '\#', $re) . '#';
        $rt = preg_match($str, $val);
        if ($rt === FALSE) {
            throw new Exception('验证器正则表达式错误!');
        }
        return $rt != 0;
    }

    /**
     * 判断是数字
     * @param $val
     * @return bool
     */
    public static function test_number($val)
    {
        return !!preg_match('/^[\-\+]?((\d+(\.\d*)?)|(\.\d+))$/', $val);
    }

    /**
     * 判断是整数
     * @param $val
     * @return bool
     */
    public static function test_integer($val)
    {
        return !!preg_match('/^[\-\+]?\d+$/', $val);
    }

    /**
     * 判断值
     * @param $val
     * @param $num
     * @param bool $noeq
     * @return bool
     */
    public static function test_max($val, $num, $noeq = false)
    {
        if ($noeq) {
            return floatval($val) < floatval($num);
        } else {
            return floatval($val) <= floatval($num);
        }
    }

    /**
     * 判断值
     * @param $val
     * @param $num
     * @param bool $noeq
     * @return bool
     */
    public static function test_min($val, $num, $noeq = false)
    {
        if ($noeq) {
            return floatval($val) > floatval($num);
        } else {
            return floatval($val) >= floatval($num);
        }
    }

    /**
     * 判断值范围
     * @param $val
     * @param $min
     * @param $max
     * @param bool $noeq
     * @return bool
     */
    public static function test_range($val, $min, $max, $noeq = false)
    {
        return self::test_min($val, $min, $noeq) && self::test_max($val, $max, $noeq);
    }

    /**
     * 字符长度判断
     * @param $val
     * @param $len
     * @return bool
     */
    public static function test_minlength($val, $len)
    {
        return mb_strlen($val, 'UTF-8') >= intval($len);
    }

    /**
     * 字符长度判断
     * @param $val
     * @param $len
     * @return bool
     */
    public static function test_maxlength($val, $len)
    {
        return mb_strlen($val, 'UTF-8') <= intval($len);
    }

    /**
     * 字符区间判断
     * @param $val
     * @param $minlen
     * @param $maxlen
     * @return bool
     */
    public static function test_rangelength($val, $minlen, $maxlen)
    {
        return self::test_minlength($val, $minlen) && self::test_maxlength($val, $maxlen);
    }

    /**
     * 判断是两位小数的金额
     * @param $val
     * @return bool
     */
    public static function test_money($val)
    {
        return preg_match('/^[\-\+]{0,1}\d+[\.]\d{1,2}$/', $val) != 0 || self::test_integer($val);
    }

    /**
     * 判断日期时间格式
     * @param $val
     * @return bool
     */
    public static function test_date($val)
    {
        return !!preg_match('/^\d{4}-\d{1,2}-\d{1,2}(\s\d{1,2}(:\d{1,2}(:\d{1,2})?)?)?$/', $val);
    }

    /**
     * 添加远程校验
     * @param string $name
     * @param $func
     */
    public function addRemoute(string $name, $func)
    {
        $this->remoteFunc[$name] = $func;
    }

    /**
     * 添加校验函数
     * @param string $type
     * @param $func
     * @param string|null $error
     */
    public function addFunc(string $type, $func, string $error = null)
    {
        $this->func[$type] = $func;
        if (!empty($error)) {
            $this->def_errors[$type] = $error;
        }
    }

    /**
     * 字段检查
     * @param Field $field
     * @return bool
     */
    public function checkField(Field $field)
    {
        if (Validate::$default_errors == null) {
            Validate::$default_errors = Config::get('form.validate_default_errors', []);
        }
        if (!empty($field->error)) {
            return false;
        }
        if ($field->dataValDisabled) {
            return true;
        }
        if (!empty($field->childError)) {
            return false;
        }
        $value = $field->value;
        $validFunc = $field->getFunc('valid');
        if ($validFunc && is_callable($validFunc)) {
            $error = $validFunc($value);
            if (!empty($error)) {
                $field->error = $error;
                return false;
            }
        }
        $rules = $field->dataValRule;
        if ($rules == null) {
            return true;
        }
        $errors = $field->dataValMessage;
        if ($errors == null) {
            $errors = [];
        }
        $tempErrors = [];
        foreach ($errors as $type => $err) {
            $realType = Validate::getRealType($type);
            $tempErrors[$realType] = $err;
        }
        $errors = $tempErrors;
        $tempRules = [];
        foreach ($rules as $type => $args) {
            $realType = Validate::getRealType($type);
            $tempRules[$realType] = $args;
        }
        $rules = $tempRules;
        //验证非空
        if (isset($rules['required']) && $rules['required']) {
            $func = isset($this->func['required']) ? $this->func['required'] : Validate::getFunc('required');
            $r = call_user_func_array($func, [$value]);
            if (!$r) {
                $err = isset($this->def_errors['required']) ? $this->def_errors['required'] : (isset($errors['required']) ? $errors['required'] : (isset(Validate::$default_errors['required']) ? Validate::$default_errors['required'] : '必填项'));
                $field->error = $err;
                return false;
            }
            unset($rules['required']);
        }
        if (is_array($value)) {
            return true;
        }
        if (strlen($value) > 0 || (isset($rules['force']) && $rules['force'])) {
            unset($rules['force']);
            foreach ($rules as $type => $args) {
                if (!is_array($args)) {
                    $args = [$args];
                }
                $param = array_slice($args, 0);
                array_unshift($args, $value);
                $func = isset($this->func[$type]) ? $this->func[$type] : Validate::getFunc($type);
                if ($func == null) {
                    continue;
                }
                $out = call_user_func_array($func, $args);
                if (is_bool($out)) {
                    if ($out) {
                        continue;
                    }
                    $err = isset($this->def_errors[$type]) ? $this->def_errors[$type] : (isset($errors[$type]) ? $errors[$type] : (isset(Validate::$default_errors[$type]) ? Validate::$default_errors[$type] : '格式错误'));
                    $field->error = Validate::format($err, $param);
                    return false;
                }
                if (is_array($out) && isset($out['status']) && !$out['status'] && !empty($out['error'])) {
                    $field->error = Validate::format($out['error'], $param);
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 验证数据返回错误集合
     * @param array $rule
     */
    public static function validRules(array $input = [], array $ruleMap = [], array &$errors = [], bool $suspend = false)
    {
        if (Validate::$default_errors == null) {
            Validate::$default_errors = Config::get('form.validate_default_errors', []);
        }
        $tempErrors = [];
        $result = true;
        foreach ($ruleMap as $key => $item) {
            $tempErrors[$key] = '';
            if (!isset($item['rule'])) {
                $item['rule'] = null;
            }
            if (!isset($item['message'])) {
                $item['message'] = null;
            }
            if (isset($input[$key])) {
                $result = self::checkValue($input[$key], $item['rule'], $item['message'], $tempErrors[$key]) && $result;
            } else {
                $result = self::checkValue(null, $item['rule'], $item['message'], $tempErrors[$key]) && $result;
            }
            if (!$result) {
                $errors[$key] = $tempErrors[$key];
            }
            if ($suspend && !$result) {
                return false;
            }
        }
        return $result;
    }

    /**
     * 验证返回当个错误
     * @param array $input
     * @param array $ruleMap
     * @param string $errors
     * @return bool
     */
    public static function validRule(array $input = [], array $ruleMap = [], string &$errors = '')
    {
        $tempErrors = [];
        $result = self::validRules($input, $ruleMap, $tempErrors, true);
        if (!$result) {
            $errors = current($tempErrors);
            return false;
        }
        return true;
    }

    /**
     * 验证单个错误
     * @param array $value
     * @param array $rule
     */
    public static function checkValue($value, array $rules = null, array $message = null, string &$error)
    {
        if ($rules == null || count($rules) == 0) {
            return true;
        }
        $validFunc = isset($rules['validFunc']) ? $rules['validFunc'] : null;
        if ($validFunc && is_callable($validFunc)) {
            $err = $validFunc($value);
            if (!empty($err)) {
                $error = $err;
                return false;
            }
        }
        if ($message == null) {
            $message = [];
        }
        //获取
        $tempMegs = [];
        foreach ($message as $type => $msg) {
            $realType = Validate::getRealType($type);
            $tempMegs[$realType] = $msg;
        }
        $message = $tempMegs;
        $tempRules = [];
        foreach ($rules as $type => $args) {
            $realType = Validate::getRealType($type);
            $tempRules[$realType] = $args;
        }
        $rules = $tempRules;
        //验证非空
        if (isset($rules['required']) && $rules['required']) {
            $func = Validate::getFunc('required');
            $r = call_user_func_array($func, [$value]);
            if (!$r) {
                $error = (isset($message['required']) ? $message['required'] : (isset(Validate::$default_errors['required']) ? Validate::$default_errors['required'] : '必填项'));
                return false;
            }
            unset($rules['required']);
        }
        //如果是数组直接放弃
        if (is_array($value) || $value instanceof \stdClass) {
            return true;
        }

        if (strlen($value) > 0 || (isset($rules['force']) && $rules['force'])) {
            unset($rules['force']);
            foreach ($rules as $type => $args) {
                if (!is_array($args)) {
                    $args = [$args];
                }
                $param = array_slice($args, 0);
                array_unshift($args, $value);
                $func = Validate::getFunc($type);
                if ($func == null) {
                    continue;
                }
                $out = call_user_func_array($func, $args);
                if (is_bool($out)) {
                    if ($out) {
                        continue;
                    }
                    $err = (isset($message[$type]) ? $message[$type] : (isset(Validate::$default_errors[$type]) ? Validate::$default_errors[$type] : '格式错误'));
                    $error = Validate::format($err, $param);
                    return false;
                }
                if (is_array($out) && isset($out['status']) && !$out['status'] && !empty($out['error'])) {
                    $error = Validate::format($out['error'], $param);
                    return false;
                }
            }
        }
        return true;
    }
}


<?php

namespace CarbonPHP;

/**         Psr4AutoloaderClass
 *
 * An example of a general-purpose implementation that includes the optional
 * functionality of allowing multiple base directories for a single namespace
 * prefix.
 *
 * Given a foo-bar package of classes in the file system at the following
 * paths ...
 *
 *     /path/to/packages/foo-bar/
 *         src/
 *             Baz.php             # Foo\Bar\Baz
 *             Qux/
 *                 Quux.php        # Foo\Bar\Qux\Quux
 *         tests/
 *             BazTest.php         # Foo\Bar\BazTest
 *             Qux/
 *                 QuuxTest.php    # Foo\Bar\Qux\QuuxTest
 *
 * ... add the path to the class files for the \Foo\Bar\ namespace prefix
 * as follows:
 *
 *      <?php
 *      // instantiate the loader
 *      $loader = new \Example\Psr4AutoloaderClass;
 *
 *      // register the autoloader
 *      $loader->register();
 *
 *      // register the base directories for the namespace prefix
 *      $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
 *      $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');
 *
 * The following line would cause the autoloader to attempt to load the
 * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php:
 *
 *      <?php
 *      new \Foo\Bar\Qux\Quux;
 *
 * The following line would cause the autoloader to attempt to load the
 * \Foo\Bar\Qux\QuuxTest class from /path/to/packages/foo-bar/tests/Qux/QuuxTest.php:
 *
 *      <?php
 *      new \Foo\Bar\Qux\QuuxTest;
 */
class Autoload
{
    /**
     * An associative array where the key is a namespace prefix and the value
     * is an array of base directories for classes in that namespace.
     *
     * @var array
     */
    protected $prefixes = array();

    // This should be set to the applications file structure
    public function __construct()
    {
        spl_autoload_register( array($this, 'loadClass') );
    }

    /**
     * Adds a base directory for a namespace prefix.
     *
     * @param string $prefix The namespace prefix.
     * @param string $base_dir A base directory for class files in the
     * namespace.
     * @param bool $prepend If true, prepend the base directory to the stack
     * instead of appending it; this causes it to be searched first rather
     * than last.
     * @return void
     */
    public function addNamespace($prefix, $base_dir, $prepend = false)
    {
        // normalize namespace prefix
        $prefix = trim( $prefix, '\\' ) . '\\';

        // normalize the base directory with a trailing separator
        $base_dir = rtrim( $base_dir, DIRECTORY_SEPARATOR ) . '/';

        // initialize the namespace prefix array
        if (isset($this->prefixes[$prefix]) === false) {
            $this->prefixes[$prefix] = array();
        }

        // retain the base directory for the namespace prefix
        if ($prepend) {
            array_unshift( $this->prefixes[$prefix], $base_dir );
        } else {
            array_push( $this->prefixes[$prefix], $base_dir );
        }
    }

    /**
     * Loads the class file for a given class name.
     *
     * @param string $class The fully-qualified class name.
     * @return mixed The mapped file name on success, or boolean false on
     * failure.
     */

    private function loadClass($class)
    {
        // I Like The Common Case First Rule -- added by Richard Miles
        if ($this->requireFile(str_replace( '\\', '/', $class ) . '.php' )) return true;

        // the current namespace prefix
        $prefix = $class;

        // work backwards through the namespace names of the fully-qualified
        // class name to find a mapped file name
        while (false !== $pos = strrpos( $prefix, '\\' )) {

            // retain the trailing namespace separator in the prefix
            $prefix = substr( $class, 0, $pos + 1 );

            // the rest is the relative class name
            $relative_class = substr( $class, $pos + 1 );

            // try to load a mapped file for the prefix and relative class
            $mapped_file = $this->loadMappedFile( $prefix, $relative_class );
            if ($mapped_file) {
                return $mapped_file;
            }

            // remove the trailing namespace separator for the next iteration
            // of strrpos()
            $prefix = rtrim( $prefix, '\\' );
        }

        // never found a mapped file
        // return false;
        return false;
    }

    /**
     * If a file exists, require it from the file system.
     *
     * @param string $file The file to require.
     * @return bool True if the file exists, false if not.
     */
    private function requireFile($file)
    {
        if (file_exists( $file )) {
            require $file;
            return true;
        }
        return false;
    }

    /**
     * Load the mapped file for a namespace prefix and relative class.
     *
     * @param string $prefix The namespace prefix.
     * @param string $relative_class The relative class name.
     * @return mixed Boolean false if no mapped file can be loaded, or the
     * name of the mapped file that was loaded.
     */
    private function loadMappedFile($prefix, $relative_class)
    {
        // are there any base directories for this namespace prefix?
        if (isset($this->prefixes[$prefix]) === false) {
            return false;
        }

        // look through base directories for this namespace prefix
        foreach ($this->prefixes[$prefix] as $base_dir) {

            // replace the namespace prefix with the base directory,
            // replace namespace separators with directory separators
            // in the relative class name, append with .php
            $file = $base_dir
                . str_replace( '\\', '/', $relative_class )
                . '.php';

            // if the mapped file exists, require it
            if ($this->requireFile( $file )) {
                // yes, we're done
                return $file;
            }
        }
        // never found it
        return false;
    }
}

return new Autoload();


<?php
/**
 * Ongr_Sniffs_Commenting_BlockCommentSniff.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * Ongr_Sniffs_Commenting_BlockCommentSniff.
 *
 * Verifies that block comments are used appropriately.
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class Ongr_Sniffs_Commenting_BlockCommentSniff implements PHP_CodeSniffer_Sniff
{

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return array(
            T_COMMENT,
            T_DOC_COMMENT_OPEN_TAG,
        );

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned.
     * @param int                  $stackPtr  The position of the current token in the
     *                                        stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();

        // If it's an inline comment, return.
        if (substr($tokens[$stackPtr]['content'], 0, 2) !== '/*') {
            return;
        }

        // If this is a function/class/interface doc block comment, skip it.
        // We are only interested in inline doc block comments.
        if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_OPEN_TAG) {
            $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
            $ignore    = array(
                T_CLASS     => true,
                T_INTERFACE => true,
                T_TRAIT     => true,
                T_FUNCTION  => true,
                T_PUBLIC    => true,
                T_PRIVATE   => true,
                T_FINAL     => true,
                T_PROTECTED => true,
                T_STATIC    => true,
                T_ABSTRACT  => true,
                T_CONST     => true,
                T_VAR       => true,
            );
            if (isset($ignore[$tokens[$nextToken]['code']]) === true) {
                return;
            }

            $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
            if ($tokens[$prevToken]['code'] === T_OPEN_TAG) {
                return;
            }
            //ONGR We allow '/**' as block comment
//            $error = 'Block comments must be started with /*';
//            $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'WrongStart');
//            if ($fix === true) {
//                $phpcsFile->fixer->replaceToken($stackPtr, '/*');
//            }

            $end = $tokens[$stackPtr]['comment_closer'];
            if ($tokens[$end]['content'] !== '*/') {
                $error = 'Block comments must be ended with */';
                $fix   = $phpcsFile->addFixableError($error, $end, 'WrongEnd');
                if ($fix === true) {
                    $phpcsFile->fixer->replaceToken($stackPtr, '*/');
                }
            }

            return;
        }//end if

        $commentLines  = array($stackPtr);
        $nextComment   = $stackPtr;
        $lastLine      = $tokens[$stackPtr]['line'];
        $commentString = $tokens[$stackPtr]['content'];

        // Construct the comment into an array.
        while (($nextComment = $phpcsFile->findNext(T_WHITESPACE, ($nextComment + 1), null, true)) !== false) {
            if ($tokens[$nextComment]['code'] !== $tokens[$stackPtr]['code']) {
                // Found the next bit of code.
                break;
            }

            if (($tokens[$nextComment]['line'] - 1) !== $lastLine) {
                // Not part of the block.
                break;
            }

            $lastLine       = $tokens[$nextComment]['line'];
            $commentLines[] = $nextComment;
            $commentString .= $tokens[$nextComment]['content'];
            if ($tokens[$nextComment]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
                break;
            }
        }

        $commentText = str_replace($phpcsFile->eolChar, '', $commentString);
        $commentText = trim($commentText, '/* ');
        if ($commentText === '') {
            $error = 'Empty block comment not allowed';
            $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'Empty');
            if ($fix === true) {
                $phpcsFile->fixer->beginChangeset();
                $phpcsFile->fixer->replaceToken($stackPtr, '');
                $lastToken = array_pop($commentLines);
                for ($i = ($stackPtr + 1); $i <= $lastToken; $i++) {
                    $phpcsFile->fixer->replaceToken($i, '');
                }

                $phpcsFile->fixer->endChangeset();
            }

            return;
        }
        // ONGR we use single line block comments generated from IDE
        if (count($commentLines) === 1 && substr($tokens[$stackPtr]['content'], 0, 2) !== '/**') {
            $error = 'Single line block comment must start with "/**"';
            $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'SingleLine');
            if ($fix === true) {
                $comment = '/** '.$commentText. ' */';
                $phpcsFile->fixer->replaceToken($stackPtr, $comment);
            }

            return;
        }

        $content = trim($tokens[$stackPtr]['content']);
        if ($content !== '/*' && $content !== '/**') {
            $error = 'Block comment text must start on a new line';
            $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'NoNewLine');
            if ($fix === true) {
                $comment = preg_replace(
                    '/^(\s*\/\*\*?)/',
                    '$1'.$phpcsFile->eolChar.' ',
                    $tokens[$stackPtr]['content'],
                    1
                );
                $phpcsFile->fixer->replaceToken($stackPtr, $comment);
            }

            return;
        }

        //ONGR Allow '/*' as block comments with no space at the beginning
        $starColumn = ($tokens[$stackPtr]['column']);
        // Make sure first line isn't blank.
        if (trim($tokens[$commentLines[1]]['content']) === '') {
            $error = 'Empty line not allowed at start of comment';
            $phpcsFile->addError($error, $commentLines[1], 'HasEmptyLine');
        } else {
            // Check indentation of first line.
            $content = $tokens[$commentLines[1]]['content'];
            $commentText = ltrim($content);
            $leadingSpace = (strlen($content) - strlen($commentText));
            if ($leadingSpace !== $starColumn && trim($content)[0] !== '*') {
                $expected = $starColumn;
                $expected .= ($starColumn === 1) ? ' space' : ' spaces';
                $data = [
                    $expected,
                    $leadingSpace,
                ];
                $error = 'First line of comment not aligned correctly; expected %s but found %s';
                $phpcsFile->addError($error, $commentLines[1], 'FirstLineIndent', $data);
            }
            if (preg_match('#\p{Lu}|\*#u', $commentText[0]) === 0) {
                $error = 'Block comments must start with a capital letter';
                $phpcsFile->addError($error, $commentLines[1], 'NoCapital');
            }
        }

        // Check that each line of the comment is indented past the star.
        foreach ($commentLines as $line) {
            $leadingSpace = (strlen($tokens[$line]['content']) - strlen(ltrim($tokens[$line]['content'])));
            // First and last lines (comment opener and closer) are handled separately.
            if ($line === $commentLines[(count($commentLines) - 1)] || $line === $commentLines[0]) {
                continue;
            }

            // First comment line was handled above.
            if ($line === $commentLines[1]) {
                continue;
            }

            // If it's empty, continue.
            if (trim($tokens[$line]['content']) === '') {
                continue;
            }

            if ($leadingSpace < $starColumn) {
                $expected = $starColumn.' space';
                if ($starColumn !== 1) {
                    $expected .= 's';
                }

                $data = array(
                    $expected,
                    $leadingSpace,
                );

                $error = 'Comment line indented incorrectly; expected at least %s but found %s';
                //Ongr Disabled autofix.
                $fix   = $phpcsFile->addError($error, $line, 'LineIndent', $data);
//                if ($fix === true) {
//                    $newContent = str_repeat(' ', $starColumn).ltrim($tokens[$line]['content']);
//                    $phpcsFile->fixer->replaceToken($line, $newContent);
//                }
            }
        }//end foreach

        // Finally, test the last line is correct.
        $lastIndex = (count($commentLines) - 1);
        $content   = trim($tokens[$commentLines[$lastIndex]]['content']);
        if ($content !== '*/' && $content !== '**/') {
            $error = 'Comment closer must be on a new line';
            $phpcsFile->addError($error, $commentLines[$lastIndex]);
        } else {
            $content      = $tokens[$commentLines[$lastIndex]]['content'];
            $commentText  = ltrim($content);
            $leadingSpace = (strlen($content) - strlen($commentText));

            //ONGR Last line of block must have 1 space
            if ($leadingSpace !== ($tokens[$stackPtr]['column'])) {
                $expected = ($tokens[$stackPtr]['column'] - 1);
                if ($expected === 1) {
                    $expected .= ' space';
                } else {
                    $expected .= ' spaces';
                }

                $data = array(
                    $expected,
                    $leadingSpace,
                );

                $error = 'Last line of comment aligned incorrectly; expected %s but found %s';
                $phpcsFile->addError($error, $commentLines[$lastIndex], 'LastLineIndent', $data);
            }
        }//end if

        // Check that the lines before and after this comment are blank.
        $contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
        if (isset($tokens[$contentBefore]['scope_closer']) === true
            && $tokens[$contentBefore]['scope_opener'] === $contentBefore
        ) {
            if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) !== 1) {
                $error = 'Empty line not required before block comment';
                $phpcsFile->addError($error, $stackPtr, 'HasEmptyLineBefore');
            }
        } else {
            if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) < 2) {
                $error = 'Empty line required before block comment';
                $phpcsFile->addError($error, $stackPtr, 'NoEmptyLineBefore');
            }
        }

        $commentCloser = $commentLines[$lastIndex];
        $contentAfter  = $phpcsFile->findNext(T_WHITESPACE, ($commentCloser + 1), null, true);
        if ($contentAfter !== false && ($tokens[$contentAfter]['line'] - $tokens[$commentCloser]['line']) < 2) {
            $error = 'Empty line required after block comment';
            $phpcsFile->addError($error, $commentCloser, 'NoEmptyLineAfter');
        }

    }//end process()

}//end class


<?php
/**
 * Ongr_Sniffs_WhiteSpace_NamespaceSpacingSniff
 *
 * PHP version 5
 *
 * @category PHP
 * @package  Ongr_Strict_Codin_Standard
 * @author   Ongr Team <info@nfq.com>
 * @license  http://spdx.org/licenses/MIT MIT License
 * @link     https://github.com/ongr-io/Ongr
 */

/**
 * Ongr_Sniffs_WhiteSpace_NamespaceSpacingSniff
 *
 * Class to validate right amount of whitespaces after namespace declaration.
 *
 * PHP version 5
 *
 * @category PHP
 * @package  Ongr_Strict_Codin_Standard
 * @author   Ongr Team <info@nfq.com>
 * @license  http://spdx.org/licenses/MIT MIT License
 * @version  Release: @package_version@
 * @link     https://github.com/ongr-io/Ongr
 */
class Ongr_Sniffs_WhiteSpace_NamespaceSpacingSniff implements PHP_CodeSniffer_Sniff
{
    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return [T_NAMESPACE];
    }

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
    {
        #TODO add an autofix.
        $tokens = $phpcsFile->getTokens();

        if (isset($tokens[$stackPtr]['scope_opener'])) {
            // Skip bracketed namespaces.
            return;
        }
        $content = $phpcsFile->findNext(T_SEMICOLON, $stackPtr) + 1;
        while ($tokens[$content]['code'] == T_WHITESPACE) {
            ++$content;
        }
        if (($tokens[$content]['line'] - $tokens[$stackPtr]['line']) > 2) {
            // Case for minimum lines is written somewhere else.
            $phpcsFile->addError(
                'There must be exactly 1 blank line after namespace declaration',
                $stackPtr,
                'NamespaceSpacing'
            );
        }

        $content = $phpcsFile->findNext(T_NAMESPACE, $stackPtr) - 1;
        while ($tokens[$content]['code'] == T_WHITESPACE) {
            --$content;
        }
        $spaces = ($tokens[$content]['line'] - $tokens[$stackPtr]['line']) * -1;
        $spaces--;
        if ($spaces > 2) {
            // Case for minimum lines is written somewhere else.
            $phpcsFile->addError(
                'There must be exactly 1 blank line before namespace declaration; Found ' . $spaces,
                $stackPtr,
                'NamespaceSpacing'
            );
        }
    }
}


<?php

/*
 * This file is part of the Plum package.
 *
 * (c) 2010-2012 Julien Brochet <mewt@madalynn.eu>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Plum\Deployer;

use Plum\Server\ServerInterface;

abstract class AbstractDeployer implements DeployerInterface
{
    /**
     * {@inheritDoc}
     */
    public function deploy(ServerInterface $server, array $options = array())
    {
        $options = array_merge($options, $server->getOptions());

        $dryRun = false;
        if (isset($options['dry_run']) && $options['dry_run']) {
            $dryRun = true;
        }

        return $this->doDeploy($server, $options, $dryRun);
    }

    /**
     * Do a deploy
     *
     * @param ServerInterface $server  The server
     * @param array           $options The options
     * @param Boolean         $dryRun  Dry run mode
     */
    public abstract function doDeploy(ServerInterface $server, array $options, $dryRun);
}


<?php

namespace beacon;

use sdopx\Sdopx;

//开启调试模式
if (Config::get('sdopx.debug')) {
    Sdopx::$debug = true;
}
//设置后缀
if (Config::get('sdopx.extension')) {
    Sdopx::$extension = Config::get('sdopx.extension');
}
//注册配置项
Sdopx::registerConfig(function ($key) {
    return Config::get($key);
});

/**
 * Created by PhpStorm.
 * User: wj008
 * Date: 2017/12/12
 * Time: 15:50
 */
class View
{

    /**
     * @var View|Sdopx
     */
    private static $instance = null;
    /**
     * @var Sdopx
     */
    public $template = null;

    /**
     * @return View|Sdopx
     */
    public static function instance()
    {
        if (self::$instance == null) {
            self::$instance = new View();
        }
        return self::$instance;
    }

    public function __construct()
    {
        $this->template = $sdopx = new Sdopx();
        //如果已经有实例了，再次创建的时候使用相同的设置,可能会在实例中设置
        if (self::$instance) {
            $template = self::$instance->template;
            $sdopx->setCompileDir($template->compileDir);
            $sdopx->setTemplateDir($template->getTemplateDir());
            $sdopx->leftDelimiter = $template->leftDelimiter;
            $sdopx->rightDelimiter = $template->rightDelimiter;
            $sdopx->compileForce = $template->compileForce;
            $sdopx->compileCheck = $template->compileCheck;
            $sdopx->context = $template->context;
            $this->assign('this', $sdopx->context);
        } else {
            $config = Config::get('sdopx.*');
            //模板目录
            $templateDir = empty($config['template_dir']) ? 'view' : $config['template_dir'];
            if (is_array($templateDir)) {
                foreach ($templateDir as &$dir) {
                    $dir = Utils::trimPath($dir);
                    $dir = Utils::path(ROOT_DIR, $dir);
                }
            } else {
                $templateDir = Utils::trimPath($templateDir);
                $templateDir = Utils::path(ROOT_DIR, $templateDir);
            }
            //公共模板目录
            $commonDir = Utils::trimPath(empty($config['common_dir']) ? 'view/common' : $config['common_dir']);
            $commonDir = Utils::path(ROOT_DIR, $commonDir);
            //运行时目录
            $runtimeDir = Utils::trimPath(empty($config['runtime_dir']) ? 'runtime' : $config['runtime_dir']);
            $runtimeDir = Utils::path(ROOT_DIR, $runtimeDir);
            $sdopx->setTemplateDir($templateDir);
            $sdopx->addTemplateDir($commonDir, 'common');
            $sdopx->setCompileDir($runtimeDir);

            //设置边界符号
            if (!empty($config['left_delimiter']) && !empty($config['right_delimiter'])) {
                $sdopx->leftDelimiter = $config['left_delimiter'];
                $sdopx->rightDelimiter = $config['right_delimiter'];
            }
            //强行编译
            if (isset($config['compile_force'])) {
                $sdopx->compileForce = $config['compile_force'];
            }
            //检查编译
            if (isset($config['compile_check'])) {
                $sdopx->compileCheck = $config['compile_check'];
            }
        }
    }

    public function __call($method, $params)
    {
        return call_user_func_array([$this->template, $method], $params);
    }

    /**
     * 设置模板引擎上下文
     * @param Controller $controller
     */
    public function context(Controller $controller)
    {
        $this->template->context = $controller;
        $this->assign('this', $controller);
    }
}


<?php

namespace Nightjar\Slug;

use InvalidArgumentException;
use UnexpectedValueException;
use SilverStripe\ORM\DataObject;
use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Control\Controller;
use SilverStripe\View\Parsers\URLSegmentFilter;

/**
 * Adds a 'url slug' property to DataObject classes, in order for them to be able to be loaded via a URL
 * through a{@see SilverStripe\Control\Controller}. The typical use case for this is to view records related
 * to a {@see Page}, to be able to have a controller action that doesn't need to reference the ID ofthe record.
 * E.g. /products/nice-jacket - where this is /pageType/relatedObject-notAPage
 *
 * To simplify the controller section of this purpose {@see SlugHandler}
 */
class Slug extends DataExtension
{
    /**
     * Used to set {@see $active} to inactive, or 'link'
     */
    const ACTIVE_NONE = null;

    /**
     * Used to set and check {@see $active} as a section (ancestor of 'current')
     */
    const ACTIVE_SECTION = false;

    /**
     * Used to set and check {@see $active} as the current object active in a request
     */
    const ACTIVE_CURRENT = true;

    private static $db = [
        'URLSlug' => 'Varchar(255)',
    ];

    private static $indexes = [
        'URLSlug' => true,
    ];

    /**
     * The field on the owner that we should take the value from in order to generate a slug
     *
     * @var string
     */
    protected $fieldToSlug;

    /**
     * If we should restrict the slugging uniqueness to a certain subset of the owner class,
     * this will be the name of the relation to filter by to detect uniqueness
     *
     * @var string|null
     */
    protected $relationName;

    /**
     * Whether or not we should update the URLSlug field when the field to slug changes
     *
     * @var boolean
     */
    protected $enforceParity;

    /**
     * The owner has been accessed via a route involving the URLSlug
     * Tri state; current, section, none
     *
     * @var null|boolean {@see setSlugActive}
     */
    protected $active = null;

    /**
     * Apply extension with configurable defaults
     *
     * @param string  $fieldToSlug   The field on the owner to base the URL Slug from - defaults to 'Title'
     * @param string  $relationName  Optional name of the has_one relationship to the owner's parent class/Page
     * @param boolean $enforceParity true to alter the URLSlug whenever the $fieldToSlug changes value (default: false)
     */
    public function __construct($fieldToSlug = 'Title', $relationName = null, $enforceParity = false)
    {
        parent::__construct();
        $this->fieldToSlug = $fieldToSlug;
        $this->relationName = $relationName;
        $this->enforceParity = $enforceParity;
    }

    public function setOwner($owner)
    {
        // parent method is set in a try, with a finally to clearOwner - so it is important we set it first,
        // otherwise our InvalidArgumentException will be swallowed by a BadMethodCallException!
        parent::setOwner($owner);

        // throw an exception if the $relationName is invalid or not has_one
        if ($this->relationName) {
            $ownerClass = get_class($owner);
            $valid = DataObject::getSchema()->hasOneComponent($ownerClass, $this->relationName);
            if (!$valid) {
                throw new InvalidArgumentException("$this->relationName is an invalid has_one on $ownerClass");
            }
        }
    }

    /**
     * Set whether this slugged item is being viewed
     * {@see self::ACTIVE_NONE}
     * {@see self::ACTIVE_SECTION}
     * {@see self::ACTIVE_CURRENT}
     *
     * @param null|boolean $active
     * @return DataObject
     * @throws InvalidArgumentException
     */
    public function setSlugActive($active)
    {
        $validParameter = (
            $active === self::ACTIVE_NONE
            || $active === self::ACTIVE_SECTION
            || $active === self::ACTIVE_CURRENT
        );

        if (!$validParameter) {
            throw new InvalidArgumentException(
                "Passed an invalid value to setSlugActive. Please use the constants provided on" . self::class
            );
        }
        $this->active = $active;
        return $this->getOwner();
    }

    /**
     * Generate a url slug segment
     *
     * @param  boolean $forceRegeneration
     * @return string
     */
    public function getSlug($forceRegeneration = false)
    {
        $owner = $this->getOwner();
        $field = $this->fieldToSlug;
        $unfilteredSlug = $owner->URLSlug;
        if (!$unfilteredSlug || $forceRegeneration) {
            $unfilteredSlug = $owner->$field;
        }
        return URLSegmentFilter::create()->filter($unfilteredSlug);
    }

    /**
     * Check for collisions, iff we need to update the slug and
     * upate the model with the confirmedsafe value before writing
     */
    public function onBeforeWrite()
    {
        $owner = $this->getOwner();
        $slugHasChanged = $owner->isChanged('URLSlug');
        $fieldToSlugHasChanged = $owner->isChanged($this->fieldToSlug);
        $updateSlug = (
            empty($owner->URLSlug)
            || ($this->enforceParity && $fieldToSlugHasChanged)
            || (!$this->enforceParity && $slugHasChanged)
        );

        if ($updateSlug) {
            $owner->URLSlug = $this->getSlug($this->enforceParity);

            $collisionList = DataObject::get(get_class($owner))->exclude('ID', $owner->ID);
            $filter = ['URLSlug' => $owner->URLSlug];
            if ($this->relationName) {
                $parentIDField = $this->relationName . 'ID';
                $filter[$parentIDField] = $owner->$parentIDField;
                // Also handle polymorphic relationships
                $parentClassName = DataObject::getSchema()->hasOneComponent(get_class($owner), $this->relationName);
                if ($parentClassName === DataObject::class) {
                    $parentClassField = $this->relationName . 'Class';
                    $filter[$parentClassField] = $owner->$parentClassField;
                }
            }

            $count = 1;
            while ($collisionList->filter($filter)->exists()) {
                $owner->URLSlug = $owner->URLSlug . $count++;
                $filter['URLSlug'] = $owner->URLSlug;
            }
        } elseif ($slugHasChanged) {
            // enforceParity is set, and the slug has changed... but the
            // field to slug has not. We need to reset to keep parity.
            // Ideally we could do this via the $original property through
            // {@see DataObject::getChangedFields}, however the returned
            // 'before' value for a changed field is unreliable :(
            // https://github.com/silverstripe/silverstripe-framework/issues/8443
            throw new UnexpectedValueException(
                'URLSlug has been updated independently of the tracked field, ' .
                'but this has been disabled via Slug::enforceParity'
            );
        }
    }

    public function updateCMSFields(FieldList $fields)
    {
        if ($this->enforceParity) {
            $fields->removeByName('URLSlug');
        }
    }

    /**
     * Get the link to be able to request this (owner) object from a URL
     * The nature of a DataExtension is that this can be overridden at any
     * time by defining the `Link($action = null)` method on the owner class.
     *
     * @param string|array $action
     * @return string
     */
    public function Link($action = null)
    {
        $link = null;
        $owner = $this->getOwner();
        $action = ($action) ? Controller::join_links($owner->URLSlug, $action) : $owner->URLSlug;

        $relationName = $this->relationName;
        if ($relationName && ($parent = $owner->$relationName()) && $parent->hasMethod('Link')) {
            $link = $parent->Link($action);
        } elseif (Controller::has_curr()) {
            // Quite the assumption, but sufficient in most cases.
            $link = Controller::curr()->Link($action);
        }
        return $link;
    }

    /**
     * Returns true if this is the slugged object being used to handle this request.
     *
     * @return boolean
     */
    public function isCurrent()
    {
        return $this->active === self::ACTIVE_CURRENT;
    }

    /**
     * Check if this slugged object is in the currently active section
     * (i.e. it, or one of its children is currently being viewed).
     *
     * @return boolean
     */
    public function isSection()
    {
        return $this->isCurrent() || ($this->active === self::ACTIVE_SECTION);
    }

    /**
     * Return "link" or "section" depending on if this is the current viewing object.
     * {@see isCurrent}
     *
     * @return string
     */
    public function LinkOrCurrent()
    {
        return $this->isCurrent() ? 'current' : 'link';
    }

    /**
     * Return "link" or "section" depending on if this is the current section.
     * {@see isSection}
     *
     * @return string
     */
    public function LinkOrSection()
    {
        return $this->isSection() ? 'section' : 'link';
    }

    /**
     * Return "current", "section", or "link" depending on if this page is the slugged item
     * currently being viewed, in the section (an ancestor of the current), or simply exists - respectively.
     *
     * @return string
     */
    public function LinkingMode()
    {
        if ($this->isCurrent()) {
            return 'current';
        } elseif ($this->isSection()) {
            return 'section';
        } else {
            return 'link';
        }
    }
}