mirror of
				https://github.com/linuxserver/Heimdall.git
				synced 2025-10-31 21:17:44 +09:00 
			
		
		
		
	Update to laravel 7
This commit is contained in:
		| @@ -2,8 +2,8 @@ | ||||
|  | ||||
| namespace App\Exceptions; | ||||
|  | ||||
| use Exception; | ||||
| use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | ||||
| use Throwable; | ||||
|  | ||||
| class Handler extends ExceptionHandler | ||||
| { | ||||
| @@ -22,32 +22,20 @@ class Handler extends ExceptionHandler | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $dontFlash = [ | ||||
|         'current_password', | ||||
|         'password', | ||||
|         'password_confirmation', | ||||
|     ]; | ||||
|  | ||||
|     /** | ||||
|      * Report or log an exception. | ||||
|      * Register the exception handling callbacks for the application. | ||||
|      * | ||||
|      * This is a great spot to send exceptions to Sentry, Bugsnag, etc. | ||||
|      * | ||||
|      * @param  \Exception  $exception | ||||
|      * @return void | ||||
|      */ | ||||
|     public function report(Exception $exception) | ||||
|     public function register() | ||||
|     { | ||||
|         parent::report($exception); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Render an exception into an HTTP response. | ||||
|      * | ||||
|      * @param  \Illuminate\Http\Request  $request | ||||
|      * @param  \Exception  $exception | ||||
|      * @return \Illuminate\Http\Response | ||||
|      */ | ||||
|     public function render($request, Exception $exception) | ||||
|     { | ||||
|         return parent::render($request, $exception); | ||||
|         $this->reportable(function (Throwable $e) { | ||||
|             // | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
|  | ||||
| use Illuminate\Support\Str; | ||||
|  | ||||
| function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afterunit = '') | ||||
| { | ||||
| 	$btype = ($is_drive_size === true) ? 1000 : 1024; | ||||
| @@ -11,6 +13,27 @@ function format_bytes($bytes, $is_drive_size = true, $beforeunit = '', $afteruni | ||||
|     else return(round($bytes, 0).$beforeunit.$labels[$x].$afterunit); | ||||
| } | ||||
|  | ||||
| function str_slug($title, $separator = '-', $language = 'en') | ||||
| { | ||||
|     return Str::slug($title, $separator, $language); | ||||
| } | ||||
|  | ||||
| if (! function_exists('str_is')) { | ||||
|     /** | ||||
|      * Determine if a given string matches a given pattern. | ||||
|      * | ||||
|      * @param  string|array  $pattern | ||||
|      * @param  string  $value | ||||
|      * @return bool | ||||
|      * | ||||
|      * @deprecated Str::is() should be used directly instead. Will be removed in Laravel 6.0. | ||||
|      */ | ||||
|     function str_is($pattern, $value) | ||||
|     { | ||||
|         return Str::is($pattern, $value); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function get_brightness($hex) { | ||||
|     // returns brightness value from 0 to 255 | ||||
|     // strip off any leading # | ||||
|   | ||||
| @@ -66,7 +66,7 @@ class SettingsController extends Controller | ||||
|         $user = $this->user(); | ||||
|  | ||||
|         if (!is_null($setting)) { | ||||
|             $data = Setting::getInput(); | ||||
|             $data = Setting::getInput($request); | ||||
|  | ||||
|             $setting_value = null; | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,7 @@ use Form; | ||||
| use Illuminate\Support\Facades\Auth; | ||||
| use App\User; | ||||
| use App\Search; | ||||
| use Illuminate\Http\Request; | ||||
|  | ||||
| class Setting extends Model | ||||
| { | ||||
| @@ -39,11 +40,11 @@ class Setting extends Model | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public static function getInput() | ||||
|     public static function getInput(Request $request) | ||||
|     { | ||||
|         return (object) [ | ||||
|             'value' => Input::get('value'), | ||||
|             'image' => Input::file('value'), | ||||
|             'value' => $request->input('value'), | ||||
|             'image' => $request->file('value'), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -7,12 +7,12 @@ | ||||
|     "require": { | ||||
|         "php": ">=7.1.3", | ||||
|         "fideloper/proxy": "^4.0", | ||||
|         "graham-campbell/github": "^7.5", | ||||
|         "guzzlehttp/guzzle": "^6.3", | ||||
|         "laravel/framework": "5.7.*", | ||||
|         "laravel/tinker": "~1.0", | ||||
|         "laravelcollective/html": "^5.5", | ||||
|         "php-http/guzzle6-adapter": "^1.1" | ||||
|         "graham-campbell/github": "^10.5", | ||||
|         "guzzlehttp/guzzle": "^7.4", | ||||
|         "laravel/framework": "^7.0", | ||||
|         "laravel/tinker": "^2.0", | ||||
|         "laravel/ui": "^2.4", | ||||
|         "laravelcollective/html": "^6.0" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "filp/whoops": "~2.0", | ||||
| @@ -59,6 +59,10 @@ | ||||
|     "config": { | ||||
|         "preferred-install": "dist", | ||||
|         "sort-packages": true, | ||||
|         "optimize-autoloader": true | ||||
|         "optimize-autoloader": true, | ||||
|         "allow-plugins": { | ||||
|             "kylekatarnls/update-helper": true, | ||||
|             "symfony/thanks": true | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										5263
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5263
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -14,7 +14,7 @@ return [ | ||||
|     */ | ||||
|  | ||||
|     'name' => env('APP_NAME', 'Heimdall'),   | ||||
|     'version' => '2.2.3', | ||||
|     'version' => '2.2.4', | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -164,7 +164,7 @@ return [ | ||||
|     | | ||||
|     */ | ||||
|  | ||||
|     'secure' => env('SESSION_SECURE_COOKIE', false), | ||||
|     'secure' => env('SESSION_SECURE_COOKIE', null), | ||||
|  | ||||
|     /* | ||||
|     |-------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
|                             </div> | ||||
|                             <a class="link{{ title_color($item->colour) }}"{!! $item->link_target !!} href="{{ $item->link }}"><i class="fas {{ $item->link_icon }}"></i></a> | ||||
|                         </div> | ||||
|                         @if(isset($item->id)) | ||||
|                         <a class="item-edit" href="{{ route($item->link_type.'.edit', [ $item->id ]) }}"><i class="fas fa-pencil"></i></a> | ||||
|                          | ||||
|                         @endif | ||||
|                     </section> | ||||
|   | ||||
							
								
								
									
										117
									
								
								vendor/bin/carbon
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/bin/carbon
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../nesbot/carbon/bin/carbon) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon'; | ||||
							
								
								
									
										5
									
								
								vendor/bin/carbon.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/carbon.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/carbon | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										117
									
								
								vendor/bin/commonmark
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/bin/commonmark
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../league/commonmark/bin/commonmark) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/league/commonmark/bin/commonmark'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/league/commonmark/bin/commonmark'; | ||||
							
								
								
									
										5
									
								
								vendor/bin/commonmark.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/commonmark.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/commonmark | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										117
									
								
								vendor/bin/patch-type-declarations
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/bin/patch-type-declarations
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../symfony/error-handler/Resources/bin/patch-type-declarations) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/error-handler/Resources/bin/patch-type-declarations'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/symfony/error-handler/Resources/bin/patch-type-declarations'; | ||||
							
								
								
									
										5
									
								
								vendor/bin/patch-type-declarations.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/patch-type-declarations.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/patch-type-declarations | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										118
									
								
								vendor/bin/php-parse
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								vendor/bin/php-parse
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,117 @@ | ||||
| ../nikic/php-parser/bin/php-parse | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../nikic/php-parser/bin/php-parse) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'; | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/bin/php-parse.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/php-parse.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/php-parse | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										118
									
								
								vendor/bin/psysh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								vendor/bin/psysh
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,117 @@ | ||||
| ../psy/psysh/bin/psysh | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../psy/psysh/bin/psysh) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/psy/psysh/bin/psysh'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/psy/psysh/bin/psysh'; | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/bin/psysh.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/psysh.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/psysh | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										118
									
								
								vendor/bin/var-dump-server
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								vendor/bin/var-dump-server
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,117 @@ | ||||
| ../symfony/var-dumper/Resources/bin/var-dump-server | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../symfony/var-dumper/Resources/bin/var-dump-server) | ||||
|  * 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_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { | ||||
|         include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'); | ||||
|         exit(0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'; | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/bin/var-dump-server.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/var-dump-server.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/var-dump-server | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										415
									
								
								vendor/brick/math/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								vendor/brick/math/CHANGELOG.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,415 @@ | ||||
| # Changelog | ||||
|  | ||||
| All notable changes to this project will be documented in this file. | ||||
|  | ||||
| ## [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) | ||||
|  | ||||
| ## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20 | ||||
|  | ||||
| 🐛 **Bug fix** | ||||
|  | ||||
| - Incorrect results could be returned when using the BCMath calculator, with a default scale set with `bcscale()`, on PHP >= 7.2 (#55). | ||||
|  | ||||
| ## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19 | ||||
|  | ||||
| ✨ New features | ||||
|  | ||||
| - `BigInteger::not()` returns the bitwise `NOT` value | ||||
|  | ||||
| 🐛 **Bug fixes** | ||||
|  | ||||
| - `BigInteger::toBytes()` could return an incorrect binary representation for some numbers | ||||
| - The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available | ||||
|  | ||||
| ## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18 | ||||
|  | ||||
| 👌 **Improvements** | ||||
|  | ||||
| - `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal` | ||||
|  | ||||
| 💥 **Breaking changes** | ||||
|  | ||||
| - Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead | ||||
| - Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead | ||||
|  | ||||
| ## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19 | ||||
|  | ||||
| 🐛 **Bug fix** | ||||
|  | ||||
| - `BigInteger::toBytes()` could return an incorrect binary representation for some numbers | ||||
| - The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available | ||||
|  | ||||
| ## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18 | ||||
|  | ||||
| 🚑 **Critical fix** | ||||
|  | ||||
| - This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle. | ||||
|  | ||||
| ✨ **New features** | ||||
|  | ||||
| - `BigInteger::modInverse()` calculates a modular multiplicative inverse | ||||
| - `BigInteger::fromBytes()` creates a `BigInteger` from a byte string | ||||
| - `BigInteger::toBytes()` converts a `BigInteger` to a byte string | ||||
| - `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length | ||||
| - `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds | ||||
|  | ||||
| 💩 **Deprecations** | ||||
|  | ||||
| - `BigInteger::powerMod()` is now deprecated in favour of `modPow()` | ||||
|  | ||||
| ## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15 | ||||
|  | ||||
| 🐛 **Fixes** | ||||
|  | ||||
| - added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable` | ||||
|  | ||||
| ⚡️ **Optimizations** | ||||
|  | ||||
| - additional optimization in `BigInteger::remainder()` | ||||
|  | ||||
| ## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18 | ||||
|  | ||||
| ✨ **New features** | ||||
|  | ||||
| - `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit | ||||
|  | ||||
| ## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16 | ||||
|  | ||||
| ✨ **New features** | ||||
|  | ||||
| - `BigInteger::isEven()` tests whether the number is even | ||||
| - `BigInteger::isOdd()` tests whether the number is odd | ||||
| - `BigInteger::testBit()` tests if a bit is set | ||||
| - `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number | ||||
|  | ||||
| ## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03 | ||||
|  | ||||
| 🛠️ **Maintenance release** | ||||
|  | ||||
| Classes are now annotated for better static analysis with [psalm](https://psalm.dev/). | ||||
|  | ||||
| This is a maintenance release: no bug fixes, no new features, no breaking changes. | ||||
|  | ||||
| ## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23 | ||||
|  | ||||
| ✨ **New feature** | ||||
|  | ||||
| `BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto. | ||||
|  | ||||
| ## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21 | ||||
|  | ||||
| ✨ **New feature** | ||||
|  | ||||
| `BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different. | ||||
|  | ||||
| ## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08 | ||||
|  | ||||
| ⚡️ **Performance improvements** | ||||
|  | ||||
| A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24. | ||||
|  | ||||
| ## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25 | ||||
|  | ||||
| 🐛 **Bug fixes** | ||||
|  | ||||
| - `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected) | ||||
|  | ||||
| ✨ **New features** | ||||
|  | ||||
| - `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet | ||||
| - `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number | ||||
|  | ||||
| These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation. | ||||
|  | ||||
| 💩 **Deprecations** | ||||
|  | ||||
| - `BigInteger::parse()` is now deprecated in favour of `fromBase()` | ||||
|  | ||||
| `BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences: | ||||
|  | ||||
| - the `$base` parameter is required, it does not default to `10` | ||||
| - it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed | ||||
|  | ||||
| ## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20 | ||||
|  | ||||
| **Improvements** | ||||
|  | ||||
| - Safer conversion from `float` when using custom locales | ||||
| - **Much faster** `NativeCalculator` implementation 🚀 | ||||
|  | ||||
| You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before. | ||||
|  | ||||
| ## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11 | ||||
|  | ||||
| **New method** | ||||
|  | ||||
| `BigNumber::sum()` returns the sum of one or more numbers. | ||||
|  | ||||
| ## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12 | ||||
|  | ||||
| **Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20). | ||||
|  | ||||
| Thanks @manowark 👍 | ||||
|  | ||||
| ## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07 | ||||
|  | ||||
| **New method** | ||||
|  | ||||
| `BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale. | ||||
|  | ||||
| ## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06 | ||||
|  | ||||
| **New method** | ||||
|  | ||||
| `BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k). | ||||
|  | ||||
| **New exception** | ||||
|  | ||||
| `NegativeNumberException` is thrown when calling `sqrt()` on a negative number. | ||||
|  | ||||
| ## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08 | ||||
|  | ||||
| **Performance update** | ||||
|  | ||||
| - Further improvement of `toInt()` performance | ||||
| - `NativeCalculator` can now perform some multiplications more efficiently | ||||
|  | ||||
| ## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07 | ||||
|  | ||||
| Performance optimization of `toInt()` methods. | ||||
|  | ||||
| ## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13 | ||||
|  | ||||
| **Breaking changes** | ||||
|  | ||||
| The following deprecated methods have been removed. Use the new method name instead: | ||||
|  | ||||
| | Method removed | Replacement method | | ||||
| | --- | --- | | ||||
| | `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` | | ||||
| | `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` | | ||||
|  | ||||
| --- | ||||
|  | ||||
| **New features** | ||||
|  | ||||
| `BigInteger` has been augmented with 5 new methods for bitwise operations: | ||||
|  | ||||
| | New method | Description | | ||||
| | --- | --- | | ||||
| | `and()` | performs a bitwise `AND` operation on two numbers | | ||||
| | `or()` | performs a bitwise `OR` operation on two numbers | | ||||
| | `xor()` | performs a bitwise `XOR` operation on two numbers | | ||||
| | `shiftedLeft()` | returns the number shifted left by a number of bits | | ||||
| | `shiftedRight()` | returns the number shifted right by a number of bits | | ||||
|  | ||||
| Thanks to @DASPRiD 👍 | ||||
|  | ||||
| ## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20 | ||||
|  | ||||
| **New method:** `BigDecimal::hasNonZeroFractionalPart()` | ||||
|  | ||||
| **Renamed/deprecated methods:** | ||||
|  | ||||
| - `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated | ||||
| - `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated | ||||
|  | ||||
| ## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21 | ||||
|  | ||||
| **Performance update** | ||||
|  | ||||
| `BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available. | ||||
|  | ||||
| ## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01 | ||||
|  | ||||
| This is a maintenance release, no code has been changed. | ||||
|  | ||||
| - When installed with `--no-dev`, the autoloader does not autoload tests anymore | ||||
| - Tests and other files unnecessary for production are excluded from the dist package | ||||
|  | ||||
| This will help make installations more compact. | ||||
|  | ||||
| ## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02 | ||||
|  | ||||
| Methods renamed: | ||||
|  | ||||
| - `BigNumber:sign()` has been renamed to `getSign()` | ||||
| - `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()` | ||||
| - `BigDecimal::scale()` has been renamed to `getScale()` | ||||
| - `BigDecimal::integral()` has been renamed to `getIntegral()` | ||||
| - `BigDecimal::fraction()` has been renamed to `getFraction()` | ||||
| - `BigRational::numerator()` has been renamed to `getNumerator()` | ||||
| - `BigRational::denominator()` has been renamed to `getDenominator()` | ||||
|  | ||||
| Classes renamed: | ||||
|  | ||||
| - `ArithmeticException` has been renamed to `MathException` | ||||
|  | ||||
| ## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02 | ||||
|  | ||||
| The base class for all exceptions is now `MathException`. | ||||
| `ArithmeticException` has been deprecated, and will be removed in 0.7.0. | ||||
|  | ||||
| ## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02 | ||||
|  | ||||
| A number of methods have been renamed: | ||||
|  | ||||
| - `BigNumber:sign()` is deprecated; use `getSign()` instead | ||||
| - `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead | ||||
| - `BigDecimal::scale()` is deprecated; use `getScale()` instead | ||||
| - `BigDecimal::integral()` is deprecated; use `getIntegral()` instead | ||||
| - `BigDecimal::fraction()` is deprecated; use `getFraction()` instead | ||||
| - `BigRational::numerator()` is deprecated; use `getNumerator()` instead | ||||
| - `BigRational::denominator()` is deprecated; use `getDenominator()` instead | ||||
|  | ||||
| The old methods will be removed in version 0.7.0. | ||||
|  | ||||
| ## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25 | ||||
|  | ||||
| - Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5` | ||||
| - Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead | ||||
| - Method `BigNumber::toInteger()` has been renamed to `toInt()` | ||||
|  | ||||
| ## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17 | ||||
|  | ||||
| `BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php). | ||||
| The JSON output is always a string. | ||||
|  | ||||
| ## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31 | ||||
|  | ||||
| This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. | ||||
|  | ||||
| ## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06 | ||||
|  | ||||
| The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again. | ||||
|  | ||||
| ## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05 | ||||
|  | ||||
| **New method: `BigNumber::toScale()`** | ||||
|  | ||||
| This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary. | ||||
|  | ||||
| ## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04 | ||||
|  | ||||
| **New features** | ||||
| - Common `BigNumber` interface for all classes, with the following methods: | ||||
|   - `sign()` and derived methods (`isZero()`, `isPositive()`, ...) | ||||
|   - `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types | ||||
|   - `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods | ||||
|   - `toInteger()` and `toFloat()` conversion methods to native types | ||||
| - Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type | ||||
| - New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits | ||||
| - New methods: `BigRational::quotient()` and `remainder()` | ||||
| - Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException` | ||||
| - Factory methods `zero()`, `one()` and `ten()` available in all classes | ||||
| - Rounding mode reintroduced in `BigInteger::dividedBy()` | ||||
|  | ||||
| This release also comes with many performance improvements. | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Breaking changes** | ||||
| - `BigInteger`: | ||||
|   - `getSign()` is renamed to `sign()` | ||||
|   - `toString()` is renamed to `toBase()` | ||||
|   - `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour | ||||
| - `BigDecimal`: | ||||
|   - `getSign()` is renamed to `sign()` | ||||
|   - `getUnscaledValue()` is renamed to `unscaledValue()` | ||||
|   - `getScale()` is renamed to `scale()` | ||||
|   - `getIntegral()` is renamed to `integral()` | ||||
|   - `getFraction()` is renamed to `fraction()` | ||||
|   - `divideAndRemainder()` is renamed to `quotientAndRemainder()` | ||||
|   - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode | ||||
|   - `toBigInteger()` does not accept a `$roundingMode` parameter any more | ||||
|   - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour | ||||
| - `BigRational`: | ||||
|   - `getSign()` is renamed to `sign()` | ||||
|   - `getNumerator()` is renamed to  `numerator()` | ||||
|   - `getDenominator()` is renamed to  `denominator()` | ||||
|   - `of()` is renamed to `nd()`, while `parse()` is renamed to `of()` | ||||
| - Miscellaneous: | ||||
|   - `ArithmeticException` is moved to an `Exception\` sub-namespace | ||||
|   - `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException` | ||||
|  | ||||
| ## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31 | ||||
|  | ||||
| Backport of two bug fixes from the 0.5 branch: | ||||
| - `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected | ||||
| - Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. | ||||
|  | ||||
| ## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16 | ||||
|  | ||||
| New method: `BigDecimal::stripTrailingZeros()` | ||||
|  | ||||
| ## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12 | ||||
|  | ||||
| Introducing a `BigRational` class, to perform calculations on fractions of any size. | ||||
|  | ||||
| ## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12 | ||||
|  | ||||
| Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`. | ||||
|  | ||||
| `BigInteger::dividedBy()` now always returns the quotient of the division. | ||||
|  | ||||
| ## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31 | ||||
|  | ||||
| Backport of two bug fixes from the 0.5 branch: | ||||
|  | ||||
| - `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected | ||||
| - Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. | ||||
|  | ||||
| ## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11 | ||||
|  | ||||
| New methods: | ||||
| - `BigInteger::remainder()` returns the remainder of a division only | ||||
| - `BigInteger::gcd()` returns the greatest common divisor of two numbers | ||||
|  | ||||
| ## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07 | ||||
|  | ||||
| Fix `toString()` not handling negative numbers. | ||||
|  | ||||
| ## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07 | ||||
|  | ||||
| `BigInteger` and `BigDecimal` now have a `getSign()` method that returns: | ||||
| - `-1` if the number is negative | ||||
| - `0` if the number is zero | ||||
| - `1` if the number is positive | ||||
|  | ||||
| ## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05 | ||||
|  | ||||
| Minor performance improvements | ||||
|  | ||||
| ## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04 | ||||
|  | ||||
| The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`. | ||||
|  | ||||
| ## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04 | ||||
|  | ||||
| Stronger immutability guarantee for `BigInteger` and `BigDecimal`. | ||||
|  | ||||
| So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that. | ||||
|  | ||||
| ## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02 | ||||
|  | ||||
| Added `BigDecimal::divideAndRemainder()` | ||||
|  | ||||
| ## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22 | ||||
|  | ||||
| - `min()` and `max()` do not accept an `array` any more, but a variable number of parameters | ||||
| - **minimum PHP version is now 5.6** | ||||
| - continuous integration with PHP 7 | ||||
|  | ||||
| ## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01 | ||||
|  | ||||
| - Added `BigInteger::power()` | ||||
| - Added HHVM support | ||||
|  | ||||
| ## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31 | ||||
|  | ||||
| First beta release. | ||||
|  | ||||
							
								
								
									
										20
									
								
								vendor/brick/math/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/brick/math/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2013-present Benjamin Morel | ||||
|  | ||||
| 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. | ||||
							
								
								
									
										17
									
								
								vendor/brick/math/SECURITY.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/brick/math/SECURITY.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # 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. | ||||
							
								
								
									
										35
									
								
								vendor/brick/math/composer.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/brick/math/composer.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| { | ||||
|     "name": "brick/math", | ||||
|     "description": "Arbitrary-precision arithmetic library", | ||||
|     "type": "library", | ||||
|     "keywords": [ | ||||
|         "Brick", | ||||
|         "Math", | ||||
|         "Arbitrary-precision", | ||||
|         "Arithmetic", | ||||
|         "BigInteger", | ||||
|         "BigDecimal", | ||||
|         "BigRational", | ||||
|         "Bignum" | ||||
|     ], | ||||
|     "license": "MIT", | ||||
|     "require": { | ||||
|         "php": "^7.1 || ^8.0", | ||||
|         "ext-json": "*" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", | ||||
|         "php-coveralls/php-coveralls": "^2.2", | ||||
|         "vimeo/psalm": "4.9.2" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "Brick\\Math\\": "src/" | ||||
|         } | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { | ||||
|             "Brick\\Math\\Tests\\": "tests/" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										895
									
								
								vendor/brick/math/src/BigDecimal.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										895
									
								
								vendor/brick/math/src/BigDecimal.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,895 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math; | ||||
|  | ||||
| use Brick\Math\Exception\DivisionByZeroException; | ||||
| use Brick\Math\Exception\MathException; | ||||
| use Brick\Math\Exception\NegativeNumberException; | ||||
| use Brick\Math\Internal\Calculator; | ||||
|  | ||||
| /** | ||||
|  * Immutable, arbitrary-precision signed decimal numbers. | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| final class BigDecimal extends BigNumber | ||||
| { | ||||
|     /** | ||||
|      * The unscaled value of this decimal number. | ||||
|      * | ||||
|      * 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; | ||||
|  | ||||
|     /** | ||||
|      * The scale (number of digits after the decimal point) of this decimal number. | ||||
|      * | ||||
|      * This must be zero or more. | ||||
|      * | ||||
|      * @var int | ||||
|      */ | ||||
|     private $scale; | ||||
|  | ||||
|     /** | ||||
|      * Protected constructor. Use a factory method to obtain an instance. | ||||
|      * | ||||
|      * @param string $value The unscaled value, validated. | ||||
|      * @param int    $scale The scale, validated. | ||||
|      */ | ||||
|     protected function __construct(string $value, int $scale = 0) | ||||
|     { | ||||
|         $this->value = $value; | ||||
|         $this->scale = $scale; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a BigDecimal of the given value. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $value | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @throws MathException If the value cannot be converted to a BigDecimal. | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function of($value) : BigNumber | ||||
|     { | ||||
|         return parent::of($value)->toBigDecimal(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a BigDecimal from an unscaled value and a scale. | ||||
|      * | ||||
|      * Example: `(12345, 3)` will result in the BigDecimal `12.345`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger. | ||||
|      * @param int                        $scale The scale of the number, positive or zero. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If the scale is negative. | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal | ||||
|     { | ||||
|         if ($scale < 0) { | ||||
|             throw new \InvalidArgumentException('The scale cannot be negative.'); | ||||
|         } | ||||
|  | ||||
|         return new BigDecimal((string) BigInteger::of($value), $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigDecimal representing zero, with a scale of zero. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function zero() : BigDecimal | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigDecimal|null $zero | ||||
|          */ | ||||
|         static $zero; | ||||
|  | ||||
|         if ($zero === null) { | ||||
|             $zero = new BigDecimal('0'); | ||||
|         } | ||||
|  | ||||
|         return $zero; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigDecimal representing one, with a scale of zero. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function one() : BigDecimal | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigDecimal|null $one | ||||
|          */ | ||||
|         static $one; | ||||
|  | ||||
|         if ($one === null) { | ||||
|             $one = new BigDecimal('1'); | ||||
|         } | ||||
|  | ||||
|         return $one; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigDecimal representing ten, with a scale of zero. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function ten() : BigDecimal | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigDecimal|null $ten | ||||
|          */ | ||||
|         static $ten; | ||||
|  | ||||
|         if ($ten === null) { | ||||
|             $ten = new BigDecimal('10'); | ||||
|         } | ||||
|  | ||||
|         return $ten; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the sum of this number and the given one. | ||||
|      * | ||||
|      * The result has a scale of `max($this->scale, $that->scale)`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The result. | ||||
|      * | ||||
|      * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. | ||||
|      */ | ||||
|     public function plus($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->value === '0' && $that->scale <= $this->scale) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($this->value === '0' && $this->scale <= $that->scale) { | ||||
|             return $that; | ||||
|         } | ||||
|  | ||||
|         [$a, $b] = $this->scaleValues($this, $that); | ||||
|  | ||||
|         $value = Calculator::get()->add($a, $b); | ||||
|         $scale = $this->scale > $that->scale ? $this->scale : $that->scale; | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the difference of this number and the given one. | ||||
|      * | ||||
|      * The result has a scale of `max($this->scale, $that->scale)`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The result. | ||||
|      * | ||||
|      * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. | ||||
|      */ | ||||
|     public function minus($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->value === '0' && $that->scale <= $this->scale) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         [$a, $b] = $this->scaleValues($this, $that); | ||||
|  | ||||
|         $value = Calculator::get()->sub($a, $b); | ||||
|         $scale = $this->scale > $that->scale ? $this->scale : $that->scale; | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the product of this number and the given one. | ||||
|      * | ||||
|      * The result has a scale of `$this->scale + $that->scale`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The result. | ||||
|      * | ||||
|      * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. | ||||
|      */ | ||||
|     public function multipliedBy($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->value === '1' && $that->scale === 0) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($this->value === '1' && $this->scale === 0) { | ||||
|             return $that; | ||||
|         } | ||||
|  | ||||
|         $value = Calculator::get()->mul($this->value, $that->value); | ||||
|         $scale = $this->scale + $that->scale; | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the result of the division of this number by the given one, at the given scale. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that         The divisor. | ||||
|      * @param int|null                   $scale        The desired scale, or null to use the scale of this number. | ||||
|      * @param int                        $roundingMode An optional rounding mode. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If the scale or rounding mode is invalid. | ||||
|      * @throws MathException             If the number is invalid, is zero, or rounding was necessary. | ||||
|      */ | ||||
|     public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->isZero()) { | ||||
|             throw DivisionByZeroException::divisionByZero(); | ||||
|         } | ||||
|  | ||||
|         if ($scale === null) { | ||||
|             $scale = $this->scale; | ||||
|         } elseif ($scale < 0) { | ||||
|             throw new \InvalidArgumentException('Scale cannot be negative.'); | ||||
|         } | ||||
|  | ||||
|         if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         $p = $this->valueWithMinScale($that->scale + $scale); | ||||
|         $q = $that->valueWithMinScale($this->scale - $scale); | ||||
|  | ||||
|         $result = Calculator::get()->divRound($p, $q, $roundingMode); | ||||
|  | ||||
|         return new BigDecimal($result, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the exact result of the division of this number by the given one. | ||||
|      * | ||||
|      * The scale of the result is automatically calculated to fit all the fraction digits. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The result. | ||||
|      * | ||||
|      * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero, | ||||
|      *                       or the result yields an infinite number of digits. | ||||
|      */ | ||||
|     public function exactlyDividedBy($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->value === '0') { | ||||
|             throw DivisionByZeroException::divisionByZero(); | ||||
|         } | ||||
|  | ||||
|         [, $b] = $this->scaleValues($this, $that); | ||||
|  | ||||
|         $d = \rtrim($b, '0'); | ||||
|         $scale = \strlen($b) - \strlen($d); | ||||
|  | ||||
|         $calculator = Calculator::get(); | ||||
|  | ||||
|         foreach ([5, 2] as $prime) { | ||||
|             for (;;) { | ||||
|                 $lastDigit = (int) $d[-1]; | ||||
|  | ||||
|                 if ($lastDigit % $prime !== 0) { | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 $d = $calculator->divQ($d, (string) $prime); | ||||
|                 $scale++; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $this->dividedBy($that, $scale)->stripTrailingZeros(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns this number exponentiated to the given value. | ||||
|      * | ||||
|      * The result has a scale of `$this->scale * $exponent`. | ||||
|      * | ||||
|      * @param int $exponent The exponent. | ||||
|      * | ||||
|      * @return BigDecimal The result. | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. | ||||
|      */ | ||||
|     public function power(int $exponent) : BigDecimal | ||||
|     { | ||||
|         if ($exponent === 0) { | ||||
|             return BigDecimal::one(); | ||||
|         } | ||||
|  | ||||
|         if ($exponent === 1) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { | ||||
|             throw new \InvalidArgumentException(\sprintf( | ||||
|                 'The exponent %d is not in the range 0 to %d.', | ||||
|                 $exponent, | ||||
|                 Calculator::MAX_POWER | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient of the division of this number by this given one. | ||||
|      * | ||||
|      * The quotient has a scale of `0`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The quotient. | ||||
|      * | ||||
|      * @throws MathException If the divisor is not a valid decimal number, or is zero. | ||||
|      */ | ||||
|     public function quotient($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->isZero()) { | ||||
|             throw DivisionByZeroException::divisionByZero(); | ||||
|         } | ||||
|  | ||||
|         $p = $this->valueWithMinScale($that->scale); | ||||
|         $q = $that->valueWithMinScale($this->scale); | ||||
|  | ||||
|         $quotient = Calculator::get()->divQ($p, $q); | ||||
|  | ||||
|         return new BigDecimal($quotient, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the remainder of the division of this number by this given one. | ||||
|      * | ||||
|      * The remainder has a scale of `max($this->scale, $that->scale)`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The remainder. | ||||
|      * | ||||
|      * @throws MathException If the divisor is not a valid decimal number, or is zero. | ||||
|      */ | ||||
|     public function remainder($that) : BigDecimal | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->isZero()) { | ||||
|             throw DivisionByZeroException::divisionByZero(); | ||||
|         } | ||||
|  | ||||
|         $p = $this->valueWithMinScale($that->scale); | ||||
|         $q = $that->valueWithMinScale($this->scale); | ||||
|  | ||||
|         $remainder = Calculator::get()->divR($p, $q); | ||||
|  | ||||
|         $scale = $this->scale > $that->scale ? $this->scale : $that->scale; | ||||
|  | ||||
|         return new BigDecimal($remainder, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient and remainder of the division of this number by the given one. | ||||
|      * | ||||
|      * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal[] An array containing the quotient and the remainder. | ||||
|      * | ||||
|      * @throws MathException If the divisor is not a valid decimal number, or is zero. | ||||
|      */ | ||||
|     public function quotientAndRemainder($that) : array | ||||
|     { | ||||
|         $that = BigDecimal::of($that); | ||||
|  | ||||
|         if ($that->isZero()) { | ||||
|             throw DivisionByZeroException::divisionByZero(); | ||||
|         } | ||||
|  | ||||
|         $p = $this->valueWithMinScale($that->scale); | ||||
|         $q = $that->valueWithMinScale($this->scale); | ||||
|  | ||||
|         [$quotient, $remainder] = Calculator::get()->divQR($p, $q); | ||||
|  | ||||
|         $scale = $this->scale > $that->scale ? $this->scale : $that->scale; | ||||
|  | ||||
|         $quotient = new BigDecimal($quotient, 0); | ||||
|         $remainder = new BigDecimal($remainder, $scale); | ||||
|  | ||||
|         return [$quotient, $remainder]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the square root of this number, rounded down to the given number of decimals. | ||||
|      * | ||||
|      * @param int $scale | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If the scale is negative. | ||||
|      * @throws NegativeNumberException If this number is negative. | ||||
|      */ | ||||
|     public function sqrt(int $scale) : BigDecimal | ||||
|     { | ||||
|         if ($scale < 0) { | ||||
|             throw new \InvalidArgumentException('Scale cannot be negative.'); | ||||
|         } | ||||
|  | ||||
|         if ($this->value === '0') { | ||||
|             return new BigDecimal('0', $scale); | ||||
|         } | ||||
|  | ||||
|         if ($this->value[0] === '-') { | ||||
|             throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); | ||||
|         } | ||||
|  | ||||
|         $value = $this->value; | ||||
|         $addDigits = 2 * $scale - $this->scale; | ||||
|  | ||||
|         if ($addDigits > 0) { | ||||
|             // add zeros | ||||
|             $value .= \str_repeat('0', $addDigits); | ||||
|         } elseif ($addDigits < 0) { | ||||
|             // trim digits | ||||
|             if (-$addDigits >= \strlen($this->value)) { | ||||
|                 // requesting a scale too low, will always yield a zero result | ||||
|                 return new BigDecimal('0', $scale); | ||||
|             } | ||||
|  | ||||
|             $value = \substr($value, 0, $addDigits); | ||||
|         } | ||||
|  | ||||
|         $value = Calculator::get()->sqrt($value); | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a copy of this BigDecimal with the decimal point moved $n places to the left. | ||||
|      * | ||||
|      * @param int $n | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      */ | ||||
|     public function withPointMovedLeft(int $n) : BigDecimal | ||||
|     { | ||||
|         if ($n === 0) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($n < 0) { | ||||
|             return $this->withPointMovedRight(-$n); | ||||
|         } | ||||
|  | ||||
|         return new BigDecimal($this->value, $this->scale + $n); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a copy of this BigDecimal with the decimal point moved $n places to the right. | ||||
|      * | ||||
|      * @param int $n | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      */ | ||||
|     public function withPointMovedRight(int $n) : BigDecimal | ||||
|     { | ||||
|         if ($n === 0) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($n < 0) { | ||||
|             return $this->withPointMovedLeft(-$n); | ||||
|         } | ||||
|  | ||||
|         $value = $this->value; | ||||
|         $scale = $this->scale - $n; | ||||
|  | ||||
|         if ($scale < 0) { | ||||
|             if ($value !== '0') { | ||||
|                 $value .= \str_repeat('0', -$scale); | ||||
|             } | ||||
|             $scale = 0; | ||||
|         } | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      */ | ||||
|     public function stripTrailingZeros() : BigDecimal | ||||
|     { | ||||
|         if ($this->scale === 0) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         $trimmedValue = \rtrim($this->value, '0'); | ||||
|  | ||||
|         if ($trimmedValue === '') { | ||||
|             return BigDecimal::zero(); | ||||
|         } | ||||
|  | ||||
|         $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue); | ||||
|  | ||||
|         if ($trimmableZeros === 0) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         if ($trimmableZeros > $this->scale) { | ||||
|             $trimmableZeros = $this->scale; | ||||
|         } | ||||
|  | ||||
|         $value = \substr($this->value, 0, -$trimmableZeros); | ||||
|         $scale = $this->scale - $trimmableZeros; | ||||
|  | ||||
|         return new BigDecimal($value, $scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the absolute value of this number. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      */ | ||||
|     public function abs() : BigDecimal | ||||
|     { | ||||
|         return $this->isNegative() ? $this->negated() : $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the negated value of this number. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      */ | ||||
|     public function negated() : BigDecimal | ||||
|     { | ||||
|         return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function compareTo($that) : int | ||||
|     { | ||||
|         $that = BigNumber::of($that); | ||||
|  | ||||
|         if ($that instanceof BigInteger) { | ||||
|             $that = $that->toBigDecimal(); | ||||
|         } | ||||
|  | ||||
|         if ($that instanceof BigDecimal) { | ||||
|             [$a, $b] = $this->scaleValues($this, $that); | ||||
|  | ||||
|             return Calculator::get()->cmp($a, $b); | ||||
|         } | ||||
|  | ||||
|         return - $that->compareTo($this); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function getSign() : int | ||||
|     { | ||||
|         return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return BigInteger | ||||
|      */ | ||||
|     public function getUnscaledValue() : BigInteger | ||||
|     { | ||||
|         return BigInteger::create($this->value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return int | ||||
|      */ | ||||
|     public function getScale() : int | ||||
|     { | ||||
|         return $this->scale; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a string representing the integral part of this decimal number. | ||||
|      * | ||||
|      * Example: `-123.456` => `-123`. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getIntegralPart() : string | ||||
|     { | ||||
|         if ($this->scale === 0) { | ||||
|             return $this->value; | ||||
|         } | ||||
|  | ||||
|         $value = $this->getUnscaledValueWithLeadingZeros(); | ||||
|  | ||||
|         return \substr($value, 0, -$this->scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a string representing the fractional part of this decimal number. | ||||
|      * | ||||
|      * If the scale is zero, an empty string is returned. | ||||
|      * | ||||
|      * Examples: `-123.456` => '456', `123` => ''. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getFractionalPart() : string | ||||
|     { | ||||
|         if ($this->scale === 0) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         $value = $this->getUnscaledValueWithLeadingZeros(); | ||||
|  | ||||
|         return \substr($value, -$this->scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether this decimal number has a non-zero fractional part. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function hasNonZeroFractionalPart() : bool | ||||
|     { | ||||
|         return $this->getFractionalPart() !== \str_repeat('0', $this->scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigInteger() : BigInteger | ||||
|     { | ||||
|         $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); | ||||
|  | ||||
|         return BigInteger::create($zeroScaleDecimal->value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigDecimal() : BigDecimal | ||||
|     { | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigRational() : BigRational | ||||
|     { | ||||
|         $numerator = BigInteger::create($this->value); | ||||
|         $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale)); | ||||
|  | ||||
|         return BigRational::create($numerator, $denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal | ||||
|     { | ||||
|         if ($scale === $this->scale) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toInt() : int | ||||
|     { | ||||
|         return $this->toBigInteger()->toInt(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toFloat() : float | ||||
|     { | ||||
|         return (float) (string) $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function __toString() : string | ||||
|     { | ||||
|         if ($this->scale === 0) { | ||||
|             return $this->value; | ||||
|         } | ||||
|  | ||||
|         $value = $this->getUnscaledValueWithLeadingZeros(); | ||||
|  | ||||
|         return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is required for serializing the object and SHOULD NOT be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * | ||||
|      * @return array{value: string, scale: int} | ||||
|      */ | ||||
|     public function __serialize(): array | ||||
|     { | ||||
|         return ['value' => $this->value, 'scale' => $this->scale]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is only here to allow unserializing the object and cannot be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * @psalm-suppress RedundantPropertyInitializationCheck | ||||
|      * | ||||
|      * @param array{value: string, scale: int} $data | ||||
|      * | ||||
|      * @return void | ||||
|      * | ||||
|      * @throws \LogicException | ||||
|      */ | ||||
|     public function __unserialize(array $data): void | ||||
|     { | ||||
|         if (isset($this->value)) { | ||||
|             throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); | ||||
|         } | ||||
|  | ||||
|         $this->value = $data['value']; | ||||
|         $this->scale = $data['scale']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is required by interface Serializable and SHOULD NOT be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function serialize() : string | ||||
|     { | ||||
|         return $this->value . ':' . $this->scale; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is only here to implement interface Serializable and cannot be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * @psalm-suppress RedundantPropertyInitializationCheck | ||||
|      * | ||||
|      * @param string $value | ||||
|      * | ||||
|      * @return void | ||||
|      * | ||||
|      * @throws \LogicException | ||||
|      */ | ||||
|     public function unserialize($value) : void | ||||
|     { | ||||
|         if (isset($this->value)) { | ||||
|             throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); | ||||
|         } | ||||
|  | ||||
|         [$value, $scale] = \explode(':', $value); | ||||
|  | ||||
|         $this->value = $value; | ||||
|         $this->scale = (int) $scale; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Puts the internal values of the given decimal numbers on the same scale. | ||||
|      * | ||||
|      * @param BigDecimal $x The first decimal number. | ||||
|      * @param BigDecimal $y The second decimal number. | ||||
|      * | ||||
|      * @return array{string, string} The scaled integer values of $x and $y. | ||||
|      */ | ||||
|     private function scaleValues(BigDecimal $x, BigDecimal $y) : array | ||||
|     { | ||||
|         $a = $x->value; | ||||
|         $b = $y->value; | ||||
|  | ||||
|         if ($b !== '0' && $x->scale > $y->scale) { | ||||
|             $b .= \str_repeat('0', $x->scale - $y->scale); | ||||
|         } elseif ($a !== '0' && $x->scale < $y->scale) { | ||||
|             $a .= \str_repeat('0', $y->scale - $x->scale); | ||||
|         } | ||||
|  | ||||
|         return [$a, $b]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $scale | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function valueWithMinScale(int $scale) : string | ||||
|     { | ||||
|         $value = $this->value; | ||||
|  | ||||
|         if ($this->value !== '0' && $scale > $this->scale) { | ||||
|             $value .= \str_repeat('0', $scale - $this->scale); | ||||
|         } | ||||
|  | ||||
|         return $value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds leading zeros if necessary to the unscaled value to represent the full decimal number. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function getUnscaledValueWithLeadingZeros() : string | ||||
|     { | ||||
|         $value = $this->value; | ||||
|         $targetLength = $this->scale + 1; | ||||
|         $negative = ($value[0] === '-'); | ||||
|         $length = \strlen($value); | ||||
|  | ||||
|         if ($negative) { | ||||
|             $length--; | ||||
|         } | ||||
|  | ||||
|         if ($length >= $targetLength) { | ||||
|             return $this->value; | ||||
|         } | ||||
|  | ||||
|         if ($negative) { | ||||
|             $value = \substr($value, 1); | ||||
|         } | ||||
|  | ||||
|         $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); | ||||
|  | ||||
|         if ($negative) { | ||||
|             $value = '-' . $value; | ||||
|         } | ||||
|  | ||||
|         return $value; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1184
									
								
								vendor/brick/math/src/BigInteger.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1184
									
								
								vendor/brick/math/src/BigInteger.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										572
									
								
								vendor/brick/math/src/BigNumber.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								vendor/brick/math/src/BigNumber.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,572 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math; | ||||
|  | ||||
| use Brick\Math\Exception\DivisionByZeroException; | ||||
| use Brick\Math\Exception\MathException; | ||||
| use Brick\Math\Exception\NumberFormatException; | ||||
| use Brick\Math\Exception\RoundingNecessaryException; | ||||
|  | ||||
| /** | ||||
|  * Common interface for arbitrary-precision rational numbers. | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| abstract class BigNumber implements \Serializable, \JsonSerializable | ||||
| { | ||||
|     /** | ||||
|      * The regular expression used to parse integer, decimal and rational numbers. | ||||
|      */ | ||||
|     private const PARSE_REGEXP = | ||||
|         '/^' . | ||||
|             '(?<sign>[\-\+])?' . | ||||
|             '(?:' . | ||||
|                 '(?:' . | ||||
|                     '(?<integral>[0-9]+)?' . | ||||
|                     '(?<point>\.)?' . | ||||
|                     '(?<fractional>[0-9]+)?' . | ||||
|                     '(?:[eE](?<exponent>[\-\+]?[0-9]+))?' . | ||||
|                 ')|(?:' . | ||||
|                     '(?<numerator>[0-9]+)' . | ||||
|                     '\/?' . | ||||
|                     '(?<denominator>[0-9]+)' . | ||||
|                 ')' . | ||||
|             ')' . | ||||
|         '$/'; | ||||
|  | ||||
|     /** | ||||
|      * Creates a BigNumber of the given value. | ||||
|      * | ||||
|      * The concrete return type is dependent on the given value, with the following rules: | ||||
|      * | ||||
|      * - BigNumber instances are returned as is | ||||
|      * - integer numbers are returned as BigInteger | ||||
|      * - floating point numbers are converted to a string then parsed as such | ||||
|      * - strings containing a `/` character are returned as BigRational | ||||
|      * - strings containing a `.` character or using an exponential notation are returned as BigDecimal | ||||
|      * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $value | ||||
|      * | ||||
|      * @return BigNumber | ||||
|      * | ||||
|      * @throws NumberFormatException   If the format of the number is not valid. | ||||
|      * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function of($value) : BigNumber | ||||
|     { | ||||
|         if ($value instanceof BigNumber) { | ||||
|             return $value; | ||||
|         } | ||||
|  | ||||
|         if (\is_int($value)) { | ||||
|             return new BigInteger((string) $value); | ||||
|         } | ||||
|  | ||||
|         /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */ | ||||
|         $value = \is_float($value) ? self::floatToString($value) : (string) $value; | ||||
|  | ||||
|         $throw = static function() use ($value) : void { | ||||
|             throw new NumberFormatException(\sprintf( | ||||
|                 'The given value "%s" does not represent a valid number.', | ||||
|                 $value | ||||
|             )); | ||||
|         }; | ||||
|  | ||||
|         if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { | ||||
|             $throw(); | ||||
|         } | ||||
|  | ||||
|         $getMatch = static function(string $value) use ($matches) : ?string { | ||||
|             return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null; | ||||
|         }; | ||||
|  | ||||
|         $sign        = $getMatch('sign'); | ||||
|         $numerator   = $getMatch('numerator'); | ||||
|         $denominator = $getMatch('denominator'); | ||||
|  | ||||
|         if ($numerator !== null) { | ||||
|             assert($denominator !== null); | ||||
|  | ||||
|             if ($sign !== null) { | ||||
|                 $numerator = $sign . $numerator; | ||||
|             } | ||||
|  | ||||
|             $numerator   = self::cleanUp($numerator); | ||||
|             $denominator = self::cleanUp($denominator); | ||||
|  | ||||
|             if ($denominator === '0') { | ||||
|                 throw DivisionByZeroException::denominatorMustNotBeZero(); | ||||
|             } | ||||
|  | ||||
|             return new BigRational( | ||||
|                 new BigInteger($numerator), | ||||
|                 new BigInteger($denominator), | ||||
|                 false | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $point      = $getMatch('point'); | ||||
|         $integral   = $getMatch('integral'); | ||||
|         $fractional = $getMatch('fractional'); | ||||
|         $exponent   = $getMatch('exponent'); | ||||
|  | ||||
|         if ($integral === null && $fractional === null) { | ||||
|             $throw(); | ||||
|         } | ||||
|  | ||||
|         if ($integral === null) { | ||||
|             $integral = '0'; | ||||
|         } | ||||
|  | ||||
|         if ($point !== null || $exponent !== null) { | ||||
|             $fractional = ($fractional ?? ''); | ||||
|             $exponent = ($exponent !== null) ? (int) $exponent : 0; | ||||
|  | ||||
|             if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { | ||||
|                 throw new NumberFormatException('Exponent too large.'); | ||||
|             } | ||||
|  | ||||
|             $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional); | ||||
|  | ||||
|             $scale = \strlen($fractional) - $exponent; | ||||
|  | ||||
|             if ($scale < 0) { | ||||
|                 if ($unscaledValue !== '0') { | ||||
|                     $unscaledValue .= \str_repeat('0', - $scale); | ||||
|                 } | ||||
|                 $scale = 0; | ||||
|             } | ||||
|  | ||||
|             return new BigDecimal($unscaledValue, $scale); | ||||
|         } | ||||
|  | ||||
|         $integral = self::cleanUp(($sign ?? '') . $integral); | ||||
|  | ||||
|         return new BigInteger($integral); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Safely converts float to string, avoiding locale-dependent issues. | ||||
|      * | ||||
|      * @see https://github.com/brick/math/pull/20 | ||||
|      * | ||||
|      * @param float $float | ||||
|      * | ||||
|      * @return string | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      * @psalm-suppress ImpureFunctionCall | ||||
|      */ | ||||
|     private static function floatToString(float $float) : string | ||||
|     { | ||||
|         $currentLocale = \setlocale(LC_NUMERIC, '0'); | ||||
|         \setlocale(LC_NUMERIC, 'C'); | ||||
|  | ||||
|         $result = (string) $float; | ||||
|  | ||||
|         \setlocale(LC_NUMERIC, $currentLocale); | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Proxy method to access protected constructors from sibling classes. | ||||
|      * | ||||
|      * @internal | ||||
|      * | ||||
|      * @param mixed ...$args The arguments to the constructor. | ||||
|      * | ||||
|      * @return static | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      * @psalm-suppress TooManyArguments | ||||
|      * @psalm-suppress UnsafeInstantiation | ||||
|      */ | ||||
|     protected static function create(... $args) : BigNumber | ||||
|     { | ||||
|         return new static(... $args); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the minimum of the given values. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible | ||||
|      *                                              to an instance of the class this method is called on. | ||||
|      * | ||||
|      * @return static The minimum value. | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If no values are given. | ||||
|      * @throws MathException             If an argument is not valid. | ||||
|      * | ||||
|      * @psalm-suppress LessSpecificReturnStatement | ||||
|      * @psalm-suppress MoreSpecificReturnType | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function min(...$values) : BigNumber | ||||
|     { | ||||
|         $min = null; | ||||
|  | ||||
|         foreach ($values as $value) { | ||||
|             $value = static::of($value); | ||||
|  | ||||
|             if ($min === null || $value->isLessThan($min)) { | ||||
|                 $min = $value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($min === null) { | ||||
|             throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); | ||||
|         } | ||||
|  | ||||
|         return $min; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the maximum of the given values. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible | ||||
|      *                                              to an instance of the class this method is called on. | ||||
|      * | ||||
|      * @return static The maximum value. | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If no values are given. | ||||
|      * @throws MathException             If an argument is not valid. | ||||
|      * | ||||
|      * @psalm-suppress LessSpecificReturnStatement | ||||
|      * @psalm-suppress MoreSpecificReturnType | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function max(...$values) : BigNumber | ||||
|     { | ||||
|         $max = null; | ||||
|  | ||||
|         foreach ($values as $value) { | ||||
|             $value = static::of($value); | ||||
|  | ||||
|             if ($max === null || $value->isGreaterThan($max)) { | ||||
|                 $max = $value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($max === null) { | ||||
|             throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); | ||||
|         } | ||||
|  | ||||
|         return $max; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the sum of the given values. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible | ||||
|      *                                              to an instance of the class this method is called on. | ||||
|      * | ||||
|      * @return static The sum. | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If no values are given. | ||||
|      * @throws MathException             If an argument is not valid. | ||||
|      * | ||||
|      * @psalm-suppress LessSpecificReturnStatement | ||||
|      * @psalm-suppress MoreSpecificReturnType | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function sum(...$values) : BigNumber | ||||
|     { | ||||
|         /** @var BigNumber|null $sum */ | ||||
|         $sum = null; | ||||
|  | ||||
|         foreach ($values as $value) { | ||||
|             $value = static::of($value); | ||||
|  | ||||
|             $sum = $sum === null ? $value : self::add($sum, $value); | ||||
|         } | ||||
|  | ||||
|         if ($sum === null) { | ||||
|             throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); | ||||
|         } | ||||
|  | ||||
|         return $sum; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException. | ||||
|      * | ||||
|      * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to | ||||
|      *       concrete classes the responsibility to perform the addition themselves or delegate it to the given number, | ||||
|      *       depending on their ability to perform the operation. This will also require a version bump because we're | ||||
|      *       potentially breaking custom BigNumber implementations (if any...) | ||||
|      * | ||||
|      * @param BigNumber $a | ||||
|      * @param BigNumber $b | ||||
|      * | ||||
|      * @return BigNumber | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     private static function add(BigNumber $a, BigNumber $b) : BigNumber | ||||
|     { | ||||
|         if ($a instanceof BigRational) { | ||||
|             return $a->plus($b); | ||||
|         } | ||||
|  | ||||
|         if ($b instanceof BigRational) { | ||||
|             return $b->plus($a); | ||||
|         } | ||||
|  | ||||
|         if ($a instanceof BigDecimal) { | ||||
|             return $a->plus($b); | ||||
|         } | ||||
|  | ||||
|         if ($b instanceof BigDecimal) { | ||||
|             return $b->plus($a); | ||||
|         } | ||||
|  | ||||
|         /** @var BigInteger $a */ | ||||
|  | ||||
|         return $a->plus($b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removes optional leading zeros and + sign from the given number. | ||||
|      * | ||||
|      * @param string $number The number, validated as a non-empty string of digits with optional leading sign. | ||||
|      * | ||||
|      * @return string | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     private static function cleanUp(string $number) : string | ||||
|     { | ||||
|         $firstChar = $number[0]; | ||||
|  | ||||
|         if ($firstChar === '+' || $firstChar === '-') { | ||||
|             $number = \substr($number, 1); | ||||
|         } | ||||
|  | ||||
|         $number = \ltrim($number, '0'); | ||||
|  | ||||
|         if ($number === '') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         if ($firstChar === '-') { | ||||
|             return '-' . $number; | ||||
|         } | ||||
|  | ||||
|         return $number; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is equal to the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isEqualTo($that) : bool | ||||
|     { | ||||
|         return $this->compareTo($that) === 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is strictly lower than the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isLessThan($that) : bool | ||||
|     { | ||||
|         return $this->compareTo($that) < 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is lower than or equal to the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isLessThanOrEqualTo($that) : bool | ||||
|     { | ||||
|         return $this->compareTo($that) <= 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is strictly greater than the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isGreaterThan($that) : bool | ||||
|     { | ||||
|         return $this->compareTo($that) > 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is greater than or equal to the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isGreaterThanOrEqualTo($that) : bool | ||||
|     { | ||||
|         return $this->compareTo($that) >= 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number equals zero. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isZero() : bool | ||||
|     { | ||||
|         return $this->getSign() === 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is strictly negative. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isNegative() : bool | ||||
|     { | ||||
|         return $this->getSign() < 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is negative or zero. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isNegativeOrZero() : bool | ||||
|     { | ||||
|         return $this->getSign() <= 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is strictly positive. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isPositive() : bool | ||||
|     { | ||||
|         return $this->getSign() > 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if this number is positive or zero. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function isPositiveOrZero() : bool | ||||
|     { | ||||
|         return $this->getSign() >= 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the sign of this number. | ||||
|      * | ||||
|      * @return int -1 if the number is negative, 0 if zero, 1 if positive. | ||||
|      */ | ||||
|     abstract public function getSign() : int; | ||||
|  | ||||
|     /** | ||||
|      * Compares this number to the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that | ||||
|      * | ||||
|      * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. | ||||
|      * | ||||
|      * @throws MathException If the number is not valid. | ||||
|      */ | ||||
|     abstract public function compareTo($that) : int; | ||||
|  | ||||
|     /** | ||||
|      * Converts this number to a BigInteger. | ||||
|      * | ||||
|      * @return BigInteger The converted number. | ||||
|      * | ||||
|      * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. | ||||
|      */ | ||||
|     abstract public function toBigInteger() : BigInteger; | ||||
|  | ||||
|     /** | ||||
|      * Converts this number to a BigDecimal. | ||||
|      * | ||||
|      * @return BigDecimal The converted number. | ||||
|      * | ||||
|      * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. | ||||
|      */ | ||||
|     abstract public function toBigDecimal() : BigDecimal; | ||||
|  | ||||
|     /** | ||||
|      * Converts this number to a BigRational. | ||||
|      * | ||||
|      * @return BigRational The converted number. | ||||
|      */ | ||||
|     abstract public function toBigRational() : BigRational; | ||||
|  | ||||
|     /** | ||||
|      * Converts this number to a BigDecimal with the given scale, using rounding if necessary. | ||||
|      * | ||||
|      * @param int $scale        The scale of the resulting `BigDecimal`. | ||||
|      * @param int $roundingMode A `RoundingMode` constant. | ||||
|      * | ||||
|      * @return BigDecimal | ||||
|      * | ||||
|      * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. | ||||
|      *                                    This only applies when RoundingMode::UNNECESSARY is used. | ||||
|      */ | ||||
|     abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; | ||||
|  | ||||
|     /** | ||||
|      * Returns the exact value of this number as a native integer. | ||||
|      * | ||||
|      * If this number cannot be converted to a native integer without losing precision, an exception is thrown. | ||||
|      * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit. | ||||
|      * | ||||
|      * @return int The converted value. | ||||
|      * | ||||
|      * @throws MathException If this number cannot be exactly converted to a native integer. | ||||
|      */ | ||||
|     abstract public function toInt() : int; | ||||
|  | ||||
|     /** | ||||
|      * Returns an approximation of this number as a floating-point value. | ||||
|      * | ||||
|      * Note that this method can discard information as the precision of a floating-point value | ||||
|      * is inherently limited. | ||||
|      * | ||||
|      * If the number is greater than the largest representable floating point number, positive infinity is returned. | ||||
|      * If the number is less than the smallest representable floating point number, negative infinity is returned. | ||||
|      * | ||||
|      * @return float The converted value. | ||||
|      */ | ||||
|     abstract public function toFloat() : float; | ||||
|  | ||||
|     /** | ||||
|      * Returns a string representation of this number. | ||||
|      * | ||||
|      * The output of this method can be parsed by the `of()` factory method; | ||||
|      * this will yield an object equal to this one, without any information loss. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     abstract public function __toString() : string; | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function jsonSerialize() : string | ||||
|     { | ||||
|         return $this->__toString(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										523
									
								
								vendor/brick/math/src/BigRational.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										523
									
								
								vendor/brick/math/src/BigRational.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,523 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math; | ||||
|  | ||||
| use Brick\Math\Exception\DivisionByZeroException; | ||||
| use Brick\Math\Exception\MathException; | ||||
| use Brick\Math\Exception\NumberFormatException; | ||||
| use Brick\Math\Exception\RoundingNecessaryException; | ||||
|  | ||||
| /** | ||||
|  * An arbitrarily large rational number. | ||||
|  * | ||||
|  * This class is immutable. | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| final class BigRational extends BigNumber | ||||
| { | ||||
|     /** | ||||
|      * The numerator. | ||||
|      * | ||||
|      * @var BigInteger | ||||
|      */ | ||||
|     private $numerator; | ||||
|  | ||||
|     /** | ||||
|      * The denominator. Always strictly positive. | ||||
|      * | ||||
|      * @var BigInteger | ||||
|      */ | ||||
|     private $denominator; | ||||
|  | ||||
|     /** | ||||
|      * Protected constructor. Use a factory method to obtain an instance. | ||||
|      * | ||||
|      * @param BigInteger $numerator        The numerator. | ||||
|      * @param BigInteger $denominator      The denominator. | ||||
|      * @param bool       $checkDenominator Whether to check the denominator for negative and zero. | ||||
|      * | ||||
|      * @throws DivisionByZeroException If the denominator is zero. | ||||
|      */ | ||||
|     protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) | ||||
|     { | ||||
|         if ($checkDenominator) { | ||||
|             if ($denominator->isZero()) { | ||||
|                 throw DivisionByZeroException::denominatorMustNotBeZero(); | ||||
|             } | ||||
|  | ||||
|             if ($denominator->isNegative()) { | ||||
|                 $numerator   = $numerator->negated(); | ||||
|                 $denominator = $denominator->negated(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $this->numerator   = $numerator; | ||||
|         $this->denominator = $denominator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a BigRational of the given value. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $value | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @throws MathException If the value cannot be converted to a BigRational. | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function of($value) : BigNumber | ||||
|     { | ||||
|         return parent::of($value)->toBigRational(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a BigRational out of a numerator and a denominator. | ||||
|      * | ||||
|      * If the denominator is negative, the signs of both the numerator and the denominator | ||||
|      * will be inverted to ensure that the denominator is always positive. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $numerator   The numerator. Must be convertible to a BigInteger. | ||||
|      * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @throws NumberFormatException      If an argument does not represent a valid number. | ||||
|      * @throws RoundingNecessaryException If an argument represents a non-integer number. | ||||
|      * @throws DivisionByZeroException    If the denominator is zero. | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function nd($numerator, $denominator) : BigRational | ||||
|     { | ||||
|         $numerator   = BigInteger::of($numerator); | ||||
|         $denominator = BigInteger::of($denominator); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigRational representing zero. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function zero() : BigRational | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigRational|null $zero | ||||
|          */ | ||||
|         static $zero; | ||||
|  | ||||
|         if ($zero === null) { | ||||
|             $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false); | ||||
|         } | ||||
|  | ||||
|         return $zero; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigRational representing one. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function one() : BigRational | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigRational|null $one | ||||
|          */ | ||||
|         static $one; | ||||
|  | ||||
|         if ($one === null) { | ||||
|             $one = new BigRational(BigInteger::one(), BigInteger::one(), false); | ||||
|         } | ||||
|  | ||||
|         return $one; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a BigRational representing ten. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function ten() : BigRational | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-suppress ImpureStaticVariable | ||||
|          * @var BigRational|null $ten | ||||
|          */ | ||||
|         static $ten; | ||||
|  | ||||
|         if ($ten === null) { | ||||
|             $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false); | ||||
|         } | ||||
|  | ||||
|         return $ten; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return BigInteger | ||||
|      */ | ||||
|     public function getNumerator() : BigInteger | ||||
|     { | ||||
|         return $this->numerator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return BigInteger | ||||
|      */ | ||||
|     public function getDenominator() : BigInteger | ||||
|     { | ||||
|         return $this->denominator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient of the division of the numerator by the denominator. | ||||
|      * | ||||
|      * @return BigInteger | ||||
|      */ | ||||
|     public function quotient() : BigInteger | ||||
|     { | ||||
|         return $this->numerator->quotient($this->denominator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the remainder of the division of the numerator by the denominator. | ||||
|      * | ||||
|      * @return BigInteger | ||||
|      */ | ||||
|     public function remainder() : BigInteger | ||||
|     { | ||||
|         return $this->numerator->remainder($this->denominator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient and remainder of the division of the numerator by the denominator. | ||||
|      * | ||||
|      * @return BigInteger[] | ||||
|      */ | ||||
|     public function quotientAndRemainder() : array | ||||
|     { | ||||
|         return $this->numerator->quotientAndRemainder($this->denominator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the sum of this number and the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The number to add. | ||||
|      * | ||||
|      * @return BigRational The result. | ||||
|      * | ||||
|      * @throws MathException If the number is not valid. | ||||
|      */ | ||||
|     public function plus($that) : BigRational | ||||
|     { | ||||
|         $that = BigRational::of($that); | ||||
|  | ||||
|         $numerator   = $this->numerator->multipliedBy($that->denominator); | ||||
|         $numerator   = $numerator->plus($that->numerator->multipliedBy($this->denominator)); | ||||
|         $denominator = $this->denominator->multipliedBy($that->denominator); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the difference of this number and the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The number to subtract. | ||||
|      * | ||||
|      * @return BigRational The result. | ||||
|      * | ||||
|      * @throws MathException If the number is not valid. | ||||
|      */ | ||||
|     public function minus($that) : BigRational | ||||
|     { | ||||
|         $that = BigRational::of($that); | ||||
|  | ||||
|         $numerator   = $this->numerator->multipliedBy($that->denominator); | ||||
|         $numerator   = $numerator->minus($that->numerator->multipliedBy($this->denominator)); | ||||
|         $denominator = $this->denominator->multipliedBy($that->denominator); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the product of this number and the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The multiplier. | ||||
|      * | ||||
|      * @return BigRational The result. | ||||
|      * | ||||
|      * @throws MathException If the multiplier is not a valid number. | ||||
|      */ | ||||
|     public function multipliedBy($that) : BigRational | ||||
|     { | ||||
|         $that = BigRational::of($that); | ||||
|  | ||||
|         $numerator   = $this->numerator->multipliedBy($that->numerator); | ||||
|         $denominator = $this->denominator->multipliedBy($that->denominator); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the result of the division of this number by the given one. | ||||
|      * | ||||
|      * @param BigNumber|int|float|string $that The divisor. | ||||
|      * | ||||
|      * @return BigRational The result. | ||||
|      * | ||||
|      * @throws MathException If the divisor is not a valid number, or is zero. | ||||
|      */ | ||||
|     public function dividedBy($that) : BigRational | ||||
|     { | ||||
|         $that = BigRational::of($that); | ||||
|  | ||||
|         $numerator   = $this->numerator->multipliedBy($that->denominator); | ||||
|         $denominator = $this->denominator->multipliedBy($that->numerator); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns this number exponentiated to the given value. | ||||
|      * | ||||
|      * @param int $exponent The exponent. | ||||
|      * | ||||
|      * @return BigRational The result. | ||||
|      * | ||||
|      * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. | ||||
|      */ | ||||
|     public function power(int $exponent) : BigRational | ||||
|     { | ||||
|         if ($exponent === 0) { | ||||
|             $one = BigInteger::one(); | ||||
|  | ||||
|             return new BigRational($one, $one, false); | ||||
|         } | ||||
|  | ||||
|         if ($exponent === 1) { | ||||
|             return $this; | ||||
|         } | ||||
|  | ||||
|         return new BigRational( | ||||
|             $this->numerator->power($exponent), | ||||
|             $this->denominator->power($exponent), | ||||
|             false | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the reciprocal of this BigRational. | ||||
|      * | ||||
|      * The reciprocal has the numerator and denominator swapped. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      * | ||||
|      * @throws DivisionByZeroException If the numerator is zero. | ||||
|      */ | ||||
|     public function reciprocal() : BigRational | ||||
|     { | ||||
|         return new BigRational($this->denominator, $this->numerator, true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the absolute value of this BigRational. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      */ | ||||
|     public function abs() : BigRational | ||||
|     { | ||||
|         return new BigRational($this->numerator->abs(), $this->denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the negated value of this BigRational. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      */ | ||||
|     public function negated() : BigRational | ||||
|     { | ||||
|         return new BigRational($this->numerator->negated(), $this->denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the simplified value of this BigRational. | ||||
|      * | ||||
|      * @return BigRational | ||||
|      */ | ||||
|     public function simplified() : BigRational | ||||
|     { | ||||
|         $gcd = $this->numerator->gcd($this->denominator); | ||||
|  | ||||
|         $numerator = $this->numerator->quotient($gcd); | ||||
|         $denominator = $this->denominator->quotient($gcd); | ||||
|  | ||||
|         return new BigRational($numerator, $denominator, false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function compareTo($that) : int | ||||
|     { | ||||
|         return $this->minus($that)->getSign(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function getSign() : int | ||||
|     { | ||||
|         return $this->numerator->getSign(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigInteger() : BigInteger | ||||
|     { | ||||
|         $simplified = $this->simplified(); | ||||
|  | ||||
|         if (! $simplified->denominator->isEqualTo(1)) { | ||||
|             throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.'); | ||||
|         } | ||||
|  | ||||
|         return $simplified->numerator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigDecimal() : BigDecimal | ||||
|     { | ||||
|         return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBigRational() : BigRational | ||||
|     { | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal | ||||
|     { | ||||
|         return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toInt() : int | ||||
|     { | ||||
|         return $this->toBigInteger()->toInt(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toFloat() : float | ||||
|     { | ||||
|         return $this->numerator->toFloat() / $this->denominator->toFloat(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function __toString() : string | ||||
|     { | ||||
|         $numerator   = (string) $this->numerator; | ||||
|         $denominator = (string) $this->denominator; | ||||
|  | ||||
|         if ($denominator === '1') { | ||||
|             return $numerator; | ||||
|         } | ||||
|  | ||||
|         return $this->numerator . '/' . $this->denominator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is required for serializing the object and SHOULD NOT be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * | ||||
|      * @return array{numerator: BigInteger, denominator: BigInteger} | ||||
|      */ | ||||
|     public function __serialize(): array | ||||
|     { | ||||
|         return ['numerator' => $this->numerator, 'denominator' => $this->denominator]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is only here to allow unserializing the object and cannot be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * @psalm-suppress RedundantPropertyInitializationCheck | ||||
|      * | ||||
|      * @param array{numerator: BigInteger, denominator: BigInteger} $data | ||||
|      * | ||||
|      * @return void | ||||
|      * | ||||
|      * @throws \LogicException | ||||
|      */ | ||||
|     public function __unserialize(array $data): void | ||||
|     { | ||||
|         if (isset($this->numerator)) { | ||||
|             throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); | ||||
|         } | ||||
|  | ||||
|         $this->numerator = $data['numerator']; | ||||
|         $this->denominator = $data['denominator']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is required by interface Serializable and SHOULD NOT be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function serialize() : string | ||||
|     { | ||||
|         return $this->numerator . '/' . $this->denominator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This method is only here to implement interface Serializable and cannot be accessed directly. | ||||
|      * | ||||
|      * @internal | ||||
|      * @psalm-suppress RedundantPropertyInitializationCheck | ||||
|      * | ||||
|      * @param string $value | ||||
|      * | ||||
|      * @return void | ||||
|      * | ||||
|      * @throws \LogicException | ||||
|      */ | ||||
|     public function unserialize($value) : void | ||||
|     { | ||||
|         if (isset($this->numerator)) { | ||||
|             throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); | ||||
|         } | ||||
|  | ||||
|         [$numerator, $denominator] = \explode('/', $value); | ||||
|  | ||||
|         $this->numerator   = BigInteger::of($numerator); | ||||
|         $this->denominator = BigInteger::of($denominator); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										41
									
								
								vendor/brick/math/src/Exception/DivisionByZeroException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/brick/math/src/Exception/DivisionByZeroException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| /** | ||||
|  * Exception thrown when a division by zero occurs. | ||||
|  */ | ||||
| class DivisionByZeroException extends MathException | ||||
| { | ||||
|     /** | ||||
|      * @return DivisionByZeroException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function divisionByZero() : DivisionByZeroException | ||||
|     { | ||||
|         return new self('Division by zero.'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return DivisionByZeroException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function modulusMustNotBeZero() : DivisionByZeroException | ||||
|     { | ||||
|         return new self('The modulus must not be zero.'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return DivisionByZeroException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function denominatorMustNotBeZero() : DivisionByZeroException | ||||
|     { | ||||
|         return new self('The denominator of a rational number cannot be zero.'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/brick/math/src/Exception/IntegerOverflowException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/brick/math/src/Exception/IntegerOverflowException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| use Brick\Math\BigInteger; | ||||
|  | ||||
| /** | ||||
|  * Exception thrown when an integer overflow occurs. | ||||
|  */ | ||||
| class IntegerOverflowException extends MathException | ||||
| { | ||||
|     /** | ||||
|      * @param BigInteger $value | ||||
|      * | ||||
|      * @return IntegerOverflowException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function toIntOverflow(BigInteger $value) : IntegerOverflowException | ||||
|     { | ||||
|         $message = '%s is out of range %d to %d and cannot be represented as an integer.'; | ||||
|  | ||||
|         return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								vendor/brick/math/src/Exception/MathException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/brick/math/src/Exception/MathException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| /** | ||||
|  * Base class for all math exceptions. | ||||
|  * | ||||
|  * This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code. | ||||
|  */ | ||||
| class MathException extends \RuntimeException | ||||
| { | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/brick/math/src/Exception/NegativeNumberException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/brick/math/src/Exception/NegativeNumberException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| /** | ||||
|  * Exception thrown when attempting to perform an unsupported operation, such as a square root, on a negative number. | ||||
|  */ | ||||
| class NegativeNumberException extends MathException | ||||
| { | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/brick/math/src/Exception/NumberFormatException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/brick/math/src/Exception/NumberFormatException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| /** | ||||
|  * Exception thrown when attempting to create a number from a string with an invalid format. | ||||
|  */ | ||||
| class NumberFormatException extends MathException | ||||
| { | ||||
|     /** | ||||
|      * @param string $char The failing character. | ||||
|      * | ||||
|      * @return NumberFormatException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function charNotInAlphabet(string $char) : self | ||||
|     { | ||||
|         $ord = \ord($char); | ||||
|  | ||||
|         if ($ord < 32 || $ord > 126) { | ||||
|             $char = \strtoupper(\dechex($ord)); | ||||
|  | ||||
|             if ($ord < 10) { | ||||
|                 $char = '0' . $char; | ||||
|             } | ||||
|         } else { | ||||
|             $char = '"' . $char . '"'; | ||||
|         } | ||||
|  | ||||
|         return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/brick/math/src/Exception/RoundingNecessaryException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/brick/math/src/Exception/RoundingNecessaryException.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Exception; | ||||
|  | ||||
| /** | ||||
|  * Exception thrown when a number cannot be represented at the requested scale without rounding. | ||||
|  */ | ||||
| class RoundingNecessaryException extends MathException | ||||
| { | ||||
|     /** | ||||
|      * @return RoundingNecessaryException | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      */ | ||||
|     public static function roundingNecessary() : RoundingNecessaryException | ||||
|     { | ||||
|         return new self('Rounding is necessary to represent the result of the operation at this scale.'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										756
									
								
								vendor/brick/math/src/Internal/Calculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										756
									
								
								vendor/brick/math/src/Internal/Calculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,756 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Internal; | ||||
|  | ||||
| use Brick\Math\Exception\RoundingNecessaryException; | ||||
| use Brick\Math\RoundingMode; | ||||
|  | ||||
| /** | ||||
|  * Performs basic operations on arbitrary size integers. | ||||
|  * | ||||
|  * Unless otherwise specified, all parameters must be validated as non-empty strings of digits, | ||||
|  * without leading zero, and with an optional leading minus sign if the number is not zero. | ||||
|  * | ||||
|  * Any other parameter format will lead to undefined behaviour. | ||||
|  * All methods must return strings respecting this format, unless specified otherwise. | ||||
|  * | ||||
|  * @internal | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| abstract class Calculator | ||||
| { | ||||
|     /** | ||||
|      * The maximum exponent value allowed for the pow() method. | ||||
|      */ | ||||
|     public const MAX_POWER = 1000000; | ||||
|  | ||||
|     /** | ||||
|      * The alphabet for converting from and to base 2 to 36, lowercase. | ||||
|      */ | ||||
|     public const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'; | ||||
|  | ||||
|     /** | ||||
|      * The Calculator instance in use. | ||||
|      * | ||||
|      * @var Calculator|null | ||||
|      */ | ||||
|     private static $instance; | ||||
|  | ||||
|     /** | ||||
|      * Sets the Calculator instance to use. | ||||
|      * | ||||
|      * An instance is typically set only in unit tests: the autodetect is usually the best option. | ||||
|      * | ||||
|      * @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     final public static function set(?Calculator $calculator) : void | ||||
|     { | ||||
|         self::$instance = $calculator; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the Calculator instance to use. | ||||
|      * | ||||
|      * If none has been explicitly set, the fastest available implementation will be returned. | ||||
|      * | ||||
|      * @return Calculator | ||||
|      * | ||||
|      * @psalm-pure | ||||
|      * @psalm-suppress ImpureStaticProperty | ||||
|      */ | ||||
|     final public static function get() : Calculator | ||||
|     { | ||||
|         if (self::$instance === null) { | ||||
|             /** @psalm-suppress ImpureMethodCall */ | ||||
|             self::$instance = self::detect(); | ||||
|         } | ||||
|  | ||||
|         return self::$instance; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the fastest available Calculator implementation. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      * | ||||
|      * @return Calculator | ||||
|      */ | ||||
|     private static function detect() : Calculator | ||||
|     { | ||||
|         if (\extension_loaded('gmp')) { | ||||
|             return new Calculator\GmpCalculator(); | ||||
|         } | ||||
|  | ||||
|         if (\extension_loaded('bcmath')) { | ||||
|             return new Calculator\BcMathCalculator(); | ||||
|         } | ||||
|  | ||||
|         return new Calculator\NativeCalculator(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Extracts the sign & digits of the operands. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits. | ||||
|      */ | ||||
|     final protected function init(string $a, string $b) : array | ||||
|     { | ||||
|         return [ | ||||
|             $aNeg = ($a[0] === '-'), | ||||
|             $bNeg = ($b[0] === '-'), | ||||
|  | ||||
|             $aNeg ? \substr($a, 1) : $a, | ||||
|             $bNeg ? \substr($b, 1) : $b, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the absolute value of a number. | ||||
|      * | ||||
|      * @param string $n The number. | ||||
|      * | ||||
|      * @return string The absolute value. | ||||
|      */ | ||||
|     final public function abs(string $n) : string | ||||
|     { | ||||
|         return ($n[0] === '-') ? \substr($n, 1) : $n; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Negates a number. | ||||
|      * | ||||
|      * @param string $n The number. | ||||
|      * | ||||
|      * @return string The negated value. | ||||
|      */ | ||||
|     final public function neg(string $n) : string | ||||
|     { | ||||
|         if ($n === '0') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         if ($n[0] === '-') { | ||||
|             return \substr($n, 1); | ||||
|         } | ||||
|  | ||||
|         return '-' . $n; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compares two numbers. | ||||
|      * | ||||
|      * @param string $a The first number. | ||||
|      * @param string $b The second number. | ||||
|      * | ||||
|      * @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number. | ||||
|      */ | ||||
|     final public function cmp(string $a, string $b) : int | ||||
|     { | ||||
|         [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); | ||||
|  | ||||
|         if ($aNeg && ! $bNeg) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         if ($bNeg && ! $aNeg) { | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         $aLen = \strlen($aDig); | ||||
|         $bLen = \strlen($bDig); | ||||
|  | ||||
|         if ($aLen < $bLen) { | ||||
|             $result = -1; | ||||
|         } elseif ($aLen > $bLen) { | ||||
|             $result = 1; | ||||
|         } else { | ||||
|             $result = $aDig <=> $bDig; | ||||
|         } | ||||
|  | ||||
|         return $aNeg ? -$result : $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds two numbers. | ||||
|      * | ||||
|      * @param string $a The augend. | ||||
|      * @param string $b The addend. | ||||
|      * | ||||
|      * @return string The sum. | ||||
|      */ | ||||
|     abstract public function add(string $a, string $b) : string; | ||||
|  | ||||
|     /** | ||||
|      * Subtracts two numbers. | ||||
|      * | ||||
|      * @param string $a The minuend. | ||||
|      * @param string $b The subtrahend. | ||||
|      * | ||||
|      * @return string The difference. | ||||
|      */ | ||||
|     abstract public function sub(string $a, string $b) : string; | ||||
|  | ||||
|     /** | ||||
|      * Multiplies two numbers. | ||||
|      * | ||||
|      * @param string $a The multiplicand. | ||||
|      * @param string $b The multiplier. | ||||
|      * | ||||
|      * @return string The product. | ||||
|      */ | ||||
|     abstract public function mul(string $a, string $b) : string; | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient of the division of two numbers. | ||||
|      * | ||||
|      * @param string $a The dividend. | ||||
|      * @param string $b The divisor, must not be zero. | ||||
|      * | ||||
|      * @return string The quotient. | ||||
|      */ | ||||
|     abstract public function divQ(string $a, string $b) : string; | ||||
|  | ||||
|     /** | ||||
|      * Returns the remainder of the division of two numbers. | ||||
|      * | ||||
|      * @param string $a The dividend. | ||||
|      * @param string $b The divisor, must not be zero. | ||||
|      * | ||||
|      * @return string The remainder. | ||||
|      */ | ||||
|     abstract public function divR(string $a, string $b) : string; | ||||
|  | ||||
|     /** | ||||
|      * Returns the quotient and remainder of the division of two numbers. | ||||
|      * | ||||
|      * @param string $a The dividend. | ||||
|      * @param string $b The divisor, must not be zero. | ||||
|      * | ||||
|      * @return string[] An array containing the quotient and remainder. | ||||
|      */ | ||||
|     abstract public function divQR(string $a, string $b) : array; | ||||
|  | ||||
|     /** | ||||
|      * Exponentiates a number. | ||||
|      * | ||||
|      * @param string $a The base number. | ||||
|      * @param int    $e The exponent, validated as an integer between 0 and MAX_POWER. | ||||
|      * | ||||
|      * @return string The power. | ||||
|      */ | ||||
|     abstract public function pow(string $a, int $e) : string; | ||||
|  | ||||
|     /** | ||||
|      * @param string $a | ||||
|      * @param string $b The modulus; must not be zero. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function mod(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->divR($this->add($this->divR($a, $b), $b), $b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the modular multiplicative inverse of $x modulo $m. | ||||
|      * | ||||
|      * If $x has no multiplicative inverse mod m, this method must return null. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library has built-in support. | ||||
|      * | ||||
|      * @param string $x | ||||
|      * @param string $m The modulus; must not be negative or zero. | ||||
|      * | ||||
|      * @return string|null | ||||
|      */ | ||||
|     public function modInverse(string $x, string $m) : ?string | ||||
|     { | ||||
|         if ($m === '1') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         $modVal = $x; | ||||
|  | ||||
|         if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) { | ||||
|             $modVal = $this->mod($x, $m); | ||||
|         } | ||||
|  | ||||
|         $x = '0'; | ||||
|         $y = '0'; | ||||
|         $g = $this->gcdExtended($modVal, $m, $x, $y); | ||||
|  | ||||
|         if ($g !== '1') { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return $this->mod($this->add($this->mod($x, $m), $m), $m); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Raises a number into power with modulo. | ||||
|      * | ||||
|      * @param string $base The base number; must be positive or zero. | ||||
|      * @param string $exp  The exponent; must be positive or zero. | ||||
|      * @param string $mod  The modulus; must be strictly positive. | ||||
|      * | ||||
|      * @return string The power. | ||||
|      */ | ||||
|     abstract public function modPow(string $base, string $exp, string $mod) : string; | ||||
|  | ||||
|     /** | ||||
|      * Returns the greatest common divisor of the two numbers. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for GCD calculations. | ||||
|      * | ||||
|      * @param string $a The first number. | ||||
|      * @param string $b The second number. | ||||
|      * | ||||
|      * @return string The GCD, always positive, or zero if both arguments are zero. | ||||
|      */ | ||||
|     public function gcd(string $a, string $b) : string | ||||
|     { | ||||
|         if ($a === '0') { | ||||
|             return $this->abs($b); | ||||
|         } | ||||
|  | ||||
|         if ($b === '0') { | ||||
|             return $this->abs($a); | ||||
|         } | ||||
|  | ||||
|         return $this->gcd($b, $this->divR($a, $b)); | ||||
|     } | ||||
|  | ||||
|     private function gcdExtended(string $a, string $b, string &$x, string &$y) : string | ||||
|     { | ||||
|         if ($a === '0') { | ||||
|             $x = '0'; | ||||
|             $y = '1'; | ||||
|  | ||||
|             return $b; | ||||
|         } | ||||
|  | ||||
|         $x1 = '0'; | ||||
|         $y1 = '0'; | ||||
|  | ||||
|         $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1); | ||||
|  | ||||
|         $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); | ||||
|         $y = $x1; | ||||
|  | ||||
|         return $gcd; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the square root of the given number, rounded down. | ||||
|      * | ||||
|      * The result is the largest x such that x² ≤ n. | ||||
|      * The input MUST NOT be negative. | ||||
|      * | ||||
|      * @param string $n The number. | ||||
|      * | ||||
|      * @return string The square root. | ||||
|      */ | ||||
|     abstract public function sqrt(string $n) : string; | ||||
|  | ||||
|     /** | ||||
|      * Converts a number from an arbitrary base. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for base conversion. | ||||
|      * | ||||
|      * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base. | ||||
|      * @param int    $base   The base of the number, validated from 2 to 36. | ||||
|      * | ||||
|      * @return string The converted number, following the Calculator conventions. | ||||
|      */ | ||||
|     public function fromBase(string $number, int $base) : string | ||||
|     { | ||||
|         return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a number to an arbitrary base. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for base conversion. | ||||
|      * | ||||
|      * @param string $number The number to convert, following the Calculator conventions. | ||||
|      * @param int    $base   The base to convert to, validated from 2 to 36. | ||||
|      * | ||||
|      * @return string The converted number, lowercase. | ||||
|      */ | ||||
|     public function toBase(string $number, int $base) : string | ||||
|     { | ||||
|         $negative = ($number[0] === '-'); | ||||
|  | ||||
|         if ($negative) { | ||||
|             $number = \substr($number, 1); | ||||
|         } | ||||
|  | ||||
|         $number = $this->toArbitraryBase($number, self::ALPHABET, $base); | ||||
|  | ||||
|         if ($negative) { | ||||
|             return '-' . $number; | ||||
|         } | ||||
|  | ||||
|         return $number; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10. | ||||
|      * | ||||
|      * @param string $number   The number to convert, validated as a non-empty string, | ||||
|      *                         containing only chars in the given alphabet/base. | ||||
|      * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. | ||||
|      * @param int    $base     The base of the number, validated from 2 to alphabet length. | ||||
|      * | ||||
|      * @return string The number in base 10, following the Calculator conventions. | ||||
|      */ | ||||
|     final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string | ||||
|     { | ||||
|         // remove leading "zeros" | ||||
|         $number = \ltrim($number, $alphabet[0]); | ||||
|  | ||||
|         if ($number === '') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         // optimize for "one" | ||||
|         if ($number === $alphabet[1]) { | ||||
|             return '1'; | ||||
|         } | ||||
|  | ||||
|         $result = '0'; | ||||
|         $power = '1'; | ||||
|  | ||||
|         $base = (string) $base; | ||||
|  | ||||
|         for ($i = \strlen($number) - 1; $i >= 0; $i--) { | ||||
|             $index = \strpos($alphabet, $number[$i]); | ||||
|  | ||||
|             if ($index !== 0) { | ||||
|                 $result = $this->add($result, ($index === 1) | ||||
|                     ? $power | ||||
|                     : $this->mul($power, (string) $index) | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             if ($i !== 0) { | ||||
|                 $power = $this->mul($power, $base); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a non-negative number to an arbitrary base using a custom alphabet. | ||||
|      * | ||||
|      * @param string $number   The number to convert, positive or zero, following the Calculator conventions. | ||||
|      * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. | ||||
|      * @param int    $base     The base to convert to, validated from 2 to alphabet length. | ||||
|      * | ||||
|      * @return string The converted number in the given alphabet. | ||||
|      */ | ||||
|     final public function toArbitraryBase(string $number, string $alphabet, int $base) : string | ||||
|     { | ||||
|         if ($number === '0') { | ||||
|             return $alphabet[0]; | ||||
|         } | ||||
|  | ||||
|         $base = (string) $base; | ||||
|         $result = ''; | ||||
|  | ||||
|         while ($number !== '0') { | ||||
|             [$number, $remainder] = $this->divQR($number, $base); | ||||
|             $remainder = (int) $remainder; | ||||
|  | ||||
|             $result .= $alphabet[$remainder]; | ||||
|         } | ||||
|  | ||||
|         return \strrev($result); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs a rounded division. | ||||
|      * | ||||
|      * Rounding is performed when the remainder of the division is not zero. | ||||
|      * | ||||
|      * @param string $a            The dividend. | ||||
|      * @param string $b            The divisor, must not be zero. | ||||
|      * @param int    $roundingMode The rounding mode. | ||||
|      * | ||||
|      * @return string | ||||
|      * | ||||
|      * @throws \InvalidArgumentException  If the rounding mode is invalid. | ||||
|      * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. | ||||
|      */ | ||||
|     final public function divRound(string $a, string $b, int $roundingMode) : string | ||||
|     { | ||||
|         [$quotient, $remainder] = $this->divQR($a, $b); | ||||
|  | ||||
|         $hasDiscardedFraction = ($remainder !== '0'); | ||||
|         $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-'); | ||||
|  | ||||
|         $discardedFractionSign = function() use ($remainder, $b) : int { | ||||
|             $r = $this->abs($this->mul($remainder, '2')); | ||||
|             $b = $this->abs($b); | ||||
|  | ||||
|             return $this->cmp($r, $b); | ||||
|         }; | ||||
|  | ||||
|         $increment = false; | ||||
|  | ||||
|         switch ($roundingMode) { | ||||
|             case RoundingMode::UNNECESSARY: | ||||
|                 if ($hasDiscardedFraction) { | ||||
|                     throw RoundingNecessaryException::roundingNecessary(); | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::UP: | ||||
|                 $increment = $hasDiscardedFraction; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::DOWN: | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::CEILING: | ||||
|                 $increment = $hasDiscardedFraction && $isPositiveOrZero; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::FLOOR: | ||||
|                 $increment = $hasDiscardedFraction && ! $isPositiveOrZero; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::HALF_UP: | ||||
|                 $increment = $discardedFractionSign() >= 0; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::HALF_DOWN: | ||||
|                 $increment = $discardedFractionSign() > 0; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::HALF_CEILING: | ||||
|                 $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::HALF_FLOOR: | ||||
|                 $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; | ||||
|                 break; | ||||
|  | ||||
|             case RoundingMode::HALF_EVEN: | ||||
|                 $lastDigit = (int) $quotient[-1]; | ||||
|                 $lastDigitIsEven = ($lastDigit % 2 === 0); | ||||
|                 $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; | ||||
|                 break; | ||||
|  | ||||
|             default: | ||||
|                 throw new \InvalidArgumentException('Invalid rounding mode.'); | ||||
|         } | ||||
|  | ||||
|         if ($increment) { | ||||
|             return $this->add($quotient, $isPositiveOrZero ? '1' : '-1'); | ||||
|         } | ||||
|  | ||||
|         return $quotient; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculates bitwise AND of two numbers. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for bitwise operations. | ||||
|      * | ||||
|      * @param string $a | ||||
|      * @param string $b | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function and(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->bitwise('and', $a, $b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculates bitwise OR of two numbers. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for bitwise operations. | ||||
|      * | ||||
|      * @param string $a | ||||
|      * @param string $b | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function or(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->bitwise('or', $a, $b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculates bitwise XOR of two numbers. | ||||
|      * | ||||
|      * This method can be overridden by the concrete implementation if the underlying library | ||||
|      * has built-in support for bitwise operations. | ||||
|      * | ||||
|      * @param string $a | ||||
|      * @param string $b | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function xor(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->bitwise('xor', $a, $b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function bitwise(string $operator, string $a, string $b) : string | ||||
|     { | ||||
|         [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); | ||||
|  | ||||
|         $aBin = $this->toBinary($aDig); | ||||
|         $bBin = $this->toBinary($bDig); | ||||
|  | ||||
|         $aLen = \strlen($aBin); | ||||
|         $bLen = \strlen($bBin); | ||||
|  | ||||
|         if ($aLen > $bLen) { | ||||
|             $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin; | ||||
|         } elseif ($bLen > $aLen) { | ||||
|             $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin; | ||||
|         } | ||||
|  | ||||
|         if ($aNeg) { | ||||
|             $aBin = $this->twosComplement($aBin); | ||||
|         } | ||||
|         if ($bNeg) { | ||||
|             $bBin = $this->twosComplement($bBin); | ||||
|         } | ||||
|  | ||||
|         switch ($operator) { | ||||
|             case 'and': | ||||
|                 $value = $aBin & $bBin; | ||||
|                 $negative = ($aNeg and $bNeg); | ||||
|                 break; | ||||
|  | ||||
|             case 'or': | ||||
|                 $value = $aBin | $bBin; | ||||
|                 $negative = ($aNeg or $bNeg); | ||||
|                 break; | ||||
|  | ||||
|             case 'xor': | ||||
|                 $value = $aBin ^ $bBin; | ||||
|                 $negative = ($aNeg xor $bNeg); | ||||
|                 break; | ||||
|  | ||||
|             // @codeCoverageIgnoreStart | ||||
|             default: | ||||
|                 throw new \InvalidArgumentException('Invalid bitwise operator.'); | ||||
|             // @codeCoverageIgnoreEnd | ||||
|         } | ||||
|  | ||||
|         if ($negative) { | ||||
|             $value = $this->twosComplement($value); | ||||
|         } | ||||
|  | ||||
|         $result = $this->toDecimal($value); | ||||
|  | ||||
|         return $negative ? $this->neg($result) : $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param string $number A positive, binary number. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function twosComplement(string $number) : string | ||||
|     { | ||||
|         $xor = \str_repeat("\xff", \strlen($number)); | ||||
|  | ||||
|         $number ^= $xor; | ||||
|  | ||||
|         for ($i = \strlen($number) - 1; $i >= 0; $i--) { | ||||
|             $byte = \ord($number[$i]); | ||||
|  | ||||
|             if (++$byte !== 256) { | ||||
|                 $number[$i] = \chr($byte); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $number[$i] = "\x00"; | ||||
|  | ||||
|             if ($i === 0) { | ||||
|                 $number = "\x01" . $number; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $number; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a decimal number to a binary string. | ||||
|      * | ||||
|      * @param string $number The number to convert, positive or zero, only digits. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function toBinary(string $number) : string | ||||
|     { | ||||
|         $result = ''; | ||||
|  | ||||
|         while ($number !== '0') { | ||||
|             [$number, $remainder] = $this->divQR($number, '256'); | ||||
|             $result .= \chr((int) $remainder); | ||||
|         } | ||||
|  | ||||
|         return \strrev($result); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the positive decimal representation of a binary number. | ||||
|      * | ||||
|      * @param string $bytes The bytes representing the number. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function toDecimal(string $bytes) : string | ||||
|     { | ||||
|         $result = '0'; | ||||
|         $power = '1'; | ||||
|  | ||||
|         for ($i = \strlen($bytes) - 1; $i >= 0; $i--) { | ||||
|             $index = \ord($bytes[$i]); | ||||
|  | ||||
|             if ($index !== 0) { | ||||
|                 $result = $this->add($result, ($index === 1) | ||||
|                     ? $power | ||||
|                     : $this->mul($power, (string) $index) | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             if ($i !== 0) { | ||||
|                 $power = $this->mul($power, '256'); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										116
									
								
								vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Internal\Calculator; | ||||
|  | ||||
| use Brick\Math\Internal\Calculator; | ||||
|  | ||||
| /** | ||||
|  * Calculator implementation built around the bcmath library. | ||||
|  * | ||||
|  * @internal | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| class BcMathCalculator extends Calculator | ||||
| { | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function add(string $a, string $b) : string | ||||
|     { | ||||
|         return \bcadd($a, $b, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function sub(string $a, string $b) : string | ||||
|     { | ||||
|         return \bcsub($a, $b, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function mul(string $a, string $b) : string | ||||
|     { | ||||
|         return \bcmul($a, $b, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      * | ||||
|      * @psalm-suppress InvalidNullableReturnType | ||||
|      * @psalm-suppress NullableReturnStatement | ||||
|      */ | ||||
|     public function divQ(string $a, string $b) : string | ||||
|     { | ||||
|         return \bcdiv($a, $b, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      * | ||||
|      * @psalm-suppress InvalidNullableReturnType | ||||
|      * @psalm-suppress NullableReturnStatement | ||||
|      */ | ||||
|     public function divR(string $a, string $b) : string | ||||
|     { | ||||
|         if (version_compare(PHP_VERSION, '7.2') >= 0) { | ||||
|             return \bcmod($a, $b, 0); | ||||
|         } | ||||
|  | ||||
|         return \bcmod($a, $b); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divQR(string $a, string $b) : array | ||||
|     { | ||||
|         $q = \bcdiv($a, $b, 0); | ||||
|  | ||||
|         if (version_compare(PHP_VERSION, '7.2') >= 0) { | ||||
|             $r = \bcmod($a, $b, 0); | ||||
|         } else { | ||||
|             $r = \bcmod($a, $b); | ||||
|         } | ||||
|  | ||||
|         assert($q !== null); | ||||
|         assert($r !== null); | ||||
|  | ||||
|         return [$q, $r]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function pow(string $a, int $e) : string | ||||
|     { | ||||
|         return \bcpow($a, (string) $e, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      * | ||||
|      * @psalm-suppress InvalidNullableReturnType | ||||
|      * @psalm-suppress NullableReturnStatement | ||||
|      */ | ||||
|     public function modPow(string $base, string $exp, string $mod) : string | ||||
|     { | ||||
|         return \bcpowmod($base, $exp, $mod, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritDoc} | ||||
|      * | ||||
|      * @psalm-suppress NullableReturnStatement | ||||
|      * @psalm-suppress InvalidNullableReturnType | ||||
|      */ | ||||
|     public function sqrt(string $n) : string | ||||
|     { | ||||
|         return \bcsqrt($n, 0); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										156
									
								
								vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Internal\Calculator; | ||||
|  | ||||
| use Brick\Math\Internal\Calculator; | ||||
|  | ||||
| /** | ||||
|  * Calculator implementation built around the GMP library. | ||||
|  * | ||||
|  * @internal | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| class GmpCalculator extends Calculator | ||||
| { | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function add(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_add($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function sub(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_sub($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function mul(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_mul($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divQ(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_div_q($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divR(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_div_r($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divQR(string $a, string $b) : array | ||||
|     { | ||||
|         [$q, $r] = \gmp_div_qr($a, $b); | ||||
|  | ||||
|         return [ | ||||
|             \gmp_strval($q), | ||||
|             \gmp_strval($r) | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function pow(string $a, int $e) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_pow($a, $e)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function modInverse(string $x, string $m) : ?string | ||||
|     { | ||||
|         $result = \gmp_invert($x, $m); | ||||
|  | ||||
|         if ($result === false) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return \gmp_strval($result); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function modPow(string $base, string $exp, string $mod) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_powm($base, $exp, $mod)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function gcd(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_gcd($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function fromBase(string $number, int $base) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_init($number, $base)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function toBase(string $number, int $base) : string | ||||
|     { | ||||
|         return \gmp_strval($number, $base); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function and(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_and($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function or(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_or($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function xor(string $a, string $b) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_xor($a, $b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritDoc} | ||||
|      */ | ||||
|     public function sqrt(string $n) : string | ||||
|     { | ||||
|         return \gmp_strval(\gmp_sqrt($n)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										634
									
								
								vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										634
									
								
								vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,634 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math\Internal\Calculator; | ||||
|  | ||||
| use Brick\Math\Internal\Calculator; | ||||
|  | ||||
| /** | ||||
|  * Calculator implementation using only native PHP code. | ||||
|  * | ||||
|  * @internal | ||||
|  * | ||||
|  * @psalm-immutable | ||||
|  */ | ||||
| class NativeCalculator extends Calculator | ||||
| { | ||||
|     /** | ||||
|      * The max number of digits the platform can natively add, subtract, multiply or divide without overflow. | ||||
|      * For multiplication, this represents the max sum of the lengths of both operands. | ||||
|      * | ||||
|      * 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; | ||||
|  | ||||
|     /** | ||||
|      * Class constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         switch (PHP_INT_SIZE) { | ||||
|             case 4: | ||||
|                 $this->maxDigits = 9; | ||||
|                 break; | ||||
|  | ||||
|             case 8: | ||||
|                 $this->maxDigits = 18; | ||||
|                 break; | ||||
|  | ||||
|             default: | ||||
|                 throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function add(string $a, string $b) : string | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-var numeric-string $a | ||||
|          * @psalm-var numeric-string $b | ||||
|          */ | ||||
|         $result = $a + $b; | ||||
|  | ||||
|         if (is_int($result)) { | ||||
|             return (string) $result; | ||||
|         } | ||||
|  | ||||
|         if ($a === '0') { | ||||
|             return $b; | ||||
|         } | ||||
|  | ||||
|         if ($b === '0') { | ||||
|             return $a; | ||||
|         } | ||||
|  | ||||
|         [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); | ||||
|  | ||||
|         $result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig); | ||||
|  | ||||
|         if ($aNeg) { | ||||
|             $result = $this->neg($result); | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function sub(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->add($a, $this->neg($b)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function mul(string $a, string $b) : string | ||||
|     { | ||||
|         /** | ||||
|          * @psalm-var numeric-string $a | ||||
|          * @psalm-var numeric-string $b | ||||
|          */ | ||||
|         $result = $a * $b; | ||||
|  | ||||
|         if (is_int($result)) { | ||||
|             return (string) $result; | ||||
|         } | ||||
|  | ||||
|         if ($a === '0' || $b === '0') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         if ($a === '1') { | ||||
|             return $b; | ||||
|         } | ||||
|  | ||||
|         if ($b === '1') { | ||||
|             return $a; | ||||
|         } | ||||
|  | ||||
|         if ($a === '-1') { | ||||
|             return $this->neg($b); | ||||
|         } | ||||
|  | ||||
|         if ($b === '-1') { | ||||
|             return $this->neg($a); | ||||
|         } | ||||
|  | ||||
|         [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); | ||||
|  | ||||
|         $result = $this->doMul($aDig, $bDig); | ||||
|  | ||||
|         if ($aNeg !== $bNeg) { | ||||
|             $result = $this->neg($result); | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divQ(string $a, string $b) : string | ||||
|     { | ||||
|         return $this->divQR($a, $b)[0]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divR(string $a, string $b): string | ||||
|     { | ||||
|         return $this->divQR($a, $b)[1]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function divQR(string $a, string $b) : array | ||||
|     { | ||||
|         if ($a === '0') { | ||||
|             return ['0', '0']; | ||||
|         } | ||||
|  | ||||
|         if ($a === $b) { | ||||
|             return ['1', '0']; | ||||
|         } | ||||
|  | ||||
|         if ($b === '1') { | ||||
|             return [$a, '0']; | ||||
|         } | ||||
|  | ||||
|         if ($b === '-1') { | ||||
|             return [$this->neg($a), '0']; | ||||
|         } | ||||
|  | ||||
|         /** @psalm-var numeric-string $a */ | ||||
|         $na = $a * 1; // cast to number | ||||
|  | ||||
|         if (is_int($na)) { | ||||
|             /** @psalm-var numeric-string $b */ | ||||
|             $nb = $b * 1; | ||||
|  | ||||
|             if (is_int($nb)) { | ||||
|                 // the only division that may overflow is PHP_INT_MIN / -1, | ||||
|                 // which cannot happen here as we've already handled a divisor of -1 above. | ||||
|                 $r = $na % $nb; | ||||
|                 $q = ($na - $r) / $nb; | ||||
|  | ||||
|                 assert(is_int($q)); | ||||
|  | ||||
|                 return [ | ||||
|                     (string) $q, | ||||
|                     (string) $r | ||||
|                 ]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); | ||||
|  | ||||
|         [$q, $r] = $this->doDiv($aDig, $bDig); | ||||
|  | ||||
|         if ($aNeg !== $bNeg) { | ||||
|             $q = $this->neg($q); | ||||
|         } | ||||
|  | ||||
|         if ($aNeg) { | ||||
|             $r = $this->neg($r); | ||||
|         } | ||||
|  | ||||
|         return [$q, $r]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function pow(string $a, int $e) : string | ||||
|     { | ||||
|         if ($e === 0) { | ||||
|             return '1'; | ||||
|         } | ||||
|  | ||||
|         if ($e === 1) { | ||||
|             return $a; | ||||
|         } | ||||
|  | ||||
|         $odd = $e % 2; | ||||
|         $e -= $odd; | ||||
|  | ||||
|         $aa = $this->mul($a, $a); | ||||
|  | ||||
|         /** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */ | ||||
|         $result = $this->pow($aa, $e / 2); | ||||
|  | ||||
|         if ($odd === 1) { | ||||
|             $result = $this->mul($result, $a); | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/ | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function modPow(string $base, string $exp, string $mod) : string | ||||
|     { | ||||
|         // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0) | ||||
|         if ($base === '0' && $exp === '0' && $mod === '1') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0) | ||||
|         if ($exp === '0' && $mod === '1') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         $x = $base; | ||||
|  | ||||
|         $res = '1'; | ||||
|  | ||||
|         // numbers are positive, so we can use remainder instead of modulo | ||||
|         $x = $this->divR($x, $mod); | ||||
|  | ||||
|         while ($exp !== '0') { | ||||
|             if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd | ||||
|                 $res = $this->divR($this->mul($res, $x), $mod); | ||||
|             } | ||||
|  | ||||
|             $exp = $this->divQ($exp, '2'); | ||||
|             $x = $this->divR($this->mul($x, $x), $mod); | ||||
|         } | ||||
|  | ||||
|         return $res; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html | ||||
|      * | ||||
|      * {@inheritDoc} | ||||
|      */ | ||||
|     public function sqrt(string $n) : string | ||||
|     { | ||||
|         if ($n === '0') { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         // initial approximation | ||||
|         $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1); | ||||
|  | ||||
|         $decreased = false; | ||||
|  | ||||
|         for (;;) { | ||||
|             $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2'); | ||||
|  | ||||
|             if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $decreased = $this->cmp($nx, $x) < 0; | ||||
|             $x = $nx; | ||||
|         } | ||||
|  | ||||
|         return $x; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the addition of two non-signed large integers. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function doAdd(string $a, string $b) : string | ||||
|     { | ||||
|         [$a, $b, $length] = $this->pad($a, $b); | ||||
|  | ||||
|         $carry = 0; | ||||
|         $result = ''; | ||||
|  | ||||
|         for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { | ||||
|             $blockLength = $this->maxDigits; | ||||
|  | ||||
|             if ($i < 0) { | ||||
|                 $blockLength += $i; | ||||
|                 /** @psalm-suppress LoopInvalidation */ | ||||
|                 $i = 0; | ||||
|             } | ||||
|  | ||||
|             /** @psalm-var numeric-string $blockA */ | ||||
|             $blockA = \substr($a, $i, $blockLength); | ||||
|  | ||||
|             /** @psalm-var numeric-string $blockB */ | ||||
|             $blockB = \substr($b, $i, $blockLength); | ||||
|  | ||||
|             $sum = (string) ($blockA + $blockB + $carry); | ||||
|             $sumLength = \strlen($sum); | ||||
|  | ||||
|             if ($sumLength > $blockLength) { | ||||
|                 $sum = \substr($sum, 1); | ||||
|                 $carry = 1; | ||||
|             } else { | ||||
|                 if ($sumLength < $blockLength) { | ||||
|                     $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; | ||||
|                 } | ||||
|                 $carry = 0; | ||||
|             } | ||||
|  | ||||
|             $result = $sum . $result; | ||||
|  | ||||
|             if ($i === 0) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($carry === 1) { | ||||
|             $result = '1' . $result; | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the subtraction of two non-signed large integers. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function doSub(string $a, string $b) : string | ||||
|     { | ||||
|         if ($a === $b) { | ||||
|             return '0'; | ||||
|         } | ||||
|  | ||||
|         // Ensure that we always subtract to a positive result: biggest minus smallest. | ||||
|         $cmp = $this->doCmp($a, $b); | ||||
|  | ||||
|         $invert = ($cmp === -1); | ||||
|  | ||||
|         if ($invert) { | ||||
|             $c = $a; | ||||
|             $a = $b; | ||||
|             $b = $c; | ||||
|         } | ||||
|  | ||||
|         [$a, $b, $length] = $this->pad($a, $b); | ||||
|  | ||||
|         $carry = 0; | ||||
|         $result = ''; | ||||
|  | ||||
|         $complement = 10 ** $this->maxDigits; | ||||
|  | ||||
|         for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { | ||||
|             $blockLength = $this->maxDigits; | ||||
|  | ||||
|             if ($i < 0) { | ||||
|                 $blockLength += $i; | ||||
|                 /** @psalm-suppress LoopInvalidation */ | ||||
|                 $i = 0; | ||||
|             } | ||||
|  | ||||
|             /** @psalm-var numeric-string $blockA */ | ||||
|             $blockA = \substr($a, $i, $blockLength); | ||||
|  | ||||
|             /** @psalm-var numeric-string $blockB */ | ||||
|             $blockB = \substr($b, $i, $blockLength); | ||||
|  | ||||
|             $sum = $blockA - $blockB - $carry; | ||||
|  | ||||
|             if ($sum < 0) { | ||||
|                 $sum += $complement; | ||||
|                 $carry = 1; | ||||
|             } else { | ||||
|                 $carry = 0; | ||||
|             } | ||||
|  | ||||
|             $sum = (string) $sum; | ||||
|             $sumLength = \strlen($sum); | ||||
|  | ||||
|             if ($sumLength < $blockLength) { | ||||
|                 $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; | ||||
|             } | ||||
|  | ||||
|             $result = $sum . $result; | ||||
|  | ||||
|             if ($i === 0) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Carry cannot be 1 when the loop ends, as a > b | ||||
|         assert($carry === 0); | ||||
|  | ||||
|         $result = \ltrim($result, '0'); | ||||
|  | ||||
|         if ($invert) { | ||||
|             $result = $this->neg($result); | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the multiplication of two non-signed large integers. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function doMul(string $a, string $b) : string | ||||
|     { | ||||
|         $x = \strlen($a); | ||||
|         $y = \strlen($b); | ||||
|  | ||||
|         $maxDigits = \intdiv($this->maxDigits, 2); | ||||
|         $complement = 10 ** $maxDigits; | ||||
|  | ||||
|         $result = '0'; | ||||
|  | ||||
|         for ($i = $x - $maxDigits;; $i -= $maxDigits) { | ||||
|             $blockALength = $maxDigits; | ||||
|  | ||||
|             if ($i < 0) { | ||||
|                 $blockALength += $i; | ||||
|                 /** @psalm-suppress LoopInvalidation */ | ||||
|                 $i = 0; | ||||
|             } | ||||
|  | ||||
|             $blockA = (int) \substr($a, $i, $blockALength); | ||||
|  | ||||
|             $line = ''; | ||||
|             $carry = 0; | ||||
|  | ||||
|             for ($j = $y - $maxDigits;; $j -= $maxDigits) { | ||||
|                 $blockBLength = $maxDigits; | ||||
|  | ||||
|                 if ($j < 0) { | ||||
|                     $blockBLength += $j; | ||||
|                     /** @psalm-suppress LoopInvalidation */ | ||||
|                     $j = 0; | ||||
|                 } | ||||
|  | ||||
|                 $blockB = (int) \substr($b, $j, $blockBLength); | ||||
|  | ||||
|                 $mul = $blockA * $blockB + $carry; | ||||
|                 $value = $mul % $complement; | ||||
|                 $carry = ($mul - $value) / $complement; | ||||
|  | ||||
|                 $value = (string) $value; | ||||
|                 $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT); | ||||
|  | ||||
|                 $line = $value . $line; | ||||
|  | ||||
|                 if ($j === 0) { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if ($carry !== 0) { | ||||
|                 $line = $carry . $line; | ||||
|             } | ||||
|  | ||||
|             $line = \ltrim($line, '0'); | ||||
|  | ||||
|             if ($line !== '') { | ||||
|                 $line .= \str_repeat('0', $x - $blockALength - $i); | ||||
|                 $result = $this->add($result, $line); | ||||
|             } | ||||
|  | ||||
|             if ($i === 0) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the division of two non-signed large integers. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return string[] The quotient and remainder. | ||||
|      */ | ||||
|     private function doDiv(string $a, string $b) : array | ||||
|     { | ||||
|         $cmp = $this->doCmp($a, $b); | ||||
|  | ||||
|         if ($cmp === -1) { | ||||
|             return ['0', $a]; | ||||
|         } | ||||
|  | ||||
|         $x = \strlen($a); | ||||
|         $y = \strlen($b); | ||||
|  | ||||
|         // we now know that a >= b && x >= y | ||||
|  | ||||
|         $q = '0'; // quotient | ||||
|         $r = $a; // remainder | ||||
|         $z = $y; // focus length, always $y or $y+1 | ||||
|  | ||||
|         for (;;) { | ||||
|             $focus = \substr($a, 0, $z); | ||||
|  | ||||
|             $cmp = $this->doCmp($focus, $b); | ||||
|  | ||||
|             if ($cmp === -1) { | ||||
|                 if ($z === $x) { // remainder < dividend | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 $z++; | ||||
|             } | ||||
|  | ||||
|             $zeros = \str_repeat('0', $x - $z); | ||||
|  | ||||
|             $q = $this->add($q, '1' . $zeros); | ||||
|             $a = $this->sub($a, $b . $zeros); | ||||
|  | ||||
|             $r = $a; | ||||
|  | ||||
|             if ($r === '0') { // remainder == 0 | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $x = \strlen($a); | ||||
|  | ||||
|             if ($x < $y) { // remainder < dividend | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             $z = $y; | ||||
|         } | ||||
|  | ||||
|         return [$q, $r]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Compares two non-signed large numbers. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return int [-1, 0, 1] | ||||
|      */ | ||||
|     private function doCmp(string $a, string $b) : int | ||||
|     { | ||||
|         $x = \strlen($a); | ||||
|         $y = \strlen($b); | ||||
|  | ||||
|         $cmp = $x <=> $y; | ||||
|  | ||||
|         if ($cmp !== 0) { | ||||
|             return $cmp; | ||||
|         } | ||||
|  | ||||
|         return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length. | ||||
|      * | ||||
|      * The numbers must only consist of digits, without leading minus sign. | ||||
|      * | ||||
|      * @param string $a The first operand. | ||||
|      * @param string $b The second operand. | ||||
|      * | ||||
|      * @return array{string, string, int} | ||||
|      */ | ||||
|     private function pad(string $a, string $b) : array | ||||
|     { | ||||
|         $x = \strlen($a); | ||||
|         $y = \strlen($b); | ||||
|  | ||||
|         if ($x > $y) { | ||||
|             $b = \str_repeat('0', $x - $y) . $b; | ||||
|  | ||||
|             return [$a, $b, $x]; | ||||
|         } | ||||
|  | ||||
|         if ($x < $y) { | ||||
|             $a = \str_repeat('0', $y - $x) . $a; | ||||
|  | ||||
|             return [$a, $b, $y]; | ||||
|         } | ||||
|  | ||||
|         return [$a, $b, $x]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										107
									
								
								vendor/brick/math/src/RoundingMode.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								vendor/brick/math/src/RoundingMode.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Brick\Math; | ||||
|  | ||||
| /** | ||||
|  * Specifies a rounding behavior for numerical operations capable of discarding precision. | ||||
|  * | ||||
|  * Each rounding mode indicates how the least significant returned digit of a rounded result | ||||
|  * is to be calculated. If fewer digits are returned than the digits needed to represent the | ||||
|  * exact numerical result, the discarded digits will be referred to as the discarded fraction | ||||
|  * regardless the digits' contribution to the value of the number. In other words, considered | ||||
|  * as a numerical value, the discarded fraction could have an absolute value greater than one. | ||||
|  */ | ||||
| final class RoundingMode | ||||
| { | ||||
|     /** | ||||
|      * Private constructor. This class is not instantiable. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     private function __construct() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Asserts that the requested operation has an exact result, hence no rounding is necessary. | ||||
|      * | ||||
|      * If this rounding mode is specified on an operation that yields a result that | ||||
|      * cannot be represented at the requested scale, a RoundingNecessaryException is thrown. | ||||
|      */ | ||||
|     public const UNNECESSARY = 0; | ||||
|  | ||||
|     /** | ||||
|      * Rounds away from zero. | ||||
|      * | ||||
|      * Always increments the digit prior to a nonzero discarded fraction. | ||||
|      * Note that this rounding mode never decreases the magnitude of the calculated value. | ||||
|      */ | ||||
|     public const UP = 1; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards zero. | ||||
|      * | ||||
|      * Never increments the digit prior to a discarded fraction (i.e., truncates). | ||||
|      * Note that this rounding mode never increases the magnitude of the calculated value. | ||||
|      */ | ||||
|     public const DOWN = 2; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards positive infinity. | ||||
|      * | ||||
|      * If the result is positive, behaves as for UP; if negative, behaves as for DOWN. | ||||
|      * Note that this rounding mode never decreases the calculated value. | ||||
|      */ | ||||
|     public const CEILING = 3; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards negative infinity. | ||||
|      * | ||||
|      * If the result is positive, behave as for DOWN; if negative, behave as for UP. | ||||
|      * Note that this rounding mode never increases the calculated value. | ||||
|      */ | ||||
|     public const FLOOR = 4; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up. | ||||
|      * | ||||
|      * Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN. | ||||
|      * Note that this is the rounding mode commonly taught at school. | ||||
|      */ | ||||
|     public const HALF_UP = 5; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. | ||||
|      * | ||||
|      * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. | ||||
|      */ | ||||
|     public const HALF_DOWN = 6; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. | ||||
|      * | ||||
|      * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. | ||||
|      */ | ||||
|     public const HALF_CEILING = 7; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. | ||||
|      * | ||||
|      * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. | ||||
|      */ | ||||
|     public const HALF_FLOOR = 8; | ||||
|  | ||||
|     /** | ||||
|      * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. | ||||
|      * | ||||
|      * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd; | ||||
|      * behaves as for HALF_DOWN if it's even. | ||||
|      * | ||||
|      * Note that this is the rounding mode that statistically minimizes | ||||
|      * cumulative error when applied repeatedly over a sequence of calculations. | ||||
|      * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. | ||||
|      */ | ||||
|     public const HALF_EVEN = 9; | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/clue/stream-filter/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/clue/stream-filter/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| github: clue | ||||
| custom: https://clue.engineering/support | ||||
							
								
								
									
										2
									
								
								vendor/clue/stream-filter/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/clue/stream-filter/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +0,0 @@ | ||||
| /vendor | ||||
| /composer.lock | ||||
							
								
								
									
										27
									
								
								vendor/clue/stream-filter/.travis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/clue/stream-filter/.travis.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | ||||
| language: php | ||||
|  | ||||
| php: | ||||
| # - 5.3 # requires old distro, see below | ||||
|   - 5.4 | ||||
|   - 5.5 | ||||
|   - 5.6 | ||||
|   - 7.0 | ||||
|   - 7.1 | ||||
|   - 7.2 | ||||
|   - hhvm # ignore errors, see below | ||||
|  | ||||
| # lock distro so new future defaults will not break the build | ||||
| dist: trusty | ||||
|  | ||||
| matrix: | ||||
|   include: | ||||
|     - php: 5.3 | ||||
|       dist: precise | ||||
|   allow_failures: | ||||
|     - php: hhvm | ||||
|  | ||||
| install: | ||||
|   - composer install --no-interaction | ||||
|  | ||||
| script: | ||||
|   - vendor/bin/phpunit --coverage-text | ||||
							
								
								
									
										23
									
								
								vendor/clue/stream-filter/CHANGELOG.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/clue/stream-filter/CHANGELOG.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,28 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 1.6.0 (2022-02-21) | ||||
|  | ||||
| *   Feature: Support PHP 8.1 release. | ||||
|     (#45 by @clue) | ||||
|  | ||||
| *   Improve documentation to use fully-qualified function names. | ||||
|     (#43 by @SimonFrings and #42 by @PaulRotmann) | ||||
|  | ||||
| *   Improve test suite and use GitHub actions for continuous integration (CI). | ||||
|     (#39 and #40 by @SimonFrings) | ||||
|  | ||||
| ## 1.5.0 (2020-10-02) | ||||
|  | ||||
| *   Feature: Improve performance by using global imports. | ||||
|     (#38 by @clue) | ||||
|  | ||||
| *   Improve API documentation and add support / sponsorship info. | ||||
|     (#30 by @clue and #35 by @SimonFrings) | ||||
|  | ||||
| *   Improve test suite and add `.gitattributes` to exclude dev files from exports. | ||||
|     Prepare PHP 8 support, update to PHPUnit 9 and simplify test matrix. | ||||
|     (#32 and #37 by @clue and #34 and #36 by @SimonFrings) | ||||
|  | ||||
| ## 1.4.1 (2019-04-09) | ||||
|  | ||||
| *   Fix: Check if the function is declared before declaring it. | ||||
|   | ||||
							
								
								
									
										111
									
								
								vendor/clue/stream-filter/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										111
									
								
								vendor/clue/stream-filter/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,10 +1,14 @@ | ||||
| # clue/stream-filter [](https://travis-ci.org/clue/php-stream-filter) | ||||
| # clue/stream-filter | ||||
|  | ||||
| [](https://github.com/clue/stream-filter/actions) | ||||
| [](https://packagist.org/packages/clue/stream-filter) | ||||
|  | ||||
| A simple and modern approach to stream filtering in PHP | ||||
|  | ||||
| **Table of contents** | ||||
|  | ||||
| * [Why?](#why) | ||||
| * [Support us](#support-us) | ||||
| * [Usage](#usage) | ||||
|     * [append()](#append) | ||||
|     * [prepend()](#prepend) | ||||
| @@ -39,12 +43,36 @@ This project aims to make these features more accessible to a broader audience. | ||||
| * **Good test coverage** - | ||||
|   Comes with an automated tests suite and is regularly tested in the *real world* | ||||
|  | ||||
| ## Support us | ||||
|  | ||||
| We invest a lot of time developing, maintaining and updating our awesome | ||||
| open-source projects. You can help us sustain this high-quality of our work by | ||||
| [becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get | ||||
| numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue) | ||||
| for details. | ||||
|  | ||||
| Let's take these projects to the next level together! 🚀 | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| This lightweight library consists only of a few simple functions. | ||||
| All functions reside under the `Clue\StreamFilter` namespace. | ||||
|  | ||||
| The below examples assume you use an import statement similar to this: | ||||
| The below examples refer to all functions with their fully-qualified names like this: | ||||
|  | ||||
| ```php | ||||
| Clue\StreamFilter\append(…); | ||||
| ``` | ||||
|  | ||||
| As of PHP 5.6+ you can also import each required function into your code like this: | ||||
|  | ||||
| ```php | ||||
| use function Clue\StreamFilter\append; | ||||
|  | ||||
| append(…); | ||||
| ``` | ||||
|  | ||||
| Alternatively, you can also use an import statement similar to this: | ||||
|  | ||||
| ```php | ||||
| use Clue\StreamFilter as Filter; | ||||
| @@ -52,21 +80,14 @@ use Clue\StreamFilter as Filter; | ||||
| Filter\append(…); | ||||
| ``` | ||||
|  | ||||
| Alternatively, you can also refer to them with their fully-qualified name: | ||||
|  | ||||
| ```php | ||||
| \Clue\StreamFilter\append(…); | ||||
| ``` | ||||
|  | ||||
| ### append() | ||||
|  | ||||
| The `append($stream, $callback, $read_write = STREAM_FILTER_ALL)` function can be used to | ||||
| The `append(resource<stream> $stream, callable $callback, int $read_write = STREAM_FILTER_ALL): resource<stream filter>` function can be used to | ||||
| append a filter callback to the given stream. | ||||
|  | ||||
| Each stream can have a list of filters attached. | ||||
| This function appends a filter to the end of this list. | ||||
|  | ||||
| This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
| If the given filter can not be added, it throws an `Exception`. | ||||
|  | ||||
| The `$stream` can be any valid stream resource, such as: | ||||
| @@ -75,11 +96,11 @@ The `$stream` can be any valid stream resource, such as: | ||||
| $stream = fopen('demo.txt', 'w+'); | ||||
| ``` | ||||
|  | ||||
| The `$callback` should be a valid callable function which accepts an individual chunk of data | ||||
| and should return the updated chunk: | ||||
| The `$callback` should be a valid callable function which accepts  | ||||
| an individual chunk of data and should return the updated chunk: | ||||
|  | ||||
| ```php | ||||
| $filter = Filter\append($stream, function ($chunk) { | ||||
| $filter = Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|     // will be called each time you read or write a $chunk to/from the stream | ||||
|     return $chunk; | ||||
| }); | ||||
| @@ -88,17 +109,17 @@ $filter = Filter\append($stream, function ($chunk) { | ||||
| As such, you can also use native PHP functions or any other `callable`: | ||||
|  | ||||
| ```php | ||||
| Filter\append($stream, 'strtoupper'); | ||||
| Clue\StreamFilter\append($stream, 'strtoupper'); | ||||
|  | ||||
| // will write "HELLO" to the underlying stream | ||||
| fwrite($stream, 'hello'); | ||||
| ``` | ||||
|  | ||||
| If the `$callback` accepts invocation without parameters, then this signature | ||||
| will be invoked once ending (flushing) the filter: | ||||
| If the `$callback` accepts invocation without parameters, | ||||
| then this signature will be invoked once ending (flushing) the filter: | ||||
|  | ||||
| ```php | ||||
| Filter\append($stream, function ($chunk = null) { | ||||
| Clue\StreamFilter\append($stream, function ($chunk = null) { | ||||
|     if ($chunk === null) { | ||||
|         // will be called once ending the filter | ||||
|         return 'end'; | ||||
| @@ -114,11 +135,11 @@ fclose($stream); | ||||
| from the end signal handler if the stream is being closed. | ||||
|  | ||||
| If your callback throws an `Exception`, then the filter process will be aborted. | ||||
| In order to play nice with PHP's stream handling, the `Exception` will be | ||||
| transformed to a PHP warning instead: | ||||
| In order to play nice with PHP's stream handling, | ||||
| the `Exception` will be transformed to a PHP warning instead: | ||||
|  | ||||
| ```php | ||||
| Filter\append($stream, function ($chunk) { | ||||
| Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|     throw new \RuntimeException('Unexpected chunk'); | ||||
| }); | ||||
|  | ||||
| @@ -126,20 +147,23 @@ Filter\append($stream, function ($chunk) { | ||||
| fwrite($stream, 'hello'); | ||||
| ``` | ||||
|  | ||||
| The optional `$read_write` parameter can be used to only invoke the `$callback` when either writing to the stream or only when reading from the stream: | ||||
| The optional `$read_write` parameter can be used to only invoke the `$callback` | ||||
| when either writing to the stream or only when reading from the stream: | ||||
|  | ||||
| ```php | ||||
| Filter\append($stream, function ($chunk) { | ||||
| Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|     // will be called each time you write to the stream | ||||
|     return $chunk; | ||||
| }, STREAM_FILTER_WRITE); | ||||
|  | ||||
| Filter\append($stream, function ($chunk) { | ||||
| Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|     // will be called each time you read from the stream | ||||
|     return $chunk; | ||||
| }, STREAM_FILTER_READ); | ||||
| ``` | ||||
|  | ||||
| This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
|  | ||||
| > Note that once a filter has been added to stream, the stream can no longer be passed to | ||||
| > [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php) | ||||
| > (and family). | ||||
| @@ -153,29 +177,30 @@ Filter\append($stream, function ($chunk) { | ||||
|  | ||||
| ### prepend() | ||||
|  | ||||
| The `prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)` function can be used to | ||||
| The `prepend(resource<stream> $stream, callable $callback, int $read_write = STREAM_FILTER_ALL): resource<stream filter>` function can be used to | ||||
| prepend a filter callback to the given stream. | ||||
|  | ||||
| Each stream can have a list of filters attached. | ||||
| This function prepends a filter to the start of this list. | ||||
|  | ||||
| This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
| If the given filter can not be added, it throws an `Exception`. | ||||
|  | ||||
| ```php | ||||
| $filter = Filter\prepend($stream, function ($chunk) { | ||||
| $filter = Clue\StreamFilter\prepend($stream, function ($chunk) { | ||||
|     // will be called each time you read or write a $chunk to/from the stream | ||||
|     return $chunk; | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
|  | ||||
| Except for the position in the list of filters, this function behaves exactly | ||||
| like the [`append()`](#append) function. | ||||
| For more details about its behavior, see also the [`append()`](#append) function. | ||||
|  | ||||
| ### fun() | ||||
|  | ||||
| The `fun($filter, $parameters = null)` function can be used to | ||||
| The `fun(string $filter, mixed $parameters = null): callable` function can be used to | ||||
| create a filter function which uses the given built-in `$filter`. | ||||
|  | ||||
| PHP comes with a useful set of [built-in filters](https://www.php.net/manual/en/filters.php). | ||||
| @@ -183,20 +208,20 @@ Using `fun()` makes accessing these as easy as passing an input string to filter | ||||
| and getting the filtered output string. | ||||
|  | ||||
| ```php | ||||
| $fun = Filter\fun('string.rot13'); | ||||
| $fun = Clue\StreamFilter\fun('string.rot13'); | ||||
|  | ||||
| assert('grfg' === $fun('test')); | ||||
| assert('test' === $fun($fun('test')); | ||||
| ``` | ||||
|  | ||||
| Please note that not all filter functions may be available depending on installed | ||||
| PHP extensions and the PHP version in use. | ||||
| Please note that not all filter functions may be available depending  | ||||
| on installed PHP extensions and the PHP version in use. | ||||
| In particular, [HHVM](https://hhvm.com/) may not offer the same filter functions | ||||
| or parameters as Zend PHP. | ||||
| Accessing an unknown filter function will result in a `RuntimeException`: | ||||
|  | ||||
| ```php | ||||
| Filter\fun('unknown'); // throws RuntimeException | ||||
| Clue\StreamFilter\fun('unknown'); // throws RuntimeException | ||||
| ``` | ||||
|  | ||||
| Some filters may accept or require additional filter parameters – most | ||||
| @@ -209,7 +234,7 @@ Please refer to the individual filter definition for more details. | ||||
| For example, the `string.strip_tags` filter can be invoked like this: | ||||
|  | ||||
| ```php | ||||
| $fun = Filter\fun('string.strip_tags', '<a><b>'); | ||||
| $fun = Clue\StreamFilter\fun('string.strip_tags', '<a><b>'); | ||||
|  | ||||
| $ret = $fun('<b>h<br>i</b>'); | ||||
| assert('<b>hi</b>' === $ret); | ||||
| @@ -223,7 +248,7 @@ may use internal buffers and may emit a final data chunk on close. | ||||
| The filter function can be closed by invoking without any arguments: | ||||
|  | ||||
| ```php | ||||
| $fun = Filter\fun('zlib.deflate'); | ||||
| $fun = Clue\StreamFilter\fun('zlib.deflate'); | ||||
|  | ||||
| $ret = $fun('hello') . $fun('world') . $fun(); | ||||
| assert('helloworld' === gzinflate($ret)); | ||||
| @@ -233,7 +258,7 @@ The filter function must not be used anymore after it has been closed. | ||||
| Doing so will result in a `RuntimeException`: | ||||
|  | ||||
| ```php | ||||
| $fun = Filter\fun('string.rot13'); | ||||
| $fun = Clue\StreamFilter\fun('string.rot13'); | ||||
| $fun(); | ||||
|  | ||||
| $fun('test'); // throws RuntimeException | ||||
| @@ -248,40 +273,40 @@ If you feel some test case is missing or outdated, we're happy to accept PRs! :) | ||||
|  | ||||
| ### remove() | ||||
|  | ||||
| The `remove($filter)` function can be used to | ||||
| The `remove(resource<stream filter> $filter): bool` function can be used to | ||||
| remove a filter previously added via [`append()`](#append) or [`prepend()`](#prepend). | ||||
|  | ||||
| ```php | ||||
| $filter = Filter\append($stream, function () { | ||||
| $filter = Clue\StreamFilter\append($stream, function () { | ||||
|     // … | ||||
| }); | ||||
| Filter\remove($filter); | ||||
| Clue\StreamFilter\remove($filter); | ||||
| ``` | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| The recommended way to install this library is [through Composer](https://getcomposer.org). | ||||
| The recommended way to install this library is [through Composer](https://getcomposer.org/). | ||||
| [New to Composer?](https://getcomposer.org/doc/00-intro.md) | ||||
|  | ||||
| This project follows [SemVer](https://semver.org/). | ||||
| This will install the latest supported version: | ||||
|  | ||||
| ```bash | ||||
| $ composer require clue/stream-filter:^1.4.1 | ||||
| $ composer require clue/stream-filter:^1.6 | ||||
| ``` | ||||
|  | ||||
| See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. | ||||
|  | ||||
| This project aims to run on any platform and thus does not require any PHP | ||||
| extensions and supports running on legacy PHP 5.3 through current PHP 7+ and | ||||
| extensions and supports running on legacy PHP 5.3 through current PHP 8+ and | ||||
| HHVM. | ||||
| It's *highly recommended to use PHP 7+* for this project. | ||||
| It's *highly recommended to use the latest supported PHP version* for this project. | ||||
| Older PHP versions may suffer from a number of inconsistencies documented above. | ||||
|  | ||||
| ## Tests | ||||
|  | ||||
| To run the test suite, you first need to clone this repo and then install all | ||||
| dependencies [through Composer](https://getcomposer.org): | ||||
| dependencies [through Composer](https://getcomposer.org/): | ||||
|  | ||||
| ```bash | ||||
| $ composer install | ||||
| @@ -290,7 +315,7 @@ $ composer install | ||||
| To run the test suite, go to the project root and run: | ||||
|  | ||||
| ```bash | ||||
| $ php vendor/bin/phpunit | ||||
| $ vendor/bin/phpunit | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/clue/stream-filter/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/clue/stream-filter/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -7,17 +7,20 @@ | ||||
|     "authors": [ | ||||
|         { | ||||
|             "name": "Christian Lück", | ||||
|             "email": "christian@lueck.tv" | ||||
|             "email": "christian@clue.engineering" | ||||
|         } | ||||
|     ], | ||||
|     "require": { | ||||
|         "php": ">=5.3" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "^5.0 || ^4.8" | ||||
|         "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { "Clue\\StreamFilter\\": "src/" }, | ||||
|         "files": [ "src/functions_include.php" ] | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { "Clue\\Tests\\StreamFilter\\": "tests/" } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // $ echo test | php examples/base64_encode.php | php examples/base64_decode.php | ||||
|  | ||||
| require __DIR__ . '/../vendor/autoload.php'; | ||||
|  | ||||
| // decoding requires buffering in chunks of 4 bytes each | ||||
| $buffer = ''; | ||||
| Clue\StreamFilter\append(STDIN, function ($chunk = null) use (&$buffer) { | ||||
|     if ($chunk === null) { | ||||
|         if (strlen($buffer) % 4 !== 0) { | ||||
|             throw new \UnexpectedValueException('Invalid length'); | ||||
|         } | ||||
|         $chunk = $buffer; | ||||
|     } else { | ||||
|         $buffer .= $chunk; | ||||
|         $len = strlen($buffer) - (strlen($buffer) % 4); | ||||
|         $chunk = (string)substr($buffer, 0, $len); | ||||
|         $buffer = (string)substr($buffer, $len); | ||||
|     } | ||||
|  | ||||
|     $ret = base64_decode($chunk, true); | ||||
|     if ($ret === false) { | ||||
|         throw new \UnexpectedValueException('Not a valid base64 encoded chunk'); | ||||
|     } | ||||
|     return $ret; | ||||
| }, STREAM_FILTER_READ); | ||||
|  | ||||
| fpassthru(STDIN); | ||||
| @@ -1,21 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // $ echo test | php examples/base64_encode.php | base64 --decode | ||||
|  | ||||
| require __DIR__ . '/../vendor/autoload.php'; | ||||
|  | ||||
| // encoding requires buffering in chunks of 3 bytes each | ||||
| $buffer = ''; | ||||
| Clue\StreamFilter\append(STDIN, function ($chunk = null) use (&$buffer) { | ||||
|     if ($chunk === null) { | ||||
|         return base64_encode($buffer); | ||||
|     } | ||||
|     $buffer .= $chunk; | ||||
|     $len = strlen($buffer) - (strlen($buffer) % 3); | ||||
|     $chunk = substr($buffer, 0, $len); | ||||
|     $buffer = substr($buffer, $len); | ||||
|  | ||||
|     return base64_encode($chunk); | ||||
| }, STREAM_FILTER_READ); | ||||
|  | ||||
| fpassthru(STDIN); | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // $ echo test | php examples/uppercase.php | ||||
|  | ||||
| require __DIR__ . '/../vendor/autoload.php'; | ||||
|  | ||||
| Clue\StreamFilter\append(STDIN, 'strtoupper'); | ||||
|  | ||||
| fpassthru(STDIN); | ||||
							
								
								
									
										19
									
								
								vendor/clue/stream-filter/phpunit.xml.dist
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/clue/stream-filter/phpunit.xml.dist
									
									
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
| <phpunit bootstrap="vendor/autoload.php" | ||||
|          colors="true" | ||||
|          convertErrorsToExceptions="true" | ||||
|          convertNoticesToExceptions="true" | ||||
|          convertWarningsToExceptions="true" | ||||
| > | ||||
|     <testsuites> | ||||
|         <testsuite> | ||||
|             <directory>./tests/</directory> | ||||
|         </testsuite> | ||||
|     </testsuites> | ||||
|     <filter> | ||||
|         <whitelist> | ||||
|             <directory>./src/</directory> | ||||
|         </whitelist> | ||||
|     </filter> | ||||
| </phpunit> | ||||
							
								
								
									
										50
									
								
								vendor/clue/stream-filter/src/CallbackFilter.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/clue/stream-filter/src/CallbackFilter.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,39 +2,37 @@ | ||||
|  | ||||
| namespace Clue\StreamFilter; | ||||
|  | ||||
| use php_user_filter; | ||||
| use InvalidArgumentException; | ||||
| use ReflectionFunction; | ||||
| use Exception; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @internal | ||||
|  * @see append() | ||||
|  * @see prepend() | ||||
|  */ | ||||
| class CallbackFilter extends php_user_filter | ||||
| class CallbackFilter extends \php_user_filter | ||||
| { | ||||
|     private $callback; | ||||
|     private $closed = true; | ||||
|     private $supportsClose = false; | ||||
|  | ||||
|     /** @return bool */ | ||||
|     #[\ReturnTypeWillChange] | ||||
|     public function onCreate() | ||||
|     { | ||||
|         $this->closed = false; | ||||
|  | ||||
|         if (!is_callable($this->params)) { | ||||
|             throw new InvalidArgumentException('No valid callback parameter given to stream_filter_(append|prepend)'); | ||||
|         if (!\is_callable($this->params)) { | ||||
|             throw new \InvalidArgumentException('No valid callback parameter given to stream_filter_(append|prepend)'); | ||||
|         } | ||||
|         $this->callback = $this->params; | ||||
|  | ||||
|         // callback supports end event if it accepts invocation without arguments | ||||
|         $ref = new ReflectionFunction($this->callback); | ||||
|         $ref = new \ReflectionFunction($this->callback); | ||||
|         $this->supportsClose = ($ref->getNumberOfRequiredParameters() === 0); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** @return void */ | ||||
|     #[\ReturnTypeWillChange] | ||||
|     public function onClose() | ||||
|     { | ||||
|         $this->closed = true; | ||||
| @@ -44,8 +42,8 @@ class CallbackFilter extends php_user_filter | ||||
|             $this->supportsClose = false; | ||||
|             // invoke without argument to signal end and discard resulting buffer | ||||
|             try { | ||||
|                 call_user_func($this->callback); | ||||
|             } catch (Exception $ignored) { | ||||
|                 \call_user_func($this->callback); | ||||
|             } catch (\Exception $ignored) { | ||||
|                 // this might be called during engine shutdown, so it's not safe | ||||
|                 // to raise any errors or exceptions here | ||||
|                 // trigger_error('Error closing filter: ' . $ignored->getMessage(), E_USER_WARNING); | ||||
| @@ -55,31 +53,33 @@ class CallbackFilter extends php_user_filter | ||||
|         $this->callback = null; | ||||
|     } | ||||
|  | ||||
|     /** @return int */ | ||||
|     #[\ReturnTypeWillChange] | ||||
|     public function filter($in, $out, &$consumed, $closing) | ||||
|     { | ||||
|         // concatenate whole buffer from input brigade | ||||
|         $data = ''; | ||||
|         while ($bucket = stream_bucket_make_writeable($in)) { | ||||
|         while ($bucket = \stream_bucket_make_writeable($in)) { | ||||
|             $consumed += $bucket->datalen; | ||||
|             $data .= $bucket->data; | ||||
|         } | ||||
|  | ||||
|         // skip processing callback that already ended | ||||
|         if ($this->closed) { | ||||
|             return PSFS_FEED_ME; | ||||
|             return \PSFS_FEED_ME; | ||||
|         } | ||||
|  | ||||
|         // only invoke filter function if buffer is not empty | ||||
|         // this may skip flushing a closing filter | ||||
|         if ($data !== '') { | ||||
|             try { | ||||
|                 $data = call_user_func($this->callback, $data); | ||||
|             } catch (Exception $e) { | ||||
|                 $data = \call_user_func($this->callback, $data); | ||||
|             } catch (\Exception $e) { | ||||
|                 // exception should mark filter as closed | ||||
|                 $this->onClose(); | ||||
|                 trigger_error('Error invoking filter: ' . $e->getMessage(), E_USER_WARNING); | ||||
|                 \trigger_error('Error invoking filter: ' . $e->getMessage(), \E_USER_WARNING); | ||||
|  | ||||
|                 return PSFS_ERR_FATAL; | ||||
|                 return \PSFS_ERR_FATAL; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -93,11 +93,11 @@ class CallbackFilter extends php_user_filter | ||||
|  | ||||
|                 // invoke without argument to signal end and append resulting buffer | ||||
|                 try { | ||||
|                     $data .= call_user_func($this->callback); | ||||
|                 } catch (Exception $e) { | ||||
|                     trigger_error('Error ending filter: ' . $e->getMessage(), E_USER_WARNING); | ||||
|                     $data .= \call_user_func($this->callback); | ||||
|                 } catch (\Exception $e) { | ||||
|                     \trigger_error('Error ending filter: ' . $e->getMessage(), \E_USER_WARNING); | ||||
|  | ||||
|                     return PSFS_ERR_FATAL; | ||||
|                     return \PSFS_ERR_FATAL; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -105,16 +105,16 @@ class CallbackFilter extends php_user_filter | ||||
|         if ($data !== '') { | ||||
|             // create a new bucket for writing the resulting buffer to the output brigade | ||||
|             // reusing an existing bucket turned out to be bugged in some environments (ancient PHP versions and HHVM) | ||||
|             $bucket = @stream_bucket_new($this->stream, $data); | ||||
|             $bucket = @\stream_bucket_new($this->stream, $data); | ||||
|  | ||||
|             // legacy PHP versions (PHP < 5.4) do not support passing data from the event signal handler | ||||
|             // because closing the stream invalidates the stream and its stream bucket brigade before | ||||
|             // invoking the filter close handler. | ||||
|             if ($bucket !== false) { | ||||
|                 stream_bucket_append($out, $bucket); | ||||
|                 \stream_bucket_append($out, $bucket); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return PSFS_PASS_ON; | ||||
|         return \PSFS_PASS_ON; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										243
									
								
								vendor/clue/stream-filter/src/functions.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										243
									
								
								vendor/clue/stream-filter/src/functions.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,54 +2,187 @@ | ||||
|  | ||||
| namespace Clue\StreamFilter; | ||||
|  | ||||
| use RuntimeException; | ||||
|  | ||||
| /** | ||||
|  * append a callback filter to the given stream | ||||
|  * Append a filter callback to the given stream. | ||||
|  * | ||||
|  * Each stream can have a list of filters attached. | ||||
|  * This function appends a filter to the end of this list. | ||||
|  * | ||||
|  * If the given filter can not be added, it throws an `Exception`. | ||||
|  * | ||||
|  * The `$stream` can be any valid stream resource, such as: | ||||
|  * | ||||
|  * ```php | ||||
|  * $stream = fopen('demo.txt', 'w+'); | ||||
|  * ``` | ||||
|  * | ||||
|  * The `$callback` should be a valid callable function which accepts | ||||
|  * an individual chunk of data and should return the updated chunk: | ||||
|  * | ||||
|  * ```php | ||||
|  * $filter = Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|  *     // will be called each time you read or write a $chunk to/from the stream | ||||
|  *     return $chunk; | ||||
|  * }); | ||||
|  * ``` | ||||
|  * | ||||
|  * As such, you can also use native PHP functions or any other `callable`: | ||||
|  * | ||||
|  * ```php | ||||
|  * Clue\StreamFilter\append($stream, 'strtoupper'); | ||||
|  * | ||||
|  * // will write "HELLO" to the underlying stream | ||||
|  * fwrite($stream, 'hello'); | ||||
|  * ``` | ||||
|  * | ||||
|  * If the `$callback` accepts invocation without parameters, | ||||
|  * then this signature will be invoked once ending (flushing) the filter: | ||||
|  * | ||||
|  * ```php | ||||
|  * Clue\StreamFilter\append($stream, function ($chunk = null) { | ||||
|  *     if ($chunk === null) { | ||||
|  *         // will be called once ending the filter | ||||
|  *         return 'end'; | ||||
|  *     } | ||||
|  *     // will be called each time you read or write a $chunk to/from the stream | ||||
|  *     return $chunk; | ||||
|  * }); | ||||
|  * | ||||
|  * fclose($stream); | ||||
|  * ``` | ||||
|  * | ||||
|  * > Note: Legacy PHP versions (PHP < 5.4) do not support passing additional data | ||||
|  * from the end signal handler if the stream is being closed. | ||||
|  * | ||||
|  * If your callback throws an `Exception`, then the filter process will be aborted. | ||||
|  * In order to play nice with PHP's stream handling, | ||||
|  * the `Exception` will be transformed to a PHP warning instead: | ||||
|  * | ||||
|  * ```php | ||||
|  * Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|  *     throw new \RuntimeException('Unexpected chunk'); | ||||
|  * }); | ||||
|  * | ||||
|  * // raises an E_USER_WARNING with "Error invoking filter: Unexpected chunk" | ||||
|  * fwrite($stream, 'hello'); | ||||
|  * ``` | ||||
|  * | ||||
|  * The optional `$read_write` parameter can be used to only invoke the `$callback` | ||||
|  * when either writing to the stream or only when reading from the stream: | ||||
|  * | ||||
|  * ```php | ||||
|  * Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|  *     // will be called each time you write to the stream | ||||
|  *     return $chunk; | ||||
|  * }, STREAM_FILTER_WRITE); | ||||
|  * | ||||
|  * Clue\StreamFilter\append($stream, function ($chunk) { | ||||
|  *     // will be called each time you read from the stream | ||||
|  *     return $chunk; | ||||
|  * }, STREAM_FILTER_READ); | ||||
|  * ``` | ||||
|  * | ||||
|  * This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
|  * | ||||
|  * > Note that once a filter has been added to stream, the stream can no longer be passed to | ||||
|  * > [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php) | ||||
|  * > (and family). | ||||
|  * > | ||||
|  * > > Warning: stream_select(): cannot cast a filtered stream on this system in {file} on line {line} | ||||
|  * > | ||||
|  * > This is due to limitations of PHP's stream filter support, as it can no longer reliably | ||||
|  * > tell when the underlying stream resource is actually ready. | ||||
|  * > As an alternative, consider calling `stream_select()` on the unfiltered stream and | ||||
|  * > then pass the unfiltered data through the [`fun()`](#fun) function. | ||||
|  * | ||||
|  * @param resource $stream | ||||
|  * @param callable $callback | ||||
|  * @param int $read_write | ||||
|  * @return resource filter resource which can be used for `remove()` | ||||
|  * @throws Exception on error | ||||
|  * @throws \Exception on error | ||||
|  * @uses stream_filter_append() | ||||
|  */ | ||||
| function append($stream, $callback, $read_write = STREAM_FILTER_ALL) | ||||
| { | ||||
|     $ret = @stream_filter_append($stream, register(), $read_write, $callback); | ||||
|     $ret = @\stream_filter_append($stream, register(), $read_write, $callback); | ||||
|  | ||||
|     // PHP 8 throws above on type errors, older PHP and memory issues can throw here | ||||
|     // @codeCoverageIgnoreStart | ||||
|     if ($ret === false) { | ||||
|         $error = error_get_last() + array('message' => ''); | ||||
|         throw new RuntimeException('Unable to append filter: ' . $error['message']); | ||||
|         $error = \error_get_last() + array('message' => ''); | ||||
|         throw new \RuntimeException('Unable to append filter: ' . $error['message']); | ||||
|     } | ||||
|     // @codeCoverageIgnoreEnd | ||||
|  | ||||
|     return $ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * prepend a callback filter to the given stream | ||||
|  * Prepend a filter callback to the given stream. | ||||
|  * | ||||
|  * Each stream can have a list of filters attached. | ||||
|  * This function prepends a filter to the start of this list. | ||||
|  * | ||||
|  * If the given filter can not be added, it throws an `Exception`. | ||||
|  * | ||||
|  * ```php | ||||
|  * $filter = Clue\StreamFilter\prepend($stream, function ($chunk) { | ||||
|  *     // will be called each time you read or write a $chunk to/from the stream | ||||
|  *     return $chunk; | ||||
|  * }); | ||||
|  * ``` | ||||
|  * | ||||
|  * This function returns a filter resource which can be passed to [`remove()`](#remove). | ||||
|  * | ||||
|  * Except for the position in the list of filters, this function behaves exactly | ||||
|  * like the [`append()`](#append) function. | ||||
|  * For more details about its behavior, see also the [`append()`](#append) function. | ||||
|  * | ||||
|  * @param resource $stream | ||||
|  * @param callable $callback | ||||
|  * @param int $read_write | ||||
|  * @return resource filter resource which can be used for `remove()` | ||||
|  * @throws Exception on error | ||||
|  * @throws \Exception on error | ||||
|  * @uses stream_filter_prepend() | ||||
|  */ | ||||
| function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL) | ||||
| { | ||||
|     $ret = @stream_filter_prepend($stream, register(), $read_write, $callback); | ||||
|     $ret = @\stream_filter_prepend($stream, register(), $read_write, $callback); | ||||
|  | ||||
|     // PHP 8 throws above on type errors, older PHP and memory issues can throw here | ||||
|     // @codeCoverageIgnoreStart | ||||
|     if ($ret === false) { | ||||
|         $error = error_get_last() + array('message' => ''); | ||||
|         throw new RuntimeException('Unable to prepend filter: ' . $error['message']); | ||||
|         $error = \error_get_last() + array('message' => ''); | ||||
|         throw new \RuntimeException('Unable to prepend filter: ' . $error['message']); | ||||
|     } | ||||
|     // @codeCoverageIgnoreEnd | ||||
|  | ||||
|     return $ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Creates filter fun (function) which uses the given built-in $filter | ||||
|  * Create a filter function which uses the given built-in `$filter`. | ||||
|  * | ||||
|  * PHP comes with a useful set of [built-in filters](https://www.php.net/manual/en/filters.php). | ||||
|  * Using `fun()` makes accessing these as easy as passing an input string to filter | ||||
|  * and getting the filtered output string. | ||||
|  * | ||||
|  * ```php | ||||
|  * $fun = Clue\StreamFilter\fun('string.rot13'); | ||||
|  * | ||||
|  * assert('grfg' === $fun('test')); | ||||
|  * assert('test' === $fun($fun('test')); | ||||
|  * ``` | ||||
|  * | ||||
|  * Please note that not all filter functions may be available depending | ||||
|  * on installed PHP extensions and the PHP version in use. | ||||
|  * In particular, [HHVM](https://hhvm.com/) may not offer the same filter functions | ||||
|  * or parameters as Zend PHP. | ||||
|  * Accessing an unknown filter function will result in a `RuntimeException`: | ||||
|  * | ||||
|  * ```php | ||||
|  * Clue\StreamFilter\fun('unknown'); // throws RuntimeException | ||||
|  * ``` | ||||
|  * | ||||
|  * Some filters may accept or require additional filter parameters – most | ||||
|  * filters do not require filter parameters. | ||||
| @@ -58,28 +191,67 @@ function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL) | ||||
|  * In particular, note how *not passing* this parameter at all differs from | ||||
|  * explicitly passing a `null` value (which many filters do not accept). | ||||
|  * Please refer to the individual filter definition for more details. | ||||
|  * For example, the `string.strip_tags` filter can be invoked like this: | ||||
|  * | ||||
|  * ```php | ||||
|  * $fun = Clue\StreamFilter\fun('string.strip_tags', '<a><b>'); | ||||
|  * | ||||
|  * $ret = $fun('<b>h<br>i</b>'); | ||||
|  * assert('<b>hi</b>' === $ret); | ||||
|  * ``` | ||||
|  * | ||||
|  * Under the hood, this function allocates a temporary memory stream, so it's | ||||
|  * recommended to clean up the filter function after use. | ||||
|  * Also, some filter functions (in particular the | ||||
|  * [zlib compression filters](https://www.php.net/manual/en/filters.compression.php)) | ||||
|  * may use internal buffers and may emit a final data chunk on close. | ||||
|  * The filter function can be closed by invoking without any arguments: | ||||
|  * | ||||
|  * ```php | ||||
|  * $fun = Clue\StreamFilter\fun('zlib.deflate'); | ||||
|  * | ||||
|  * $ret = $fun('hello') . $fun('world') . $fun(); | ||||
|  * assert('helloworld' === gzinflate($ret)); | ||||
|  * ``` | ||||
|  * | ||||
|  * The filter function must not be used anymore after it has been closed. | ||||
|  * Doing so will result in a `RuntimeException`: | ||||
|  * | ||||
|  * ```php | ||||
|  * $fun = Clue\StreamFilter\fun('string.rot13'); | ||||
|  * $fun(); | ||||
|  * | ||||
|  * $fun('test'); // throws RuntimeException | ||||
|  * ``` | ||||
|  * | ||||
|  * > Note: If you're using the zlib compression filters, then you should be wary | ||||
|  * about engine inconsistencies between different PHP versions and HHVM. | ||||
|  * These inconsistencies exist in the underlying PHP engines and there's little we | ||||
|  * can do about this in this library. | ||||
|  * [Our test suite](tests/) contains several test cases that exhibit these issues. | ||||
|  * If you feel some test case is missing or outdated, we're happy to accept PRs! :) | ||||
|  * | ||||
|  * @param string $filter     built-in filter name. See stream_get_filters() or http://php.net/manual/en/filters.php | ||||
|  * @param mixed  $parameters (optional) parameters to pass to the built-in filter as-is | ||||
|  * @return callable a filter callback which can be append()'ed or prepend()'ed | ||||
|  * @throws RuntimeException on error | ||||
|  * @throws \RuntimeException on error | ||||
|  * @link http://php.net/manual/en/filters.php | ||||
|  * @see stream_get_filters() | ||||
|  * @see append() | ||||
|  */ | ||||
| function fun($filter, $parameters = null) | ||||
| { | ||||
|     $fp = fopen('php://memory', 'w'); | ||||
|     if (func_num_args() === 1) { | ||||
|         $filter = @stream_filter_append($fp, $filter, STREAM_FILTER_WRITE); | ||||
|     $fp = \fopen('php://memory', 'w'); | ||||
|     if (\func_num_args() === 1) { | ||||
|         $filter = @\stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE); | ||||
|     } else { | ||||
|         $filter = @stream_filter_append($fp, $filter, STREAM_FILTER_WRITE, $parameters); | ||||
|         $filter = @\stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE, $parameters); | ||||
|     } | ||||
|  | ||||
|     if ($filter === false) { | ||||
|         fclose($fp); | ||||
|         $error = error_get_last() + array('message' => ''); | ||||
|         throw new RuntimeException('Unable to access built-in filter: ' . $error['message']); | ||||
|         \fclose($fp); | ||||
|         $error = \error_get_last() + array('message' => ''); | ||||
|         throw new \RuntimeException('Unable to access built-in filter: ' . $error['message']); | ||||
|     } | ||||
|  | ||||
|     // append filter function which buffers internally | ||||
| @@ -89,7 +261,7 @@ function fun($filter, $parameters = null) | ||||
|  | ||||
|         // always return empty string in order to skip actually writing to stream resource | ||||
|         return ''; | ||||
|     }, STREAM_FILTER_WRITE); | ||||
|     }, \STREAM_FILTER_WRITE); | ||||
|  | ||||
|     $closed = false; | ||||
|  | ||||
| @@ -100,12 +272,12 @@ function fun($filter, $parameters = null) | ||||
|         if ($chunk === null) { | ||||
|             $closed = true; | ||||
|             $buffer = ''; | ||||
|             fclose($fp); | ||||
|             \fclose($fp); | ||||
|             return $buffer; | ||||
|         } | ||||
|         // initialize buffer and invoke filters by attempting to write to stream | ||||
|         $buffer = ''; | ||||
|         fwrite($fp, $chunk); | ||||
|         \fwrite($fp, $chunk); | ||||
|  | ||||
|         // buffer now contains everything the filter function returned | ||||
|         return $buffer; | ||||
| @@ -113,22 +285,31 @@ function fun($filter, $parameters = null) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * remove a callback filter from the given stream | ||||
|  * Remove a filter previously added via `append()` or `prepend()`. | ||||
|  * | ||||
|  * ```php | ||||
|  * $filter = Clue\StreamFilter\append($stream, function () { | ||||
|  *     // … | ||||
|  * }); | ||||
|  * Clue\StreamFilter\remove($filter); | ||||
|  * ``` | ||||
|  * | ||||
|  * @param resource $filter | ||||
|  * @return boolean true on success or false on error | ||||
|  * @throws Exception on error | ||||
|  * @return bool true on success or false on error | ||||
|  * @throws \RuntimeException on error | ||||
|  * @uses stream_filter_remove() | ||||
|  */ | ||||
| function remove($filter) | ||||
| { | ||||
|     if (@stream_filter_remove($filter) === false) { | ||||
|         throw new RuntimeException('Unable to remove given filter'); | ||||
|     if (@\stream_filter_remove($filter) === false) { | ||||
|         // PHP 8 throws above on type errors, older PHP and memory issues can throw here | ||||
|         $error = \error_get_last(); | ||||
|         throw new \RuntimeException('Unable to remove filter: ' . $error['message']); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * registers the callback filter and returns the resulting filter name | ||||
|  * Registers the callback filter and returns the resulting filter name | ||||
|  * | ||||
|  * There should be little reason to call this function manually. | ||||
|  * | ||||
| @@ -140,7 +321,7 @@ function register() | ||||
|     static $registered = null; | ||||
|     if ($registered === null) { | ||||
|         $registered = 'stream-callback'; | ||||
|         stream_filter_register($registered, __NAMESPACE__ . '\CallbackFilter'); | ||||
|         \stream_filter_register($registered, __NAMESPACE__ . '\CallbackFilter'); | ||||
|     } | ||||
|     return $registered; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| <?php | ||||
|  | ||||
| if (!function_exists('Clue\\StreamFilter\\append')) { | ||||
| // @codeCoverageIgnoreStart | ||||
| if (!\function_exists('Clue\\StreamFilter\\append')) { | ||||
|     require __DIR__ . '/functions.php'; | ||||
| } | ||||
|   | ||||
							
								
								
									
										386
									
								
								vendor/clue/stream-filter/tests/FilterTest.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										386
									
								
								vendor/clue/stream-filter/tests/FilterTest.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,386 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| use Clue\StreamFilter; | ||||
|  | ||||
| class FilterTest extends PHPUnit_Framework_TestCase | ||||
| { | ||||
|     public function testAppendSimpleCallback() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             return strtoupper($chunk); | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         fwrite($stream, 'world'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('HELLOWORLD', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendNativePhpFunction() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, 'strtoupper'); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         fwrite($stream, 'world'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('HELLOWORLD', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendChangingChunkSize() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             return str_replace(array('a','e','i','o','u'), '', $chunk); | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         fwrite($stream, 'world'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('hllwrld', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendReturningEmptyStringWillNotPassThrough() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             return ''; | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         fwrite($stream, 'world'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendEndEventCanBeBufferedOnClose() | ||||
|     { | ||||
|         if (PHP_VERSION < 5.4) $this->markTestSkipped('Not supported on legacy PHP'); | ||||
|  | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk = null) { | ||||
|             if ($chunk === null) { | ||||
|                 // this signals the end event | ||||
|                 return '!'; | ||||
|             } | ||||
|             return $chunk . ' '; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         $buffered = ''; | ||||
|         StreamFilter\append($stream, function ($chunk) use (&$buffered) { | ||||
|             $buffered .= $chunk; | ||||
|             return ''; | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         fwrite($stream, 'world'); | ||||
|  | ||||
|         fclose($stream); | ||||
|  | ||||
|         $this->assertEquals('hello world !', $buffered); | ||||
|     } | ||||
|  | ||||
|     public function testAppendEndEventWillBeCalledOnRemove() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         $ended = false; | ||||
|         $filter = StreamFilter\append($stream, function ($chunk = null) use (&$ended) { | ||||
|             if ($chunk === null) { | ||||
|                 $ended = true; | ||||
|             } | ||||
|             return $chunk; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         $this->assertEquals(0, $ended); | ||||
|         StreamFilter\remove($filter); | ||||
|         $this->assertEquals(1, $ended); | ||||
|     } | ||||
|  | ||||
|     public function testAppendEndEventWillBeCalledOnClose() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         $ended = false; | ||||
|         StreamFilter\append($stream, function ($chunk = null) use (&$ended) { | ||||
|             if ($chunk === null) { | ||||
|                 $ended = true; | ||||
|             } | ||||
|             return $chunk; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         $this->assertEquals(0, $ended); | ||||
|         fclose($stream); | ||||
|         $this->assertEquals(1, $ended); | ||||
|     } | ||||
|  | ||||
|     public function testAppendWriteOnly() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         $invoked = 0; | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) use (&$invoked) { | ||||
|             ++$invoked; | ||||
|  | ||||
|             return $chunk; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         fwrite($stream, 'a'); | ||||
|         fwrite($stream, 'b'); | ||||
|         fwrite($stream, 'c'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals(3, $invoked); | ||||
|         $this->assertEquals('abc', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendReadOnly() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         $invoked = 0; | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) use (&$invoked) { | ||||
|             ++$invoked; | ||||
|  | ||||
|             return $chunk; | ||||
|         }, STREAM_FILTER_READ); | ||||
|  | ||||
|         fwrite($stream, 'a'); | ||||
|         fwrite($stream, 'b'); | ||||
|         fwrite($stream, 'c'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals(0, $invoked); | ||||
|         $this->assertEquals('abc', stream_get_contents($stream)); | ||||
|         $this->assertEquals(1, $invoked); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testOrderCallingAppendAfterPrepend() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             return '[' . $chunk . ']'; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         StreamFilter\prepend($stream, function ($chunk) { | ||||
|             return '(' . $chunk . ')'; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('[(hello)]', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testRemoveFilter() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         $first = StreamFilter\append($stream, function ($chunk) { | ||||
|             return $chunk . '?'; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             return $chunk . '!'; | ||||
|         }, STREAM_FILTER_WRITE); | ||||
|  | ||||
|         StreamFilter\remove($first); | ||||
|  | ||||
|         fwrite($stream, 'hello'); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('hello!', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendFunDechunk() | ||||
|     { | ||||
|         if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (dechunk filter does not exist)'); | ||||
|  | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, StreamFilter\fun('dechunk'), STREAM_FILTER_WRITE); | ||||
|  | ||||
|         fwrite($stream, "2\r\nhe\r\n"); | ||||
|         fwrite($stream, "3\r\nllo\r\n"); | ||||
|         fwrite($stream, "0\r\n\r\n"); | ||||
|         rewind($stream); | ||||
|  | ||||
|         $this->assertEquals('hello', stream_get_contents($stream)); | ||||
|  | ||||
|         fclose($stream); | ||||
|     } | ||||
|  | ||||
|     public function testAppendThrows() | ||||
|     { | ||||
|         $this->createErrorHandler($errors); | ||||
|  | ||||
|         $stream = $this->createStream(); | ||||
|         $this->createErrorHandler($errors); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk) { | ||||
|             throw new \DomainException($chunk); | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'test'); | ||||
|  | ||||
|         $this->removeErrorHandler(); | ||||
|         $this->assertCount(1, $errors); | ||||
|         $this->assertContains('test', $errors[0]); | ||||
|     } | ||||
|  | ||||
|     public function testAppendThrowsDuringEnd() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|         $this->createErrorHandler($errors); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk = null) { | ||||
|             if ($chunk === null) { | ||||
|                 throw new \DomainException('end'); | ||||
|             } | ||||
|             return $chunk; | ||||
|         }); | ||||
|  | ||||
|         fclose($stream); | ||||
|  | ||||
|         $this->removeErrorHandler(); | ||||
|  | ||||
|         // We can only assert we're not seeing an exception here… | ||||
|         // * php 5.3-5.6 sees one error here | ||||
|         // * php 7 does not see any error here | ||||
|         // * hhvm sees the same error twice | ||||
|         // | ||||
|         // If you're curious: | ||||
|         // | ||||
|         // var_dump($errors); | ||||
|         // $this->assertCount(1, $errors); | ||||
|         // $this->assertContains('end', $errors[0]); | ||||
|     } | ||||
|  | ||||
|     public function testAppendThrowsShouldTriggerEnd() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|         $this->createErrorHandler($errors); | ||||
|  | ||||
|         $ended = false; | ||||
|         StreamFilter\append($stream, function ($chunk = null) use (&$ended) { | ||||
|             if ($chunk === null) { | ||||
|                 $ended = true; | ||||
|                 return ''; | ||||
|             } | ||||
|             throw new \DomainException($chunk); | ||||
|         }); | ||||
|  | ||||
|         $this->assertEquals(false, $ended); | ||||
|         fwrite($stream, 'test'); | ||||
|         $this->assertEquals(true, $ended); | ||||
|  | ||||
|         $this->removeErrorHandler(); | ||||
|         $this->assertCount(1, $errors); | ||||
|         $this->assertContains('test', $errors[0]); | ||||
|     } | ||||
|  | ||||
|     public function testAppendThrowsShouldTriggerEndButIgnoreExceptionDuringEnd() | ||||
|     { | ||||
|         //$this->markTestIncomplete(); | ||||
|         $stream = $this->createStream(); | ||||
|         $this->createErrorHandler($errors); | ||||
|  | ||||
|         StreamFilter\append($stream, function ($chunk = null) { | ||||
|             if ($chunk === null) { | ||||
|                 $chunk = 'end'; | ||||
|                 //return ''; | ||||
|             } | ||||
|             throw new \DomainException($chunk); | ||||
|         }); | ||||
|  | ||||
|         fwrite($stream, 'test'); | ||||
|  | ||||
|         $this->removeErrorHandler(); | ||||
|         $this->assertCount(1, $errors); | ||||
|         $this->assertContains('test', $errors[0]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException RuntimeException | ||||
|      */ | ||||
|     public function testAppendInvalidStreamIsRuntimeError() | ||||
|     { | ||||
|         if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid stream)'); | ||||
|         StreamFilter\append(false, function () { }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException RuntimeException | ||||
|      */ | ||||
|     public function testPrependInvalidStreamIsRuntimeError() | ||||
|     { | ||||
|         if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid stream)'); | ||||
|         StreamFilter\prepend(false, function () { }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException RuntimeException | ||||
|      */ | ||||
|     public function testRemoveInvalidFilterIsRuntimeError() | ||||
|     { | ||||
|         if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (does not reject invalid filters)'); | ||||
|         StreamFilter\remove(false); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException InvalidArgumentException | ||||
|      */ | ||||
|     public function testInvalidCallbackIsInvalidArgument() | ||||
|     { | ||||
|         $stream = $this->createStream(); | ||||
|  | ||||
|         StreamFilter\append($stream, 'a-b-c'); | ||||
|     } | ||||
|  | ||||
|     private function createStream() | ||||
|     { | ||||
|         return fopen('php://memory', 'r+'); | ||||
|     } | ||||
|  | ||||
|     private function createErrorHandler(&$errors) | ||||
|     { | ||||
|         $errors = array(); | ||||
|         set_error_handler(function ($_, $message) use (&$errors) { | ||||
|             $errors []= $message; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     private function removeErrorHandler() | ||||
|     { | ||||
|         restore_error_handler(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/clue/stream-filter/tests/FunTest.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/clue/stream-filter/tests/FunTest.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,61 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| use Clue\StreamFilter as Filter; | ||||
|  | ||||
| class FunTest extends PHPUnit_Framework_TestCase | ||||
| { | ||||
|     public function testFunInRot13() | ||||
|     { | ||||
|         $rot = Filter\fun('string.rot13'); | ||||
|  | ||||
|         $this->assertEquals('grfg', $rot('test')); | ||||
|         $this->assertEquals('test', $rot($rot('test'))); | ||||
|         $this->assertEquals(null, $rot()); | ||||
|     } | ||||
|  | ||||
|     public function testFunInQuotedPrintable() | ||||
|     { | ||||
|         $encode = Filter\fun('convert.quoted-printable-encode'); | ||||
|         $decode = Filter\fun('convert.quoted-printable-decode'); | ||||
|  | ||||
|         $this->assertEquals('t=C3=A4st', $encode('täst')); | ||||
|         $this->assertEquals('täst', $decode($encode('täst'))); | ||||
|         $this->assertEquals(null, $encode()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException RuntimeException | ||||
|      */ | ||||
|     public function testFunWriteAfterCloseRot13() | ||||
|     { | ||||
|         $rot = Filter\fun('string.rot13'); | ||||
|  | ||||
|         $this->assertEquals(null, $rot()); | ||||
|         $rot('test'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @expectedException RuntimeException | ||||
|      */ | ||||
|     public function testFunInvalid() | ||||
|     { | ||||
|         Filter\fun('unknown'); | ||||
|     } | ||||
|  | ||||
|     public function testFunInBase64() | ||||
|     { | ||||
|         $encode = Filter\fun('convert.base64-encode'); | ||||
|         $decode = Filter\fun('convert.base64-decode'); | ||||
|  | ||||
|         $string = 'test'; | ||||
|         $this->assertEquals(base64_encode($string), $encode($string) . $encode()); | ||||
|         $this->assertEquals($string, $decode(base64_encode($string))); | ||||
|  | ||||
|         $encode = Filter\fun('convert.base64-encode'); | ||||
|         $decode = Filter\fun('convert.base64-decode'); | ||||
|         $this->assertEquals($string, $decode($encode($string) . $encode())); | ||||
|  | ||||
|         $encode = Filter\fun('convert.base64-encode'); | ||||
|         $this->assertEquals(null, $encode()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										79
									
								
								vendor/clue/stream-filter/tests/FunZlibTest.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/clue/stream-filter/tests/FunZlibTest.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,79 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| use Clue\StreamFilter; | ||||
|  | ||||
| class BuiltInZlibTest extends PHPUnit_Framework_TestCase | ||||
| { | ||||
|     public function testFunZlibDeflateHelloWorld() | ||||
|     { | ||||
|         $deflate = StreamFilter\fun('zlib.deflate'); | ||||
|  | ||||
|         $data = $deflate('hello') . $deflate(' ') . $deflate('world') . $deflate(); | ||||
|  | ||||
|         $this->assertEquals(gzdeflate('hello world'), $data); | ||||
|     } | ||||
|  | ||||
|     public function testFunZlibDeflateEmpty() | ||||
|     { | ||||
|         if (PHP_VERSION >= 7) $this->markTestSkipped('Not supported on PHP7 (empty string does not invoke filter)'); | ||||
|  | ||||
|         $deflate = StreamFilter\fun('zlib.deflate'); | ||||
|  | ||||
|         //$data = gzdeflate(''); | ||||
|         $data = $deflate(); | ||||
|  | ||||
|         $this->assertEquals("\x03\x00", $data); | ||||
|     } | ||||
|  | ||||
|     public function testFunZlibDeflateBig() | ||||
|     { | ||||
|         $deflate = StreamFilter\fun('zlib.deflate'); | ||||
|  | ||||
|         $n = 1000; | ||||
|         $expected = str_repeat('hello', $n); | ||||
|  | ||||
|         $bytes = ''; | ||||
|         for ($i = 0; $i < $n; ++$i) { | ||||
|             $bytes .= $deflate('hello'); | ||||
|         } | ||||
|         $bytes .= $deflate(); | ||||
|  | ||||
|         $this->assertEquals($expected, gzinflate($bytes)); | ||||
|     } | ||||
|  | ||||
|     public function testFunZlibInflateHelloWorld() | ||||
|     { | ||||
|         $inflate = StreamFilter\fun('zlib.inflate'); | ||||
|  | ||||
|         $data = $inflate(gzdeflate('hello world')) . $inflate(); | ||||
|  | ||||
|         $this->assertEquals('hello world', $data); | ||||
|     } | ||||
|  | ||||
|     public function testFunZlibInflateEmpty() | ||||
|     { | ||||
|         $inflate = StreamFilter\fun('zlib.inflate'); | ||||
|  | ||||
|         $data = $inflate("\x03\x00") . $inflate(); | ||||
|  | ||||
|         $this->assertEquals('', $data); | ||||
|     } | ||||
|  | ||||
|     public function testFunZlibInflateBig() | ||||
|     { | ||||
|         if (defined('HHVM_VERSION')) $this->markTestSkipped('Not supported on HHVM (final chunk will not be emitted)'); | ||||
|  | ||||
|         $inflate = StreamFilter\fun('zlib.inflate'); | ||||
|  | ||||
|         $expected = str_repeat('hello', 10); | ||||
|         $bytes = gzdeflate($expected); | ||||
|  | ||||
|         $ret = ''; | ||||
|         foreach (str_split($bytes, 2) as $chunk) { | ||||
|             $ret .= $inflate($chunk); | ||||
|         } | ||||
|         $ret .= $inflate(); | ||||
|  | ||||
|         $this->assertEquals($expected, $ret); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										149
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										149
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							| @@ -37,57 +37,130 @@ namespace Composer\Autoload; | ||||
|  * | ||||
|  * @author Fabien Potencier <fabien@symfony.com> | ||||
|  * @author Jordi Boggiano <j.boggiano@seld.be> | ||||
|  * @see    http://www.php-fig.org/psr/psr-0/ | ||||
|  * @see    http://www.php-fig.org/psr/psr-4/ | ||||
|  * @see    https://www.php-fig.org/psr/psr-0/ | ||||
|  * @see    https://www.php-fig.org/psr/psr-4/ | ||||
|  */ | ||||
| class ClassLoader | ||||
| { | ||||
|     /** @var ?string */ | ||||
|     private $vendorDir; | ||||
|  | ||||
|     // PSR-4 | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, array<string, int>> | ||||
|      */ | ||||
|     private $prefixLengthsPsr4 = array(); | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, array<int, string>> | ||||
|      */ | ||||
|     private $prefixDirsPsr4 = array(); | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, string> | ||||
|      */ | ||||
|     private $fallbackDirsPsr4 = array(); | ||||
|  | ||||
|     // PSR-0 | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, array<string, string[]>> | ||||
|      */ | ||||
|     private $prefixesPsr0 = array(); | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, string> | ||||
|      */ | ||||
|     private $fallbackDirsPsr0 = array(); | ||||
|  | ||||
|     /** @var bool */ | ||||
|     private $useIncludePath = false; | ||||
|  | ||||
|     /** | ||||
|      * @var string[] | ||||
|      * @psalm-var array<string, string> | ||||
|      */ | ||||
|     private $classMap = array(); | ||||
|  | ||||
|     /** @var bool */ | ||||
|     private $classMapAuthoritative = false; | ||||
|  | ||||
|     /** | ||||
|      * @var bool[] | ||||
|      * @psalm-var array<string, bool> | ||||
|      */ | ||||
|     private $missingClasses = array(); | ||||
|  | ||||
|     /** @var ?string */ | ||||
|     private $apcuPrefix; | ||||
|  | ||||
|     /** | ||||
|      * @var self[] | ||||
|      */ | ||||
|     private static $registeredLoaders = array(); | ||||
|  | ||||
|     /** | ||||
|      * @param ?string $vendorDir | ||||
|      */ | ||||
|     public function __construct($vendorDir = null) | ||||
|     { | ||||
|         $this->vendorDir = $vendorDir; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string[] | ||||
|      */ | ||||
|     public function getPrefixes() | ||||
|     { | ||||
|         if (!empty($this->prefixesPsr0)) { | ||||
|             return call_user_func_array('array_merge', $this->prefixesPsr0); | ||||
|             return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); | ||||
|         } | ||||
|  | ||||
|         return array(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array[] | ||||
|      * @psalm-return array<string, array<int, string>> | ||||
|      */ | ||||
|     public function getPrefixesPsr4() | ||||
|     { | ||||
|         return $this->prefixDirsPsr4; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array[] | ||||
|      * @psalm-return array<string, string> | ||||
|      */ | ||||
|     public function getFallbackDirs() | ||||
|     { | ||||
|         return $this->fallbackDirsPsr0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array[] | ||||
|      * @psalm-return array<string, string> | ||||
|      */ | ||||
|     public function getFallbackDirsPsr4() | ||||
|     { | ||||
|         return $this->fallbackDirsPsr4; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string[] Array of classname => path | ||||
|      * @psalm-return array<string, string> | ||||
|      */ | ||||
|     public function getClassMap() | ||||
|     { | ||||
|         return $this->classMap; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $classMap Class to filename map | ||||
|      * @param string[] $classMap Class to filename map | ||||
|      * @psalm-param array<string, string> $classMap | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function addClassMap(array $classMap) | ||||
|     { | ||||
| @@ -103,8 +176,10 @@ class ClassLoader | ||||
|      * appending or prepending to the ones previously set for this prefix. | ||||
|      * | ||||
|      * @param string          $prefix  The prefix | ||||
|      * @param array|string $paths   The PSR-0 root directories | ||||
|      * @param string[]|string $paths   The PSR-0 root directories | ||||
|      * @param bool            $prepend Whether to prepend the directories | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function add($prefix, $paths, $prepend = false) | ||||
|     { | ||||
| @@ -148,10 +223,12 @@ class ClassLoader | ||||
|      * appending or prepending to the ones previously set for this namespace. | ||||
|      * | ||||
|      * @param string          $prefix  The prefix/namespace, with trailing '\\' | ||||
|      * @param array|string $paths   The PSR-4 base directories | ||||
|      * @param string[]|string $paths   The PSR-4 base directories | ||||
|      * @param bool            $prepend Whether to prepend the directories | ||||
|      * | ||||
|      * @throws \InvalidArgumentException | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function addPsr4($prefix, $paths, $prepend = false) | ||||
|     { | ||||
| @@ -196,7 +273,9 @@ class ClassLoader | ||||
|      * replacing any others previously set for this prefix. | ||||
|      * | ||||
|      * @param string          $prefix The prefix | ||||
|      * @param array|string $paths  The PSR-0 base directories | ||||
|      * @param string[]|string $paths  The PSR-0 base directories | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function set($prefix, $paths) | ||||
|     { | ||||
| @@ -212,9 +291,11 @@ class ClassLoader | ||||
|      * replacing any others previously set for this namespace. | ||||
|      * | ||||
|      * @param string          $prefix The prefix/namespace, with trailing '\\' | ||||
|      * @param array|string $paths  The PSR-4 base directories | ||||
|      * @param string[]|string $paths  The PSR-4 base directories | ||||
|      * | ||||
|      * @throws \InvalidArgumentException | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function setPsr4($prefix, $paths) | ||||
|     { | ||||
| @@ -234,6 +315,8 @@ class ClassLoader | ||||
|      * Turns on searching the include path for class files. | ||||
|      * | ||||
|      * @param bool $useIncludePath | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function setUseIncludePath($useIncludePath) | ||||
|     { | ||||
| @@ -256,6 +339,8 @@ class ClassLoader | ||||
|      * that have not been registered with the class map. | ||||
|      * | ||||
|      * @param bool $classMapAuthoritative | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function setClassMapAuthoritative($classMapAuthoritative) | ||||
|     { | ||||
| @@ -276,10 +361,12 @@ class ClassLoader | ||||
|      * APCu prefix to use to cache found/not-found classes, if the extension is enabled. | ||||
|      * | ||||
|      * @param string|null $apcuPrefix | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function setApcuPrefix($apcuPrefix) | ||||
|     { | ||||
|         $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; | ||||
|         $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -296,25 +383,44 @@ class ClassLoader | ||||
|      * Registers this instance as an autoloader. | ||||
|      * | ||||
|      * @param bool $prepend Whether to prepend the autoloader or not | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function register($prepend = false) | ||||
|     { | ||||
|         spl_autoload_register(array($this, 'loadClass'), true, $prepend); | ||||
|  | ||||
|         if (null === $this->vendorDir) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($prepend) { | ||||
|             self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; | ||||
|         } else { | ||||
|             unset(self::$registeredLoaders[$this->vendorDir]); | ||||
|             self::$registeredLoaders[$this->vendorDir] = $this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Unregisters this instance as an autoloader. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function unregister() | ||||
|     { | ||||
|         spl_autoload_unregister(array($this, 'loadClass')); | ||||
|  | ||||
|         if (null !== $this->vendorDir) { | ||||
|             unset(self::$registeredLoaders[$this->vendorDir]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Loads the given class or interface. | ||||
|      * | ||||
|      * @param  string    $class The name of the class | ||||
|      * @return bool|null True if loaded, null otherwise | ||||
|      * @return true|null True if loaded, null otherwise | ||||
|      */ | ||||
|     public function loadClass($class) | ||||
|     { | ||||
| @@ -323,6 +429,8 @@ class ClassLoader | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -367,6 +475,21 @@ class ClassLoader | ||||
|         return $file; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the currently registered loaders indexed by their corresponding vendor directories. | ||||
|      * | ||||
|      * @return self[] | ||||
|      */ | ||||
|     public static function getRegisteredLoaders() | ||||
|     { | ||||
|         return self::$registeredLoaders; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param  string       $class | ||||
|      * @param  string       $ext | ||||
|      * @return string|false | ||||
|      */ | ||||
|     private function findFileWithExtension($class, $ext) | ||||
|     { | ||||
|         // PSR-4 lookup | ||||
| @@ -377,7 +500,7 @@ class ClassLoader | ||||
|             $subPath = $class; | ||||
|             while (false !== $lastPos = strrpos($subPath, '\\')) { | ||||
|                 $subPath = substr($subPath, 0, $lastPos); | ||||
|                 $search = $subPath.'\\'; | ||||
|                 $search = $subPath . '\\'; | ||||
|                 if (isset($this->prefixDirsPsr4[$search])) { | ||||
|                     $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); | ||||
|                     foreach ($this->prefixDirsPsr4[$search] as $dir) { | ||||
| @@ -438,6 +561,10 @@ class ClassLoader | ||||
|  * Scope isolated include. | ||||
|  * | ||||
|  * Prevents access to $this/self from included files. | ||||
|  * | ||||
|  * @param  string $file | ||||
|  * @return void | ||||
|  * @private | ||||
|  */ | ||||
| function includeFile($file) | ||||
| { | ||||
|   | ||||
							
								
								
									
										350
									
								
								vendor/composer/InstalledVersions.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								vendor/composer/InstalledVersions.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * This file is part of Composer. | ||||
|  * | ||||
|  * (c) Nils Adermann <naderman@naderman.de> | ||||
|  *     Jordi Boggiano <j.boggiano@seld.be> | ||||
|  * | ||||
|  * For the full copyright and license information, please view the LICENSE | ||||
|  * file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Composer; | ||||
|  | ||||
| use Composer\Autoload\ClassLoader; | ||||
| use Composer\Semver\VersionParser; | ||||
|  | ||||
| /** | ||||
|  * This class is copied in every Composer installed project and available to all | ||||
|  * | ||||
|  * See also https://getcomposer.org/doc/07-runtime.md#installed-versions | ||||
|  * | ||||
|  * To require its presence, you can require `composer-runtime-api ^2.0` | ||||
|  */ | ||||
| class InstalledVersions | ||||
| { | ||||
|     /** | ||||
|      * @var mixed[]|null | ||||
|      * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null | ||||
|      */ | ||||
|     private static $installed; | ||||
|  | ||||
|     /** | ||||
|      * @var bool|null | ||||
|      */ | ||||
|     private static $canGetVendors; | ||||
|  | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> | ||||
|      */ | ||||
|     private static $installedByVendor = array(); | ||||
|  | ||||
|     /** | ||||
|      * Returns a list of all package names which are present, either by being installed, replaced or provided | ||||
|      * | ||||
|      * @return string[] | ||||
|      * @psalm-return list<string> | ||||
|      */ | ||||
|     public static function getInstalledPackages() | ||||
|     { | ||||
|         $packages = array(); | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             $packages[] = array_keys($installed['versions']); | ||||
|         } | ||||
|  | ||||
|         if (1 === \count($packages)) { | ||||
|             return $packages[0]; | ||||
|         } | ||||
|  | ||||
|         return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a list of all package names with a specific type e.g. 'library' | ||||
|      * | ||||
|      * @param  string   $type | ||||
|      * @return string[] | ||||
|      * @psalm-return list<string> | ||||
|      */ | ||||
|     public static function getInstalledPackagesByType($type) | ||||
|     { | ||||
|         $packagesByType = array(); | ||||
|  | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             foreach ($installed['versions'] as $name => $package) { | ||||
|                 if (isset($package['type']) && $package['type'] === $type) { | ||||
|                     $packagesByType[] = $name; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $packagesByType; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks whether the given package is installed | ||||
|      * | ||||
|      * This also returns true if the package name is provided or replaced by another package | ||||
|      * | ||||
|      * @param  string $packageName | ||||
|      * @param  bool   $includeDevRequirements | ||||
|      * @return bool | ||||
|      */ | ||||
|     public static function isInstalled($packageName, $includeDevRequirements = true) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (isset($installed['versions'][$packageName])) { | ||||
|                 return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks whether the given package satisfies a version constraint | ||||
|      * | ||||
|      * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: | ||||
|      * | ||||
|      *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') | ||||
|      * | ||||
|      * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality | ||||
|      * @param  string        $packageName | ||||
|      * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package | ||||
|      * @return bool | ||||
|      */ | ||||
|     public static function satisfies(VersionParser $parser, $packageName, $constraint) | ||||
|     { | ||||
|         $constraint = $parser->parseConstraints($constraint); | ||||
|         $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); | ||||
|  | ||||
|         return $provided->matches($constraint); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a version constraint representing all the range(s) which are installed for a given package | ||||
|      * | ||||
|      * It is easier to use this via isInstalled() with the $constraint argument if you need to check | ||||
|      * whether a given version of a package is installed, and not just whether it exists | ||||
|      * | ||||
|      * @param  string $packageName | ||||
|      * @return string Version constraint usable with composer/semver | ||||
|      */ | ||||
|     public static function getVersionRanges($packageName) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (!isset($installed['versions'][$packageName])) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $ranges = array(); | ||||
|             if (isset($installed['versions'][$packageName]['pretty_version'])) { | ||||
|                 $ranges[] = $installed['versions'][$packageName]['pretty_version']; | ||||
|             } | ||||
|             if (array_key_exists('aliases', $installed['versions'][$packageName])) { | ||||
|                 $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); | ||||
|             } | ||||
|             if (array_key_exists('replaced', $installed['versions'][$packageName])) { | ||||
|                 $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); | ||||
|             } | ||||
|             if (array_key_exists('provided', $installed['versions'][$packageName])) { | ||||
|                 $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); | ||||
|             } | ||||
|  | ||||
|             return implode(' || ', $ranges); | ||||
|         } | ||||
|  | ||||
|         throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param  string      $packageName | ||||
|      * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present | ||||
|      */ | ||||
|     public static function getVersion($packageName) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (!isset($installed['versions'][$packageName])) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (!isset($installed['versions'][$packageName]['version'])) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             return $installed['versions'][$packageName]['version']; | ||||
|         } | ||||
|  | ||||
|         throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param  string      $packageName | ||||
|      * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present | ||||
|      */ | ||||
|     public static function getPrettyVersion($packageName) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (!isset($installed['versions'][$packageName])) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (!isset($installed['versions'][$packageName]['pretty_version'])) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             return $installed['versions'][$packageName]['pretty_version']; | ||||
|         } | ||||
|  | ||||
|         throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param  string      $packageName | ||||
|      * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference | ||||
|      */ | ||||
|     public static function getReference($packageName) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (!isset($installed['versions'][$packageName])) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (!isset($installed['versions'][$packageName]['reference'])) { | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             return $installed['versions'][$packageName]['reference']; | ||||
|         } | ||||
|  | ||||
|         throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param  string      $packageName | ||||
|      * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. | ||||
|      */ | ||||
|     public static function getInstallPath($packageName) | ||||
|     { | ||||
|         foreach (self::getInstalled() as $installed) { | ||||
|             if (!isset($installed['versions'][$packageName])) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; | ||||
|         } | ||||
|  | ||||
|         throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array | ||||
|      * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} | ||||
|      */ | ||||
|     public static function getRootPackage() | ||||
|     { | ||||
|         $installed = self::getInstalled(); | ||||
|  | ||||
|         return $installed[0]['root']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the raw installed.php data for custom implementations | ||||
|      * | ||||
|      * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. | ||||
|      * @return array[] | ||||
|      * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} | ||||
|      */ | ||||
|     public static function getRawData() | ||||
|     { | ||||
|         @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); | ||||
|  | ||||
|         if (null === self::$installed) { | ||||
|             // only require the installed.php file if this file is loaded from its dumped location, | ||||
|             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 | ||||
|             if (substr(__DIR__, -8, 1) !== 'C') { | ||||
|                 self::$installed = include __DIR__ . '/installed.php'; | ||||
|             } else { | ||||
|                 self::$installed = array(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return self::$installed; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the raw data of all installed.php which are currently loaded for custom implementations | ||||
|      * | ||||
|      * @return array[] | ||||
|      * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> | ||||
|      */ | ||||
|     public static function getAllRawData() | ||||
|     { | ||||
|         return self::getInstalled(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Lets you reload the static array from another file | ||||
|      * | ||||
|      * This is only useful for complex integrations in which a project needs to use | ||||
|      * this class but then also needs to execute another project's autoloader in process, | ||||
|      * and wants to ensure both projects have access to their version of installed.php. | ||||
|      * | ||||
|      * A typical case would be PHPUnit, where it would need to make sure it reads all | ||||
|      * the data it needs from this class, then call reload() with | ||||
|      * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure | ||||
|      * the project in which it runs can then also use this class safely, without | ||||
|      * interference between PHPUnit's dependencies and the project's dependencies. | ||||
|      * | ||||
|      * @param  array[] $data A vendor/composer/installed.php data set | ||||
|      * @return void | ||||
|      * | ||||
|      * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data | ||||
|      */ | ||||
|     public static function reload($data) | ||||
|     { | ||||
|         self::$installed = $data; | ||||
|         self::$installedByVendor = array(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array[] | ||||
|      * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> | ||||
|      */ | ||||
|     private static function getInstalled() | ||||
|     { | ||||
|         if (null === self::$canGetVendors) { | ||||
|             self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); | ||||
|         } | ||||
|  | ||||
|         $installed = array(); | ||||
|  | ||||
|         if (self::$canGetVendors) { | ||||
|             foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { | ||||
|                 if (isset(self::$installedByVendor[$vendorDir])) { | ||||
|                     $installed[] = self::$installedByVendor[$vendorDir]; | ||||
|                 } elseif (is_file($vendorDir.'/composer/installed.php')) { | ||||
|                     $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; | ||||
|                     if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { | ||||
|                         self::$installed = $installed[count($installed) - 1]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (null === self::$installed) { | ||||
|             // only require the installed.php file if this file is loaded from its dumped location, | ||||
|             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 | ||||
|             if (substr(__DIR__, -8, 1) !== 'C') { | ||||
|                 self::$installed = require __DIR__ . '/installed.php'; | ||||
|             } else { | ||||
|                 self::$installed = array(); | ||||
|             } | ||||
|         } | ||||
|         $installed[] = self::$installed; | ||||
|  | ||||
|         return $installed; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										69
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										69
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,56 +1,21 @@ | ||||
| Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ | ||||
| Upstream-Name: Composer | ||||
| Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be> | ||||
| Source: https://github.com/composer/composer | ||||
|  | ||||
| Files: * | ||||
| Copyright: 2016, Nils Adermann <naderman@naderman.de> | ||||
|            2016, Jordi Boggiano <j.boggiano@seld.be> | ||||
| License: Expat | ||||
| Copyright (c) Nils Adermann, Jordi Boggiano | ||||
|  | ||||
| Files: src/Composer/Util/TlsHelper.php | ||||
| Copyright: 2016, Nils Adermann <naderman@naderman.de> | ||||
|            2016, Jordi Boggiano <j.boggiano@seld.be> | ||||
|            2013, Evan Coury <me@evancoury.com> | ||||
| License: Expat and BSD-2-Clause | ||||
| 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: | ||||
|  | ||||
| License: BSD-2-Clause | ||||
|  Redistribution and use in source and binary forms, with or without modification, | ||||
|  are permitted provided that the following conditions are met: | ||||
|  . | ||||
|      * Redistributions of source code must retain the above copyright notice, | ||||
|        this list of conditions and the following disclaimer. | ||||
|  . | ||||
|      * Redistributions in binary form must reproduce the above copyright notice, | ||||
|        this list of conditions and the following disclaimer in the documentation | ||||
|        and/or other materials provided with the distribution. | ||||
|  . | ||||
|  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
|  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||||
|  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||
|  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| 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. | ||||
|  | ||||
| License: Expat | ||||
|  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. | ||||
|   | ||||
							
								
								
									
										1615
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1615
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										27
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,31 +6,30 @@ $vendorDir = dirname(dirname(__FILE__)); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
|     'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', | ||||
|     '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', | ||||
|     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', | ||||
|     'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', | ||||
|     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', | ||||
|     'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', | ||||
|     '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', | ||||
|     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', | ||||
|     'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', | ||||
|     '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', | ||||
|     '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', | ||||
|     'cf97c57bfe0f23854afd2f3818abb7a0' => $vendorDir . '/zendframework/zend-diactoros/src/functions/create_uploaded_file.php', | ||||
|     '9bf37a3d0dad93e29cb4e1b1bfab04e9' => $vendorDir . '/zendframework/zend-diactoros/src/functions/marshal_headers_from_sapi.php', | ||||
|     'ce70dccb4bcc2efc6e94d2ee526e6972' => $vendorDir . '/zendframework/zend-diactoros/src/functions/marshal_method_from_sapi.php', | ||||
|     'f86420df471f14d568bfcb71e271b523' => $vendorDir . '/zendframework/zend-diactoros/src/functions/marshal_protocol_version_from_sapi.php', | ||||
|     'b87481e008a3700344428ae089e7f9e5' => $vendorDir . '/zendframework/zend-diactoros/src/functions/marshal_uri_from_sapi.php', | ||||
|     '0b0974a5566a1077e4f2e111341112c1' => $vendorDir . '/zendframework/zend-diactoros/src/functions/normalize_server.php', | ||||
|     '1ca3bc274755662169f9629d5412a1da' => $vendorDir . '/zendframework/zend-diactoros/src/functions/normalize_uploaded_files.php', | ||||
|     '40360c0b9b437e69bcbb7f1349ce029e' => $vendorDir . '/zendframework/zend-diactoros/src/functions/parse_cookie_header.php', | ||||
|     '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', | ||||
|     '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', | ||||
|     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', | ||||
|     '9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php', | ||||
|     '8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php', | ||||
|     'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', | ||||
|     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', | ||||
|     '8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php', | ||||
|     '801c31d8ed748cfa537fa45402288c95' => $vendorDir . '/psy/psysh/src/functions.php', | ||||
|     'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php', | ||||
|     '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', | ||||
|     '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', | ||||
|     'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', | ||||
|     '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', | ||||
|     '6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php', | ||||
|     '538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php', | ||||
|     '801c31d8ed748cfa537fa45402288c95' => $vendorDir . '/psy/psysh/src/functions.php', | ||||
|     'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php', | ||||
|     'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', | ||||
|     'f0906e6318348a765ffb6eb24e0d0938' => $vendorDir . '/laravel/framework/src/Illuminate/Foundation/helpers.php', | ||||
|     '58571171fd5812e6e447dce228f52f4d' => $vendorDir . '/laravel/framework/src/Illuminate/Support/helpers.php', | ||||
|     'f18cc91337d49233e5754e93f3ed9ec3' => $vendorDir . '/laravelcollective/html/src/helpers.php', | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/composer/autoload_namespaces.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/composer/autoload_namespaces.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,8 +6,5 @@ $vendorDir = dirname(dirname(__FILE__)); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
|     'UpdateHelper\\' => array($vendorDir . '/kylekatarnls/update-helper/src'), | ||||
|     'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'), | ||||
|     'Parsedown' => array($vendorDir . '/erusev/parsedown'), | ||||
|     'Mockery' => array($vendorDir . '/mockery/mockery/library'), | ||||
| ); | ||||
|   | ||||
							
								
								
									
										38
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,25 +6,31 @@ $vendorDir = dirname(dirname(__FILE__)); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
|     'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'), | ||||
|     'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'), | ||||
|     'Zend\\Diactoros\\' => array($vendorDir . '/zendframework/zend-diactoros/src'), | ||||
|     'XdgBaseDir\\' => array($vendorDir . '/dnoegel/php-xdg-base-dir/src'), | ||||
|     'Whoops\\' => array($vendorDir . '/filp/whoops/src/Whoops'), | ||||
|     'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), | ||||
|     'TijsVerkoyen\\CssToInlineStyles\\' => array($vendorDir . '/tijsverkoyen/css-to-inline-styles/src'), | ||||
|     'Tests\\' => array($baseDir . '/tests'), | ||||
|     'Symfony\\Thanks\\' => array($vendorDir . '/symfony/thanks/src'), | ||||
|     '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'), | ||||
|     'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), | ||||
|     'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), | ||||
|     'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), | ||||
|     'Symfony\\Polyfill\\Intl\\Grapheme\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'), | ||||
|     'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'), | ||||
|     'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), | ||||
|     'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'), | ||||
|     '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\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), | ||||
|     'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), | ||||
|     'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), | ||||
|     'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), | ||||
|     'Symfony\\Component\\Routing\\' => array($vendorDir . '/symfony/routing'), | ||||
|     'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), | ||||
|     'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'), | ||||
| @@ -33,52 +39,58 @@ return array( | ||||
|     'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), | ||||
|     'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), | ||||
|     'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), | ||||
|     'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'), | ||||
|     'Symfony\\Component\\ErrorHandler\\' => array($vendorDir . '/symfony/error-handler'), | ||||
|     'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'), | ||||
|     'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), | ||||
|     'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'), | ||||
|     'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), | ||||
|     'Ramsey\\Collection\\' => array($vendorDir . '/ramsey/collection/src'), | ||||
|     'Psy\\' => array($vendorDir . '/psy/psysh/src'), | ||||
|     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), | ||||
|     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), | ||||
|     'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), | ||||
|     '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\\Cache\\' => array($vendorDir . '/psr/cache/src'), | ||||
|     'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src/Prophecy'), | ||||
|     'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), | ||||
|     'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'), | ||||
|     'Opis\\Closure\\' => array($vendorDir . '/opis/closure/src'), | ||||
|     'Nexmo\\' => array($vendorDir . '/nexmo/client/src'), | ||||
|     'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), | ||||
|     'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), | ||||
|     'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), | ||||
|     'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'), | ||||
|     'League\\CommonMark\\' => array($vendorDir . '/league/commonmark/src'), | ||||
|     'Laravel\\Ui\\' => array($vendorDir . '/laravel/ui/src'), | ||||
|     'Laravel\\Tinker\\' => array($vendorDir . '/laravel/tinker/src'), | ||||
|     'JakubOnderka\\PhpConsoleHighlighter\\' => array($vendorDir . '/jakub-onderka/php-console-highlighter/src'), | ||||
|     'JakubOnderka\\PhpConsoleColor\\' => array($vendorDir . '/jakub-onderka/php-console-color/src'), | ||||
|     'Illuminate\\Notifications\\' => array($vendorDir . '/laravel/nexmo-notification-channel/src', $vendorDir . '/laravel/slack-notification-channel/src'), | ||||
|     'Illuminate\\Foundation\\Auth\\' => array($vendorDir . '/laravel/ui/auth-backend'), | ||||
|     'Illuminate\\' => array($vendorDir . '/laravel/framework/src/Illuminate'), | ||||
|     'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'), | ||||
|     'Http\\Message\\MultipartStream\\' => array($vendorDir . '/php-http/multipart-stream-builder/src'), | ||||
|     'Http\\Message\\' => array($vendorDir . '/php-http/message/src', $vendorDir . '/php-http/message-factory/src'), | ||||
|     'Http\\Discovery\\' => array($vendorDir . '/php-http/discovery/src'), | ||||
|     'Http\\Client\\Common\\Plugin\\' => array($vendorDir . '/php-http/cache-plugin/src'), | ||||
|     'Http\\Client\\Common\\' => array($vendorDir . '/php-http/client-common/src'), | ||||
|     'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'), | ||||
|     'Http\\Adapter\\Guzzle6\\' => array($vendorDir . '/php-http/guzzle6-adapter/src'), | ||||
|     'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), | ||||
|     'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), | ||||
|     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), | ||||
|     'GrahamCampbell\\Manager\\' => array($vendorDir . '/graham-campbell/manager/src'), | ||||
|     'GrahamCampbell\\GitHub\\' => array($vendorDir . '/graham-campbell/github/src'), | ||||
|     'GrahamCampbell\\CachePlugin\\' => array($vendorDir . '/graham-campbell/cache-plugin/src'), | ||||
|     'GrahamCampbell\\BoundedCache\\' => array($vendorDir . '/graham-campbell/bounded-cache/src'), | ||||
|     'Github\\' => array($vendorDir . '/knplabs/github-api/lib/Github'), | ||||
|     'Fideloper\\Proxy\\' => array($vendorDir . '/fideloper/proxy/src'), | ||||
|     'Faker\\' => array($vendorDir . '/fzaninotto/faker/src/Faker'), | ||||
|     'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'), | ||||
|     'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), | ||||
|     'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), | ||||
|     'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), | ||||
|     'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'), | ||||
|     'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'), | ||||
|     'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'), | ||||
|     'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), | ||||
|     'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'), | ||||
|     'Collective\\Html\\' => array($vendorDir . '/laravelcollective/html/src'), | ||||
|     'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'), | ||||
|     'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'), | ||||
|     'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), | ||||
|     'App\\' => array($baseDir . '/app'), | ||||
|     '' => array($vendorDir . '/nesbot/carbon/src'), | ||||
| ); | ||||
|   | ||||
							
								
								
									
										18
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							| @@ -13,19 +13,24 @@ class ComposerAutoloaderInit4b6fb9210a1ea37c2db27b8ff53a1ecf | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return \Composer\Autoload\ClassLoader | ||||
|      */ | ||||
|     public static function getLoader() | ||||
|     { | ||||
|         if (null !== self::$loader) { | ||||
|             return self::$loader; | ||||
|         } | ||||
|  | ||||
|         require __DIR__ . '/platform_check.php'; | ||||
|  | ||||
|         spl_autoload_register(array('ComposerAutoloaderInit4b6fb9210a1ea37c2db27b8ff53a1ecf', 'loadClassLoader'), true, true); | ||||
|         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | ||||
|         self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); | ||||
|         spl_autoload_unregister(array('ComposerAutoloaderInit4b6fb9210a1ea37c2db27b8ff53a1ecf', 'loadClassLoader')); | ||||
|  | ||||
|         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); | ||||
|         if ($useStaticLoader) { | ||||
|             require_once __DIR__ . '/autoload_static.php'; | ||||
|             require __DIR__ . '/autoload_static.php'; | ||||
|  | ||||
|             call_user_func(\Composer\Autoload\ComposerStaticInit4b6fb9210a1ea37c2db27b8ff53a1ecf::getInitializer($loader)); | ||||
|         } else { | ||||
| @@ -60,11 +65,16 @@ class ComposerAutoloaderInit4b6fb9210a1ea37c2db27b8ff53a1ecf | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param string $fileIdentifier | ||||
|  * @param string $file | ||||
|  * @return void | ||||
|  */ | ||||
| function composerRequire4b6fb9210a1ea37c2db27b8ff53a1ecf($fileIdentifier, $file) | ||||
| { | ||||
|     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { | ||||
|         require $file; | ||||
|  | ||||
|         $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; | ||||
|  | ||||
|         require $file; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										1845
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1845
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5786
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5786
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1320
									
								
								vendor/composer/installed.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1320
									
								
								vendor/composer/installed.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										26
									
								
								vendor/composer/platform_check.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/composer/platform_check.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| // platform_check.php @generated by Composer | ||||
|  | ||||
| $issues = array(); | ||||
|  | ||||
| if (!(PHP_VERSION_ID >= 70400)) { | ||||
|     $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; | ||||
| } | ||||
|  | ||||
| if ($issues) { | ||||
|     if (!headers_sent()) { | ||||
|         header('HTTP/1.1 500 Internal Server Error'); | ||||
|     } | ||||
|     if (!ini_get('display_errors')) { | ||||
|         if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { | ||||
|             fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); | ||||
|         } elseif (!headers_sent()) { | ||||
|             echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; | ||||
|         } | ||||
|     } | ||||
|     trigger_error( | ||||
|         'Composer detected issues in your platform: ' . implode(' ', $issues), | ||||
|         E_USER_ERROR | ||||
|     ); | ||||
| } | ||||
							
								
								
									
										1
									
								
								vendor/dnoegel/php-xdg-base-dir/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/dnoegel/php-xdg-base-dir/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| /vendor/ | ||||
							
								
								
									
										19
									
								
								vendor/dnoegel/php-xdg-base-dir/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/dnoegel/php-xdg-base-dir/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| Copyright (c) 2014 Daniel Nögel | ||||
|  | ||||
| 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. | ||||
							
								
								
									
										38
									
								
								vendor/dnoegel/php-xdg-base-dir/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/dnoegel/php-xdg-base-dir/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,38 +0,0 @@ | ||||
| # XDG Base Directory | ||||
|  | ||||
| [](LICENSE.md) | ||||
|  | ||||
| Implementation of XDG Base Directory  specification for php | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| Via Composer | ||||
|  | ||||
| ``` bash | ||||
| $ composer require dnoegel/php-xdg-base-dir | ||||
| ``` | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ``` php | ||||
| $xdg = \XdgBaseDir\Xdg(); | ||||
|  | ||||
| echo $xdg->getHomeDir(); | ||||
| echo $xdg->getHomeConfigDir() | ||||
| echo $xdg->getHomeDataDir() | ||||
| echo $xdg->getHomeCacheDir() | ||||
| echo $xdg->getRuntimeDir() | ||||
|  | ||||
| $xdg->getDataDirs() // returns array | ||||
| $xdg->getConfigDirs() // returns array | ||||
| ``` | ||||
|  | ||||
| ## Testing | ||||
|  | ||||
| ``` bash | ||||
| $ phpunit | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| The MIT License (MIT). Please see [License File](https://github.com/dnoegel/php-xdg-base-dir/blob/master/LICENSE) for more information. | ||||
							
								
								
									
										17
									
								
								vendor/dnoegel/php-xdg-base-dir/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/dnoegel/php-xdg-base-dir/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,17 +0,0 @@ | ||||
| { | ||||
|     "name": "dnoegel/php-xdg-base-dir", | ||||
|     "description": "implementation of xdg base directory specification for php", | ||||
|     "type": "project", | ||||
|     "license": "MIT", | ||||
|     "require": { | ||||
|         "php": ">=5.3.2" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "@stable" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "XdgBaseDir\\": "src/" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/dnoegel/php-xdg-base-dir/phpunit.xml.dist
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/dnoegel/php-xdg-base-dir/phpunit.xml.dist
									
									
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
| <phpunit colors="true" | ||||
|          convertErrorsToExceptions="true" | ||||
|          convertNoticesToExceptions="true" | ||||
|          convertWarningsToExceptions="true" | ||||
|          processIsolation="false" | ||||
|          stopOnFailure="false" | ||||
|          syntaxCheck="false" | ||||
|          bootstrap="vendor/autoload.php" | ||||
|         > | ||||
|  | ||||
|     <testsuites> | ||||
|         <testsuite name="php-xdg-base-dir unit tests"> | ||||
|             <directory>./tests/</directory> | ||||
|         </testsuite> | ||||
|     </testsuites> | ||||
|  | ||||
|     <filter> | ||||
|         <whitelist> | ||||
|             <directory>./src/</directory> | ||||
|         </whitelist> | ||||
|     </filter> | ||||
| </phpunit> | ||||
							
								
								
									
										121
									
								
								vendor/dnoegel/php-xdg-base-dir/src/Xdg.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										121
									
								
								vendor/dnoegel/php-xdg-base-dir/src/Xdg.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,121 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace XdgBaseDir; | ||||
|  | ||||
| /** | ||||
|  * Simple implementation of the XDG standard http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html | ||||
|  * | ||||
|  * Based on the python implementation https://github.com/takluyver/pyxdg/blob/master/xdg/BaseDirectory.py | ||||
|  * | ||||
|  * Class Xdg | ||||
|  * @package ShopwareCli\Application | ||||
|  */ | ||||
| class Xdg | ||||
| { | ||||
|     const S_IFDIR = 040000; // directory | ||||
|     const S_IRWXO = 00007;  // rwx other | ||||
|     const S_IRWXG = 00056;  // rwx group | ||||
|     const RUNTIME_DIR_FALLBACK = 'php-xdg-runtime-dir-fallback-'; | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getHomeDir() | ||||
|     { | ||||
|         return getenv('HOME') ?: (getenv('HOMEDRIVE') . DIRECTORY_SEPARATOR . getenv('HOMEPATH')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getHomeConfigDir() | ||||
|     { | ||||
|         $path = getenv('XDG_CONFIG_HOME') ?: $this->getHomeDir() . DIRECTORY_SEPARATOR . '.config'; | ||||
|  | ||||
|         return $path; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getHomeDataDir() | ||||
|     { | ||||
|         $path = getenv('XDG_DATA_HOME') ?: $this->getHomeDir() . DIRECTORY_SEPARATOR . '.local' . DIRECTORY_SEPARATOR . 'share'; | ||||
|  | ||||
|         return $path; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getConfigDirs() | ||||
|     { | ||||
|         $configDirs = getenv('XDG_CONFIG_DIRS') ? explode(':', getenv('XDG_CONFIG_DIRS')) : array('/etc/xdg'); | ||||
|  | ||||
|         $paths = array_merge(array($this->getHomeConfigDir()), $configDirs); | ||||
|  | ||||
|         return $paths; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getDataDirs() | ||||
|     { | ||||
|         $dataDirs = getenv('XDG_DATA_DIRS') ? explode(':', getenv('XDG_DATA_DIRS')) : array('/usr/local/share', '/usr/share'); | ||||
|  | ||||
|         $paths = array_merge(array($this->getHomeDataDir()), $dataDirs); | ||||
|  | ||||
|         return $paths; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getHomeCacheDir() | ||||
|     { | ||||
|         $path = getenv('XDG_CACHE_HOME') ?: $this->getHomeDir() . DIRECTORY_SEPARATOR . '.cache'; | ||||
|  | ||||
|         return $path; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public function getRuntimeDir($strict=true) | ||||
|     { | ||||
|         if ($runtimeDir = getenv('XDG_RUNTIME_DIR')) { | ||||
|             return $runtimeDir; | ||||
|         } | ||||
|  | ||||
|         if ($strict) { | ||||
|             throw new \RuntimeException('XDG_RUNTIME_DIR was not set'); | ||||
|         } | ||||
|  | ||||
|         $fallback = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::RUNTIME_DIR_FALLBACK . getenv('USER'); | ||||
|  | ||||
|         $create = false; | ||||
|  | ||||
|         if (!is_dir($fallback)) { | ||||
|             mkdir($fallback, 0700, true); | ||||
|         } | ||||
|  | ||||
|         $st = lstat($fallback); | ||||
|  | ||||
|         # The fallback must be a directory | ||||
|         if (!$st['mode'] & self::S_IFDIR) { | ||||
|             rmdir($fallback); | ||||
|             $create = true; | ||||
|         } elseif ($st['uid'] != getmyuid() || | ||||
|             $st['mode'] & (self::S_IRWXG | self::S_IRWXO) | ||||
|         ) { | ||||
|             rmdir($fallback); | ||||
|             $create = true; | ||||
|         } | ||||
|  | ||||
|         if ($create) { | ||||
|             mkdir($fallback, 0700, true); | ||||
|         } | ||||
|  | ||||
|         return $fallback; | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										116
									
								
								vendor/dnoegel/php-xdg-base-dir/tests/XdgTest.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/dnoegel/php-xdg-base-dir/tests/XdgTest.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,116 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| class XdgTest extends PHPUnit_Framework_TestCase | ||||
| { | ||||
|     /** | ||||
|      * @return \XdgBaseDir\Xdg | ||||
|      */ | ||||
|     public function getXdg() | ||||
|     { | ||||
|         return new \XdgBaseDir\Xdg(); | ||||
|     } | ||||
|  | ||||
|     public function testGetHomeDir() | ||||
|     { | ||||
|          putenv('HOME=/fake-dir'); | ||||
|          $this->assertEquals('/fake-dir', $this->getXdg()->getHomeDir()); | ||||
|     } | ||||
|  | ||||
|     public function testGetFallbackHomeDir() | ||||
|     { | ||||
|         putenv('HOME='); | ||||
|         putenv('HOMEDRIVE=C:'); | ||||
|         putenv('HOMEPATH=fake-dir'); | ||||
|         $this->assertEquals('C:/fake-dir', $this->getXdg()->getHomeDir()); | ||||
|     } | ||||
|  | ||||
|     public function testXdgPutCache() | ||||
|     { | ||||
|         putenv('XDG_DATA_HOME=tmp/'); | ||||
|         putenv('XDG_CONFIG_HOME=tmp/'); | ||||
|         putenv('XDG_CACHE_HOME=tmp/'); | ||||
|         $this->assertEquals('tmp/', $this->getXdg()->getHomeCacheDir()); | ||||
|     } | ||||
|  | ||||
|     public function testXdgPutData() | ||||
|     { | ||||
|         putenv('XDG_DATA_HOME=tmp/'); | ||||
|         $this->assertEquals('tmp/', $this->getXdg()->getHomeDataDir()); | ||||
|     } | ||||
|  | ||||
|     public function testXdgPutConfig() | ||||
|     { | ||||
|         putenv('XDG_CONFIG_HOME=tmp/'); | ||||
|         $this->assertEquals('tmp/', $this->getXdg()->getHomeConfigDir()); | ||||
|     } | ||||
|  | ||||
|     public function testXdgDataDirsShouldIncludeHomeDataDir() | ||||
|     { | ||||
|         putenv('XDG_DATA_HOME=tmp/'); | ||||
|         putenv('XDG_CONFIG_HOME=tmp/'); | ||||
|  | ||||
|         $this->assertArrayHasKey('tmp/', array_flip($this->getXdg()->getDataDirs())); | ||||
|     } | ||||
|  | ||||
|     public function testXdgConfigDirsShouldIncludeHomeConfigDir() | ||||
|     { | ||||
|         putenv('XDG_CONFIG_HOME=tmp/'); | ||||
|  | ||||
|         $this->assertArrayHasKey('tmp/', array_flip($this->getXdg()->getConfigDirs())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * If XDG_RUNTIME_DIR is set, it should be returned | ||||
|      */ | ||||
|     public function testGetRuntimeDir() | ||||
|     { | ||||
|         putenv('XDG_RUNTIME_DIR=/tmp/'); | ||||
|         $runtimeDir = $this->getXdg()->getRuntimeDir(); | ||||
|  | ||||
|         $this->assertEquals(is_dir($runtimeDir), true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * In strict mode, an exception should be shown if XDG_RUNTIME_DIR does not exist | ||||
|      * | ||||
|      * @expectedException \RuntimeException | ||||
|      */ | ||||
|     public function testGetRuntimeDirShouldThrowException() | ||||
|     { | ||||
|         putenv('XDG_RUNTIME_DIR='); | ||||
|         $this->getXdg()->getRuntimeDir(true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * In fallback mode a directory should be created | ||||
|      */ | ||||
|     public function testGetRuntimeDirShouldCreateDirectory() | ||||
|     { | ||||
|         putenv('XDG_RUNTIME_DIR='); | ||||
|         $dir = $this->getXdg()->getRuntimeDir(false); | ||||
|         $permission = decoct(fileperms($dir) & 0777); | ||||
|         $this->assertEquals(700, $permission); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ensure, that the fallback directories are created with correct permission | ||||
|      */ | ||||
|     public function testGetRuntimeShouldDeleteDirsWithWrongPermission() | ||||
|     { | ||||
|         $runtimeDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . XdgBaseDir\Xdg::RUNTIME_DIR_FALLBACK . getenv('USER'); | ||||
|  | ||||
|         rmdir($runtimeDir); | ||||
|         mkdir($runtimeDir, 0764, true); | ||||
|  | ||||
|         // Permission should be wrong now | ||||
|         $permission = decoct(fileperms($runtimeDir) & 0777); | ||||
|         $this->assertEquals(764, $permission); | ||||
|  | ||||
|         putenv('XDG_RUNTIME_DIR='); | ||||
|         $dir = $this->getXdg()->getRuntimeDir(false); | ||||
|  | ||||
|         // Permission should be fixed | ||||
|         $permission = decoct(fileperms($dir) & 0777); | ||||
|         $this->assertEquals(700, $permission); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/doctrine/inflector/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/doctrine/inflector/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| # Doctrine Inflector | ||||
|  | ||||
| Doctrine Inflector is a small library that can perform string manipulations | ||||
| with regard to upper-/lowercase and singular/plural forms of words. | ||||
| with regard to uppercase/lowercase and singular/plural forms of words. | ||||
|  | ||||
| [](https://travis-ci.org/doctrine/inflector) | ||||
| [](https://github.com/doctrine/inflector/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x) | ||||
| [](https://codecov.io/gh/doctrine/inflector/branch/2.0.x) | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/doctrine/inflector/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/doctrine/inflector/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,9 +1,9 @@ | ||||
| { | ||||
|     "name": "doctrine/inflector", | ||||
|     "type": "library", | ||||
|     "description": "Common String Manipulations with regard to casing and singular/plural rules.", | ||||
|     "keywords": ["string", "inflection", "singularize", "pluralize"], | ||||
|     "homepage": "http://www.doctrine-project.org", | ||||
|     "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", | ||||
|     "keywords": ["php", "strings", "words", "manipulation", "inflector", "inflection", "uppercase", "lowercase", "singular", "plural"], | ||||
|     "homepage": "https://www.doctrine-project.org/projects/inflector.html", | ||||
|     "license": "MIT", | ||||
|     "authors": [ | ||||
|         {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, | ||||
| @@ -13,20 +13,24 @@ | ||||
|         {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} | ||||
|     ], | ||||
|     "require": { | ||||
|         "php": "^7.1" | ||||
|         "php": "^7.2 || ^8.0" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "^6.2" | ||||
|         "doctrine/coding-standard": "^8.2", | ||||
|         "phpstan/phpstan": "^0.12", | ||||
|         "phpstan/phpstan-phpunit": "^0.12", | ||||
|         "phpstan/phpstan-strict-rules": "^0.12", | ||||
|         "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", | ||||
|         "vimeo/psalm": "^4.10" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" } | ||||
|         "psr-4": { | ||||
|             "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" | ||||
|         } | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { "Doctrine\\Tests\\Common\\Inflector\\": "tests/Doctrine/Tests/Common/Inflector" } | ||||
|     }, | ||||
|     "extra": { | ||||
|         "branch-alias": { | ||||
|             "dev-master": "1.3.x-dev" | ||||
|         "psr-4": { | ||||
|             "Doctrine\\Tests\\Inflector\\": "tests/Doctrine/Tests/Inflector" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										226
									
								
								vendor/doctrine/inflector/docs/en/index.rst
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								vendor/doctrine/inflector/docs/en/index.rst
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| Introduction | ||||
| ============ | ||||
|  | ||||
| The Doctrine Inflector has methods for inflecting text. The features include pluralization, | ||||
| singularization, converting between camelCase and under_score and capitalizing | ||||
| words. | ||||
|  | ||||
| Installation | ||||
| ============ | ||||
|  | ||||
| You can install the Inflector with composer: | ||||
|  | ||||
| .. code-block:: console | ||||
|  | ||||
|     $ composer require doctrine/inflector | ||||
|  | ||||
| Usage | ||||
| ===== | ||||
|  | ||||
| Using the inflector is easy, you can create a new ``Doctrine\Inflector\Inflector`` instance by using | ||||
| the ``Doctrine\Inflector\InflectorFactory`` class: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     use Doctrine\Inflector\InflectorFactory; | ||||
|  | ||||
|     $inflector = InflectorFactory::create()->build(); | ||||
|  | ||||
| By default it will create an English inflector. If you want to use another language, just pass the language | ||||
| you want to create an inflector for to the ``createForLanguage()`` method: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     use Doctrine\Inflector\InflectorFactory; | ||||
|     use Doctrine\Inflector\Language; | ||||
|  | ||||
|     $inflector = InflectorFactory::createForLanguage(Language::SPANISH)->build(); | ||||
|  | ||||
| The supported languages are as follows: | ||||
|  | ||||
| - ``Language::ENGLISH`` | ||||
| - ``Language::FRENCH`` | ||||
| - ``Language::NORWEGIAN_BOKMAL`` | ||||
| - ``Language::PORTUGUESE`` | ||||
| - ``Language::SPANISH`` | ||||
| - ``Language::TURKISH`` | ||||
|  | ||||
| If you want to manually construct the inflector instead of using a factory, you can do so like this: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     use Doctrine\Inflector\CachedWordInflector; | ||||
|     use Doctrine\Inflector\RulesetInflector; | ||||
|     use Doctrine\Inflector\Rules\English; | ||||
|  | ||||
|     $inflector = new Inflector( | ||||
|         new CachedWordInflector(new RulesetInflector( | ||||
|             English\Rules::getSingularRuleset() | ||||
|         )), | ||||
|         new CachedWordInflector(new RulesetInflector( | ||||
|             English\Rules::getPluralRuleset() | ||||
|         )) | ||||
|     ); | ||||
|  | ||||
| Adding Languages | ||||
| ---------------- | ||||
|  | ||||
| If you are interested in adding support for your language, take a look at the other languages defined in the | ||||
| ``Doctrine\Inflector\Rules`` namespace and the tests located in ``Doctrine\Tests\Inflector\Rules``. You can copy | ||||
| one of the languages and update the rules for your language. | ||||
|  | ||||
| Once you have done this, send a pull request to the ``doctrine/inflector`` repository with the additions. | ||||
|  | ||||
| Custom Setup | ||||
| ============ | ||||
|  | ||||
| If you want to setup custom singular and plural rules, you can configure these in the factory: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     use Doctrine\Inflector\InflectorFactory; | ||||
|     use Doctrine\Inflector\Rules\Pattern; | ||||
|     use Doctrine\Inflector\Rules\Patterns; | ||||
|     use Doctrine\Inflector\Rules\Ruleset; | ||||
|     use Doctrine\Inflector\Rules\Substitution; | ||||
|     use Doctrine\Inflector\Rules\Substitutions; | ||||
|     use Doctrine\Inflector\Rules\Transformation; | ||||
|     use Doctrine\Inflector\Rules\Transformations; | ||||
|     use Doctrine\Inflector\Rules\Word; | ||||
|  | ||||
|     $inflector = InflectorFactory::create() | ||||
|         ->withSingularRules( | ||||
|             new Ruleset( | ||||
|                 new Transformations( | ||||
|                     new Transformation(new Pattern('/^(bil)er$/i'), '\1'), | ||||
|                     new Transformation(new Pattern('/^(inflec|contribu)tors$/i'), '\1ta') | ||||
|                 ), | ||||
|                 new Patterns(new Pattern('singulars')), | ||||
|                 new Substitutions(new Substitution(new Word('spins'), new Word('spinor'))) | ||||
|             ) | ||||
|         ) | ||||
|         ->withPluralRules( | ||||
|             new Ruleset( | ||||
|                 new Transformations( | ||||
|                     new Transformation(new Pattern('^(bil)er$'), '\1'), | ||||
|                     new Transformation(new Pattern('^(inflec|contribu)tors$'), '\1ta') | ||||
|                 ), | ||||
|                 new Patterns(new Pattern('noflect'), new Pattern('abtuse')), | ||||
|                 new Substitutions( | ||||
|                     new Substitution(new Word('amaze'), new Word('amazable')), | ||||
|                     new Substitution(new Word('phone'), new Word('phonezes')) | ||||
|                 ) | ||||
|             ) | ||||
|         ) | ||||
|         ->build(); | ||||
|  | ||||
| No operation inflector | ||||
| ---------------------- | ||||
|  | ||||
| The ``Doctrine\Inflector\NoopWordInflector`` may be used to configure an inflector that doesn't perform any operation for | ||||
| pluralization and/or singularization. If will simply return the input as output. | ||||
|  | ||||
| This is an implementation of the `Null Object design pattern <https://sourcemaking.com/design_patterns/null_object>`_. | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     use Doctrine\Inflector\Inflector; | ||||
|     use Doctrine\Inflector\NoopWordInflector; | ||||
|  | ||||
|     $inflector = new Inflector(new NoopWordInflector(), new NoopWordInflector()); | ||||
|  | ||||
| Tableize | ||||
| ======== | ||||
|  | ||||
| Converts ``ModelName`` to ``model_name``: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->tableize('ModelName'); // model_name | ||||
|  | ||||
| Classify | ||||
| ======== | ||||
|  | ||||
| Converts ``model_name`` to ``ModelName``: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->classify('model_name'); // ModelName | ||||
|  | ||||
| Camelize | ||||
| ======== | ||||
|  | ||||
| This method uses `Classify`_ and then converts the first character to lowercase: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->camelize('model_name'); // modelName | ||||
|  | ||||
| Capitalize | ||||
| ========== | ||||
|  | ||||
| Takes a string and capitalizes all of the words, like PHP's built-in | ||||
| ``ucwords`` function. This extends that behavior, however, by allowing the | ||||
| word delimiters to be configured, rather than only separating on | ||||
| whitespace. | ||||
|  | ||||
| Here is an example: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     $string = 'top-o-the-morning to all_of_you!'; | ||||
|  | ||||
|     echo $inflector->capitalize($string); // Top-O-The-Morning To All_of_you! | ||||
|  | ||||
|     echo $inflector->capitalize($string, '-_ '); // Top-O-The-Morning To All_Of_You! | ||||
|  | ||||
| Pluralize | ||||
| ========= | ||||
|  | ||||
| Returns a word in plural form. | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->pluralize('browser'); // browsers | ||||
|  | ||||
| Singularize | ||||
| =========== | ||||
|  | ||||
| Returns a word in singular form. | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->singularize('browsers'); // browser | ||||
|  | ||||
| Urlize | ||||
| ====== | ||||
|  | ||||
| Generate a URL friendly string from a string of text: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->urlize('My first blog post'); // my-first-blog-post | ||||
|  | ||||
| Unaccent | ||||
| ======== | ||||
|  | ||||
| You can unaccent a string of text using the ``unaccent()`` method: | ||||
|  | ||||
| .. code-block:: php | ||||
|  | ||||
|     echo $inflector->unaccent('año'); // ano | ||||
|  | ||||
| Legacy API | ||||
| ========== | ||||
|  | ||||
| The API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0. | ||||
| Support for languages other than English is available in the 2.0 API only. | ||||
|  | ||||
| Acknowledgements | ||||
| ================ | ||||
|  | ||||
| The language rules in this library have been adapted from several different sources, including but not limited to: | ||||
|  | ||||
| - `Ruby On Rails Inflector <http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html>`_ | ||||
| - `ICanBoogie Inflector <https://github.com/ICanBoogie/Inflector>`_ | ||||
| - `CakePHP Inflector <https://book.cakephp.org/3.0/en/core-libraries/inflector.html>`_ | ||||
| @@ -1,490 +0,0 @@ | ||||
| <?php | ||||
| /* | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
|  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
|  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
|  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
|  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
|  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
|  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  * | ||||
|  * This software consists of voluntary contributions made by many individuals | ||||
|  * and is licensed under the MIT license. For more information, see | ||||
|  * <http://www.doctrine-project.org>. | ||||
|  */ | ||||
|  | ||||
| namespace Doctrine\Common\Inflector; | ||||
|  | ||||
| /** | ||||
|  * Doctrine inflector has static methods for inflecting text. | ||||
|  * | ||||
|  * The methods in these classes are from several different sources collected | ||||
|  * across several different php projects and several different authors. The | ||||
|  * original author names and emails are not known. | ||||
|  * | ||||
|  * Pluralize & Singularize implementation are borrowed from CakePHP with some modifications. | ||||
|  * | ||||
|  * @link   www.doctrine-project.org | ||||
|  * @since  1.0 | ||||
|  * @author Konsta Vesterinen <kvesteri@cc.hut.fi> | ||||
|  * @author Jonathan H. Wage <jonwage@gmail.com> | ||||
|  */ | ||||
| class Inflector | ||||
| { | ||||
|     /** | ||||
|      * Plural inflector rules. | ||||
|      * | ||||
|      * @var string[][] | ||||
|      */ | ||||
|     private static $plural = array( | ||||
|         'rules' => array( | ||||
|             '/(s)tatus$/i' => '\1\2tatuses', | ||||
|             '/(quiz)$/i' => '\1zes', | ||||
|             '/^(ox)$/i' => '\1\2en', | ||||
|             '/([m|l])ouse$/i' => '\1ice', | ||||
|             '/(matr|vert|ind)(ix|ex)$/i' => '\1ices', | ||||
|             '/(x|ch|ss|sh)$/i' => '\1es', | ||||
|             '/([^aeiouy]|qu)y$/i' => '\1ies', | ||||
|             '/(hive|gulf)$/i' => '\1s', | ||||
|             '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', | ||||
|             '/sis$/i' => 'ses', | ||||
|             '/([ti])um$/i' => '\1a', | ||||
|             '/(c)riterion$/i' => '\1riteria', | ||||
|             '/(p)erson$/i' => '\1eople', | ||||
|             '/(m)an$/i' => '\1en', | ||||
|             '/(c)hild$/i' => '\1hildren', | ||||
|             '/(f)oot$/i' => '\1eet', | ||||
|             '/(buffal|her|potat|tomat|volcan)o$/i' => '\1\2oes', | ||||
|             '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i', | ||||
|             '/us$/i' => 'uses', | ||||
|             '/(alias)$/i' => '\1es', | ||||
|             '/(analys|ax|cris|test|thes)is$/i' => '\1es', | ||||
|             '/s$/' => 's', | ||||
|             '/^$/' => '', | ||||
|             '/$/' => 's', | ||||
|         ), | ||||
|         'uninflected' => array( | ||||
|             '.*[nrlm]ese', | ||||
|             '.*deer', | ||||
|             '.*fish', | ||||
|             '.*measles', | ||||
|             '.*ois', | ||||
|             '.*pox', | ||||
|             '.*sheep', | ||||
|             'people', | ||||
|             'cookie', | ||||
|             'police', | ||||
|         ), | ||||
|         'irregular' => array( | ||||
|             'atlas' => 'atlases', | ||||
|             'axe' => 'axes', | ||||
|             'beef' => 'beefs', | ||||
|             'brother' => 'brothers', | ||||
|             'cafe' => 'cafes', | ||||
|             'chateau' => 'chateaux', | ||||
|             'niveau' => 'niveaux', | ||||
|             'child' => 'children', | ||||
|             'cookie' => 'cookies', | ||||
|             'corpus' => 'corpuses', | ||||
|             'cow' => 'cows', | ||||
|             'criterion' => 'criteria', | ||||
|             'curriculum' => 'curricula', | ||||
|             'demo' => 'demos', | ||||
|             'domino' => 'dominoes', | ||||
|             'echo' => 'echoes', | ||||
|             'foot' => 'feet', | ||||
|             'fungus' => 'fungi', | ||||
|             'ganglion' => 'ganglions', | ||||
|             'genie' => 'genies', | ||||
|             'genus' => 'genera', | ||||
|             'goose' => 'geese', | ||||
|             'graffito' => 'graffiti', | ||||
|             'hippopotamus' => 'hippopotami', | ||||
|             'hoof' => 'hoofs', | ||||
|             'human' => 'humans', | ||||
|             'iris' => 'irises', | ||||
|             'larva' => 'larvae', | ||||
|             'leaf' => 'leaves', | ||||
|             'loaf' => 'loaves', | ||||
|             'man' => 'men', | ||||
|             'medium' => 'media', | ||||
|             'memorandum' => 'memoranda', | ||||
|             'money' => 'monies', | ||||
|             'mongoose' => 'mongooses', | ||||
|             'motto' => 'mottoes', | ||||
|             'move' => 'moves', | ||||
|             'mythos' => 'mythoi', | ||||
|             'niche' => 'niches', | ||||
|             'nucleus' => 'nuclei', | ||||
|             'numen' => 'numina', | ||||
|             'occiput' => 'occiputs', | ||||
|             'octopus' => 'octopuses', | ||||
|             'opus' => 'opuses', | ||||
|             'ox' => 'oxen', | ||||
|             'passerby' => 'passersby', | ||||
|             'penis' => 'penises', | ||||
|             'person' => 'people', | ||||
|             'plateau' => 'plateaux', | ||||
|             'runner-up' => 'runners-up', | ||||
|             'sex' => 'sexes', | ||||
|             'soliloquy' => 'soliloquies', | ||||
|             'son-in-law' => 'sons-in-law', | ||||
|             'syllabus' => 'syllabi', | ||||
|             'testis' => 'testes', | ||||
|             'thief' => 'thieves', | ||||
|             'tooth' => 'teeth', | ||||
|             'tornado' => 'tornadoes', | ||||
|             'trilby' => 'trilbys', | ||||
|             'turf' => 'turfs', | ||||
|             'valve' => 'valves', | ||||
|             'volcano' => 'volcanoes', | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     /** | ||||
|      * Singular inflector rules. | ||||
|      * | ||||
|      * @var string[][] | ||||
|      */ | ||||
|     private static $singular = array( | ||||
|         'rules' => array( | ||||
|             '/(s)tatuses$/i' => '\1\2tatus', | ||||
|             '/^(.*)(menu)s$/i' => '\1\2', | ||||
|             '/(quiz)zes$/i' => '\\1', | ||||
|             '/(matr)ices$/i' => '\1ix', | ||||
|             '/(vert|ind)ices$/i' => '\1ex', | ||||
|             '/^(ox)en/i' => '\1', | ||||
|             '/(alias)(es)*$/i' => '\1', | ||||
|             '/(buffal|her|potat|tomat|volcan)oes$/i' => '\1o', | ||||
|             '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us', | ||||
|             '/([ftw]ax)es/i' => '\1', | ||||
|             '/(analys|ax|cris|test|thes)es$/i' => '\1is', | ||||
|             '/(shoe|slave)s$/i' => '\1', | ||||
|             '/(o)es$/i' => '\1', | ||||
|             '/ouses$/' => 'ouse', | ||||
|             '/([^a])uses$/' => '\1us', | ||||
|             '/([m|l])ice$/i' => '\1ouse', | ||||
|             '/(x|ch|ss|sh)es$/i' => '\1', | ||||
|             '/(m)ovies$/i' => '\1\2ovie', | ||||
|             '/(s)eries$/i' => '\1\2eries', | ||||
|             '/([^aeiouy]|qu)ies$/i' => '\1y', | ||||
|             '/([lr])ves$/i' => '\1f', | ||||
|             '/(tive)s$/i' => '\1', | ||||
|             '/(hive)s$/i' => '\1', | ||||
|             '/(drive)s$/i' => '\1', | ||||
|             '/(dive)s$/i' => '\1', | ||||
|             '/(olive)s$/i' => '\1', | ||||
|             '/([^fo])ves$/i' => '\1fe', | ||||
|             '/(^analy)ses$/i' => '\1sis', | ||||
|             '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', | ||||
|             '/(c)riteria$/i' => '\1riterion', | ||||
|             '/([ti])a$/i' => '\1um', | ||||
|             '/(p)eople$/i' => '\1\2erson', | ||||
|             '/(m)en$/i' => '\1an', | ||||
|             '/(c)hildren$/i' => '\1\2hild', | ||||
|             '/(f)eet$/i' => '\1oot', | ||||
|             '/(n)ews$/i' => '\1\2ews', | ||||
|             '/eaus$/' => 'eau', | ||||
|             '/^(.*us)$/' => '\\1', | ||||
|             '/s$/i' => '', | ||||
|         ), | ||||
|         'uninflected' => array( | ||||
|             '.*[nrlm]ese', | ||||
|             '.*deer', | ||||
|             '.*fish', | ||||
|             '.*measles', | ||||
|             '.*ois', | ||||
|             '.*pox', | ||||
|             '.*sheep', | ||||
|             '.*ss', | ||||
|             'data', | ||||
|             'police', | ||||
|             'pants', | ||||
|             'clothes', | ||||
|         ), | ||||
|         'irregular' => array( | ||||
|             'abuses'     => 'abuse', | ||||
|             'avalanches' => 'avalanche', | ||||
|             'caches'     => 'cache', | ||||
|             'criteria'   => 'criterion', | ||||
|             'curves'     => 'curve', | ||||
|             'emphases'   => 'emphasis', | ||||
|             'foes'       => 'foe', | ||||
|             'geese'      => 'goose', | ||||
|             'graves'     => 'grave', | ||||
|             'hoaxes'     => 'hoax', | ||||
|             'media'      => 'medium', | ||||
|             'neuroses'   => 'neurosis', | ||||
|             'waves'      => 'wave', | ||||
|             'oases'      => 'oasis', | ||||
|             'valves'     => 'valve', | ||||
|         ) | ||||
|     ); | ||||
|  | ||||
|     /** | ||||
|      * Words that should not be inflected. | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     private static $uninflected = array( | ||||
|         '.*?media', 'Amoyese', 'audio', 'bison', 'Borghese', 'bream', 'breeches', | ||||
|         'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers', 'cod', 'coitus', 'compensation', 'Congoese', | ||||
|         'contretemps', 'coreopsis', 'corps', 'data', 'debris', 'deer', 'diabetes', 'djinn', 'education', 'eland', | ||||
|         'elk', 'emoji', 'equipment', 'evidence', 'Faroese', 'feedback', 'fish', 'flounder', 'Foochowese', | ||||
|         'Furniture', 'furniture', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'gold',  | ||||
|         'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'jedi', | ||||
|         'Kiplingese', 'knowledge', 'Kongoese', 'love', 'Lucchese', 'Luggage', 'mackerel', 'Maltese', 'metadata', | ||||
|         'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese', 'nutrition', 'offspring', | ||||
|         'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'plankton', 'pliers', 'pokemon', 'police', 'Portuguese', | ||||
|         'proceedings', 'rabies', 'rain', 'rhinoceros', 'rice', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', | ||||
|         'series', 'Shavese', 'shears', 'sheep', 'siemens', 'species', 'staff', 'swine', 'traffic', | ||||
|         'trousers', 'trout', 'tuna', 'us', 'Vermontese', 'Wenchowese', 'wheat', 'whiting', 'wildebeest', 'Yengeese' | ||||
|     ); | ||||
|  | ||||
|     /** | ||||
|      * Method cache array. | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     private static $cache = array(); | ||||
|  | ||||
|     /** | ||||
|      * The initial state of Inflector so reset() works. | ||||
|      * | ||||
|      * @var array | ||||
|      */ | ||||
|     private static $initialState = array(); | ||||
|  | ||||
|     /** | ||||
|      * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. | ||||
|      */ | ||||
|     public static function tableize(string $word) : string | ||||
|     { | ||||
|         return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. | ||||
|      */ | ||||
|     public static function classify(string $word) : string | ||||
|     { | ||||
|         return str_replace([' ', '_', '-'], '', ucwords($word, ' _-')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Camelizes a word. This uses the classify() method and turns the first character to lowercase. | ||||
|      */ | ||||
|     public static function camelize(string $word) : string | ||||
|     { | ||||
|         return lcfirst(self::classify($word)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Uppercases words with configurable delimeters between words. | ||||
|      * | ||||
|      * Takes a string and capitalizes all of the words, like PHP's built-in | ||||
|      * ucwords function. This extends that behavior, however, by allowing the | ||||
|      * word delimeters to be configured, rather than only separating on | ||||
|      * whitespace. | ||||
|      * | ||||
|      * Here is an example: | ||||
|      * <code> | ||||
|      * <?php | ||||
|      * $string = 'top-o-the-morning to all_of_you!'; | ||||
|      * echo \Doctrine\Common\Inflector\Inflector::ucwords($string); | ||||
|      * // Top-O-The-Morning To All_of_you! | ||||
|      * | ||||
|      * echo \Doctrine\Common\Inflector\Inflector::ucwords($string, '-_ '); | ||||
|      * // Top-O-The-Morning To All_Of_You! | ||||
|      * ?> | ||||
|      * </code> | ||||
|      * | ||||
|      * @param string $string The string to operate on. | ||||
|      * @param string $delimiters A list of word separators. | ||||
|      * | ||||
|      * @return string The string with all delimeter-separated words capitalized. | ||||
|      */ | ||||
|     public static function ucwords(string $string, string $delimiters = " \n\t\r\0\x0B-") : string | ||||
|     { | ||||
|         return ucwords($string, $delimiters); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Clears Inflectors inflected value caches, and resets the inflection | ||||
|      * rules to the initial values. | ||||
|      */ | ||||
|     public static function reset() : void | ||||
|     { | ||||
|         if (empty(self::$initialState)) { | ||||
|             self::$initialState = get_class_vars('Inflector'); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         foreach (self::$initialState as $key => $val) { | ||||
|             if ($key !== 'initialState') { | ||||
|                 self::${$key} = $val; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds custom inflection $rules, of either 'plural' or 'singular' $type. | ||||
|      * | ||||
|      * ### Usage: | ||||
|      * | ||||
|      * {{{ | ||||
|      * Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables')); | ||||
|      * Inflector::rules('plural', array( | ||||
|      *     'rules' => array('/^(inflect)ors$/i' => '\1ables'), | ||||
|      *     'uninflected' => array('dontinflectme'), | ||||
|      *     'irregular' => array('red' => 'redlings') | ||||
|      * )); | ||||
|      * }}} | ||||
|      * | ||||
|      * @param string  $type         The type of inflection, either 'plural' or 'singular' | ||||
|      * @param array|iterable $rules An array of rules to be added. | ||||
|      * @param boolean $reset        If true, will unset default inflections for all | ||||
|      *                              new rules that are being defined in $rules. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public static function rules(string $type, iterable $rules, bool $reset = false) : void | ||||
|     { | ||||
|         foreach ($rules as $rule => $pattern) { | ||||
|             if ( ! is_array($pattern)) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if ($reset) { | ||||
|                 self::${$type}[$rule] = $pattern; | ||||
|             } else { | ||||
|                 self::${$type}[$rule] = ($rule === 'uninflected') | ||||
|                     ? array_merge($pattern, self::${$type}[$rule]) | ||||
|                     : $pattern + self::${$type}[$rule]; | ||||
|             } | ||||
|  | ||||
|             unset($rules[$rule], self::${$type}['cache' . ucfirst($rule)]); | ||||
|  | ||||
|             if (isset(self::${$type}['merged'][$rule])) { | ||||
|                 unset(self::${$type}['merged'][$rule]); | ||||
|             } | ||||
|  | ||||
|             if ($type === 'plural') { | ||||
|                 self::$cache['pluralize'] = self::$cache['tableize'] = array(); | ||||
|             } elseif ($type === 'singular') { | ||||
|                 self::$cache['singularize'] = array(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         self::${$type}['rules'] = $rules + self::${$type}['rules']; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a word in plural form. | ||||
|      * | ||||
|      * @param string $word The word in singular form. | ||||
|      * | ||||
|      * @return string The word in plural form. | ||||
|      */ | ||||
|     public static function pluralize(string $word) : string | ||||
|     { | ||||
|         if (isset(self::$cache['pluralize'][$word])) { | ||||
|             return self::$cache['pluralize'][$word]; | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$plural['merged']['irregular'])) { | ||||
|             self::$plural['merged']['irregular'] = self::$plural['irregular']; | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$plural['merged']['uninflected'])) { | ||||
|             self::$plural['merged']['uninflected'] = array_merge(self::$plural['uninflected'], self::$uninflected); | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$plural['cacheUninflected']) || !isset(self::$plural['cacheIrregular'])) { | ||||
|             self::$plural['cacheUninflected'] = '(?:' . implode('|', self::$plural['merged']['uninflected']) . ')'; | ||||
|             self::$plural['cacheIrregular']   = '(?:' . implode('|', array_keys(self::$plural['merged']['irregular'])) . ')'; | ||||
|         } | ||||
|  | ||||
|         if (preg_match('/(.*)\\b(' . self::$plural['cacheIrregular'] . ')$/i', $word, $regs)) { | ||||
|             self::$cache['pluralize'][$word] = $regs[1] . $word[0] . substr(self::$plural['merged']['irregular'][strtolower($regs[2])], 1); | ||||
|  | ||||
|             return self::$cache['pluralize'][$word]; | ||||
|         } | ||||
|  | ||||
|         if (preg_match('/^(' . self::$plural['cacheUninflected'] . ')$/i', $word, $regs)) { | ||||
|             self::$cache['pluralize'][$word] = $word; | ||||
|  | ||||
|             return $word; | ||||
|         } | ||||
|  | ||||
|         foreach (self::$plural['rules'] as $rule => $replacement) { | ||||
|             if (preg_match($rule, $word)) { | ||||
|                 self::$cache['pluralize'][$word] = preg_replace($rule, $replacement, $word); | ||||
|  | ||||
|                 return self::$cache['pluralize'][$word]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a word in singular form. | ||||
|      * | ||||
|      * @param string $word The word in plural form. | ||||
|      * | ||||
|      * @return string The word in singular form. | ||||
|      */ | ||||
|     public static function singularize(string $word) : string | ||||
|     { | ||||
|         if (isset(self::$cache['singularize'][$word])) { | ||||
|             return self::$cache['singularize'][$word]; | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$singular['merged']['uninflected'])) { | ||||
|             self::$singular['merged']['uninflected'] = array_merge( | ||||
|                 self::$singular['uninflected'], | ||||
|                 self::$uninflected | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$singular['merged']['irregular'])) { | ||||
|             self::$singular['merged']['irregular'] = array_merge( | ||||
|                 self::$singular['irregular'], | ||||
|                 array_flip(self::$plural['irregular']) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if (!isset(self::$singular['cacheUninflected']) || !isset(self::$singular['cacheIrregular'])) { | ||||
|             self::$singular['cacheUninflected'] = '(?:' . implode('|', self::$singular['merged']['uninflected']) . ')'; | ||||
|             self::$singular['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$singular['merged']['irregular'])) . ')'; | ||||
|         } | ||||
|  | ||||
|         if (preg_match('/(.*)\\b(' . self::$singular['cacheIrregular'] . ')$/i', $word, $regs)) { | ||||
|             self::$cache['singularize'][$word] = $regs[1] . $word[0] . substr(self::$singular['merged']['irregular'][strtolower($regs[2])], 1); | ||||
|  | ||||
|             return self::$cache['singularize'][$word]; | ||||
|         } | ||||
|  | ||||
|         if (preg_match('/^(' . self::$singular['cacheUninflected'] . ')$/i', $word, $regs)) { | ||||
|             self::$cache['singularize'][$word] = $word; | ||||
|  | ||||
|             return $word; | ||||
|         } | ||||
|  | ||||
|         foreach (self::$singular['rules'] as $rule => $replacement) { | ||||
|             if (preg_match($rule, $word)) { | ||||
|                 self::$cache['singularize'][$word] = preg_replace($rule, $replacement, $word); | ||||
|  | ||||
|                 return self::$cache['singularize'][$word]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         self::$cache['singularize'][$word] = $word; | ||||
|  | ||||
|         return $word; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										24
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| class CachedWordInflector implements WordInflector | ||||
| { | ||||
|     /** @var WordInflector */ | ||||
|     private $wordInflector; | ||||
|  | ||||
|     /** @var string[] */ | ||||
|     private $cache = []; | ||||
|  | ||||
|     public function __construct(WordInflector $wordInflector) | ||||
|     { | ||||
|         $this->wordInflector = $wordInflector; | ||||
|     } | ||||
|  | ||||
|     public function inflect(string $word): string | ||||
|     { | ||||
|         return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										66
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
|  | ||||
| use function array_unshift; | ||||
|  | ||||
| abstract class GenericLanguageInflectorFactory implements LanguageInflectorFactory | ||||
| { | ||||
|     /** @var Ruleset[] */ | ||||
|     private $singularRulesets = []; | ||||
|  | ||||
|     /** @var Ruleset[] */ | ||||
|     private $pluralRulesets = []; | ||||
|  | ||||
|     final public function __construct() | ||||
|     { | ||||
|         $this->singularRulesets[] = $this->getSingularRuleset(); | ||||
|         $this->pluralRulesets[]   = $this->getPluralRuleset(); | ||||
|     } | ||||
|  | ||||
|     final public function build(): Inflector | ||||
|     { | ||||
|         return new Inflector( | ||||
|             new CachedWordInflector(new RulesetInflector( | ||||
|                 ...$this->singularRulesets | ||||
|             )), | ||||
|             new CachedWordInflector(new RulesetInflector( | ||||
|                 ...$this->pluralRulesets | ||||
|             )) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory | ||||
|     { | ||||
|         if ($reset) { | ||||
|             $this->singularRulesets = []; | ||||
|         } | ||||
|  | ||||
|         if ($singularRules instanceof Ruleset) { | ||||
|             array_unshift($this->singularRulesets, $singularRules); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory | ||||
|     { | ||||
|         if ($reset) { | ||||
|             $this->pluralRulesets = []; | ||||
|         } | ||||
|  | ||||
|         if ($pluralRules instanceof Ruleset) { | ||||
|             array_unshift($this->pluralRulesets, $pluralRules); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     abstract protected function getSingularRuleset(): Ruleset; | ||||
|  | ||||
|     abstract protected function getPluralRuleset(): Ruleset; | ||||
| } | ||||
							
								
								
									
										507
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										507
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,507 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| use RuntimeException; | ||||
|  | ||||
| use function chr; | ||||
| use function function_exists; | ||||
| use function lcfirst; | ||||
| use function mb_strtolower; | ||||
| use function ord; | ||||
| use function preg_match; | ||||
| use function preg_replace; | ||||
| use function sprintf; | ||||
| use function str_replace; | ||||
| use function strlen; | ||||
| use function strtolower; | ||||
| use function strtr; | ||||
| use function trim; | ||||
| use function ucwords; | ||||
|  | ||||
| class Inflector | ||||
| { | ||||
|     private const ACCENTED_CHARACTERS = [ | ||||
|         'À' => 'A', | ||||
|         'Á' => 'A', | ||||
|         'Â' => 'A', | ||||
|         'Ã' => 'A', | ||||
|         'Ä' => 'Ae', | ||||
|         'Æ' => 'Ae', | ||||
|         'Å' => 'Aa', | ||||
|         'æ' => 'a', | ||||
|         'Ç' => 'C', | ||||
|         'È' => 'E', | ||||
|         'É' => 'E', | ||||
|         'Ê' => 'E', | ||||
|         'Ë' => 'E', | ||||
|         'Ì' => 'I', | ||||
|         'Í' => 'I', | ||||
|         'Î' => 'I', | ||||
|         'Ï' => 'I', | ||||
|         'Ñ' => 'N', | ||||
|         'Ò' => 'O', | ||||
|         'Ó' => 'O', | ||||
|         'Ô' => 'O', | ||||
|         'Õ' => 'O', | ||||
|         'Ö' => 'Oe', | ||||
|         'Ù' => 'U', | ||||
|         'Ú' => 'U', | ||||
|         'Û' => 'U', | ||||
|         'Ü' => 'Ue', | ||||
|         'Ý' => 'Y', | ||||
|         'ß' => 'ss', | ||||
|         'à' => 'a', | ||||
|         'á' => 'a', | ||||
|         'â' => 'a', | ||||
|         'ã' => 'a', | ||||
|         'ä' => 'ae', | ||||
|         'å' => 'aa', | ||||
|         'ç' => 'c', | ||||
|         'è' => 'e', | ||||
|         'é' => 'e', | ||||
|         'ê' => 'e', | ||||
|         'ë' => 'e', | ||||
|         'ì' => 'i', | ||||
|         'í' => 'i', | ||||
|         'î' => 'i', | ||||
|         'ï' => 'i', | ||||
|         'ñ' => 'n', | ||||
|         'ò' => 'o', | ||||
|         'ó' => 'o', | ||||
|         'ô' => 'o', | ||||
|         'õ' => 'o', | ||||
|         'ö' => 'oe', | ||||
|         'ù' => 'u', | ||||
|         'ú' => 'u', | ||||
|         'û' => 'u', | ||||
|         'ü' => 'ue', | ||||
|         'ý' => 'y', | ||||
|         'ÿ' => 'y', | ||||
|         'Ā' => 'A', | ||||
|         'ā' => 'a', | ||||
|         'Ă' => 'A', | ||||
|         'ă' => 'a', | ||||
|         'Ą' => 'A', | ||||
|         'ą' => 'a', | ||||
|         'Ć' => 'C', | ||||
|         'ć' => 'c', | ||||
|         'Ĉ' => 'C', | ||||
|         'ĉ' => 'c', | ||||
|         'Ċ' => 'C', | ||||
|         'ċ' => 'c', | ||||
|         'Č' => 'C', | ||||
|         'č' => 'c', | ||||
|         'Ď' => 'D', | ||||
|         'ď' => 'd', | ||||
|         'Đ' => 'D', | ||||
|         'đ' => 'd', | ||||
|         'Ē' => 'E', | ||||
|         'ē' => 'e', | ||||
|         'Ĕ' => 'E', | ||||
|         'ĕ' => 'e', | ||||
|         'Ė' => 'E', | ||||
|         'ė' => 'e', | ||||
|         'Ę' => 'E', | ||||
|         'ę' => 'e', | ||||
|         'Ě' => 'E', | ||||
|         'ě' => 'e', | ||||
|         'Ĝ' => 'G', | ||||
|         'ĝ' => 'g', | ||||
|         'Ğ' => 'G', | ||||
|         'ğ' => 'g', | ||||
|         'Ġ' => 'G', | ||||
|         'ġ' => 'g', | ||||
|         'Ģ' => 'G', | ||||
|         'ģ' => 'g', | ||||
|         'Ĥ' => 'H', | ||||
|         'ĥ' => 'h', | ||||
|         'Ħ' => 'H', | ||||
|         'ħ' => 'h', | ||||
|         'Ĩ' => 'I', | ||||
|         'ĩ' => 'i', | ||||
|         'Ī' => 'I', | ||||
|         'ī' => 'i', | ||||
|         'Ĭ' => 'I', | ||||
|         'ĭ' => 'i', | ||||
|         'Į' => 'I', | ||||
|         'į' => 'i', | ||||
|         'İ' => 'I', | ||||
|         'ı' => 'i', | ||||
|         'IJ' => 'IJ', | ||||
|         'ij' => 'ij', | ||||
|         'Ĵ' => 'J', | ||||
|         'ĵ' => 'j', | ||||
|         'Ķ' => 'K', | ||||
|         'ķ' => 'k', | ||||
|         'ĸ' => 'k', | ||||
|         'Ĺ' => 'L', | ||||
|         'ĺ' => 'l', | ||||
|         'Ļ' => 'L', | ||||
|         'ļ' => 'l', | ||||
|         'Ľ' => 'L', | ||||
|         'ľ' => 'l', | ||||
|         'Ŀ' => 'L', | ||||
|         'ŀ' => 'l', | ||||
|         'Ł' => 'L', | ||||
|         'ł' => 'l', | ||||
|         'Ń' => 'N', | ||||
|         'ń' => 'n', | ||||
|         'Ņ' => 'N', | ||||
|         'ņ' => 'n', | ||||
|         'Ň' => 'N', | ||||
|         'ň' => 'n', | ||||
|         'ʼn' => 'N', | ||||
|         'Ŋ' => 'n', | ||||
|         'ŋ' => 'N', | ||||
|         'Ō' => 'O', | ||||
|         'ō' => 'o', | ||||
|         'Ŏ' => 'O', | ||||
|         'ŏ' => 'o', | ||||
|         'Ő' => 'O', | ||||
|         'ő' => 'o', | ||||
|         'Œ' => 'OE', | ||||
|         'œ' => 'oe', | ||||
|         'Ø' => 'O', | ||||
|         'ø' => 'o', | ||||
|         'Ŕ' => 'R', | ||||
|         'ŕ' => 'r', | ||||
|         'Ŗ' => 'R', | ||||
|         'ŗ' => 'r', | ||||
|         'Ř' => 'R', | ||||
|         'ř' => 'r', | ||||
|         'Ś' => 'S', | ||||
|         'ś' => 's', | ||||
|         'Ŝ' => 'S', | ||||
|         'ŝ' => 's', | ||||
|         'Ş' => 'S', | ||||
|         'ş' => 's', | ||||
|         'Š' => 'S', | ||||
|         'š' => 's', | ||||
|         'Ţ' => 'T', | ||||
|         'ţ' => 't', | ||||
|         'Ť' => 'T', | ||||
|         'ť' => 't', | ||||
|         'Ŧ' => 'T', | ||||
|         'ŧ' => 't', | ||||
|         'Ũ' => 'U', | ||||
|         'ũ' => 'u', | ||||
|         'Ū' => 'U', | ||||
|         'ū' => 'u', | ||||
|         'Ŭ' => 'U', | ||||
|         'ŭ' => 'u', | ||||
|         'Ů' => 'U', | ||||
|         'ů' => 'u', | ||||
|         'Ű' => 'U', | ||||
|         'ű' => 'u', | ||||
|         'Ų' => 'U', | ||||
|         'ų' => 'u', | ||||
|         'Ŵ' => 'W', | ||||
|         'ŵ' => 'w', | ||||
|         'Ŷ' => 'Y', | ||||
|         'ŷ' => 'y', | ||||
|         'Ÿ' => 'Y', | ||||
|         'Ź' => 'Z', | ||||
|         'ź' => 'z', | ||||
|         'Ż' => 'Z', | ||||
|         'ż' => 'z', | ||||
|         'Ž' => 'Z', | ||||
|         'ž' => 'z', | ||||
|         'ſ' => 's', | ||||
|         '€' => 'E', | ||||
|         '£' => '', | ||||
|     ]; | ||||
|  | ||||
|     /** @var WordInflector */ | ||||
|     private $singularizer; | ||||
|  | ||||
|     /** @var WordInflector */ | ||||
|     private $pluralizer; | ||||
|  | ||||
|     public function __construct(WordInflector $singularizer, WordInflector $pluralizer) | ||||
|     { | ||||
|         $this->singularizer = $singularizer; | ||||
|         $this->pluralizer   = $pluralizer; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'. | ||||
|      */ | ||||
|     public function tableize(string $word): string | ||||
|     { | ||||
|         $tableized = preg_replace('~(?<=\\w)([A-Z])~u', '_$1', $word); | ||||
|  | ||||
|         if ($tableized === null) { | ||||
|             throw new RuntimeException(sprintf( | ||||
|                 'preg_replace returned null for value "%s"', | ||||
|                 $word | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         return mb_strtolower($tableized); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'. | ||||
|      */ | ||||
|     public function classify(string $word): string | ||||
|     { | ||||
|         return str_replace([' ', '_', '-'], '', ucwords($word, ' _-')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Camelizes a word. This uses the classify() method and turns the first character to lowercase. | ||||
|      */ | ||||
|     public function camelize(string $word): string | ||||
|     { | ||||
|         return lcfirst($this->classify($word)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Uppercases words with configurable delimiters between words. | ||||
|      * | ||||
|      * Takes a string and capitalizes all of the words, like PHP's built-in | ||||
|      * ucwords function. This extends that behavior, however, by allowing the | ||||
|      * word delimiters to be configured, rather than only separating on | ||||
|      * whitespace. | ||||
|      * | ||||
|      * Here is an example: | ||||
|      * <code> | ||||
|      * <?php | ||||
|      * $string = 'top-o-the-morning to all_of_you!'; | ||||
|      * echo $inflector->capitalize($string); | ||||
|      * // Top-O-The-Morning To All_of_you! | ||||
|      * | ||||
|      * echo $inflector->capitalize($string, '-_ '); | ||||
|      * // Top-O-The-Morning To All_Of_You! | ||||
|      * ?> | ||||
|      * </code> | ||||
|      * | ||||
|      * @param string $string     The string to operate on. | ||||
|      * @param string $delimiters A list of word separators. | ||||
|      * | ||||
|      * @return string The string with all delimiter-separated words capitalized. | ||||
|      */ | ||||
|     public function capitalize(string $string, string $delimiters = " \n\t\r\0\x0B-"): string | ||||
|     { | ||||
|         return ucwords($string, $delimiters); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Checks if the given string seems like it has utf8 characters in it. | ||||
|      * | ||||
|      * @param string $string The string to check for utf8 characters in. | ||||
|      */ | ||||
|     public function seemsUtf8(string $string): bool | ||||
|     { | ||||
|         for ($i = 0; $i < strlen($string); $i++) { | ||||
|             if (ord($string[$i]) < 0x80) { | ||||
|                 continue; // 0bbbbbbb | ||||
|             } | ||||
|  | ||||
|             if ((ord($string[$i]) & 0xE0) === 0xC0) { | ||||
|                 $n = 1; // 110bbbbb | ||||
|             } elseif ((ord($string[$i]) & 0xF0) === 0xE0) { | ||||
|                 $n = 2; // 1110bbbb | ||||
|             } elseif ((ord($string[$i]) & 0xF8) === 0xF0) { | ||||
|                 $n = 3; // 11110bbb | ||||
|             } elseif ((ord($string[$i]) & 0xFC) === 0xF8) { | ||||
|                 $n = 4; // 111110bb | ||||
|             } elseif ((ord($string[$i]) & 0xFE) === 0xFC) { | ||||
|                 $n = 5; // 1111110b | ||||
|             } else { | ||||
|                 return false; // Does not match any model | ||||
|             } | ||||
|  | ||||
|             for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ? | ||||
|                 if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Remove any illegal characters, accents, etc. | ||||
|      * | ||||
|      * @param  string $string String to unaccent | ||||
|      * | ||||
|      * @return string Unaccented string | ||||
|      */ | ||||
|     public function unaccent(string $string): string | ||||
|     { | ||||
|         if (preg_match('/[\x80-\xff]/', $string) === false) { | ||||
|             return $string; | ||||
|         } | ||||
|  | ||||
|         if ($this->seemsUtf8($string)) { | ||||
|             $string = strtr($string, self::ACCENTED_CHARACTERS); | ||||
|         } else { | ||||
|             $characters = []; | ||||
|  | ||||
|             // Assume ISO-8859-1 if not UTF-8 | ||||
|             $characters['in'] = | ||||
|                   chr(128) | ||||
|                 . chr(131) | ||||
|                 . chr(138) | ||||
|                 . chr(142) | ||||
|                 . chr(154) | ||||
|                 . chr(158) | ||||
|                 . chr(159) | ||||
|                 . chr(162) | ||||
|                 . chr(165) | ||||
|                 . chr(181) | ||||
|                 . chr(192) | ||||
|                 . chr(193) | ||||
|                 . chr(194) | ||||
|                 . chr(195) | ||||
|                 . chr(196) | ||||
|                 . chr(197) | ||||
|                 . chr(199) | ||||
|                 . chr(200) | ||||
|                 . chr(201) | ||||
|                 . chr(202) | ||||
|                 . chr(203) | ||||
|                 . chr(204) | ||||
|                 . chr(205) | ||||
|                 . chr(206) | ||||
|                 . chr(207) | ||||
|                 . chr(209) | ||||
|                 . chr(210) | ||||
|                 . chr(211) | ||||
|                 . chr(212) | ||||
|                 . chr(213) | ||||
|                 . chr(214) | ||||
|                 . chr(216) | ||||
|                 . chr(217) | ||||
|                 . chr(218) | ||||
|                 . chr(219) | ||||
|                 . chr(220) | ||||
|                 . chr(221) | ||||
|                 . chr(224) | ||||
|                 . chr(225) | ||||
|                 . chr(226) | ||||
|                 . chr(227) | ||||
|                 . chr(228) | ||||
|                 . chr(229) | ||||
|                 . chr(231) | ||||
|                 . chr(232) | ||||
|                 . chr(233) | ||||
|                 . chr(234) | ||||
|                 . chr(235) | ||||
|                 . chr(236) | ||||
|                 . chr(237) | ||||
|                 . chr(238) | ||||
|                 . chr(239) | ||||
|                 . chr(241) | ||||
|                 . chr(242) | ||||
|                 . chr(243) | ||||
|                 . chr(244) | ||||
|                 . chr(245) | ||||
|                 . chr(246) | ||||
|                 . chr(248) | ||||
|                 . chr(249) | ||||
|                 . chr(250) | ||||
|                 . chr(251) | ||||
|                 . chr(252) | ||||
|                 . chr(253) | ||||
|                 . chr(255); | ||||
|  | ||||
|             $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'; | ||||
|  | ||||
|             $string = strtr($string, $characters['in'], $characters['out']); | ||||
|  | ||||
|             $doubleChars = []; | ||||
|  | ||||
|             $doubleChars['in'] = [ | ||||
|                 chr(140), | ||||
|                 chr(156), | ||||
|                 chr(198), | ||||
|                 chr(208), | ||||
|                 chr(222), | ||||
|                 chr(223), | ||||
|                 chr(230), | ||||
|                 chr(240), | ||||
|                 chr(254), | ||||
|             ]; | ||||
|  | ||||
|             $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th']; | ||||
|  | ||||
|             $string = str_replace($doubleChars['in'], $doubleChars['out'], $string); | ||||
|         } | ||||
|  | ||||
|         return $string; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Convert any passed string to a url friendly string. | ||||
|      * Converts 'My first blog post' to 'my-first-blog-post' | ||||
|      * | ||||
|      * @param  string $string String to urlize. | ||||
|      * | ||||
|      * @return string Urlized string. | ||||
|      */ | ||||
|     public function urlize(string $string): string | ||||
|     { | ||||
|         // Remove all non url friendly characters with the unaccent function | ||||
|         $unaccented = $this->unaccent($string); | ||||
|  | ||||
|         if (function_exists('mb_strtolower')) { | ||||
|             $lowered = mb_strtolower($unaccented); | ||||
|         } else { | ||||
|             $lowered = strtolower($unaccented); | ||||
|         } | ||||
|  | ||||
|         $replacements = [ | ||||
|             '/\W/' => ' ', | ||||
|             '/([A-Z]+)([A-Z][a-z])/' => '\1_\2', | ||||
|             '/([a-z\d])([A-Z])/' => '\1_\2', | ||||
|             '/[^A-Z^a-z^0-9^\/]+/' => '-', | ||||
|         ]; | ||||
|  | ||||
|         $urlized = $lowered; | ||||
|  | ||||
|         foreach ($replacements as $pattern => $replacement) { | ||||
|             $replaced = preg_replace($pattern, $replacement, $urlized); | ||||
|  | ||||
|             if ($replaced === null) { | ||||
|                 throw new RuntimeException(sprintf( | ||||
|                     'preg_replace returned null for value "%s"', | ||||
|                     $urlized | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
|             $urlized = $replaced; | ||||
|         } | ||||
|  | ||||
|         return trim($urlized, '-'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a word in singular form. | ||||
|      * | ||||
|      * @param string $word The word in plural form. | ||||
|      * | ||||
|      * @return string The word in singular form. | ||||
|      */ | ||||
|     public function singularize(string $word): string | ||||
|     { | ||||
|         return $this->singularizer->inflect($word); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a word in plural form. | ||||
|      * | ||||
|      * @param string $word The word in singular form. | ||||
|      * | ||||
|      * @return string The word in plural form. | ||||
|      */ | ||||
|     public function pluralize(string $word): string | ||||
|     { | ||||
|         return $this->pluralizer->inflect($word); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										52
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\English; | ||||
| use Doctrine\Inflector\Rules\French; | ||||
| use Doctrine\Inflector\Rules\NorwegianBokmal; | ||||
| use Doctrine\Inflector\Rules\Portuguese; | ||||
| use Doctrine\Inflector\Rules\Spanish; | ||||
| use Doctrine\Inflector\Rules\Turkish; | ||||
| use InvalidArgumentException; | ||||
|  | ||||
| use function sprintf; | ||||
|  | ||||
| final class InflectorFactory | ||||
| { | ||||
|     public static function create(): LanguageInflectorFactory | ||||
|     { | ||||
|         return self::createForLanguage(Language::ENGLISH); | ||||
|     } | ||||
|  | ||||
|     public static function createForLanguage(string $language): LanguageInflectorFactory | ||||
|     { | ||||
|         switch ($language) { | ||||
|             case Language::ENGLISH: | ||||
|                 return new English\InflectorFactory(); | ||||
|  | ||||
|             case Language::FRENCH: | ||||
|                 return new French\InflectorFactory(); | ||||
|  | ||||
|             case Language::NORWEGIAN_BOKMAL: | ||||
|                 return new NorwegianBokmal\InflectorFactory(); | ||||
|  | ||||
|             case Language::PORTUGUESE: | ||||
|                 return new Portuguese\InflectorFactory(); | ||||
|  | ||||
|             case Language::SPANISH: | ||||
|                 return new Spanish\InflectorFactory(); | ||||
|  | ||||
|             case Language::TURKISH: | ||||
|                 return new Turkish\InflectorFactory(); | ||||
|  | ||||
|             default: | ||||
|                 throw new InvalidArgumentException(sprintf( | ||||
|                     'Language "%s" is not supported.', | ||||
|                     $language | ||||
|                 )); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Language.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Language.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| final class Language | ||||
| { | ||||
|     public const ENGLISH          = 'english'; | ||||
|     public const FRENCH           = 'french'; | ||||
|     public const NORWEGIAN_BOKMAL = 'norwegian-bokmal'; | ||||
|     public const PORTUGUESE       = 'portuguese'; | ||||
|     public const SPANISH          = 'spanish'; | ||||
|     public const TURKISH          = 'turkish'; | ||||
|  | ||||
|     private function __construct() | ||||
|     { | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/LanguageInflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/LanguageInflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
|  | ||||
| interface LanguageInflectorFactory | ||||
| { | ||||
|     /** | ||||
|      * Applies custom rules for singularisation | ||||
|      * | ||||
|      * @param bool $reset If true, will unset default inflections for all new rules | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function withSingularRules(?Ruleset $singularRules, bool $reset = false): self; | ||||
|  | ||||
|     /** | ||||
|      * Applies custom rules for pluralisation | ||||
|      * | ||||
|      * @param bool $reset If true, will unset default inflections for all new rules | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): self; | ||||
|  | ||||
|     /** | ||||
|      * Builds the inflector instance with all applicable rules | ||||
|      */ | ||||
|     public function build(): Inflector; | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/NoopWordInflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/NoopWordInflector.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector; | ||||
|  | ||||
| class NoopWordInflector implements WordInflector | ||||
| { | ||||
|     public function inflect(string $word): string | ||||
|     { | ||||
|         return $word; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										182
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,182 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\English; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
| use Doctrine\Inflector\Rules\Substitution; | ||||
| use Doctrine\Inflector\Rules\Transformation; | ||||
| use Doctrine\Inflector\Rules\Word; | ||||
|  | ||||
| class Inflectible | ||||
| { | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('(s)tatuses$'), '\1\2tatus'); | ||||
|         yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatus'); | ||||
|         yield new Transformation(new Pattern('(c)ampus$'), '\1\2ampus'); | ||||
|         yield new Transformation(new Pattern('^(.*)(menu)s$'), '\1\2'); | ||||
|         yield new Transformation(new Pattern('(quiz)zes$'), '\\1'); | ||||
|         yield new Transformation(new Pattern('(matr)ices$'), '\1ix'); | ||||
|         yield new Transformation(new Pattern('(vert|ind)ices$'), '\1ex'); | ||||
|         yield new Transformation(new Pattern('^(ox)en'), '\1'); | ||||
|         yield new Transformation(new Pattern('(alias)(es)*$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)oes$'), '\1o'); | ||||
|         yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$'), '\1us'); | ||||
|         yield new Transformation(new Pattern('([ftw]ax)es'), '\1'); | ||||
|         yield new Transformation(new Pattern('(analys|ax|cris|test|thes)es$'), '\1is'); | ||||
|         yield new Transformation(new Pattern('(shoe|slave)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(o)es$'), '\1'); | ||||
|         yield new Transformation(new Pattern('ouses$'), 'ouse'); | ||||
|         yield new Transformation(new Pattern('([^a])uses$'), '\1us'); | ||||
|         yield new Transformation(new Pattern('([m|l])ice$'), '\1ouse'); | ||||
|         yield new Transformation(new Pattern('(x|ch|ss|sh)es$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(m)ovies$'), '\1\2ovie'); | ||||
|         yield new Transformation(new Pattern('(s)eries$'), '\1\2eries'); | ||||
|         yield new Transformation(new Pattern('([^aeiouy]|qu)ies$'), '\1y'); | ||||
|         yield new Transformation(new Pattern('([lr])ves$'), '\1f'); | ||||
|         yield new Transformation(new Pattern('(tive)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(hive)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(drive)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(dive)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('(olive)s$'), '\1'); | ||||
|         yield new Transformation(new Pattern('([^fo])ves$'), '\1fe'); | ||||
|         yield new Transformation(new Pattern('(^analy)ses$'), '\1sis'); | ||||
|         yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\1\2sis'); | ||||
|         yield new Transformation(new Pattern('(tax)a$'), '\1on'); | ||||
|         yield new Transformation(new Pattern('(c)riteria$'), '\1riterion'); | ||||
|         yield new Transformation(new Pattern('([ti])a$'), '\1um'); | ||||
|         yield new Transformation(new Pattern('(p)eople$'), '\1\2erson'); | ||||
|         yield new Transformation(new Pattern('(m)en$'), '\1an'); | ||||
|         yield new Transformation(new Pattern('(c)hildren$'), '\1\2hild'); | ||||
|         yield new Transformation(new Pattern('(f)eet$'), '\1oot'); | ||||
|         yield new Transformation(new Pattern('(n)ews$'), '\1\2ews'); | ||||
|         yield new Transformation(new Pattern('eaus$'), 'eau'); | ||||
|         yield new Transformation(new Pattern('s$'), ''); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('(s)tatus$'), '\1\2tatuses'); | ||||
|         yield new Transformation(new Pattern('(quiz)$'), '\1zes'); | ||||
|         yield new Transformation(new Pattern('^(ox)$'), '\1\2en'); | ||||
|         yield new Transformation(new Pattern('([m|l])ouse$'), '\1ice'); | ||||
|         yield new Transformation(new Pattern('(matr|vert|ind)(ix|ex)$'), '\1ices'); | ||||
|         yield new Transformation(new Pattern('(x|ch|ss|sh)$'), '\1es'); | ||||
|         yield new Transformation(new Pattern('([^aeiouy]|qu)y$'), '\1ies'); | ||||
|         yield new Transformation(new Pattern('(hive|gulf)$'), '\1s'); | ||||
|         yield new Transformation(new Pattern('(?:([^f])fe|([lr])f)$'), '\1\2ves'); | ||||
|         yield new Transformation(new Pattern('sis$'), 'ses'); | ||||
|         yield new Transformation(new Pattern('([ti])um$'), '\1a'); | ||||
|         yield new Transformation(new Pattern('(tax)on$'), '\1a'); | ||||
|         yield new Transformation(new Pattern('(c)riterion$'), '\1riteria'); | ||||
|         yield new Transformation(new Pattern('(p)erson$'), '\1eople'); | ||||
|         yield new Transformation(new Pattern('(m)an$'), '\1en'); | ||||
|         yield new Transformation(new Pattern('(c)hild$'), '\1hildren'); | ||||
|         yield new Transformation(new Pattern('(f)oot$'), '\1eet'); | ||||
|         yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)o$'), '\1\2oes'); | ||||
|         yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$'), '\1i'); | ||||
|         yield new Transformation(new Pattern('us$'), 'uses'); | ||||
|         yield new Transformation(new Pattern('(alias)$'), '\1es'); | ||||
|         yield new Transformation(new Pattern('(analys|ax|cris|test|thes)is$'), '\1es'); | ||||
|         yield new Transformation(new Pattern('s$'), 's'); | ||||
|         yield new Transformation(new Pattern('^$'), ''); | ||||
|         yield new Transformation(new Pattern('$'), 's'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Substitution[] | ||||
|      */ | ||||
|     public static function getIrregular(): iterable | ||||
|     { | ||||
|         yield new Substitution(new Word('atlas'), new Word('atlases')); | ||||
|         yield new Substitution(new Word('axe'), new Word('axes')); | ||||
|         yield new Substitution(new Word('beef'), new Word('beefs')); | ||||
|         yield new Substitution(new Word('brother'), new Word('brothers')); | ||||
|         yield new Substitution(new Word('cafe'), new Word('cafes')); | ||||
|         yield new Substitution(new Word('chateau'), new Word('chateaux')); | ||||
|         yield new Substitution(new Word('niveau'), new Word('niveaux')); | ||||
|         yield new Substitution(new Word('child'), new Word('children')); | ||||
|         yield new Substitution(new Word('canvas'), new Word('canvases')); | ||||
|         yield new Substitution(new Word('cookie'), new Word('cookies')); | ||||
|         yield new Substitution(new Word('corpus'), new Word('corpuses')); | ||||
|         yield new Substitution(new Word('cow'), new Word('cows')); | ||||
|         yield new Substitution(new Word('criterion'), new Word('criteria')); | ||||
|         yield new Substitution(new Word('curriculum'), new Word('curricula')); | ||||
|         yield new Substitution(new Word('demo'), new Word('demos')); | ||||
|         yield new Substitution(new Word('domino'), new Word('dominoes')); | ||||
|         yield new Substitution(new Word('echo'), new Word('echoes')); | ||||
|         yield new Substitution(new Word('foot'), new Word('feet')); | ||||
|         yield new Substitution(new Word('fungus'), new Word('fungi')); | ||||
|         yield new Substitution(new Word('ganglion'), new Word('ganglions')); | ||||
|         yield new Substitution(new Word('gas'), new Word('gases')); | ||||
|         yield new Substitution(new Word('genie'), new Word('genies')); | ||||
|         yield new Substitution(new Word('genus'), new Word('genera')); | ||||
|         yield new Substitution(new Word('goose'), new Word('geese')); | ||||
|         yield new Substitution(new Word('graffito'), new Word('graffiti')); | ||||
|         yield new Substitution(new Word('hippopotamus'), new Word('hippopotami')); | ||||
|         yield new Substitution(new Word('hoof'), new Word('hoofs')); | ||||
|         yield new Substitution(new Word('human'), new Word('humans')); | ||||
|         yield new Substitution(new Word('iris'), new Word('irises')); | ||||
|         yield new Substitution(new Word('larva'), new Word('larvae')); | ||||
|         yield new Substitution(new Word('leaf'), new Word('leaves')); | ||||
|         yield new Substitution(new Word('lens'), new Word('lenses')); | ||||
|         yield new Substitution(new Word('loaf'), new Word('loaves')); | ||||
|         yield new Substitution(new Word('man'), new Word('men')); | ||||
|         yield new Substitution(new Word('medium'), new Word('media')); | ||||
|         yield new Substitution(new Word('memorandum'), new Word('memoranda')); | ||||
|         yield new Substitution(new Word('money'), new Word('monies')); | ||||
|         yield new Substitution(new Word('mongoose'), new Word('mongooses')); | ||||
|         yield new Substitution(new Word('motto'), new Word('mottoes')); | ||||
|         yield new Substitution(new Word('move'), new Word('moves')); | ||||
|         yield new Substitution(new Word('mythos'), new Word('mythoi')); | ||||
|         yield new Substitution(new Word('niche'), new Word('niches')); | ||||
|         yield new Substitution(new Word('nucleus'), new Word('nuclei')); | ||||
|         yield new Substitution(new Word('numen'), new Word('numina')); | ||||
|         yield new Substitution(new Word('occiput'), new Word('occiputs')); | ||||
|         yield new Substitution(new Word('octopus'), new Word('octopuses')); | ||||
|         yield new Substitution(new Word('opus'), new Word('opuses')); | ||||
|         yield new Substitution(new Word('ox'), new Word('oxen')); | ||||
|         yield new Substitution(new Word('passerby'), new Word('passersby')); | ||||
|         yield new Substitution(new Word('penis'), new Word('penises')); | ||||
|         yield new Substitution(new Word('person'), new Word('people')); | ||||
|         yield new Substitution(new Word('plateau'), new Word('plateaux')); | ||||
|         yield new Substitution(new Word('runner-up'), new Word('runners-up')); | ||||
|         yield new Substitution(new Word('safe'), new Word('safes')); | ||||
|         yield new Substitution(new Word('sex'), new Word('sexes')); | ||||
|         yield new Substitution(new Word('soliloquy'), new Word('soliloquies')); | ||||
|         yield new Substitution(new Word('son-in-law'), new Word('sons-in-law')); | ||||
|         yield new Substitution(new Word('syllabus'), new Word('syllabi')); | ||||
|         yield new Substitution(new Word('testis'), new Word('testes')); | ||||
|         yield new Substitution(new Word('thief'), new Word('thieves')); | ||||
|         yield new Substitution(new Word('tooth'), new Word('teeth')); | ||||
|         yield new Substitution(new Word('tornado'), new Word('tornadoes')); | ||||
|         yield new Substitution(new Word('trilby'), new Word('trilbys')); | ||||
|         yield new Substitution(new Word('turf'), new Word('turfs')); | ||||
|         yield new Substitution(new Word('valve'), new Word('valves')); | ||||
|         yield new Substitution(new Word('volcano'), new Word('volcanoes')); | ||||
|         yield new Substitution(new Word('abuse'), new Word('abuses')); | ||||
|         yield new Substitution(new Word('avalanche'), new Word('avalanches')); | ||||
|         yield new Substitution(new Word('cache'), new Word('caches')); | ||||
|         yield new Substitution(new Word('criterion'), new Word('criteria')); | ||||
|         yield new Substitution(new Word('curve'), new Word('curves')); | ||||
|         yield new Substitution(new Word('emphasis'), new Word('emphases')); | ||||
|         yield new Substitution(new Word('foe'), new Word('foes')); | ||||
|         yield new Substitution(new Word('grave'), new Word('graves')); | ||||
|         yield new Substitution(new Word('hoax'), new Word('hoaxes')); | ||||
|         yield new Substitution(new Word('medium'), new Word('media')); | ||||
|         yield new Substitution(new Word('neurosis'), new Word('neuroses')); | ||||
|         yield new Substitution(new Word('save'), new Word('saves')); | ||||
|         yield new Substitution(new Word('wave'), new Word('waves')); | ||||
|         yield new Substitution(new Word('oasis'), new Word('oases')); | ||||
|         yield new Substitution(new Word('valve'), new Word('valves')); | ||||
|         yield new Substitution(new Word('zombie'), new Word('zombies')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\English; | ||||
|  | ||||
| use Doctrine\Inflector\GenericLanguageInflectorFactory; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
|  | ||||
| final class InflectorFactory extends GenericLanguageInflectorFactory | ||||
| { | ||||
|     protected function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getSingularRuleset(); | ||||
|     } | ||||
|  | ||||
|     protected function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getPluralRuleset(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\English; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Patterns; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
| use Doctrine\Inflector\Rules\Substitutions; | ||||
| use Doctrine\Inflector\Rules\Transformations; | ||||
|  | ||||
| final class Rules | ||||
| { | ||||
|     public static function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getSingular()), | ||||
|             new Patterns(...Uninflected::getSingular()), | ||||
|             (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getPlural()), | ||||
|             new Patterns(...Uninflected::getPlural()), | ||||
|             new Substitutions(...Inflectible::getIrregular()) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										193
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\English; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
|  | ||||
| final class Uninflected | ||||
| { | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|  | ||||
|         yield new Pattern('.*ss'); | ||||
|         yield new Pattern('clothes'); | ||||
|         yield new Pattern('data'); | ||||
|         yield new Pattern('fascia'); | ||||
|         yield new Pattern('fuchsia'); | ||||
|         yield new Pattern('galleria'); | ||||
|         yield new Pattern('mafia'); | ||||
|         yield new Pattern('militia'); | ||||
|         yield new Pattern('pants'); | ||||
|         yield new Pattern('petunia'); | ||||
|         yield new Pattern('sepia'); | ||||
|         yield new Pattern('trivia'); | ||||
|         yield new Pattern('utopia'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|  | ||||
|         yield new Pattern('people'); | ||||
|         yield new Pattern('trivia'); | ||||
|         yield new Pattern('\w+ware$'); | ||||
|         yield new Pattern('media'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     private static function getDefault(): iterable | ||||
|     { | ||||
|         yield new Pattern('\w+media'); | ||||
|         yield new Pattern('advice'); | ||||
|         yield new Pattern('aircraft'); | ||||
|         yield new Pattern('amoyese'); | ||||
|         yield new Pattern('art'); | ||||
|         yield new Pattern('audio'); | ||||
|         yield new Pattern('baggage'); | ||||
|         yield new Pattern('bison'); | ||||
|         yield new Pattern('borghese'); | ||||
|         yield new Pattern('bream'); | ||||
|         yield new Pattern('breeches'); | ||||
|         yield new Pattern('britches'); | ||||
|         yield new Pattern('buffalo'); | ||||
|         yield new Pattern('butter'); | ||||
|         yield new Pattern('cantus'); | ||||
|         yield new Pattern('carp'); | ||||
|         yield new Pattern('chassis'); | ||||
|         yield new Pattern('clippers'); | ||||
|         yield new Pattern('clothing'); | ||||
|         yield new Pattern('coal'); | ||||
|         yield new Pattern('cod'); | ||||
|         yield new Pattern('coitus'); | ||||
|         yield new Pattern('compensation'); | ||||
|         yield new Pattern('congoese'); | ||||
|         yield new Pattern('contretemps'); | ||||
|         yield new Pattern('coreopsis'); | ||||
|         yield new Pattern('corps'); | ||||
|         yield new Pattern('cotton'); | ||||
|         yield new Pattern('data'); | ||||
|         yield new Pattern('debris'); | ||||
|         yield new Pattern('deer'); | ||||
|         yield new Pattern('diabetes'); | ||||
|         yield new Pattern('djinn'); | ||||
|         yield new Pattern('education'); | ||||
|         yield new Pattern('eland'); | ||||
|         yield new Pattern('elk'); | ||||
|         yield new Pattern('emoji'); | ||||
|         yield new Pattern('equipment'); | ||||
|         yield new Pattern('evidence'); | ||||
|         yield new Pattern('faroese'); | ||||
|         yield new Pattern('feedback'); | ||||
|         yield new Pattern('fish'); | ||||
|         yield new Pattern('flounder'); | ||||
|         yield new Pattern('flour'); | ||||
|         yield new Pattern('foochowese'); | ||||
|         yield new Pattern('food'); | ||||
|         yield new Pattern('furniture'); | ||||
|         yield new Pattern('gallows'); | ||||
|         yield new Pattern('genevese'); | ||||
|         yield new Pattern('genoese'); | ||||
|         yield new Pattern('gilbertese'); | ||||
|         yield new Pattern('gold'); | ||||
|         yield new Pattern('headquarters'); | ||||
|         yield new Pattern('herpes'); | ||||
|         yield new Pattern('hijinks'); | ||||
|         yield new Pattern('homework'); | ||||
|         yield new Pattern('hottentotese'); | ||||
|         yield new Pattern('impatience'); | ||||
|         yield new Pattern('information'); | ||||
|         yield new Pattern('innings'); | ||||
|         yield new Pattern('jackanapes'); | ||||
|         yield new Pattern('jeans'); | ||||
|         yield new Pattern('jedi'); | ||||
|         yield new Pattern('kiplingese'); | ||||
|         yield new Pattern('knowledge'); | ||||
|         yield new Pattern('kongoese'); | ||||
|         yield new Pattern('leather'); | ||||
|         yield new Pattern('love'); | ||||
|         yield new Pattern('lucchese'); | ||||
|         yield new Pattern('luggage'); | ||||
|         yield new Pattern('mackerel'); | ||||
|         yield new Pattern('Maltese'); | ||||
|         yield new Pattern('management'); | ||||
|         yield new Pattern('metadata'); | ||||
|         yield new Pattern('mews'); | ||||
|         yield new Pattern('money'); | ||||
|         yield new Pattern('moose'); | ||||
|         yield new Pattern('mumps'); | ||||
|         yield new Pattern('music'); | ||||
|         yield new Pattern('nankingese'); | ||||
|         yield new Pattern('news'); | ||||
|         yield new Pattern('nexus'); | ||||
|         yield new Pattern('niasese'); | ||||
|         yield new Pattern('nutrition'); | ||||
|         yield new Pattern('offspring'); | ||||
|         yield new Pattern('oil'); | ||||
|         yield new Pattern('patience'); | ||||
|         yield new Pattern('pekingese'); | ||||
|         yield new Pattern('piedmontese'); | ||||
|         yield new Pattern('pincers'); | ||||
|         yield new Pattern('pistoiese'); | ||||
|         yield new Pattern('plankton'); | ||||
|         yield new Pattern('pliers'); | ||||
|         yield new Pattern('pokemon'); | ||||
|         yield new Pattern('police'); | ||||
|         yield new Pattern('polish'); | ||||
|         yield new Pattern('portuguese'); | ||||
|         yield new Pattern('proceedings'); | ||||
|         yield new Pattern('progress'); | ||||
|         yield new Pattern('rabies'); | ||||
|         yield new Pattern('rain'); | ||||
|         yield new Pattern('research'); | ||||
|         yield new Pattern('rhinoceros'); | ||||
|         yield new Pattern('rice'); | ||||
|         yield new Pattern('salmon'); | ||||
|         yield new Pattern('sand'); | ||||
|         yield new Pattern('sarawakese'); | ||||
|         yield new Pattern('scissors'); | ||||
|         yield new Pattern('sea[- ]bass'); | ||||
|         yield new Pattern('series'); | ||||
|         yield new Pattern('shavese'); | ||||
|         yield new Pattern('shears'); | ||||
|         yield new Pattern('sheep'); | ||||
|         yield new Pattern('siemens'); | ||||
|         yield new Pattern('silk'); | ||||
|         yield new Pattern('sms'); | ||||
|         yield new Pattern('soap'); | ||||
|         yield new Pattern('social media'); | ||||
|         yield new Pattern('spam'); | ||||
|         yield new Pattern('species'); | ||||
|         yield new Pattern('staff'); | ||||
|         yield new Pattern('sugar'); | ||||
|         yield new Pattern('swine'); | ||||
|         yield new Pattern('talent'); | ||||
|         yield new Pattern('toothpaste'); | ||||
|         yield new Pattern('traffic'); | ||||
|         yield new Pattern('travel'); | ||||
|         yield new Pattern('trousers'); | ||||
|         yield new Pattern('trout'); | ||||
|         yield new Pattern('tuna'); | ||||
|         yield new Pattern('us'); | ||||
|         yield new Pattern('vermontese'); | ||||
|         yield new Pattern('vinegar'); | ||||
|         yield new Pattern('weather'); | ||||
|         yield new Pattern('wenchowese'); | ||||
|         yield new Pattern('wheat'); | ||||
|         yield new Pattern('whiting'); | ||||
|         yield new Pattern('wildebeest'); | ||||
|         yield new Pattern('wood'); | ||||
|         yield new Pattern('wool'); | ||||
|         yield new Pattern('yengeese'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										50
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\French; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
| use Doctrine\Inflector\Rules\Substitution; | ||||
| use Doctrine\Inflector\Rules\Transformation; | ||||
| use Doctrine\Inflector\Rules\Word; | ||||
|  | ||||
| class Inflectible | ||||
| { | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\1ail'); | ||||
|         yield new Transformation(new Pattern('/ails$/'), 'ail'); | ||||
|         yield new Transformation(new Pattern('/(journ|chev)aux$/'), '\1al'); | ||||
|         yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/'), '\1'); | ||||
|         yield new Transformation(new Pattern('/s$/'), ''); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('/(s|x|z)$/'), '\1'); | ||||
|         yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\1aux'); | ||||
|         yield new Transformation(new Pattern('/ail$/'), 'ails'); | ||||
|         yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\1s'); | ||||
|         yield new Transformation(new Pattern('/al$/'), 'aux'); | ||||
|         yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\1s'); | ||||
|         yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\1x'); | ||||
|         yield new Transformation(new Pattern('/$/'), 's'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Substitution[] | ||||
|      */ | ||||
|     public static function getIrregular(): iterable | ||||
|     { | ||||
|         yield new Substitution(new Word('monsieur'), new Word('messieurs')); | ||||
|         yield new Substitution(new Word('madame'), new Word('mesdames')); | ||||
|         yield new Substitution(new Word('mademoiselle'), new Word('mesdemoiselles')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\French; | ||||
|  | ||||
| use Doctrine\Inflector\GenericLanguageInflectorFactory; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
|  | ||||
| final class InflectorFactory extends GenericLanguageInflectorFactory | ||||
| { | ||||
|     protected function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getSingularRuleset(); | ||||
|     } | ||||
|  | ||||
|     protected function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getPluralRuleset(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\French; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Patterns; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
| use Doctrine\Inflector\Rules\Substitutions; | ||||
| use Doctrine\Inflector\Rules\Transformations; | ||||
|  | ||||
| final class Rules | ||||
| { | ||||
|     public static function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getSingular()), | ||||
|             new Patterns(...Uninflected::getSingular()), | ||||
|             (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getPlural()), | ||||
|             new Patterns(...Uninflected::getPlural()), | ||||
|             new Substitutions(...Inflectible::getIrregular()) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\French; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
|  | ||||
| final class Uninflected | ||||
| { | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     private static function getDefault(): iterable | ||||
|     { | ||||
|         yield new Pattern(''); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										40
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\NorwegianBokmal; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
| use Doctrine\Inflector\Rules\Substitution; | ||||
| use Doctrine\Inflector\Rules\Transformation; | ||||
| use Doctrine\Inflector\Rules\Word; | ||||
|  | ||||
| class Inflectible | ||||
| { | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('/re$/i'), 'r'); | ||||
|         yield new Transformation(new Pattern('/er$/i'), ''); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Transformation[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield new Transformation(new Pattern('/e$/i'), 'er'); | ||||
|         yield new Transformation(new Pattern('/r$/i'), 're'); | ||||
|         yield new Transformation(new Pattern('/$/'), 'er'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Substitution[] | ||||
|      */ | ||||
|     public static function getIrregular(): iterable | ||||
|     { | ||||
|         yield new Substitution(new Word('konto'), new Word('konti')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/InflectorFactory.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\NorwegianBokmal; | ||||
|  | ||||
| use Doctrine\Inflector\GenericLanguageInflectorFactory; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
|  | ||||
| final class InflectorFactory extends GenericLanguageInflectorFactory | ||||
| { | ||||
|     protected function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getSingularRuleset(); | ||||
|     } | ||||
|  | ||||
|     protected function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return Rules::getPluralRuleset(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Rules.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\NorwegianBokmal; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Patterns; | ||||
| use Doctrine\Inflector\Rules\Ruleset; | ||||
| use Doctrine\Inflector\Rules\Substitutions; | ||||
| use Doctrine\Inflector\Rules\Transformations; | ||||
|  | ||||
| final class Rules | ||||
| { | ||||
|     public static function getSingularRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getSingular()), | ||||
|             new Patterns(...Uninflected::getSingular()), | ||||
|             (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public static function getPluralRuleset(): Ruleset | ||||
|     { | ||||
|         return new Ruleset( | ||||
|             new Transformations(...Inflectible::getPlural()), | ||||
|             new Patterns(...Uninflected::getPlural()), | ||||
|             new Substitutions(...Inflectible::getIrregular()) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules\NorwegianBokmal; | ||||
|  | ||||
| use Doctrine\Inflector\Rules\Pattern; | ||||
|  | ||||
| final class Uninflected | ||||
| { | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getSingular(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     public static function getPlural(): iterable | ||||
|     { | ||||
|         yield from self::getDefault(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Pattern[] | ||||
|      */ | ||||
|     private static function getDefault(): iterable | ||||
|     { | ||||
|         yield new Pattern('barn'); | ||||
|         yield new Pattern('fjell'); | ||||
|         yield new Pattern('hus'); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Pattern.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Pattern.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules; | ||||
|  | ||||
| use function preg_match; | ||||
|  | ||||
| final class Pattern | ||||
| { | ||||
|     /** @var string */ | ||||
|     private $pattern; | ||||
|  | ||||
|     /** @var string */ | ||||
|     private $regex; | ||||
|  | ||||
|     public function __construct(string $pattern) | ||||
|     { | ||||
|         $this->pattern = $pattern; | ||||
|  | ||||
|         if (isset($this->pattern[0]) && $this->pattern[0] === '/') { | ||||
|             $this->regex = $this->pattern; | ||||
|         } else { | ||||
|             $this->regex = '/' . $this->pattern . '/i'; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function getPattern(): string | ||||
|     { | ||||
|         return $this->pattern; | ||||
|     } | ||||
|  | ||||
|     public function getRegex(): string | ||||
|     { | ||||
|         return $this->regex; | ||||
|     } | ||||
|  | ||||
|     public function matches(string $word): bool | ||||
|     { | ||||
|         return preg_match($this->getRegex(), $word) === 1; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Doctrine\Inflector\Rules; | ||||
|  | ||||
| use function array_map; | ||||
| use function implode; | ||||
| use function preg_match; | ||||
|  | ||||
| class Patterns | ||||
| { | ||||
|     /** @var Pattern[] */ | ||||
|     private $patterns; | ||||
|  | ||||
|     /** @var string */ | ||||
|     private $regex; | ||||
|  | ||||
|     public function __construct(Pattern ...$patterns) | ||||
|     { | ||||
|         $this->patterns = $patterns; | ||||
|  | ||||
|         $patterns = array_map(static function (Pattern $pattern): string { | ||||
|             return $pattern->getPattern(); | ||||
|         }, $this->patterns); | ||||
|  | ||||
|         $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i'; | ||||
|     } | ||||
|  | ||||
|     public function matches(string $word): bool | ||||
|     { | ||||
|         return preg_match($this->regex, $word, $regs) === 1; | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user