refactor: Cleanup git state - commit all staged changes
Major refactoring cleanup: - Add new controller architecture (class-controller-*.php) - Add new settings-v2 UI (views/settings-v2/) - Add new CSS architecture (agentic-sidebar.css, tokens) - Add esbuild build pipeline (scripts/build.js, package.json) - Add composer dependencies (vendor/) - Add frontend src directory (assets/js/src/index.jsx) - Add documentation files - Remove old/obsolete files (class-settings.php, old CSS) This commits all pending changes from previous refactoring efforts.
This commit is contained in:
19
vendor/doctrine/deprecations/LICENSE
vendored
Normal file
19
vendor/doctrine/deprecations/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2020-2021 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.
|
||||
216
vendor/doctrine/deprecations/README.md
vendored
Normal file
216
vendor/doctrine/deprecations/README.md
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
# Doctrine Deprecations
|
||||
|
||||
A small (side-effect free by default) layer on top of
|
||||
`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging.
|
||||
|
||||
- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under
|
||||
- options to avoid having to rely on error handlers global state by using PSR-3 logging
|
||||
- deduplicate deprecation messages to avoid excessive triggering and reduce overhead
|
||||
|
||||
We recommend to collect Deprecations using a PSR logger instead of relying on
|
||||
the global error handler.
|
||||
|
||||
## Usage from consumer perspective:
|
||||
|
||||
Enable Doctrine deprecations to be sent to a PSR3 logger:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
|
||||
```
|
||||
|
||||
Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)`
|
||||
messages by setting the `DOCTRINE_DEPRECATIONS` environment variable to `trigger`.
|
||||
Alternatively, call:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::enableWithTriggerError();
|
||||
```
|
||||
|
||||
If you only want to enable deprecation tracking, without logging or calling `trigger_error`
|
||||
then set the `DOCTRINE_DEPRECATIONS` environment variable to `track`.
|
||||
Alternatively, call:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
|
||||
```
|
||||
|
||||
Tracking is enabled with all three modes and provides access to all triggered
|
||||
deprecations and their individual count:
|
||||
|
||||
```php
|
||||
$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations();
|
||||
|
||||
foreach ($deprecations as $identifier => $count) {
|
||||
echo $identifier . " was triggered " . $count . " times\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Suppressing Specific Deprecations
|
||||
|
||||
Disable triggering about specific deprecations:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier");
|
||||
```
|
||||
|
||||
Disable all deprecations from a package
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm");
|
||||
```
|
||||
|
||||
### Other Operations
|
||||
|
||||
When used within PHPUnit or other tools that could collect multiple instances of the same deprecations
|
||||
the deduplication can be disabled:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::withoutDeduplication();
|
||||
```
|
||||
|
||||
Disable deprecation tracking again:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::disable();
|
||||
```
|
||||
|
||||
## Usage from a library/producer perspective:
|
||||
|
||||
When you want to unconditionally trigger a deprecation even when called
|
||||
from the library itself then the `trigger` method is the way to go:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::trigger(
|
||||
"doctrine/orm",
|
||||
"https://link/to/deprecations-description",
|
||||
"message"
|
||||
);
|
||||
```
|
||||
|
||||
If variable arguments are provided at the end, they are used with `sprintf` on
|
||||
the message.
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::trigger(
|
||||
"doctrine/orm",
|
||||
"https://github.com/doctrine/orm/issue/1234",
|
||||
"message %s %d",
|
||||
"foo",
|
||||
1234
|
||||
);
|
||||
```
|
||||
|
||||
When you want to trigger a deprecation only when it is called by a function
|
||||
outside of the current package, but not trigger when the package itself is the cause,
|
||||
then use:
|
||||
|
||||
```php
|
||||
\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside(
|
||||
"doctrine/orm",
|
||||
"https://link/to/deprecations-description",
|
||||
"message"
|
||||
);
|
||||
```
|
||||
|
||||
Based on the issue link each deprecation message is only triggered once per
|
||||
request.
|
||||
|
||||
A limited stacktrace is included in the deprecation message to find the
|
||||
offending location.
|
||||
|
||||
Note: A producer/library should never call `Deprecation::enableWith` methods
|
||||
and leave the decision how to handle deprecations to application and
|
||||
frameworks.
|
||||
|
||||
## Usage in PHPUnit tests
|
||||
|
||||
There is a `VerifyDeprecations` trait that you can use to make assertions on
|
||||
the occurrence of deprecations within a test.
|
||||
|
||||
```php
|
||||
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
|
||||
|
||||
class MyTest extends TestCase
|
||||
{
|
||||
use VerifyDeprecations;
|
||||
|
||||
public function testSomethingDeprecation()
|
||||
{
|
||||
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
|
||||
|
||||
triggerTheCodeWithDeprecation();
|
||||
}
|
||||
|
||||
public function testSomethingDeprecationFixed()
|
||||
{
|
||||
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
|
||||
|
||||
triggerTheCodeWithoutDeprecation();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Displaying deprecations after running a PHPUnit test suite
|
||||
|
||||
It is possible to integrate this library with PHPUnit to display all
|
||||
deprecations triggered during the test suite execution.
|
||||
|
||||
```xml
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
failOnDeprecation="true"
|
||||
>
|
||||
<!-- one attribute to display the deprecations, the other to fail the test suite -->
|
||||
|
||||
<php>
|
||||
<!-- ensures native PHP deprecations are used -->
|
||||
<server name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<!-- ensures the @ operator in @trigger_error is ignored -->
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
```
|
||||
|
||||
Note that you can still trigger Deprecations in your code, provided you use the
|
||||
`#[IgnoreDeprecations]` to ignore them for tests that call it.
|
||||
|
||||
At the moment, it is not possible to disable deduplication with an environment
|
||||
variable, but you can use a bootstrap file to achieve that:
|
||||
|
||||
```php
|
||||
// tests/bootstrap.php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
Deprecation::withoutDeduplication();
|
||||
```
|
||||
|
||||
Then, reference that file in your PHPUnit configuration:
|
||||
|
||||
```xml
|
||||
<phpunit …
|
||||
bootstrap="tests/bootstrap.php"
|
||||
…
|
||||
>
|
||||
…
|
||||
</phpunit>
|
||||
```
|
||||
|
||||
## What is a deprecation identifier?
|
||||
|
||||
An identifier for deprecations is just a link to any resource, most often a
|
||||
Github Issue or Pull Request explaining the deprecation and potentially its
|
||||
alternative.
|
||||
39
vendor/doctrine/deprecations/composer.json
vendored
Normal file
39
vendor/doctrine/deprecations/composer.json
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"homepage": "https://www.doctrine-project.org/",
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9 || ^12 || ^14",
|
||||
"phpstan/phpstan": "1.4.10 || 2.1.30",
|
||||
"phpstan/phpstan-phpunit": "^1.0 || ^2",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
|
||||
"psr/log": "^1 || ^2 || ^3"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<=7.5 || >=14"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Deprecations\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"DeprecationTests\\": "test_fixtures/src",
|
||||
"Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
309
vendor/doctrine/deprecations/src/Deprecation.php
vendored
Normal file
309
vendor/doctrine/deprecations/src/Deprecation.php
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Deprecations;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_reduce;
|
||||
use function assert;
|
||||
use function debug_backtrace;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
use function substr;
|
||||
use function trigger_error;
|
||||
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* Manages Deprecation logging in different ways.
|
||||
*
|
||||
* By default triggered exceptions are not logged.
|
||||
*
|
||||
* To enable different deprecation logging mechanisms you can call the
|
||||
* following methods:
|
||||
*
|
||||
* - Minimal collection of deprecations via getTriggeredDeprecations()
|
||||
* \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
|
||||
*
|
||||
* - Uses @trigger_error with E_USER_DEPRECATED
|
||||
* \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
|
||||
*
|
||||
* - Sends deprecation messages via a PSR-3 logger
|
||||
* \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
|
||||
*
|
||||
* Packages that trigger deprecations should use the `trigger()` or
|
||||
* `triggerIfCalledFromOutside()` methods.
|
||||
*/
|
||||
class Deprecation
|
||||
{
|
||||
private const TYPE_NONE = 0;
|
||||
private const TYPE_TRACK_DEPRECATIONS = 1;
|
||||
private const TYPE_TRIGGER_ERROR = 2;
|
||||
private const TYPE_PSR_LOGGER = 4;
|
||||
|
||||
/** @var int-mask-of<self::TYPE_*>|null */
|
||||
private static $type;
|
||||
|
||||
/** @var LoggerInterface|null */
|
||||
private static $logger;
|
||||
|
||||
/** @var array<string,bool> */
|
||||
private static $ignoredPackages = [];
|
||||
|
||||
/** @var array<string,int> */
|
||||
private static $triggeredDeprecations = [];
|
||||
|
||||
/** @var array<string,bool> */
|
||||
private static $ignoredLinks = [];
|
||||
|
||||
/** @var bool */
|
||||
private static $deduplication = true;
|
||||
|
||||
/**
|
||||
* Trigger a deprecation for the given package and identfier.
|
||||
*
|
||||
* The link should point to a Github issue or Wiki entry detailing the
|
||||
* deprecation. It is additionally used to de-duplicate the trigger of the
|
||||
* same deprecation during a request.
|
||||
*
|
||||
* @param float|int|string $args
|
||||
*/
|
||||
public static function trigger(string $package, string $link, string $message, ...$args): void
|
||||
{
|
||||
$type = self::$type ?? self::getTypeFromEnv();
|
||||
|
||||
if ($type === self::TYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$ignoredLinks[$link])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (array_key_exists($link, self::$triggeredDeprecations)) {
|
||||
self::$triggeredDeprecations[$link]++;
|
||||
} else {
|
||||
self::$triggeredDeprecations[$link] = 1;
|
||||
}
|
||||
|
||||
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$ignoredPackages[$package])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
|
||||
$message = sprintf($message, ...$args);
|
||||
|
||||
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a deprecation for the given package and identifier when called from outside.
|
||||
*
|
||||
* "Outside" means we assume that $package is currently installed as a
|
||||
* dependency and the caller is not a file in that package. When $package
|
||||
* is installed as a root package then deprecations triggered from the
|
||||
* tests folder are also considered "outside".
|
||||
*
|
||||
* This deprecation method assumes that you are using Composer to install
|
||||
* the dependency and are using the default /vendor/ folder and not a
|
||||
* Composer plugin to change the install location. The assumption is also
|
||||
* that $package is the exact composer packge name.
|
||||
*
|
||||
* Compared to {@link trigger()} this method causes some overhead when
|
||||
* deprecation tracking is enabled even during deduplication, because it
|
||||
* needs to call {@link debug_backtrace()}
|
||||
*
|
||||
* @param float|int|string $args
|
||||
*/
|
||||
public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
|
||||
{
|
||||
$type = self::$type ?? self::getTypeFromEnv();
|
||||
|
||||
if ($type === self::TYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
|
||||
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
|
||||
if (isset($backtrace[1]['file'], $backtrace[0]['file']) && strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
|
||||
$path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $package) . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (strpos($backtrace[0]['file'], $path) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($backtrace[1]['file'], $path) !== false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset(self::$ignoredLinks[$link])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (array_key_exists($link, self::$triggeredDeprecations)) {
|
||||
self::$triggeredDeprecations[$link]++;
|
||||
} else {
|
||||
self::$triggeredDeprecations[$link] = 1;
|
||||
}
|
||||
|
||||
if (self::$deduplication === true && self::$triggeredDeprecations[$link] > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$ignoredPackages[$package])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf($message, ...$args);
|
||||
|
||||
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
|
||||
}
|
||||
|
||||
/** @param list<array{function: string, line?: int, file?: string, class?: class-string, type?: string, args?: mixed[], object?: object}> $backtrace */
|
||||
private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
|
||||
{
|
||||
$type = self::$type ?? self::getTypeFromEnv();
|
||||
|
||||
if (($type & self::TYPE_PSR_LOGGER) > 0) {
|
||||
$context = [
|
||||
'file' => $backtrace[0]['file'] ?? null,
|
||||
'line' => $backtrace[0]['line'] ?? null,
|
||||
'package' => $package,
|
||||
'link' => $link,
|
||||
];
|
||||
|
||||
assert(self::$logger !== null);
|
||||
|
||||
self::$logger->notice($message, $context);
|
||||
}
|
||||
|
||||
if (! (($type & self::TYPE_TRIGGER_ERROR) > 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message .= sprintf(
|
||||
' (%s:%d called by %s:%d, %s, package %s)',
|
||||
self::basename($backtrace[0]['file'] ?? 'native code'),
|
||||
$backtrace[0]['line'] ?? 0,
|
||||
self::basename($backtrace[1]['file'] ?? 'native code'),
|
||||
$backtrace[1]['line'] ?? 0,
|
||||
$link,
|
||||
$package
|
||||
);
|
||||
|
||||
@trigger_error($message, E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-local-aware version of PHPs basename function.
|
||||
*/
|
||||
private static function basename(string $filename): string
|
||||
{
|
||||
$pos = strrpos($filename, DIRECTORY_SEPARATOR);
|
||||
|
||||
if ($pos === false) {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
return substr($filename, $pos + 1);
|
||||
}
|
||||
|
||||
public static function enableTrackingDeprecations(): void
|
||||
{
|
||||
self::$type = self::$type ?? self::getTypeFromEnv();
|
||||
self::$type |= self::TYPE_TRACK_DEPRECATIONS;
|
||||
}
|
||||
|
||||
public static function enableWithTriggerError(): void
|
||||
{
|
||||
self::$type = self::$type ?? self::getTypeFromEnv();
|
||||
self::$type |= self::TYPE_TRIGGER_ERROR;
|
||||
}
|
||||
|
||||
public static function enableWithPsrLogger(LoggerInterface $logger): void
|
||||
{
|
||||
self::$type = self::$type ?? self::getTypeFromEnv();
|
||||
self::$type |= self::TYPE_PSR_LOGGER;
|
||||
self::$logger = $logger;
|
||||
}
|
||||
|
||||
public static function withoutDeduplication(): void
|
||||
{
|
||||
self::$deduplication = false;
|
||||
}
|
||||
|
||||
public static function disable(): void
|
||||
{
|
||||
self::$type = self::TYPE_NONE;
|
||||
self::$logger = null;
|
||||
self::$deduplication = true;
|
||||
self::$ignoredLinks = [];
|
||||
|
||||
foreach (self::$triggeredDeprecations as $link => $count) {
|
||||
self::$triggeredDeprecations[$link] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static function ignorePackage(string $packageName): void
|
||||
{
|
||||
self::$ignoredPackages[$packageName] = true;
|
||||
}
|
||||
|
||||
public static function ignoreDeprecations(string ...$links): void
|
||||
{
|
||||
foreach ($links as $link) {
|
||||
self::$ignoredLinks[$link] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getUniqueTriggeredDeprecationsCount(): int
|
||||
{
|
||||
return array_reduce(self::$triggeredDeprecations, static function (int $carry, int $count) {
|
||||
return $carry + $count;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns each triggered deprecation link identifier and the amount of occurrences.
|
||||
*
|
||||
* @return array<string,int>
|
||||
*/
|
||||
public static function getTriggeredDeprecations(): array
|
||||
{
|
||||
return self::$triggeredDeprecations;
|
||||
}
|
||||
|
||||
/** @return int-mask-of<self::TYPE_*> */
|
||||
private static function getTypeFromEnv(): int
|
||||
{
|
||||
switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) {
|
||||
case 'trigger':
|
||||
self::$type = self::TYPE_TRIGGER_ERROR;
|
||||
break;
|
||||
|
||||
case 'track':
|
||||
self::$type = self::TYPE_TRACK_DEPRECATIONS;
|
||||
break;
|
||||
|
||||
default:
|
||||
self::$type = self::TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return self::$type;
|
||||
}
|
||||
}
|
||||
66
vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php
vendored
Normal file
66
vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Deprecations\PHPUnit;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use PHPUnit\Framework\Attributes\After;
|
||||
use PHPUnit\Framework\Attributes\Before;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
trait VerifyDeprecations
|
||||
{
|
||||
/** @var array<string,int> */
|
||||
private $doctrineDeprecationsExpectations = [];
|
||||
|
||||
/** @var array<string,int> */
|
||||
private $doctrineNoDeprecationsExpectations = [];
|
||||
|
||||
public function expectDeprecationWithIdentifier(string $identifier): void
|
||||
{
|
||||
$this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
|
||||
}
|
||||
|
||||
public function expectNoDeprecationWithIdentifier(string $identifier): void
|
||||
{
|
||||
$this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
|
||||
}
|
||||
|
||||
/** @before */
|
||||
#[Before]
|
||||
public function enableDeprecationTracking(): void
|
||||
{
|
||||
Deprecation::enableTrackingDeprecations();
|
||||
}
|
||||
|
||||
/** @after */
|
||||
#[After]
|
||||
public function verifyDeprecationsAreTriggered(): void
|
||||
{
|
||||
foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
|
||||
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
|
||||
|
||||
$this->assertTrue(
|
||||
$actualCount > $expectation,
|
||||
sprintf(
|
||||
"Expected deprecation with identifier '%s' was not triggered by code executed in test.",
|
||||
$identifier
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
|
||||
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
|
||||
|
||||
$this->assertTrue(
|
||||
$actualCount === $expectation,
|
||||
sprintf(
|
||||
"Deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
|
||||
$identifier
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
vendor/doctrine/instantiator/LICENSE
vendored
Normal file
19
vendor/doctrine/instantiator/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 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.
|
||||
38
vendor/doctrine/instantiator/README.md
vendored
Normal file
38
vendor/doctrine/instantiator/README.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Doctrine Instantiator
|
||||
|
||||
This library provides a way of avoiding usage of constructors when instantiating PHP classes.
|
||||
|
||||
[](https://travis-ci.org/doctrine/instantiator)
|
||||
[](https://codecov.io/gh/doctrine/instantiator/branch/master)
|
||||
[](https://www.versioneye.com/package/php--doctrine--instantiator)
|
||||
|
||||
[](https://packagist.org/packages/doctrine/instantiator)
|
||||
[](https://packagist.org/packages/doctrine/instantiator)
|
||||
|
||||
## Installation
|
||||
|
||||
The suggested installation method is via [composer](https://getcomposer.org/):
|
||||
|
||||
```sh
|
||||
composer require doctrine/instantiator
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The instantiator is able to create new instances of any class without using the constructor or any API of the class
|
||||
itself:
|
||||
|
||||
```php
|
||||
$instantiator = new \Doctrine\Instantiator\Instantiator();
|
||||
|
||||
$instance = $instantiator->instantiate(\My\ClassName\Here::class);
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) contents if you wish to help out!
|
||||
|
||||
## Credits
|
||||
|
||||
This library was migrated from [ocramius/instantiator](https://github.com/Ocramius/Instantiator), which
|
||||
has been donated to the doctrine organization, and which is now deprecated in favour of this package.
|
||||
47
vendor/doctrine/instantiator/composer.json
vendored
Normal file
47
vendor/doctrine/instantiator/composer.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
||||
"keywords": [
|
||||
"instantiate",
|
||||
"constructor"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com",
|
||||
"homepage": "https://ocramius.github.io/"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-phar": "*",
|
||||
"ext-pdo": "*",
|
||||
"doctrine/coding-standard": "^14",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^10.5.58"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-0": {
|
||||
"DoctrineTest\\InstantiatorPerformance\\": "tests",
|
||||
"DoctrineTest\\InstantiatorTest\\": "tests",
|
||||
"DoctrineTest\\InstantiatorTestAsset\\": "tests"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
14
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php
vendored
Normal file
14
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Instantiator\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Base exception marker interface for the instantiator component
|
||||
*/
|
||||
interface ExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
52
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php
vendored
Normal file
52
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Instantiator\Exception;
|
||||
|
||||
use InvalidArgumentException as BaseInvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
|
||||
use function interface_exists;
|
||||
use function sprintf;
|
||||
use function trait_exists;
|
||||
|
||||
/**
|
||||
* Exception for invalid arguments provided to the instantiator
|
||||
*/
|
||||
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
public static function fromNonExistingClass(string $className): self
|
||||
{
|
||||
if (interface_exists($className)) {
|
||||
return new self(sprintf('The provided type "%s" is an interface, and cannot be instantiated', $className));
|
||||
}
|
||||
|
||||
if (trait_exists($className)) {
|
||||
return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className));
|
||||
}
|
||||
|
||||
return new self(sprintf('The provided class "%s" does not exist', $className));
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public static function fromAbstractClass(ReflectionClass $reflectionClass): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The provided class "%s" is abstract, and cannot be instantiated',
|
||||
$reflectionClass->getName(),
|
||||
));
|
||||
}
|
||||
|
||||
public static function fromEnum(string $className): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The provided class "%s" is an enum, and cannot be instantiated',
|
||||
$className,
|
||||
));
|
||||
}
|
||||
}
|
||||
61
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php
vendored
Normal file
61
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Instantiator\Exception;
|
||||
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
use UnexpectedValueException as BaseUnexpectedValueException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Exception for given parameters causing invalid/unexpected state on instantiation
|
||||
*/
|
||||
class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
|
||||
{
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public static function fromSerializationTriggeredException(
|
||||
ReflectionClass $reflectionClass,
|
||||
Exception $exception,
|
||||
): self {
|
||||
return new self(
|
||||
sprintf(
|
||||
'An exception was raised while trying to instantiate an instance of "%s" via un-serialization',
|
||||
$reflectionClass->getName(),
|
||||
),
|
||||
0,
|
||||
$exception,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public static function fromUncleanUnSerialization(
|
||||
ReflectionClass $reflectionClass,
|
||||
string $errorString,
|
||||
int $errorCode,
|
||||
string $errorFile,
|
||||
int $errorLine,
|
||||
): self {
|
||||
return new self(
|
||||
sprintf(
|
||||
'Could not produce an instance of "%s" via un-serialization, since an error was triggered '
|
||||
. 'in file "%s" at line "%d"',
|
||||
$reflectionClass->getName(),
|
||||
$errorFile,
|
||||
$errorLine,
|
||||
),
|
||||
0,
|
||||
new Exception($errorString, $errorCode),
|
||||
);
|
||||
}
|
||||
}
|
||||
253
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php
vendored
Normal file
253
vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Instantiator;
|
||||
|
||||
use ArrayIterator;
|
||||
use Doctrine\Instantiator\Exception\ExceptionInterface;
|
||||
use Doctrine\Instantiator\Exception\InvalidArgumentException;
|
||||
use Doctrine\Instantiator\Exception\UnexpectedValueException;
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Serializable;
|
||||
|
||||
use function class_exists;
|
||||
use function enum_exists;
|
||||
use function is_subclass_of;
|
||||
use function restore_error_handler;
|
||||
use function set_error_handler;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function unserialize;
|
||||
|
||||
final class Instantiator implements InstantiatorInterface
|
||||
{
|
||||
/**
|
||||
* Markers used internally by PHP to define whether {@see \unserialize} should invoke
|
||||
* the method {@see \Serializable::unserialize()} when dealing with classes implementing
|
||||
* the {@see \Serializable} interface.
|
||||
*/
|
||||
private const string SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
|
||||
private const string SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';
|
||||
|
||||
/**
|
||||
* Used to instantiate specific classes, indexed by class name.
|
||||
*
|
||||
* @var array<class-string, callable(): object>
|
||||
*/
|
||||
private static array $cachedInstantiators = [];
|
||||
|
||||
/**
|
||||
* Array of objects that can directly be cloned, indexed by class name.
|
||||
*
|
||||
* @var object[]
|
||||
*/
|
||||
private static array $cachedCloneables = [];
|
||||
|
||||
/**
|
||||
* @phpstan-param class-string<T> $className
|
||||
*
|
||||
* @phpstan-return T
|
||||
*
|
||||
* @throws ExceptionInterface
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function instantiate(string $className): object
|
||||
{
|
||||
if (isset(self::$cachedCloneables[$className])) {
|
||||
/** @phpstan-var T */
|
||||
$cachedCloneable = self::$cachedCloneables[$className];
|
||||
|
||||
return clone $cachedCloneable;
|
||||
}
|
||||
|
||||
if (isset(self::$cachedInstantiators[$className])) {
|
||||
$factory = self::$cachedInstantiators[$className];
|
||||
|
||||
return $factory();
|
||||
}
|
||||
|
||||
return $this->buildAndCacheFromFactory($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the requested object and caches it in static properties for performance
|
||||
*
|
||||
* @phpstan-param class-string<T> $className
|
||||
*
|
||||
* @phpstan-return T
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function buildAndCacheFromFactory(string $className): object
|
||||
{
|
||||
$factory = self::$cachedInstantiators[$className] = $this->buildFactory($className);
|
||||
$instance = $factory();
|
||||
|
||||
if ($this->isSafeToClone(new ReflectionClass($instance))) {
|
||||
self::$cachedCloneables[$className] = clone $instance;
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a callable capable of instantiating the given $className without
|
||||
* invoking its constructor.
|
||||
*
|
||||
* @phpstan-param class-string<T> $className
|
||||
*
|
||||
* @phpstan-return callable(): T
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws UnexpectedValueException
|
||||
* @throws ReflectionException
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function buildFactory(string $className): callable
|
||||
{
|
||||
$reflectionClass = $this->getReflectionClass($className);
|
||||
|
||||
if ($this->isInstantiableViaReflection($reflectionClass)) {
|
||||
return [$reflectionClass, 'newInstanceWithoutConstructor'];
|
||||
}
|
||||
|
||||
$serializedString = sprintf(
|
||||
'%s:%d:"%s":0:{}',
|
||||
is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER,
|
||||
strlen($className),
|
||||
$className,
|
||||
);
|
||||
|
||||
$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);
|
||||
|
||||
return static fn () => unserialize($serializedString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param class-string<T> $className
|
||||
*
|
||||
* @phpstan-return ReflectionClass<T>
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ReflectionException
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function getReflectionClass(string $className): ReflectionClass
|
||||
{
|
||||
if (! class_exists($className)) {
|
||||
throw InvalidArgumentException::fromNonExistingClass($className);
|
||||
}
|
||||
|
||||
if (enum_exists($className, false)) {
|
||||
throw InvalidArgumentException::fromEnum($className);
|
||||
}
|
||||
|
||||
$reflection = new ReflectionClass($className);
|
||||
|
||||
if ($reflection->isAbstract()) {
|
||||
throw InvalidArgumentException::fromAbstractClass($reflection);
|
||||
}
|
||||
|
||||
return $reflection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString): void
|
||||
{
|
||||
set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error): bool {
|
||||
$error = UnexpectedValueException::fromUncleanUnSerialization(
|
||||
$reflectionClass,
|
||||
$message,
|
||||
$code,
|
||||
$file,
|
||||
$line,
|
||||
);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
try {
|
||||
$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
throw $error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void
|
||||
{
|
||||
try {
|
||||
unserialize($serializedString);
|
||||
} catch (Exception $exception) {
|
||||
throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool
|
||||
{
|
||||
return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether the given class is to be considered internal
|
||||
*
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function hasInternalAncestors(ReflectionClass $reflectionClass): bool
|
||||
{
|
||||
do {
|
||||
if ($reflectionClass->isInternal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$reflectionClass = $reflectionClass->getParentClass();
|
||||
} while ($reflectionClass);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a class is cloneable
|
||||
*
|
||||
* Classes implementing `__clone` cannot be safely cloned, as that may cause side-effects.
|
||||
*
|
||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function isSafeToClone(ReflectionClass $reflectionClass): bool
|
||||
{
|
||||
return $reflectionClass->isCloneable()
|
||||
&& ! $reflectionClass->hasMethod('__clone')
|
||||
&& ! $reflectionClass->isSubclassOf(ArrayIterator::class);
|
||||
}
|
||||
}
|
||||
24
vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php
vendored
Normal file
24
vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Instantiator;
|
||||
|
||||
use Doctrine\Instantiator\Exception\ExceptionInterface;
|
||||
|
||||
/**
|
||||
* Instantiator provides utility methods to build objects without invoking their constructors
|
||||
*/
|
||||
interface InstantiatorInterface
|
||||
{
|
||||
/**
|
||||
* @phpstan-param class-string<T> $className
|
||||
*
|
||||
* @phpstan-return T
|
||||
*
|
||||
* @throws ExceptionInterface
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function instantiate(string $className): object;
|
||||
}
|
||||
19
vendor/doctrine/lexer/LICENSE
vendored
Normal file
19
vendor/doctrine/lexer/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2018 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.
|
||||
9
vendor/doctrine/lexer/README.md
vendored
Normal file
9
vendor/doctrine/lexer/README.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Doctrine Lexer
|
||||
|
||||
[](https://github.com/doctrine/lexer/actions)
|
||||
|
||||
Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
|
||||
|
||||
This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
|
||||
|
||||
https://www.doctrine-project.org/projects/lexer.html
|
||||
22
vendor/doctrine/lexer/UPGRADE.md
vendored
Normal file
22
vendor/doctrine/lexer/UPGRADE.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
|
||||
awareness about deprecated code.
|
||||
|
||||
- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
|
||||
Static Analysis tools (like Psalm, phpstan)
|
||||
- Use of our low-overhead runtime deprecation API, details:
|
||||
https://github.com/doctrine/deprecations/
|
||||
|
||||
# Upgrade to 3.0.0
|
||||
|
||||
`Doctrine\Common\Lexer\Token` no longer implements `ArrayAccess`.
|
||||
Parameter type declarations have been added to
|
||||
`Doctrine\Common\Lexer\AbstractLexer` and `Doctrine\Common\Lexer\Token`.
|
||||
You should add both parameter type declarations and return type declarations to
|
||||
your lexers, based on the `@return` phpdoc.
|
||||
|
||||
# Upgrade to 2.0.0
|
||||
|
||||
`AbstractLexer::glimpse()` and `AbstractLexer::peek()` now return
|
||||
instances of `Doctrine\Common\Lexer\Token`, which is an array-like class
|
||||
Using it as an array is deprecated in favor of using properties of that class.
|
||||
Using `count()` on it is deprecated with no replacement.
|
||||
55
vendor/doctrine/lexer/composer.json
vendored
Normal file
55
vendor/doctrine/lexer/composer.json
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"php",
|
||||
"parser",
|
||||
"lexer",
|
||||
"annotations",
|
||||
"docblock"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^12",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"psalm/plugin-phpunit": "^0.18.3",
|
||||
"vimeo/psalm": "^5.21"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Lexer\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\Common\\Lexer\\": "tests"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
}
|
||||
}
|
||||
328
vendor/doctrine/lexer/src/AbstractLexer.php
vendored
Normal file
328
vendor/doctrine/lexer/src/AbstractLexer.php
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Common\Lexer;
|
||||
|
||||
use ReflectionClass;
|
||||
use UnitEnum;
|
||||
|
||||
use function implode;
|
||||
use function preg_split;
|
||||
use function sprintf;
|
||||
use function substr;
|
||||
|
||||
use const PREG_SPLIT_DELIM_CAPTURE;
|
||||
use const PREG_SPLIT_NO_EMPTY;
|
||||
use const PREG_SPLIT_OFFSET_CAPTURE;
|
||||
|
||||
/**
|
||||
* Base class for writing simple lexers, i.e. for creating small DSLs.
|
||||
*
|
||||
* @template T of UnitEnum|string|int
|
||||
* @template V of string|int
|
||||
*/
|
||||
abstract class AbstractLexer
|
||||
{
|
||||
/**
|
||||
* Lexer original input string.
|
||||
*/
|
||||
private string $input;
|
||||
|
||||
/**
|
||||
* Array of scanned tokens.
|
||||
*
|
||||
* @var list<Token<T, V>>
|
||||
*/
|
||||
private array $tokens = [];
|
||||
|
||||
/**
|
||||
* Current lexer position in input string.
|
||||
*/
|
||||
private int $position = 0;
|
||||
|
||||
/**
|
||||
* Current peek of current lexer position.
|
||||
*/
|
||||
private int $peek = 0;
|
||||
|
||||
/**
|
||||
* The next token in the input.
|
||||
*
|
||||
* @var Token<T, V>|null
|
||||
*/
|
||||
public Token|null $lookahead;
|
||||
|
||||
/**
|
||||
* The last matched/seen token.
|
||||
*
|
||||
* @var Token<T, V>|null
|
||||
*/
|
||||
public Token|null $token;
|
||||
|
||||
/**
|
||||
* Composed regex for input parsing.
|
||||
*
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private string|null $regex = null;
|
||||
|
||||
/**
|
||||
* Sets the input data to be tokenized.
|
||||
*
|
||||
* The Lexer is immediately reset and the new input tokenized.
|
||||
* Any unprocessed tokens from any previous input are lost.
|
||||
*
|
||||
* @param string $input The input to be tokenized.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setInput(string $input)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->tokens = [];
|
||||
|
||||
$this->reset();
|
||||
$this->scan($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->lookahead = null;
|
||||
$this->token = null;
|
||||
$this->peek = 0;
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the peek pointer to 0.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetPeek()
|
||||
{
|
||||
$this->peek = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the lexer position on the input to the given position.
|
||||
*
|
||||
* @param int $position Position to place the lexical scanner.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetPosition(int $position = 0)
|
||||
{
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the original lexer's input until a given position.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputUntilPosition(int $position)
|
||||
{
|
||||
return substr($this->input, 0, $position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given token matches the current lookahead.
|
||||
*
|
||||
* @param T $type
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @psalm-assert-if-true !=null $this->lookahead
|
||||
*/
|
||||
public function isNextToken(int|string|UnitEnum $type)
|
||||
{
|
||||
return $this->lookahead !== null && $this->lookahead->isA($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any of the given tokens matches the current lookahead.
|
||||
*
|
||||
* @param list<T> $types
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @psalm-assert-if-true !=null $this->lookahead
|
||||
*/
|
||||
public function isNextTokenAny(array $types)
|
||||
{
|
||||
return $this->lookahead !== null && $this->lookahead->isA(...$types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the next token in the input string.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @psalm-assert-if-true !null $this->lookahead
|
||||
*/
|
||||
public function moveNext()
|
||||
{
|
||||
$this->peek = 0;
|
||||
$this->token = $this->lookahead;
|
||||
$this->lookahead = isset($this->tokens[$this->position])
|
||||
? $this->tokens[$this->position++] : null;
|
||||
|
||||
return $this->lookahead !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the lexer to skip input tokens until it sees a token with the given value.
|
||||
*
|
||||
* @param T $type The token type to skip until.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function skipUntil(int|string|UnitEnum $type)
|
||||
{
|
||||
while ($this->lookahead !== null && ! $this->lookahead->isA($type)) {
|
||||
$this->moveNext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given value is identical to the given token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isA(string $value, int|string|UnitEnum $token)
|
||||
{
|
||||
return $this->getType($value) === $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the lookahead token forward.
|
||||
*
|
||||
* @return Token<T, V>|null The next token or NULL if there are no more tokens ahead.
|
||||
*/
|
||||
public function peek()
|
||||
{
|
||||
if (isset($this->tokens[$this->position + $this->peek])) {
|
||||
return $this->tokens[$this->position + $this->peek++];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at the next token, returns it and immediately resets the peek.
|
||||
*
|
||||
* @return Token<T, V>|null The next token or NULL if there are no more tokens ahead.
|
||||
*/
|
||||
public function glimpse()
|
||||
{
|
||||
$peek = $this->peek();
|
||||
$this->peek = 0;
|
||||
|
||||
return $peek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the input string for tokens.
|
||||
*
|
||||
* @param string $input A query string.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function scan(string $input)
|
||||
{
|
||||
if (! isset($this->regex)) {
|
||||
$this->regex = sprintf(
|
||||
'/(%s)|%s/%s',
|
||||
implode(')|(', $this->getCatchablePatterns()),
|
||||
implode('|', $this->getNonCatchablePatterns()),
|
||||
$this->getModifiers(),
|
||||
);
|
||||
}
|
||||
|
||||
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
|
||||
$matches = preg_split($this->regex, $input, -1, $flags);
|
||||
|
||||
if ($matches === false) {
|
||||
// Work around https://bugs.php.net/78122
|
||||
$matches = [[$input, 0]];
|
||||
}
|
||||
|
||||
foreach ($matches as $match) {
|
||||
// Must remain before 'value' assignment since it can change content
|
||||
$firstMatch = $match[0];
|
||||
$type = $this->getType($firstMatch);
|
||||
|
||||
$this->tokens[] = new Token(
|
||||
$firstMatch,
|
||||
$type,
|
||||
$match[1],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the literal for a given token.
|
||||
*
|
||||
* @param T $token
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public function getLiteral(int|string|UnitEnum $token)
|
||||
{
|
||||
if ($token instanceof UnitEnum) {
|
||||
return $token::class . '::' . $token->name;
|
||||
}
|
||||
|
||||
$className = static::class;
|
||||
|
||||
$reflClass = new ReflectionClass($className);
|
||||
$constants = $reflClass->getConstants();
|
||||
|
||||
foreach ($constants as $name => $value) {
|
||||
if ($value === $token) {
|
||||
return $className . '::' . $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regex modifiers
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getModifiers()
|
||||
{
|
||||
return 'iu';
|
||||
}
|
||||
|
||||
/**
|
||||
* Lexical catchable patterns.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
abstract protected function getCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Lexical non-catchable patterns.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
abstract protected function getNonCatchablePatterns();
|
||||
|
||||
/**
|
||||
* Retrieve token type. Also processes the token value if necessary.
|
||||
*
|
||||
* @return T|null
|
||||
*
|
||||
* @param-out V $value
|
||||
*/
|
||||
abstract protected function getType(string &$value);
|
||||
}
|
||||
56
vendor/doctrine/lexer/src/Token.php
vendored
Normal file
56
vendor/doctrine/lexer/src/Token.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Common\Lexer;
|
||||
|
||||
use UnitEnum;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @template T of UnitEnum|string|int
|
||||
* @template V of string|int
|
||||
*/
|
||||
final class Token
|
||||
{
|
||||
/**
|
||||
* The string value of the token in the input string
|
||||
*
|
||||
* @readonly
|
||||
* @var V
|
||||
*/
|
||||
public string|int $value;
|
||||
|
||||
/**
|
||||
* The type of the token (identifier, numeric, string, input parameter, none)
|
||||
*
|
||||
* @readonly
|
||||
* @var T|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* The position of the token in the input string
|
||||
*
|
||||
* @readonly
|
||||
*/
|
||||
public int $position;
|
||||
|
||||
/**
|
||||
* @param V $value
|
||||
* @param T|null $type
|
||||
*/
|
||||
public function __construct(string|int $value, $type, int $position)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->type = $type;
|
||||
$this->position = $position;
|
||||
}
|
||||
|
||||
/** @param T ...$types */
|
||||
public function isA(...$types): bool
|
||||
{
|
||||
return in_array($this->type, $types, true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user