Przeglądaj źródła

[更新]ComposerUpdate

Anyon 7 lat temu
rodzic
commit
9cca1a81d9

+ 1 - 1
thinkphp/library/think/App.php

@@ -20,7 +20,7 @@ use think\route\Dispatch;
  */
 class App implements \ArrayAccess
 {
-    const VERSION = '5.1.9';
+    const VERSION = '5.1.10';
 
     /**
      * 当前模块路径

+ 1 - 7
thinkphp/library/think/Loader.php

@@ -56,13 +56,7 @@ class Loader
     public static function getRootPath()
     {
         if ('cli' == PHP_SAPI) {
-            $cwdPath = getcwd();
-
-            if (0 === strpos($_SERVER['argv'][0], $cwdPath)) {
-                $scriptName = $_SERVER['argv'][0];
-            } else {
-                $scriptName = $cwdPath . DIRECTORY_SEPARATOR . $_SERVER['argv'][0];
-            }
+            $scriptName = realpath($_SERVER['argv'][0]);
         } else {
             $scriptName = $_SERVER['SCRIPT_FILENAME'];
         }

+ 27 - 9
thinkphp/library/think/console/command/Clear.php

@@ -24,22 +24,40 @@ class Clear extends Command
         $this
             ->setName('clear')
             ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null)
+            ->addOption('cache', 'c', Option::VALUE_NONE, 'clear cache file')
+            ->addOption('log', 'l', Option::VALUE_NONE, 'clear log file')
+            ->addOption('dir', 'r', Option::VALUE_NONE, 'clear empty dir')
             ->setDescription('Clear runtime file');
     }
 
     protected function execute(Input $input, Output $output)
     {
-        $path  = $input->getOption('path') ?: App::getRuntimePath();
-        $files = scandir($path);
-        if ($files) {
-            foreach ($files as $file) {
-                if ('.' != $file && '..' != $file && is_dir($path . $file)) {
-                    array_map('unlink', glob($path . $file . DIRECTORY_SEPARATOR . '*.*'));
-                } elseif ('.gitignore' != $file && is_file($path . $file)) {
-                    unlink($path . $file);
+        if ($input->getOption('cache')) {
+            $path = App::getRuntimePath() . 'cache';
+        } elseif ($input->getOption('log')) {
+            $path = App::getRuntimePath() . 'log';
+        } else {
+            $path = $input->getOption('path') ?: App::getRuntimePath();
+        }
+
+        $rmdir = $input->getOption('dir') ? true : false;
+        $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir);
+        $output->writeln("<info>Clear Successed</info>");
+    }
+
+    protected function clear($path, $rmdir)
+    {
+        $files = is_dir($path) ? scandir($path) : [];
+
+        foreach ($files as $file) {
+            if ('.' != $file && '..' != $file && is_dir($path . $file)) {
+                array_map('unlink', glob($path . $file . DIRECTORY_SEPARATOR . '*.*'));
+                if ($rmdir) {
+                    rmdir($path . $file);
                 }
+            } elseif ('.gitignore' != $file && is_file($path . $file)) {
+                unlink($path . $file);
             }
         }
-        $output->writeln("<info>Clear Successed</info>");
     }
 }

+ 43 - 20
thinkphp/library/think/db/Builder.php

@@ -136,7 +136,7 @@ abstract class Builder
             } elseif (is_null($val)) {
                 $result[$item] = 'NULL';
             } elseif (is_array($val) && !empty($val)) {
-                switch ($val[0]) {
+                switch (strtoupper($val[0])) {
                     case 'INC':
                         $result[$item] = $item . ' + ' . floatval($val[1]);
                         break;
@@ -563,6 +563,10 @@ abstract class Builder
         // EXISTS 查询
         if ($value instanceof \Closure) {
             $value = $this->parseClosure($query, $value, false);
+        } elseif ($value instanceof Expression) {
+            $value = $value->getValue();
+        } else {
+            throw new Exception('where express error:' . $value);
         }
 
         return $exp . ' (' . $value . ')';
@@ -744,6 +748,10 @@ abstract class Builder
 
         $bindName = $bindName ?: $key;
 
+        if ($query->isBind($bindName)) {
+            $bindName .= '_' . str_replace('.', '_', uniqid('', true));
+        }
+
         $query->bind($bindName, $value, $bindType);
 
         return ':' . $bindName;
@@ -815,21 +823,7 @@ abstract class Builder
             if ($val instanceof Expression) {
                 $array[] = $val->getValue();
             } elseif (is_array($val)) {
-                if (isset($val['sort'])) {
-                    $sort = ' ' . $val['sort'];
-                    unset($val['sort']);
-                } else {
-                    $sort = '';
-                }
-
-                $options = $query->getOptions();
-                $bind    = $this->connection->getFieldsBind($options['table']);
-
-                foreach ($val as $k => $item) {
-                    $val[$k] = $this->parseDataBind($query, $key, $item, $bind, $k);
-                }
-
-                $array[] = 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
+                $array[] = $this->parseOrderField($query, $key, $val);
             } elseif ('[rand]' == $val) {
                 $array[] = $this->parseRand($query);
             } else {
@@ -839,14 +833,43 @@ abstract class Builder
                     $sort = $val;
                 }
 
-                $sort    = in_array(strtolower($sort), ['asc', 'desc'], true) ? ' ' . $sort : '';
+                $sort    = strtoupper($sort);
+                $sort    = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
                 $array[] = $this->parseKey($query, $key, true) . $sort;
             }
         }
 
-        $order = implode(',', $array);
+        return ' ORDER BY ' . implode(',', $array);
+    }
+
+    /**
+     * group分析
+     * @access protected
+     * @param  Query     $query        查询对象
+     * @param  mixed     $key
+     * @param  array     $val
+     * @return string
+     */
+    protected function parseOrderField($query, $key, $val)
+    {
+        if (isset($val['sort'])) {
+            $sort = $val['sort'];
+            unset($val['sort']);
+        } else {
+            $sort = '';
+        }
+
+        $sort = strtoupper($sort);
+        $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
+
+        $options = $query->getOptions();
+        $bind    = $this->connection->getFieldsBind($options['table']);
+
+        foreach ($val as $k => $item) {
+            $val[$k] = $this->parseDataBind($query, $key, $item, $bind, $k);
+        }
 
-        return ' ORDER BY ' . $order;
+        return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort;
     }
 
     /**
@@ -1065,7 +1088,7 @@ abstract class Builder
         $fields = [];
 
         foreach ($insertFields as $field) {
-            $fields[] = $this->parseKey($query, $field, true);
+            $fields[] = $this->parseKey($query, $field);
         }
 
         return str_replace(

+ 24 - 7
thinkphp/library/think/db/Query.php

@@ -1233,6 +1233,10 @@ class Query
      */
     public function whereExists($condition, $logic = 'AND')
     {
+        if (is_string($condition)) {
+            $condition = $this->raw($condition);
+        }
+
         $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition];
         return $this;
     }
@@ -1246,6 +1250,10 @@ class Query
      */
     public function whereNotExists($condition, $logic = 'AND')
     {
+        if (is_string($condition)) {
+            $condition = $this->raw($condition);
+        }
+
         $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition];
         return $this;
     }
@@ -1485,14 +1493,16 @@ class Query
             if (in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
                 // null查询
                 $where = [$field, $op, ''];
-            } elseif (in_array(strtolower($op), ['=', 'eq', null], true)) {
+            } elseif (in_array($op, ['=', 'eq', 'EQ', null], true)) {
                 $where = [$field, 'NULL', ''];
-            } elseif (in_array(strtolower($op), ['<>', 'neq'], true)) {
+            } elseif (in_array($op, ['<>', 'neq', 'NEQ'], true)) {
                 $where = [$field, 'NOTNULL', ''];
             } else {
                 // 字段相等查询
                 $where = [$field, '=', $op];
             }
+        } elseif (in_array(strtoupper($op), ['REGEXP', 'NOT REGEXP', 'EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
+            $where = [$field, $op, is_string($condition) ? $this->raw($condition) : $condition];
         } else {
             $where = $field ? [$field, $op, $condition] : null;
         }
@@ -1537,8 +1547,12 @@ class Query
     {
         $logic = strtoupper($logic);
 
-        if (isset($this->options['where'][$logic][$field])) {
-            unset($this->options['where'][$logic][$field]);
+        if (isset($this->options['where'][$logic])) {
+            foreach ($this->options['where'][$logic] as $key => $val) {
+                if (is_array($val) && $val[0] == $field) {
+                    unset($this->options['where'][$logic][$key]);
+                }
+            }
         }
 
         return $this;
@@ -1827,11 +1841,14 @@ class Query
      * @param  string       $order
      * @return $this
      */
-    public function orderField($field, array $values = [], $order = '')
+    public function orderField($field, array $values, $order = '')
     {
-        $values['sort'] = $order;
+        if (!empty($values)) {
+            $values['sort'] = $order;
+
+            $this->options['order'][$field] = $values;
+        }
 
-        $this->options['order'][$field] = $values;
         return $this;
     }
 

+ 9 - 32
thinkphp/library/think/db/builder/Mysql.php

@@ -12,6 +12,7 @@
 namespace think\db\builder;
 
 use think\db\Builder;
+use think\db\Expression;
 use think\db\Query;
 
 /**
@@ -88,16 +89,16 @@ class Mysql extends Builder
     /**
      * 正则查询
      * @access protected
-     * @param  Query     $query        查询对象
-     * @param  string    $key
-     * @param  string    $exp
-     * @param  mixed     $value
-     * @param  string    $field
+     * @param  Query        $query        查询对象
+     * @param  string       $key
+     * @param  string       $exp
+     * @param  Expression   $value
+     * @param  string       $field
      * @return string
      */
-    protected function parseRegexp(Query $query, $key, $exp, $value, $field)
+    protected function parseRegexp(Query $query, $key, $exp, Expression $value, $field)
     {
-        return $key . ' ' . $exp . ' ' . $value;
+        return $key . ' ' . $exp . ' ' . $value->getValue();
     }
 
     /**
@@ -135,7 +136,7 @@ class Mysql extends Builder
             }
         }
 
-        if ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
+        if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) {
             $key = '`' . $key . '`';
         }
 
@@ -151,30 +152,6 @@ class Mysql extends Builder
     }
 
     /**
-     * field分析
-     * @access protected
-     * @param  Query     $query     查询对象
-     * @param  mixed     $fields    字段名
-     * @return string
-     */
-    protected function parseField(Query $query, $fields)
-    {
-        $fieldsStr = parent::parseField($query, $fields);
-        $options   = $query->getOptions();
-
-        if (!empty($options['point'])) {
-            $array = [];
-            foreach ($options['point'] as $key => $field) {
-                $key     = !is_numeric($key) ? $key : $field;
-                $array[] = 'AsText(' . $this->parseKey($query, $key) . ') AS ' . $this->parseKey($query, $field);
-            }
-            $fieldsStr .= ',' . implode(',', $array);
-        }
-
-        return $fieldsStr;
-    }
-
-    /**
      * 随机排序
      * @access protected
      * @param  Query     $query        查询对象

+ 1 - 1
thinkphp/library/think/db/builder/Pgsql.php

@@ -51,7 +51,7 @@ class Pgsql extends Builder
      * @access public
      * @param  Query     $query     查询对象
      * @param  string    $key       字段名
-     * @param  bool   $strict   严格检测
+     * @param  bool      $strict   严格检测
      * @return string
      */
     public function parseKey(Query $query, $key, $strict = false)

+ 1 - 1
thinkphp/library/think/db/builder/Sqlsrv.php

@@ -104,7 +104,7 @@ class Sqlsrv extends Builder
             }
         }
 
-        if ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
+        if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {
             $key = '[' . $key . ']';
         }
 

+ 11 - 2
thinkphp/library/think/route/Rule.php

@@ -985,13 +985,22 @@ abstract class Rule
         }
 
         // 是否区分 / 地址访问
-        if (!empty($option['remove_slash']) && '/' != $rule) {
-            $rule = rtrim($rule, '/');
+        if ('/' != $rule) {
+            if (!empty($option['remove_slash'])) {
+                $rule = rtrim($rule, '/');
+            } elseif (substr($rule, -1) == '/') {
+                $rule     = rtrim($rule, '/');
+                $hasSlash = true;
+            }
         }
 
         $regex = str_replace($match, $replace, $rule);
         $regex = str_replace([')?/', ')/', ')?-', ')-', '\\\\/'], [')\/', ')\/', ')\-', ')\-', '\/'], $regex);
 
+        if (isset($hasSlash)) {
+            $regex .= '\/';
+        }
+
         return $regex . ($completeMatch ? '$' : '');
     }
 

+ 1 - 1
vendor/autoload.php

@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32::getLoader();
+return ComposerAutoloaderInit7f21c27a120d47e6491fd4a016f044cb::getLoader();

+ 2 - 0
vendor/composer/autoload_classmap.php

@@ -101,11 +101,13 @@ return array(
     'Qiniu\\Storage\\ResumeUploader' => $vendorDir . '/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php',
     'Qiniu\\Storage\\UploadManager' => $vendorDir . '/qiniu/php-sdk/src/Qiniu/Storage/UploadManager.php',
     'Qiniu\\Zone' => $vendorDir . '/qiniu/php-sdk/src/Qiniu/Zone.php',
+    'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => $vendorDir . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => $vendorDir . '/symfony/options-resolver/Exception/AccessException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/options-resolver/Exception/ExceptionInterface.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/MissingOptionsException.php',
+    'Symfony\\Component\\OptionsResolver\\Exception\\NoConfigurationException' => $vendorDir . '/symfony/options-resolver/Exception/NoConfigurationException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => $vendorDir . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => $vendorDir . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
     'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',

+ 7 - 7
vendor/composer/autoload_real.php

@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32
+class ComposerAutoloaderInit7f21c27a120d47e6491fd4a016f044cb
 {
     private static $loader;
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInit7f21c27a120d47e6491fd4a016f044cb', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInit7f21c27a120d47e6491fd4a016f044cb', 'loadClassLoader'));
 
         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
         if ($useStaticLoader) {
             require_once __DIR__ . '/autoload_static.php';
 
-            call_user_func(\Composer\Autoload\ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32::getInitializer($loader));
+            call_user_func(\Composer\Autoload\ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb::getInitializer($loader));
         } else {
             $map = require __DIR__ . '/autoload_namespaces.php';
             foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInite11d5d0f579f9ff8739edc30bb4f8f32
         $loader->register(true);
 
         if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32::$files;
+            $includeFiles = Composer\Autoload\ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb::$files;
         } else {
             $includeFiles = require __DIR__ . '/autoload_files.php';
         }
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequiree11d5d0f579f9ff8739edc30bb4f8f32($fileIdentifier, $file);
+            composerRequire7f21c27a120d47e6491fd4a016f044cb($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
 
-function composerRequiree11d5d0f579f9ff8739edc30bb4f8f32($fileIdentifier, $file)
+function composerRequire7f21c27a120d47e6491fd4a016f044cb($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         require $file;

+ 6 - 4
vendor/composer/autoload_static.php

@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32
+class ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb
 {
     public static $files = array (
         '1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
@@ -179,11 +179,13 @@ class ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32
         'Qiniu\\Storage\\ResumeUploader' => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php',
         'Qiniu\\Storage\\UploadManager' => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/Storage/UploadManager.php',
         'Qiniu\\Zone' => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/Zone.php',
+        'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => __DIR__ . '/..' . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/AccessException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/ExceptionInterface.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/MissingOptionsException.php',
+        'Symfony\\Component\\OptionsResolver\\Exception\\NoConfigurationException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/NoConfigurationException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
         'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
@@ -256,9 +258,9 @@ class ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInite11d5d0f579f9ff8739edc30bb4f8f32::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit7f21c27a120d47e6491fd4a016f044cb::$classMap;
 
         }, null, ClassLoader::class);
     }

+ 14 - 14
vendor/composer/installed.json

@@ -175,17 +175,17 @@
     },
     {
         "name": "topthink/framework",
-        "version": "v5.1.9",
-        "version_normalized": "5.1.9.0",
+        "version": "v5.1.10",
+        "version_normalized": "5.1.10.0",
         "source": {
             "type": "git",
             "url": "https://github.com/top-think/framework.git",
-            "reference": "c49df2fa54879105e451f7eaaf841d218206f02f"
+            "reference": "66b546f7cac130712d1e08fe2620105228f4bd8a"
         },
         "dist": {
             "type": "zip",
-            "url": "https://files.phpcomposer.com/files/top-think/framework/c49df2fa54879105e451f7eaaf841d218206f02f.zip",
-            "reference": "c49df2fa54879105e451f7eaaf841d218206f02f",
+            "url": "https://files.phpcomposer.com/files/top-think/framework/66b546f7cac130712d1e08fe2620105228f4bd8a.zip",
+            "reference": "66b546f7cac130712d1e08fe2620105228f4bd8a",
             "shasum": ""
         },
         "require": {
@@ -201,7 +201,7 @@
             "sebastian/phpcpd": "2.*",
             "squizlabs/php_codesniffer": "2.*"
         },
-        "time": "2018-04-12T11:16:28+00:00",
+        "time": "2018-04-16T05:33:00+00:00",
         "type": "think-framework",
         "installation-source": "dist",
         "notification-url": "https://packagist.org/downloads/",
@@ -269,27 +269,27 @@
     },
     {
         "name": "symfony/options-resolver",
-        "version": "v3.3.6",
-        "version_normalized": "3.3.6.0",
+        "version": "v3.4.8",
+        "version_normalized": "3.4.8.0",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/options-resolver.git",
-            "reference": "ff48982d295bcac1fd861f934f041ebc73ae40f0"
+            "reference": "f3109a6aedd20e35c3a33190e932c2b063b7b50e"
         },
         "dist": {
             "type": "zip",
-            "url": "https://files.phpcomposer.com/files/symfony/options-resolver/ff48982d295bcac1fd861f934f041ebc73ae40f0.zip",
-            "reference": "ff48982d295bcac1fd861f934f041ebc73ae40f0",
+            "url": "https://files.phpcomposer.com/files/symfony/options-resolver/f3109a6aedd20e35c3a33190e932c2b063b7b50e.zip",
+            "reference": "f3109a6aedd20e35c3a33190e932c2b063b7b50e",
             "shasum": ""
         },
         "require": {
-            "php": ">=5.5.9"
+            "php": "^5.5.9|>=7.0.8"
         },
-        "time": "2017-04-12T14:14:56+00:00",
+        "time": "2018-01-11T07:56:07+00:00",
         "type": "library",
         "extra": {
             "branch-alias": {
-                "dev-master": "3.3-dev"
+                "dev-master": "3.4-dev"
             }
         },
         "installation-source": "dist",

+ 8 - 2
vendor/symfony/options-resolver/CHANGELOG.md

@@ -1,6 +1,12 @@
 CHANGELOG
 =========
 
+3.4.0
+-----
+
+ * added `OptionsResolverIntrospector` to inspect options definitions inside an `OptionsResolver` instance
+ * added array of types support in allowed types (e.g int[])
+
 2.6.0
 -----
 
@@ -25,7 +31,7 @@ CHANGELOG
  * deprecated OptionsResolver::isKnown() in favor of isDefined()
  * [BC BREAK] OptionsResolver::isRequired() returns true now if a required
    option has a default value set
- * [BC BREAK] merged Options into OptionsResolver and turned Options into an 
+ * [BC BREAK] merged Options into OptionsResolver and turned Options into an
    interface
  * deprecated Options::overload() (now in OptionsResolver)
  * deprecated Options::set() (now in OptionsResolver)
@@ -36,7 +42,7 @@ CHANGELOG
    lazy option/normalizer closures now
  * [BC BREAK] removed Traversable interface from Options since using within
    lazy option/normalizer closures resulted in exceptions
- * [BC BREAK] removed Options::all() since using within lazy option/normalizer 
+ * [BC BREAK] removed Options::all() since using within lazy option/normalizer
    closures resulted in exceptions
  * [BC BREAK] OptionDefinitionException now extends LogicException instead of
    RuntimeException

+ 102 - 0
vendor/symfony/options-resolver/Debug/OptionsResolverIntrospector.php

@@ -0,0 +1,102 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsResolver\Debug;
+
+use Symfony\Component\OptionsResolver\Exception\NoConfigurationException;
+use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+/**
+ * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
+ *
+ * @final
+ */
+class OptionsResolverIntrospector
+{
+    private $get;
+
+    public function __construct(OptionsResolver $optionsResolver)
+    {
+        $this->get = \Closure::bind(function ($property, $option, $message) {
+            /** @var OptionsResolver $this */
+            if (!$this->isDefined($option)) {
+                throw new UndefinedOptionsException(sprintf('The option "%s" does not exist.', $option));
+            }
+
+            if (!array_key_exists($option, $this->{$property})) {
+                throw new NoConfigurationException($message);
+            }
+
+            return $this->{$property}[$option];
+        }, $optionsResolver, $optionsResolver);
+    }
+
+    /**
+     * @param string $option
+     *
+     * @return mixed
+     *
+     * @throws NoConfigurationException on no configured value
+     */
+    public function getDefault($option)
+    {
+        return call_user_func($this->get, 'defaults', $option, sprintf('No default value was set for the "%s" option.', $option));
+    }
+
+    /**
+     * @param string $option
+     *
+     * @return \Closure[]
+     *
+     * @throws NoConfigurationException on no configured closures
+     */
+    public function getLazyClosures($option)
+    {
+        return call_user_func($this->get, 'lazy', $option, sprintf('No lazy closures were set for the "%s" option.', $option));
+    }
+
+    /**
+     * @param string $option
+     *
+     * @return string[]
+     *
+     * @throws NoConfigurationException on no configured types
+     */
+    public function getAllowedTypes($option)
+    {
+        return call_user_func($this->get, 'allowedTypes', $option, sprintf('No allowed types were set for the "%s" option.', $option));
+    }
+
+    /**
+     * @param string $option
+     *
+     * @return mixed[]
+     *
+     * @throws NoConfigurationException on no configured values
+     */
+    public function getAllowedValues($option)
+    {
+        return call_user_func($this->get, 'allowedValues', $option, sprintf('No allowed values were set for the "%s" option.', $option));
+    }
+
+    /**
+     * @param string $option
+     *
+     * @return \Closure
+     *
+     * @throws NoConfigurationException on no configured normalizer
+     */
+    public function getNormalizer($option)
+    {
+        return call_user_func($this->get, 'normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option));
+    }
+}

+ 26 - 0
vendor/symfony/options-resolver/Exception/NoConfigurationException.php

@@ -0,0 +1,26 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsResolver\Exception;
+
+use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
+
+/**
+ * Thrown when trying to introspect an option definition property
+ * for which no value was configured inside the OptionsResolver instance.
+ *
+ * @see OptionsResolverIntrospector
+ *
+ * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
+ */
+class NoConfigurationException extends \RuntimeException implements ExceptionInterface
+{
+}

+ 1 - 1
vendor/symfony/options-resolver/LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2004-2017 Fabien Potencier
+Copyright (c) 2004-2018 Fabien Potencier
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 75 - 33
vendor/symfony/options-resolver/OptionsResolver.php

@@ -28,29 +28,21 @@ class OptionsResolver implements Options
 {
     /**
      * The names of all defined options.
-     *
-     * @var array
      */
     private $defined = array();
 
     /**
      * The default option values.
-     *
-     * @var array
      */
     private $defaults = array();
 
     /**
      * The names of required options.
-     *
-     * @var array
      */
     private $required = array();
 
     /**
      * The resolved option values.
-     *
-     * @var array
      */
     private $resolved = array();
 
@@ -63,22 +55,16 @@ class OptionsResolver implements Options
 
     /**
      * A list of accepted values for each option.
-     *
-     * @var array
      */
     private $allowedValues = array();
 
     /**
      * A list of accepted types for each option.
-     *
-     * @var array
      */
     private $allowedTypes = array();
 
     /**
      * A list of closures for evaluating lazy options.
-     *
-     * @var array
      */
     private $lazy = array();
 
@@ -86,8 +72,6 @@ class OptionsResolver implements Options
      * A list of lazy options whose closure is currently being called.
      *
      * This list helps detecting circular dependencies between lazy options.
-     *
-     * @var array
      */
     private $calling = array();
 
@@ -98,8 +82,6 @@ class OptionsResolver implements Options
      * necessary in order to avoid inconsistencies during the resolving
      * process. If any option is changed after being read, all evaluated
      * lazy options that depend on this option would become invalid.
-     *
-     * @var bool
      */
     private $locked = false;
 
@@ -792,21 +774,12 @@ class OptionsResolver implements Options
         // Validate the type of the resolved option
         if (isset($this->allowedTypes[$option])) {
             $valid = false;
+            $invalidTypes = array();
 
             foreach ($this->allowedTypes[$option] as $type) {
                 $type = isset(self::$typeAliases[$type]) ? self::$typeAliases[$type] : $type;
 
-                if (function_exists($isFunction = 'is_'.$type)) {
-                    if ($isFunction($value)) {
-                        $valid = true;
-                        break;
-                    }
-
-                    continue;
-                }
-
-                if ($value instanceof $type) {
-                    $valid = true;
+                if ($valid = $this->verifyTypes($type, $value, $invalidTypes)) {
                     break;
                 }
             }
@@ -818,7 +791,7 @@ class OptionsResolver implements Options
                     $option,
                     $this->formatValue($value),
                     implode('" or "', $this->allowedTypes[$option]),
-                    $this->formatTypeOf($value)
+                    implode('|', array_keys($invalidTypes))
                 ));
             }
         }
@@ -896,6 +869,45 @@ class OptionsResolver implements Options
     }
 
     /**
+     * @param string $type
+     * @param mixed  $value
+     * @param array  &$invalidTypes
+     *
+     * @return bool
+     */
+    private function verifyTypes($type, $value, array &$invalidTypes)
+    {
+        if ('[]' === substr($type, -2) && is_array($value)) {
+            $originalType = $type;
+            $type = substr($type, 0, -2);
+            $invalidValues = array_filter( // Filter out valid values, keeping invalid values in the resulting array
+                $value,
+                function ($value) use ($type) {
+                    return !self::isValueValidType($type, $value);
+                }
+            );
+
+            if (!$invalidValues) {
+                return true;
+            }
+
+            $invalidTypes[$this->formatTypeOf($value, $originalType)] = true;
+
+            return false;
+        }
+
+        if (self::isValueValidType($type, $value)) {
+            return true;
+        }
+
+        if (!$invalidTypes) {
+            $invalidTypes[$this->formatTypeOf($value, null)] = true;
+        }
+
+        return false;
+    }
+
+    /**
      * Returns whether a resolved option with the given name exists.
      *
      * @param string $option The option name
@@ -963,13 +975,38 @@ class OptionsResolver implements Options
      * parameters should usually not be included in messages aimed at
      * non-technical people.
      *
-     * @param mixed $value The value to return the type of
+     * @param mixed  $value The value to return the type of
+     * @param string $type
      *
      * @return string The type of the value
      */
-    private function formatTypeOf($value)
+    private function formatTypeOf($value, $type)
     {
-        return is_object($value) ? get_class($value) : gettype($value);
+        $suffix = '';
+
+        if ('[]' === substr($type, -2)) {
+            $suffix = '[]';
+            $type = substr($type, 0, -2);
+            while ('[]' === substr($type, -2)) {
+                $type = substr($type, 0, -2);
+                $value = array_shift($value);
+                if (!is_array($value)) {
+                    break;
+                }
+                $suffix .= '[]';
+            }
+
+            if (is_array($value)) {
+                $subTypes = array();
+                foreach ($value as $val) {
+                    $subTypes[$this->formatTypeOf($val, null)] = true;
+                }
+
+                return implode('|', array_keys($subTypes)).$suffix;
+            }
+        }
+
+        return (is_object($value) ? get_class($value) : gettype($value)).$suffix;
     }
 
     /**
@@ -1036,4 +1073,9 @@ class OptionsResolver implements Options
 
         return implode(', ', $values);
     }
+
+    private static function isValueValidType($type, $value)
+    {
+        return (function_exists($isFunction = 'is_'.$type) && $isFunction($value)) || $value instanceof $type;
+    }
 }

+ 203 - 0
vendor/symfony/options-resolver/Tests/Debug/OptionsResolverIntrospectorTest.php

@@ -0,0 +1,203 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsResolver\Tests\Debug;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\OptionsResolver\Debug\OptionsResolverIntrospector;
+use Symfony\Component\OptionsResolver\Options;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class OptionsResolverIntrospectorTest extends TestCase
+{
+    public function testGetDefault()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefault($option = 'foo', 'bar');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getDefault($option));
+    }
+
+    public function testGetDefaultNull()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefault($option = 'foo', null);
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertNull($debug->getDefault($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException
+     * @expectedExceptionMessage No default value was set for the "foo" option.
+     */
+    public function testGetDefaultThrowsOnNoConfiguredValue()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getDefault($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
+     * @expectedExceptionMessage The option "foo" does not exist.
+     */
+    public function testGetDefaultThrowsOnNotDefinedOption()
+    {
+        $resolver = new OptionsResolver();
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getDefault('foo'));
+    }
+
+    public function testGetLazyClosures()
+    {
+        $resolver = new OptionsResolver();
+        $closures = array();
+        $resolver->setDefault($option = 'foo', $closures[] = function (Options $options) {});
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame($closures, $debug->getLazyClosures($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException
+     * @expectedExceptionMessage No lazy closures were set for the "foo" option.
+     */
+    public function testGetLazyClosuresThrowsOnNoConfiguredValue()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getLazyClosures($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
+     * @expectedExceptionMessage The option "foo" does not exist.
+     */
+    public function testGetLazyClosuresThrowsOnNotDefinedOption()
+    {
+        $resolver = new OptionsResolver();
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getLazyClosures('foo'));
+    }
+
+    public function testGetAllowedTypes()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+        $resolver->setAllowedTypes($option = 'foo', $allowedTypes = array('string', 'bool'));
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame($allowedTypes, $debug->getAllowedTypes($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException
+     * @expectedExceptionMessage No allowed types were set for the "foo" option.
+     */
+    public function testGetAllowedTypesThrowsOnNoConfiguredValue()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getAllowedTypes($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
+     * @expectedExceptionMessage The option "foo" does not exist.
+     */
+    public function testGetAllowedTypesThrowsOnNotDefinedOption()
+    {
+        $resolver = new OptionsResolver();
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getAllowedTypes('foo'));
+    }
+
+    public function testGetAllowedValues()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+        $resolver->setAllowedValues($option = 'foo', $allowedValues = array('bar', 'baz'));
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame($allowedValues, $debug->getAllowedValues($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException
+     * @expectedExceptionMessage No allowed values were set for the "foo" option.
+     */
+    public function testGetAllowedValuesThrowsOnNoConfiguredValue()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getAllowedValues($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
+     * @expectedExceptionMessage The option "foo" does not exist.
+     */
+    public function testGetAllowedValuesThrowsOnNotDefinedOption()
+    {
+        $resolver = new OptionsResolver();
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getAllowedValues('foo'));
+    }
+
+    public function testGetNormalizer()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+        $resolver->setNormalizer($option = 'foo', $normalizer = function () {});
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame($normalizer, $debug->getNormalizer($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException
+     * @expectedExceptionMessage No normalizer was set for the "foo" option.
+     */
+    public function testGetNormalizerThrowsOnNoConfiguredValue()
+    {
+        $resolver = new OptionsResolver();
+        $resolver->setDefined($option = 'foo');
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getNormalizer($option));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
+     * @expectedExceptionMessage The option "foo" does not exist.
+     */
+    public function testGetNormalizerThrowsOnNotDefinedOption()
+    {
+        $resolver = new OptionsResolver();
+
+        $debug = new OptionsResolverIntrospector($resolver);
+        $this->assertSame('bar', $debug->getNormalizer('foo'));
+    }
+}

+ 100 - 6
vendor/symfony/options-resolver/Tests/OptionsResolverTest.php

@@ -486,6 +486,15 @@ class OptionsResolverTest extends TestCase
         $this->resolver->setAllowedTypes('foo', 'string');
     }
 
+    public function testResolveTypedArray()
+    {
+        $this->resolver->setDefined('foo');
+        $this->resolver->setAllowedTypes('foo', 'string[]');
+        $options = $this->resolver->resolve(array('foo' => array('bar', 'baz')));
+
+        $this->assertSame(array('foo' => array('bar', 'baz')), $options);
+    }
+
     /**
      * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException
      */
@@ -501,6 +510,65 @@ class OptionsResolverTest extends TestCase
     }
 
     /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+     * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but is of type "DateTime[]".
+     */
+    public function testResolveFailsIfInvalidTypedArray()
+    {
+        $this->resolver->setDefined('foo');
+        $this->resolver->setAllowedTypes('foo', 'int[]');
+
+        $this->resolver->resolve(array('foo' => array(new \DateTime())));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+     * @expectedExceptionMessage The option "foo" with value "bar" is expected to be of type "int[]", but is of type "string".
+     */
+    public function testResolveFailsWithNonArray()
+    {
+        $this->resolver->setDefined('foo');
+        $this->resolver->setAllowedTypes('foo', 'int[]');
+
+        $this->resolver->resolve(array('foo' => 'bar'));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+     * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but is of type "integer|stdClass|array|DateTime[]".
+     */
+    public function testResolveFailsIfTypedArrayContainsInvalidTypes()
+    {
+        $this->resolver->setDefined('foo');
+        $this->resolver->setAllowedTypes('foo', 'int[]');
+        $values = range(1, 5);
+        $values[] = new \stdClass();
+        $values[] = array();
+        $values[] = new \DateTime();
+        $values[] = 123;
+
+        $this->resolver->resolve(array('foo' => $values));
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+     * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[][]", but is of type "double[][]".
+     */
+    public function testResolveFailsWithCorrectLevelsButWrongScalar()
+    {
+        $this->resolver->setDefined('foo');
+        $this->resolver->setAllowedTypes('foo', 'int[][]');
+
+        $this->resolver->resolve(
+            array(
+                'foo' => array(
+                    array(1.2),
+                ),
+            )
+        );
+    }
+
+    /**
      * @dataProvider provideInvalidTypes
      */
     public function testResolveFailsIfInvalidType($actualType, $allowedType, $exceptionMessage)
@@ -568,6 +636,32 @@ class OptionsResolverTest extends TestCase
         $this->assertNotEmpty($this->resolver->resolve());
     }
 
+    public function testResolveSucceedsIfTypedArray()
+    {
+        $this->resolver->setDefault('foo', null);
+        $this->resolver->setAllowedTypes('foo', array('null', 'DateTime[]'));
+
+        $data = array(
+            'foo' => array(
+                new \DateTime(),
+                new \DateTime(),
+            ),
+        );
+        $result = $this->resolver->resolve($data);
+        $this->assertEquals($data, $result);
+    }
+
+    /**
+     * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+     */
+    public function testResolveFailsIfNotInstanceOfClass()
+    {
+        $this->resolver->setDefault('foo', 'bar');
+        $this->resolver->setAllowedTypes('foo', '\stdClass');
+
+        $this->resolver->resolve();
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // addAllowedTypes()
     ////////////////////////////////////////////////////////////////////////////
@@ -1419,12 +1513,12 @@ class OptionsResolverTest extends TestCase
         });
 
         $this->resolver->setDefault('lazy2', function (Options $options) {
-            Assert::assertTrue(isset($options['default1']));
-            Assert::assertTrue(isset($options['default2']));
-            Assert::assertTrue(isset($options['required']));
-            Assert::assertTrue(isset($options['lazy1']));
-            Assert::assertTrue(isset($options['lazy2']));
-            Assert::assertFalse(isset($options['defined']));
+            Assert::assertArrayHasKey('default1', $options);
+            Assert::assertArrayHasKey('default2', $options);
+            Assert::assertArrayHasKey('required', $options);
+            Assert::assertArrayHasKey('lazy1', $options);
+            Assert::assertArrayHasKey('lazy2', $options);
+            Assert::assertArrayNotHasKey('defined', $options);
 
             Assert::assertSame(0, $options['default1']);
             Assert::assertSame(42, $options['default2']);

+ 2 - 2
vendor/symfony/options-resolver/composer.json

@@ -16,7 +16,7 @@
         }
     ],
     "require": {
-        "php": ">=5.5.9"
+        "php": "^5.5.9|>=7.0.8"
     },
     "autoload": {
         "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" },
@@ -27,7 +27,7 @@
     "minimum-stability": "dev",
     "extra": {
         "branch-alias": {
-            "dev-master": "3.3-dev"
+            "dev-master": "3.4-dev"
         }
     }
 }