Bladeren bron

更新google

王大坤 2 jaren geleden
bovenliggende
commit
577e175234
100 gewijzigde bestanden met toevoegingen van 49896 en 4646 verwijderingen
  1. 12 0
      .idea/codeception.xml
  2. 10 4
      .idea/new_api.iml
  3. 10 4
      .idea/php.xml
  4. 16 0
      .idea/phpspec.xml
  5. 41 0
      app/libs/google/Oauth.php
  6. 5 4
      composer.json
  7. 392 199
      composer.lock
  8. 6 0
      config/swdz.php
  9. 22 6
      vendor/adbario/php-dot-notation/src/Dot.php
  10. 5 4
      vendor/adbario/php-dot-notation/src/helpers.php
  11. 4 0
      vendor/alibabacloud/client/CHANGELOG.md
  12. 2 3
      vendor/alibabacloud/client/README-zh-CN.md
  13. 2 3
      vendor/alibabacloud/client/README.md
  14. 26 8
      vendor/alibabacloud/client/composer.json
  15. 1 1
      vendor/alibabacloud/client/src/AlibabaCloud.php
  16. 2 2
      vendor/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php
  17. 2 2
      vendor/alibabacloud/client/src/Exception/ServerException.php
  18. 2 2
      vendor/alibabacloud/client/src/Functions.php
  19. 2 2
      vendor/alibabacloud/client/src/Log/LogFormatter.php
  20. 1 1
      vendor/alibabacloud/client/src/Request/Request.php
  21. 2 4
      vendor/alibabacloud/client/src/Request/RoaRequest.php
  22. 3 3
      vendor/alibabacloud/client/src/Request/Traits/RetryTrait.php
  23. 47 0
      vendor/alibabacloud/client/src/Support/Stringy.php
  24. 4 0
      vendor/alibabacloud/client/src/Traits/ArrayAccessTrait.php
  25. 2 2
      vendor/alibabacloud/client/src/Traits/ClientTrait.php
  26. 1 1
      vendor/alibabacloud/client/src/Traits/EndpointTrait.php
  27. 7 0
      vendor/alibabacloud/client/src/Traits/HasDataTrait.php
  28. 1 1
      vendor/alibabacloud/client/src/Traits/LogTrait.php
  29. 5 0
      vendor/aliyuncs/oss-sdk-php/CHANGELOG.md
  30. 65 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketStat.php
  31. 76 0
      vendor/aliyuncs/oss-sdk-php/samples/CredentialsPhp.php
  32. 45 0
      vendor/aliyuncs/oss-sdk-php/samples/CredentialsProvider.php
  33. 63 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/Credentials.php
  34. 11 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/CredentialsProvider.php
  35. 35 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/StaticCredentialsProvider.php
  36. 1 1
      vendor/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php
  37. 246 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Model/BucketStat.php
  38. 92 29
      vendor/aliyuncs/oss-sdk-php/src/OSS/OssClient.php
  39. 43 17
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetBucketStatResultTest.php
  40. 148 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientTest.php
  41. 119 0
      vendor/bin/yaml-lint
  42. 20 2
      vendor/brick/math/CHANGELOG.md
  43. 0 17
      vendor/brick/math/SECURITY.md
  44. 3 3
      vendor/brick/math/composer.json
  45. 2 6
      vendor/brick/math/src/BigDecimal.php
  46. 16 3
      vendor/brick/math/src/BigInteger.php
  47. 1 3
      vendor/brick/math/src/BigNumber.php
  48. 4 7
      vendor/brick/math/src/BigRational.php
  49. 15 20
      vendor/brick/math/src/Internal/Calculator.php
  50. 0 6
      vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
  51. 1 3
      vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
  52. 23452 6
      vendor/composer/autoload_classmap.php
  53. 4 3
      vendor/composer/autoload_files.php
  54. 9 4
      vendor/composer/autoload_psr4.php
  55. 23501 29
      vendor/composer/autoload_static.php
  56. 436 236
      vendor/composer/installed.json
  57. 272 203
      vendor/composer/installed.php
  58. 2 2
      vendor/composer/platform_check.php
  59. 0 180
      vendor/danielstjules/stringy/CHANGELOG.md
  60. 0 19
      vendor/danielstjules/stringy/LICENSE.txt
  61. 0 1082
      vendor/danielstjules/stringy/README.md
  62. 0 35
      vendor/danielstjules/stringy/composer.json
  63. 0 19
      vendor/danielstjules/stringy/src/Create.php
  64. 0 161
      vendor/danielstjules/stringy/src/StaticStringy.php
  65. 0 1986
      vendor/danielstjules/stringy/src/Stringy.php
  66. 4 4
      vendor/dingo/blueprint/composer.json
  67. 6 0
      vendor/doctrine/annotations/README.md
  68. 8 5
      vendor/doctrine/annotations/composer.json
  69. 1 1
      vendor/doctrine/annotations/docs/en/custom.rst
  70. 9 0
      vendor/doctrine/annotations/docs/en/index.rst
  71. 1 3
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
  72. 2 2
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
  73. 2 2
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
  74. 2 2
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
  75. 3 8
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
  76. 1 3
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
  77. 16 2
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
  78. 30 11
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
  79. 1 3
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
  80. 14 14
      vendor/doctrine/dbal/README.md
  81. 2 2
      vendor/doctrine/dbal/bin/doctrine-dbal.php
  82. 13 12
      vendor/doctrine/dbal/composer.json
  83. 37 0
      vendor/doctrine/dbal/src/ArrayParameterType.php
  84. 1 3
      vendor/doctrine/dbal/src/ArrayParameters/Exception.php
  85. 2 4
      vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php
  86. 1 1
      vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php
  87. 12 21
      vendor/doctrine/dbal/src/Cache/ArrayResult.php
  88. 3 9
      vendor/doctrine/dbal/src/Cache/CacheException.php
  89. 8 15
      vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php
  90. 64 9
      vendor/doctrine/dbal/src/Configuration.php
  91. 248 127
      vendor/doctrine/dbal/src/Connection.php
  92. 5 15
      vendor/doctrine/dbal/src/ConnectionException.php
  93. 15 4
      vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php
  94. 11 2
      vendor/doctrine/dbal/src/Driver.php
  95. 1 3
      vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php
  96. 2 6
      vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php
  97. 3 7
      vendor/doctrine/dbal/src/Driver/API/PostgreSQL/ExceptionConverter.php
  98. 7 6
      vendor/doctrine/dbal/src/Driver/API/SQLite/ExceptionConverter.php
  99. 32 0
      vendor/doctrine/dbal/src/Driver/API/SQLite/UserDefinedFunctions.php
  100. 12 2
      vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php

+ 12 - 0
.idea/codeception.xml

xqd
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Codeception">
+    <option name="configurations">
+      <list>
+        <Configuration>
+          <option name="path" value="$PROJECT_DIR$/tests" />
+        </Configuration>
+      </list>
+    </option>
+  </component>
+</project>

+ 10 - 4
.idea/new_api.iml

xqd xqd xqd xqd xqd xqd xqd xqd
@@ -18,7 +18,6 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/clagiordano/weblibs-configmanager" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
-      <excludeFolder url="file://$MODULE_DIR$/vendor/danielstjules/stringy" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/dcat/easy-excel" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/dcat/laravel-admin" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/dflydev/dot-access-data" />
@@ -39,9 +38,13 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/facade/ignition-contracts" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/fakerphp/faker" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/filp/whoops" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/firebase/php-jwt" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/fruitcake/laravel-cors" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/giggsey/libphonenumber-for-php" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/giggsey/locale" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/google/apiclient" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/google/apiclient-services" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/google/auth" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/graham-campbell/result-type" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
@@ -85,6 +88,8 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/laravel-wechat" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/socialite" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/wechat" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/paragonie/constant_time_encoding" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/paragonie/random_compat" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/php-open-source-saver/jwt-auth" />
@@ -92,7 +97,8 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpoption/phpoption" />
-      <excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/prophecy" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/phpseclib/phpseclib" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpdoc-parser" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
@@ -103,6 +109,7 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/prettus/l5-repository" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/prettus/laravel-validation" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
@@ -135,7 +142,6 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/socialiteproviders/weixin" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/spatie/eloquent-sortable" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-package-tools" />
-      <excludeFolder url="file://$MODULE_DIR$/vendor/stella-maris/clock" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/stomp-php/stomp-php" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/swiftmailer/swiftmailer" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
@@ -159,7 +165,6 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php72" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php73" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
-      <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php81" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/psr-http-message-bridge" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
@@ -169,6 +174,7 @@
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
+      <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/tencent/tls-sig-api-v2" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/tencentcloud/tencentcloud-sdk-php" />
       <excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />

+ 10 - 4
.idea/php.xml

xqd xqd xqd xqd
@@ -13,7 +13,6 @@
   <component name="PhpIncludePathManager">
     <include_path>
       <path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
-      <path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
       <path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
       <path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
       <path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
@@ -58,7 +57,6 @@
       <path value="$PROJECT_DIR$/vendor/socialiteproviders/weixin" />
       <path value="$PROJECT_DIR$/vendor/dingo/blueprint" />
       <path value="$PROJECT_DIR$/vendor/dflydev/dot-access-data" />
-      <path value="$PROJECT_DIR$/vendor/stella-maris/clock" />
       <path value="$PROJECT_DIR$/vendor/socialiteproviders/facebook" />
       <path value="$PROJECT_DIR$/vendor/opis/closure" />
       <path value="$PROJECT_DIR$/vendor/adbario/php-dot-notation" />
@@ -118,8 +116,6 @@
       <path value="$PROJECT_DIR$/vendor/facade/ignition" />
       <path value="$PROJECT_DIR$/vendor/facade/ignition-contracts" />
       <path value="$PROJECT_DIR$/vendor/facade/flare-client-php" />
-      <path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
-      <path value="$PROJECT_DIR$/vendor/danielstjules/stringy" />
       <path value="$PROJECT_DIR$/vendor/php-open-source-saver/jwt-auth" />
       <path value="$PROJECT_DIR$/vendor/monolog/monolog" />
       <path value="$PROJECT_DIR$/vendor/dragonmantank/cron-expression" />
@@ -182,6 +178,16 @@
       <path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
       <path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
       <path value="$PROJECT_DIR$/vendor/composer" />
+      <path value="$PROJECT_DIR$/vendor/psr/clock" />
+      <path value="$PROJECT_DIR$/vendor/symfony/yaml" />
+      <path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
+      <path value="$PROJECT_DIR$/vendor/firebase/php-jwt" />
+      <path value="$PROJECT_DIR$/vendor/paragonie/random_compat" />
+      <path value="$PROJECT_DIR$/vendor/phpseclib/phpseclib" />
+      <path value="$PROJECT_DIR$/vendor/paragonie/constant_time_encoding" />
+      <path value="$PROJECT_DIR$/vendor/google/auth" />
+      <path value="$PROJECT_DIR$/vendor/google/apiclient" />
+      <path value="$PROJECT_DIR$/vendor/google/apiclient-services" />
     </include_path>
   </component>
   <component name="PhpProjectSharedConfiguration" php_language_level="7.3" />

+ 16 - 0
.idea/phpspec.xml

xqd
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="PHPSpec">
+    <suites>
+      <PhpSpecSuiteConfiguration>
+        <option name="myPath" value="$PROJECT_DIR$" />
+      </PhpSpecSuiteConfiguration>
+      <PhpSpecSuiteConfiguration>
+        <option name="myPath" value="$PROJECT_DIR$" />
+      </PhpSpecSuiteConfiguration>
+      <PhpSpecSuiteConfiguration>
+        <option name="myPath" value="$PROJECT_DIR$" />
+      </PhpSpecSuiteConfiguration>
+    </suites>
+  </component>
+</project>

+ 41 - 0
app/libs/google/Oauth.php

xqd
@@ -0,0 +1,41 @@
+<?php
+
+namespace App\libs\google;
+
+use Google\Client;
+use Illuminate\Support\Facades\Config;
+
+class Oauth
+{
+    public function __construct()
+    {
+        $this->config = Config::get('swdz.goodle');
+        $this->client = new Client([
+            'client_id' => $this->config['client_id'],
+            'client_secret' => $this->config['client_secret'],
+            'redirect_uri' => $this->config['redirect_uri'],
+            'scopes' => $this->config['scopes']
+        ]);
+    }
+
+    /**
+     * APP通过code换取用户信息
+     *
+     * @return array|false
+     * @throws \Psr\Container\ContainerExceptionInterface
+     * @throws \Psr\Container\NotFoundExceptionInterface
+     */
+    public function appAuth(){
+        $code = request()->get('code', null);
+        return $this->client->verifyIdToken($code);
+    }
+
+    /**
+     * WEB打开授权页面(待补充)
+     *
+     * @return void
+     */
+    public function webAuth(){
+
+    }
+}

+ 5 - 4
composer.json

xqd xqd
@@ -6,12 +6,16 @@
     "license": "MIT",
     "require": {
         "php": "^7.3|^8.0",
+        "ext-curl": "*",
+        "ext-json": "*",
+        "ext-openssl": "*",
         "alibabacloud/iot": "^1.8",
         "api-ecosystem-for-laravel/dingo-api": "^v3.1.1",
         "dcat/easy-excel": "^1.0",
         "dcat/laravel-admin": "2.*",
         "fruitcake/laravel-cors": "^2.0",
         "giggsey/libphonenumber-for-php": "^8.12",
+        "google/apiclient": "^2.15",
         "guzzlehttp/guzzle": "^7.0.1",
         "iidestiny/laravel-filesystem-oss": "2.1",
         "jormin/laravel-ddoc": "^1.1",
@@ -29,10 +33,7 @@
         "socialiteproviders/weixin": "^4.1",
         "stomp-php/stomp-php": "^5.0",
         "tencent/tls-sig-api-v2": "1.0",
-        "tencentcloud/tencentcloud-sdk-php": "^3.0",
-        "ext-curl": "*",
-        "ext-json": "*",
-        "ext-openssl": "*"
+        "tencentcloud/tencentcloud-sdk-php": "^3.0"
     },
     "require-dev": {
         "facade/ignition": "^2.5",

File diff suppressed because it is too large
+ 392 - 199
composer.lock


+ 6 - 0
config/swdz.php

xqd
@@ -10,4 +10,10 @@ return [
         // accessToken 储存驱动 db|redis
         'token_drive'   => 'db'
     ],
+    'goodle' => [
+        'client_id' => '521103626174-tvkfskvjnou2uonp90fm4mvg4b0h1ioe.apps.googleusercontent.com',
+        'client_secret' => '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',
+        'redirect_uri' => 'https://t11.9026.com/api/auth/callback',//网页授权使用
+        'scopes' => ['email', 'profile']
+    ]
 ];

+ 22 - 6
vendor/adbario/php-dot-notation/src/Dot.php

xqd xqd xqd xqd xqd xqd xqd
@@ -29,14 +29,25 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
      */
     protected $items = [];
 
+
+    /**
+     * The delimiter (alternative to a '.') to be used.
+     *
+     * @var string
+     */
+    protected $delimiter = '.';
+
+
     /**
      * Create a new Dot instance
      *
      * @param mixed $items
+     * @param string $delimiter
      */
-    public function __construct($items = [])
+    public function __construct($items = [], $delimiter = '.')
     {
         $this->items = $this->getArrayItems($items);
+        $this->delimiter = strlen($delimiter) ? $delimiter : '.';
     }
 
     /**
@@ -104,7 +115,7 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
             }
 
             $items = &$this->items;
-            $segments = explode('.', $key);
+            $segments = explode($this->delimiter, $key);
             $lastSegment = array_pop($segments);
 
             foreach ($segments as $segment) {
@@ -148,6 +159,10 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
             $items = $this->items;
         }
 
+        if (!func_num_args()) {
+            $delimiter = $this->delimiter;
+        }
+
         foreach ($items as $key => $value) {
             if (is_array($value) && !empty($value)) {
                 $flatten = array_merge(
@@ -179,13 +194,13 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
             return $this->items[$key];
         }
 
-        if (strpos($key, '.') === false) {
+        if (strpos($key, $this->delimiter) === false) {
             return $default;
         }
 
         $items = $this->items;
 
-        foreach (explode('.', $key) as $segment) {
+        foreach (explode($this->delimiter, $key) as $segment) {
             if (!is_array($items) || !$this->exists($items, $segment)) {
                 return $default;
             }
@@ -234,7 +249,7 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
                 continue;
             }
 
-            foreach (explode('.', $key) as $segment) {
+            foreach (explode($this->delimiter, $key) as $segment) {
                 if (!is_array($items) || !$this->exists($items, $segment)) {
                     return false;
                 }
@@ -446,7 +461,7 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
 
         $items = &$this->items;
 
-        foreach (explode('.', $keys) as $key) {
+        foreach (explode($this->delimiter, $keys) as $key) {
             if (!isset($items[$key]) || !is_array($items[$key])) {
                 $items[$key] = [];
             }
@@ -600,6 +615,7 @@ class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
      *
      * @return array
      */
+    #[\ReturnTypeWillChange]
     public function jsonSerialize()
     {
         return $this->items;

+ 5 - 4
vendor/adbario/php-dot-notation/src/helpers.php

xqd
@@ -11,13 +11,14 @@ use Adbar\Dot;
 
 if (! function_exists('dot')) {
     /**
-     * Create a new Dot object with the given items
+     * Create a new Dot object with the given items and optional delimiter
      *
-     * @param  mixed $items
+     * @param  mixed  $items
+     * @param  string $delimiter
      * @return \Adbar\Dot
      */
-    function dot($items)
+    function dot($items, $delimiter = '.')
     {
-        return new Dot($items);
+        return new Dot($items, $delimiter);
     }
 }

+ 4 - 0
vendor/alibabacloud/client/CHANGELOG.md

xqd
@@ -1,5 +1,9 @@
 # CHANGELOG
 
+## 1.5.32 - 2022-12-08
+
+- Support PHP versions: From 5.5 up to 8.1
+
 ## 1.5.31 - 2021-05-13
 
 - Deprecate `\GuzzleHttp\Psr7\parse_query` method

+ 2 - 3
vendor/alibabacloud/client/README-zh-CN.md

xqd
@@ -6,9 +6,8 @@
 [![composer.lock](https://poser.pugx.org/alibabacloud/client/composerlock)](https://packagist.org/packages/alibabacloud/client)
 [![Total Downloads](https://poser.pugx.org/alibabacloud/client/downloads)](https://packagist.org/packages/alibabacloud/client)
 [![License](https://poser.pugx.org/alibabacloud/client/license)](https://packagist.org/packages/alibabacloud/client)
-[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg)](https://codecov.io/gh/aliyun/openapi-sdk-php-client)
-[![Travis Build Status](https://travis-ci.org/aliyun/openapi-sdk-php-client.svg?branch=master)](https://travis-ci.org/aliyun/openapi-sdk-php-client)
-[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/qb8j3lhg8349k0hk/branch/master?svg=true)](https://ci.appveyor.com/project/aliyun/openapi-sdk-php-client/branch/master)
+[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg?token=90Yd5Bne3S)](https://codecov.io/gh/aliyun/openapi-sdk-php-client)
+[![PHP Version Require](http://poser.pugx.org/alibabacloud/client/require/php)](https://packagist.org/packages/alibabacloud/client)
 
 
 ![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)

+ 2 - 3
vendor/alibabacloud/client/README.md

xqd
@@ -6,9 +6,8 @@ English | [简体中文](/README-zh-CN.md)
 [![composer.lock](https://poser.pugx.org/alibabacloud/client/composerlock)](https://packagist.org/packages/alibabacloud/client)
 [![Total Downloads](https://poser.pugx.org/alibabacloud/client/downloads)](https://packagist.org/packages/alibabacloud/client)
 [![License](https://poser.pugx.org/alibabacloud/client/license)](https://packagist.org/packages/alibabacloud/client)
-[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg)](https://codecov.io/gh/aliyun/openapi-sdk-php-client)
-[![Travis Build Status](https://travis-ci.org/aliyun/openapi-sdk-php-client.svg?branch=master)](https://travis-ci.org/aliyun/openapi-sdk-php-client)
-[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/qb8j3lhg8349k0hk/branch/master?svg=true)](https://ci.appveyor.com/project/aliyun/openapi-sdk-php-client/branch/master)
+[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg?token=90Yd5Bne3S)](https://codecov.io/gh/aliyun/openapi-sdk-php-client)
+[![PHP Version Require](http://poser.pugx.org/alibabacloud/client/require/php)](https://packagist.org/packages/alibabacloud/client)
 
 
 ![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)

+ 26 - 8
vendor/alibabacloud/client/composer.json

xqd xqd xqd xqd
@@ -35,9 +35,8 @@
     "ext-simplexml": "*",
     "ext-xmlwriter": "*",
     "guzzlehttp/guzzle": "^6.3|^7.0",
-    "danielstjules/stringy": "^3.1",
     "mtdowling/jmespath.php": "^2.5",
-    "adbario/php-dot-notation": "^2.2",
+    "adbario/php-dot-notation": "^2.4.1",
     "clagiordano/weblibs-configmanager": "^1.0"
   },
   "require-dev": {
@@ -49,7 +48,7 @@
     "drupal/coder": "^8.3",
     "symfony/dotenv": "^3.4",
     "league/climate": "^3.2.4",
-    "phpunit/phpunit": "^5.7.27|^6.1",
+    "phpunit/phpunit": "^5.7|^6.6|^7.5|^8.5|^9.5",
     "monolog/monolog": "^1.24",
     "composer/composer": "^1.8",
     "mikey179/vfsstream": "^1.6",
@@ -73,7 +72,10 @@
   },
   "config": {
     "preferred-install": "dist",
-    "optimize-autoloader": true
+    "optimize-autoloader": true,
+    "allow-plugins": {
+      "dealerdirect/phpcodesniffer-composer-installer": true
+    }
   },
   "minimum-stability": "dev",
   "prefer-stable": true,
@@ -95,13 +97,29 @@
     "test": [
       "phpunit --colors=always"
     ],
-    "unit": [
+    "test4HighVersion": [
+      "@clearCache",
+      "phpunit --testsuite=Test4HighVersion --colors=always"
+    ],
+    "test4LowVersion": [
+      "@clearCache",
+      "phpunit --testsuite=Test4LowVersion --colors=always"
+    ],
+    "unit4HighVersion": [
+      "@clearCache",
+      "phpunit --testsuite=Unit4HighVersion --colors=always"
+    ],
+    "unit4LowVersion": [
+      "@clearCache",
+      "phpunit --testsuite=Unit4LowVersion --colors=always"
+    ],
+    "feature4HighVersion": [
       "@clearCache",
-      "phpunit --testsuite=Unit --colors=always"
+      "phpunit --testsuite=Feature4HighVersion --colors=always"
     ],
-    "feature": [
+    "feature4LowVersion": [
       "@clearCache",
-      "phpunit --testsuite=Feature --colors=always"
+      "phpunit --testsuite=Feature4LowVersion --colors=always"
     ],
     "coverage": "open cache/coverage/index.html",
     "clearCache": "rm -rf cache/*",

+ 1 - 1
vendor/alibabacloud/client/src/AlibabaCloud.php

xqd
@@ -30,7 +30,7 @@ class AlibabaCloud
     /**
      * Version of the Client
      */
-    const VERSION = '1.5.29';
+    const VERSION = '1.5.32';
 
     /**
      * This static method can directly call the specific service.

+ 2 - 2
vendor/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php

xqd xqd
@@ -3,7 +3,7 @@
 namespace AlibabaCloud\Client\Credentials\Providers;
 
 use Exception;
-use Stringy\Stringy;
+use AlibabaCloud\Client\Support\Stringy;
 use AlibabaCloud\Client\SDK;
 use AlibabaCloud\Client\Result\Result;
 use Psr\Http\Message\ResponseInterface;
@@ -112,7 +112,7 @@ class EcsRamRoleProvider extends Provider
         try {
             return RpcRequest::createClient()->request('GET', $url, $options);
         } catch (GuzzleException $exception) {
-            if (Stringy::create($exception->getMessage())->contains('timed')) {
+            if (Stringy::contains($exception->getMessage(), 'timed')) {
                 $message = 'Timeout or instance does not belong to Alibaba Cloud';
             } else {
                 $message = $exception->getMessage();

+ 2 - 2
vendor/alibabacloud/client/src/Exception/ServerException.php

xqd xqd
@@ -2,7 +2,7 @@
 
 namespace AlibabaCloud\Client\Exception;
 
-use Stringy\Stringy;
+use AlibabaCloud\Client\Support\Stringy;
 use RuntimeException;
 use AlibabaCloud\Client\SDK;
 use AlibabaCloud\Client\Result\Result;
@@ -83,7 +83,7 @@ class ServerException extends AlibabaCloudException
     private function distinguishSignatureErrors()
     {
         if ($this->result->getRequest()
-            && Stringy::create($this->errorMessage)->contains($this->result->getRequest()->stringToSign())) {
+            && Stringy::contains($this->errorMessage, $this->result->getRequest()->stringToSign())) {
             $this->errorCode    = 'InvalidAccessKeySecret';
             $this->errorMessage = 'Specified Access Key Secret is not valid.';
         }

+ 2 - 2
vendor/alibabacloud/client/src/Functions.php

xqd xqd
@@ -3,7 +3,7 @@
 namespace AlibabaCloud\Client;
 
 use Closure;
-use Stringy\Stringy;
+use AlibabaCloud\Client\Support\Stringy;
 use League\CLImate\CLImate;
 use AlibabaCloud\Client\Exception\ClientException;
 
@@ -60,7 +60,7 @@ function inOpenBasedir($filename, $throwException = false)
 function inDir($filename, array $dirs)
 {
     foreach ($dirs as $dir) {
-        if (!Stringy::create($dir)->endsWith(DIRECTORY_SEPARATOR)) {
+        if (!Stringy::endsWith($dir, DIRECTORY_SEPARATOR)) {
             $dir .= DIRECTORY_SEPARATOR;
         }
 

+ 2 - 2
vendor/alibabacloud/client/src/Log/LogFormatter.php

xqd
@@ -37,14 +37,14 @@ class LogFormatter
      */
     public function __construct($template)
     {
-        parent::__construct($template);
+        // parent::__construct($template);
         self::$logStartTime = microtime(true);
         $this->template     = $template;
         $timezone           = new DateTimeZone(date_default_timezone_get() ?: 'UTC');
         if (PHP_VERSION_ID < 70100) {
             self::$ts = DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), $timezone);
         } else {
-            self::$ts = new DateTime(null, $timezone);
+            self::$ts = new DateTime('now', $timezone);
         }
     }
 

+ 1 - 1
vendor/alibabacloud/client/src/Request/Request.php

xqd
@@ -113,7 +113,7 @@ abstract class Request implements ArrayAccess
         $this->options['timeout']         = self::TIMEOUT;
 
         // Turn on debug mode based on environment variable.
-        if (strtolower(\AlibabaCloud\Client\env('DEBUG')) === 'sdk') {
+        if (null !== \AlibabaCloud\Client\env('DEBUG') && strtolower(\AlibabaCloud\Client\env('DEBUG')) === 'sdk') {
             $this->options['debug'] = true;
         }
 

+ 2 - 4
vendor/alibabacloud/client/src/Request/RoaRequest.php

xqd xqd
@@ -3,7 +3,7 @@
 namespace AlibabaCloud\Client\Request;
 
 use Exception;
-use Stringy\Stringy;
+use AlibabaCloud\Client\Support\Stringy;
 use RuntimeException;
 use AlibabaCloud\Client\SDK;
 use AlibabaCloud\Client\Encode;
@@ -98,9 +98,7 @@ class RoaRequest extends Request
      */
     private function encodeBody(array $params)
     {
-        $stringy = Stringy::create($this->options['headers']['Content-Type']);
-
-        if ($stringy->contains('application/json', false)) {
+        if (Stringy::contains($this->options['headers']['Content-Type'], 'application/json', false)) {
             $this->options['body']                   = json_encode($params);
             $this->options['headers']['Content-MD5'] = base64_encode(md5($this->options['body'], true));
 

+ 3 - 3
vendor/alibabacloud/client/src/Request/Traits/RetryTrait.php

xqd xqd xqd
@@ -3,7 +3,7 @@
 namespace AlibabaCloud\Client\Request\Traits;
 
 use Exception;
-use Stringy\Stringy;
+use AlibabaCloud\Client\Support\Stringy;
 use AlibabaCloud\Client\Result\Result;
 use AlibabaCloud\Client\Filter\ClientFilter;
 use AlibabaCloud\Client\Exception\ClientException;
@@ -109,7 +109,7 @@ trait RetryTrait
         }
 
         foreach ($this->serverRetryStrings as $message) {
-            if (Stringy::create($result->getBody())->contains($message)) {
+            if (Stringy::contains($result->getBody(), $message)) {
                 $this->serverRetry--;
 
                 return true;
@@ -137,7 +137,7 @@ trait RetryTrait
         }
 
         foreach ($this->clientRetryStrings as $message) {
-            if (Stringy::create($exception->getMessage())->contains($message)) {
+            if (Stringy::contains($exception->getMessage(), $message)) {
                 $this->clientRetry--;
 
                 return true;

+ 47 - 0
vendor/alibabacloud/client/src/Support/Stringy.php

xqd
@@ -0,0 +1,47 @@
+<?php
+
+namespace AlibabaCloud\Client\Support;
+
+/**
+ * Class Stringy
+ *
+ * @package AlibabaCloud\Client\Support
+ */
+class Stringy
+{
+
+    private static function _value($value, $default = '')
+    {
+        return null === $value ? $default : $value;
+    }
+
+    /**
+     * @param string $str
+     * @param string $substr
+     *
+     * @return bool
+     */
+    public static function contains($str, $substr)
+    {
+        return false !== strpos(self::_value($str), self::_value($substr));
+    }
+
+    /**
+     * @param string $str
+     * @param string $substr
+     *
+     * @return bool
+     */
+    public static function endsWith($str, $substr)
+    {
+        $str      = self::_value($str);
+        $substr = self::_value($substr);
+        $length = \strlen($substr);
+        if (!$length) {
+            return true;
+        }
+
+        return substr($str, -$length) === $substr;
+    }
+
+}

+ 4 - 0
vendor/alibabacloud/client/src/Traits/ArrayAccessTrait.php

xqd xqd xqd xqd
@@ -17,6 +17,7 @@ trait ArrayAccessTrait
      *
      * @return mixed|null
      */
+    #[\ReturnTypeWillChange]
     public function & offsetGet($offset)
     {
         if (isset($this->data[$offset])) {
@@ -32,6 +33,7 @@ trait ArrayAccessTrait
      * @param string       $offset
      * @param string|mixed $value
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($offset, $value)
     {
         $this->data[$offset] = $value;
@@ -42,6 +44,7 @@ trait ArrayAccessTrait
      *
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function offsetExists($offset)
     {
         return isset($this->data[$offset]);
@@ -50,6 +53,7 @@ trait ArrayAccessTrait
     /**
      * @param string $offset
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($offset)
     {
         unset($this->data[$offset]);

+ 2 - 2
vendor/alibabacloud/client/src/Traits/ClientTrait.php

xqd
@@ -182,14 +182,14 @@ trait ClientTrait
      */
     public static function accessKeyClient($accessKeyId, $accessKeySecret)
     {
-        if (strpos($accessKeyId, ' ') !== false) {
+        if (null === $accessKeyId || strpos($accessKeyId, ' ') !== false) {
             throw new ClientException(
                 'AccessKey ID format is invalid',
                 SDK::INVALID_ARGUMENT
             );
         }
 
-        if (strpos($accessKeySecret, ' ') !== false) {
+        if (null === $accessKeySecret || strpos($accessKeySecret, ' ') !== false) {
             throw new ClientException(
                 'AccessKey Secret format is invalid',
                 SDK::INVALID_ARGUMENT

+ 1 - 1
vendor/alibabacloud/client/src/Traits/EndpointTrait.php

xqd
@@ -64,7 +64,7 @@ trait EndpointTrait
         if (self::resolveHostByStatic($productCode, $global)) {
             return true;
         }
-        $productCode = strtolower($productCode);
+        $productCode = null !== $productCode? strtolower($productCode) : null;
         return (bool)Config::get("endpoints.{$productCode}.{$global}");
     }
 

+ 7 - 0
vendor/alibabacloud/client/src/Traits/HasDataTrait.php

xqd xqd xqd xqd xqd xqd xqd
@@ -131,6 +131,7 @@ trait HasDataTrait
      *
      * @return bool
      */
+    #[\ReturnTypeWillChange]
     public function offsetExists($key)
     {
         return $this->dot->has($key);
@@ -143,6 +144,7 @@ trait HasDataTrait
      *
      * @return mixed
      */
+    #[\ReturnTypeWillChange]
     public function offsetGet($key)
     {
         return $this->dot->offsetGet($key);
@@ -154,6 +156,7 @@ trait HasDataTrait
      * @param int|string|null $key
      * @param mixed           $value
      */
+    #[\ReturnTypeWillChange]
     public function offsetSet($key, $value)
     {
         $this->dot->offsetSet($key, $value);
@@ -164,6 +167,7 @@ trait HasDataTrait
      *
      * @param int|string $key
      */
+    #[\ReturnTypeWillChange]
     public function offsetUnset($key)
     {
         $this->delete($key);
@@ -192,6 +196,7 @@ trait HasDataTrait
      *
      * @return int
      */
+    #[\ReturnTypeWillChange]
     public function count($key = null)
     {
         return $this->dot->count($key);
@@ -202,6 +207,7 @@ trait HasDataTrait
      *
      * @return ArrayIterator
      */
+    #[\ReturnTypeWillChange]
     public function getIterator()
     {
         return $this->dot->getIterator();
@@ -212,6 +218,7 @@ trait HasDataTrait
      *
      * @return array
      */
+    #[\ReturnTypeWillChange]
     public function jsonSerialize()
     {
         return $this->dot->jsonSerialize();

+ 1 - 1
vendor/alibabacloud/client/src/Traits/LogTrait.php

xqd
@@ -55,7 +55,7 @@ trait LogTrait
         if (PHP_VERSION_ID < 70100) {
             self::$ts = DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), $timezone);
         } else {
-            self::$ts = new DateTime(null, $timezone);
+            self::$ts = new DateTime('now', $timezone);
         }
     }
 

+ 5 - 0
vendor/aliyuncs/oss-sdk-php/CHANGELOG.md

xqd
@@ -1,5 +1,10 @@
 # ChangeLog - Aliyun OSS SDK for PHP
 
+## v2.6.0 / 2022-08-03
+* Added: support credentials provider.
+* Fixed: compatible with swoole curl handler.
+* Added: support more bucket stat info.
+
 ## v2.5.0 / 2022-05-13
 * Added: support bucket transfer acceleration.
 * Added: support bucket cname token.

+ 65 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketStat.php

xqd
@@ -0,0 +1,65 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// Get Bucket Stat
+$stat = $ossClient->getBucketStat($bucket);
+Common::println("Bucket ".$bucket." current storage is:".$stat->getStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." object count is:".$stat->getObjectCount().PHP_EOL);
+Common::println("Bucket ".$bucket." multipart upload count is:".$stat->getMultipartUploadCount().PHP_EOL);
+Common::println("Bucket ".$bucket." live channel count is:".$stat->getLiveChannelCount().PHP_EOL);
+Common::println("Bucket ".$bucket." last modified time is:".$stat->getLastModifiedTime().PHP_EOL);
+Common::println("Bucket ".$bucket." standard storage is:".$stat->getStandardStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." standard object count is:".$stat->getStandardObjectCount().PHP_EOL);
+Common::println("Bucket ".$bucket." infrequent access storage is:".$stat->getInfrequentAccessStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." infrequent access real storage is:".$stat->getInfrequentAccessRealStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." infrequent access object count is:".$stat->getInfrequentAccessObjectCount().PHP_EOL);
+Common::println("Bucket ".$bucket." archive storage is:".$stat->getArchiveStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." archive real storage is:".$stat->getArchiveRealStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." archive object count is:".$stat->getArchiveObjectCount().PHP_EOL);
+Common::println("Bucket ".$bucket." cold archive storage is:".$stat->getColdArchiveStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." cold archive real storage is:".$stat->getColdArchiveRealStorage().PHP_EOL);
+Common::println("Bucket ".$bucket." cold archive object count is:".$stat->getColdArchiveObjectCount().PHP_EOL);
+
+//******************************* For complete usage, see the following functions ****************************************************
+getBucketStat($ossClient,$bucket);
+/**
+ * get bucket stat
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function getBucketStat($ossClient, $bucket)
+{
+    try {
+        $stat = $ossClient->getBucketStat($bucket);
+    } catch (OssException $e) {
+        printf(__FUNCTION__ . ": FAILED\n");
+        printf($e->getMessage() . "\n");
+        return;
+    }
+    printf("Bucket ".$bucket." current storage is:".$stat->getStorage().PHP_EOL);
+    printf("Bucket ".$bucket." object count is:".$stat->getObjectCount().PHP_EOL);
+    printf("Bucket ".$bucket." multipart upload count is:".$stat->getMultipartUploadCount().PHP_EOL);
+    printf("Bucket ".$bucket." live channel count is:".$stat->getLiveChannelCount().PHP_EOL);
+    printf("Bucket ".$bucket." last modified time is:".$stat->getLastModifiedTime().PHP_EOL);
+    printf("Bucket ".$bucket." standard storage is:".$stat->getStandardStorage().PHP_EOL);
+    printf("Bucket ".$bucket." standard object count is:".$stat->getStandardObjectCount().PHP_EOL);
+    printf("Bucket ".$bucket." infrequent access storage is:".$stat->getInfrequentAccessStorage().PHP_EOL);
+    printf("Bucket ".$bucket." infrequent access real storage is:".$stat->getInfrequentAccessRealStorage().PHP_EOL);
+    printf("Bucket ".$bucket." infrequent access object count is:".$stat->getInfrequentAccessObjectCount().PHP_EOL);
+    printf("Bucket ".$bucket." archive storage is:".$stat->getArchiveStorage().PHP_EOL);
+    printf("Bucket ".$bucket." archive real storage is:".$stat->getArchiveRealStorage().PHP_EOL);
+    printf("Bucket ".$bucket." archive object count is:".$stat->getArchiveObjectCount().PHP_EOL);
+    printf("Bucket ".$bucket." cold archive storage is:".$stat->getColdArchiveStorage().PHP_EOL);
+    printf("Bucket ".$bucket." cold archive real storage is:".$stat->getColdArchiveRealStorage().PHP_EOL);
+    printf("Bucket ".$bucket." cold archive object count is:".$stat->getColdArchiveObjectCount().PHP_EOL);
+    print(__FUNCTION__ . ": OK" . "\n");
+}

+ 76 - 0
vendor/aliyuncs/oss-sdk-php/samples/CredentialsPhp.php

xqd
@@ -0,0 +1,76 @@
+<?php
+
+//=============================================================================
+
+//How to use credentials-php to access oss
+
+// step 1:Install credentials-php  composer require alibabacloud/credentials
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Credentials\CredentialsProvider;
+use AlibabaCloud\Credentials\Credential;
+use OSS\Credentials\StaticCredentialsProvider;
+
+// public provider conversion class
+class AlibabaCloudCredentialsWrapper implements CredentialsProvider{
+    /**
+     * @var Credential
+     */
+    private $warpper;
+    public function __construct($credential){
+        $this->warpper = $credential;
+    }
+    public function getCredentials(){
+        $ak = $this->warpper->getAccessKeyId();
+        $sk = $this->warpper->getAccessKeySecret();
+        $token = $this->warpper->getSecurityToken();
+        return new StaticCredentialsProvider($ak, $sk, $token);
+    }
+}
+
+$bucket = Common::getBucketName();
+
+//AccessKey Credentials demo
+$credential = new Credential(array(
+    'type'              => 'access_key',
+    'access_key_id'     => '<access_key_id>',
+    'access_key_secret' => '<accessKey_secret>',
+));
+$providerWarpper = new AlibabaCloudCredentialsWrapper($credential);
+$config = array(
+    'provider' => $providerWarpper,
+    'endpoint'=> '<endpoint>'
+);
+try {
+    $ossClient = new OssClient($config);
+    $ossClient->putObject($bucket,'c.file','hi oss,this is credentials test of access key');
+    $result = $ossClient->getObject($bucket,'c.file');
+    var_dump($result);
+} catch (OssException $e) {
+    printf($e->getMessage() . "\n");
+    return;
+}
+
+
+// EcsRamRole Credentials demo
+$ecsRamRole = new Credential(array(
+    'type'      => 'ecs_ram_role',
+    'role_name' => 'EcsRamRoleOssTest',
+));
+$providerWarpper = new AlibabaCloudCredentialsWrapper($ecsRamRole);
+$bucket = 'oss-bucket-cd-yp-test';
+$config = array(
+    'provider' => $providerWarpper,
+    'endpoint'=> '<endpoint>'
+);
+try {
+    $ossClient = new OssClient($config);
+    $ossClient->putObject($bucket,'c.file','hi oss,this is credentials test of EcsRamRole');
+    $result = $ossClient->getObject($bucket,'c.file');
+    var_dump($result);
+} catch (OssException $e) {
+    printf($e->getMessage() . "\n");
+    return;
+}

+ 45 - 0
vendor/aliyuncs/oss-sdk-php/samples/CredentialsProvider.php

xqd
@@ -0,0 +1,45 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Credentials\StaticCredentialsProvider;
+$bucket = Common::getBucketName();
+
+// Access Key Provider demo
+$id = '<access_key_id>';
+$secret = '<accessKey_secret>';
+$provider = new StaticCredentialsProvider($id,$secret);
+$config = array(
+    'provider' => $provider,
+    'endpoint'=>'<endpoint>'
+);
+try {
+    $ossClient = new OssClient($config);
+    $ossClient->putObject($bucket,'c.file','hi oss,this is credentials test of access key provider');
+    $result = $ossClient->getObject($bucket,'c.file');
+    var_dump($result);
+} catch (OssException $e) {
+    printf($e->getMessage() . "\n");
+    return;
+}
+
+// Sts provider demo
+$id = '<access_key_id>';
+$secret = '<accessKey_secret>';
+$token = '<security_token>';
+$provider = new StaticCredentialsProvider($id,$secret,$token);
+$config = array(
+    'provider' => $provider,
+    'endpoint'=> "<endpoint>"
+);
+
+try {
+    $ossClient = new OssClient($config);
+    $ossClient->putObject($bucket,'c.file','hi oss,this is credentials test of sts provider');
+    $result = $ossClient->getObject($bucket,'c.file');
+    var_dump($result);
+} catch (OssException $e) {
+    printf($e->getMessage() . "\n");
+    return;
+}

+ 63 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/Credentials.php

xqd
@@ -0,0 +1,63 @@
+<?php
+
+
+namespace OSS\Credentials;
+
+use OSS\Core\OssException;
+
+/**
+ * Basic implementation of the OSS Credentials that allows callers to
+ * pass in the OSS Access Key and OSS Secret Access Key in the constructor.
+ */
+class Credentials
+{
+    private $key;
+    private $secret;
+    private $token;
+
+    /**
+     * Constructor a new BasicOSSCredentials object, with the specified OSS
+     * access key and OSS secret key
+     *
+     * @param string $key     OSS access key ID
+     * @param string $secret  OSS secret access key
+     * @param string $token   Security token to use
+     */
+    public function __construct($key, $secret, $token = null)
+    {
+        if (empty($key)) {
+            throw new OssException("access key id is empty");
+        }
+        if (empty($secret)) {
+            throw new OssException("access key secret is empty");
+        }
+        $this->key = trim($key);
+        $this->secret = trim($secret);
+        $this->token = $token;
+    }
+
+
+    /**
+     * @return string
+     */
+    public function getAccessKeyId()
+    {
+        return $this->key;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAccessKeySecret()
+    {
+        return $this->secret;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getSecurityToken()
+    {
+        return $this->token;
+    }
+}

+ 11 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/CredentialsProvider.php

xqd
@@ -0,0 +1,11 @@
+<?php
+namespace OSS\Credentials;
+
+interface CredentialsProvider
+{
+
+    /**
+     * @return Credentials
+     */
+    public function getCredentials();
+}

+ 35 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Credentials/StaticCredentialsProvider.php

xqd
@@ -0,0 +1,35 @@
+<?php
+namespace OSS\Credentials;
+
+/**
+ * Basic implementation of the OSS Credentials interface that allows callers to
+ * pass in the OSS Access Key Id and OSS Secret Access Key in the constructor.
+ */
+class StaticCredentialsProvider implements CredentialsProvider
+{
+
+    /**
+     * @var Credentials
+     */
+    private $credentials;
+    /**
+     * Constructs a new StaticCredentialsProvider object, with the specified OSS
+     * access key and OSS secret key
+     *
+     * @param string $key     OSS access key ID
+     * @param string $secret  OSS access key secret
+     * @param string $token   Security token to use
+     */
+    public function __construct($key, $secret, $token = null)
+    {
+        $this->credentials = new Credentials($key, $secret, $token);
+    }
+
+    /**
+     * @return Credentials
+     */
+    public function getCredentials()
+    {
+        return $this->credentials;
+    }
+}

+ 1 - 1
vendor/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php

xqd
@@ -789,7 +789,7 @@ class RequestCore
         }
 
         // As long as this came back as a valid resource or CurlHandle instance...
-        if (is_resource($curl_handle) || (is_object($curl_handle) && get_class($curl_handle) === 'CurlHandle')) {
+        if (is_resource($curl_handle) || (is_object($curl_handle) && in_array(get_class($curl_handle),array('CurlHandle','Swoole\Curl\Handler', 'Swoole\Coroutine\Curl\Handle'),true))) {
             // Determine what's what.
             $header_size = curl_getinfo($curl_handle, CURLINFO_HEADER_SIZE);
             $this->response_headers = substr($this->response, 0, $header_size);

+ 246 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Model/BucketStat.php

xqd xqd xqd
@@ -41,6 +41,135 @@ class BucketStat
         return $this->multipartUploadCount;
     }
 
+    /**
+     * Get live channel count
+     *
+     * @return int
+     */
+    public function getLiveChannelCount()
+    {
+        return $this->liveChannelCount;
+    }
+
+    /**
+     * Get last modified time
+     *
+     * @return int
+     */
+    public function getLastModifiedTime()
+    {
+        return $this->lastModifiedTime;
+    }
+
+    /**
+     * Get standard storage
+     *
+     * @return int
+     */
+    public function getStandardStorage()
+    {
+        return $this->standardStorage;
+    }
+
+    /**
+     * Get standard object count
+     *
+     * @return int
+     */
+    public function getStandardObjectCount()
+    {
+        return $this->standardObjectCount;
+    }
+
+    /**
+     * Get infrequent access storage
+     *
+     * @return int
+     */
+    public function getInfrequentAccessStorage()
+    {
+        return $this->infrequentAccessStorage;
+    }
+
+    /**
+     * Get infrequent access real storage
+     *
+     * @return int
+     */
+    public function getInfrequentAccessRealStorage()
+    {
+        return $this->infrequentAccessRealStorage;
+    }
+
+    /**
+     * Get infrequent access object count
+     *
+     * @return int
+     */
+    public function getInfrequentAccessObjectCount()
+    {
+        return $this->infrequentAccessObjectCount;
+    }
+
+    /**
+     * Get archive storage
+     *
+     * @return int
+     */
+    public function getArchiveStorage()
+    {
+        return $this->archiveStorage;
+    }
+
+    /**
+     * Get archive real storage
+     *
+     * @return int
+     */
+    public function getArchiveRealStorage()
+    {
+        return $this->archiveRealStorage;
+    }
+    /**
+     * Get archive object count
+     *
+     * @return int
+     */
+    public function getArchiveObjectCount()
+    {
+        return $this->archiveObjectCount;
+    }
+
+    /**
+     * Get cold archive storage
+     *
+     * @return int
+     */
+    public function getColdArchiveStorage()
+    {
+        return $this->coldArchiveStorage;
+    }
+
+    /**
+     * Get cold archive real storage
+     *
+     * @return int
+     */
+    public function getColdArchiveRealStorage()
+    {
+        return $this->coldArchiveRealStorage;
+    }
+
+    /**
+     * Get cold archive object count
+     *
+     * @return int
+     */
+    public function getColdArchiveObjectCount()
+    {
+        return $this->coldArchiveObjectCount;
+    }
+
     /**
      * Parse stat from the xml.
      *
@@ -60,6 +189,45 @@ class BucketStat
         if (isset($xml->MultipartUploadCount) ) {
             $this->multipartUploadCount = intval($xml->MultipartUploadCount);
         }
+        if (isset($xml->LiveChannelCount) ) {
+            $this->liveChannelCount = intval($xml->LiveChannelCount);
+        }
+        if (isset($xml->LastModifiedTime) ) {
+            $this->lastModifiedTime = intval($xml->LastModifiedTime);
+        }
+        if (isset($xml->StandardStorage) ) {
+            $this->standardStorage = intval($xml->StandardStorage);
+        }
+        if (isset($xml->StandardObjectCount) ) {
+            $this->standardObjectCount = intval($xml->StandardObjectCount);
+        }
+        if (isset($xml->InfrequentAccessStorage) ) {
+            $this->infrequentAccessStorage = intval($xml->InfrequentAccessStorage);
+        }
+        if (isset($xml->InfrequentAccessRealStorage) ) {
+            $this->infrequentAccessRealStorage = intval($xml->InfrequentAccessRealStorage);
+        }
+        if (isset($xml->InfrequentAccessObjectCount) ) {
+            $this->infrequentAccessObjectCount = intval($xml->InfrequentAccessObjectCount);
+        }
+        if (isset($xml->ArchiveStorage) ) {
+            $this->archiveStorage = intval($xml->ArchiveStorage);
+        }
+        if (isset($xml->ArchiveRealStorage) ) {
+            $this->archiveRealStorage = intval($xml->ArchiveRealStorage);
+        }
+        if (isset($xml->ArchiveObjectCount) ) {
+            $this->archiveObjectCount = intval($xml->ArchiveObjectCount);
+        }
+        if (isset($xml->ColdArchiveStorage) ) {
+            $this->coldArchiveStorage = intval($xml->ColdArchiveStorage);
+        }
+        if (isset($xml->ColdArchiveRealStorage) ) {
+            $this->coldArchiveRealStorage = intval($xml->ColdArchiveRealStorage);
+        }
+        if (isset($xml->ColdArchiveObjectCount) ) {
+            $this->coldArchiveObjectCount = intval($xml->ColdArchiveObjectCount);
+        }
     }
     
     /**
@@ -82,4 +250,82 @@ class BucketStat
      */
     private $multipartUploadCount;
 
+    /**
+     * live channel count
+     * @var int
+     */
+    private $liveChannelCount;
+
+    /**
+     * last modified time
+     * @var int
+     */
+    private $lastModifiedTime;
+
+    /**
+     * standard storage
+     * @var int
+     */
+    private $standardStorage;
+
+    /**
+     * standard object count
+     * @var int
+     */
+    private $standardObjectCount;
+
+    /**
+     * infrequent access storage
+     * @var int
+     */
+    private $infrequentAccessStorage;
+
+    /**
+     * infrequent access real storage
+     * @var int
+     */
+    private $infrequentAccessRealStorage;
+
+    /**
+     * infrequent access object Count
+     * @var int
+     */
+    private $infrequentAccessObjectCount;
+
+    /**
+     * archive storage
+     * @var int
+     */
+    private $archiveStorage;
+
+    /**
+     * archive real storage
+     * @var int
+     */
+    private $archiveRealStorage;
+
+    /**
+     * archive object count
+     * @var int
+     */
+    private $archiveObjectCount;
+
+    /**
+     * cold archive storage
+     * @var int
+     */
+    private $coldArchiveStorage;
+
+    /**
+     * cold archive real storage
+     * @var int
+     */
+    private $coldArchiveRealStorage;
+
+    /**
+     * cold archive object count
+     * @var int
+     */
+    private $coldArchiveObjectCount;
+
 }

+ 92 - 29
vendor/aliyuncs/oss-sdk-php/src/OSS/OssClient.php

xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd
@@ -3,6 +3,9 @@ namespace OSS;
 
 use OSS\Core\MimeTypes;
 use OSS\Core\OssException;
+use OSS\Credentials\Credentials;
+use OSS\Credentials\CredentialsProvider;
+use OSS\Credentials\StaticCredentialsProvider;
 use OSS\Http\RequestCore;
 use OSS\Http\RequestCore_Exception;
 use OSS\Http\ResponseCore;
@@ -89,12 +92,25 @@ use OSS\Result\GetBucketCnameTokenResult;
  */
 class OssClient
 {
+
+    /**
+     * OssClient constructor.
+     */
+    public function __construct()
+    {
+        $argNum = func_num_args();
+        $args = func_get_args();
+        if($argNum == 1 && is_array($args[0])){
+            call_user_func_array(array($this,'__initNewClient'),$args);
+        }else{
+            call_user_func_array(array($this,'__initClient'),$args);
+        }
+    }
+
     /**
-     * Constructor
-     *
      * There're a few different ways to create an OssClient object:
      * 1. Most common one from access Id, access Key and the endpoint: $ossClient = new OssClient($id, $key, $endpoint)
-     * 2. If the endpoint is the CName (such as www.testoss.com, make sure it's CName binded in the OSS console), 
+     * 2. If the endpoint is the CName (such as www.testoss.com, make sure it's CName binded in the OSS console),
      *    uses $ossClient = new OssClient($id, $key, $endpoint, true)
      * 3. If using Alicloud's security token service (STS), then the AccessKeyId, AccessKeySecret and STS token are all got from STS.
      * Use this: $ossClient = new OssClient($id, $key, $endpoint, false, $token)
@@ -108,7 +124,7 @@ class OssClient
      * @param string $requestProxy
      * @throws OssException
      */
-    public function __construct($accessKeyId, $accessKeySecret, $endpoint, $isCName = false, $securityToken = NULL, $requestProxy = NULL)
+    private function __initClient($accessKeyId, $accessKeySecret, $endpoint, $isCName = false, $securityToken = NULL, $requestProxy = NULL)
     {
         $accessKeyId = trim($accessKeyId);
         $accessKeySecret = trim($accessKeySecret);
@@ -120,17 +136,36 @@ class OssClient
         if (empty($accessKeySecret)) {
             throw new OssException("access key secret is empty");
         }
+        $provider = new StaticCredentialsProvider($accessKeyId,$accessKeySecret,$securityToken);
+        $config = array(
+            'endpoint'              => $endpoint,
+            'cname'                 => $isCName,
+            'request_proxy'         => $requestProxy,
+            'provider'              => $provider
+        );
+        $this->__initNewClient($config);
+    }
+
+    /**
+     * @param array $config
+     * @throws OssException
+     */
+    private function __initNewClient($config=array()){
+        $isCName = isset($config['cname']) ? $config['cname']: false;
+        $endpoint = isset($config['endpoint']) ? $config['endpoint'] : '';
+        $requestProxy = isset($config['request_proxy']) ? $config['request_proxy']: null;
+        $provider = isset($config['provider']) ? $config['provider'] : '';
         if (empty($endpoint)) {
             throw new OssException("endpoint is empty");
         }
         $this->hostname = $this->checkEndpoint($endpoint, $isCName);
-        $this->accessKeyId = $accessKeyId;
-        $this->accessKeySecret = $accessKeySecret;
-        $this->securityToken = $securityToken;
         $this->requestProxy = $requestProxy;
+        if(!$provider instanceof CredentialsProvider){
+            throw new OssException("provider must be an instance of CredentialsProvider");
+        }
+        $this->provider = $provider;
         self::checkEnv();
     }
-
     /**
      * Lists the Bucket [GetService]. Not applicable if the endpoint is CName (because CName must be binded to a specific bucket).
      *
@@ -877,9 +912,12 @@ class OssClient
         $resource = '/' . $bucket . '/' . $channelName;
 
         $string_to_sign = $expires . "\n" . $cano_params . $resource;
-        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
+        $cred = $this->provider->getCredentials();
+        $this->checkCredentials($cred);
 
-        $query_items[] = 'OSSAccessKeyId=' . rawurlencode($this->accessKeyId);
+        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $cred->getAccessKeySecret(), true));
+
+        $query_items[] = 'OSSAccessKeyId=' . rawurlencode($cred->getAccessKeyId());
         $query_items[] = 'Expires=' . rawurlencode($expires);
         $query_items[] = 'Signature=' . rawurlencode($signature);
 
@@ -912,9 +950,12 @@ class OssClient
         $resource = '/' . $bucket . '/' . $channelName;
 
         $string_to_sign = $expiration . "\n" . $cano_params . $resource;
-        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
+        $cred = $this->provider->getCredentials();
+        $this->checkCredentials($cred);
+
+        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $cred->getAccessKeySecret(), true));
 
-        $query_items[] = 'OSSAccessKeyId=' . rawurlencode($this->accessKeyId);
+        $query_items[] = 'OSSAccessKeyId=' . rawurlencode($cred->getAccessKeyId());
         $query_items[] = 'Expires=' . rawurlencode($expiration);
         $query_items[] = 'Signature=' . rawurlencode($signature);
 
@@ -2967,13 +3008,16 @@ class OssClient
         $this->authPrecheckObjectEncoding($options);
         //Validates ACL
         $this->authPrecheckAcl($options);
+        $cred = $this->provider->getCredentials();
+        $this->checkCredentials($cred);
+
         // Should https or http be used?
         $scheme = $this->useSSL ? 'https://' : 'http://';
         // gets the host name. If the host name is public domain or private domain, form a third level domain by prefixing the bucket name on the domain name.
         $hostname = $this->generateHostname($options[self::OSS_BUCKET]);
         $string_to_sign = '';
-        $headers = $this->generateHeaders($options, $hostname);
-        $signable_query_string_params = $this->generateSignableQueryStringParam($options);
+        $headers = $this->generateHeaders($options, $hostname,$cred);
+        $signable_query_string_params = $this->generateSignableQueryStringParam($options,$cred);
         $signable_query_string = OssUtil::toQueryString($signable_query_string_params);
         $resource_uri = $this->generateResourceUri($options);
         //Generates the URL (add query parameters)
@@ -3086,12 +3130,11 @@ class OssClient
         // Sort the strings to be signed.
         $string_to_sign_ordered .= $this->stringToSignSorted($signable_resource);
 
-
-        $signature = base64_encode(hash_hmac('sha1', $string_to_sign_ordered, $this->accessKeySecret, true));
-        $request->add_header('Authorization', 'OSS ' . $this->accessKeyId . ':' . $signature);
+        $signature = base64_encode(hash_hmac('sha1', $string_to_sign_ordered,$cred->getAccessKeySecret(), true));
+        $request->add_header('Authorization', 'OSS ' . $cred->getAccessKeyId() . ':' . $signature);
 
         if (isset($options[self::OSS_PREAUTH]) && (integer)$options[self::OSS_PREAUTH] > 0) {
-            $signed_url = $requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($this->accessKeyId) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature);
+            $signed_url = $requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($cred->getAccessKeyId()) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature);
             return $signed_url;
         } elseif (isset($options[self::OSS_PREAUTH])) {
             return $requestUrl;
@@ -3301,9 +3344,10 @@ class OssClient
      * Generates the signalbe query string parameters in array type
      *
      * @param array $options
+     * @param Credentials $cred
      * @return array
      */
-    private function generateSignableQueryStringParam($options)
+    private function generateSignableQueryStringParam($options,$cred)
     {
         $signableQueryStringParams = array();
         $signableList = array(
@@ -3337,8 +3381,8 @@ class OssClient
             }
         }
 
-        if ($this->enableStsInUrl && (!is_null($this->securityToken))) {
-            $signableQueryStringParams["security-token"] = $this->securityToken;
+        if ($this->enableStsInUrl && (!empty($cred->getSecurityToken()))) {
+            $signableQueryStringParams["security-token"] = $cred->getSecurityToken();
         }
 
         return $signableQueryStringParams;
@@ -3420,9 +3464,10 @@ class OssClient
      *
      * @param mixed $options
      * @param string $hostname hostname
+     * @param Credentials $cred
      * @return array
      */
-    private function generateHeaders($options, $hostname)
+    private function generateHeaders($options, $hostname,$cred)
     {
         $headers = array(
             self::OSS_CONTENT_MD5 => '',
@@ -3435,8 +3480,8 @@ class OssClient
         }
 
         //Add stsSecurityToken
-        if ((!is_null($this->securityToken)) && (!$this->enableStsInUrl)) {
-            $headers[self::OSS_SECURITY_TOKEN] = $this->securityToken;
+        if ((!empty($cred->getSecurityToken())) && (!$this->enableStsInUrl)) {
+            $headers[self::OSS_SECURITY_TOKEN] = $cred->getSecurityToken();
         }
         //Merge HTTP headers
         if (isset($options[self::OSS_HEADERS])) {
@@ -3487,6 +3532,23 @@ class OssClient
         return $ret_endpoint;
     }
 
+    /**
+     * @param Credentials $credential
+     * @return OssException
+     */
+    private function checkCredentials($credential)
+    {
+        if (empty($credential)) {
+            throw new OssException("credentials is empty.");
+        }
+        if (empty($credential->getAccessKeyId())) {
+            throw new OssException("access key id is empty");
+        }
+        if (empty($credential->getAccessKeySecret())) {
+            throw new OssException("access key secret is empty");
+        }
+    }
+
     /**
      * Check if all dependent extensions are installed correctly.
      * For now only "curl" is needed.
@@ -3664,8 +3726,8 @@ class OssClient
     );
     // OssClient version information
     const OSS_NAME = "aliyun-sdk-php";
-    const OSS_VERSION = "2.5.0";
-    const OSS_BUILD = "20220513";
+    const OSS_VERSION = "2.6.0";
+    const OSS_BUILD = "20220803";
     const OSS_AUTHOR = "";
     const OSS_OPTIONS_ORIGIN = 'Origin';
     const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method';
@@ -3679,10 +3741,11 @@ class OssClient
     // user's domain type. It could be one of the four: OSS_HOST_TYPE_NORMAL, OSS_HOST_TYPE_IP, OSS_HOST_TYPE_SPECIAL, OSS_HOST_TYPE_CNAME
     private $hostType = self::OSS_HOST_TYPE_NORMAL;
     private $requestProxy = null;
-    private $accessKeyId;
-    private $accessKeySecret;
+    /**
+     * @var CredentialsProvider
+     */
+    private $provider;
     private $hostname;
-    private $securityToken;
     private $enableStsInUrl = false;
     private $timeout = 0;
     private $connectTimeout = 0;

+ 43 - 17
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetBucketStatResultTest.php

xqd xqd
@@ -9,20 +9,33 @@ use OSS\Http\ResponseCore;
 class GetBucketStatResultTest extends \PHPUnit\Framework\TestCase
 {
 
-    private $validXml = <<<BBBB
-        <?xml version="1.0" ?>
-        <BucketStat>
-            <Storage>100</Storage>
-            <ObjectCount>200</ObjectCount>
-            <MultipartUploadCount>10</MultipartUploadCount>
-        </BucketStat>
-        BBBB;
-
-    private $invalidXml = <<<BBBB
-        <?xml version="1.0" ?>
-        <BucketStat>
-        </BucketStat>
-        BBBB;
+private $validXml = <<<BBBB
+<?xml version="1.0" encoding="UTF-8"?>
+<BucketStat>
+  <Storage>1600</Storage>
+  <ObjectCount>230</ObjectCount>
+  <MultipartUploadCount>40</MultipartUploadCount>
+  <LiveChannelCount>4</LiveChannelCount>
+  <LastModifiedTime>1643341269</LastModifiedTime>
+  <StandardStorage>430</StandardStorage>
+  <StandardObjectCount>66</StandardObjectCount>
+  <InfrequentAccessStorage>2359296</InfrequentAccessStorage>
+  <InfrequentAccessRealStorage>360</InfrequentAccessRealStorage>
+  <InfrequentAccessObjectCount>54</InfrequentAccessObjectCount>
+  <ArchiveStorage>2949120</ArchiveStorage>
+  <ArchiveRealStorage>450</ArchiveRealStorage>
+  <ArchiveObjectCount>74</ArchiveObjectCount>
+  <ColdArchiveStorage>2359296</ColdArchiveStorage>
+  <ColdArchiveRealStorage>360</ColdArchiveRealStorage>
+  <ColdArchiveObjectCount>36</ColdArchiveObjectCount>
+</BucketStat>
+BBBB;
+
+private $invalidXml = <<<BBBB
+<?xml version="1.0" ?>
+<BucketStat>
+</BucketStat>
+BBBB;
 
     public function testParseValidXml()
     {
@@ -32,9 +45,22 @@ class GetBucketStatResultTest extends \PHPUnit\Framework\TestCase
         $this->assertNotNull($result->getData());
         $this->assertNotNull($result->getRawResponse());
         $stat = $result->getData();
-        $this->assertEquals(100, $stat->getStorage());
-        $this->assertEquals(200, $stat->getObjectCount());
-        $this->assertEquals(10, $stat->getMultipartUploadCount());
+        $this->assertEquals(1600, $stat->getStorage());
+        $this->assertEquals(230, $stat->getObjectCount());
+        $this->assertEquals(40, $stat->getMultipartUploadCount());
+        $this->assertEquals(4, $stat->getLiveChannelCount());
+        $this->assertEquals(1643341269, $stat->getLastModifiedTime());
+        $this->assertEquals(430, $stat->getStandardStorage());
+        $this->assertEquals(66, $stat->getStandardObjectCount());
+        $this->assertEquals(2359296, $stat->getInfrequentAccessStorage());
+        $this->assertEquals(360, $stat->getInfrequentAccessRealStorage());
+        $this->assertEquals(54, $stat->getInfrequentAccessObjectCount());
+        $this->assertEquals(2949120, $stat->getArchiveStorage());
+        $this->assertEquals(450, $stat->getArchiveRealStorage());
+        $this->assertEquals(74, $stat->getArchiveObjectCount());
+        $this->assertEquals(2359296, $stat->getColdArchiveStorage());
+        $this->assertEquals(360, $stat->getColdArchiveRealStorage());
+        $this->assertEquals(36, $stat->getColdArchiveObjectCount());
     }
 
     public function testParseNullXml()

+ 148 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientTest.php

xqd xqd
@@ -4,6 +4,79 @@ namespace OSS\Tests;
 
 use OSS\Core\OssException;
 use OSS\OssClient;
+use OSS\Credentials\Credentials;
+use OSS\Credentials\CredentialsProvider;
+use OSS\Credentials\StaticCredentialsProvider;
+
+class TestEmptyIdCredentials extends Credentials
+{
+    public function __construct()
+    {
+    }
+
+    public function getAccessKeyId()
+    {
+        return '';
+    }
+
+    public function getAccessKeySecret()
+    {
+        return 'secret';
+    }
+
+    public function getSecurityToken()
+    {
+        return null;
+    }
+}
+
+class TestEmptySecretCredentials extends Credentials
+{
+    public function __construct()
+    {
+    }
+
+    public function getAccessKeyId()
+    {
+        return 'id';
+    }
+
+    public function getAccessKeySecret()
+    {
+        return '';
+    }
+
+    public function getSecurityToken()
+    {
+        return null;
+    }
+}
+
+
+class TestCredentialsProvider implements CredentialsProvider
+{
+    private $credentials;
+    public function __construct($flag)
+    {
+        if ($flag == 2) {
+            $this->credentials =  new TestEmptyIdCredentials();
+        }
+        else if ($flag == 1) {
+            $this->credentials =  new TestEmptySecretCredentials();
+        }
+        else {
+            $this->credentials = null;
+        }
+    }
+
+    /**
+     * @return Credentials
+     */
+    public function getCredentials()
+    {
+        return $this->credentials;
+    }
+}
 
 
 class OssClientTest extends TestOssClientBase
@@ -343,4 +416,79 @@ class OssClientTest extends TestOssClientBase
             $this->assertFalse(true);
         }
     }
+
+    public function testEmptyCredentials()
+    {
+        // empty case, should throw exception
+        try {
+            $id = '';
+            $secret = 'accessKey_secret';
+            $provider = new StaticCredentialsProvider($id, $secret);
+            $config = array(
+                'provider' => $provider,
+                'endpoint'=>'http://oss-cn-hangzhou.aliyuncs.com'
+            );
+            $ossClient = new OssClient($config);
+            $this->assertFalse(true);
+        } catch (OssException $e) {
+            $this->assertEquals('access key id is empty', $e->getMessage());
+        }
+
+        // empty case, should throw exception
+        try {
+            $id = 'id';
+            $secret = '';
+            $provider = new StaticCredentialsProvider($id, $secret);
+            $config = array(
+                'provider' => $provider,
+                'endpoint'=>'http://oss-cn-hangzhou.aliyuncs.com'
+            );
+            $ossClient = new OssClient($config);
+            $this->assertFalse(true);
+        } catch (OssException $e) {
+            $this->assertEquals('access key secret is empty', $e->getMessage());
+        }
+
+        // empty case, should throw exception
+        try {
+            $provider = new TestCredentialsProvider(0);
+            $config = array(
+                'provider' => $provider,
+                'endpoint'=>'http://oss-cn-hangzhou.aliyuncs.com'
+            );
+            $ossClient = new OssClient($config);
+            $ossClient->getBucketAcl("bucket");
+            $this->assertFalse(true);
+        } catch (OssException $e) {
+            $this->assertEquals('credentials is empty.', $e->getMessage());
+        }
+
+        // empty case, should throw exception
+        try {
+            $provider = new TestCredentialsProvider(1);
+            $config = array(
+                'provider' => $provider,
+                'endpoint'=>'http://oss-cn-hangzhou.aliyuncs.com'
+            );
+            $ossClient = new OssClient($config);
+            $ossClient->getBucketAcl("bucket");
+            $this->assertFalse(true);
+        } catch (OssException $e) {
+            $this->assertEquals('access key secret is empty', $e->getMessage());
+        }
+
+        // empty case, should throw exception
+        try {
+            $provider = new TestCredentialsProvider(2);
+            $config = array(
+                'provider' => $provider,
+                'endpoint'=>'http://oss-cn-hangzhou.aliyuncs.com'
+            );
+            $ossClient = new OssClient($config);
+            $ossClient->getBucketAcl("bucket");
+            $this->assertFalse(true);
+        } catch (OssException $e) {
+            $this->assertEquals('access key id is empty', $e->getMessage());
+        }
+    }
 }

+ 119 - 0
vendor/bin/yaml-lint

xqd
@@ -0,0 +1,119 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * Proxy PHP file generated by Composer
+ *
+ * This file includes the referenced bin path (../symfony/yaml/Resources/bin/yaml-lint)
+ * using a stream wrapper to prevent the shebang from being output on PHP<8
+ *
+ * @generated
+ */
+
+namespace Composer;
+
+$GLOBALS['_composer_bin_dir'] = __DIR__;
+$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
+
+if (PHP_VERSION_ID < 80000) {
+    if (!class_exists('Composer\BinProxyWrapper')) {
+        /**
+         * @internal
+         */
+        final class BinProxyWrapper
+        {
+            private $handle;
+            private $position;
+            private $realpath;
+
+            public function stream_open($path, $mode, $options, &$opened_path)
+            {
+                // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
+                $opened_path = substr($path, 17);
+                $this->realpath = realpath($opened_path) ?: $opened_path;
+                $opened_path = $this->realpath;
+                $this->handle = fopen($this->realpath, $mode);
+                $this->position = 0;
+
+                return (bool) $this->handle;
+            }
+
+            public function stream_read($count)
+            {
+                $data = fread($this->handle, $count);
+
+                if ($this->position === 0) {
+                    $data = preg_replace('{^#!.*\r?\n}', '', $data);
+                }
+
+                $this->position += strlen($data);
+
+                return $data;
+            }
+
+            public function stream_cast($castAs)
+            {
+                return $this->handle;
+            }
+
+            public function stream_close()
+            {
+                fclose($this->handle);
+            }
+
+            public function stream_lock($operation)
+            {
+                return $operation ? flock($this->handle, $operation) : true;
+            }
+
+            public function stream_seek($offset, $whence)
+            {
+                if (0 === fseek($this->handle, $offset, $whence)) {
+                    $this->position = ftell($this->handle);
+                    return true;
+                }
+
+                return false;
+            }
+
+            public function stream_tell()
+            {
+                return $this->position;
+            }
+
+            public function stream_eof()
+            {
+                return feof($this->handle);
+            }
+
+            public function stream_stat()
+            {
+                return array();
+            }
+
+            public function stream_set_option($option, $arg1, $arg2)
+            {
+                return true;
+            }
+
+            public function url_stat($path, $flags)
+            {
+                $path = substr($path, 17);
+                if (file_exists($path)) {
+                    return stat($path);
+                }
+
+                return false;
+            }
+        }
+    }
+
+    if (
+        (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
+        || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
+    ) {
+        return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint');
+    }
+}
+
+return include __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint';

+ 20 - 2
vendor/brick/math/CHANGELOG.md

xqd xqd
@@ -2,11 +2,29 @@
 
 All notable changes to this project will be documented in this file.
 
+## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11
+
+👌 **Improvements**
+
+- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic
+
+## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02
+
+✨ **New features**
+
+- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers
+
+## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18
+
+💥 **Breaking changes**
+
+- Minimum PHP version is now 7.4
+
 ## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15
 
 🚀 **Compatibility with PHP 8.1**
 
-- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham)
+- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (#60) thanks @TRowbotham
 
 ## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20
 
@@ -16,7 +34,7 @@ All notable changes to this project will be documented in this file.
 
 ## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19
 
-✨ New features
+✨ **New features**
 
 - `BigInteger::not()` returns the bitwise `NOT` value
 

+ 0 - 17
vendor/brick/math/SECURITY.md

xqd
@@ -1,17 +0,0 @@
-# Security Policy
-
-## Supported Versions
-
-Only the last two release streams are supported.
-
-| Version | Supported          |
-| ------- | ------------------ |
-| 0.9.x   | :white_check_mark: |
-| 0.8.x   | :white_check_mark: |
-| < 0.8   | :x:                |
-
-## Reporting a Vulnerability
-
-To report a security vulnerability, please use the
-[Tidelift security contact](https://tidelift.com/security).
-Tidelift will coordinate the fix and disclosure.

+ 3 - 3
vendor/brick/math/composer.json

xqd
@@ -14,13 +14,13 @@
     ],
     "license": "MIT",
     "require": {
-        "php": "^7.1 || ^8.0",
+        "php": "^7.4 || ^8.0",
         "ext-json": "*"
     },
     "require-dev": {
-        "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
+        "phpunit/phpunit": "^9.0",
         "php-coveralls/php-coveralls": "^2.2",
-        "vimeo/psalm": "4.9.2"
+        "vimeo/psalm": "4.25.0"
     },
     "autoload": {
         "psr-4": {

+ 2 - 6
vendor/brick/math/src/BigDecimal.php

xqd
@@ -22,19 +22,15 @@ final class BigDecimal extends BigNumber
      * This is a string of digits with an optional leading minus sign.
      * No leading zero must be present.
      * No leading minus sign must be present if the value is 0.
-     *
-     * @var string
      */
-    private $value;
+    private string $value;
 
     /**
      * The scale (number of digits after the decimal point) of this decimal number.
      *
      * This must be zero or more.
-     *
-     * @var int
      */
-    private $scale;
+    private int $scale;
 
     /**
      * Protected constructor. Use a factory method to obtain an instance.

+ 16 - 3
vendor/brick/math/src/BigInteger.php

xqd xqd
@@ -26,10 +26,8 @@ final class BigInteger extends BigNumber
      *
      * No leading zeros must be present.
      * No leading minus sign must be present if the number is zero.
-     *
-     * @var string
      */
-    private $value;
+    private string $value;
 
     /**
      * Protected constructor. Use a factory method to obtain an instance.
@@ -361,6 +359,21 @@ final class BigInteger extends BigNumber
         return $ten;
     }
 
+    public static function gcdMultiple(BigInteger $a, BigInteger ...$n): BigInteger
+    {
+        $result = $a;
+
+        foreach ($n as $next) {
+            $result = $result->gcd($next);
+
+            if ($result->isEqualTo(1)) {
+                return $result;
+            }
+        }
+
+        return $result;
+    }
+
     /**
      * Returns the sum of this number and the given one.
      *

+ 1 - 3
vendor/brick/math/src/BigNumber.php

xqd
@@ -81,9 +81,7 @@ abstract class BigNumber implements \Serializable, \JsonSerializable
             $throw();
         }
 
-        $getMatch = static function(string $value) use ($matches) : ?string {
-            return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null;
-        };
+        $getMatch = static fn(string $value): ?string => (($matches[$value] ?? '') !== '') ? $matches[$value] : null;
 
         $sign        = $getMatch('sign');
         $numerator   = $getMatch('numerator');

+ 4 - 7
vendor/brick/math/src/BigRational.php

xqd xqd
@@ -20,17 +20,13 @@ final class BigRational extends BigNumber
 {
     /**
      * The numerator.
-     *
-     * @var BigInteger
      */
-    private $numerator;
+    private BigInteger $numerator;
 
     /**
      * The denominator. Always strictly positive.
-     *
-     * @var BigInteger
      */
-    private $denominator;
+    private BigInteger $denominator;
 
     /**
      * Protected constructor. Use a factory method to obtain an instance.
@@ -433,7 +429,8 @@ final class BigRational extends BigNumber
      */
     public function toFloat() : float
     {
-        return $this->numerator->toFloat() / $this->denominator->toFloat();
+        $simplified = $this->simplified();
+        return $simplified->numerator->toFloat() / $simplified->denominator->toFloat();
     }
 
     /**

+ 15 - 20
vendor/brick/math/src/Internal/Calculator.php

xqd xqd xqd xqd xqd xqd
@@ -34,10 +34,8 @@ abstract class Calculator
 
     /**
      * The Calculator instance in use.
-     *
-     * @var Calculator|null
      */
-    private static $instance;
+    private static ?Calculator $instance = null;
 
     /**
      * Sets the Calculator instance to use.
@@ -234,7 +232,7 @@ abstract class Calculator
      * @param string $a The dividend.
      * @param string $b The divisor, must not be zero.
      *
-     * @return string[] An array containing the quotient and remainder.
+     * @return array{string, string} An array containing the quotient and remainder.
      */
     abstract public function divQR(string $a, string $b) : array;
 
@@ -283,9 +281,7 @@ abstract class Calculator
             $modVal = $this->mod($x, $m);
         }
 
-        $x = '0';
-        $y = '0';
-        $g = $this->gcdExtended($modVal, $m, $x, $y);
+        [$g, $x] = $this->gcdExtended($modVal, $m);
 
         if ($g !== '1') {
             return null;
@@ -329,24 +325,21 @@ abstract class Calculator
         return $this->gcd($b, $this->divR($a, $b));
     }
 
-    private function gcdExtended(string $a, string $b, string &$x, string &$y) : string
+    /**
+     * @return array{string, string, string} GCD, X, Y
+     */
+    private function gcdExtended(string $a, string $b) : array
     {
         if ($a === '0') {
-            $x = '0';
-            $y = '1';
-
-            return $b;
+            return [$b, '0', '1'];
         }
 
-        $x1 = '0';
-        $y1 = '0';
-
-        $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1);
+        [$gcd, $x1, $y1] = $this->gcdExtended($this->mod($b, $a), $a);
 
         $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
         $y = $x1;
 
-        return $gcd;
+        return [$gcd, $x, $y];
     }
 
     /**
@@ -493,6 +486,8 @@ abstract class Calculator
      *
      * @throws \InvalidArgumentException  If the rounding mode is invalid.
      * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
+     *
+     * @psalm-suppress ImpureFunctionCall
      */
     final public function divRound(string $a, string $b, int $roundingMode) : string
     {
@@ -616,9 +611,9 @@ abstract class Calculator
     /**
      * Performs a bitwise operation on a decimal number.
      *
-     * @param string $operator The operator to use, must be "and", "or" or "xor".
-     * @param string $a        The left operand.
-     * @param string $b        The right operand.
+     * @param 'and'|'or'|'xor' $operator The operator to use.
+     * @param string           $a        The left operand.
+     * @param string           $b        The right operand.
      *
      * @return string
      */

+ 0 - 6
vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php

xqd xqd
@@ -94,9 +94,6 @@ class BcMathCalculator extends Calculator
 
     /**
      * {@inheritdoc}
-     *
-     * @psalm-suppress InvalidNullableReturnType
-     * @psalm-suppress NullableReturnStatement
      */
     public function modPow(string $base, string $exp, string $mod) : string
     {
@@ -105,9 +102,6 @@ class BcMathCalculator extends Calculator
 
     /**
      * {@inheritDoc}
-     *
-     * @psalm-suppress NullableReturnStatement
-     * @psalm-suppress InvalidNullableReturnType
      */
     public function sqrt(string $n) : string
     {

+ 1 - 3
vendor/brick/math/src/Internal/Calculator/NativeCalculator.php

xqd
@@ -22,10 +22,8 @@ class NativeCalculator extends Calculator
      * For addition, it is assumed that an extra digit can hold a carry (1) without overflowing.
      * Example: 32-bit: max number 1,999,999,999 (9 digits + carry)
      *          64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry)
-     *
-     * @var int
      */
-    private $maxDigits;
+    private int $maxDigits;
 
     /**
      * Class constructor.

File diff suppressed because it is too large
+ 23452 - 6
vendor/composer/autoload_classmap.php


+ 4 - 3
vendor/composer/autoload_files.php

xqd xqd xqd
@@ -6,8 +6,8 @@ $vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
-    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
     '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
+    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
     'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
@@ -21,16 +21,15 @@ return array(
     '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
     'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
     'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
-    '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
     'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
     'd767e4fc2dc52fe66584ab8c6684783e' => $vendorDir . '/adbario/php-dot-notation/src/helpers.php',
-    '65fec9ebcfbb3cbb4fd0d519687aea01' => $vendorDir . '/danielstjules/stringy/src/Create.php',
     'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php',
     '538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php',
     'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
     '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
     '66453932bc1be9fb2f910a27947d11b6' => $vendorDir . '/alibabacloud/client/src/Functions.php',
     '9cdd7b9056abc3081735233ba9dd9c7f' => $vendorDir . '/facade/flare-client-php/src/helpers.php',
+    '1f87db08236948d07391152dccb70f04' => $vendorDir . '/google/apiclient-services/autoload.php',
     '265b4faa2b3a9766332744949e83bf97' => $vendorDir . '/laravel/framework/src/Illuminate/Collections/helpers.php',
     'c7a3c339e7e14b60e06a2d7fcce9476b' => $vendorDir . '/laravel/framework/src/Illuminate/Events/functions.php',
     'f0906e6318348a765ffb6eb24e0d0938' => $vendorDir . '/laravel/framework/src/Illuminate/Foundation/helpers.php',
@@ -38,10 +37,12 @@ return array(
     '6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
     'f0e7e63bbb278a92db02393536748c5f' => $vendorDir . '/overtrue/wechat/src/Kernel/Support/Helpers.php',
     '6747f579ad6817f318cc3a7e7a0abb93' => $vendorDir . '/overtrue/wechat/src/Kernel/Helpers.php',
+    'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
     '801c31d8ed748cfa537fa45402288c95' => $vendorDir . '/psy/psysh/src/functions.php',
     '658bb4096adc969c7b632b99525cd486' => $vendorDir . '/api-ecosystem-for-laravel/dingo-api/src/helpers.php',
     '044fc72df35e84c745ee0d4120dc15d2' => $vendorDir . '/dcat/laravel-admin/src/Support/helpers.php',
     'ed962a97bd972bc82007176b647d4e36' => $vendorDir . '/facade/ignition/src/helpers.php',
+    'a8d3953fd9959404dd22d3dfcd0a79f0' => $vendorDir . '/google/apiclient/src/aliases.php',
     'f960e77410032f236cef8c56617b313e' => $vendorDir . '/overtrue/laravel-lang/src/helpers.php',
     'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.php',
     'ff086428ca04349ca1a7b01ea2d9a650' => $baseDir . '/app/Helper/function.php',

+ 9 - 4
vendor/composer/autoload_psr4.php

xqd xqd xqd xqd xqd xqd
@@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
 
 return array(
     'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
+    'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
     'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'),
     'libphonenumber\\' => array($vendorDir . '/giggsey/libphonenumber-for-php/src'),
     'h4cc\\WKHTMLToPDF\\' => array($vendorDir . '/h4cc/wkhtmltopdf-amd64'),
@@ -17,7 +18,6 @@ return array(
     'Tests\\' => array($baseDir . '/tests'),
     'Tencent\\' => array($vendorDir . '/tencent/tls-sig-api-v2/src'),
     'TencentCloud\\' => array($vendorDir . '/tencentcloud/tencentcloud-sdk-php/src/TencentCloud'),
-    'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
     'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
     'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
     'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
@@ -31,6 +31,7 @@ return array(
     'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
     'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'),
     'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'),
+    'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
     'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
     'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
     'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
@@ -47,9 +48,7 @@ return array(
     'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
     'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'),
     'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
-    'Stringy\\' => array($vendorDir . '/danielstjules/stringy/src'),
     'Stomp\\' => array($vendorDir . '/stomp-php/stomp-php/src'),
-    'StellaMaris\\Clock\\' => array($vendorDir . '/stella-maris/clock/src'),
     'Spatie\\LaravelPackageTools\\' => array($vendorDir . '/spatie/laravel-package-tools/src'),
     'Spatie\\EloquentSortable\\' => array($vendorDir . '/spatie/eloquent-sortable/src'),
     'SocialiteProviders\\Weixin\\' => array($vendorDir . '/socialiteproviders/weixin'),
@@ -64,12 +63,14 @@ return array(
     'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
     'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
+    'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
     'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
-    'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src/Prophecy'),
     'Prettus\\Validator\\' => array($vendorDir . '/prettus/laravel-validation/src/Prettus/Validator'),
     'Prettus\\Repository\\' => array($vendorDir . '/prettus/l5-repository/src/Prettus/Repository'),
     'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
     'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),
+    'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
+    'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'),
     'PHPOpenSourceSaver\\JWTAuth\\' => array($vendorDir . '/php-open-source-saver/jwt-auth/src'),
     'Overtrue\\Socialite\\' => array($vendorDir . '/overtrue/socialite/src'),
     'Overtrue\\LaravelWeChat\\' => array($vendorDir . '/overtrue/laravel-wechat/src'),
@@ -105,8 +106,12 @@ return array(
     'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
     'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'),
+    'Google\\Service\\' => array($vendorDir . '/google/apiclient-services/src'),
+    'Google\\Auth\\' => array($vendorDir . '/google/auth/src'),
+    'Google\\' => array($vendorDir . '/google/apiclient/src'),
     'Giggsey\\Locale\\' => array($vendorDir . '/giggsey/locale/src'),
     'Fruitcake\\Cors\\' => array($vendorDir . '/fruitcake/laravel-cors/src'),
+    'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
     'Faker\\' => array($vendorDir . '/fakerphp/faker/src/Faker'),
     'Facade\\Ignition\\' => array($vendorDir . '/facade/ignition/src'),
     'Facade\\IgnitionContracts\\' => array($vendorDir . '/facade/ignition-contracts/src'),

File diff suppressed because it is too large
+ 23501 - 29
vendor/composer/autoload_static.php


File diff suppressed because it is too large
+ 436 - 236
vendor/composer/installed.json


File diff suppressed because it is too large
+ 272 - 203
vendor/composer/installed.php


+ 2 - 2
vendor/composer/platform_check.php

xqd
@@ -4,8 +4,8 @@
 
 $issues = array();
 
-if (!(PHP_VERSION_ID >= 80002)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.2". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 80100)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
 }
 
 if ($issues) {

+ 0 - 180
vendor/danielstjules/stringy/CHANGELOG.md

xqd
@@ -1,180 +0,0 @@
-### 3.1.0 (2017-06-11)
-* Add $language support to slugify
-* Add bg specific transliteration
-* ЬЪ/ьъ handling is now language-specific
-
-### 3.0.1 (2017-04-12)
-* Don't replace @ in toAscii
-* Use normal replacement for @ in slugify, e.g. user@home => user-home
-
-### 3.0.0 (2017-03-08)
-
-* Breaking change: added $language parameter to toAscii, before
-  $removeUnsupported
-* Breaking change: dropped PHP 5.3 support
-* Breaking change: any StaticStringy methods that previously returned instances
-  of Stringy now return strings
-
-### 2.4.0 (2017-03-02)
-
-* Add startsWithAny
-* Add endsWithAny
-* Add stripWhitespace
-* Fix error handling for unsupported encodings
-* Change private methods to protected for extending class
-* Fix safeTruncate for strings without spaces
-* Additional char support in toAscii, e.g. full width chars and wide
-  non-breaking space
-
-### 2.3.2 (2016-05-02)
-
-* Improve support without mbstring
-
-### 2.3.1 (2016-03-21)
-
-* Always use root namespace for mbstring functions
-
-### 2.3.0 (2016-03-19)
-
-* Add Persian characters in Stringy::charsArray()
-* Use symfony/polyfill-mbstring to avoid dependency on ext-mbstring
-
-### 2.2.0 (2015-12-20)
-
-* isJSON now returns false for empty strings
-* Update for German umlaut transformation
-* Use reflection to generate method list for StaticStringy
-* Added isBase64 method
-* Improved toAscii char coverage
-
-### 2.1.0 (2015-09-02)
-
-* Added simplified StaticStringy class
-* str in Stringy::create and constructor is now optional
-
-### 2.0.0 (2015-07-29)
-
- * Removed StaticStringy class
- * Added append, prepend, toBoolean, repeat, between, slice, split, and lines
- * camelize/upperCamelize now strip leading dashes and underscores
- * titleize converts to lowercase, thus no longer preserving acronyms
-
-### 1.10.0 (2015-07-22)
-
- * Added trimLeft, trimRight
- * Added support for unicode whitespace to trim
- * Added delimit
- * Added indexOf and indexOfLast
- * Added htmlEncode and htmlDecode
- * Added "Ç" in toAscii()
-
-### 1.9.0 (2015-02-09)
-
- * Added hasUpperCase and hasLowerCase
- * Added $removeUnsupported parameter to toAscii()
- * Improved toAscii support with additional Unicode spaces, Vietnamese chars,
-   and numerous other characters
- * Separated the charsArray from toAscii as a protected method that may be
-   extended by inheriting classes
- * Chars array is cached for better performance
-
-### 1.8.1 (2015-01-08)
-
- * Optimized chars()
- * Added "ä Ä Ö Ü"" in toAscii()
- * Added support for Unicode spaces in toAscii()
- * Replaced instances of self::create() with static::create()
- * Added missing test cases for safeTruncate() and longestCommonSuffix()
- * Updated Stringy\create() to avoid collision when it already exists
-
-### 1.8.0 (2015-01-03)
-
- * Listed ext-mbstring in composer.json
- * Added Stringy\create function for PHP 5.6
-
-### 1.7.0 (2014-10-14)
-
- * Added containsAll and containsAny
- * Light cleanup
-
-### 1.6.0 (2014-09-14)
-
- * Added toTitleCase
-
-### 1.5.2 (2014-07-09)
-
- * Announced support for HHVM
-
-### 1.5.1 (2014-04-19)
-
-  * Fixed toAscii() failing to remove remaining non-ascii characters
-  * Updated slugify() to treat dash and underscore as delimiters by default
-  * Updated slugify() to remove leading and trailing delimiter, if present
-
-### 1.5.0 (2014-03-19)
-
-  * Made both str and encoding protected, giving property access to subclasses
-  * Added getEncoding()
-  * Fixed isJSON() giving false negatives
-  * Cleaned up and simplified: replace(), collapseWhitespace(), underscored(),
-    dasherize(), pad(), padLeft(), padRight() and padBoth()
-  * Fixed handling consecutive invalid chars in slugify()
-  * Removed conflicting hard sign transliteration in toAscii()
-
-### 1.4.0 (2014-02-12)
-
-  * Implemented the IteratorAggregate interface, added chars()
-  * Renamed count() to countSubstr()
-  * Updated count() to implement Countable interface
-  * Implemented the ArrayAccess interface with positive and negative indices
-  * Switched from PSR-0 to PSR-4 autoloading
-
-### 1.3.0 (2013-12-16)
-
-  * Additional Bulgarian support for toAscii
-  * str property made private
-  * Constructor casts first argument to string
-  * Constructor throws an InvalidArgumentException when given an array
-  * Constructor throws an InvalidArgumentException when given an object without
-    a __toString method
-
-### 1.2.2 (2013-12-04)
-
-  * Updated create function to use late static binding
-  * Added optional $replacement param to slugify
-
-### 1.2.1 (2013-10-11)
-
-  * Cleaned up tests
-  * Added homepage to composer.json
-
-### 1.2.0 (2013-09-15)
-
-  * Fixed pad's use of InvalidArgumentException
-  * Fixed replace(). It now correctly treats regex special chars as normal chars
-  * Added additional Cyrillic letters to toAscii
-  * Added $caseSensitive to contains() and count()
-  * Added toLowerCase()
-  * Added toUpperCase()
-  * Added regexReplace()
-
-### 1.1.0 (2013-08-31)
-
-  * Fix for collapseWhitespace()
-  * Added isHexadecimal()
-  * Added constructor to Stringy\Stringy
-  * Added isSerialized()
-  * Added isJson()
-
-### 1.0.0 (2013-08-1)
-
-  * 1.0.0 release
-  * Added test coverage for Stringy::create and method chaining
-  * Added tests for returned type
-  * Fixed StaticStringy::replace(). It was returning a Stringy object instead of string
-  * Renamed standardize() to the more appropriate toAscii()
-  * Cleaned up comments and README
-
-### 1.0.0-rc.1 (2013-07-28)
-
-  * Release candidate

+ 0 - 19
vendor/danielstjules/stringy/LICENSE.txt

xqd
@@ -1,19 +0,0 @@
-Copyright (C) 2013 Daniel St. Jules
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.

+ 0 - 1082
vendor/danielstjules/stringy/README.md

xqd
@@ -1,1082 +0,0 @@
-![Stringy](http://danielstjules.com/github/stringy-logo.png)
-
-A PHP string manipulation library with multibyte support. Compatible with PHP
-5.4+, PHP 7+, and HHVM.
-
-``` php
-s('string')->toTitleCase()->ensureRight('y') == 'Stringy'
-```
-
-Refer to the [1.x branch](https://github.com/danielstjules/Stringy/tree/1.x) or
-[2.x branch](https://github.com/danielstjules/Stringy/tree/2.x) for older
-documentation.
-
-[![Build Status](https://api.travis-ci.org/danielstjules/Stringy.svg?branch=master)](https://travis-ci.org/danielstjules/Stringy)
-[![Total Downloads](https://poser.pugx.org/danielstjules/stringy/downloads)](https://packagist.org/packages/danielstjules/stringy)
-[![License](https://poser.pugx.org/danielstjules/stringy/license)](https://packagist.org/packages/danielstjules/stringy)
-
-* [Why?](#why)
-* [Installation](#installation)
-* [OO and Chaining](#oo-and-chaining)
-* [Implemented Interfaces](#implemented-interfaces)
-* [PHP 5.6 Creation](#php-56-creation)
-* [StaticStringy](#staticstringy)
-* [Class methods](#class-methods)
-    * [create](#createmixed-str--encoding-)
-* [Instance methods](#instance-methods)
-<table>
-    <tr>
-        <td><a href="#appendstring-string">append</a></td>
-        <td><a href="#atint-index">at</a></td>
-        <td><a href="#betweenstring-start-string-end--int-offset">between</a></td>
-        <td><a href="#camelize">camelize</a></td>
-    </tr>
-    <tr>
-        <td><a href="#chars">chars</a></td>
-        <td><a href="#collapsewhitespace">collapseWhitespace</a></td>
-        <td><a href="#containsstring-needle--boolean-casesensitive--true-">contains</a></td>
-        <td><a href="#containsallarray-needles--boolean-casesensitive--true-">containsAll</a></td>
-    </tr>
-    <tr>
-        <td><a href="#containsanyarray-needles--boolean-casesensitive--true-">containsAny</a></td>
-        <td><a href="#countsubstrstring-substring--boolean-casesensitive--true-">countSubstr</a></td>
-        <td><a href="#dasherize">dasherize</a></td>
-        <td><a href="#delimitint-delimiter">delimit</a></td>
-    </tr>
-    <tr>
-        <td><a href="#endswithstring-substring--boolean-casesensitive--true-">endsWith</a></td>
-        <td><a href="#endswithanystring-substrings--boolean-casesensitive--true-">endsWithAny</a></td>
-        <td><a href="#ensureleftstring-substring">ensureLeft</a></td>
-        <td><a href="#ensurerightstring-substring">ensureRight</a></td>
-    </tr>
-    <tr>
-        <td><a href="#firstint-n">first</a></td>
-        <td><a href="#getencoding">getEncoding</a></td>
-        <td><a href="#haslowercase">hasLowerCase</a></td>
-        <td><a href="#hasuppercase">hasUpperCase</a></td>
-    </tr>
-    <tr>
-        <td><a href="#htmldecode">htmlDecode</a></td>
-        <td><a href="#htmlencode">htmlEncode</a></td>
-        <td><a href="#humanize">humanize</a></td>
-        <td><a href="#indexofstring-needle--offset--0-">indexOf</a></td>
-    </tr>
-    <tr>
-        <td><a href="#indexoflaststring-needle--offset--0-">indexOfLast</a></td>
-        <td><a href="#insertint-index-string-substring">insert</a></td>
-        <td><a href="#isalpha">isAlpha</a></td>
-        <td><a href="#isalphanumeric">isAlphanumeric</a></td>
-    </tr>
-    <tr>
-        <td><a href="#isbase64">isBase64</a></td>
-        <td><a href="#isblank">isBlank</a></td>
-        <td><a href="#ishexadecimal">isHexadecimal</a></td>
-        <td><a href="#isjson">isJson</a></td>
-    </tr>
-    <tr>
-        <td><a href="#islowercase">isLowerCase</a></td>
-        <td><a href="#isserialized">isSerialized</a></td>
-        <td><a href="#isuppercase">isUpperCase</a></td>
-        <td><a href="#lastint-n">last</a></td>
-    </tr>
-    <tr>
-        <td><a href="#length">length</a></td>
-        <td><a href="#lines">lines</a></td>
-        <td><a href="#longestcommonprefixstring-otherstr">longestCommonPrefix</a></td>
-        <td><a href="#longestcommonsuffixstring-otherstr">longestCommonSuffix</a></td>
-    </tr>
-    <tr>
-        <td><a href="#longestcommonsubstringstring-otherstr">longestCommonSubstring</a></td>
-        <td><a href="#lowercasefirst">lowerCaseFirst</a></td>
-        <td><a href="#padint-length--string-padstr-----string-padtype--right-">pad</a></td>
-        <td><a href="#padbothint-length--string-padstr----">padBoth</a></td>
-    </tr>
-    <tr>
-        <td><a href="#padleftint-length--string-padstr----">padLeft</a></td>
-        <td><a href="#padrightint-length--string-padstr----">padRight</a></td>
-        <td><a href="#prependstring-string">prepend</a></td>
-        <td><a href="#regexreplacestring-pattern-string-replacement--string-options--msr">regexReplace</a></td>
-    </tr>
-    <tr>
-        <td><a href="#removeleftstring-substring">removeLeft</a></td>
-        <td><a href="#removerightstring-substring">removeRight</a></td>
-        <td><a href="#repeatint-multiplier">repeat</a></td>
-        <td><a href="#replacestring-search-string-replacement">replace</a></td>
-    </tr>
-    <tr>
-        <td><a href="#reverse">reverse</a></td>
-        <td><a href="#safetruncateint-length--string-substring---">safeTruncate</a></td>
-        <td><a href="#shuffle">shuffle</a></td>
-        <td><a href="#slugify-string-replacement-----string-language--en">slugify</a></td>
-    </tr>
-    <tr>
-        <td><a href="#sliceint-start--int-end-">slice</a></td>
-        <td><a href="#splitstring-pattern--int-limit-">split</a></td>
-        <td><a href="#startswithstring-substring--boolean-casesensitive--true-">startsWith</a></td>
-        <td><a href="#startswithanystring-substrings--boolean-casesensitive--true-">startsWithAny</a></td>
-    </tr>
-    <tr>
-        <td><a href="#stripwhitespace">stripWhitespace</a></td>
-        <td><a href="#substrint-start--int-length-">substr</a></td>
-        <td><a href="#surroundstring-substring">surround</a></td>
-        <td><a href="#swapcase">swapCase</a></td>
-    </tr>
-    <tr>
-        <td><a href="#tidy">tidy</a></td>
-        <td><a href="#titleize-array-ignore">titleize</a></td>
-        <td><a href="#toascii-string-language--en--bool-removeunsupported--true-">toAscii</a></td>
-        <td><a href="#toboolean">toBoolean</a></td>
-    </tr>
-    <tr>
-        <td><a href="#tolowercase">toLowerCase</a></td>
-        <td><a href="#tospaces-tablength--4-">toSpaces</a></td>
-        <td><a href="#totabs-tablength--4-">toTabs</a></td>
-        <td><a href="#totitlecase">toTitleCase</a></td>
-    </tr>
-    <tr>
-        <td><a href="#touppercase">toUpperCase</a></td>
-        <td><a href="#trim-string-chars">trim</a></td>
-        <td><a href="#trimleft-string-chars">trimLeft</a></td>
-        <td><a href="#trimright-string-chars">trimRight</a></td>
-    </tr>
-    <tr>
-        <td><a href="#truncateint-length--string-substring---">truncate</a></td>
-        <td><a href="#underscored">underscored</a></td>
-        <td><a href="#uppercamelize">upperCamelize</a></td>
-        <td><a href="#uppercasefirst">upperCaseFirst</a></td>
-    </tr>
-</table>
-
-* [Extensions](#extensions)
-* [Tests](#tests)
-* [License](#license)
-
-## Why?
-
-In part due to a lack of multibyte support (including UTF-8) across many of
-PHP's standard string functions. But also to offer an OO wrapper around the
-`mbstring` module's multibyte-compatible functions. Stringy handles some quirks,
-provides additional functionality, and hopefully makes strings a little easier
-to work with!
-
-```php
-// Standard library
-strtoupper('fòôbàř');       // 'FòôBàř'
-strlen('fòôbàř');           // 10
-
-// mbstring
-mb_strtoupper('fòôbàř');    // 'FÒÔBÀŘ'
-mb_strlen('fòôbàř');        // '6'
-
-// Stringy
-s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ'
-s('fòôbàř')->length();      // '6'
-```
-
-## Installation
-
-If you're using Composer to manage dependencies, you can include the following
-in your composer.json file:
-
-```json
-"require": {
-    "danielstjules/stringy": "~3.1.0"
-}
-```
-
-Then, after running `composer update` or `php composer.phar update`, you can
-load the class using Composer's autoloading:
-
-```php
-require 'vendor/autoload.php';
-```
-
-Otherwise, you can simply require the file directly:
-
-```php
-require_once 'path/to/Stringy/src/Stringy.php';
-```
-
-And in either case, I'd suggest using an alias.
-
-```php
-use Stringy\Stringy as S;
-```
-
-Please note that Stringy relies on the `mbstring` module for its underlying
-multibyte support. If the module is not found, Stringy will use
-[symfony/polyfill-mbstring](https://github.com/symfony/polyfill-mbstring).
-ex-mbstring is a non-default, but very common module. For example, with debian
-and ubuntu, it's included in libapache2-mod-php5, php5-cli, and php5-fpm. For
-OSX users, it's a default for any version of PHP installed with homebrew.
-If compiling PHP from scratch, it can be included with the
-`--enable-mbstring` flag.
-
-## OO and Chaining
-
-The library offers OO method chaining, as seen below:
-
-```php
-use Stringy\Stringy as S;
-echo S::create('fòô     bàř')->collapseWhitespace()->swapCase(); // 'FÒÔ BÀŘ'
-```
-
-`Stringy\Stringy` has a __toString() method, which returns the current string
-when the object is used in a string context, ie:
-`(string) S::create('foo')  // 'foo'`
-
-## Implemented Interfaces
-
-`Stringy\Stringy` implements the `IteratorAggregate` interface, meaning that
-`foreach` can be used with an instance of the class:
-
-``` php
-$stringy = S::create('fòôbàř');
-foreach ($stringy as $char) {
-    echo $char;
-}
-// 'fòôbàř'
-```
-
-It implements the `Countable` interface, enabling the use of `count()` to
-retrieve the number of characters in the string:
-
-``` php
-$stringy = S::create('fòô');
-count($stringy);  // 3
-```
-
-Furthermore, the `ArrayAccess` interface has been implemented. As a result,
-`isset()` can be used to check if a character at a specific index exists. And
-since `Stringy\Stringy` is immutable, any call to `offsetSet` or `offsetUnset`
-will throw an exception. `offsetGet` has been implemented, however, and accepts
-both positive and negative indexes. Invalid indexes result in an
-`OutOfBoundsException`.
-
-``` php
-$stringy = S::create('bàř');
-echo $stringy[2];     // 'ř'
-echo $stringy[-2];    // 'à'
-isset($stringy[-4]);  // false
-
-$stringy[3];          // OutOfBoundsException
-$stringy[2] = 'a';    // Exception
-```
-
-## PHP 5.6 Creation
-
-As of PHP 5.6, [`use function`](https://wiki.php.net/rfc/use_function) is
-available for importing functions. Stringy exposes a namespaced function,
-`Stringy\create`, which emits the same behaviour as `Stringy\Stringy::create()`.
-If running PHP 5.6, or another runtime that supports the `use function` syntax,
-you can take advantage of an even simpler API as seen below:
-
-``` php
-use function Stringy\create as s;
-
-// Instead of: S::create('fòô     bàř')
-s('fòô     bàř')->collapseWhitespace()->swapCase();
-```
-
-## StaticStringy
-
-All methods listed under "Instance methods" are available as part of a static
-wrapper. For StaticStringy methods, the optional encoding is expected to be the
-last argument. The return value is not cast, and may thus be of type Stringy,
-integer, boolean, etc.
-
-```php
-use Stringy\StaticStringy as S;
-
-// Translates to Stringy::create('fòôbàř')->slice(0, 3);
-// Returns a Stringy object with the string "fòô"
-S::slice('fòôbàř', 0, 3);
-```
-
-## Class methods
-
-##### create(mixed $str [, $encoding ])
-
-Creates a Stringy object and assigns both str and encoding properties
-the supplied values. $str is cast to a string prior to assignment, and if
-$encoding is not specified, it defaults to mb_internal_encoding(). It
-then returns the initialized object. Throws an InvalidArgumentException
-if the first argument is an array or object without a __toString method.
-
-```php
-$stringy = S::create('fòôbàř'); // 'fòôbàř'
-```
-
-## Instance Methods
-
-Stringy objects are immutable. All examples below make use of PHP 5.6
-function importing, and PHP 5.4 short array syntax. They also assume the
-encoding returned by mb_internal_encoding() is UTF-8. For further details,
-see the documentation for the create method above, as well as the notes
-on PHP 5.6 creation.
-
-##### append(string $string)
-
-Returns a new string with $string appended.
-
-```php
-s('fòô')->append('bàř'); // 'fòôbàř'
-```
-
-##### at(int $index)
-
-Returns the character at $index, with indexes starting at 0.
-
-```php
-s('fòôbàř')->at(3); // 'b'
-```
-
-##### between(string $start, string $end [, int $offset])
-
-Returns the substring between $start and $end, if found, or an empty
-string. An optional offset may be supplied from which to begin the
-search for the start string.
-
-```php
-s('{foo} and {bar}')->between('{', '}'); // 'foo'
-```
-
-##### camelize()
-
-Returns a camelCase version of the string. Trims surrounding spaces,
-capitalizes letters following digits, spaces, dashes and underscores,
-and removes spaces, dashes, as well as underscores.
-
-```php
-s('Camel-Case')->camelize(); // 'camelCase'
-```
-
-##### chars()
-
-Returns an array consisting of the characters in the string.
-
-```php
-s('fòôbàř')->chars(); // ['f', 'ò', 'ô', 'b', 'à', 'ř']
-```
-
-##### collapseWhitespace()
-
-Trims the string and replaces consecutive whitespace characters with a
-single space. This includes tabs and newline characters, as well as
-multibyte whitespace such as the thin space and ideographic space.
-
-```php
-s('   Ο     συγγραφέας  ')->collapseWhitespace(); // 'Ο συγγραφέας'
-```
-
-##### contains(string $needle [, boolean $caseSensitive = true ])
-
-Returns true if the string contains $needle, false otherwise. By default,
-the comparison is case-sensitive, but can be made insensitive
-by setting $caseSensitive to false.
-
-```php
-s('Ο συγγραφέας είπε')->contains('συγγραφέας'); // true
-```
-
-##### containsAll(array $needles [, boolean $caseSensitive = true ])
-
-Returns true if the string contains all $needles, false otherwise. By
-default the comparison is case-sensitive, but can be made insensitive by
-setting $caseSensitive to false.
-
-```php
-s('foo & bar')->containsAll(['foo', 'bar']); // true
-```
-
-##### containsAny(array $needles [, boolean $caseSensitive = true ])
-
-Returns true if the string contains any $needles, false otherwise. By
-default the comparison is case-sensitive, but can be made insensitive by
-setting $caseSensitive to false.
-
-```php
-s('str contains foo')->containsAny(['foo', 'bar']); // true
-```
-
-##### countSubstr(string $substring [, boolean $caseSensitive = true ])
-
-Returns the number of occurrences of $substring in the given string.
-By default, the comparison is case-sensitive, but can be made insensitive
-by setting $caseSensitive to false.
-
-```php
-s('Ο συγγραφέας είπε')->countSubstr('α'); // 2
-```
-
-##### dasherize()
-
-Returns a lowercase and trimmed string separated by dashes. Dashes are
-inserted before uppercase characters (with the exception of the first
-character of the string), and in place of spaces as well as underscores.
-
-```php
-s('fooBar')->dasherize(); // 'foo-bar'
-```
-
-##### delimit(int $delimiter)
-
-Returns a lowercase and trimmed string separated by the given delimiter.
-Delimiters are inserted before uppercase characters (with the exception
-of the first character of the string), and in place of spaces, dashes,
-and underscores. Alpha delimiters are not converted to lowercase.
-
-```php
-s('fooBar')->delimit('::'); // 'foo::bar'
-```
-
-##### endsWith(string $substring [, boolean $caseSensitive = true ])
-
-Returns true if the string ends with $substring, false otherwise. By
-default, the comparison is case-sensitive, but can be made insensitive by
-setting $caseSensitive to false.
-
-```php
-s('fòôbàř')->endsWith('bàř'); // true
-```
-
-##### endsWithAny(string[] $substrings [, boolean $caseSensitive = true ])
-
-Returns true if the string ends with any of $substrings, false otherwise.
-By default, the comparison is case-sensitive, but can be made insensitive
-by setting $caseSensitive to false.
-
-```php
-s('fòôbàř')->endsWithAny(['bàř', 'baz']); // true
-```
-
-##### ensureLeft(string $substring)
-
-Ensures that the string begins with $substring. If it doesn't, it's prepended.
-
-```php
-s('foobar')->ensureLeft('http://'); // 'http://foobar'
-```
-
-##### ensureRight(string $substring)
-
-Ensures that the string ends with $substring. If it doesn't, it's appended.
-
-```php
-s('foobar')->ensureRight('.com'); // 'foobar.com'
-```
-
-##### first(int $n)
-
-Returns the first $n characters of the string.
-
-```php
-s('fòôbàř')->first(3); // 'fòô'
-```
-
-##### getEncoding()
-
-Returns the encoding used by the Stringy object.
-
-```php
-s('fòôbàř')->getEncoding(); // 'UTF-8'
-```
-
-##### hasLowerCase()
-
-Returns true if the string contains a lower case char, false otherwise.
-
-```php
-s('fòôbàř')->hasLowerCase(); // true
-```
-
-##### hasUpperCase()
-
-Returns true if the string contains an upper case char, false otherwise.
-
-```php
-s('fòôbàř')->hasUpperCase(); // false
-```
-
-##### htmlDecode()
-
-Convert all HTML entities to their applicable characters. An alias of
-html_entity_decode. For a list of flags, refer to
-http://php.net/manual/en/function.html-entity-decode.php
-
-```php
-s('&amp;')->htmlDecode(); // '&'
-```
-
-##### htmlEncode()
-
-Convert all applicable characters to HTML entities. An alias of
-htmlentities. Refer to http://php.net/manual/en/function.htmlentities.php
-for a list of flags.
-
-```php
-s('&')->htmlEncode(); // '&amp;'
-```
-
-##### humanize()
-
-Capitalizes the first word of the string, replaces underscores with
-spaces, and strips '_id'.
-
-```php
-s('author_id')->humanize(); // 'Author'
-```
-
-##### indexOf(string $needle [, $offset = 0 ]);
-
-Returns the index of the first occurrence of $needle in the string,
-and false if not found. Accepts an optional offset from which to begin
-the search. A negative index searches from the end
-
-```php
-s('string')->indexOf('ing'); // 3
-```
-
-##### indexOfLast(string $needle [, $offset = 0 ]);
-
-Returns the index of the last occurrence of $needle in the string,
-and false if not found. Accepts an optional offset from which to begin
-the search. Offsets may be negative to count from the last character
-in the string.
-
-```php
-s('foobarfoo')->indexOfLast('foo'); // 10
-```
-
-##### insert(int $index, string $substring)
-
-Inserts $substring into the string at the $index provided.
-
-```php
-s('fòôbř')->insert('à', 4); // 'fòôbàř'
-```
-
-##### isAlpha()
-
-Returns true if the string contains only alphabetic chars, false otherwise.
-
-```php
-s('丹尼爾')->isAlpha(); // true
-```
-
-##### isAlphanumeric()
-
-Returns true if the string contains only alphabetic and numeric chars, false
-otherwise.
-
-```php
-s('دانيال1')->isAlphanumeric(); // true
-```
-
-##### isBase64()
-
-Returns true if the string is base64 encoded, false otherwise.
-
-```php
-s('Zm9vYmFy')->isBase64(); // true
-```
-
-##### isBlank()
-
-Returns true if the string contains only whitespace chars, false otherwise.
-
-```php
-s("\n\t  \v\f")->isBlank(); // true
-```
-
-##### isHexadecimal()
-
-Returns true if the string contains only hexadecimal chars, false otherwise.
-
-```php
-s('A102F')->isHexadecimal(); // true
-```
-
-##### isJson()
-
-Returns true if the string is JSON, false otherwise. Unlike json_decode
-in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
-in that an empty string is not considered valid JSON.
-
-```php
-s('{"foo":"bar"}')->isJson(); // true
-```
-
-##### isLowerCase()
-
-Returns true if the string contains only lower case chars, false otherwise.
-
-```php
-s('fòôbàř')->isLowerCase(); // true
-```
-
-##### isSerialized()
-
-Returns true if the string is serialized, false otherwise.
-
-```php
-s('a:1:{s:3:"foo";s:3:"bar";}')->isSerialized(); // true
-```
-
-##### isUpperCase()
-
-Returns true if the string contains only upper case chars, false otherwise.
-
-```php
-s('FÒÔBÀŘ')->isUpperCase(); // true
-```
-
-##### last(int $n)
-
-Returns the last $n characters of the string.
-
-```php
-s('fòôbàř')->last(3); // 'bàř'
-```
-
-##### length()
-
-Returns the length of the string. An alias for PHP's mb_strlen() function.
-
-```php
-s('fòôbàř')->length(); // 6
-```
-
-##### lines()
-
-Splits on newlines and carriage returns, returning an array of Stringy
-objects corresponding to the lines in the string.
-
-```php
-s("fòô\r\nbàř\n")->lines(); // ['fòô', 'bàř', '']
-```
-
-##### longestCommonPrefix(string $otherStr)
-
-Returns the longest common prefix between the string and $otherStr.
-
-```php
-s('foobar')->longestCommonPrefix('foobaz'); // 'fooba'
-```
-
-##### longestCommonSuffix(string $otherStr)
-
-Returns the longest common suffix between the string and $otherStr.
-
-```php
-s('fòôbàř')->longestCommonSuffix('fòrbàř'); // 'bàř'
-```
-
-##### longestCommonSubstring(string $otherStr)
-
-Returns the longest common substring between the string and $otherStr. In the
-case of ties, it returns that which occurs first.
-
-```php
-s('foobar')->longestCommonSubstring('boofar'); // 'oo'
-```
-
-##### lowerCaseFirst()
-
-Converts the first character of the supplied string to lower case.
-
-```php
-s('Σ foo')->lowerCaseFirst(); // 'σ foo'
-```
-
-##### pad(int $length [, string $padStr = ' ' [, string $padType = 'right' ]])
-
-Pads the string to a given length with $padStr. If length is less than
-or equal to the length of the string, no padding takes places. The default
-string used for padding is a space, and the default type (one of 'left',
-'right', 'both') is 'right'. Throws an InvalidArgumentException if
-$padType isn't one of those 3 values.
-
-```php
-s('fòôbàř')->pad(9, '-/', 'left'); // '-/-fòôbàř'
-```
-
-##### padBoth(int $length [, string $padStr = ' ' ])
-
-Returns a new string of a given length such that both sides of the string
-string are padded. Alias for pad() with a $padType of 'both'.
-
-```php
-s('foo bar')->padBoth(9, ' '); // ' foo bar '
-```
-
-##### padLeft(int $length [, string $padStr = ' ' ])
-
-Returns a new string of a given length such that the beginning of the
-string is padded. Alias for pad() with a $padType of 'left'.
-
-```php
-s('foo bar')->padLeft(9, ' '); // '  foo bar'
-```
-
-##### padRight(int $length [, string $padStr = ' ' ])
-
-Returns a new string of a given length such that the end of the string is
-padded. Alias for pad() with a $padType of 'right'.
-
-```php
-s('foo bar')->padRight(10, '_*'); // 'foo bar_*_'
-```
-
-##### prepend(string $string)
-
-Returns a new string starting with $string.
-
-```php
-s('bàř')->prepend('fòô'); // 'fòôbàř'
-```
-
-##### regexReplace(string $pattern, string $replacement [, string $options = 'msr'])
-
-Replaces all occurrences of $pattern in $str by $replacement. An alias
-for mb_ereg_replace(). Note that the 'i' option with multibyte patterns
-in mb_ereg_replace() requires PHP 5.6+ for correct results. This is due
-to a lack of support in the bundled version of Oniguruma in PHP < 5.6,
-and current versions of HHVM (3.8 and below).
-
-```php
-s('fòô ')->regexReplace('f[òô]+\s', 'bàř'); // 'bàř'
-s('fò')->regexReplace('(ò)', '\\1ô'); // 'fòô'
-```
-
-##### removeLeft(string $substring)
-
-Returns a new string with the prefix $substring removed, if present.
-
-```php
-s('fòôbàř')->removeLeft('fòô'); // 'bàř'
-```
-
-##### removeRight(string $substring)
-
-Returns a new string with the suffix $substring removed, if present.
-
-```php
-s('fòôbàř')->removeRight('bàř'); // 'fòô'
-```
-
-##### repeat(int $multiplier)
-
-Returns a repeated string given a multiplier. An alias for str_repeat.
-
-```php
-s('α')->repeat(3); // 'ααα'
-```
-
-##### replace(string $search, string $replacement)
-
-Replaces all occurrences of $search in $str by $replacement.
-
-```php
-s('fòô bàř fòô bàř')->replace('fòô ', ''); // 'bàř bàř'
-```
-
-##### reverse()
-
-Returns a reversed string. A multibyte version of strrev().
-
-```php
-s('fòôbàř')->reverse(); // 'řàbôòf'
-```
-
-##### safeTruncate(int $length [, string $substring = '' ])
-
-Truncates the string to a given length, while ensuring that it does not
-split words. If $substring is provided, and truncating occurs, the
-string is further truncated so that the substring may be appended without
-exceeding the desired length.
-
-```php
-s('What are your plans today?')->safeTruncate(22, '...');
-// 'What are your plans...'
-```
-
-##### shuffle()
-
-A multibyte str_shuffle() function. It returns a string with its characters in
-random order.
-
-```php
-s('fòôbàř')->shuffle(); // 'àôřbòf'
-```
-
-##### slugify([, string $replacement = '-' [, string $language = 'en']])
-
-Converts the string into an URL slug. This includes replacing non-ASCII
-characters with their closest ASCII equivalents, removing remaining
-non-ASCII and non-alphanumeric characters, and replacing whitespace with
-$replacement. The replacement defaults to a single dash, and the string
-is also converted to lowercase. The language of the source string can
-also be supplied for language-specific transliteration.
-
-```php
-s('Using strings like fòô bàř')->slugify(); // 'using-strings-like-foo-bar'
-```
-
-##### slice(int $start [, int $end ])
-
-Returns the substring beginning at $start, and up to, but not including
-the index specified by $end. If $end is omitted, the function extracts
-the remaining string. If $end is negative, it is computed from the end
-of the string.
-
-```php
-s('fòôbàř')->slice(3, -1); // 'bà'
-```
-
-##### split(string $pattern [, int $limit ])
-
-Splits the string with the provided regular expression, returning an
-array of Stringy objects. An optional integer $limit will truncate the
-results.
-
-```php
-s('foo,bar,baz')->split(',', 2); // ['foo', 'bar']
-```
-
-##### startsWith(string $substring [, boolean $caseSensitive = true ])
-
-Returns true if the string begins with $substring, false otherwise.
-By default, the comparison is case-sensitive, but can be made insensitive
-by setting $caseSensitive to false.
-
-```php
-s('FÒÔbàřbaz')->startsWith('fòôbàř', false); // true
-```
-
-##### startsWithAny(string[] $substrings [, boolean $caseSensitive = true ])
-
-Returns true if the string begins with any of $substrings, false
-otherwise. By default the comparison is case-sensitive, but can be made
-insensitive by setting $caseSensitive to false.
-
-```php
-s('FÒÔbàřbaz')->startsWithAny(['fòô', 'bàř'], false); // true
-```
-
-##### stripWhitespace()
-
-Strip all whitespace characters. This includes tabs and newline
-characters, as well as multibyte whitespace such as the thin space
-and ideographic space.
-
-```php
-s('   Ο     συγγραφέας  ')->stripWhitespace(); // 'Οσυγγραφέας'
-```
-
-##### substr(int $start [, int $length ])
-
-Returns the substring beginning at $start with the specified $length.
-It differs from the mb_substr() function in that providing a $length of
-null will return the rest of the string, rather than an empty string.
-
-```php
-s('fòôbàř')->substr(2, 3); // 'ôbà'
-```
-
-##### surround(string $substring)
-
-Surrounds a string with the given substring.
-
-```php
-s(' ͜ ')->surround('ʘ'); // 'ʘ ͜ ʘ'
-```
-
-##### swapCase()
-
-Returns a case swapped version of the string.
-
-```php
-s('Ντανιλ')->swapCase(); // 'νΤΑΝΙΛ'
-```
-
-##### tidy()
-
-Returns a string with smart quotes, ellipsis characters, and dashes from
-Windows-1252 (commonly used in Word documents) replaced by their ASCII equivalents.
-
-```php
-s('“I see…”')->tidy(); // '"I see..."'
-```
-
-##### titleize([, array $ignore])
-
-Returns a trimmed string with the first letter of each word capitalized.
-Also accepts an array, $ignore, allowing you to list words not to be
-capitalized.
-
-```php
-$ignore = ['at', 'by', 'for', 'in', 'of', 'on', 'out', 'to', 'the'];
-s('i like to watch television')->titleize($ignore);
-// 'I Like to Watch Television'
-```
-
-##### toAscii([, string $language = 'en' [, bool $removeUnsupported = true ]])
-
-Returns an ASCII version of the string. A set of non-ASCII characters are
-replaced with their closest ASCII counterparts, and the rest are removed
-by default. The language or locale of the source string can be supplied
-for language-specific transliteration in any of the following formats:
-en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
-to "aeoeue" rather than "aou" as in other languages.
-
-```php
-s('fòôbàř')->toAscii(); // 'foobar'
-s('äöü')->toAscii(); // 'aou'
-s('äöü')->toAscii('de'); // 'aeoeue'
-```
-
-##### toBoolean()
-
-Returns a boolean representation of the given logical string value.
-For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
-'off', and 'no' will return false. In all instances, case is ignored.
-For other numeric strings, their sign will determine the return value.
-In addition, blank strings consisting of only whitespace will return
-false. For all other strings, the return value is a result of a
-boolean cast.
-
-```php
-s('OFF')->toBoolean(); // false
-```
-
-##### toLowerCase()
-
-Converts all characters in the string to lowercase. An alias for PHP's
-mb_strtolower().
-
-```php
-s('FÒÔBÀŘ')->toLowerCase(); // 'fòôbàř'
-```
-
-##### toSpaces([, tabLength = 4 ])
-
-Converts each tab in the string to some number of spaces, as defined by
-$tabLength. By default, each tab is converted to 4 consecutive spaces.
-
-```php
-s(' String speech = "Hi"')->toSpaces(); // '    String speech = "Hi"'
-```
-
-##### toTabs([, tabLength = 4 ])
-
-Converts each occurrence of some consecutive number of spaces, as defined
-by $tabLength, to a tab. By default, each 4 consecutive spaces are
-converted to a tab.
-
-```php
-s('    fòô    bàř')->toTabs();
-// '   fòô bàř'
-```
-
-##### toTitleCase()
-
-Converts the first character of each word in the string to uppercase.
-
-```php
-s('fòô bàř')->toTitleCase(); // 'Fòô Bàř'
-```
-
-##### toUpperCase()
-
-Converts all characters in the string to uppercase. An alias for PHP's
-mb_strtoupper().
-
-```php
-s('fòôbàř')->toUpperCase(); // 'FÒÔBÀŘ'
-```
-
-##### trim([, string $chars])
-
-Returns a string with whitespace removed from the start and end of the
-string. Supports the removal of unicode whitespace. Accepts an optional
-string of characters to strip instead of the defaults.
-
-```php
-s('  fòôbàř  ')->trim(); // 'fòôbàř'
-```
-
-##### trimLeft([, string $chars])
-
-Returns a string with whitespace removed from the start of the string.
-Supports the removal of unicode whitespace. Accepts an optional
-string of characters to strip instead of the defaults.
-
-```php
-s('  fòôbàř  ')->trimLeft(); // 'fòôbàř  '
-```
-
-##### trimRight([, string $chars])
-
-Returns a string with whitespace removed from the end of the string.
-Supports the removal of unicode whitespace. Accepts an optional
-string of characters to strip instead of the defaults.
-
-```php
-s('  fòôbàř  ')->trimRight(); // '  fòôbàř'
-```
-
-##### truncate(int $length [, string $substring = '' ])
-
-Truncates the string to a given length. If $substring is provided, and
-truncating occurs, the string is further truncated so that the substring
-may be appended without exceeding the desired length.
-
-```php
-s('What are your plans today?')->truncate(19, '...'); // 'What are your pl...'
-```
-
-##### underscored()
-
-Returns a lowercase and trimmed string separated by underscores.
-Underscores are inserted before uppercase characters (with the exception
-of the first character of the string), and in place of spaces as well as dashes.
-
-```php
-s('TestUCase')->underscored(); // 'test_u_case'
-```
-
-##### upperCamelize()
-
-Returns an UpperCamelCase version of the supplied string. It trims
-surrounding spaces, capitalizes letters following digits, spaces, dashes
-and underscores, and removes spaces, dashes, underscores.
-
-```php
-s('Upper Camel-Case')->upperCamelize(); // 'UpperCamelCase'
-```
-
-##### upperCaseFirst()
-
-Converts the first character of the supplied string to upper case.
-
-```php
-s('σ foo')->upperCaseFirst(); // 'Σ foo'
-```
-
-## Extensions
-
-The following is a list of libraries that extend Stringy:
-
- * [SliceableStringy](https://github.com/danielstjules/SliceableStringy):
-Python-like string slices in PHP
- * [SubStringy](https://github.com/TCB13/SubStringy):
-Advanced substring methods
-
-## Tests
-
-From the project directory, tests can be ran using `phpunit`
-
-## License
-
-Released under the MIT License - see `LICENSE.txt` for details.

+ 0 - 35
vendor/danielstjules/stringy/composer.json

xqd
@@ -1,35 +0,0 @@
-{
-    "name": "danielstjules/stringy",
-    "description": "A string manipulation library with multibyte support",
-    "keywords": [
-        "multibyte", "string", "manipulation", "utility", "methods", "utf-8",
-        "helpers", "utils", "utf"
-    ],
-    "homepage": "https://github.com/danielstjules/Stringy",
-    "license": "MIT",
-    "authors": [
-        {
-            "name": "Daniel St. Jules",
-            "email": "danielst.jules@gmail.com",
-            "homepage": "http://www.danielstjules.com"
-        }
-    ],
-    "require": {
-        "php": ">=5.4.0",
-        "symfony/polyfill-mbstring": "~1.1"
-    },
-    "require-dev": {
-        "phpunit/phpunit": "~4.0"
-    },
-    "support": {
-        "issues": "https://github.com/danielstjules/Stringy/issues",
-        "source": "https://github.com/danielstjules/Stringy"
-    },
-    "autoload": {
-        "psr-4": { "Stringy\\": "src/" },
-        "files": ["src/Create.php"]
-    },
-    "autoload-dev": {
-        "classmap": [ "tests" ]
-    }
-}

+ 0 - 19
vendor/danielstjules/stringy/src/Create.php

xqd
@@ -1,19 +0,0 @@
-<?php
-
-namespace Stringy;
-
-if (!function_exists('Stringy\create')) {
-    /**
-     * Creates a Stringy object and returns it on success.
-     *
-     * @param  mixed   $str      Value to modify, after being cast to string
-     * @param  string  $encoding The character encoding
-     * @return Stringy A Stringy object
-     * @throws \InvalidArgumentException if an array or object without a
-     *         __toString method is passed as the first argument
-     */
-    function create($str, $encoding = null)
-    {
-        return new Stringy($str, $encoding);
-    }
-}

+ 0 - 161
vendor/danielstjules/stringy/src/StaticStringy.php

xqd
@@ -1,161 +0,0 @@
-<?php
-
-namespace Stringy;
-
-use BadMethodCallException;
-use ReflectionClass;
-use ReflectionMethod;
-
-/**
- * Class StaticStringy
- *
- * @method static string append(string $str, string $stringAppend, string $encoding = null)
- * @method static string at(string $str, int $index, string $encoding = null)
- * @method static string between(string $str, string $start, string $end, int $offset = 0, string $encoding = null)
- * @method static string camelize(string $str, string $encoding = null)
- * @method static string chars(string $str, string $encoding = null)
- * @method static string collapseWhitespace(string $str, string $encoding = null)
- * @method static bool contains(string $str, string $needle, bool $caseSensitive = true, string $encoding = null)
- * @method static bool containsAll(string $str, string[] $needle, bool $caseSensitive = true, string $encoding = null)
- * @method static bool containsAny(string $str, string[] $needle, bool $caseSensitive = true, string $encoding = null)
- * @method static int count(string $str, string $encoding = null)
- * @method static int countSubstr(string $str, string $substring, bool $caseSensitive = true, string $encoding = null)
- * @method static string dasherize(string $str, string $encoding = null)
- * @method static string delimit(string $str, string $delimiter, string $encoding = null)
- * @method static bool endsWith(string $str, string $substring, bool $caseSensitive = true, string $encoding = null)
- * @method static bool endsWithAny(string $str, string[] $substrings, bool $caseSensitive = true, string $encoding = null)
- * @method static string ensureLeft(string $str, string $substring, string $encoding = null)
- * @method static string ensureRight(string $str, string $substring, string $encoding = null)
- * @method static string first(string $str, int $n, string $encoding = null)
- * @method static bool hasLowerCase(string $str, string $encoding = null)
- * @method static bool hasUpperCase(string $str, string $encoding = null)
- * @method static string htmlDecode(string $str, int $flags = ENT_COMPAT, string $encoding = null)
- * @method static string htmlEncode(string $str, int $flags = ENT_COMPAT, string $encoding = null)
- * @method static string humanize(string $str, string $encoding = null)
- * @method static int indexOf(string $str, string $needle, int $offset = 0, string $encoding = null)
- * @method static int indexOfLast(string $str, string $needle, int $offset = 0, string $encoding = null)
- * @method static string insert(string $str, string $substring, int $index = 0, string $encoding = null)
- * @method static bool isAlpha(string $str, string $encoding = null)
- * @method static bool isAlphanumeric(string $str, string $encoding = null)
- * @method static bool isBase64(string $str, string $encoding = null)
- * @method static bool isBlank(string $str, string $encoding = null)
- * @method static bool isHexadecimal(string $str, string $encoding = null)
- * @method static bool isJson(string $str, string $encoding = null)
- * @method static bool isLowerCase(string $str, string $encoding = null)
- * @method static bool isSerialized(string $str, string $encoding = null)
- * @method static bool isUpperCase(string $str, string $encoding = null)
- * @method static string last(string $str, string $encoding = null)
- * @method static int length(string $str, string $encoding = null)
- * @method static string[] lines(string $str, string $encoding = null)
- * @method static string longestCommonPrefix(string $str, string $otherStr, string $encoding = null)
- * @method static string longestCommonSuffix(string $str, string $otherStr, string $encoding = null)
- * @method static string longestCommonSubstring(string $str, string $otherStr, string $encoding = null)
- * @method static string lowerCaseFirst(string $str, string $encoding = null)
- * @method static string pad(string $str, int $length, string $padStr = ' ', string $padType = 'right', string $encoding = null)
- * @method static string padBoth(string $str, int $length, string $padStr = ' ', string $encoding = null)
- * @method static string padLeft(string $str, int $length, string $padStr = ' ', string $encoding = null)
- * @method static string padRight(string $str, int $length, string $padStr = ' ', string $encoding = null)
- * @method static string prepend(string $str, string $string, string $encoding = null)
- * @method static string regexReplace(string $str, string $pattern, string $replacement, string $options = 'msr', string $encoding = null)
- * @method static string removeLeft(string $str, string $substring, string $encoding = null)
- * @method static string removeRight(string $str, string $substring, string $encoding = null)
- * @method static string repeat(string $str, int $multiplier, string $encoding = null)
- * @method static string replace(string $str, string $search, string $replacement, string $encoding = null)
- * @method static string reverse(string $str, string $encoding = null)
- * @method static string safeTruncate(string $str, int $length, string $substring = '', string $encoding = null)
- * @method static string shuffle(string $str, string $encoding = null)
- * @method static string slugify(string $str, string $replacement = '-', string $encoding = null)
- * @method static string slice(string $str, int $start, int $end = null, string $encoding = null)
- * @method static string split(string $str, string $pattern, int $limit = null, string $encoding = null)
- * @method static bool startsWith(string $str, string $substring, bool $caseSensitive = true, string $encoding = null)
- * @method static bool startsWithAny(string $str, string[] $substrings, bool $caseSensitive = true, string $encoding = null)
- * @method static string stripWhitespace(string $str, string $encoding = null)
- * @method static string substr(string $str, int $start, int $length = null, string $encoding = null)
- * @method static string surround(string $str, string $substring, string $encoding = null)
- * @method static string swapCase(string $str, string $encoding = null)
- * @method static string tidy(string $str, string $encoding = null)
- * @method static string titleize(string $str, string $encoding = null)
- * @method static string toAscii(string $str, string $language = 'en', bool $removeUnsupported = true, string $encoding = null)
- * @method static bool toBoolean(string $str, string $encoding = null)
- * @method static string toLowerCase(string $str, string $encoding = null)
- * @method static string toSpaces(string $str, int $tabLength = 4, string $encoding = null)
- * @method static string toTabs(string $str, int $tabLength = 4, string $encoding = null)
- * @method static string toTitleCase(string $str, string $encoding = null)
- * @method static string toUpperCase(string $str, string $encoding = null)
- * @method static string trim(string $str, string $chars = null, string $encoding = null)
- * @method static string trimLeft(string $str, string $chars = null, string $encoding = null)
- * @method static string trimRight(string $str, string $chars = null, string $encoding = null)
- * @method static string truncate(string $str, int $length, string $substring = '', string $encoding = null)
- * @method static string underscored(string $str, string $encoding = null)
- * @method static string upperCamelize(string $str, string $encoding = null)
- * @method static string upperCaseFirst(string $str, string $encoding = null)
- */
-class StaticStringy
-{
-    /**
-     * A mapping of method names to the numbers of arguments it accepts. Each
-     * should be two more than the equivalent Stringy method. Necessary as
-     * static methods place the optional $encoding as the last parameter.
-     *
-     * @var string[]
-     */
-    protected static $methodArgs = null;
-
-    /**
-     * Creates an instance of Stringy and invokes the given method with the
-     * rest of the passed arguments. The optional encoding is expected to be
-     * the last argument. For example, the following:
-     * StaticStringy::slice('fòôbàř', 0, 3, 'UTF-8'); translates to
-     * Stringy::create('fòôbàř', 'UTF-8')->slice(0, 3);
-     * The result is not cast, so the return value may be of type Stringy,
-     * integer, boolean, etc.
-     *
-     * @param string  $name
-     * @param mixed[] $arguments
-     *
-     * @return Stringy
-     *
-     * @throws \BadMethodCallException
-     */
-    public static function __callStatic($name, $arguments)
-    {
-        if (!static::$methodArgs) {
-            $stringyClass = new ReflectionClass('Stringy\Stringy');
-            $methods = $stringyClass->getMethods(ReflectionMethod::IS_PUBLIC);
-
-            foreach ($methods as $method) {
-                $params = $method->getNumberOfParameters() + 2;
-                static::$methodArgs[$method->name] = $params;
-            }
-        }
-
-        if (!isset(static::$methodArgs[$name])) {
-            throw new BadMethodCallException($name . ' is not a valid method');
-        }
-
-        $numArgs = count($arguments);
-        $str = ($numArgs) ? $arguments[0] : '';
-
-        if ($numArgs === static::$methodArgs[$name]) {
-            $args = array_slice($arguments, 1, -1);
-            $encoding = $arguments[$numArgs - 1];
-        } else {
-            $args = array_slice($arguments, 1);
-            $encoding = null;
-        }
-
-        $stringy = Stringy::create($str, $encoding);
-
-        $result = call_user_func_array([$stringy, $name], $args);
-
-        $cast = function($val) {
-            if (is_object($val) && $val instanceof Stringy) {
-                return (string) $val;
-            } else {
-                return $val;
-            }
-        };
-
-        return is_array($result) ? array_map($cast, $result) : $cast($result);
-    }
-}

+ 0 - 1986
vendor/danielstjules/stringy/src/Stringy.php

xqd
@@ -1,1986 +0,0 @@
-<?php
-
-namespace Stringy;
-
-use ArrayAccess;
-use ArrayIterator;
-use Countable;
-use Exception;
-use InvalidArgumentException;
-use IteratorAggregate;
-use OutOfBoundsException;
-
-class Stringy implements Countable, IteratorAggregate, ArrayAccess
-{
-    /**
-     * An instance's string.
-     *
-     * @var string
-     */
-    protected $str;
-
-    /**
-     * The string's encoding, which should be one of the mbstring module's
-     * supported encodings.
-     *
-     * @var string
-     */
-    protected $encoding;
-
-    /**
-     * Initializes a Stringy object and assigns both str and encoding properties
-     * the supplied values. $str is cast to a string prior to assignment, and if
-     * $encoding is not specified, it defaults to mb_internal_encoding(). Throws
-     * an InvalidArgumentException if the first argument is an array or object
-     * without a __toString method.
-     *
-     * @param  mixed  $str      Value to modify, after being cast to string
-     * @param  string $encoding The character encoding
-     * @throws \InvalidArgumentException if an array or object without a
-     *         __toString method is passed as the first argument
-     */
-    public function __construct($str = '', $encoding = null)
-    {
-        if (is_array($str)) {
-            throw new InvalidArgumentException(
-                'Passed value cannot be an array'
-            );
-        } elseif (is_object($str) && !method_exists($str, '__toString')) {
-            throw new InvalidArgumentException(
-                'Passed object must have a __toString method'
-            );
-        }
-
-        $this->str = (string) $str;
-        $this->encoding = $encoding ?: \mb_internal_encoding();
-    }
-
-    /**
-     * Creates a Stringy object and assigns both str and encoding properties
-     * the supplied values. $str is cast to a string prior to assignment, and if
-     * $encoding is not specified, it defaults to mb_internal_encoding(). It
-     * then returns the initialized object. Throws an InvalidArgumentException
-     * if the first argument is an array or object without a __toString method.
-     *
-     * @param  mixed  $str      Value to modify, after being cast to string
-     * @param  string $encoding The character encoding
-     * @return static A Stringy object
-     * @throws \InvalidArgumentException if an array or object without a
-     *         __toString method is passed as the first argument
-     */
-    public static function create($str = '', $encoding = null)
-    {
-        return new static($str, $encoding);
-    }
-
-    /**
-     * Returns the value in $str.
-     *
-     * @return string The current value of the $str property
-     */
-    public function __toString()
-    {
-        return $this->str;
-    }
-
-    /**
-     * Returns a new string with $string appended.
-     *
-     * @param  string $string The string to append
-     * @return static Object with appended $string
-     */
-    public function append($string)
-    {
-        return static::create($this->str . $string, $this->encoding);
-    }
-
-    /**
-     * Returns the character at $index, with indexes starting at 0.
-     *
-     * @param  int    $index Position of the character
-     * @return static The character at $index
-     */
-    public function at($index)
-    {
-        return $this->substr($index, 1);
-    }
-
-    /**
-     * Returns the substring between $start and $end, if found, or an empty
-     * string. An optional offset may be supplied from which to begin the
-     * search for the start string.
-     *
-     * @param  string $start  Delimiter marking the start of the substring
-     * @param  string $end    Delimiter marking the end of the substring
-     * @param  int    $offset Index from which to begin the search
-     * @return static Object whose $str is a substring between $start and $end
-     */
-    public function between($start, $end, $offset = 0)
-    {
-        $startIndex = $this->indexOf($start, $offset);
-        if ($startIndex === false) {
-            return static::create('', $this->encoding);
-        }
-
-        $substrIndex = $startIndex + \mb_strlen($start, $this->encoding);
-        $endIndex = $this->indexOf($end, $substrIndex);
-        if ($endIndex === false) {
-            return static::create('', $this->encoding);
-        }
-
-        return $this->substr($substrIndex, $endIndex - $substrIndex);
-    }
-
-    /**
-     * Returns a camelCase version of the string. Trims surrounding spaces,
-     * capitalizes letters following digits, spaces, dashes and underscores,
-     * and removes spaces, dashes, as well as underscores.
-     *
-     * @return static Object with $str in camelCase
-     */
-    public function camelize()
-    {
-        $encoding = $this->encoding;
-        $stringy = $this->trim()->lowerCaseFirst();
-        $stringy->str = preg_replace('/^[-_]+/', '', $stringy->str);
-
-        $stringy->str = preg_replace_callback(
-            '/[-_\s]+(.)?/u',
-            function ($match) use ($encoding) {
-                if (isset($match[1])) {
-                    return \mb_strtoupper($match[1], $encoding);
-                }
-
-                return '';
-            },
-            $stringy->str
-        );
-
-        $stringy->str = preg_replace_callback(
-            '/[\d]+(.)?/u',
-            function ($match) use ($encoding) {
-                return \mb_strtoupper($match[0], $encoding);
-            },
-            $stringy->str
-        );
-
-        return $stringy;
-    }
-
-    /**
-     * Returns an array consisting of the characters in the string.
-     *
-     * @return array An array of string chars
-     */
-    public function chars()
-    {
-        $chars = [];
-        for ($i = 0, $l = $this->length(); $i < $l; $i++) {
-            $chars[] = $this->at($i)->str;
-        }
-
-        return $chars;
-    }
-
-    /**
-     * Trims the string and replaces consecutive whitespace characters with a
-     * single space. This includes tabs and newline characters, as well as
-     * multibyte whitespace such as the thin space and ideographic space.
-     *
-     * @return static Object with a trimmed $str and condensed whitespace
-     */
-    public function collapseWhitespace()
-    {
-        return $this->regexReplace('[[:space:]]+', ' ')->trim();
-    }
-
-    /**
-     * Returns true if the string contains $needle, false otherwise. By default
-     * the comparison is case-sensitive, but can be made insensitive by setting
-     * $caseSensitive to false.
-     *
-     * @param  string $needle        Substring to look for
-     * @param  bool   $caseSensitive Whether or not to enforce case-sensitivity
-     * @return bool   Whether or not $str contains $needle
-     */
-    public function contains($needle, $caseSensitive = true)
-    {
-        $encoding = $this->encoding;
-
-        if ($caseSensitive) {
-            return (\mb_strpos($this->str, $needle, 0, $encoding) !== false);
-        }
-
-        return (\mb_stripos($this->str, $needle, 0, $encoding) !== false);
-    }
-
-    /**
-     * Returns true if the string contains all $needles, false otherwise. By
-     * default the comparison is case-sensitive, but can be made insensitive by
-     * setting $caseSensitive to false.
-     *
-     * @param  string[] $needles       Substrings to look for
-     * @param  bool     $caseSensitive Whether or not to enforce case-sensitivity
-     * @return bool     Whether or not $str contains $needle
-     */
-    public function containsAll($needles, $caseSensitive = true)
-    {
-        if (empty($needles)) {
-            return false;
-        }
-
-        foreach ($needles as $needle) {
-            if (!$this->contains($needle, $caseSensitive)) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Returns true if the string contains any $needles, false otherwise. By
-     * default the comparison is case-sensitive, but can be made insensitive by
-     * setting $caseSensitive to false.
-     *
-     * @param  string[] $needles       Substrings to look for
-     * @param  bool     $caseSensitive Whether or not to enforce case-sensitivity
-     * @return bool     Whether or not $str contains $needle
-     */
-    public function containsAny($needles, $caseSensitive = true)
-    {
-        if (empty($needles)) {
-            return false;
-        }
-
-        foreach ($needles as $needle) {
-            if ($this->contains($needle, $caseSensitive)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the length of the string, implementing the countable interface.
-     *
-     * @return int The number of characters in the string, given the encoding
-     */
-    public function count()
-    {
-        return $this->length();
-    }
-
-    /**
-     * Returns the number of occurrences of $substring in the given string.
-     * By default, the comparison is case-sensitive, but can be made insensitive
-     * by setting $caseSensitive to false.
-     *
-     * @param  string $substring     The substring to search for
-     * @param  bool   $caseSensitive Whether or not to enforce case-sensitivity
-     * @return int    The number of $substring occurrences
-     */
-    public function countSubstr($substring, $caseSensitive = true)
-    {
-        if ($caseSensitive) {
-            return \mb_substr_count($this->str, $substring, $this->encoding);
-        }
-
-        $str = \mb_strtoupper($this->str, $this->encoding);
-        $substring = \mb_strtoupper($substring, $this->encoding);
-
-        return \mb_substr_count($str, $substring, $this->encoding);
-    }
-
-    /**
-     * Returns a lowercase and trimmed string separated by dashes. Dashes are
-     * inserted before uppercase characters (with the exception of the first
-     * character of the string), and in place of spaces as well as underscores.
-     *
-     * @return static Object with a dasherized $str
-     */
-    public function dasherize()
-    {
-        return $this->delimit('-');
-    }
-
-    /**
-     * Returns a lowercase and trimmed string separated by the given delimiter.
-     * Delimiters are inserted before uppercase characters (with the exception
-     * of the first character of the string), and in place of spaces, dashes,
-     * and underscores. Alpha delimiters are not converted to lowercase.
-     *
-     * @param  string $delimiter Sequence used to separate parts of the string
-     * @return static Object with a delimited $str
-     */
-    public function delimit($delimiter)
-    {
-        $regexEncoding = $this->regexEncoding();
-        $this->regexEncoding($this->encoding);
-
-        $str = $this->eregReplace('\B([A-Z])', '-\1', $this->trim());
-        $str = \mb_strtolower($str, $this->encoding);
-        $str = $this->eregReplace('[-_\s]+', $delimiter, $str);
-
-        $this->regexEncoding($regexEncoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns true if the string ends with $substring, false otherwise. By
-     * default, the comparison is case-sensitive, but can be made insensitive
-     * by setting $caseSensitive to false.
-     *
-     * @param  string $substring     The substring to look for
-     * @param  bool   $caseSensitive Whether or not to enforce case-sensitivity
-     * @return bool   Whether or not $str ends with $substring
-     */
-    public function endsWith($substring, $caseSensitive = true)
-    {
-        $substringLength = \mb_strlen($substring, $this->encoding);
-        $strLength = $this->length();
-
-        $endOfStr = \mb_substr($this->str, $strLength - $substringLength,
-            $substringLength, $this->encoding);
-
-        if (!$caseSensitive) {
-            $substring = \mb_strtolower($substring, $this->encoding);
-            $endOfStr = \mb_strtolower($endOfStr, $this->encoding);
-        }
-
-        return (string) $substring === $endOfStr;
-    }
-
-    /**
-     * Returns true if the string ends with any of $substrings, false otherwise.
-     * By default, the comparison is case-sensitive, but can be made insensitive
-     * by setting $caseSensitive to false.
-     *
-     * @param  string[] $substrings    Substrings to look for
-     * @param  bool     $caseSensitive Whether or not to enforce
-     *                                 case-sensitivity
-     * @return bool     Whether or not $str ends with $substring
-     */
-    public function endsWithAny($substrings, $caseSensitive = true)
-    {
-        if (empty($substrings)) {
-            return false;
-        }
-
-        foreach ($substrings as $substring) {
-            if ($this->endsWith($substring, $caseSensitive)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Ensures that the string begins with $substring. If it doesn't, it's
-     * prepended.
-     *
-     * @param  string $substring The substring to add if not present
-     * @return static Object with its $str prefixed by the $substring
-     */
-    public function ensureLeft($substring)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if (!$stringy->startsWith($substring)) {
-            $stringy->str = $substring . $stringy->str;
-        }
-
-        return $stringy;
-    }
-
-    /**
-     * Ensures that the string ends with $substring. If it doesn't, it's
-     * appended.
-     *
-     * @param  string $substring The substring to add if not present
-     * @return static Object with its $str suffixed by the $substring
-     */
-    public function ensureRight($substring)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if (!$stringy->endsWith($substring)) {
-            $stringy->str .= $substring;
-        }
-
-        return $stringy;
-    }
-
-    /**
-     * Returns the first $n characters of the string.
-     *
-     * @param  int    $n Number of characters to retrieve from the start
-     * @return static Object with its $str being the first $n chars
-     */
-    public function first($n)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if ($n < 0) {
-            $stringy->str = '';
-            return $stringy;
-        }
-
-        return $stringy->substr(0, $n);
-    }
-
-    /**
-     * Returns the encoding used by the Stringy object.
-     *
-     * @return string The current value of the $encoding property
-     */
-    public function getEncoding()
-    {
-        return $this->encoding;
-    }
-
-    /**
-     * Returns a new ArrayIterator, thus implementing the IteratorAggregate
-     * interface. The ArrayIterator's constructor is passed an array of chars
-     * in the multibyte string. This enables the use of foreach with instances
-     * of Stringy\Stringy.
-     *
-     * @return \ArrayIterator An iterator for the characters in the string
-     */
-    public function getIterator()
-    {
-        return new ArrayIterator($this->chars());
-    }
-
-    /**
-     * Returns true if the string contains a lower case char, false
-     * otherwise.
-     *
-     * @return bool Whether or not the string contains a lower case character.
-     */
-    public function hasLowerCase()
-    {
-        return $this->matchesPattern('.*[[:lower:]]');
-    }
-
-    /**
-     * Returns true if the string contains an upper case char, false
-     * otherwise.
-     *
-     * @return bool Whether or not the string contains an upper case character.
-     */
-    public function hasUpperCase()
-    {
-        return $this->matchesPattern('.*[[:upper:]]');
-    }
-
-
-    /**
-     * Convert all HTML entities to their applicable characters. An alias of
-     * html_entity_decode. For a list of flags, refer to
-     * http://php.net/manual/en/function.html-entity-decode.php
-     *
-     * @param  int|null $flags Optional flags
-     * @return static   Object with the resulting $str after being html decoded.
-     */
-    public function htmlDecode($flags = ENT_COMPAT)
-    {
-        $str = html_entity_decode($this->str, $flags, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Convert all applicable characters to HTML entities. An alias of
-     * htmlentities. Refer to http://php.net/manual/en/function.htmlentities.php
-     * for a list of flags.
-     *
-     * @param  int|null $flags Optional flags
-     * @return static   Object with the resulting $str after being html encoded.
-     */
-    public function htmlEncode($flags = ENT_COMPAT)
-    {
-        $str = htmlentities($this->str, $flags, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Capitalizes the first word of the string, replaces underscores with
-     * spaces, and strips '_id'.
-     *
-     * @return static Object with a humanized $str
-     */
-    public function humanize()
-    {
-        $str = str_replace(['_id', '_'], ['', ' '], $this->str);
-
-        return static::create($str, $this->encoding)->trim()->upperCaseFirst();
-    }
-
-    /**
-     * Returns the index of the first occurrence of $needle in the string,
-     * and false if not found. Accepts an optional offset from which to begin
-     * the search.
-     *
-     * @param  string   $needle Substring to look for
-     * @param  int      $offset Offset from which to search
-     * @return int|bool The occurrence's index if found, otherwise false
-     */
-    public function indexOf($needle, $offset = 0)
-    {
-        return \mb_strpos($this->str, (string) $needle,
-            (int) $offset, $this->encoding);
-    }
-
-    /**
-     * Returns the index of the last occurrence of $needle in the string,
-     * and false if not found. Accepts an optional offset from which to begin
-     * the search. Offsets may be negative to count from the last character
-     * in the string.
-     *
-     * @param  string   $needle Substring to look for
-     * @param  int      $offset Offset from which to search
-     * @return int|bool The last occurrence's index if found, otherwise false
-     */
-    public function indexOfLast($needle, $offset = 0)
-    {
-        return \mb_strrpos($this->str, (string) $needle,
-            (int) $offset, $this->encoding);
-    }
-
-    /**
-     * Inserts $substring into the string at the $index provided.
-     *
-     * @param  string $substring String to be inserted
-     * @param  int    $index     The index at which to insert the substring
-     * @return static Object with the resulting $str after the insertion
-     */
-    public function insert($substring, $index)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-        if ($index > $stringy->length()) {
-            return $stringy;
-        }
-
-        $start = \mb_substr($stringy->str, 0, $index, $stringy->encoding);
-        $end = \mb_substr($stringy->str, $index, $stringy->length(),
-            $stringy->encoding);
-
-        $stringy->str = $start . $substring . $end;
-
-        return $stringy;
-    }
-
-    /**
-     * Returns true if the string contains only alphabetic chars, false
-     * otherwise.
-     *
-     * @return bool Whether or not $str contains only alphabetic chars
-     */
-    public function isAlpha()
-    {
-        return $this->matchesPattern('^[[:alpha:]]*$');
-    }
-
-    /**
-     * Returns true if the string contains only alphabetic and numeric chars,
-     * false otherwise.
-     *
-     * @return bool Whether or not $str contains only alphanumeric chars
-     */
-    public function isAlphanumeric()
-    {
-        return $this->matchesPattern('^[[:alnum:]]*$');
-    }
-
-    /**
-     * Returns true if the string contains only whitespace chars, false
-     * otherwise.
-     *
-     * @return bool Whether or not $str contains only whitespace characters
-     */
-    public function isBlank()
-    {
-        return $this->matchesPattern('^[[:space:]]*$');
-    }
-
-    /**
-     * Returns true if the string contains only hexadecimal chars, false
-     * otherwise.
-     *
-     * @return bool Whether or not $str contains only hexadecimal chars
-     */
-    public function isHexadecimal()
-    {
-        return $this->matchesPattern('^[[:xdigit:]]*$');
-    }
-
-    /**
-     * Returns true if the string is JSON, false otherwise. Unlike json_decode
-     * in PHP 5.x, this method is consistent with PHP 7 and other JSON parsers,
-     * in that an empty string is not considered valid JSON.
-     *
-     * @return bool Whether or not $str is JSON
-     */
-    public function isJson()
-    {
-        if (!$this->length()) {
-            return false;
-        }
-
-        json_decode($this->str);
-
-        return (json_last_error() === JSON_ERROR_NONE);
-    }
-
-    /**
-     * Returns true if the string contains only lower case chars, false
-     * otherwise.
-     *
-     * @return bool Whether or not $str contains only lower case characters
-     */
-    public function isLowerCase()
-    {
-        return $this->matchesPattern('^[[:lower:]]*$');
-    }
-
-    /**
-     * Returns true if the string is serialized, false otherwise.
-     *
-     * @return bool Whether or not $str is serialized
-     */
-    public function isSerialized()
-    {
-        return $this->str === 'b:0;' || @unserialize($this->str) !== false;
-    }
-
-
-    /**
-     * Returns true if the string is base64 encoded, false otherwise.
-     *
-     * @return bool Whether or not $str is base64 encoded
-     */
-    public function isBase64()
-    {
-        return (base64_encode(base64_decode($this->str, true)) === $this->str);
-    }
-
-    /**
-     * Returns true if the string contains only lower case chars, false
-     * otherwise.
-     *
-     * @return bool Whether or not $str contains only lower case characters
-     */
-    public function isUpperCase()
-    {
-        return $this->matchesPattern('^[[:upper:]]*$');
-    }
-
-    /**
-     * Returns the last $n characters of the string.
-     *
-     * @param  int    $n Number of characters to retrieve from the end
-     * @return static Object with its $str being the last $n chars
-     */
-    public function last($n)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if ($n <= 0) {
-            $stringy->str = '';
-            return $stringy;
-        }
-
-        return $stringy->substr(-$n);
-    }
-
-    /**
-     * Returns the length of the string. An alias for PHP's mb_strlen() function.
-     *
-     * @return int The number of characters in $str given the encoding
-     */
-    public function length()
-    {
-        return \mb_strlen($this->str, $this->encoding);
-    }
-
-    /**
-     * Splits on newlines and carriage returns, returning an array of Stringy
-     * objects corresponding to the lines in the string.
-     *
-     * @return static[] An array of Stringy objects
-     */
-    public function lines()
-    {
-        $array = $this->split('[\r\n]{1,2}', $this->str);
-        for ($i = 0; $i < count($array); $i++) {
-            $array[$i] = static::create($array[$i], $this->encoding);
-        }
-
-        return $array;
-    }
-
-    /**
-     * Returns the longest common prefix between the string and $otherStr.
-     *
-     * @param  string $otherStr Second string for comparison
-     * @return static Object with its $str being the longest common prefix
-     */
-    public function longestCommonPrefix($otherStr)
-    {
-        $encoding = $this->encoding;
-        $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding));
-
-        $longestCommonPrefix = '';
-        for ($i = 0; $i < $maxLength; $i++) {
-            $char = \mb_substr($this->str, $i, 1, $encoding);
-
-            if ($char == \mb_substr($otherStr, $i, 1, $encoding)) {
-                $longestCommonPrefix .= $char;
-            } else {
-                break;
-            }
-        }
-
-        return static::create($longestCommonPrefix, $encoding);
-    }
-
-    /**
-     * Returns the longest common suffix between the string and $otherStr.
-     *
-     * @param  string $otherStr Second string for comparison
-     * @return static Object with its $str being the longest common suffix
-     */
-    public function longestCommonSuffix($otherStr)
-    {
-        $encoding = $this->encoding;
-        $maxLength = min($this->length(), \mb_strlen($otherStr, $encoding));
-
-        $longestCommonSuffix = '';
-        for ($i = 1; $i <= $maxLength; $i++) {
-            $char = \mb_substr($this->str, -$i, 1, $encoding);
-
-            if ($char == \mb_substr($otherStr, -$i, 1, $encoding)) {
-                $longestCommonSuffix = $char . $longestCommonSuffix;
-            } else {
-                break;
-            }
-        }
-
-        return static::create($longestCommonSuffix, $encoding);
-    }
-
-    /**
-     * Returns the longest common substring between the string and $otherStr.
-     * In the case of ties, it returns that which occurs first.
-     *
-     * @param  string $otherStr Second string for comparison
-     * @return static Object with its $str being the longest common substring
-     */
-    public function longestCommonSubstring($otherStr)
-    {
-        // Uses dynamic programming to solve
-        // http://en.wikipedia.org/wiki/Longest_common_substring_problem
-        $encoding = $this->encoding;
-        $stringy = static::create($this->str, $encoding);
-        $strLength = $stringy->length();
-        $otherLength = \mb_strlen($otherStr, $encoding);
-
-        // Return if either string is empty
-        if ($strLength == 0 || $otherLength == 0) {
-            $stringy->str = '';
-            return $stringy;
-        }
-
-        $len = 0;
-        $end = 0;
-        $table = array_fill(0, $strLength + 1,
-            array_fill(0, $otherLength + 1, 0));
-
-        for ($i = 1; $i <= $strLength; $i++) {
-            for ($j = 1; $j <= $otherLength; $j++) {
-                $strChar = \mb_substr($stringy->str, $i - 1, 1, $encoding);
-                $otherChar = \mb_substr($otherStr, $j - 1, 1, $encoding);
-
-                if ($strChar == $otherChar) {
-                    $table[$i][$j] = $table[$i - 1][$j - 1] + 1;
-                    if ($table[$i][$j] > $len) {
-                        $len = $table[$i][$j];
-                        $end = $i;
-                    }
-                } else {
-                    $table[$i][$j] = 0;
-                }
-            }
-        }
-
-        $stringy->str = \mb_substr($stringy->str, $end - $len, $len, $encoding);
-
-        return $stringy;
-    }
-
-    /**
-     * Converts the first character of the string to lower case.
-     *
-     * @return static Object with the first character of $str being lower case
-     */
-    public function lowerCaseFirst()
-    {
-        $first = \mb_substr($this->str, 0, 1, $this->encoding);
-        $rest = \mb_substr($this->str, 1, $this->length() - 1,
-            $this->encoding);
-
-        $str = \mb_strtolower($first, $this->encoding) . $rest;
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns whether or not a character exists at an index. Offsets may be
-     * negative to count from the last character in the string. Implements
-     * part of the ArrayAccess interface.
-     *
-     * @param  mixed   $offset The index to check
-     * @return boolean Whether or not the index exists
-     */
-    public function offsetExists($offset)
-    {
-        $length = $this->length();
-        $offset = (int) $offset;
-
-        if ($offset >= 0) {
-            return ($length > $offset);
-        }
-
-        return ($length >= abs($offset));
-    }
-
-    /**
-     * Returns the character at the given index. Offsets may be negative to
-     * count from the last character in the string. Implements part of the
-     * ArrayAccess interface, and throws an OutOfBoundsException if the index
-     * does not exist.
-     *
-     * @param  mixed $offset         The index from which to retrieve the char
-     * @return mixed                 The character at the specified index
-     * @throws \OutOfBoundsException If the positive or negative offset does
-     *                               not exist
-     */
-    public function offsetGet($offset)
-    {
-        $offset = (int) $offset;
-        $length = $this->length();
-
-        if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) {
-            throw new OutOfBoundsException('No character exists at the index');
-        }
-
-        return \mb_substr($this->str, $offset, 1, $this->encoding);
-    }
-
-    /**
-     * Implements part of the ArrayAccess interface, but throws an exception
-     * when called. This maintains the immutability of Stringy objects.
-     *
-     * @param  mixed      $offset The index of the character
-     * @param  mixed      $value  Value to set
-     * @throws \Exception When called
-     */
-    public function offsetSet($offset, $value)
-    {
-        // Stringy is immutable, cannot directly set char
-        throw new Exception('Stringy object is immutable, cannot modify char');
-    }
-
-    /**
-     * Implements part of the ArrayAccess interface, but throws an exception
-     * when called. This maintains the immutability of Stringy objects.
-     *
-     * @param  mixed      $offset The index of the character
-     * @throws \Exception When called
-     */
-    public function offsetUnset($offset)
-    {
-        // Don't allow directly modifying the string
-        throw new Exception('Stringy object is immutable, cannot unset char');
-    }
-
-    /**
-     * Pads the string to a given length with $padStr. If length is less than
-     * or equal to the length of the string, no padding takes places. The
-     * default string used for padding is a space, and the default type (one of
-     * 'left', 'right', 'both') is 'right'. Throws an InvalidArgumentException
-     * if $padType isn't one of those 3 values.
-     *
-     * @param  int    $length  Desired string length after padding
-     * @param  string $padStr  String used to pad, defaults to space
-     * @param  string $padType One of 'left', 'right', 'both'
-     * @return static Object with a padded $str
-     * @throws /InvalidArgumentException If $padType isn't one of 'right',
-     *         'left' or 'both'
-     */
-    public function pad($length, $padStr = ' ', $padType = 'right')
-    {
-        if (!in_array($padType, ['left', 'right', 'both'])) {
-            throw new InvalidArgumentException('Pad expects $padType ' .
-                "to be one of 'left', 'right' or 'both'");
-        }
-
-        switch ($padType) {
-            case 'left':
-                return $this->padLeft($length, $padStr);
-            case 'right':
-                return $this->padRight($length, $padStr);
-            default:
-                return $this->padBoth($length, $padStr);
-        }
-    }
-
-    /**
-     * Returns a new string of a given length such that both sides of the
-     * string are padded. Alias for pad() with a $padType of 'both'.
-     *
-     * @param  int    $length Desired string length after padding
-     * @param  string $padStr String used to pad, defaults to space
-     * @return static String with padding applied
-     */
-    public function padBoth($length, $padStr = ' ')
-    {
-        $padding = $length - $this->length();
-
-        return $this->applyPadding(floor($padding / 2), ceil($padding / 2),
-            $padStr);
-    }
-
-    /**
-     * Returns a new string of a given length such that the beginning of the
-     * string is padded. Alias for pad() with a $padType of 'left'.
-     *
-     * @param  int    $length Desired string length after padding
-     * @param  string $padStr String used to pad, defaults to space
-     * @return static String with left padding
-     */
-    public function padLeft($length, $padStr = ' ')
-    {
-        return $this->applyPadding($length - $this->length(), 0, $padStr);
-    }
-
-    /**
-     * Returns a new string of a given length such that the end of the string
-     * is padded. Alias for pad() with a $padType of 'right'.
-     *
-     * @param  int    $length Desired string length after padding
-     * @param  string $padStr String used to pad, defaults to space
-     * @return static String with right padding
-     */
-    public function padRight($length, $padStr = ' ')
-    {
-        return $this->applyPadding(0, $length - $this->length(), $padStr);
-    }
-
-    /**
-     * Returns a new string starting with $string.
-     *
-     * @param  string $string The string to append
-     * @return static Object with appended $string
-     */
-    public function prepend($string)
-    {
-        return static::create($string . $this->str, $this->encoding);
-    }
-
-    /**
-     * Replaces all occurrences of $pattern in $str by $replacement. An alias
-     * for mb_ereg_replace(). Note that the 'i' option with multibyte patterns
-     * in mb_ereg_replace() requires PHP 5.6+ for correct results. This is due
-     * to a lack of support in the bundled version of Oniguruma in PHP < 5.6,
-     * and current versions of HHVM (3.8 and below).
-     *
-     * @param  string $pattern     The regular expression pattern
-     * @param  string $replacement The string to replace with
-     * @param  string $options     Matching conditions to be used
-     * @return static Object with the resulting $str after the replacements
-     */
-    public function regexReplace($pattern, $replacement, $options = 'msr')
-    {
-        $regexEncoding = $this->regexEncoding();
-        $this->regexEncoding($this->encoding);
-
-        $str = $this->eregReplace($pattern, $replacement, $this->str, $options);
-        $this->regexEncoding($regexEncoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns a new string with the prefix $substring removed, if present.
-     *
-     * @param  string $substring The prefix to remove
-     * @return static Object having a $str without the prefix $substring
-     */
-    public function removeLeft($substring)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if ($stringy->startsWith($substring)) {
-            $substringLength = \mb_strlen($substring, $stringy->encoding);
-            return $stringy->substr($substringLength);
-        }
-
-        return $stringy;
-    }
-
-    /**
-     * Returns a new string with the suffix $substring removed, if present.
-     *
-     * @param  string $substring The suffix to remove
-     * @return static Object having a $str without the suffix $substring
-     */
-    public function removeRight($substring)
-    {
-        $stringy = static::create($this->str, $this->encoding);
-
-        if ($stringy->endsWith($substring)) {
-            $substringLength = \mb_strlen($substring, $stringy->encoding);
-            return $stringy->substr(0, $stringy->length() - $substringLength);
-        }
-
-        return $stringy;
-    }
-
-    /**
-     * Returns a repeated string given a multiplier. An alias for str_repeat.
-     *
-     * @param  int    $multiplier The number of times to repeat the string
-     * @return static Object with a repeated str
-     */
-    public function repeat($multiplier)
-    {
-        $repeated = str_repeat($this->str, $multiplier);
-
-        return static::create($repeated, $this->encoding);
-    }
-
-    /**
-     * Replaces all occurrences of $search in $str by $replacement.
-     *
-     * @param  string $search      The needle to search for
-     * @param  string $replacement The string to replace with
-     * @return static Object with the resulting $str after the replacements
-     */
-    public function replace($search, $replacement)
-    {
-        return $this->regexReplace(preg_quote($search), $replacement);
-    }
-
-    /**
-     * Returns a reversed string. A multibyte version of strrev().
-     *
-     * @return static Object with a reversed $str
-     */
-    public function reverse()
-    {
-        $strLength = $this->length();
-        $reversed = '';
-
-        // Loop from last index of string to first
-        for ($i = $strLength - 1; $i >= 0; $i--) {
-            $reversed .= \mb_substr($this->str, $i, 1, $this->encoding);
-        }
-
-        return static::create($reversed, $this->encoding);
-    }
-
-    /**
-     * Truncates the string to a given length, while ensuring that it does not
-     * split words. If $substring is provided, and truncating occurs, the
-     * string is further truncated so that the substring may be appended without
-     * exceeding the desired length.
-     *
-     * @param  int    $length    Desired length of the truncated string
-     * @param  string $substring The substring to append if it can fit
-     * @return static Object with the resulting $str after truncating
-     */
-    public function safeTruncate($length, $substring = '')
-    {
-        $stringy = static::create($this->str, $this->encoding);
-        if ($length >= $stringy->length()) {
-            return $stringy;
-        }
-
-        // Need to further trim the string so we can append the substring
-        $encoding = $stringy->encoding;
-        $substringLength = \mb_strlen($substring, $encoding);
-        $length = $length - $substringLength;
-
-        $truncated = \mb_substr($stringy->str, 0, $length, $encoding);
-
-        // If the last word was truncated
-        if (mb_strpos($stringy->str, ' ', $length - 1, $encoding) != $length) {
-            // Find pos of the last occurrence of a space, get up to that
-            $lastPos = \mb_strrpos($truncated, ' ', 0, $encoding);
-            if ($lastPos !== false) {
-                $truncated = \mb_substr($truncated, 0, $lastPos, $encoding);
-            }
-        }
-
-        $stringy->str = $truncated . $substring;
-
-        return $stringy;
-    }
-
-    /*
-     * A multibyte str_shuffle() function. It returns a string with its
-     * characters in random order.
-     *
-     * @return static Object with a shuffled $str
-     */
-    public function shuffle()
-    {
-        $indexes = range(0, $this->length() - 1);
-        shuffle($indexes);
-
-        $shuffledStr = '';
-        foreach ($indexes as $i) {
-            $shuffledStr .= \mb_substr($this->str, $i, 1, $this->encoding);
-        }
-
-        return static::create($shuffledStr, $this->encoding);
-    }
-
-    /**
-     * Converts the string into an URL slug. This includes replacing non-ASCII
-     * characters with their closest ASCII equivalents, removing remaining
-     * non-ASCII and non-alphanumeric characters, and replacing whitespace with
-     * $replacement. The replacement defaults to a single dash, and the string
-     * is also converted to lowercase. The language of the source string can
-     * also be supplied for language-specific transliteration.
-     *
-     * @param  string $replacement The string used to replace whitespace
-     * @param  string $language    Language of the source string
-     * @return static Object whose $str has been converted to an URL slug
-     */
-    public function slugify($replacement = '-', $language = 'en')
-    {
-        $stringy = $this->toAscii($language);
-
-        $stringy->str = str_replace('@', $replacement, $stringy);
-        $quotedReplacement = preg_quote($replacement);
-        $pattern = "/[^a-zA-Z\d\s-_$quotedReplacement]/u";
-        $stringy->str = preg_replace($pattern, '', $stringy);
-
-        return $stringy->toLowerCase()->delimit($replacement)
-                       ->removeLeft($replacement)->removeRight($replacement);
-    }
-
-    /**
-     * Returns true if the string begins with $substring, false otherwise. By
-     * default, the comparison is case-sensitive, but can be made insensitive
-     * by setting $caseSensitive to false.
-     *
-     * @param  string $substring     The substring to look for
-     * @param  bool   $caseSensitive Whether or not to enforce
-     *                               case-sensitivity
-     * @return bool   Whether or not $str starts with $substring
-     */
-    public function startsWith($substring, $caseSensitive = true)
-    {
-        $substringLength = \mb_strlen($substring, $this->encoding);
-        $startOfStr = \mb_substr($this->str, 0, $substringLength,
-            $this->encoding);
-
-        if (!$caseSensitive) {
-            $substring = \mb_strtolower($substring, $this->encoding);
-            $startOfStr = \mb_strtolower($startOfStr, $this->encoding);
-        }
-
-        return (string) $substring === $startOfStr;
-    }
-
-    /**
-     * Returns true if the string begins with any of $substrings, false
-     * otherwise. By default the comparison is case-sensitive, but can be made
-     * insensitive by setting $caseSensitive to false.
-     *
-     * @param  string[] $substrings    Substrings to look for
-     * @param  bool     $caseSensitive Whether or not to enforce
-     *                                 case-sensitivity
-     * @return bool     Whether or not $str starts with $substring
-     */
-    public function startsWithAny($substrings, $caseSensitive = true)
-    {
-        if (empty($substrings)) {
-            return false;
-        }
-
-        foreach ($substrings as $substring) {
-            if ($this->startsWith($substring, $caseSensitive)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the substring beginning at $start, and up to, but not including
-     * the index specified by $end. If $end is omitted, the function extracts
-     * the remaining string. If $end is negative, it is computed from the end
-     * of the string.
-     *
-     * @param  int    $start Initial index from which to begin extraction
-     * @param  int    $end   Optional index at which to end extraction
-     * @return static Object with its $str being the extracted substring
-     */
-    public function slice($start, $end = null)
-    {
-        if ($end === null) {
-            $length = $this->length();
-        } elseif ($end >= 0 && $end <= $start) {
-            return static::create('', $this->encoding);
-        } elseif ($end < 0) {
-            $length = $this->length() + $end - $start;
-        } else {
-            $length = $end - $start;
-        }
-
-        return $this->substr($start, $length);
-    }
-
-    /**
-     * Splits the string with the provided regular expression, returning an
-     * array of Stringy objects. An optional integer $limit will truncate the
-     * results.
-     *
-     * @param  string   $pattern The regex with which to split the string
-     * @param  int      $limit   Optional maximum number of results to return
-     * @return static[] An array of Stringy objects
-     */
-    public function split($pattern, $limit = null)
-    {
-        if ($limit === 0) {
-            return [];
-        }
-
-        // mb_split errors when supplied an empty pattern in < PHP 5.4.13
-        // and HHVM < 3.8
-        if ($pattern === '') {
-            return [static::create($this->str, $this->encoding)];
-        }
-
-        $regexEncoding = $this->regexEncoding();
-        $this->regexEncoding($this->encoding);
-
-        // mb_split returns the remaining unsplit string in the last index when
-        // supplying a limit
-        $limit = ($limit > 0) ? $limit += 1 : -1;
-
-        static $functionExists;
-        if ($functionExists === null) {
-            $functionExists = function_exists('\mb_split');
-        }
-
-        if ($functionExists) {
-            $array = \mb_split($pattern, $this->str, $limit);
-        } else if ($this->supportsEncoding()) {
-            $array = \preg_split("/$pattern/", $this->str, $limit);
-        }
-
-        $this->regexEncoding($regexEncoding);
-
-        if ($limit > 0 && count($array) === $limit) {
-            array_pop($array);
-        }
-
-        for ($i = 0; $i < count($array); $i++) {
-            $array[$i] = static::create($array[$i], $this->encoding);
-        }
-
-        return $array;
-    }
-
-    /**
-     * Strip all whitespace characters. This includes tabs and newline
-     * characters, as well as multibyte whitespace such as the thin space
-     * and ideographic space.
-     *
-     * @return static Object with whitespace stripped
-     */
-    public function stripWhitespace()
-    {
-        return $this->regexReplace('[[:space:]]+', '');
-    }
-
-    /**
-     * Returns the substring beginning at $start with the specified $length.
-     * It differs from the mb_substr() function in that providing a $length of
-     * null will return the rest of the string, rather than an empty string.
-     *
-     * @param  int    $start  Position of the first character to use
-     * @param  int    $length Maximum number of characters used
-     * @return static Object with its $str being the substring
-     */
-    public function substr($start, $length = null)
-    {
-        $length = $length === null ? $this->length() : $length;
-        $str = \mb_substr($this->str, $start, $length, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Surrounds $str with the given substring.
-     *
-     * @param  string $substring The substring to add to both sides
-     * @return static Object whose $str had the substring both prepended and
-     *                 appended
-     */
-    public function surround($substring)
-    {
-        $str = implode('', [$substring, $this->str, $substring]);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns a case swapped version of the string.
-     *
-     * @return static Object whose $str has each character's case swapped
-     */
-    public function swapCase()
-    {
-        $stringy = static::create($this->str, $this->encoding);
-        $encoding = $stringy->encoding;
-
-        $stringy->str = preg_replace_callback(
-            '/[\S]/u',
-            function ($match) use ($encoding) {
-                if ($match[0] == \mb_strtoupper($match[0], $encoding)) {
-                    return \mb_strtolower($match[0], $encoding);
-                }
-
-                return \mb_strtoupper($match[0], $encoding);
-            },
-            $stringy->str
-        );
-
-        return $stringy;
-    }
-
-    /**
-     * Returns a string with smart quotes, ellipsis characters, and dashes from
-     * Windows-1252 (commonly used in Word documents) replaced by their ASCII
-     * equivalents.
-     *
-     * @return static Object whose $str has those characters removed
-     */
-    public function tidy()
-    {
-        $str = preg_replace([
-            '/\x{2026}/u',
-            '/[\x{201C}\x{201D}]/u',
-            '/[\x{2018}\x{2019}]/u',
-            '/[\x{2013}\x{2014}]/u',
-        ], [
-            '...',
-            '"',
-            "'",
-            '-',
-        ], $this->str);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns a trimmed string with the first letter of each word capitalized.
-     * Also accepts an array, $ignore, allowing you to list words not to be
-     * capitalized.
-     *
-     * @param  array  $ignore An array of words not to capitalize
-     * @return static Object with a titleized $str
-     */
-    public function titleize($ignore = null)
-    {
-        $stringy = static::create($this->trim(), $this->encoding);
-        $encoding = $this->encoding;
-
-        $stringy->str = preg_replace_callback(
-            '/([\S]+)/u',
-            function ($match) use ($encoding, $ignore) {
-                if ($ignore && in_array($match[0], $ignore)) {
-                    return $match[0];
-                }
-
-                $stringy = new Stringy($match[0], $encoding);
-
-                return (string) $stringy->toLowerCase()->upperCaseFirst();
-            },
-            $stringy->str
-        );
-
-        return $stringy;
-    }
-
-    /**
-     * Returns an ASCII version of the string. A set of non-ASCII characters are
-     * replaced with their closest ASCII counterparts, and the rest are removed
-     * by default. The language or locale of the source string can be supplied
-     * for language-specific transliteration in any of the following formats:
-     * en, en_GB, or en-GB. For example, passing "de" results in "äöü" mapping
-     * to "aeoeue" rather than "aou" as in other languages.
-     *
-     * @param  string $language          Language of the source string
-     * @param  bool   $removeUnsupported Whether or not to remove the
-     *                                    unsupported characters
-     * @return static Object whose $str contains only ASCII characters
-     */
-    public function toAscii($language = 'en', $removeUnsupported = true)
-    {
-        $str = $this->str;
-
-        $langSpecific = $this->langSpecificCharsArray($language);
-        if (!empty($langSpecific)) {
-            $str = str_replace($langSpecific[0], $langSpecific[1], $str);
-        }
-
-        foreach ($this->charsArray() as $key => $value) {
-            $str = str_replace($value, $key, $str);
-        }
-
-        if ($removeUnsupported) {
-            $str = preg_replace('/[^\x20-\x7E]/u', '', $str);
-        }
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns a boolean representation of the given logical string value.
-     * For example, 'true', '1', 'on' and 'yes' will return true. 'false', '0',
-     * 'off', and 'no' will return false. In all instances, case is ignored.
-     * For other numeric strings, their sign will determine the return value.
-     * In addition, blank strings consisting of only whitespace will return
-     * false. For all other strings, the return value is a result of a
-     * boolean cast.
-     *
-     * @return bool A boolean value for the string
-     */
-    public function toBoolean()
-    {
-        $key = $this->toLowerCase()->str;
-        $map = [
-            'true'  => true,
-            '1'     => true,
-            'on'    => true,
-            'yes'   => true,
-            'false' => false,
-            '0'     => false,
-            'off'   => false,
-            'no'    => false
-        ];
-
-        if (array_key_exists($key, $map)) {
-            return $map[$key];
-        } elseif (is_numeric($this->str)) {
-            return (intval($this->str) > 0);
-        }
-
-        return (bool) $this->regexReplace('[[:space:]]', '')->str;
-    }
-
-    /**
-     * Converts all characters in the string to lowercase. An alias for PHP's
-     * mb_strtolower().
-     *
-     * @return static Object with all characters of $str being lowercase
-     */
-    public function toLowerCase()
-    {
-        $str = \mb_strtolower($this->str, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Converts each tab in the string to some number of spaces, as defined by
-     * $tabLength. By default, each tab is converted to 4 consecutive spaces.
-     *
-     * @param  int    $tabLength Number of spaces to replace each tab with
-     * @return static Object whose $str has had tabs switched to spaces
-     */
-    public function toSpaces($tabLength = 4)
-    {
-        $spaces = str_repeat(' ', $tabLength);
-        $str = str_replace("\t", $spaces, $this->str);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Converts each occurrence of some consecutive number of spaces, as
-     * defined by $tabLength, to a tab. By default, each 4 consecutive spaces
-     * are converted to a tab.
-     *
-     * @param  int    $tabLength Number of spaces to replace with a tab
-     * @return static Object whose $str has had spaces switched to tabs
-     */
-    public function toTabs($tabLength = 4)
-    {
-        $spaces = str_repeat(' ', $tabLength);
-        $str = str_replace($spaces, "\t", $this->str);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Converts the first character of each word in the string to uppercase.
-     *
-     * @return static Object with all characters of $str being title-cased
-     */
-    public function toTitleCase()
-    {
-        $str = \mb_convert_case($this->str, \MB_CASE_TITLE, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Converts all characters in the string to uppercase. An alias for PHP's
-     * mb_strtoupper().
-     *
-     * @return static Object with all characters of $str being uppercase
-     */
-    public function toUpperCase()
-    {
-        $str = \mb_strtoupper($this->str, $this->encoding);
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns a string with whitespace removed from the start and end of the
-     * string. Supports the removal of unicode whitespace. Accepts an optional
-     * string of characters to strip instead of the defaults.
-     *
-     * @param  string $chars Optional string of characters to strip
-     * @return static Object with a trimmed $str
-     */
-    public function trim($chars = null)
-    {
-        $chars = ($chars) ? preg_quote($chars) : '[:space:]';
-
-        return $this->regexReplace("^[$chars]+|[$chars]+\$", '');
-    }
-
-    /**
-     * Returns a string with whitespace removed from the start of the string.
-     * Supports the removal of unicode whitespace. Accepts an optional
-     * string of characters to strip instead of the defaults.
-     *
-     * @param  string $chars Optional string of characters to strip
-     * @return static Object with a trimmed $str
-     */
-    public function trimLeft($chars = null)
-    {
-        $chars = ($chars) ? preg_quote($chars) : '[:space:]';
-
-        return $this->regexReplace("^[$chars]+", '');
-    }
-
-    /**
-     * Returns a string with whitespace removed from the end of the string.
-     * Supports the removal of unicode whitespace. Accepts an optional
-     * string of characters to strip instead of the defaults.
-     *
-     * @param  string $chars Optional string of characters to strip
-     * @return static Object with a trimmed $str
-     */
-    public function trimRight($chars = null)
-    {
-        $chars = ($chars) ? preg_quote($chars) : '[:space:]';
-
-        return $this->regexReplace("[$chars]+\$", '');
-    }
-
-    /**
-     * Truncates the string to a given length. If $substring is provided, and
-     * truncating occurs, the string is further truncated so that the substring
-     * may be appended without exceeding the desired length.
-     *
-     * @param  int    $length    Desired length of the truncated string
-     * @param  string $substring The substring to append if it can fit
-     * @return static Object with the resulting $str after truncating
-     */
-    public function truncate($length, $substring = '')
-    {
-        $stringy = static::create($this->str, $this->encoding);
-        if ($length >= $stringy->length()) {
-            return $stringy;
-        }
-
-        // Need to further trim the string so we can append the substring
-        $substringLength = \mb_strlen($substring, $stringy->encoding);
-        $length = $length - $substringLength;
-
-        $truncated = \mb_substr($stringy->str, 0, $length, $stringy->encoding);
-        $stringy->str = $truncated . $substring;
-
-        return $stringy;
-    }
-
-    /**
-     * Returns a lowercase and trimmed string separated by underscores.
-     * Underscores are inserted before uppercase characters (with the exception
-     * of the first character of the string), and in place of spaces as well as
-     * dashes.
-     *
-     * @return static Object with an underscored $str
-     */
-    public function underscored()
-    {
-        return $this->delimit('_');
-    }
-
-    /**
-     * Returns an UpperCamelCase version of the supplied string. It trims
-     * surrounding spaces, capitalizes letters following digits, spaces, dashes
-     * and underscores, and removes spaces, dashes, underscores.
-     *
-     * @return static Object with $str in UpperCamelCase
-     */
-    public function upperCamelize()
-    {
-        return $this->camelize()->upperCaseFirst();
-    }
-
-    /**
-     * Converts the first character of the supplied string to upper case.
-     *
-     * @return static Object with the first character of $str being upper case
-     */
-    public function upperCaseFirst()
-    {
-        $first = \mb_substr($this->str, 0, 1, $this->encoding);
-        $rest = \mb_substr($this->str, 1, $this->length() - 1,
-            $this->encoding);
-
-        $str = \mb_strtoupper($first, $this->encoding) . $rest;
-
-        return static::create($str, $this->encoding);
-    }
-
-    /**
-     * Returns the replacements for the toAscii() method.
-     *
-     * @return array An array of replacements.
-     */
-    protected function charsArray()
-    {
-        static $charsArray;
-        if (isset($charsArray)) return $charsArray;
-
-        return $charsArray = [
-            '0'     => ['°', '₀', '۰', '0'],
-            '1'     => ['¹', '₁', '۱', '1'],
-            '2'     => ['²', '₂', '۲', '2'],
-            '3'     => ['³', '₃', '۳', '3'],
-            '4'     => ['⁴', '₄', '۴', '٤', '4'],
-            '5'     => ['⁵', '₅', '۵', '٥', '5'],
-            '6'     => ['⁶', '₆', '۶', '٦', '6'],
-            '7'     => ['⁷', '₇', '۷', '7'],
-            '8'     => ['⁸', '₈', '۸', '8'],
-            '9'     => ['⁹', '₉', '۹', '9'],
-            'a'     => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ',
-                        'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å',
-                        'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ',
-                        'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά',
-                        'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ',
-                        'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ', 'ا', 'a', 'ä'],
-            'b'     => ['б', 'β', 'ب', 'ဗ', 'ბ', 'b'],
-            'c'     => ['ç', 'ć', 'č', 'ĉ', 'ċ', 'c'],
-            'd'     => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ',
-                        'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ', 'd'],
-            'e'     => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ',
-                        'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ',
-                        'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э',
-                        'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए', 'إ', 'ئ', 'e'],
-            'f'     => ['ф', 'φ', 'ف', 'ƒ', 'ფ', 'f'],
-            'g'     => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ဂ', 'გ', 'گ',
-                        'g'],
-            'h'     => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ', 'h'],
-            'i'     => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į',
-                        'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ',
-                        'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ',
-                        'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი',
-                        'इ', 'ی', 'i'],
-            'j'     => ['ĵ', 'ј', 'Ј', 'ჯ', 'ج', 'j'],
-            'k'     => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ',
-                        'ک', 'k'],
-            'l'     => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ',
-                        'l'],
-            'm'     => ['м', 'μ', 'م', 'မ', 'მ', 'm'],
-            'n'     => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န',
-                        'ნ', 'n'],
-            'o'     => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ',
-                        'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő',
-                        'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό',
-                        'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ', 'o',
-                        'ö'],
-            'p'     => ['п', 'π', 'ပ', 'პ', 'پ', 'p'],
-            'q'     => ['ყ', 'q'],
-            'r'     => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ', 'r'],
-            's'     => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ',
-                        'ſ', 'ს', 's'],
-            't'     => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ',
-                        'თ', 'ტ', 't'],
-            'u'     => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ',
-                        'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ',
-                        'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ', 'u',
-                        'ў', 'ü'],
-            'v'     => ['в', 'ვ', 'ϐ', 'v'],
-            'w'     => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ', 'w'],
-            'x'     => ['χ', 'ξ', 'x'],
-            'y'     => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ',
-                        'ϋ', 'ύ', 'ΰ', 'ي', 'ယ', 'y'],
-            'z'     => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ', 'z'],
-            'aa'    => ['ع', 'आ', 'آ'],
-            'ae'    => ['æ', 'ǽ'],
-            'ai'    => ['ऐ'],
-            'ch'    => ['ч', 'ჩ', 'ჭ', 'چ'],
-            'dj'    => ['ђ', 'đ'],
-            'dz'    => ['џ', 'ძ'],
-            'ei'    => ['ऍ'],
-            'gh'    => ['غ', 'ღ'],
-            'ii'    => ['ई'],
-            'ij'    => ['ij'],
-            'kh'    => ['х', 'خ', 'ხ'],
-            'lj'    => ['љ'],
-            'nj'    => ['њ'],
-            'oe'    => ['œ', 'ؤ'],
-            'oi'    => ['ऑ'],
-            'oii'   => ['ऒ'],
-            'ps'    => ['ψ'],
-            'sh'    => ['ш', 'შ', 'ش'],
-            'shch'  => ['щ'],
-            'ss'    => ['ß'],
-            'sx'    => ['ŝ'],
-            'th'    => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
-            'ts'    => ['ц', 'ც', 'წ'],
-            'uu'    => ['ऊ'],
-            'ya'    => ['я'],
-            'yu'    => ['ю'],
-            'zh'    => ['ж', 'ჟ', 'ژ'],
-            '(c)'   => ['©'],
-            'A'     => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ',
-                        'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą',
-                        'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ',
-                        'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ',
-                        'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ', 'A', 'Ä'],
-            'B'     => ['Б', 'Β', 'ब', 'B'],
-            'C'     => ['Ç','Ć', 'Č', 'Ĉ', 'Ċ', 'C'],
-            'D'     => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ',
-                        'D'],
-            'E'     => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ',
-                        'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ',
-                        'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э',
-                        'Є', 'Ə', 'E'],
-            'F'     => ['Ф', 'Φ', 'F'],
-            'G'     => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ', 'G'],
-            'H'     => ['Η', 'Ή', 'Ħ', 'H'],
-            'I'     => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į',
-                        'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ',
-                        'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ',
-                        'I'],
-            'J'     => ['J'],
-            'K'     => ['К', 'Κ', 'K'],
-            'L'     => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल', 'L'],
-            'M'     => ['М', 'Μ', 'M'],
-            'N'     => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν', 'N'],
-            'O'     => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ',
-                        'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő',
-                        'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ',
-                        'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ', 'O', 'Ö'],
-            'P'     => ['П', 'Π', 'P'],
-            'Q'     => ['Q'],
-            'R'     => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ', 'R'],
-            'S'     => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ', 'S'],
-            'T'     => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ', 'T'],
-            'U'     => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ',
-                        'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ',
-                        'Ǘ', 'Ǚ', 'Ǜ', 'U', 'Ў', 'Ü'],
-            'V'     => ['В', 'V'],
-            'W'     => ['Ω', 'Ώ', 'Ŵ', 'W'],
-            'X'     => ['Χ', 'Ξ', 'X'],
-            'Y'     => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ',
-                        'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ', 'Y'],
-            'Z'     => ['Ź', 'Ž', 'Ż', 'З', 'Ζ', 'Z'],
-            'AE'    => ['Æ', 'Ǽ'],
-            'Ch'    => ['Ч'],
-            'Dj'    => ['Ђ'],
-            'Dz'    => ['Џ'],
-            'Gx'    => ['Ĝ'],
-            'Hx'    => ['Ĥ'],
-            'Ij'    => ['IJ'],
-            'Jx'    => ['Ĵ'],
-            'Kh'    => ['Х'],
-            'Lj'    => ['Љ'],
-            'Nj'    => ['Њ'],
-            'Oe'    => ['Œ'],
-            'Ps'    => ['Ψ'],
-            'Sh'    => ['Ш'],
-            'Shch'  => ['Щ'],
-            'Ss'    => ['ẞ'],
-            'Th'    => ['Þ'],
-            'Ts'    => ['Ц'],
-            'Ya'    => ['Я'],
-            'Yu'    => ['Ю'],
-            'Zh'    => ['Ж'],
-            ' '     => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81",
-                        "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84",
-                        "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87",
-                        "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A",
-                        "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80",
-                        "\xEF\xBE\xA0"],
-        ];
-    }
-
-    /**
-     * Returns language-specific replacements for the toAscii() method.
-     * For example, German will map 'ä' to 'ae', while other languages
-     * will simply return 'a'.
-     *
-     * @param  string $language Language of the source string
-     * @return array  An array of replacements.
-     */
-    protected static function langSpecificCharsArray($language = 'en')
-    {
-        $split = preg_split('/[-_]/', $language);
-        $language = strtolower($split[0]);
-
-        static $charsArray = [];
-        if (isset($charsArray[$language])) {
-            return $charsArray[$language];
-        }
-
-        $languageSpecific = [
-            'de' => [
-                ['ä',  'ö',  'ü',  'Ä',  'Ö',  'Ü' ],
-                ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'],
-            ],
-            'bg' => [
-                ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
-                ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y']
-            ]
-        ];
-
-        if (isset($languageSpecific[$language])) {
-            $charsArray[$language] = $languageSpecific[$language];
-        } else {
-            $charsArray[$language] = [];
-        }
-
-        return $charsArray[$language];
-    }
-
-    /**
-     * Adds the specified amount of left and right padding to the given string.
-     * The default character used is a space.
-     *
-     * @param  int    $left   Length of left padding
-     * @param  int    $right  Length of right padding
-     * @param  string $padStr String used to pad
-     * @return static String with padding applied
-     */
-    protected function applyPadding($left = 0, $right = 0, $padStr = ' ')
-    {
-        $stringy = static::create($this->str, $this->encoding);
-        $length = \mb_strlen($padStr, $stringy->encoding);
-
-        $strLength = $stringy->length();
-        $paddedLength = $strLength + $left + $right;
-
-        if (!$length || $paddedLength <= $strLength) {
-            return $stringy;
-        }
-
-        $leftPadding = \mb_substr(str_repeat($padStr, ceil($left / $length)), 0,
-            $left, $stringy->encoding);
-        $rightPadding = \mb_substr(str_repeat($padStr, ceil($right / $length)),
-            0, $right, $stringy->encoding);
-
-        $stringy->str = $leftPadding . $stringy->str . $rightPadding;
-
-        return $stringy;
-    }
-
-    /**
-     * Returns true if $str matches the supplied pattern, false otherwise.
-     *
-     * @param  string $pattern Regex pattern to match against
-     * @return bool   Whether or not $str matches the pattern
-     */
-    protected function matchesPattern($pattern)
-    {
-        $regexEncoding = $this->regexEncoding();
-        $this->regexEncoding($this->encoding);
-
-        $match = \mb_ereg_match($pattern, $this->str);
-        $this->regexEncoding($regexEncoding);
-
-        return $match;
-    }
-
-    /**
-     * Alias for mb_ereg_replace with a fallback to preg_replace if the
-     * mbstring module is not installed.
-     */
-    protected function eregReplace($pattern, $replacement, $string, $option = 'msr')
-    {
-        static $functionExists;
-        if ($functionExists === null) {
-            $functionExists = function_exists('\mb_split');
-        }
-
-        if ($functionExists) {
-            return \mb_ereg_replace($pattern, $replacement, $string, $option);
-        } else if ($this->supportsEncoding()) {
-            $option = str_replace('r', '', $option);
-            return \preg_replace("/$pattern/u$option", $replacement, $string);
-        }
-    }
-
-    /**
-     * Alias for mb_regex_encoding which default to a noop if the mbstring
-     * module is not installed.
-     */
-    protected function regexEncoding()
-    {
-        static $functionExists;
-
-        if ($functionExists === null) {
-            $functionExists = function_exists('\mb_regex_encoding');
-        }
-
-        if ($functionExists) {
-            $args = func_get_args();
-            return call_user_func_array('\mb_regex_encoding', $args);
-        }
-    }
-
-    protected function supportsEncoding()
-    {
-        $supported = ['UTF-8' => true, 'ASCII' => true];
-
-        if (isset($supported[$this->encoding])) {
-            return true;
-        } else {
-            throw new \RuntimeException('Stringy method requires the ' .
-                'mbstring module for encodings other than ASCII and UTF-8. ' .
-                'Encoding used: ' . $this->encoding);
-        }
-    }
-}

+ 4 - 4
vendor/dingo/blueprint/composer.json

xqd
@@ -11,14 +11,14 @@
     ],
     "require": {
         "php": "^7.2.5|^8.0",
-        "illuminate/support": "^7.0|^8.0",
-        "illuminate/filesystem": "^7.0|^8.0",
-        "doctrine/annotations": "~1.2",
+        "illuminate/support": "^7.0|^8.0|^9.0|^10.0",
+        "illuminate/filesystem": "^7.0|^8.0|^9.0|^10.0",
+        "doctrine/annotations": "~1.2 | ^2.0",
         "phpdocumentor/reflection-docblock": "^3.1 || ^4.1 || ^5"
     },
     "require-dev": {
         "squizlabs/php_codesniffer": "~2.0",
-        "phpunit/phpunit": "^6.5|^8.3|^9.0"
+        "phpunit/phpunit": "^6.5|^8.3|^9.0|^10.0"
     },
     "autoload": {
         "psr-4": {

+ 6 - 0
vendor/doctrine/annotations/README.md

xqd
@@ -1,3 +1,9 @@
+⚠️ PHP 8 introduced
+[attributes](https://www.php.net/manual/en/language.attributes.overview.php),
+which are a native replacement for annotations. As such, this library is
+considered feature complete, and should receive exclusively bugfixes and
+security fixes.
+
 # Doctrine Annotations
 
 [![Build Status](https://github.com/doctrine/annotations/workflows/Continuous%20Integration/badge.svg?label=build)](https://github.com/doctrine/persistence/actions)

+ 8 - 5
vendor/doctrine/annotations/composer.json

xqd
@@ -34,17 +34,20 @@
     "require": {
         "php": "^7.1 || ^8.0",
         "ext-tokenizer": "*",
-        "doctrine/lexer": "1.*",
+        "doctrine/lexer": "^1 || ^2",
         "psr/cache": "^1 || ^2 || ^3"
     },
     "require-dev": {
         "doctrine/cache": "^1.11 || ^2.0",
-        "doctrine/coding-standard": "^6.0 || ^8.1",
-        "phpstan/phpstan": "^1.4.10 || ^1.8.0",
-        "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5",
-        "symfony/cache": "^4.4 || ^5.2",
+        "doctrine/coding-standard": "^9 || ^10",
+        "phpstan/phpstan": "~1.4.10 || ^1.8.0",
+        "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+        "symfony/cache": "^4.4 || ^5.4 || ^6",
         "vimeo/psalm": "^4.10"
     },
+    "suggest": {
+        "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
+    },
     "autoload": {
         "psr-4": {
             "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"

+ 1 - 1
vendor/doctrine/annotations/docs/en/custom.rst

xqd
@@ -69,7 +69,7 @@ When using the ``@NamedArgumentConstructor`` tag, the first argument of the
 constructor is considered as the default one.
 
 
-Usage with the ``@NamedArgumentContrustor`` tag
+Usage with the ``@NamedArgumentConstructor`` tag
 
 .. code-block:: php
 

+ 9 - 0
vendor/doctrine/annotations/docs/en/index.rst

xqd
@@ -1,3 +1,12 @@
+Deprecation notice
+==================
+
+PHP 8 introduced `attributes
+<https://www.php.net/manual/en/language.attributes.overview.php>`_,
+which are a native replacement for annotations. As such, this library is
+considered feature complete, and should receive exclusively bugfixes and
+security fixes.
+
 Introduction
 ============
 

+ 1 - 3
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php

xqd
@@ -18,9 +18,7 @@ class Annotation
      */
     public $value;
 
-    /**
-     * @param array<string, mixed> $data Key-value for properties to be defined in this class.
-     */
+    /** @param array<string, mixed> $data Key-value for properties to be defined in this class. */
     final public function __construct(array $data)
     {
         foreach ($data as $key => $value) {

+ 2 - 2
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php

xqd
@@ -34,9 +34,9 @@ final class Enum
     public $literal;
 
     /**
-     * @throws InvalidArgumentException
-     *
      * @phpstan-param array{literal?: mixed[], value: list<scalar>} $values
+     *
+     * @throws InvalidArgumentException
      */
     public function __construct(array $values)
     {

+ 2 - 2
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php

xqd
@@ -21,9 +21,9 @@ final class IgnoreAnnotation
     public $names;
 
     /**
-     * @throws RuntimeException
-     *
      * @phpstan-param array{value: string|list<string>} $values
+     *
+     * @throws RuntimeException
      */
     public function __construct(array $values)
     {

+ 2 - 2
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php

xqd
@@ -56,9 +56,9 @@ final class Target
     public $literal;
 
     /**
-     * @throws InvalidArgumentException
-     *
      * @phpstan-param array{value?: string|list<string>} $values
+     *
+     * @throws InvalidArgumentException
      */
     public function __construct(array $values)
     {

+ 3 - 8
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php

xqd xqd xqd
@@ -133,10 +133,9 @@ class AnnotationException extends Exception
      * @param string $annotationName
      * @param string $context
      * @param mixed  $given
+     * @phpstan-param list<string>        $available
      *
      * @return AnnotationException
-     *
-     * @phpstan-param list<string>        $available
      */
     public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
     {
@@ -150,9 +149,7 @@ class AnnotationException extends Exception
         ));
     }
 
-    /**
-     * @return AnnotationException
-     */
+    /** @return AnnotationException */
     public static function optimizerPlusSaveComments()
     {
         return new self(
@@ -160,9 +157,7 @@ class AnnotationException extends Exception
         );
     }
 
-    /**
-     * @return AnnotationException
-     */
+    /** @return AnnotationException */
     public static function optimizerPlusLoadComments()
     {
         return new self(

+ 1 - 3
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php

xqd
@@ -38,9 +38,7 @@ final class CachedReader implements Reader
     /** @var int[] */
     private $loadedFilemtimes = [];
 
-    /**
-     * @param bool $debug
-     */
+    /** @param bool $debug */
     public function __construct(Reader $reader, Cache $cache, $debug = false)
     {
         $this->delegate = $reader;

+ 16 - 2
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php

xqd xqd xqd xqd
@@ -15,6 +15,8 @@ use function substr;
 
 /**
  * Simple lexer for docblock annotations.
+ *
+ * @template-extends AbstractLexer<DocLexer::T_*, string>
  */
 final class DocLexer extends AbstractLexer
 {
@@ -39,7 +41,7 @@ final class DocLexer extends AbstractLexer
     public const T_COLON               = 112;
     public const T_MINUS               = 113;
 
-    /** @var array<string, int> */
+    /** @var array<string, self::T*> */
     protected $noCase = [
         '@'  => self::T_AT,
         ','  => self::T_COMMA,
@@ -53,7 +55,7 @@ final class DocLexer extends AbstractLexer
         '\\' => self::T_NAMESPACE_SEPARATOR,
     ];
 
-    /** @var array<string, int> */
+    /** @var array<string, self::T*> */
     protected $withCase = [
         'true'  => self::T_TRUE,
         'false' => self::T_FALSE,
@@ -126,4 +128,16 @@ final class DocLexer extends AbstractLexer
 
         return $type;
     }
+
+    /** @return array{value: int|string, type:self::T_*|null, position:int} */
+    public function peek(): ?array
+    {
+        $token = parent::peek();
+
+        if ($token === null) {
+            return null;
+        }
+
+        return (array) $token;
+    }
 }

+ 30 - 11
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php

xqd xqd xqd xqd xqd xqd xqd
@@ -357,10 +357,10 @@ final class DocParser
      * @param string $input   The docblock string to parse.
      * @param string $context The parsing context.
      *
+     * @phpstan-return list<object> Array of annotations. If no annotations are found, an empty array is returned.
+     *
      * @throws AnnotationException
      * @throws ReflectionException
-     *
-     * @phpstan-return list<object> Array of annotations. If no annotations are found, an empty array is returned.
      */
     public function parse($input, $context = '')
     {
@@ -426,9 +426,9 @@ final class DocParser
      * If any of them matches, this method updates the lookahead token; otherwise
      * a syntax error is raised.
      *
-     * @throws AnnotationException
-     *
      * @phpstan-param list<mixed[]> $tokens
+     *
+     * @throws AnnotationException
      */
     private function matchAny(array $tokens): bool
     {
@@ -613,6 +613,10 @@ final class DocParser
                 $metadata['default_property'] = reset($metadata['properties']);
             } elseif ($metadata['has_named_argument_constructor']) {
                 foreach ($constructor->getParameters() as $parameter) {
+                    if ($parameter->isVariadic()) {
+                        break;
+                    }
+
                     $metadata['constructor_args'][$parameter->getName()] = [
                         'position' => $parameter->getPosition(),
                         'default' => $parameter->isOptional() ? $parameter->getDefaultValue() : null,
@@ -674,10 +678,10 @@ final class DocParser
     /**
      * Annotations ::= Annotation {[ "*" ]* [Annotation]}*
      *
+     * @phpstan-return list<object>
+     *
      * @throws AnnotationException
      * @throws ReflectionException
-     *
-     * @phpstan-return list<object>
      */
     private function Annotations(): array
     {
@@ -942,6 +946,23 @@ EXCEPTION
 
         if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {
             if (PHP_VERSION_ID >= 80000) {
+                foreach ($values as $property => $value) {
+                    if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
+                        throw AnnotationException::creationError(sprintf(
+                            <<<'EXCEPTION'
+The annotation @%s declared on %s does not have a property named "%s"
+that can be set through its named arguments constructor.
+Available named arguments: %s
+EXCEPTION
+                            ,
+                            $originalName,
+                            $this->context,
+                            $property,
+                            implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))
+                        ));
+                    }
+                }
+
                 return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);
             }
 
@@ -1166,9 +1187,7 @@ EXCEPTION
         return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class');
     }
 
-    /**
-     * @return int|false
-     */
+    /** @return int|false */
     private function getClassConstantPositionInIdentifier(string $identifier)
     {
         return stripos($identifier, '::class');
@@ -1357,10 +1376,10 @@ EXCEPTION
      * KeyValuePair ::= Key ("=" | ":") PlainValue | Constant
      * Key ::= string | integer | Constant
      *
+     * @phpstan-return array{mixed, mixed}
+     *
      * @throws AnnotationException
      * @throws ReflectionException
-     *
-     * @phpstan-return array{mixed, mixed}
      */
     private function ArrayEntry(): array
     {

+ 1 - 3
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php

xqd
@@ -46,9 +46,7 @@ class TokenParser
      */
     private $pointer = 0;
 
-    /**
-     * @param string $contents
-     */
+    /** @param string $contents */
     public function __construct($contents)
     {
         $this->tokens = token_get_all($contents);

+ 14 - 14
vendor/doctrine/dbal/README.md

xqd xqd
@@ -1,11 +1,11 @@
 # Doctrine DBAL
 
-|                 [4.0-dev][4.0]                  |                     [3.3][3.3]                      |
+|                 [4.0-dev][4.0]                  |                     [3.6][3.6]                      |
 |:-----------------------------------------------:|:---------------------------------------------------:|
-|    [![GitHub Actions][GA 4.0 image]][GA 4.0]    |      [![GitHub Actions][GA 3.3 image]][GA 3.3]      |
-| [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] |   [![AppVeyor][AppVeyor 3.3 image]][AppVeyor 3.3]   |
-| [![Code Coverage][Coverage image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.3 image]][CodeCov 3.3] |
-|                       N/A                       | [![Code Coverage][TypeCov 3.3 image]][TypeCov 3.3]  |
+|    [![GitHub Actions][GA 4.0 image]][GA 4.0]    |      [![GitHub Actions][GA 3.6 image]][GA 3.6]      |
+| [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] |   [![AppVeyor][AppVeyor 3.6 image]][AppVeyor 3.6]   |
+| [![Code Coverage][Coverage image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.6 image]][CodeCov 3.6] |
+|                       N/A                       | [![Type Coverage][TypeCov 3.6 image]][TypeCov 3.6]  |
 
 Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features for database schema introspection and schema management.
 
@@ -23,12 +23,12 @@ Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features f
   [GA 4.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x
   [GA 4.0 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg
 
-  [Coverage 3.3 image]: https://codecov.io/gh/doctrine/dbal/branch/3.3.x/graph/badge.svg
-  [3.3]: https://github.com/doctrine/dbal/tree/3.3.x
-  [CodeCov 3.3]: https://codecov.io/gh/doctrine/dbal/branch/3.3.x
-  [AppVeyor 3.3]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.3.x
-  [AppVeyor 3.3 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.3.x?svg=true
-  [GA 3.3]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.3.x
-  [GA 3.3 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.3.x
-  [TypeCov 3.3]: https://shepherd.dev/github/doctrine/dbal
-  [TypeCov 3.3 image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg
+  [Coverage 3.6 image]: https://codecov.io/gh/doctrine/dbal/branch/3.6.x/graph/badge.svg
+  [3.6]: https://github.com/doctrine/dbal/tree/3.6.x
+  [CodeCov 3.6]: https://codecov.io/gh/doctrine/dbal/branch/3.6.x
+  [AppVeyor 3.6]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.6.x
+  [AppVeyor 3.6 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.6.x?svg=true
+  [GA 3.6]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.6.x
+  [GA 3.6 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.6.x
+  [TypeCov 3.6]: https://shepherd.dev/github/doctrine/dbal
+  [TypeCov 3.6 image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg

+ 2 - 2
vendor/doctrine/dbal/bin/doctrine-dbal.php

xqd
@@ -5,8 +5,8 @@ use Doctrine\DBAL\Tools\Console\ConsoleRunner;
 fwrite(
     STDERR,
     '[Warning] The use of this script is discouraged.'
-        . ' You find instructions on how to boostrap the console runner in our documentation.'
-        . PHP_EOL
+        . ' You find instructions on how to bootstrap the console runner in our documentation.'
+        . PHP_EOL,
 );
 
 echo PHP_EOL . PHP_EOL;

+ 13 - 12
vendor/doctrine/dbal/composer.json

xqd
@@ -31,25 +31,26 @@
         {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}
     ],
     "require": {
-        "php": "^7.3 || ^8.0",
+        "php": "^7.4 || ^8.0",
         "composer-runtime-api": "^2",
         "doctrine/cache": "^1.11|^2.0",
         "doctrine/deprecations": "^0.5.3|^1",
-        "doctrine/event-manager": "^1.0",
+        "doctrine/event-manager": "^1|^2",
         "psr/cache": "^1|^2|^3",
         "psr/log": "^1|^2|^3"
     },
     "require-dev": {
-        "doctrine/coding-standard": "9.0.0",
-        "jetbrains/phpstorm-stubs": "2022.1",
-        "phpstan/phpstan": "1.7.13",
-        "phpstan/phpstan-strict-rules": "^1.2",
-        "phpunit/phpunit": "9.5.20",
-        "psalm/plugin-phpunit": "0.16.1",
-        "squizlabs/php_codesniffer": "3.7.0",
-        "symfony/cache": "^5.2|^6.0",
-        "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
-        "vimeo/psalm": "4.23.0"
+        "doctrine/coding-standard": "12.0.0",
+        "fig/log-test": "^1",
+        "jetbrains/phpstorm-stubs": "2022.3",
+        "phpstan/phpstan": "1.10.14",
+        "phpstan/phpstan-strict-rules": "^1.5",
+        "phpunit/phpunit": "9.6.7",
+        "psalm/plugin-phpunit": "0.18.4",
+        "squizlabs/php_codesniffer": "3.7.2",
+        "symfony/cache": "^5.4|^6.0",
+        "symfony/console": "^4.4|^5.4|^6.0",
+        "vimeo/psalm": "4.30.0"
     },
     "suggest": {
         "symfony/console": "For helpful console commands such as SQL execution and import of files."

+ 37 - 0
vendor/doctrine/dbal/src/ArrayParameterType.php

xqd
@@ -0,0 +1,37 @@
+<?php
+
+namespace Doctrine\DBAL;
+
+final class ArrayParameterType
+{
+    /**
+     * Represents an array of ints to be expanded by Doctrine SQL parsing.
+     */
+    public const INTEGER = ParameterType::INTEGER + Connection::ARRAY_PARAM_OFFSET;
+
+    /**
+     * Represents an array of strings to be expanded by Doctrine SQL parsing.
+     */
+    public const STRING = ParameterType::STRING + Connection::ARRAY_PARAM_OFFSET;
+
+    /**
+     * Represents an array of ascii strings to be expanded by Doctrine SQL parsing.
+     */
+    public const ASCII = ParameterType::ASCII + Connection::ARRAY_PARAM_OFFSET;
+
+    /**
+     * @internal
+     *
+     * @psalm-param self::INTEGER|self::STRING|self::ASCII $type
+     *
+     * @psalm-return ParameterType::INTEGER|ParameterType::STRING|ParameterType::ASCII
+     */
+    public static function toElementParameterType(int $type): int
+    {
+        return $type - Connection::ARRAY_PARAM_OFFSET;
+    }
+
+    private function __construct()
+    {
+    }
+}

+ 1 - 3
vendor/doctrine/dbal/src/ArrayParameters/Exception.php

xqd
@@ -4,9 +4,7 @@ namespace Doctrine\DBAL\ArrayParameters;
 
 use Throwable;
 
-/**
- * @internal
- */
+/** @internal */
 interface Exception extends Throwable
 {
 }

+ 2 - 4
vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php

xqd
@@ -7,15 +7,13 @@ use LogicException;
 
 use function sprintf;
 
-/**
- * @psalm-immutable
- */
+/** @psalm-immutable */
 class MissingNamedParameter extends LogicException implements Exception
 {
     public static function new(string $name): self
     {
         return new self(
-            sprintf('Named parameter "%s" does not have a bound value.', $name)
+            sprintf('Named parameter "%s" does not have a bound value.', $name),
         );
     }
 }

+ 1 - 1
vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php

xqd
@@ -17,7 +17,7 @@ class MissingPositionalParameter extends LogicException implements Exception
     public static function new(int $index): self
     {
         return new self(
-            sprintf('Positional parameter at index %d does not have a bound value.', $index)
+            sprintf('Positional parameter at index %d does not have a bound value.', $index),
         );
     }
 }

+ 12 - 21
vendor/doctrine/dbal/src/Cache/ArrayResult.php

xqd xqd xqd xqd xqd xqd xqd xqd
@@ -9,23 +9,16 @@ use function array_values;
 use function count;
 use function reset;
 
-/**
- * @internal The class is internal to the caching layer implementation.
- */
+/** @internal The class is internal to the caching layer implementation. */
 final class ArrayResult implements Result
 {
     /** @var list<array<string, mixed>> */
-    private $data;
+    private array $data;
 
-    /** @var int */
-    private $columnCount = 0;
+    private int $columnCount = 0;
+    private int $num         = 0;
 
-    /** @var int */
-    private $num = 0;
-
-    /**
-     * @param list<array<string, mixed>> $data
-     */
+    /** @param list<array<string, mixed>> $data */
     public function __construct(array $data)
     {
         $this->data = $data;
@@ -37,7 +30,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchNumeric()
     {
@@ -51,7 +44,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchAssociative()
     {
@@ -59,7 +52,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchOne()
     {
@@ -73,7 +66,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchAllNumeric(): array
     {
@@ -81,7 +74,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchAllAssociative(): array
     {
@@ -89,7 +82,7 @@ final class ArrayResult implements Result
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function fetchFirstColumn(): array
     {
@@ -111,9 +104,7 @@ final class ArrayResult implements Result
         $this->data = [];
     }
 
-    /**
-     * @return array<string, mixed>|false
-     */
+    /** @return array<string, mixed>|false */
     private function fetch()
     {
         if (! isset($this->data[$this->num])) {

+ 3 - 9
vendor/doctrine/dbal/src/Cache/CacheException.php

xqd
@@ -4,22 +4,16 @@ namespace Doctrine\DBAL\Cache;
 
 use Doctrine\DBAL\Exception;
 
-/**
- * @psalm-immutable
- */
+/** @psalm-immutable */
 class CacheException extends Exception
 {
-    /**
-     * @return CacheException
-     */
+    /** @return CacheException */
     public static function noCacheKey()
     {
         return new self('No cache key was set.');
     }
 
-    /**
-     * @return CacheException
-     */
+    /** @return CacheException */
     public static function noResultDriverConfigured()
     {
         return new self('Trying to cache a query but no result driver is configured.');

+ 8 - 15
vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php

xqd xqd xqd xqd xqd xqd xqd
@@ -23,8 +23,7 @@ use function sprintf;
  */
 class QueryCacheProfile
 {
-    /** @var CacheItemPoolInterface|null */
-    private $resultCache;
+    private ?CacheItemPoolInterface $resultCache = null;
 
     /** @var int */
     private $lifetime;
@@ -50,7 +49,7 @@ class QueryCacheProfile
                 'Passing an instance of %s to %s as $resultCache is deprecated. Pass an instance of %s instead.',
                 Cache::class,
                 __METHOD__,
-                CacheItemPoolInterface::class
+                CacheItemPoolInterface::class,
             );
 
             $this->resultCache = CacheAdapter::wrap($resultCache);
@@ -59,7 +58,7 @@ class QueryCacheProfile
                 '$resultCache: Expected either null or an instance of %s or %s, got %s.',
                 CacheItemPoolInterface::class,
                 Cache::class,
-                get_class($resultCache)
+                get_class($resultCache),
             ));
         }
     }
@@ -80,15 +79,13 @@ class QueryCacheProfile
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/pull/4620',
             '%s is deprecated, call getResultCache() instead.',
-            __METHOD__
+            __METHOD__,
         );
 
         return $this->resultCache !== null ? DoctrineProvider::wrap($this->resultCache) : null;
     }
 
-    /**
-     * @return int
-     */
+    /** @return int */
     public function getLifetime()
     {
         return $this->lifetime;
@@ -116,7 +113,7 @@ class QueryCacheProfile
      * @param array<int, Type|int|string|null>|array<string, Type|int|string|null> $types
      * @param array<string, mixed>                                                 $connectionParams
      *
-     * @return string[]
+     * @return array{string, string}
      */
     public function generateCacheKeys($sql, $params, $types, array $connectionParams = [])
     {
@@ -130,11 +127,7 @@ class QueryCacheProfile
             '&connectionParams=' . hash('sha256', serialize($connectionParams));
 
         // should the key be automatically generated using the inputs or is the cache key set?
-        if ($this->cacheKey === null) {
-            $cacheKey = sha1($realCacheKey);
-        } else {
-            $cacheKey = $this->cacheKey;
-        }
+        $cacheKey = $this->cacheKey ?? sha1($realCacheKey);
 
         return [$cacheKey, $realCacheKey];
     }
@@ -155,7 +148,7 @@ class QueryCacheProfile
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/pull/4620',
             '%s is deprecated, call setResultCache() instead.',
-            __METHOD__
+            __METHOD__,
         );
 
         return new QueryCacheProfile($this->lifetime, $this->cacheKey, CacheAdapter::wrap($cache));

+ 64 - 9
vendor/doctrine/dbal/src/Configuration.php

xqd xqd xqd xqd xqd xqd xqd
@@ -7,16 +7,19 @@ use Doctrine\Common\Cache\Psr6\CacheAdapter;
 use Doctrine\Common\Cache\Psr6\DoctrineProvider;
 use Doctrine\DBAL\Driver\Middleware;
 use Doctrine\DBAL\Logging\SQLLogger;
+use Doctrine\DBAL\Schema\SchemaManagerFactory;
 use Doctrine\Deprecations\Deprecation;
 use Psr\Cache\CacheItemPoolInterface;
 
+use function func_num_args;
+
 /**
  * Configuration container for the Doctrine DBAL.
  */
 class Configuration
 {
     /** @var Middleware[] */
-    private $middlewares = [];
+    private array $middlewares = [];
 
     /**
      * The SQL logger in use. If null, SQL logging is disabled.
@@ -27,10 +30,8 @@ class Configuration
 
     /**
      * The cache driver implementation that is used for query result caching.
-     *
-     * @var CacheItemPoolInterface|null
      */
-    private $resultCache;
+    private ?CacheItemPoolInterface $resultCache = null;
 
     /**
      * The cache driver implementation that is used for query result caching.
@@ -55,19 +56,46 @@ class Configuration
      */
     protected $autoCommit = true;
 
+    private ?SchemaManagerFactory $schemaManagerFactory = null;
+
+    public function __construct()
+    {
+        $this->schemaAssetsFilter = static function (): bool {
+            return true;
+        };
+    }
+
     /**
      * Sets the SQL logger to use. Defaults to NULL which means SQL logging is disabled.
+     *
+     * @deprecated Use {@see setMiddlewares()} and {@see \Doctrine\DBAL\Logging\Middleware} instead.
      */
     public function setSQLLogger(?SQLLogger $logger = null): void
     {
+        Deprecation::trigger(
+            'doctrine/dbal',
+            'https://github.com/doctrine/dbal/pull/4967',
+            '%s is deprecated, use setMiddlewares() and Logging\\Middleware instead.',
+            __METHOD__,
+        );
+
         $this->sqlLogger = $logger;
     }
 
     /**
      * Gets the SQL logger that is used.
+     *
+     * @deprecated
      */
     public function getSQLLogger(): ?SQLLogger
     {
+        Deprecation::triggerIfCalledFromOutside(
+            'doctrine/dbal',
+            'https://github.com/doctrine/dbal/pull/4967',
+            '%s is deprecated.',
+            __METHOD__,
+        );
+
         return $this->sqlLogger;
     }
 
@@ -90,7 +118,7 @@ class Configuration
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/pull/4620',
             '%s is deprecated, call getResultCache() instead.',
-            __METHOD__
+            __METHOD__,
         );
 
         return $this->resultCacheImpl;
@@ -116,7 +144,7 @@ class Configuration
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/pull/4620',
             '%s is deprecated, call setResultCache() instead.',
-            __METHOD__
+            __METHOD__,
         );
 
         $this->resultCacheImpl = $cacheImpl;
@@ -128,6 +156,22 @@ class Configuration
      */
     public function setSchemaAssetsFilter(?callable $callable = null): void
     {
+        if (func_num_args() < 1) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/pull/5483',
+                'Not passing an argument to %s is deprecated.',
+                __METHOD__,
+            );
+        } elseif ($callable === null) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/pull/5483',
+                'Using NULL as a schema asset filter is deprecated.'
+                    . ' Use a callable that always returns true instead.',
+            );
+        }
+
         $this->schemaAssetsFilter = $callable;
     }
 
@@ -179,11 +223,22 @@ class Configuration
         return $this;
     }
 
-    /**
-     * @return Middleware[]
-     */
+    /** @return Middleware[] */
     public function getMiddlewares(): array
     {
         return $this->middlewares;
     }
+
+    public function getSchemaManagerFactory(): ?SchemaManagerFactory
+    {
+        return $this->schemaManagerFactory;
+    }
+
+    /** @return $this */
+    public function setSchemaManagerFactory(SchemaManagerFactory $schemaManagerFactory): self
+    {
+        $this->schemaManagerFactory = $schemaManagerFactory;
+
+        return $this;
+    }
 }

+ 248 - 127
vendor/doctrine/dbal/src/Connection.php

xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd
@@ -21,13 +21,18 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
 use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
 use Doctrine\DBAL\Query\QueryBuilder;
 use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
+use Doctrine\DBAL\Schema\LegacySchemaManagerFactory;
+use Doctrine\DBAL\Schema\SchemaManagerFactory;
 use Doctrine\DBAL\SQL\Parser;
 use Doctrine\DBAL\Types\Type;
 use Doctrine\Deprecations\Deprecation;
 use LogicException;
+use SensitiveParameter;
 use Throwable;
 use Traversable;
 
+use function array_key_exists;
 use function assert;
 use function count;
 use function get_class;
@@ -49,35 +54,47 @@ class Connection
 {
     /**
      * Represents an array of ints to be expanded by Doctrine SQL parsing.
+     *
+     * @deprecated Use {@see ArrayParameterType::INTEGER} instead.
      */
-    public const PARAM_INT_ARRAY = ParameterType::INTEGER + self::ARRAY_PARAM_OFFSET;
+    public const PARAM_INT_ARRAY = ArrayParameterType::INTEGER;
 
     /**
      * Represents an array of strings to be expanded by Doctrine SQL parsing.
+     *
+     * @deprecated Use {@see ArrayParameterType::STRING} instead.
      */
-    public const PARAM_STR_ARRAY = ParameterType::STRING + self::ARRAY_PARAM_OFFSET;
+    public const PARAM_STR_ARRAY = ArrayParameterType::STRING;
 
     /**
      * Represents an array of ascii strings to be expanded by Doctrine SQL parsing.
+     *
+     * @deprecated Use {@see ArrayParameterType::ASCII} instead.
      */
-    public const PARAM_ASCII_STR_ARRAY = ParameterType::ASCII + self::ARRAY_PARAM_OFFSET;
+    public const PARAM_ASCII_STR_ARRAY = ArrayParameterType::ASCII;
 
     /**
      * Offset by which PARAM_* constants are detected as arrays of the param type.
+     *
+     * @internal Should be used only within the wrapper layer.
      */
     public const ARRAY_PARAM_OFFSET = 100;
 
     /**
      * The wrapped driver connection.
      *
-     * @var \Doctrine\DBAL\Driver\Connection|null
+     * @var DriverConnection|null
      */
     protected $_conn;
 
     /** @var Configuration */
     protected $_config;
 
-    /** @var EventManager */
+    /**
+     * @deprecated
+     *
+     * @var EventManager
+     */
     protected $_eventManager;
 
     /**
@@ -89,31 +106,25 @@ class Connection
 
     /**
      * The current auto-commit mode of this connection.
-     *
-     * @var bool
      */
-    private $autoCommit = true;
+    private bool $autoCommit = true;
 
     /**
      * The transaction nesting level.
-     *
-     * @var int
      */
-    private $transactionNestingLevel = 0;
+    private int $transactionNestingLevel = 0;
 
     /**
      * The currently active transaction isolation level or NULL before it has been determined.
      *
-     * @var int|null
+     * @var TransactionIsolationLevel::*|null
      */
     private $transactionIsolationLevel;
 
     /**
      * If nested transactions should use savepoints.
-     *
-     * @var bool
      */
-    private $nestTransactionsWithSavepoints = false;
+    private bool $nestTransactionsWithSavepoints = false;
 
     /**
      * The parameters used during creation of the Connection instance.
@@ -121,20 +132,15 @@ class Connection
      * @var array<string,mixed>
      * @psalm-var Params
      */
-    private $params;
+    private array $params;
 
     /**
      * The database platform object used by the connection or NULL before it's initialized.
-     *
-     * @var AbstractPlatform|null
      */
-    private $platform;
-
-    /** @var ExceptionConverter|null */
-    private $exceptionConverter;
+    private ?AbstractPlatform $platform = null;
 
-    /** @var Parser|null */
-    private $parser;
+    private ?ExceptionConverter $exceptionConverter = null;
+    private ?Parser $parser                         = null;
 
     /**
      * The schema manager.
@@ -154,10 +160,10 @@ class Connection
 
     /**
      * Flag that indicates whether the current transaction is marked for rollback only.
-     *
-     * @var bool
      */
-    private $isRollbackOnly = false;
+    private bool $isRollbackOnly = false;
+
+    private SchemaManagerFactory $schemaManagerFactory;
 
     /**
      * Initializes a new instance of the Connection class.
@@ -169,11 +175,11 @@ class Connection
      * @param Configuration|null  $config       The configuration, optional.
      * @param EventManager|null   $eventManager The event manager, optional.
      * @psalm-param Params $params
-     * @phpstan-param array<string,mixed> $params
      *
      * @throws Exception
      */
     public function __construct(
+        #[SensitiveParameter]
         array $params,
         Driver $driver,
         ?Configuration $config = null,
@@ -183,13 +189,8 @@ class Connection
         $this->params  = $params;
 
         // Create default config and event manager if none given
-        if ($config === null) {
-            $config = new Configuration();
-        }
-
-        if ($eventManager === null) {
-            $eventManager = new EventManager();
-        }
+        $config       ??= new Configuration();
+        $eventManager ??= new EventManager();
 
         $this->_config       = $config;
         $this->_eventManager = $eventManager;
@@ -199,6 +200,13 @@ class Connection
                 throw Exception::invalidPlatformType($params['platform']);
             }
 
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/pull/5699',
+                'The "platform" connection parameter is deprecated.'
+                    . ' Use a driver middleware that would instantiate the platform instead.',
+            );
+
             $this->platform = $params['platform'];
             $this->platform->setEventManager($this->_eventManager);
         }
@@ -206,6 +214,21 @@ class Connection
         $this->_expr = $this->createExpressionBuilder();
 
         $this->autoCommit = $config->getAutoCommit();
+
+        $schemaManagerFactory = $config->getSchemaManagerFactory();
+        if ($schemaManagerFactory === null) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5812',
+                'Not configuring a schema manager factory is deprecated.'
+                    . ' Use %s which is going to be the default in DBAL 4.',
+                DefaultSchemaManagerFactory::class,
+            );
+
+            $schemaManagerFactory = new LegacySchemaManagerFactory();
+        }
+
+        $this->schemaManagerFactory = $schemaManagerFactory;
     }
 
     /**
@@ -264,10 +287,19 @@ class Connection
     /**
      * Gets the EventManager used by the Connection.
      *
+     * @deprecated
+     *
      * @return EventManager
      */
     public function getEventManager()
     {
+        Deprecation::triggerIfCalledFromOutside(
+            'doctrine/dbal',
+            'https://github.com/doctrine/dbal/issues/5784',
+            '%s is deprecated.',
+            __METHOD__,
+        );
+
         return $this->_eventManager;
     }
 
@@ -309,7 +341,7 @@ class Connection
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/issues/4515',
             'Connection::getExpressionBuilder() is deprecated,'
-                . ' use Connection::createExpressionBuilder() instead.'
+                . ' use Connection::createExpressionBuilder() instead.',
         );
 
         return $this->_expr;
@@ -324,13 +356,15 @@ class Connection
      *              the connection is already open.
      *
      * @throws Exception
+     *
+     * @psalm-assert !null $this->_conn
      */
     public function connect()
     {
         Deprecation::triggerIfCalledFromOutside(
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/issues/4966',
-            'Public access to Connection::connect() is deprecated.'
+            'Public access to Connection::connect() is deprecated.',
         );
 
         if ($this->_conn !== null) {
@@ -348,6 +382,13 @@ class Connection
         }
 
         if ($this->_eventManager->hasListeners(Events::postConnect)) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5784',
+                'Subscribing to %s events is deprecated. Implement a middleware instead.',
+                Events::postConnect,
+            );
+
             $eventArgs = new Event\ConnectionEventArgs($this);
             $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
         }
@@ -399,6 +440,10 @@ class Connection
             return $this->params['serverVersion'];
         }
 
+        if (isset($this->params['primary']) && isset($this->params['primary']['serverVersion'])) {
+            return $this->params['primary']['serverVersion'];
+        }
+
         // If not connected, we need to connect now to determine the platform version.
         if ($this->_conn === null) {
             try {
@@ -408,6 +453,15 @@ class Connection
                     throw $originalException;
                 }
 
+                Deprecation::trigger(
+                    'doctrine/dbal',
+                    'https://github.com/doctrine/dbal/pull/5707',
+                    'Relying on a fallback connection used to determine the database platform while connecting'
+                        . ' to a non-existing database is deprecated. Either use an existing database name in'
+                        . ' connection parameters or omit the database name if the platform'
+                        . ' and the server configuration allow that.',
+                );
+
                 // The database to connect to might not yet exist.
                 // Retry detection without database name connection parameter.
                 $params = $this->params;
@@ -458,9 +512,9 @@ class Connection
 
         Deprecation::trigger(
             'doctrine/dbal',
-            'https://github.com/doctrine/dbal/pulls/4750',
+            'https://github.com/doctrine/dbal/pull/4750',
             'Not implementing the ServerInfoAwareConnection interface in %s is deprecated',
-            get_class($connection)
+            get_class($connection),
         );
 
         // Unable to detect platform version.
@@ -641,7 +695,7 @@ class Connection
         return $this->executeStatement(
             'DELETE FROM ' . $table . ' WHERE ' . implode(' AND ', $conditions),
             $values,
-            is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types
+            is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types,
         );
     }
 
@@ -659,7 +713,7 @@ class Connection
     /**
      * Sets the transaction isolation level.
      *
-     * @param int $level The level to set.
+     * @param TransactionIsolationLevel::* $level The level to set.
      *
      * @return int|string
      *
@@ -675,17 +729,13 @@ class Connection
     /**
      * Gets the currently active transaction isolation level.
      *
-     * @return int The current transaction isolation level.
+     * @return TransactionIsolationLevel::* The current transaction isolation level.
      *
      * @throws Exception
      */
     public function getTransactionIsolation()
     {
-        if ($this->transactionIsolationLevel === null) {
-            $this->transactionIsolationLevel = $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel();
-        }
-
-        return $this->transactionIsolationLevel;
+        return $this->transactionIsolationLevel ??= $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel();
     }
 
     /**
@@ -757,7 +807,7 @@ class Connection
             'INSERT INTO ' . $table . ' (' . implode(', ', $columns) . ')' .
             ' VALUES (' . implode(', ', $set) . ')',
             $values,
-            is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types
+            is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types,
         );
     }
 
@@ -1005,7 +1055,7 @@ class Connection
     }
 
     /**
-     * Executes an, optionally parametrized, SQL query.
+     * Executes an, optionally parameterized, SQL query.
      *
      * If the query is parametrized, a prepared statement is used.
      * If an SQLLogger is configured, the execution is logged.
@@ -1040,12 +1090,10 @@ class Connection
                 }
 
                 $stmt = $connection->prepare($sql);
-                if (count($types) > 0) {
-                    $this->_bindTypedValues($stmt, $params, $types);
-                    $result = $stmt->execute();
-                } else {
-                    $result = $stmt->execute($params);
-                }
+
+                $this->bindParameters($stmt, $params, $types);
+
+                $result = $stmt->execute();
             } else {
                 $result = $connection->query($sql);
             }
@@ -1079,7 +1127,7 @@ class Connection
         }
 
         $connectionParams = $this->params;
-        unset($connectionParams['platform']);
+        unset($connectionParams['platform'], $connectionParams['password'], $connectionParams['url']);
 
         [$cacheKey, $realKey] = $qcp->generateCacheKeys($sql, $params, $types, $connectionParams);
 
@@ -1147,15 +1195,10 @@ class Connection
 
                 $stmt = $connection->prepare($sql);
 
-                if (count($types) > 0) {
-                    $this->_bindTypedValues($stmt, $params, $types);
-
-                    $result = $stmt->execute();
-                } else {
-                    $result = $stmt->execute($params);
-                }
+                $this->bindParameters($stmt, $params, $types);
 
-                return $result->rowCount();
+                return $stmt->execute()
+                    ->rowCount();
             }
 
             return $connection->exec($sql);
@@ -1198,7 +1241,7 @@ class Connection
             Deprecation::trigger(
                 'doctrine/dbal',
                 'https://github.com/doctrine/dbal/issues/4687',
-                'The usage of Connection::lastInsertId() with a sequence name is deprecated.'
+                'The usage of Connection::lastInsertId() with a sequence name is deprecated.',
             );
         }
 
@@ -1217,11 +1260,13 @@ class Connection
      * If an exception occurs during execution of the function or transaction commit,
      * the transaction is rolled back and the exception re-thrown.
      *
-     * @param Closure $func The function to execute transactionally.
+     * @param Closure(self):T $func The function to execute transactionally.
      *
-     * @return mixed The value returned by $func
+     * @return T The value returned by $func
      *
      * @throws Throwable
+     *
+     * @template T
      */
     public function transactional(Closure $func)
     {
@@ -1249,6 +1294,18 @@ class Connection
      */
     public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints)
     {
+        if (! $nestTransactionsWithSavepoints) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/pull/5383',
+                <<<'DEPRECATION'
+                Nesting transactions without enabling savepoints is deprecated.
+                Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
+                DEPRECATION,
+                self::class,
+            );
+        }
+
         if ($this->transactionNestingLevel > 0) {
             throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction();
         }
@@ -1312,9 +1369,30 @@ class Connection
             if ($logger !== null) {
                 $logger->stopQuery();
             }
+        } else {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/pull/5383',
+                <<<'DEPRECATION'
+                Nesting transactions without enabling savepoints is deprecated.
+                Call %s::setNestTransactionsWithSavepoints(true) to enable savepoints.
+                DEPRECATION,
+                self::class,
+            );
         }
 
-        $this->getEventManager()->dispatchEvent(Events::onTransactionBegin, new TransactionBeginEventArgs($this));
+        $eventManager = $this->getEventManager();
+
+        if ($eventManager->hasListeners(Events::onTransactionBegin)) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5784',
+                'Subscribing to %s events is deprecated.',
+                Events::onTransactionBegin,
+            );
+
+            $eventManager->dispatchEvent(Events::onTransactionBegin, new TransactionBeginEventArgs($this));
+        }
 
         return true;
     }
@@ -1338,32 +1416,26 @@ class Connection
 
         $connection = $this->getWrappedConnection();
 
-        $logger = $this->_config->getSQLLogger();
-
         if ($this->transactionNestingLevel === 1) {
-            if ($logger !== null) {
-                $logger->startQuery('"COMMIT"');
-            }
-
-            $result = $connection->commit();
-
-            if ($logger !== null) {
-                $logger->stopQuery();
-            }
+            $result = $this->doCommit($connection);
         } elseif ($this->nestTransactionsWithSavepoints) {
-            if ($logger !== null) {
-                $logger->startQuery('"RELEASE SAVEPOINT"');
-            }
-
             $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
-            if ($logger !== null) {
-                $logger->stopQuery();
-            }
         }
 
         --$this->transactionNestingLevel;
 
-        $this->getEventManager()->dispatchEvent(Events::onTransactionCommit, new TransactionCommitEventArgs($this));
+        $eventManager = $this->getEventManager();
+
+        if ($eventManager->hasListeners(Events::onTransactionCommit)) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5784',
+                'Subscribing to %s events is deprecated.',
+                Events::onTransactionCommit,
+            );
+
+            $eventManager->dispatchEvent(Events::onTransactionCommit, new TransactionCommitEventArgs($this));
+        }
 
         if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) {
             return $result;
@@ -1374,6 +1446,28 @@ class Connection
         return $result;
     }
 
+    /**
+     * @return bool
+     *
+     * @throws DriverException
+     */
+    private function doCommit(DriverConnection $connection)
+    {
+        $logger = $this->_config->getSQLLogger();
+
+        if ($logger !== null) {
+            $logger->startQuery('"COMMIT"');
+        }
+
+        $result = $connection->commit();
+
+        if ($logger !== null) {
+            $logger->stopQuery();
+        }
+
+        return $result;
+    }
+
     /**
      * Commits all current nesting transactions.
      *
@@ -1441,7 +1535,18 @@ class Connection
             --$this->transactionNestingLevel;
         }
 
-        $this->getEventManager()->dispatchEvent(Events::onTransactionRollBack, new TransactionRollBackEventArgs($this));
+        $eventManager = $this->getEventManager();
+
+        if ($eventManager->hasListeners(Events::onTransactionRollBack)) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5784',
+                'Subscribing to %s events is deprecated.',
+                Events::onTransactionRollBack,
+            );
+
+            $eventManager->dispatchEvent(Events::onTransactionRollBack, new TransactionRollBackEventArgs($this));
+        }
 
         return true;
     }
@@ -1477,6 +1582,8 @@ class Connection
      */
     public function releaseSavepoint($savepoint)
     {
+        $logger = $this->_config->getSQLLogger();
+
         $platform = $this->getDatabasePlatform();
 
         if (! $platform->supportsSavepoints()) {
@@ -1484,10 +1591,24 @@ class Connection
         }
 
         if (! $platform->supportsReleaseSavepoints()) {
+            if ($logger !== null) {
+                $logger->stopQuery();
+            }
+
             return;
         }
 
+        if ($logger !== null) {
+            $logger->startQuery('"RELEASE SAVEPOINT"');
+        }
+
         $this->executeStatement($platform->releaseSavePoint($savepoint));
+
+        if ($logger === null) {
+            return;
+        }
+
+        $logger->stopQuery();
     }
 
     /**
@@ -1525,28 +1646,23 @@ class Connection
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/issues/4966',
             'Connection::getWrappedConnection() is deprecated.'
-                . ' Use Connection::getNativeConnection() to access the native connection.'
+                . ' Use Connection::getNativeConnection() to access the native connection.',
         );
 
         $this->connect();
 
-        assert($this->_conn !== null);
-
         return $this->_conn;
     }
 
-    /**
-     * @return resource|object
-     */
+    /** @return resource|object */
     public function getNativeConnection()
     {
         $this->connect();
 
-        assert($this->_conn !== null);
         if (! method_exists($this->_conn, 'getNativeConnection')) {
             throw new LogicException(sprintf(
                 'The driver connection %s does not support accessing the native connection.',
-                get_class($this->_conn)
+                get_class($this->_conn),
             ));
         }
 
@@ -1561,10 +1677,7 @@ class Connection
      */
     public function createSchemaManager(): AbstractSchemaManager
     {
-        return $this->_driver->getSchemaManager(
-            $this,
-            $this->getDatabasePlatform()
-        );
+        return $this->schemaManagerFactory->createSchemaManager($this);
     }
 
     /**
@@ -1582,14 +1695,10 @@ class Connection
         Deprecation::triggerIfCalledFromOutside(
             'doctrine/dbal',
             'https://github.com/doctrine/dbal/issues/4515',
-            'Connection::getSchemaManager() is deprecated, use Connection::createSchemaManager() instead.'
+            'Connection::getSchemaManager() is deprecated, use Connection::createSchemaManager() instead.',
         );
 
-        if ($this->_schemaManager === null) {
-            $this->_schemaManager = $this->createSchemaManager();
-        }
-
-        return $this->_schemaManager;
+        return $this->_schemaManager ??= $this->createSchemaManager();
     }
 
     /**
@@ -1667,7 +1776,7 @@ class Connection
      *
      * @throws Exception
      */
-    private function _bindTypedValues(DriverStatement $stmt, array $params, array $types): void
+    private function bindParameters(DriverStatement $stmt, array $params, array $types): void
     {
         // Check whether parameters are positional or named. Mixing is not allowed.
         if (is_int(key($params))) {
@@ -1677,11 +1786,21 @@ class Connection
                 if (isset($types[$key])) {
                     $type                  = $types[$key];
                     [$value, $bindingType] = $this->getBindingInfo($value, $type);
-                    $stmt->bindValue($bindIndex, $value, $bindingType);
                 } else {
-                    $stmt->bindValue($bindIndex, $value);
+                    if (array_key_exists($key, $types)) {
+                        Deprecation::trigger(
+                            'doctrine/dbal',
+                            'https://github.com/doctrine/dbal/pull/5550',
+                            'Using NULL as prepared statement parameter type is deprecated.'
+                                . 'Omit or use Parameter::STRING instead',
+                        );
+                    }
+
+                    $bindingType = ParameterType::STRING;
                 }
 
+                $stmt->bindValue($bindIndex, $value, $bindingType);
+
                 ++$bindIndex;
             }
         } else {
@@ -1690,10 +1809,20 @@ class Connection
                 if (isset($types[$name])) {
                     $type                  = $types[$name];
                     [$value, $bindingType] = $this->getBindingInfo($value, $type);
-                    $stmt->bindValue($name, $value, $bindingType);
                 } else {
-                    $stmt->bindValue($name, $value);
+                    if (array_key_exists($name, $types)) {
+                        Deprecation::trigger(
+                            'doctrine/dbal',
+                            'https://github.com/doctrine/dbal/pull/5550',
+                            'Using NULL as prepared statement parameter type is deprecated.'
+                                . 'Omit or use Parameter::STRING instead',
+                        );
+                    }
+
+                    $bindingType = ParameterType::STRING;
                 }
+
+                $stmt->bindValue($name, $value, $bindingType);
             }
         }
     }
@@ -1749,9 +1878,7 @@ class Connection
         return $this->handleDriverException($e, new Query($sql, $params, $types));
     }
 
-    /**
-     * @internal
-     */
+    /** @internal */
     final public function convertException(Driver\Exception $e): DriverException
     {
         return $this->handleDriverException($e, null);
@@ -1765,11 +1892,8 @@ class Connection
      */
     private function expandArrayParameters(string $sql, array $params, array $types): array
     {
-        if ($this->parser === null) {
-            $this->parser = $this->getDatabasePlatform()->createSQLParser();
-        }
-
-        $visitor = new ExpandArrayParameters($params, $types);
+        $this->parser ??= $this->getDatabasePlatform()->createSQLParser();
+        $visitor        = new ExpandArrayParameters($params, $types);
 
         $this->parser->parse($sql, $visitor);
 
@@ -1792,9 +1916,9 @@ class Connection
 
         foreach ($types as $type) {
             if (
-                $type === self::PARAM_INT_ARRAY
-                || $type === self::PARAM_STR_ARRAY
-                || $type === self::PARAM_ASCII_STR_ARRAY
+                $type === ArrayParameterType::INTEGER
+                || $type === ArrayParameterType::STRING
+                || $type === ArrayParameterType::ASCII
             ) {
                 return true;
             }
@@ -1807,11 +1931,8 @@ class Connection
         Driver\Exception $driverException,
         ?Query $query
     ): DriverException {
-        if ($this->exceptionConverter === null) {
-            $this->exceptionConverter = $this->_driver->getExceptionConverter();
-        }
-
-        $exception = $this->exceptionConverter->convert($driverException, $query);
+        $this->exceptionConverter ??= $this->_driver->getExceptionConverter();
+        $exception                  = $this->exceptionConverter->convert($driverException, $query);
 
         if ($exception instanceof ConnectionLost) {
             $this->close();

+ 5 - 15
vendor/doctrine/dbal/src/ConnectionException.php

xqd
@@ -2,38 +2,28 @@
 
 namespace Doctrine\DBAL;
 
-/**
- * @psalm-immutable
- */
+/** @psalm-immutable */
 class ConnectionException extends Exception
 {
-    /**
-     * @return ConnectionException
-     */
+    /** @return ConnectionException */
     public static function commitFailedRollbackOnly()
     {
         return new self('Transaction commit failed because the transaction has been marked for rollback only.');
     }
 
-    /**
-     * @return ConnectionException
-     */
+    /** @return ConnectionException */
     public static function noActiveTransaction()
     {
         return new self('There is no active transaction.');
     }
 
-    /**
-     * @return ConnectionException
-     */
+    /** @return ConnectionException */
     public static function savepointsNotSupported()
     {
         return new self('Savepoints are not supported by this driver.');
     }
 
-    /**
-     * @return ConnectionException
-     */
+    /** @return ConnectionException */
     public static function mayNotAlterNestedTransactionWithSavepointsInTransaction()
     {
         return new self('May not alter the nested transaction with savepoints behavior while a transaction is open.');

+ 15 - 4
vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php

xqd xqd xqd xqd xqd
@@ -13,7 +13,9 @@ use Doctrine\DBAL\Event\ConnectionEventArgs;
 use Doctrine\DBAL\Events;
 use Doctrine\DBAL\Exception;
 use Doctrine\DBAL\Statement;
+use Doctrine\Deprecations\Deprecation;
 use InvalidArgumentException;
+use SensitiveParameter;
 
 use function array_rand;
 use function count;
@@ -97,7 +99,6 @@ class PrimaryReadReplicaConnection extends Connection
      *
      * @param array<string,mixed> $params
      * @psalm-param Params $params
-     * @phpstan-param array<string,mixed> $params
      *
      * @throws Exception
      * @throws InvalidArgumentException
@@ -147,7 +148,7 @@ class PrimaryReadReplicaConnection extends Connection
         if ($connectionName !== null) {
             throw new InvalidArgumentException(
                 'Passing a connection name as first argument is not supported anymore.'
-                    . ' Use ensureConnectedToPrimary()/ensureConnectedToReplica() instead.'
+                    . ' Use ensureConnectedToPrimary()/ensureConnectedToReplica() instead.',
             );
         }
 
@@ -199,6 +200,13 @@ class PrimaryReadReplicaConnection extends Connection
         }
 
         if ($this->_eventManager->hasListeners(Events::postConnect)) {
+            Deprecation::trigger(
+                'doctrine/dbal',
+                'https://github.com/doctrine/dbal/issues/5784',
+                'Subscribing to %s events is deprecated. Implement a middleware instead.',
+                Events::postConnect,
+            );
+
             $eventArgs = new ConnectionEventArgs($this);
             $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
         }
@@ -256,8 +264,11 @@ class PrimaryReadReplicaConnection extends Connection
      *
      * @return mixed
      */
-    protected function chooseConnectionConfiguration($connectionName, $params)
-    {
+    protected function chooseConnectionConfiguration(
+        $connectionName,
+        #[SensitiveParameter]
+        $params
+    ) {
         if ($connectionName === 'primary') {
             return $params['primary'];
         }

+ 11 - 2
vendor/doctrine/dbal/src/Driver.php

xqd xqd
@@ -7,23 +7,30 @@ use Doctrine\DBAL\Driver\Connection as DriverConnection;
 use Doctrine\DBAL\Driver\Exception;
 use Doctrine\DBAL\Platforms\AbstractPlatform;
 use Doctrine\DBAL\Schema\AbstractSchemaManager;
+use SensitiveParameter;
 
 /**
  * Driver interface.
  * Interface that all DBAL drivers must implement.
+ *
+ * @psalm-import-type Params from DriverManager
  */
 interface Driver
 {
     /**
      * Attempts to create a connection with the database.
      *
-     * @param mixed[] $params All connection parameters.
+     * @param array<string, mixed> $params All connection parameters.
+     * @psalm-param Params $params All connection parameters.
      *
      * @return DriverConnection The database connection.
      *
      * @throws Exception
      */
-    public function connect(array $params);
+    public function connect(
+        #[SensitiveParameter]
+        array $params
+    );
 
     /**
      * Gets the DatabasePlatform instance that provides all the metadata about
@@ -37,6 +44,8 @@ interface Driver
      * Gets the SchemaManager that can be used to inspect and change the underlying
      * database schema of the platform this driver connects to.
      *
+     * @deprecated Use {@link AbstractPlatform::createSchemaManager()} instead.
+     *
      * @return AbstractSchemaManager
      */
     public function getSchemaManager(Connection $conn, AbstractPlatform $platform);

+ 1 - 3
vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php

xqd
@@ -22,9 +22,7 @@ use Doctrine\DBAL\Exception\TableNotFoundException;
 use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
 use Doctrine\DBAL\Query;
 
-/**
- * @internal
- */
+/** @internal */
 final class ExceptionConverter implements ExceptionConverterInterface
 {
     /**

+ 2 - 6
vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php

xqd
@@ -20,14 +20,10 @@ use Doctrine\DBAL\Exception\TableNotFoundException;
 use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
 use Doctrine\DBAL\Query;
 
-/**
- * @internal
- */
+/** @internal */
 final class ExceptionConverter implements ExceptionConverterInterface
 {
-    /**
-     * @link http://www.dba-oracle.com/t_error_code_list.htm
-     */
+    /** @link http://www.dba-oracle.com/t_error_code_list.htm */
     public function convert(Exception $exception, ?Query $query): DriverException
     {
         switch ($exception->getCode()) {

+ 3 - 7
vendor/doctrine/dbal/src/Driver/API/PostgreSQL/ExceptionConverter.php

xqd xqd
@@ -23,14 +23,10 @@ use Doctrine\DBAL\Query;
 
 use function strpos;
 
-/**
- * @internal
- */
+/** @internal */
 final class ExceptionConverter implements ExceptionConverterInterface
 {
-    /**
-     * @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
-     */
+    /** @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html */
     public function convert(Exception $exception, ?Query $query): DriverException
     {
         switch ($exception->getSQLState()) {
@@ -81,7 +77,7 @@ final class ExceptionConverter implements ExceptionConverterInterface
                 return new ConnectionException($exception, $query);
         }
 
-        // Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.3.22 and PHP 7.4.10),
+        // Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.4.10),
         // in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code.
         // We have to match against the SQLSTATE in the error message in these cases.
         if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) {

+ 7 - 6
vendor/doctrine/dbal/src/Driver/API/SQLite/ExceptionConverter.php

xqd xqd xqd
@@ -8,6 +8,7 @@ use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
 use Doctrine\DBAL\Driver\Exception;
 use Doctrine\DBAL\Exception\ConnectionException;
 use Doctrine\DBAL\Exception\DriverException;
+use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
 use Doctrine\DBAL\Exception\InvalidFieldNameException;
 use Doctrine\DBAL\Exception\LockWaitTimeoutException;
 use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
@@ -21,14 +22,10 @@ use Doctrine\DBAL\Query;
 
 use function strpos;
 
-/**
- * @internal
- */
+/** @internal */
 final class ExceptionConverter implements ExceptionConverterInterface
 {
-    /**
-     * @link http://www.sqlite.org/c3ref/c_abort.html
-     */
+    /** @link http://www.sqlite.org/c3ref/c_abort.html */
     public function convert(Exception $exception, ?Query $query): DriverException
     {
         if (strpos($exception->getMessage(), 'database is locked') !== false) {
@@ -79,6 +76,10 @@ final class ExceptionConverter implements ExceptionConverterInterface
             return new ConnectionException($exception, $query);
         }
 
+        if (strpos($exception->getMessage(), 'FOREIGN KEY constraint failed') !== false) {
+            return new ForeignKeyConstraintViolationException($exception, $query);
+        }
+
         return new DriverException($exception, $query);
     }
 }

+ 32 - 0
vendor/doctrine/dbal/src/Driver/API/SQLite/UserDefinedFunctions.php

xqd xqd xqd
@@ -2,6 +2,11 @@
 
 namespace Doctrine\DBAL\Driver\API\SQLite;
 
+use Doctrine\DBAL\Platforms\AbstractPlatform;
+use Doctrine\DBAL\Platforms\SqlitePlatform;
+use Doctrine\Deprecations\Deprecation;
+
+use function array_merge;
 use function strpos;
 
 /**
@@ -11,6 +16,25 @@ use function strpos;
  */
 final class UserDefinedFunctions
 {
+    private const DEFAULT_FUNCTIONS = [
+        'sqrt' => ['callback' => [SqlitePlatform::class, 'udfSqrt'], 'numArgs' => 1],
+        'mod'  => ['callback' => [SqlitePlatform::class, 'udfMod'], 'numArgs' => 2],
+        'locate'  => ['callback' => [SqlitePlatform::class, 'udfLocate'], 'numArgs' => -1],
+    ];
+
+    /**
+     * @param callable(string, callable, int): bool                  $callback
+     * @param array<string, array{callback: callable, numArgs: int}> $additionalFunctions
+     */
+    public static function register(callable $callback, array $additionalFunctions = []): void
+    {
+        $userDefinedFunctions = array_merge(self::DEFAULT_FUNCTIONS, $additionalFunctions);
+
+        foreach ($userDefinedFunctions as $function => $data) {
+            $callback($function, $data['callback'], $data['numArgs']);
+        }
+    }
+
     /**
      * User-defined function that implements MOD().
      *
@@ -31,6 +55,14 @@ final class UserDefinedFunctions
      */
     public static function locate($str, $substr, $offset = 0): int
     {
+        Deprecation::trigger(
+            'doctrine/dbal',
+            'https://github.com/doctrine/dbal/pull/5749',
+            'Relying on DBAL\'s emulated LOCATE() function is deprecated. '
+                . 'Use INSTR() or %s::getLocateExpression() instead.',
+            AbstractPlatform::class,
+        );
+
         // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions.
         // So we have to make them compatible if an offset is given.
         if ($offset > 0) {

+ 12 - 2
vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php

xqd xqd xqd
@@ -9,6 +9,7 @@ use Doctrine\DBAL\Driver\API\IBMDB2\ExceptionConverter;
 use Doctrine\DBAL\Platforms\AbstractPlatform;
 use Doctrine\DBAL\Platforms\DB2Platform;
 use Doctrine\DBAL\Schema\DB2SchemaManager;
+use Doctrine\Deprecations\Deprecation;
 
 use function assert;
 
@@ -18,7 +19,7 @@ use function assert;
 abstract class AbstractDB2Driver implements Driver
 {
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
      */
     public function getDatabasePlatform()
     {
@@ -26,10 +27,19 @@ abstract class AbstractDB2Driver implements Driver
     }
 
     /**
-     * {@inheritdoc}
+     * {@inheritDoc}
+     *
+     * @deprecated Use {@link DB2Platform::createSchemaManager()} instead.
      */
     public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
     {
+        Deprecation::triggerIfCalledFromOutside(
+            'doctrine/dbal',
+            'https://github.com/doctrine/dbal/pull/5458',
+            'AbstractDB2Driver::getSchemaManager() is deprecated.'
+                . ' Use DB2Platform::createSchemaManager() instead.',
+        );
+
         assert($platform instanceof DB2Platform);
 
         return new DB2SchemaManager($conn, $platform);

Some files were not shown because too many files changed in this diff