2025.3.11
This commit is contained in:
commit
0b95eb8bf0
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/www.iml" filepath="$PROJECT_DIR$/.idea/www.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
34
.idea/php.xml
generated
Normal file
34
.idea/php.xml
generated
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/webman/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/nikic/fast-route" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/workerman" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/webman-framework" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/coroutine" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.1">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
65
.idea/workspace.xml
generated
Normal file
65
.idea/workspace.xml
generated
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="0ddfa776-bdd1-405a-b4bc-fa2ba24b6076" name="更改" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ComposerSettings" synchronizationState="SYNCHRONIZE">
|
||||
<pharConfigPath>$PROJECT_DIR$/webman/composer.json</pharConfigPath>
|
||||
<execution />
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="D:\apply\phpstudy_pro\Extensions\php\php8.2.9nts\php.exe">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/webman/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/nikic/fast-route" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/workerman" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/webman-framework" />
|
||||
<path value="$PROJECT_DIR$/webman/vendor/workerman/coroutine" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 2
|
||||
}]]></component>
|
||||
<component name="ProjectId" id="2u9XI1wtCPZFlrg7FpxEdZXKEWu" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"last_opened_file_path": "D:/www/webman",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-d6986cc7102b-76f8388c3a79-JavaScript-PS-243.24978.50" />
|
||||
<option value="bundled-php-predefined-a98d8de5180a-fbeb0b58ac0f-com.jetbrains.php.sharedIndexes-PS-243.24978.50" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="默认任务">
|
||||
<changelist id="0ddfa776-bdd1-405a-b4bc-fa2ba24b6076" name="更改" comment="" />
|
||||
<created>1741661680676</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1741661680676</updated>
|
||||
<workItem from="1741661681853" duration="24000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
</project>
|
20
.idea/www.iml
generated
Normal file
20
.idea/www.iml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/." isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/./app" isTestSource="false" packagePrefix="app\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/./app/view/components" isTestSource="false" packagePrefix="app\View\Components\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/monolog/monolog" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/nikic/fast-route" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/psr/log" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/coroutine" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/webman-framework" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/workerman" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
5
composer.json
Normal file
5
composer.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"webman/database": "v2.1.1"
|
||||
}
|
||||
}
|
5
composer.json.txt
Normal file
5
composer.json.txt
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"config": {
|
||||
"disable-tls": false,
|
||||
"secure-http": false}
|
||||
}
|
1813
composer.lock
generated
Normal file
1813
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
vendor/autoload.php
vendored
Normal file
25
vendor/autoload.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitbada8bc7bcb18a93a92df0dd06295584::getLoader();
|
119
vendor/bin/carbon
vendored
Normal file
119
vendor/bin/carbon
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
#!/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_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||
) {
|
||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon');
|
||||
}
|
||||
}
|
||||
|
||||
return 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%" %*
|
479
vendor/brick/math/CHANGELOG.md
vendored
Normal file
479
vendor/brick/math/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,479 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.12.3](https://github.com/brick/math/releases/tag/0.12.3) - 2025-02-28
|
||||
|
||||
✨ **New features**
|
||||
|
||||
- `BigDecimal::getPrecision()` Returns the number of significant digits in a decimal number
|
||||
|
||||
## [0.12.2](https://github.com/brick/math/releases/tag/0.12.2) - 2025-02-26
|
||||
|
||||
⚡️ **Performance improvements**
|
||||
|
||||
- Division in `NativeCalculator` is now faster for small divisors, thanks to [@Izumi-kun](https://github.com/Izumi-kun) in [#87](https://github.com/brick/math/pull/87).
|
||||
|
||||
👌 **Improvements**
|
||||
|
||||
- Add missing `RoundingNecessaryException` to the `@throws` annotation of `BigNumber::of()`
|
||||
|
||||
## [0.12.1](https://github.com/brick/math/releases/tag/0.12.1) - 2023-11-29
|
||||
|
||||
⚡️ **Performance improvements**
|
||||
|
||||
- `BigNumber::of()` is now faster, thanks to [@SebastienDug](https://github.com/SebastienDug) in [#77](https://github.com/brick/math/pull/77).
|
||||
|
||||
## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26
|
||||
|
||||
💥 **Breaking changes**
|
||||
|
||||
- Minimum PHP version is now 8.1
|
||||
- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now
|
||||
- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization))
|
||||
- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses:
|
||||
- the return type of `BigNumber::of()` is now `static`
|
||||
- `BigNumber` has a new abstract method `from()`
|
||||
- all `public` and `protected` functions of `BigNumber` are now `final`
|
||||
|
||||
## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16
|
||||
|
||||
💥 **Breaking changes**
|
||||
|
||||
- Minimum PHP version is now 8.0
|
||||
- Methods accepting a union of types are now strongly typed<sup>*</sup>
|
||||
- `MathException` now extends `Exception` instead of `RuntimeException`
|
||||
|
||||
<sup>* You may now run into type errors if you were passing `Stringable` objects to `of()` or any of the methods
|
||||
internally calling `of()`, with `strict_types` enabled. You can fix this by casting `Stringable` objects to `string`
|
||||
first.</sup>
|
||||
|
||||
## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11
|
||||
|
||||
👌 **Improvements**
|
||||
|
||||
- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic
|
||||
|
||||
## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02
|
||||
|
||||
✨ **New features**
|
||||
|
||||
- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers
|
||||
|
||||
## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18
|
||||
|
||||
💥 **Breaking changes**
|
||||
|
||||
- Minimum PHP version is now 7.4
|
||||
|
||||
## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15
|
||||
|
||||
🚀 **Compatibility with PHP 8.1**
|
||||
|
||||
- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (#60) 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 anymore
|
||||
- `toBigRational()` does not simplify the fraction anymore; 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` anymore, 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.
|
39
vendor/brick/math/composer.json
vendored
Normal file
39
vendor/brick/math/composer.json
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "brick/math",
|
||||
"description": "Arbitrary-precision arithmetic library",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"Brick",
|
||||
"Math",
|
||||
"Mathematics",
|
||||
"Arbitrary-precision",
|
||||
"Arithmetic",
|
||||
"BigInteger",
|
||||
"BigDecimal",
|
||||
"BigRational",
|
||||
"BigNumber",
|
||||
"Bignum",
|
||||
"Decimal",
|
||||
"Rational",
|
||||
"Integer"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.1",
|
||||
"php-coveralls/php-coveralls": "^2.2",
|
||||
"vimeo/psalm": "6.8.8"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Brick\\Math\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Brick\\Math\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
70
vendor/brick/math/psalm-baseline.xml
vendored
Normal file
70
vendor/brick/math/psalm-baseline.xml
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="6.8.8@1361cd33008feb3ae2b4a93f1860e14e538ec8c2">
|
||||
<file src="src/BigInteger.php">
|
||||
<FalsableReturnStatement>
|
||||
<code><![CDATA[\hex2bin($hex)]]></code>
|
||||
</FalsableReturnStatement>
|
||||
<InvalidFalsableReturnType>
|
||||
<code><![CDATA[string]]></code>
|
||||
</InvalidFalsableReturnType>
|
||||
</file>
|
||||
<file src="src/Exception/DivisionByZeroException.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[DivisionByZeroException]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Exception/IntegerOverflowException.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[IntegerOverflowException]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Exception/NegativeNumberException.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[NegativeNumberException]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Exception/NumberFormatException.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[NumberFormatException]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Exception/RoundingNecessaryException.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[RoundingNecessaryException]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Internal/Calculator/BcMathCalculator.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[BcMathCalculator]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Internal/Calculator/GmpCalculator.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[GmpCalculator]]></code>
|
||||
</ClassMustBeFinal>
|
||||
</file>
|
||||
<file src="src/Internal/Calculator/NativeCalculator.php">
|
||||
<ClassMustBeFinal>
|
||||
<code><![CDATA[NativeCalculator]]></code>
|
||||
</ClassMustBeFinal>
|
||||
<InvalidOperand>
|
||||
<code><![CDATA[$a * $b]]></code>
|
||||
<code><![CDATA[$a * 1]]></code>
|
||||
<code><![CDATA[$a + $b]]></code>
|
||||
<code><![CDATA[$b * 1]]></code>
|
||||
<code><![CDATA[$b * 1]]></code>
|
||||
<code><![CDATA[$blockA * $blockB + $carry]]></code>
|
||||
<code><![CDATA[$blockA + $blockB]]></code>
|
||||
<code><![CDATA[$blockA + $blockB + $carry]]></code>
|
||||
<code><![CDATA[$blockA - $blockB]]></code>
|
||||
<code><![CDATA[$blockA - $blockB - $carry]]></code>
|
||||
<code><![CDATA[$carry]]></code>
|
||||
<code><![CDATA[$mul % $complement]]></code>
|
||||
<code><![CDATA[$mul - $value]]></code>
|
||||
<code><![CDATA[$nb - 1]]></code>
|
||||
<code><![CDATA[$sum += $complement]]></code>
|
||||
<code><![CDATA[($mul - $value) / $complement]]></code>
|
||||
<code><![CDATA[($nb - 1) * 10]]></code>
|
||||
</InvalidOperand>
|
||||
</file>
|
||||
</files>
|
792
vendor/brick/math/src/BigDecimal.php
vendored
Normal file
792
vendor/brick/math/src/BigDecimal.php
vendored
Normal file
@ -0,0 +1,792 @@
|
||||
<?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;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private readonly string $value;
|
||||
|
||||
/**
|
||||
* The scale (number of digits after the decimal point) of this decimal number.
|
||||
*
|
||||
* This must be zero or more.
|
||||
*/
|
||||
private readonly int $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
#[Override]
|
||||
protected static function from(BigNumber $number): static
|
||||
{
|
||||
return $number->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.
|
||||
*
|
||||
* @throws \InvalidArgumentException If the scale is negative.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function ofUnscaledValue(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
||||
*/
|
||||
public function plus(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
||||
*/
|
||||
public function minus(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.
|
||||
*/
|
||||
public function multipliedBy(BigNumber|int|float|string $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 RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
||||
*
|
||||
* @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(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $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.
|
||||
*
|
||||
* @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(BigNumber|int|float|string $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`.
|
||||
*
|
||||
* @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 the given one.
|
||||
*
|
||||
* The quotient has a scale of `0`.
|
||||
*
|
||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||
*/
|
||||
public function quotient(BigNumber|int|float|string $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 the 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.
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||
*/
|
||||
public function remainder(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @psalm-return array{BigDecimal, BigDecimal}
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
||||
*/
|
||||
public function quotientAndRemainder(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public function abs() : BigDecimal
|
||||
{
|
||||
return $this->isNegative() ? $this->negated() : $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negated value of this number.
|
||||
*/
|
||||
public function negated() : BigDecimal
|
||||
{
|
||||
return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function compareTo(BigNumber|int|float|string $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);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getSign() : int
|
||||
{
|
||||
return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
|
||||
}
|
||||
|
||||
public function getUnscaledValue() : BigInteger
|
||||
{
|
||||
return self::newBigInteger($this->value);
|
||||
}
|
||||
|
||||
public function getScale() : int
|
||||
{
|
||||
return $this->scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of significant digits in the number.
|
||||
*
|
||||
* This is the number of digits to both sides of the decimal point, stripped of leading zeros.
|
||||
* The sign has no impact on the result.
|
||||
*
|
||||
* Examples:
|
||||
* 0 => 0
|
||||
* 0.0 => 0
|
||||
* 123 => 3
|
||||
* 123.456 => 6
|
||||
* 0.00123 => 3
|
||||
* 0.0012300 => 5
|
||||
*/
|
||||
public function getPrecision(): int
|
||||
{
|
||||
$value = $this->value;
|
||||
|
||||
if ($value === '0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$length = \strlen($value);
|
||||
|
||||
return ($value[0] === '-') ? $length - 1 : $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the integral part of this decimal number.
|
||||
*
|
||||
* Example: `-123.456` => `-123`.
|
||||
*/
|
||||
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` => ''.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public function hasNonZeroFractionalPart() : bool
|
||||
{
|
||||
return $this->getFractionalPart() !== \str_repeat('0', $this->scale);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBigInteger() : BigInteger
|
||||
{
|
||||
$zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);
|
||||
|
||||
return self::newBigInteger($zeroScaleDecimal->value);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBigDecimal() : BigDecimal
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBigRational() : BigRational
|
||||
{
|
||||
$numerator = self::newBigInteger($this->value);
|
||||
$denominator = self::newBigInteger('1' . \str_repeat('0', $this->scale));
|
||||
|
||||
return self::newBigRational($numerator, $denominator, false);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
if ($scale === $this->scale) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toInt() : int
|
||||
{
|
||||
return $this->toBigInteger()->toInt();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toFloat() : float
|
||||
{
|
||||
return (float) (string) $this;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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
|
||||
*
|
||||
* @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'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the internal values of the given decimal numbers on the same scale.
|
||||
*
|
||||
* @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];
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
1062
vendor/brick/math/src/BigInteger.php
vendored
Normal file
1062
vendor/brick/math/src/BigInteger.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
515
vendor/brick/math/src/BigNumber.php
vendored
Normal file
515
vendor/brick/math/src/BigNumber.php
vendored
Normal file
@ -0,0 +1,515 @@
|
||||
<?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;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Common interface for arbitrary-precision rational numbers.
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
abstract class BigNumber implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* The regular expression used to parse integer or decimal numbers.
|
||||
*/
|
||||
private const PARSE_REGEXP_NUMERICAL =
|
||||
'/^' .
|
||||
'(?<sign>[\-\+])?' .
|
||||
'(?<integral>[0-9]+)?' .
|
||||
'(?<point>\.)?' .
|
||||
'(?<fractional>[0-9]+)?' .
|
||||
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
|
||||
'$/';
|
||||
|
||||
/**
|
||||
* The regular expression used to parse rational numbers.
|
||||
*/
|
||||
private const PARSE_REGEXP_RATIONAL =
|
||||
'/^' .
|
||||
'(?<sign>[\-\+])?' .
|
||||
'(?<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
|
||||
*
|
||||
* @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.
|
||||
* @throws RoundingNecessaryException If the value cannot be converted to an instance of the subclass without rounding.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
final public static function of(BigNumber|int|float|string $value) : static
|
||||
{
|
||||
$value = self::_of($value);
|
||||
|
||||
if (static::class === BigNumber::class) {
|
||||
// https://github.com/vimeo/psalm/issues/10309
|
||||
assert($value instanceof static);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
return static::from($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
private static function _of(BigNumber|int|float|string $value) : BigNumber
|
||||
{
|
||||
if ($value instanceof BigNumber) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (\is_int($value)) {
|
||||
return new BigInteger((string) $value);
|
||||
}
|
||||
|
||||
if (is_float($value)) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
if (str_contains($value, '/')) {
|
||||
// Rational number
|
||||
if (\preg_match(self::PARSE_REGEXP_RATIONAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
$sign = $matches['sign'];
|
||||
$numerator = $matches['numerator'];
|
||||
$denominator = $matches['denominator'];
|
||||
|
||||
assert($numerator !== null);
|
||||
assert($denominator !== null);
|
||||
|
||||
$numerator = self::cleanUp($sign, $numerator);
|
||||
$denominator = self::cleanUp(null, $denominator);
|
||||
|
||||
if ($denominator === '0') {
|
||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||
}
|
||||
|
||||
return new BigRational(
|
||||
new BigInteger($numerator),
|
||||
new BigInteger($denominator),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
// Integer or decimal number
|
||||
if (\preg_match(self::PARSE_REGEXP_NUMERICAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
$sign = $matches['sign'];
|
||||
$point = $matches['point'];
|
||||
$integral = $matches['integral'];
|
||||
$fractional = $matches['fractional'];
|
||||
$exponent = $matches['exponent'];
|
||||
|
||||
if ($integral === null && $fractional === null) {
|
||||
throw NumberFormatException::invalidFormat($value);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by subclasses to convert a BigNumber to an instance of the subclass.
|
||||
*
|
||||
* @throws RoundingNecessaryException If the value cannot be converted.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
abstract protected static function from(BigNumber $number): static;
|
||||
|
||||
/**
|
||||
* Proxy method to access BigInteger's protected constructor from sibling classes.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
final protected function newBigInteger(string $value) : BigInteger
|
||||
{
|
||||
return new BigInteger($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method to access BigDecimal's protected constructor from sibling classes.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal
|
||||
{
|
||||
return new BigDecimal($value, $scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy method to access BigRational's protected constructor from sibling classes.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-pure
|
||||
*/
|
||||
final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational
|
||||
{
|
||||
return new BigRational($numerator, $denominator, $checkDenominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @throws \InvalidArgumentException If no values are given.
|
||||
* @throws MathException If an argument is not valid.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
final public static function min(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
$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.
|
||||
*
|
||||
* @throws \InvalidArgumentException If no values are given.
|
||||
* @throws MathException If an argument is not valid.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
final public static function max(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
$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.
|
||||
*
|
||||
* @throws \InvalidArgumentException If no values are given.
|
||||
* @throws MathException If an argument is not valid.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
final public static function sum(BigNumber|int|float|string ...$values) : static
|
||||
{
|
||||
/** @var static|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...)
|
||||
*
|
||||
* @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 applies sign.
|
||||
*
|
||||
* @param string|null $sign The sign, '+' or '-', optional. Null is allowed for convenience and treated as '+'.
|
||||
* @param string $number The number, validated as a non-empty string of digits.
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
private static function cleanUp(string|null $sign, string $number) : string
|
||||
{
|
||||
$number = \ltrim($number, '0');
|
||||
|
||||
if ($number === '') {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return $sign === '-' ? '-' . $number : $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is equal to the given one.
|
||||
*/
|
||||
final public function isEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is strictly lower than the given one.
|
||||
*/
|
||||
final public function isLessThan(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is lower than or equal to the given one.
|
||||
*/
|
||||
final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is strictly greater than the given one.
|
||||
*/
|
||||
final public function isGreaterThan(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is greater than or equal to the given one.
|
||||
*/
|
||||
final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
||||
{
|
||||
return $this->compareTo($that) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number equals zero.
|
||||
*/
|
||||
final public function isZero() : bool
|
||||
{
|
||||
return $this->getSign() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is strictly negative.
|
||||
*/
|
||||
final public function isNegative() : bool
|
||||
{
|
||||
return $this->getSign() < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is negative or zero.
|
||||
*/
|
||||
final public function isNegativeOrZero() : bool
|
||||
{
|
||||
return $this->getSign() <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is strictly positive.
|
||||
*/
|
||||
final public function isPositive() : bool
|
||||
{
|
||||
return $this->getSign() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this number is positive or zero.
|
||||
*/
|
||||
final public function isPositiveOrZero() : bool
|
||||
{
|
||||
return $this->getSign() >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sign of this number.
|
||||
*
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`.
|
||||
*
|
||||
* @throws MathException If the number is not valid.
|
||||
*/
|
||||
abstract public function compareTo(BigNumber|int|float|string $that) : int;
|
||||
|
||||
/**
|
||||
* Converts this number to a BigInteger.
|
||||
*
|
||||
* @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
|
||||
*/
|
||||
abstract public function toBigInteger() : BigInteger;
|
||||
|
||||
/**
|
||||
* Converts this number to a BigDecimal.
|
||||
*
|
||||
* @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
|
||||
*/
|
||||
abstract public function toBigDecimal() : BigDecimal;
|
||||
|
||||
/**
|
||||
* Converts this number to a BigRational.
|
||||
*/
|
||||
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 RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
||||
*
|
||||
* @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, RoundingMode $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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
abstract public function __toString() : string;
|
||||
|
||||
#[Override]
|
||||
final public function jsonSerialize() : string
|
||||
{
|
||||
return $this->__toString();
|
||||
}
|
||||
}
|
424
vendor/brick/math/src/BigRational.php
vendored
Normal file
424
vendor/brick/math/src/BigRational.php
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
<?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;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* An arbitrarily large rational number.
|
||||
*
|
||||
* This class is immutable.
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class BigRational extends BigNumber
|
||||
{
|
||||
/**
|
||||
* The numerator.
|
||||
*/
|
||||
private readonly BigInteger $numerator;
|
||||
|
||||
/**
|
||||
* The denominator. Always strictly positive.
|
||||
*/
|
||||
private readonly BigInteger $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
#[Override]
|
||||
protected static function from(BigNumber $number): static
|
||||
{
|
||||
return $number->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.
|
||||
*
|
||||
* @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(
|
||||
BigNumber|int|float|string $numerator,
|
||||
BigNumber|int|float|string $denominator,
|
||||
) : BigRational {
|
||||
$numerator = BigInteger::of($numerator);
|
||||
$denominator = BigInteger::of($denominator);
|
||||
|
||||
return new BigRational($numerator, $denominator, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BigRational representing zero.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
public function getNumerator() : BigInteger
|
||||
{
|
||||
return $this->numerator;
|
||||
}
|
||||
|
||||
public function getDenominator() : BigInteger
|
||||
{
|
||||
return $this->denominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quotient of the division of the numerator by the denominator.
|
||||
*/
|
||||
public function quotient() : BigInteger
|
||||
{
|
||||
return $this->numerator->quotient($this->denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remainder of the division of the numerator by the denominator.
|
||||
*/
|
||||
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[]
|
||||
*
|
||||
* @psalm-return array{BigInteger, 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.
|
||||
*
|
||||
* @throws MathException If the number is not valid.
|
||||
*/
|
||||
public function plus(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @throws MathException If the number is not valid.
|
||||
*/
|
||||
public function minus(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @throws MathException If the multiplier is not a valid number.
|
||||
*/
|
||||
public function multipliedBy(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @throws MathException If the divisor is not a valid number, or is zero.
|
||||
*/
|
||||
public function dividedBy(BigNumber|int|float|string $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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function abs() : BigRational
|
||||
{
|
||||
return new BigRational($this->numerator->abs(), $this->denominator, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negated value of this BigRational.
|
||||
*/
|
||||
public function negated() : BigRational
|
||||
{
|
||||
return new BigRational($this->numerator->negated(), $this->denominator, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the simplified value of this 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);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function compareTo(BigNumber|int|float|string $that) : int
|
||||
{
|
||||
return $this->minus($that)->getSign();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getSign() : int
|
||||
{
|
||||
return $this->numerator->getSign();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBigDecimal() : BigDecimal
|
||||
{
|
||||
return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBigRational() : BigRational
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
||||
{
|
||||
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toInt() : int
|
||||
{
|
||||
return $this->toBigInteger()->toInt();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toFloat() : float
|
||||
{
|
||||
$simplified = $this->simplified();
|
||||
return $simplified->numerator->toFloat() / $simplified->denominator->toFloat();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function __toString() : string
|
||||
{
|
||||
$numerator = (string) $this->numerator;
|
||||
$denominator = (string) $this->denominator;
|
||||
|
||||
if ($denominator === '1') {
|
||||
return $numerator;
|
||||
}
|
||||
|
||||
return $numerator . '/' . $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
|
||||
*
|
||||
* @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'];
|
||||
}
|
||||
}
|
35
vendor/brick/math/src/Exception/DivisionByZeroException.php
vendored
Normal file
35
vendor/brick/math/src/Exception/DivisionByZeroException.php
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Exception;
|
||||
|
||||
/**
|
||||
* Exception thrown when a division by zero occurs.
|
||||
*/
|
||||
class DivisionByZeroException extends MathException
|
||||
{
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function divisionByZero() : DivisionByZeroException
|
||||
{
|
||||
return new self('Division by zero.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function modulusMustNotBeZero() : DivisionByZeroException
|
||||
{
|
||||
return new self('The modulus must not be zero.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function denominatorMustNotBeZero() : DivisionByZeroException
|
||||
{
|
||||
return new self('The denominator of a rational number cannot be zero.');
|
||||
}
|
||||
}
|
23
vendor/brick/math/src/Exception/IntegerOverflowException.php
vendored
Normal file
23
vendor/brick/math/src/Exception/IntegerOverflowException.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Exception;
|
||||
|
||||
use Brick\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Exception thrown when an integer overflow occurs.
|
||||
*/
|
||||
class IntegerOverflowException extends MathException
|
||||
{
|
||||
/**
|
||||
* @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));
|
||||
}
|
||||
}
|
12
vendor/brick/math/src/Exception/MathException.php
vendored
Normal file
12
vendor/brick/math/src/Exception/MathException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Exception;
|
||||
|
||||
/**
|
||||
* Base class for all math exceptions.
|
||||
*/
|
||||
class MathException extends \Exception
|
||||
{
|
||||
}
|
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
|
||||
{
|
||||
}
|
41
vendor/brick/math/src/Exception/NumberFormatException.php
vendored
Normal file
41
vendor/brick/math/src/Exception/NumberFormatException.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?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
|
||||
{
|
||||
public static function invalidFormat(string $value) : self
|
||||
{
|
||||
return new self(\sprintf(
|
||||
'The given value "%s" does not represent a valid number.',
|
||||
$value,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $char The failing character.
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
}
|
19
vendor/brick/math/src/Exception/RoundingNecessaryException.php
vendored
Normal file
19
vendor/brick/math/src/Exception/RoundingNecessaryException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @psalm-pure
|
||||
*/
|
||||
public static function roundingNecessary() : RoundingNecessaryException
|
||||
{
|
||||
return new self('Rounding is necessary to represent the result of the operation at this scale.');
|
||||
}
|
||||
}
|
668
vendor/brick/math/src/Internal/Calculator.php
vendored
Normal file
668
vendor/brick/math/src/Internal/Calculator.php
vendored
Normal file
@ -0,0 +1,668 @@
|
||||
<?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 = 1_000_000;
|
||||
|
||||
/**
|
||||
* The alphabet for converting from and to base 2 to 36, lowercase.
|
||||
*/
|
||||
public const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
/**
|
||||
* The Calculator instance in use.
|
||||
*/
|
||||
private static ?Calculator $instance = null;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
final public function abs(string $n) : string
|
||||
{
|
||||
return ($n[0] === '-') ? \substr($n, 1) : $n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates a number.
|
||||
*/
|
||||
final public function neg(string $n) : string
|
||||
{
|
||||
if ($n === '0') {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if ($n[0] === '-') {
|
||||
return \substr($n, 1);
|
||||
}
|
||||
|
||||
return '-' . $n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* @psalm-return -1|0|1
|
||||
*
|
||||
* @return int -1 if the first number is less than, 0 if equal to, 1 if 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.
|
||||
*/
|
||||
abstract public function add(string $a, string $b) : string;
|
||||
|
||||
/**
|
||||
* Subtracts two numbers.
|
||||
*/
|
||||
abstract public function sub(string $a, string $b) : string;
|
||||
|
||||
/**
|
||||
* Multiplies two numbers.
|
||||
*/
|
||||
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 array{string, 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 $b The modulus; must not be zero.
|
||||
*/
|
||||
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 $m The modulus; must not be negative or zero.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
[$g, $x] = $this->gcdExtended($modVal, $m);
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{string, string, string} GCD, X, Y
|
||||
*/
|
||||
private function gcdExtended(string $a, string $b) : array
|
||||
{
|
||||
if ($a === '0') {
|
||||
return [$b, '0', '1'];
|
||||
}
|
||||
|
||||
[$gcd, $x1, $y1] = $this->gcdExtended($this->mod($b, $a), $a);
|
||||
|
||||
$x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
|
||||
$y = $x1;
|
||||
|
||||
return [$gcd, $x, $y];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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 RoundingMode $roundingMode The rounding mode.
|
||||
*
|
||||
* @throws \InvalidArgumentException If the rounding mode is invalid.
|
||||
* @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
|
||||
*
|
||||
* @psalm-suppress ImpureFunctionCall
|
||||
*/
|
||||
final public function divRound(string $a, string $b, RoundingMode $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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public function xor(string $a, string $b) : string
|
||||
{
|
||||
return $this->bitwise('xor', $a, $b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a bitwise operation on a decimal number.
|
||||
*
|
||||
* @param 'and'|'or'|'xor' $operator The operator to use.
|
||||
* @param string $a The left operand.
|
||||
* @param string $b The right operand.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
$value = match ($operator) {
|
||||
'and' => $aBin & $bBin,
|
||||
'or' => $aBin | $bBin,
|
||||
'xor' => $aBin ^ $bBin,
|
||||
};
|
||||
|
||||
$negative = match ($operator) {
|
||||
'and' => $aNeg and $bNeg,
|
||||
'or' => $aNeg or $bNeg,
|
||||
'xor' => $aNeg xor $bNeg,
|
||||
};
|
||||
|
||||
if ($negative) {
|
||||
$value = $this->twosComplement($value);
|
||||
}
|
||||
|
||||
$result = $this->toDecimal($value);
|
||||
|
||||
return $negative ? $this->neg($result) : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $number A positive, binary number.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
75
vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
vendored
Normal file
75
vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Internal\Calculator;
|
||||
|
||||
use Brick\Math\Internal\Calculator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Calculator implementation built around the bcmath library.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
class BcMathCalculator extends Calculator
|
||||
{
|
||||
#[Override]
|
||||
public function add(string $a, string $b) : string
|
||||
{
|
||||
return \bcadd($a, $b, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function sub(string $a, string $b) : string
|
||||
{
|
||||
return \bcsub($a, $b, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function mul(string $a, string $b) : string
|
||||
{
|
||||
return \bcmul($a, $b, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divQ(string $a, string $b) : string
|
||||
{
|
||||
return \bcdiv($a, $b, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divR(string $a, string $b) : string
|
||||
{
|
||||
return \bcmod($a, $b, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divQR(string $a, string $b) : array
|
||||
{
|
||||
$q = \bcdiv($a, $b, 0);
|
||||
$r = \bcmod($a, $b, 0);
|
||||
|
||||
return [$q, $r];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function pow(string $a, int $e) : string
|
||||
{
|
||||
return \bcpow($a, (string) $e, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function modPow(string $base, string $exp, string $mod) : string
|
||||
{
|
||||
return \bcpowmod($base, $exp, $mod, 0);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function sqrt(string $n) : string
|
||||
{
|
||||
return \bcsqrt($n, 0);
|
||||
}
|
||||
}
|
125
vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
vendored
Normal file
125
vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Internal\Calculator;
|
||||
|
||||
use Brick\Math\Internal\Calculator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Calculator implementation built around the GMP library.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @psalm-immutable
|
||||
*/
|
||||
class GmpCalculator extends Calculator
|
||||
{
|
||||
#[Override]
|
||||
public function add(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_add($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function sub(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_sub($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function mul(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_mul($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divQ(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_div_q($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divR(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_div_r($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divQR(string $a, string $b) : array
|
||||
{
|
||||
[$q, $r] = \gmp_div_qr($a, $b);
|
||||
|
||||
return [
|
||||
\gmp_strval($q),
|
||||
\gmp_strval($r)
|
||||
];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function pow(string $a, int $e) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_pow($a, $e));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function modInverse(string $x, string $m) : ?string
|
||||
{
|
||||
$result = \gmp_invert($x, $m);
|
||||
|
||||
if ($result === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return \gmp_strval($result);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function modPow(string $base, string $exp, string $mod) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_powm($base, $exp, $mod));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function gcd(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_gcd($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function fromBase(string $number, int $base) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_init($number, $base));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function toBase(string $number, int $base) : string
|
||||
{
|
||||
return \gmp_strval($number, $base);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function and(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_and($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function or(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_or($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function xor(string $a, string $b) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_xor($a, $b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function sqrt(string $n) : string
|
||||
{
|
||||
return \gmp_strval(\gmp_sqrt($n));
|
||||
}
|
||||
}
|
598
vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
vendored
Normal file
598
vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
vendored
Normal file
@ -0,0 +1,598 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Brick\Math\Internal\Calculator;
|
||||
|
||||
use Brick\Math\Internal\Calculator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* In 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)
|
||||
*/
|
||||
private readonly int $maxDigits;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->maxDigits = match (PHP_INT_SIZE) {
|
||||
4 => 9,
|
||||
8 => 18,
|
||||
default => throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.')
|
||||
};
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function sub(string $a, string $b) : string
|
||||
{
|
||||
return $this->add($a, $this->neg($b));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divQ(string $a, string $b) : string
|
||||
{
|
||||
return $this->divQR($a, $b)[0];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function divR(string $a, string $b): string
|
||||
{
|
||||
return $this->divQR($a, $b)[1];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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.
|
||||
$q = intdiv($na, $nb);
|
||||
$r = $na % $nb;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
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/
|
||||
*/
|
||||
#[Override]
|
||||
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
|
||||
*/
|
||||
#[Override]
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
|
||||
/** @psalm-var numeric-string $b */
|
||||
$nb = $b * 1; // cast to number
|
||||
// performance optimization in cases where the remainder will never cause int overflow
|
||||
if (is_int(($nb - 1) * 10 + 9)) {
|
||||
$r = (int) \substr($a, 0, $z - 1);
|
||||
|
||||
for ($i = $z - 1; $i < $x; $i++) {
|
||||
$n = $r * 10 + (int) $a[$i];
|
||||
/** @psalm-var int $nb */
|
||||
$q .= \intdiv($n, $nb);
|
||||
$r = $n % $nb;
|
||||
}
|
||||
|
||||
return [\ltrim($q, '0') ?: '0', (string) $r];
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @psalm-return -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.
|
||||
*
|
||||
* @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];
|
||||
}
|
||||
}
|
98
vendor/brick/math/src/RoundingMode.php
vendored
Normal file
98
vendor/brick/math/src/RoundingMode.php
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?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.
|
||||
*/
|
||||
enum RoundingMode
|
||||
{
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case UNNECESSARY;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case UP;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case DOWN;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case CEILING;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case FLOOR;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case HALF_UP;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case HALF_DOWN;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case HALF_CEILING;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case HALF_FLOOR;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
case HALF_EVEN;
|
||||
}
|
21
vendor/carbonphp/carbon-doctrine-types/LICENSE
vendored
Normal file
21
vendor/carbonphp/carbon-doctrine-types/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Carbon
|
||||
|
||||
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.
|
14
vendor/carbonphp/carbon-doctrine-types/README.md
vendored
Normal file
14
vendor/carbonphp/carbon-doctrine-types/README.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# carbonphp/carbon-doctrine-types
|
||||
|
||||
Types to use Carbon in Doctrine
|
||||
|
||||
## Documentation
|
||||
|
||||
[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/symfony/)
|
||||
|
||||
This package is an externalization of [src/Carbon/Doctrine](https://github.com/briannesbitt/Carbon/tree/2.71.0/src/Carbon/Doctrine)
|
||||
from `nestbot/carbon` package.
|
||||
|
||||
Externalization allows to better deal with different versions of dbal. With
|
||||
version 4.0 of dbal, it no longer sustainable to be compatible with all version
|
||||
using a single code.
|
36
vendor/carbonphp/carbon-doctrine-types/composer.json
vendored
Normal file
36
vendor/carbonphp/carbon-doctrine-types/composer.json
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
"description": "Types to use Carbon in Doctrine",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"date",
|
||||
"time",
|
||||
"DateTime",
|
||||
"Carbon",
|
||||
"Doctrine"
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^4.0.0",
|
||||
"nesbot/carbon": "^2.71.0 || ^3.0.0",
|
||||
"phpunit/phpunit": "^10.3"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/dbal": "<4.0.0 || >=5.0.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "KyleKatarn",
|
||||
"email": "kylekatarnls@gmail.com"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev"
|
||||
}
|
16
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php
vendored
Normal file
16
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
|
||||
interface CarbonDoctrineType
|
||||
{
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);
|
||||
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform);
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform);
|
||||
}
|
9
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonImmutableType.php
vendored
Normal file
9
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonImmutableType.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType
|
||||
{
|
||||
}
|
9
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonType.php
vendored
Normal file
9
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonType.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
class CarbonType extends DateTimeType implements CarbonDoctrineType
|
||||
{
|
||||
}
|
131
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonTypeConverter.php
vendored
Normal file
131
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonTypeConverter.php
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonInterface;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Platforms\DB2Platform;
|
||||
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||
use Doctrine\DBAL\Platforms\SQLitePlatform;
|
||||
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||
use Doctrine\DBAL\Types\Exception\InvalidType;
|
||||
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @template T of CarbonInterface
|
||||
*/
|
||||
trait CarbonTypeConverter
|
||||
{
|
||||
/**
|
||||
* This property differentiates types installed by carbonphp/carbon-doctrine-types
|
||||
* from the ones embedded previously in nesbot/carbon source directly.
|
||||
*
|
||||
* @readonly
|
||||
*/
|
||||
public bool $external = true;
|
||||
|
||||
/**
|
||||
* @return class-string<T>
|
||||
*/
|
||||
protected function getCarbonClassName(): string
|
||||
{
|
||||
return Carbon::class;
|
||||
}
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
|
||||
{
|
||||
$precision = min(
|
||||
$fieldDeclaration['precision'] ?? DateTimeDefaultPrecision::get(),
|
||||
$this->getMaximumPrecision($platform),
|
||||
);
|
||||
|
||||
$type = parent::getSQLDeclaration($fieldDeclaration, $platform);
|
||||
|
||||
if (!$precision) {
|
||||
return $type;
|
||||
}
|
||||
|
||||
if (str_contains($type, '(')) {
|
||||
return preg_replace('/\(\d+\)/', "($precision)", $type);
|
||||
}
|
||||
|
||||
[$before, $after] = explode(' ', "$type ");
|
||||
|
||||
return trim("$before($precision) $after");
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
|
||||
{
|
||||
if ($value === null) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
return $value->format('Y-m-d H:i:s.u');
|
||||
}
|
||||
|
||||
throw InvalidType::new(
|
||||
$value,
|
||||
static::class,
|
||||
['null', 'DateTime', 'Carbon']
|
||||
);
|
||||
}
|
||||
|
||||
private function doConvertToPHPValue(mixed $value)
|
||||
{
|
||||
$class = $this->getCarbonClassName();
|
||||
|
||||
if ($value === null || is_a($value, $class)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
return $class::instance($value);
|
||||
}
|
||||
|
||||
$date = null;
|
||||
$error = null;
|
||||
|
||||
try {
|
||||
$date = $class::parse($value);
|
||||
} catch (Exception $exception) {
|
||||
$error = $exception;
|
||||
}
|
||||
|
||||
if (!$date) {
|
||||
throw ValueNotConvertible::new(
|
||||
$value,
|
||||
static::class,
|
||||
'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',
|
||||
$error
|
||||
);
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
private function getMaximumPrecision(AbstractPlatform $platform): int
|
||||
{
|
||||
if ($platform instanceof DB2Platform) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
if ($platform instanceof OraclePlatform) {
|
||||
return 9;
|
||||
}
|
||||
|
||||
if ($platform instanceof SQLServerPlatform || $platform instanceof SQLitePlatform) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
}
|
30
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php
vendored
Normal file
30
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
class DateTimeDefaultPrecision
|
||||
{
|
||||
private static $precision = 6;
|
||||
|
||||
/**
|
||||
* Change the default Doctrine datetime and datetime_immutable precision.
|
||||
*
|
||||
* @param int $precision
|
||||
*/
|
||||
public static function set(int $precision): void
|
||||
{
|
||||
self::$precision = $precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default Doctrine datetime and datetime_immutable precision.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get(): int
|
||||
{
|
||||
return self::$precision;
|
||||
}
|
||||
}
|
32
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeImmutableType.php
vendored
Normal file
32
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeImmutableType.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\VarDateTimeImmutableType;
|
||||
|
||||
class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType
|
||||
{
|
||||
/** @use CarbonTypeConverter<CarbonImmutable> */
|
||||
use CarbonTypeConverter;
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*/
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonImmutable
|
||||
{
|
||||
return $this->doConvertToPHPValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<CarbonImmutable>
|
||||
*/
|
||||
protected function getCarbonClassName(): string
|
||||
{
|
||||
return CarbonImmutable::class;
|
||||
}
|
||||
}
|
24
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php
vendored
Normal file
24
vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Carbon\Doctrine;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\VarDateTimeType;
|
||||
|
||||
class DateTimeType extends VarDateTimeType implements CarbonDoctrineType
|
||||
{
|
||||
/** @use CarbonTypeConverter<Carbon> */
|
||||
use CarbonTypeConverter;
|
||||
|
||||
/**
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*/
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Carbon
|
||||
{
|
||||
return $this->doConvertToPHPValue($value);
|
||||
}
|
||||
}
|
579
vendor/composer/ClassLoader.php
vendored
Normal file
579
vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
||||
<?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\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<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)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<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)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, 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
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
378
vendor/composer/InstalledVersions.php
vendored
Normal file
378
vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,378 @@
|
||||
<?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`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: 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 || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
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((string) $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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: 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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: 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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = strtr(__DIR__, '\\', '/');
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
21
vendor/composer/LICENSE
vendored
Normal file
21
vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
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.
|
||||
|
21
vendor/composer/autoload_classmap.php
vendored
Normal file
21
vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
|
||||
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
|
||||
'DateInvalidOperationException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
|
||||
'DateInvalidTimeZoneException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
|
||||
'DateMalformedIntervalStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
|
||||
'DateMalformedPeriodStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
|
||||
'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
|
||||
'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
|
||||
'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
|
||||
'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
|
||||
'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
|
||||
);
|
20
vendor/composer/autoload_files.php
vendored
Normal file
20
vendor/composer/autoload_files.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'23f09fe3194f8c2f70923f90d6702129' => $vendorDir . '/illuminate/collections/functions.php',
|
||||
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
||||
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
|
||||
'2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
|
||||
'f625ee536139dfb962a398b200bdb2bd' => $vendorDir . '/illuminate/support/functions.php',
|
||||
'72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
|
||||
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
|
||||
'd2136ff22b54ac75cd96a40e0022218e' => $vendorDir . '/workerman/webman-framework/src/support/helpers.php',
|
||||
);
|
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
38
vendor/composer/autoload_psr4.php
vendored
Normal file
38
vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
|
||||
'support\\' => array($vendorDir . '/webman/database/src/support', $vendorDir . '/workerman/webman-framework/src/support'),
|
||||
'Workerman\\Coroutine\\' => array($vendorDir . '/workerman/coroutine/src'),
|
||||
'Workerman\\' => array($vendorDir . '/workerman/workerman/src', $vendorDir . '/workerman/coroutine/src'),
|
||||
'Webman\\Database\\' => array($vendorDir . '/webman/database/src'),
|
||||
'Webman\\' => array($vendorDir . '/workerman/webman-framework/src'),
|
||||
'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
|
||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||
'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'),
|
||||
'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
|
||||
'Symfony\\Component\\Clock\\' => array($vendorDir . '/symfony/clock'),
|
||||
'Support\\View\\' => array($vendorDir . '/workerman/webman-framework/src/support/view'),
|
||||
'Support\\Exception\\' => array($vendorDir . '/workerman/webman-framework/src/support/exception'),
|
||||
'Support\\Bootstrap\\' => array($vendorDir . '/workerman/webman-framework/src/support/bootstrap'),
|
||||
'Support\\' => array($vendorDir . '/workerman/webman-framework/src/support'),
|
||||
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
|
||||
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
|
||||
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
|
||||
'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
|
||||
'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'),
|
||||
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable'),
|
||||
'Illuminate\\Database\\' => array($vendorDir . '/illuminate/database'),
|
||||
'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
|
||||
'Illuminate\\Container\\' => array($vendorDir . '/illuminate/container'),
|
||||
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
|
||||
'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'),
|
||||
'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),
|
||||
'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'),
|
||||
'Brick\\Math\\' => array($vendorDir . '/brick/math/src'),
|
||||
);
|
50
vendor/composer/autoload_real.php
vendored
Normal file
50
vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitbada8bc7bcb18a93a92df0dd06295584
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitbada8bc7bcb18a93a92df0dd06295584', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitbada8bc7bcb18a93a92df0dd06295584', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
236
vendor/composer/autoload_static.php
vendored
Normal file
236
vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584
|
||||
{
|
||||
public static $files = array (
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'23f09fe3194f8c2f70923f90d6702129' => __DIR__ . '/..' . '/illuminate/collections/functions.php',
|
||||
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
||||
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
|
||||
'2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
|
||||
'f625ee536139dfb962a398b200bdb2bd' => __DIR__ . '/..' . '/illuminate/support/functions.php',
|
||||
'72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',
|
||||
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
|
||||
'd2136ff22b54ac75cd96a40e0022218e' => __DIR__ . '/..' . '/workerman/webman-framework/src/support/helpers.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'v' =>
|
||||
array (
|
||||
'voku\\' => 5,
|
||||
),
|
||||
's' =>
|
||||
array (
|
||||
'support\\' => 8,
|
||||
),
|
||||
'W' =>
|
||||
array (
|
||||
'Workerman\\Coroutine\\' => 20,
|
||||
'Workerman\\' => 10,
|
||||
'Webman\\Database\\' => 16,
|
||||
'Webman\\' => 7,
|
||||
),
|
||||
'S' =>
|
||||
array (
|
||||
'Symfony\\Polyfill\\Php83\\' => 23,
|
||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||
'Symfony\\Contracts\\Translation\\' => 30,
|
||||
'Symfony\\Component\\Translation\\' => 30,
|
||||
'Symfony\\Component\\Clock\\' => 24,
|
||||
'Support\\View\\' => 13,
|
||||
'Support\\Exception\\' => 18,
|
||||
'Support\\Bootstrap\\' => 18,
|
||||
'Support\\' => 8,
|
||||
),
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\SimpleCache\\' => 16,
|
||||
'Psr\\Log\\' => 8,
|
||||
'Psr\\Container\\' => 14,
|
||||
'Psr\\Clock\\' => 10,
|
||||
),
|
||||
'L' =>
|
||||
array (
|
||||
'Laravel\\SerializableClosure\\' => 28,
|
||||
),
|
||||
'I' =>
|
||||
array (
|
||||
'Illuminate\\Support\\' => 19,
|
||||
'Illuminate\\Database\\' => 20,
|
||||
'Illuminate\\Contracts\\' => 21,
|
||||
'Illuminate\\Container\\' => 21,
|
||||
),
|
||||
'F' =>
|
||||
array (
|
||||
'FastRoute\\' => 10,
|
||||
),
|
||||
'D' =>
|
||||
array (
|
||||
'Doctrine\\Inflector\\' => 19,
|
||||
),
|
||||
'C' =>
|
||||
array (
|
||||
'Carbon\\Doctrine\\' => 16,
|
||||
'Carbon\\' => 7,
|
||||
),
|
||||
'B' =>
|
||||
array (
|
||||
'Brick\\Math\\' => 11,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'voku\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',
|
||||
),
|
||||
'support\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/webman/database/src/support',
|
||||
1 => __DIR__ . '/..' . '/workerman/webman-framework/src/support',
|
||||
),
|
||||
'Workerman\\Coroutine\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/coroutine/src',
|
||||
),
|
||||
'Workerman\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/workerman/src',
|
||||
1 => __DIR__ . '/..' . '/workerman/coroutine/src',
|
||||
),
|
||||
'Webman\\Database\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/webman/database/src',
|
||||
),
|
||||
'Webman\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/webman-framework/src',
|
||||
),
|
||||
'Symfony\\Polyfill\\Php83\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
|
||||
),
|
||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||
),
|
||||
'Symfony\\Contracts\\Translation\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/translation-contracts',
|
||||
),
|
||||
'Symfony\\Component\\Translation\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/translation',
|
||||
),
|
||||
'Symfony\\Component\\Clock\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/clock',
|
||||
),
|
||||
'Support\\View\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/webman-framework/src/support/view',
|
||||
),
|
||||
'Support\\Exception\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/webman-framework/src/support/exception',
|
||||
),
|
||||
'Support\\Bootstrap\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/webman-framework/src/support/bootstrap',
|
||||
),
|
||||
'Support\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/webman-framework/src/support',
|
||||
),
|
||||
'Psr\\SimpleCache\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/simple-cache/src',
|
||||
),
|
||||
'Psr\\Log\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/log/src',
|
||||
),
|
||||
'Psr\\Container\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/container/src',
|
||||
),
|
||||
'Psr\\Clock\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/clock/src',
|
||||
),
|
||||
'Laravel\\SerializableClosure\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/laravel/serializable-closure/src',
|
||||
),
|
||||
'Illuminate\\Support\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/illuminate/support',
|
||||
1 => __DIR__ . '/..' . '/illuminate/collections',
|
||||
2 => __DIR__ . '/..' . '/illuminate/conditionable',
|
||||
3 => __DIR__ . '/..' . '/illuminate/macroable',
|
||||
),
|
||||
'Illuminate\\Database\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/illuminate/database',
|
||||
),
|
||||
'Illuminate\\Contracts\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/illuminate/contracts',
|
||||
),
|
||||
'Illuminate\\Container\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/illuminate/container',
|
||||
),
|
||||
'FastRoute\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/nikic/fast-route/src',
|
||||
),
|
||||
'Doctrine\\Inflector\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector',
|
||||
),
|
||||
'Carbon\\Doctrine\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine',
|
||||
),
|
||||
'Carbon\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon',
|
||||
),
|
||||
'Brick\\Math\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/brick/math/src',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
|
||||
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
|
||||
'DateInvalidOperationException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
|
||||
'DateInvalidTimeZoneException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
|
||||
'DateMalformedIntervalStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
|
||||
'DateMalformedPeriodStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
|
||||
'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
|
||||
'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
|
||||
'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
|
||||
'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
|
||||
'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitbada8bc7bcb18a93a92df0dd06295584::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
1884
vendor/composer/installed.json
vendored
Normal file
1884
vendor/composer/installed.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
299
vendor/composer/installed.php
vendored
Normal file
299
vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'brick/math' => array(
|
||||
'pretty_version' => '0.12.3',
|
||||
'version' => '0.12.3.0',
|
||||
'reference' => '866551da34e9a618e64a819ee1e01c20d8a588ba',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../brick/math',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'carbonphp/carbon-doctrine-types' => array(
|
||||
'pretty_version' => '3.2.0',
|
||||
'version' => '3.2.0.0',
|
||||
'reference' => '18ba5ddfec8976260ead6e866180bd5d2f71aa1d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'doctrine/inflector' => array(
|
||||
'pretty_version' => '2.0.10',
|
||||
'version' => '2.0.10.0',
|
||||
'reference' => '5817d0659c5b50c9b950feb9af7b9668e2c436bc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../doctrine/inflector',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/collections' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => '48f5357348093bc8b94c691aa3ffc861d2ecc2a0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/collections',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/conditionable' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => '911df1bda950a3b799cf80671764e34eede131c6',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/conditionable',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/container' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => '4dcc3fcbab92e734fc0c08d9cfd97f5a1aef18ca',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/container',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/contracts' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => 'b350a3cd8450846325cb49e1cbc1293598b18898',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/contracts',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/database' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => '131dcdfcc6c838115d5e58c77d4fe816f735dff8',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/database',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/macroable' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => 'e1cb9e51b9ed5d3c9bc1ab431d0a52fe42a990ed',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/macroable',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'illuminate/support' => array(
|
||||
'pretty_version' => 'v11.44.1',
|
||||
'version' => '11.44.1.0',
|
||||
'reference' => 'd86d42ad0c75a020e0e4a7c734e9424ca86811cc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../illuminate/support',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'laravel/serializable-closure' => array(
|
||||
'pretty_version' => 'v2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'reference' => 'f379c13663245f7aa4512a7869f62eb14095f23f',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laravel/serializable-closure',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'nesbot/carbon' => array(
|
||||
'pretty_version' => '3.8.6',
|
||||
'version' => '3.8.6.0',
|
||||
'reference' => 'ff2f20cf83bd4d503720632ce8a426dc747bf7fd',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../nesbot/carbon',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'nikic/fast-route' => array(
|
||||
'pretty_version' => 'v1.3.0',
|
||||
'version' => '1.3.0.0',
|
||||
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../nikic/fast-route',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/clock' => array(
|
||||
'pretty_version' => '1.0.0',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/clock',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/clock-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '1.0',
|
||||
),
|
||||
),
|
||||
'psr/container' => array(
|
||||
'pretty_version' => '2.0.2',
|
||||
'version' => '2.0.2.0',
|
||||
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/container',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/container-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '1.1|2.0',
|
||||
),
|
||||
),
|
||||
'psr/log' => array(
|
||||
'pretty_version' => '3.0.2',
|
||||
'version' => '3.0.2.0',
|
||||
'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/log',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'psr/simple-cache' => array(
|
||||
'pretty_version' => '3.0.0',
|
||||
'version' => '3.0.0.0',
|
||||
'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../psr/simple-cache',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'spatie/once' => array(
|
||||
'dev_requirement' => false,
|
||||
'replaced' => array(
|
||||
0 => '*',
|
||||
),
|
||||
),
|
||||
'symfony/clock' => array(
|
||||
'pretty_version' => 'v7.2.0',
|
||||
'version' => '7.2.0.0',
|
||||
'reference' => 'b81435fbd6648ea425d1ee96a2d8e68f4ceacd24',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/clock',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/deprecation-contracts' => array(
|
||||
'pretty_version' => 'v3.5.1',
|
||||
'version' => '3.5.1.0',
|
||||
'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-mbstring' => array(
|
||||
'pretty_version' => 'v1.31.0',
|
||||
'version' => '1.31.0.0',
|
||||
'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-php83' => array(
|
||||
'pretty_version' => 'v1.31.0',
|
||||
'version' => '1.31.0.0',
|
||||
'reference' => '2fb86d65e2d424369ad2905e83b236a8805ba491',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-php83',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/translation' => array(
|
||||
'pretty_version' => 'v7.2.4',
|
||||
'version' => '7.2.4.0',
|
||||
'reference' => '283856e6981286cc0d800b53bd5703e8e363f05a',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/translation',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/translation-contracts' => array(
|
||||
'pretty_version' => 'v3.5.1',
|
||||
'version' => '3.5.1.0',
|
||||
'reference' => '4667ff3bd513750603a09c8dedbea942487fb07c',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/translation-contracts',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/translation-implementation' => array(
|
||||
'dev_requirement' => false,
|
||||
'provided' => array(
|
||||
0 => '2.3|3.0',
|
||||
),
|
||||
),
|
||||
'voku/portable-ascii' => array(
|
||||
'pretty_version' => '2.0.3',
|
||||
'version' => '2.0.3.0',
|
||||
'reference' => 'b1d923f88091c6bf09699efcd7c8a1b1bfd7351d',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../voku/portable-ascii',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'webman/database' => array(
|
||||
'pretty_version' => 'v2.1.1',
|
||||
'version' => '2.1.1.0',
|
||||
'reference' => '360e42db6d1a6625ea55241a882a4244b84e72a0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../webman/database',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'workerman/coroutine' => array(
|
||||
'pretty_version' => 'v1.1.3',
|
||||
'version' => '1.1.3.0',
|
||||
'reference' => 'df8fc428967d512a74a8a7d80355c1d40228c9fa',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../workerman/coroutine',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'workerman/webman-framework' => array(
|
||||
'pretty_version' => 'v2.1.2',
|
||||
'version' => '2.1.2.0',
|
||||
'reference' => 'f803bd867f07bb0929faef060b59a19a44186bfc',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../workerman/webman-framework',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'workerman/workerman' => array(
|
||||
'pretty_version' => 'v5.1.0',
|
||||
'version' => '5.1.0.0',
|
||||
'reference' => '5ce17bc71dfdad0e9eba8cd658342da793d2f581',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../workerman/workerman',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
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 >= 80200)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.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
|
||||
);
|
||||
}
|
19
vendor/doctrine/inflector/LICENSE
vendored
Normal file
19
vendor/doctrine/inflector/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2015 Doctrine Project
|
||||
|
||||
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.
|
7
vendor/doctrine/inflector/README.md
vendored
Normal file
7
vendor/doctrine/inflector/README.md
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# Doctrine Inflector
|
||||
|
||||
Doctrine Inflector is a small library that can perform string manipulations
|
||||
with regard to uppercase/lowercase and singular/plural forms of words.
|
||||
|
||||
[](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)
|
41
vendor/doctrine/inflector/composer.json
vendored
Normal file
41
vendor/doctrine/inflector/composer.json
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"type": "library",
|
||||
"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"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
|
||||
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^11.0",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.3",
|
||||
"phpunit/phpunit": "^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.25 || ^5.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\Inflector\\": "tests/Doctrine/Tests/Inflector"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
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>`_
|
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;
|
||||
}
|
||||
}
|
184
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php
vendored
Normal file
184
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
<?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(?<!regatta)$'), '\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('^tights$'), 'tights');
|
||||
yield new Transformation(new Pattern('^shorts$'), 'shorts');
|
||||
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('axis'), new Word('axes'));
|
||||
yield new Substitution(new Word('axe'), new Word('axes'));
|
||||
yield new Substitution(new Word('beef'), new Word('beefs'));
|
||||
yield new Substitution(new Word('blouse'), new Word('blouses'));
|
||||
yield new Substitution(new Word('brother'), new Word('brothers'));
|
||||
yield new Substitution(new Word('cafe'), new Word('cafes'));
|
||||
yield new Substitution(new Word('cave'), new Word('caves'));
|
||||
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('brownie'), new Word('brownies'));
|
||||
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('epoch'), new Word('epochs'));
|
||||
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('sieve'), new Word('sieves'));
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
189
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
vendored
Normal file
189
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
<?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('cattle');
|
||||
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('kin');
|
||||
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');
|
||||
}
|
||||
}
|
44
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php
vendored
Normal file
44
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?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())
|
||||
);
|
||||
}
|
||||
}
|
28
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
vendored
Normal file
28
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?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('');
|
||||
}
|
||||
}
|
34
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php
vendored
Normal file
34
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?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())
|
||||
);
|
||||
}
|
||||
}
|
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
vendored
Normal file
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
98
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php
vendored
Normal file
98
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Portuguese;
|
||||
|
||||
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('/^(g|)ases$/i'), '\1ás');
|
||||
yield new Transformation(new Pattern('/(japon|escoc|ingl|dinamarqu|fregu|portugu)eses$/i'), '\1ês');
|
||||
yield new Transformation(new Pattern('/(ae|ao|oe)s$/'), 'ao');
|
||||
yield new Transformation(new Pattern('/(ãe|ão|õe)s$/'), 'ão');
|
||||
yield new Transformation(new Pattern('/^(.*[^s]s)es$/i'), '\1');
|
||||
yield new Transformation(new Pattern('/sses$/i'), 'sse');
|
||||
yield new Transformation(new Pattern('/ns$/i'), 'm');
|
||||
yield new Transformation(new Pattern('/(r|t|f|v)is$/i'), '\1il');
|
||||
yield new Transformation(new Pattern('/uis$/i'), 'ul');
|
||||
yield new Transformation(new Pattern('/ois$/i'), 'ol');
|
||||
yield new Transformation(new Pattern('/eis$/i'), 'ei');
|
||||
yield new Transformation(new Pattern('/éis$/i'), 'el');
|
||||
yield new Transformation(new Pattern('/([^p])ais$/i'), '\1al');
|
||||
yield new Transformation(new Pattern('/(r|z)es$/i'), '\1');
|
||||
yield new Transformation(new Pattern('/^(á|gá)s$/i'), '\1s');
|
||||
yield new Transformation(new Pattern('/([^ê])s$/i'), '\1');
|
||||
}
|
||||
|
||||
/** @return Transformation[] */
|
||||
public static function getPlural(): iterable
|
||||
{
|
||||
yield new Transformation(new Pattern('/^(alem|c|p)ao$/i'), '\1aes');
|
||||
yield new Transformation(new Pattern('/^(irm|m)ao$/i'), '\1aos');
|
||||
yield new Transformation(new Pattern('/ao$/i'), 'oes');
|
||||
yield new Transformation(new Pattern('/^(alem|c|p)ão$/i'), '\1ães');
|
||||
yield new Transformation(new Pattern('/^(irm|m)ão$/i'), '\1ãos');
|
||||
yield new Transformation(new Pattern('/ão$/i'), 'ões');
|
||||
yield new Transformation(new Pattern('/^(|g)ás$/i'), '\1ases');
|
||||
yield new Transformation(new Pattern('/^(japon|escoc|ingl|dinamarqu|fregu|portugu)ês$/i'), '\1eses');
|
||||
yield new Transformation(new Pattern('/m$/i'), 'ns');
|
||||
yield new Transformation(new Pattern('/([^aeou])il$/i'), '\1is');
|
||||
yield new Transformation(new Pattern('/ul$/i'), 'uis');
|
||||
yield new Transformation(new Pattern('/ol$/i'), 'ois');
|
||||
yield new Transformation(new Pattern('/el$/i'), 'eis');
|
||||
yield new Transformation(new Pattern('/al$/i'), 'ais');
|
||||
yield new Transformation(new Pattern('/(z|r)$/i'), '\1es');
|
||||
yield new Transformation(new Pattern('/(s)$/i'), '\1');
|
||||
yield new Transformation(new Pattern('/$/'), 's');
|
||||
}
|
||||
|
||||
/** @return Substitution[] */
|
||||
public static function getIrregular(): iterable
|
||||
{
|
||||
yield new Substitution(new Word('abdomen'), new Word('abdomens'));
|
||||
yield new Substitution(new Word('alemão'), new Word('alemães'));
|
||||
yield new Substitution(new Word('artesã'), new Word('artesãos'));
|
||||
yield new Substitution(new Word('álcool'), new Word('álcoois'));
|
||||
yield new Substitution(new Word('árvore'), new Word('árvores'));
|
||||
yield new Substitution(new Word('bencão'), new Word('bencãos'));
|
||||
yield new Substitution(new Word('cão'), new Word('cães'));
|
||||
yield new Substitution(new Word('campus'), new Word('campi'));
|
||||
yield new Substitution(new Word('cadáver'), new Word('cadáveres'));
|
||||
yield new Substitution(new Word('capelão'), new Word('capelães'));
|
||||
yield new Substitution(new Word('capitão'), new Word('capitães'));
|
||||
yield new Substitution(new Word('chão'), new Word('chãos'));
|
||||
yield new Substitution(new Word('charlatão'), new Word('charlatães'));
|
||||
yield new Substitution(new Word('cidadão'), new Word('cidadãos'));
|
||||
yield new Substitution(new Word('consul'), new Word('consules'));
|
||||
yield new Substitution(new Word('cristão'), new Word('cristãos'));
|
||||
yield new Substitution(new Word('difícil'), new Word('difíceis'));
|
||||
yield new Substitution(new Word('email'), new Word('emails'));
|
||||
yield new Substitution(new Word('escrivão'), new Word('escrivães'));
|
||||
yield new Substitution(new Word('fóssil'), new Word('fósseis'));
|
||||
yield new Substitution(new Word('gás'), new Word('gases'));
|
||||
yield new Substitution(new Word('germens'), new Word('germen'));
|
||||
yield new Substitution(new Word('grão'), new Word('grãos'));
|
||||
yield new Substitution(new Word('hífen'), new Word('hífens'));
|
||||
yield new Substitution(new Word('irmão'), new Word('irmãos'));
|
||||
yield new Substitution(new Word('liquens'), new Word('liquen'));
|
||||
yield new Substitution(new Word('mal'), new Word('males'));
|
||||
yield new Substitution(new Word('mão'), new Word('mãos'));
|
||||
yield new Substitution(new Word('orfão'), new Word('orfãos'));
|
||||
yield new Substitution(new Word('país'), new Word('países'));
|
||||
yield new Substitution(new Word('pai'), new Word('pais'));
|
||||
yield new Substitution(new Word('pão'), new Word('pães'));
|
||||
yield new Substitution(new Word('projétil'), new Word('projéteis'));
|
||||
yield new Substitution(new Word('réptil'), new Word('répteis'));
|
||||
yield new Substitution(new Word('sacristão'), new Word('sacristães'));
|
||||
yield new Substitution(new Word('sotão'), new Word('sotãos'));
|
||||
yield new Substitution(new Word('tabelião'), new Word('tabeliães'));
|
||||
}
|
||||
}
|
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/InflectorFactory.php
vendored
Normal file
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/InflectorFactory.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Portuguese;
|
||||
|
||||
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/Portuguese/Rules.php
vendored
Normal file
31
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Rules.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Portuguese;
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
32
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php
vendored
Normal file
32
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Portuguese;
|
||||
|
||||
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('tórax');
|
||||
yield new Pattern('tênis');
|
||||
yield new Pattern('ônibus');
|
||||
yield new Pattern('lápis');
|
||||
yield new Pattern('fênix');
|
||||
}
|
||||
}
|
39
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Ruleset.php
vendored
Normal file
39
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Ruleset.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
class Ruleset
|
||||
{
|
||||
/** @var Transformations */
|
||||
private $regular;
|
||||
|
||||
/** @var Patterns */
|
||||
private $uninflected;
|
||||
|
||||
/** @var Substitutions */
|
||||
private $irregular;
|
||||
|
||||
public function __construct(Transformations $regular, Patterns $uninflected, Substitutions $irregular)
|
||||
{
|
||||
$this->regular = $regular;
|
||||
$this->uninflected = $uninflected;
|
||||
$this->irregular = $irregular;
|
||||
}
|
||||
|
||||
public function getRegular(): Transformations
|
||||
{
|
||||
return $this->regular;
|
||||
}
|
||||
|
||||
public function getUninflected(): Patterns
|
||||
{
|
||||
return $this->uninflected;
|
||||
}
|
||||
|
||||
public function getIrregular(): Substitutions
|
||||
{
|
||||
return $this->irregular;
|
||||
}
|
||||
}
|
47
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php
vendored
Normal file
47
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Spanish;
|
||||
|
||||
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('/ereses$/'), 'erés');
|
||||
yield new Transformation(new Pattern('/iones$/'), 'ión');
|
||||
yield new Transformation(new Pattern('/ces$/'), 'z');
|
||||
yield new Transformation(new Pattern('/es$/'), '');
|
||||
yield new Transformation(new Pattern('/s$/'), '');
|
||||
}
|
||||
|
||||
/** @return Transformation[] */
|
||||
public static function getPlural(): iterable
|
||||
{
|
||||
yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\1es');
|
||||
yield new Transformation(new Pattern('/ó([sn])$/i'), 'o\1es');
|
||||
yield new Transformation(new Pattern('/í([sn])$/i'), 'i\1es');
|
||||
yield new Transformation(new Pattern('/é([sn])$/i'), 'e\1es');
|
||||
yield new Transformation(new Pattern('/á([sn])$/i'), 'a\1es');
|
||||
yield new Transformation(new Pattern('/z$/i'), 'ces');
|
||||
yield new Transformation(new Pattern('/([aeiou]s)$/i'), '\1');
|
||||
yield new Transformation(new Pattern('/([^aeéiou])$/i'), '\1es');
|
||||
yield new Transformation(new Pattern('/$/'), 's');
|
||||
}
|
||||
|
||||
/** @return Substitution[] */
|
||||
public static function getIrregular(): iterable
|
||||
{
|
||||
yield new Substitution(new Word('el'), new Word('los'));
|
||||
yield new Substitution(new Word('papá'), new Word('papás'));
|
||||
yield new Substitution(new Word('mamá'), new Word('mamás'));
|
||||
yield new Substitution(new Word('sofá'), new Word('sofás'));
|
||||
yield new Substitution(new Word('mes'), new Word('meses'));
|
||||
}
|
||||
}
|
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/InflectorFactory.php
vendored
Normal file
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/InflectorFactory.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Spanish;
|
||||
|
||||
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/Spanish/Rules.php
vendored
Normal file
31
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Rules.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Spanish;
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php
vendored
Normal file
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Spanish;
|
||||
|
||||
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('lunes');
|
||||
yield new Pattern('rompecabezas');
|
||||
yield new Pattern('crisis');
|
||||
}
|
||||
}
|
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitution.php
vendored
Normal file
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitution.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
final class Substitution
|
||||
{
|
||||
/** @var Word */
|
||||
private $from;
|
||||
|
||||
/** @var Word */
|
||||
private $to;
|
||||
|
||||
public function __construct(Word $from, Word $to)
|
||||
{
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
public function getFrom(): Word
|
||||
{
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
public function getTo(): Word
|
||||
{
|
||||
return $this->to;
|
||||
}
|
||||
}
|
57
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php
vendored
Normal file
57
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
use Doctrine\Inflector\WordInflector;
|
||||
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
|
||||
class Substitutions implements WordInflector
|
||||
{
|
||||
/** @var Substitution[] */
|
||||
private $substitutions;
|
||||
|
||||
public function __construct(Substitution ...$substitutions)
|
||||
{
|
||||
foreach ($substitutions as $substitution) {
|
||||
$this->substitutions[$substitution->getFrom()->getWord()] = $substitution;
|
||||
}
|
||||
}
|
||||
|
||||
public function getFlippedSubstitutions(): Substitutions
|
||||
{
|
||||
$substitutions = [];
|
||||
|
||||
foreach ($this->substitutions as $substitution) {
|
||||
$substitutions[] = new Substitution(
|
||||
$substitution->getTo(),
|
||||
$substitution->getFrom()
|
||||
);
|
||||
}
|
||||
|
||||
return new Substitutions(...$substitutions);
|
||||
}
|
||||
|
||||
public function inflect(string $word): string
|
||||
{
|
||||
$lowerWord = strtolower($word);
|
||||
|
||||
if (isset($this->substitutions[$lowerWord])) {
|
||||
$firstLetterUppercase = $lowerWord[0] !== $word[0];
|
||||
|
||||
$toWord = $this->substitutions[$lowerWord]->getTo()->getWord();
|
||||
|
||||
if ($firstLetterUppercase) {
|
||||
return strtoupper($toWord[0]) . substr($toWord, 1);
|
||||
}
|
||||
|
||||
return $toWord;
|
||||
}
|
||||
|
||||
return $word;
|
||||
}
|
||||
}
|
39
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php
vendored
Normal file
39
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
use Doctrine\Inflector\WordInflector;
|
||||
|
||||
use function preg_replace;
|
||||
|
||||
final class Transformation implements WordInflector
|
||||
{
|
||||
/** @var Pattern */
|
||||
private $pattern;
|
||||
|
||||
/** @var string */
|
||||
private $replacement;
|
||||
|
||||
public function __construct(Pattern $pattern, string $replacement)
|
||||
{
|
||||
$this->pattern = $pattern;
|
||||
$this->replacement = $replacement;
|
||||
}
|
||||
|
||||
public function getPattern(): Pattern
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
public function getReplacement(): string
|
||||
{
|
||||
return $this->replacement;
|
||||
}
|
||||
|
||||
public function inflect(string $word): string
|
||||
{
|
||||
return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);
|
||||
}
|
||||
}
|
29
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php
vendored
Normal file
29
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
use Doctrine\Inflector\WordInflector;
|
||||
|
||||
class Transformations implements WordInflector
|
||||
{
|
||||
/** @var Transformation[] */
|
||||
private $transformations;
|
||||
|
||||
public function __construct(Transformation ...$transformations)
|
||||
{
|
||||
$this->transformations = $transformations;
|
||||
}
|
||||
|
||||
public function inflect(string $word): string
|
||||
{
|
||||
foreach ($this->transformations as $transformation) {
|
||||
if ($transformation->getPattern()->matches($word)) {
|
||||
return $transformation->inflect($word);
|
||||
}
|
||||
}
|
||||
|
||||
return $word;
|
||||
}
|
||||
}
|
34
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php
vendored
Normal file
34
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Turkish;
|
||||
|
||||
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('/l[ae]r$/i'), '');
|
||||
}
|
||||
|
||||
/** @return Transformation[] */
|
||||
public static function getPlural(): iterable
|
||||
{
|
||||
yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\1ler');
|
||||
yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\1lar');
|
||||
}
|
||||
|
||||
/** @return Substitution[] */
|
||||
public static function getIrregular(): iterable
|
||||
{
|
||||
yield new Substitution(new Word('ben'), new Word('biz'));
|
||||
yield new Substitution(new Word('sen'), new Word('siz'));
|
||||
yield new Substitution(new Word('o'), new Word('onlar'));
|
||||
}
|
||||
}
|
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/InflectorFactory.php
vendored
Normal file
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/InflectorFactory.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Turkish;
|
||||
|
||||
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/Turkish/Rules.php
vendored
Normal file
31
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Rules.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Turkish;
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php
vendored
Normal file
30
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules\Turkish;
|
||||
|
||||
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('lunes');
|
||||
yield new Pattern('rompecabezas');
|
||||
yield new Pattern('crisis');
|
||||
}
|
||||
}
|
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php
vendored
Normal file
21
vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector\Rules;
|
||||
|
||||
class Word
|
||||
{
|
||||
/** @var string */
|
||||
private $word;
|
||||
|
||||
public function __construct(string $word)
|
||||
{
|
||||
$this->word = $word;
|
||||
}
|
||||
|
||||
public function getWord(): string
|
||||
{
|
||||
return $this->word;
|
||||
}
|
||||
}
|
56
vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php
vendored
Normal file
56
vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector;
|
||||
|
||||
use Doctrine\Inflector\Rules\Ruleset;
|
||||
|
||||
use function array_merge;
|
||||
|
||||
/**
|
||||
* Inflects based on multiple rulesets.
|
||||
*
|
||||
* Rules:
|
||||
* - If the word matches any uninflected word pattern, it is not inflected
|
||||
* - The first ruleset that returns a different value for an irregular word wins
|
||||
* - The first ruleset that returns a different value for a regular word wins
|
||||
* - If none of the above match, the word is left as-is
|
||||
*/
|
||||
class RulesetInflector implements WordInflector
|
||||
{
|
||||
/** @var Ruleset[] */
|
||||
private $rulesets;
|
||||
|
||||
public function __construct(Ruleset $ruleset, Ruleset ...$rulesets)
|
||||
{
|
||||
$this->rulesets = array_merge([$ruleset], $rulesets);
|
||||
}
|
||||
|
||||
public function inflect(string $word): string
|
||||
{
|
||||
if ($word === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($this->rulesets as $ruleset) {
|
||||
if ($ruleset->getUninflected()->matches($word)) {
|
||||
return $word;
|
||||
}
|
||||
|
||||
$inflected = $ruleset->getIrregular()->inflect($word);
|
||||
|
||||
if ($inflected !== $word) {
|
||||
return $inflected;
|
||||
}
|
||||
|
||||
$inflected = $ruleset->getRegular()->inflect($word);
|
||||
|
||||
if ($inflected !== $word) {
|
||||
return $inflected;
|
||||
}
|
||||
}
|
||||
|
||||
return $word;
|
||||
}
|
||||
}
|
10
vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php
vendored
Normal file
10
vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Inflector;
|
||||
|
||||
interface WordInflector
|
||||
{
|
||||
public function inflect(string $word): string;
|
||||
}
|
970
vendor/illuminate/collections/Arr.php
vendored
Normal file
970
vendor/illuminate/collections/Arr.php
vendored
Normal file
@ -0,0 +1,970 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Support;
|
||||
|
||||
use ArgumentCountError;
|
||||
use ArrayAccess;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use InvalidArgumentException;
|
||||
use Random\Randomizer;
|
||||
|
||||
class Arr
|
||||
{
|
||||
use Macroable;
|
||||
|
||||
/**
|
||||
* Determine whether the given value is array accessible.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public static function accessible($value)
|
||||
{
|
||||
return is_array($value) || $value instanceof ArrayAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element to an array using "dot" notation if it doesn't exist.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string|int|float $key
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public static function add($array, $key, $value)
|
||||
{
|
||||
if (is_null(static::get($array, $key))) {
|
||||
static::set($array, $key, $value);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse an array of arrays into a single array.
|
||||
*
|
||||
* @param iterable $array
|
||||
* @return array
|
||||
*/
|
||||
public static function collapse($array)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($array as $values) {
|
||||
if ($values instanceof Collection) {
|
||||
$values = $values->all();
|
||||
} elseif (! is_array($values)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$results[] = $values;
|
||||
}
|
||||
|
||||
return array_merge([], ...$results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross join the given arrays, returning all possible permutations.
|
||||
*
|
||||
* @param iterable ...$arrays
|
||||
* @return array
|
||||
*/
|
||||
public static function crossJoin(...$arrays)
|
||||
{
|
||||
$results = [[]];
|
||||
|
||||
foreach ($arrays as $index => $array) {
|
||||
$append = [];
|
||||
|
||||
foreach ($results as $product) {
|
||||
foreach ($array as $item) {
|
||||
$product[$index] = $item;
|
||||
|
||||
$append[] = $product;
|
||||
}
|
||||
}
|
||||
|
||||
$results = $append;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide an array into two arrays. One with keys and the other with values.
|
||||
*
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
public static function divide($array)
|
||||
{
|
||||
return [array_keys($array), array_values($array)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a multi-dimensional associative array with dots.
|
||||
*
|
||||
* @param iterable $array
|
||||
* @param string $prepend
|
||||
* @return array
|
||||
*/
|
||||
public static function dot($array, $prepend = '')
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value) && ! empty($value)) {
|
||||
$results = array_merge($results, static::dot($value, $prepend.$key.'.'));
|
||||
} else {
|
||||
$results[$prepend.$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a flatten "dot" notation array into an expanded array.
|
||||
*
|
||||
* @param iterable $array
|
||||
* @return array
|
||||
*/
|
||||
public static function undot($array)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
static::set($results, $key, $value);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the given array except for a specified array of keys.
|
||||
*
|
||||
* @param array $array
|
||||
* @param array|string|int|float $keys
|
||||
* @return array
|
||||
*/
|
||||
public static function except($array, $keys)
|
||||
{
|
||||
static::forget($array, $keys);
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given key exists in the provided array.
|
||||
*
|
||||
* @param \ArrayAccess|array $array
|
||||
* @param string|int|float $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists($array, $key)
|
||||
{
|
||||
if ($array instanceof Enumerable) {
|
||||
return $array->has($key);
|
||||
}
|
||||
|
||||
if ($array instanceof ArrayAccess) {
|
||||
return $array->offsetExists($key);
|
||||
}
|
||||
|
||||
if (is_float($key)) {
|
||||
$key = (string) $key;
|
||||
}
|
||||
|
||||
return array_key_exists($key, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first element in an array passing a given truth test.
|
||||
*
|
||||
* @template TKey
|
||||
* @template TValue
|
||||
* @template TFirstDefault
|
||||
*
|
||||
* @param iterable<TKey, TValue> $array
|
||||
* @param (callable(TValue, TKey): bool)|null $callback
|
||||
* @param TFirstDefault|(\Closure(): TFirstDefault) $default
|
||||
* @return TValue|TFirstDefault
|
||||
*/
|
||||
public static function first($array, ?callable $callback = null, $default = null)
|
||||
{
|
||||
if (is_null($callback)) {
|
||||
if (empty($array)) {
|
||||
return value($default);
|
||||
}
|
||||
|
||||
foreach ($array as $item) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
return value($default);
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if ($callback($value, $key)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return value($default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last element in an array passing a given truth test.
|
||||
*
|
||||
* @template TKey
|
||||
* @template TValue
|
||||
* @template TLastDefault
|
||||
*
|
||||
* @param iterable<TKey, TValue> $array
|
||||
* @param (callable(TValue, TKey): bool)|null $callback
|
||||
* @param TLastDefault|(\Closure(): TLastDefault) $default
|
||||
* @return TValue|TLastDefault
|
||||
*/
|
||||
public static function last($array, ?callable $callback = null, $default = null)
|
||||
{
|
||||
if (is_null($callback)) {
|
||||
return empty($array) ? value($default) : end($array);
|
||||
}
|
||||
|
||||
return static::first(array_reverse($array, true), $callback, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the first or last {$limit} items from an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $limit
|
||||
* @return array
|
||||
*/
|
||||
public static function take($array, $limit)
|
||||
{
|
||||
if ($limit < 0) {
|
||||
return array_slice($array, $limit, abs($limit));
|
||||
}
|
||||
|
||||
return array_slice($array, 0, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a multi-dimensional array into a single level.
|
||||
*
|
||||
* @param iterable $array
|
||||
* @param int $depth
|
||||
* @return array
|
||||
*/
|
||||
public static function flatten($array, $depth = INF)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($array as $item) {
|
||||
$item = $item instanceof Collection ? $item->all() : $item;
|
||||
|
||||
if (! is_array($item)) {
|
||||
$result[] = $item;
|
||||
} else {
|
||||
$values = $depth === 1
|
||||
? array_values($item)
|
||||
: static::flatten($item, $depth - 1);
|
||||
|
||||
foreach ($values as $value) {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one or many array items from a given array using "dot" notation.
|
||||
*
|
||||
* @param array $array
|
||||
* @param array|string|int|float $keys
|
||||
* @return void
|
||||
*/
|
||||
public static function forget(&$array, $keys)
|
||||
{
|
||||
$original = &$array;
|
||||
|
||||
$keys = (array) $keys;
|
||||
|
||||
if (count($keys) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
// if the exact key exists in the top-level, remove it
|
||||
if (static::exists($array, $key)) {
|
||||
unset($array[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode('.', $key);
|
||||
|
||||
// clean up before each pass
|
||||
$array = &$original;
|
||||
|
||||
while (count($parts) > 1) {
|
||||
$part = array_shift($parts);
|
||||
|
||||
if (isset($array[$part]) && static::accessible($array[$part])) {
|
||||
$array = &$array[$part];
|
||||
} else {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
unset($array[array_shift($parts)]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from an array using "dot" notation.
|
||||
*
|
||||
* @param \ArrayAccess|array $array
|
||||
* @param string|int|null $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($array, $key, $default = null)
|
||||
{
|
||||
if (! static::accessible($array)) {
|
||||
return value($default);
|
||||
}
|
||||
|
||||
if (is_null($key)) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
if (static::exists($array, $key)) {
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
if (! str_contains($key, '.')) {
|
||||
return $array[$key] ?? value($default);
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (static::accessible($array) && static::exists($array, $segment)) {
|
||||
$array = $array[$segment];
|
||||
} else {
|
||||
return value($default);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item or items exist in an array using "dot" notation.
|
||||
*
|
||||
* @param \ArrayAccess|array $array
|
||||
* @param string|array $keys
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($array, $keys)
|
||||
{
|
||||
$keys = (array) $keys;
|
||||
|
||||
if (! $array || $keys === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$subKeyArray = $array;
|
||||
|
||||
if (static::exists($array, $key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
|
||||
$subKeyArray = $subKeyArray[$segment];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if any of the keys exist in an array using "dot" notation.
|
||||
*
|
||||
* @param \ArrayAccess|array $array
|
||||
* @param string|array $keys
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasAny($array, $keys)
|
||||
{
|
||||
if (is_null($keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$keys = (array) $keys;
|
||||
|
||||
if (! $array) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($keys === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (static::has($array, $key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an array is associative.
|
||||
*
|
||||
* An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
|
||||
*
|
||||
* @param array $array
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAssoc(array $array)
|
||||
{
|
||||
return ! array_is_list($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an array is a list.
|
||||
*
|
||||
* An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between.
|
||||
*
|
||||
* @param array $array
|
||||
* @return bool
|
||||
*/
|
||||
public static function isList($array)
|
||||
{
|
||||
return array_is_list($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join all items using a string. The final items can use a separate glue string.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $glue
|
||||
* @param string $finalGlue
|
||||
* @return string
|
||||
*/
|
||||
public static function join($array, $glue, $finalGlue = '')
|
||||
{
|
||||
if ($finalGlue === '') {
|
||||
return implode($glue, $array);
|
||||
}
|
||||
|
||||
if (count($array) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (count($array) === 1) {
|
||||
return end($array);
|
||||
}
|
||||
|
||||
$finalItem = array_pop($array);
|
||||
|
||||
return implode($glue, $array).$finalGlue.$finalItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key an associative array by a field or using a callback.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable|array|string $keyBy
|
||||
* @return array
|
||||
*/
|
||||
public static function keyBy($array, $keyBy)
|
||||
{
|
||||
return (new Collection($array))->keyBy($keyBy)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend the key names of an associative array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $prependWith
|
||||
* @return array
|
||||
*/
|
||||
public static function prependKeysWith($array, $prependWith)
|
||||
{
|
||||
return static::mapWithKeys($array, fn ($item, $key) => [$prependWith.$key => $item]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a subset of the items from the given array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param array|string $keys
|
||||
* @return array
|
||||
*/
|
||||
public static function only($array, $keys)
|
||||
{
|
||||
return array_intersect_key($array, array_flip((array) $keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select an array of values from an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param array|string $keys
|
||||
* @return array
|
||||
*/
|
||||
public static function select($array, $keys)
|
||||
{
|
||||
$keys = static::wrap($keys);
|
||||
|
||||
return static::map($array, function ($item) use ($keys) {
|
||||
$result = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (Arr::accessible($item) && Arr::exists($item, $key)) {
|
||||
$result[$key] = $item[$key];
|
||||
} elseif (is_object($item) && isset($item->{$key})) {
|
||||
$result[$key] = $item->{$key};
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pluck an array of values from an array.
|
||||
*
|
||||
* @param iterable $array
|
||||
* @param string|array|int|null $value
|
||||
* @param string|array|null $key
|
||||
* @return array
|
||||
*/
|
||||
public static function pluck($array, $value, $key = null)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
[$value, $key] = static::explodePluckParameters($value, $key);
|
||||
|
||||
foreach ($array as $item) {
|
||||
$itemValue = data_get($item, $value);
|
||||
|
||||
// If the key is "null", we will just append the value to the array and keep
|
||||
// looping. Otherwise we will key the array using the value of the key we
|
||||
// received from the developer. Then we'll return the final array form.
|
||||
if (is_null($key)) {
|
||||
$results[] = $itemValue;
|
||||
} else {
|
||||
$itemKey = data_get($item, $key);
|
||||
|
||||
if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
|
||||
$itemKey = (string) $itemKey;
|
||||
}
|
||||
|
||||
$results[$itemKey] = $itemValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode the "value" and "key" arguments passed to "pluck".
|
||||
*
|
||||
* @param string|array $value
|
||||
* @param string|array|null $key
|
||||
* @return array
|
||||
*/
|
||||
protected static function explodePluckParameters($value, $key)
|
||||
{
|
||||
$value = is_string($value) ? explode('.', $value) : $value;
|
||||
|
||||
$key = is_null($key) || is_array($key) ? $key : explode('.', $key);
|
||||
|
||||
return [$value, $key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a map over each of the items in the array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function map(array $array, callable $callback)
|
||||
{
|
||||
$keys = array_keys($array);
|
||||
|
||||
try {
|
||||
$items = array_map($callback, $array, $keys);
|
||||
} catch (ArgumentCountError) {
|
||||
$items = array_map($callback, $array);
|
||||
}
|
||||
|
||||
return array_combine($keys, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an associative map over each of the items.
|
||||
*
|
||||
* The callback should return an associative array with a single key/value pair.
|
||||
*
|
||||
* @template TKey
|
||||
* @template TValue
|
||||
* @template TMapWithKeysKey of array-key
|
||||
* @template TMapWithKeysValue
|
||||
*
|
||||
* @param array<TKey, TValue> $array
|
||||
* @param callable(TValue, TKey): array<TMapWithKeysKey, TMapWithKeysValue> $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function mapWithKeys(array $array, callable $callback)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$assoc = $callback($value, $key);
|
||||
|
||||
foreach ($assoc as $mapKey => $mapValue) {
|
||||
$result[$mapKey] = $mapValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a map over each nested chunk of items.
|
||||
*
|
||||
* @template TKey
|
||||
* @template TValue
|
||||
*
|
||||
* @param array<TKey, array> $array
|
||||
* @param callable(mixed...): TValue $callback
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
public static function mapSpread(array $array, callable $callback)
|
||||
{
|
||||
return static::map($array, function ($chunk, $key) use ($callback) {
|
||||
$chunk[] = $key;
|
||||
|
||||
return $callback(...$chunk);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an item onto the beginning of an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param mixed $value
|
||||
* @param mixed $key
|
||||
* @return array
|
||||
*/
|
||||
public static function prepend($array, $value, $key = null)
|
||||
{
|
||||
if (func_num_args() == 2) {
|
||||
array_unshift($array, $value);
|
||||
} else {
|
||||
$array = [$key => $value] + $array;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the array, and remove it.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string|int $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function pull(&$array, $key, $default = null)
|
||||
{
|
||||
$value = static::get($array, $key, $default);
|
||||
|
||||
static::forget($array, $key);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the array into a query string.
|
||||
*
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
public static function query($array)
|
||||
{
|
||||
return http_build_query($array, '', '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one or a specified number of random values from an array.
|
||||
*
|
||||
* @param array $array
|
||||
* @param int|null $number
|
||||
* @param bool $preserveKeys
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function random($array, $number = null, $preserveKeys = false)
|
||||
{
|
||||
$requested = is_null($number) ? 1 : $number;
|
||||
|
||||
$count = count($array);
|
||||
|
||||
if ($requested > $count) {
|
||||
throw new InvalidArgumentException(
|
||||
"You requested {$requested} items, but there are only {$count} items available."
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($array) || (! is_null($number) && $number <= 0)) {
|
||||
return is_null($number) ? null : [];
|
||||
}
|
||||
|
||||
$keys = (new Randomizer)->pickArrayKeys($array, $requested);
|
||||
|
||||
if (is_null($number)) {
|
||||
return $array[$keys[0]];
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
if ($preserveKeys) {
|
||||
foreach ($keys as $key) {
|
||||
$results[$key] = $array[$key];
|
||||
}
|
||||
} else {
|
||||
foreach ($keys as $key) {
|
||||
$results[] = $array[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an array item to a given value using "dot" notation.
|
||||
*
|
||||
* If no key is given to the method, the entire array will be replaced.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string|int|null $key
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public static function set(&$array, $key, $value)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
return $array = $value;
|
||||
}
|
||||
|
||||
$keys = explode('.', $key);
|
||||
|
||||
foreach ($keys as $i => $key) {
|
||||
if (count($keys) === 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
unset($keys[$i]);
|
||||
|
||||
// If the key doesn't exist at this depth, we will just create an empty array
|
||||
// to hold the next value, allowing us to create the arrays to hold final
|
||||
// values at the correct depth. Then we'll keep digging into the array.
|
||||
if (! isset($array[$key]) || ! is_array($array[$key])) {
|
||||
$array[$key] = [];
|
||||
}
|
||||
|
||||
$array = &$array[$key];
|
||||
}
|
||||
|
||||
$array[array_shift($keys)] = $value;
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle the given array and return the result.
|
||||
*
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
public static function shuffle($array)
|
||||
{
|
||||
return (new Randomizer)->shuffleArray($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the array using the given callback or "dot" notation.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable|array|string|null $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function sort($array, $callback = null)
|
||||
{
|
||||
return (new Collection($array))->sortBy($callback)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the array in descending order using the given callback or "dot" notation.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable|array|string|null $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function sortDesc($array, $callback = null)
|
||||
{
|
||||
return (new Collection($array))->sortByDesc($callback)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively sort an array by keys and values.
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $options
|
||||
* @param bool $descending
|
||||
* @return array
|
||||
*/
|
||||
public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false)
|
||||
{
|
||||
foreach ($array as &$value) {
|
||||
if (is_array($value)) {
|
||||
$value = static::sortRecursive($value, $options, $descending);
|
||||
}
|
||||
}
|
||||
|
||||
if (! array_is_list($array)) {
|
||||
$descending
|
||||
? krsort($array, $options)
|
||||
: ksort($array, $options);
|
||||
} else {
|
||||
$descending
|
||||
? rsort($array, $options)
|
||||
: sort($array, $options);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively sort an array by keys and values in descending order.
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $options
|
||||
* @return array
|
||||
*/
|
||||
public static function sortRecursiveDesc($array, $options = SORT_REGULAR)
|
||||
{
|
||||
return static::sortRecursive($array, $options, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally compile classes from an array into a CSS class list.
|
||||
*
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
public static function toCssClasses($array)
|
||||
{
|
||||
$classList = static::wrap($array);
|
||||
|
||||
$classes = [];
|
||||
|
||||
foreach ($classList as $class => $constraint) {
|
||||
if (is_numeric($class)) {
|
||||
$classes[] = $constraint;
|
||||
} elseif ($constraint) {
|
||||
$classes[] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally compile styles from an array into a style list.
|
||||
*
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
public static function toCssStyles($array)
|
||||
{
|
||||
$styleList = static::wrap($array);
|
||||
|
||||
$styles = [];
|
||||
|
||||
foreach ($styleList as $class => $constraint) {
|
||||
if (is_numeric($class)) {
|
||||
$styles[] = Str::finish($constraint, ';');
|
||||
} elseif ($constraint) {
|
||||
$styles[] = Str::finish($class, ';');
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', $styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the array using the given callback.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function where($array, callable $callback)
|
||||
{
|
||||
return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the array using the negation of the given callback.
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function reject($array, callable $callback)
|
||||
{
|
||||
return static::where($array, fn ($value, $key) => ! $callback($value, $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter items where the value is not null.
|
||||
*
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
public static function whereNotNull($array)
|
||||
{
|
||||
return static::where($array, fn ($value) => ! is_null($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given value is not an array and not null, wrap it in one.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public static function wrap($value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return is_array($value) ? $value : [$value];
|
||||
}
|
||||
}
|
1923
vendor/illuminate/collections/Collection.php
vendored
Normal file
1923
vendor/illuminate/collections/Collection.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1311
vendor/illuminate/collections/Enumerable.php
vendored
Normal file
1311
vendor/illuminate/collections/Enumerable.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
68
vendor/illuminate/collections/HigherOrderCollectionProxy.php
vendored
Normal file
68
vendor/illuminate/collections/HigherOrderCollectionProxy.php
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Support;
|
||||
|
||||
/**
|
||||
* @template TKey of array-key
|
||||
*
|
||||
* @template-covariant TValue
|
||||
*
|
||||
* @mixin \Illuminate\Support\Enumerable<TKey, TValue>
|
||||
* @mixin TValue
|
||||
*/
|
||||
class HigherOrderCollectionProxy
|
||||
{
|
||||
/**
|
||||
* The collection being operated on.
|
||||
*
|
||||
* @var \Illuminate\Support\Enumerable<TKey, TValue>
|
||||
*/
|
||||
protected $collection;
|
||||
|
||||
/**
|
||||
* The method being proxied.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $method;
|
||||
|
||||
/**
|
||||
* Create a new proxy instance.
|
||||
*
|
||||
* @param \Illuminate\Support\Enumerable<TKey, TValue> $collection
|
||||
* @param string $method
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Enumerable $collection, $method)
|
||||
{
|
||||
$this->method = $method;
|
||||
$this->collection = $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy accessing an attribute onto the collection items.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
return $this->collection->{$this->method}(function ($value) use ($key) {
|
||||
return is_array($value) ? $value[$key] : $value->{$key};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy a method call onto the collection items.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
|
||||
return $value->{$method}(...$parameters);
|
||||
});
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user