20250203
This commit is contained in:
parent
f1a79d66ec
commit
dd62ad0ca4
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Файлы, игнорируемые по умолчанию
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Запросы HTTP-клиента в редакторе
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
43
.idea/anb_php_components_pack.iml
generated
Normal file
43
.idea/anb_php_components_pack.iml
generated
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?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$/sources" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/classes" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\classes\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/enums" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\enums\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/extensions" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\extensions\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/interfaces" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\interfaces\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/models" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\models\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/sources/traits" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\traits\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\tests\" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
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/anb_php_components_pack.iml" filepath="$PROJECT_DIR$/.idea/anb_php_components_pack.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
14
.idea/php-test-framework.xml
generated
Normal file
14
.idea/php-test-framework.xml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpTestFrameworkVersionCache">
|
||||||
|
<tools_cache>
|
||||||
|
<tool tool_name="PHPUnit">
|
||||||
|
<cache>
|
||||||
|
<versions>
|
||||||
|
<info id="локальныйD:\Program Files\PHPStorm dependens\PHPUnit\phpunit.phar" version="11.5.6" />
|
||||||
|
</versions>
|
||||||
|
</cache>
|
||||||
|
</tool>
|
||||||
|
</tools_cache>
|
||||||
|
</component>
|
||||||
|
</project>
|
55
.idea/php.xml
generated
Normal file
55
.idea/php.xml
generated
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?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$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
||||||
|
<component name="PhpStanOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpUnit">
|
||||||
|
<phpunit_settings>
|
||||||
|
<PhpUnitSettings load_method="PHPUNIT_PHAR" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" phpunit_phar_path="$PROJECT_DIR$/../../Program Files/PHPStorm dependens/PHPUnit/phpunit.phar" />
|
||||||
|
</phpunit_settings>
|
||||||
|
</component>
|
||||||
|
<component name="PsalmOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
10
.idea/phpunit.xml
generated
Normal file
10
.idea/phpunit.xml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PHPUnit">
|
||||||
|
<option name="directories">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/tests" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
36
composer.json
Normal file
36
composer.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "goodboyalex/php_components_pack",
|
||||||
|
"description": "[RU] Набор компонентов для сайта на PHP / [EN] A set of components for PHP website",
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"keywords": [
|
||||||
|
"components"
|
||||||
|
],
|
||||||
|
"homepage": "https://gitverse.ru/babaev-an/anb_php_components_pack",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"type": "library",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alexander Babaev",
|
||||||
|
"email": "contact_with_us@babaev-an.ru"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.4",
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": ">=11.5.6"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"goodboyalex\\php_components_pack\\": "sources",
|
||||||
|
"goodboyalex\\php_components_pack\\classes\\": "sources/classes",
|
||||||
|
"goodboyalex\\php_components_pack\\enums\\": "sources/enums",
|
||||||
|
"goodboyalex\\php_components_pack\\extensions\\": "sources/extensions",
|
||||||
|
"goodboyalex\\php_components_pack\\interfaces\\": "sources/interfaces",
|
||||||
|
"goodboyalex\\php_components_pack\\models\\": "sources/models",
|
||||||
|
"goodboyalex\\php_components_pack\\traits\\": "sources/traits",
|
||||||
|
"goodboyalex\\php_components_pack\\tests\\": "tests"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1613
composer.lock
generated
Normal file
1613
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
6
index.php
Normal file
6
index.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
require_once __DIR__ . '/sources/extensions/StringExtension.php';
|
||||||
|
|
||||||
|
echo \goodboyalex\php_components_pack\extensions\StringExtension::ConvertToLatin("тест");
|
363
sources/classes/ActionState.php
Normal file
363
sources/classes/ActionState.php
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Отключаем ненужные проверки.
|
||||||
|
*
|
||||||
|
* @noinspection PhpUnusedParameterInspection, PhpUnused
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\classes;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use goodboyalex\php_components_pack\enums\MessageType;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\ISerializable;
|
||||||
|
use goodboyalex\php_components_pack\models\ActionStateMessageModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Состояние действия.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ActionState implements ISerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var mixed|null $Value Значение
|
||||||
|
*/
|
||||||
|
public mixed $Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array $Messages Список информации
|
||||||
|
*/
|
||||||
|
private array $Messages = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param mixed|null $defValue Значение по умолчанию
|
||||||
|
*/
|
||||||
|
public function __construct (mixed $defValue = null)
|
||||||
|
{
|
||||||
|
$this->Value = $defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* При выводе GetStringMessages выводит только ошибки.
|
||||||
|
*
|
||||||
|
* @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу.
|
||||||
|
*/
|
||||||
|
public static function GET_STRING_ERROR_ONLY (): Closure
|
||||||
|
{
|
||||||
|
return fn (ActionStateMessageModel $message)
|
||||||
|
=> $message->MessageType === MessageType::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* При выводе GetStringMessages выводит ошибки и предупреждения.
|
||||||
|
*
|
||||||
|
* @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу.
|
||||||
|
*/
|
||||||
|
public static function GET_STRING_ERROR_AND_WARNING (): Closure
|
||||||
|
{
|
||||||
|
return fn (ActionStateMessageModel $message)
|
||||||
|
=> $message->MessageType === MessageType::Error
|
||||||
|
|| $message->MessageType === MessageType::Warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* При выводе GetStringMessages выводит все сообщения.
|
||||||
|
*
|
||||||
|
* @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу.
|
||||||
|
*/
|
||||||
|
public static function GET_STRING_ALL (): Closure
|
||||||
|
{
|
||||||
|
return fn (ActionStateMessageModel $message) => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет данные из другого состояния.
|
||||||
|
*
|
||||||
|
* @param ActionState $state Другое состояние
|
||||||
|
* @param bool $clearAllBefore Очищать сообщения перед добавлением (true) или просто добавить к текущим (false)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddState (ActionState $state, bool $clearAllBefore = false): void
|
||||||
|
{
|
||||||
|
// Если нужно очистить список сообщений
|
||||||
|
if ($clearAllBefore)
|
||||||
|
// - то очищаю список сообщений
|
||||||
|
$this->Clear(fn (ActionStateMessageModel $message) => true);
|
||||||
|
|
||||||
|
// Добавляю сообщения из другого состояния
|
||||||
|
$this->AddRange($state->GetMessages(function (ActionStateMessageModel $message)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Добавляю значение
|
||||||
|
$this->Value = $state->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Очищает список сообщений, согласно условию.
|
||||||
|
*
|
||||||
|
* @param callable $predicate Условие выборки
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function Clear (callable $predicate): void
|
||||||
|
{
|
||||||
|
// Выбираю все сообщения, удовлетворяющие условию
|
||||||
|
$list = $this->GetMessages($predicate);
|
||||||
|
|
||||||
|
// Удаляю их из списка
|
||||||
|
$this->Messages = array_diff($this->Messages, $list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выбирает сообщения по условию predicate.
|
||||||
|
*
|
||||||
|
* @param callable $predicate Условие выборки
|
||||||
|
*
|
||||||
|
* @return array Список отобранных сообщений
|
||||||
|
*/
|
||||||
|
public function GetMessages (callable $predicate): array
|
||||||
|
{
|
||||||
|
// Получаю список элементов
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
// Для каждого элемента
|
||||||
|
foreach ($this->Messages as $actionStateMessage)
|
||||||
|
// - если он подходит под условие
|
||||||
|
if ($predicate($actionStateMessage))
|
||||||
|
// - добавляю его в список
|
||||||
|
$list[] = $actionStateMessage;
|
||||||
|
|
||||||
|
// Возвращаю список
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет список
|
||||||
|
*
|
||||||
|
* @param array $messages Список сообщений
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddRange (array $messages): void
|
||||||
|
{
|
||||||
|
$this->Messages = array_merge($this->Messages, $messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает список сообщений (параметр Message у каждого сообщения).
|
||||||
|
*
|
||||||
|
* @param callable $predicate Условие выборки
|
||||||
|
* @param string $separator Разделитель
|
||||||
|
*
|
||||||
|
* @return string Список сообщений
|
||||||
|
*/
|
||||||
|
public function GetStringMessages (callable $predicate, string $separator = '\n'): string
|
||||||
|
{
|
||||||
|
// Делаю выборку
|
||||||
|
$list = $this->GetMessages($predicate);
|
||||||
|
|
||||||
|
// Формирую список сообщений
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Для каждого сообщения из выборки
|
||||||
|
foreach ($list as $message) {
|
||||||
|
// - если оно не нужного нам класса
|
||||||
|
if (!$message instanceof ActionStateMessageModel)
|
||||||
|
// -- то пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - добавляю сообщение
|
||||||
|
$result[] = $message->Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю список
|
||||||
|
return implode($separator, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет сообщение о критической ошибке.
|
||||||
|
*
|
||||||
|
* @param string $message Сообщение
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddCritical (string $message): void
|
||||||
|
{
|
||||||
|
$this->Add(new ActionStateMessageModel(MessageType::Error, true, $message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление сообщения.
|
||||||
|
*
|
||||||
|
* @param ActionStateMessageModel $message Сообщение
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function Add (ActionStateMessageModel $message): void
|
||||||
|
{
|
||||||
|
$this->Messages[] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет сообщение об ошибке.
|
||||||
|
*
|
||||||
|
* @param string $message Сообщение
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddError (string $message): void
|
||||||
|
{
|
||||||
|
$this->Add(new ActionStateMessageModel(MessageType::Error, false, $message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет предупреждение.
|
||||||
|
*
|
||||||
|
* @param string $message Сообщение.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddWarning (string $message): void
|
||||||
|
{
|
||||||
|
$this->Add(new ActionStateMessageModel(MessageType::Warning, false, $message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавляет информационное сообщение.
|
||||||
|
*
|
||||||
|
* @param string $message Сообщение.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function AddInfo (string $message): void
|
||||||
|
{
|
||||||
|
$this->Add(new ActionStateMessageModel(MessageType::Info, false, $message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, есть ли информационные сообщения.
|
||||||
|
*
|
||||||
|
* @return bool Наличие сообщений
|
||||||
|
*/
|
||||||
|
public function HasInfos (): bool
|
||||||
|
{
|
||||||
|
return $this->Count(fn (ActionStateMessageModel $message) => $message->MessageType == MessageType::Info) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Количество сообщений, удовлетворяющих условию.
|
||||||
|
*
|
||||||
|
* @param callable $predicate Условие выборки
|
||||||
|
*
|
||||||
|
* @return int Число сообщений
|
||||||
|
*/
|
||||||
|
public function Count (callable $predicate): int
|
||||||
|
{
|
||||||
|
// Получаю список сообщений
|
||||||
|
$list = $this->GetMessages($predicate);
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return count($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, успешно ли завершилась операция.
|
||||||
|
*
|
||||||
|
* @param bool $onlyCritical Игнорировать все некритические ошибки и предупреждения (не рекомендуется!)
|
||||||
|
*
|
||||||
|
* @return bool Успешно ли завершилась операция.
|
||||||
|
*/
|
||||||
|
public function IsSuccess (bool $onlyCritical = false): bool
|
||||||
|
{
|
||||||
|
// Если нужно учитывать только критические ошибки
|
||||||
|
if ($onlyCritical)
|
||||||
|
// - то проверяю наличие критических ошибок
|
||||||
|
return !$this->HasErrors($onlyCritical);
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return !$this->HasErrors() && !$this->HasWarnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, есть ли ошибки.
|
||||||
|
*
|
||||||
|
* @param bool $onlyCritical Учитывать только критические ошибки.
|
||||||
|
*
|
||||||
|
* @return bool Наличие ошибок.
|
||||||
|
*/
|
||||||
|
public function HasErrors (bool $onlyCritical = false): bool
|
||||||
|
{
|
||||||
|
return $this->Count(function (ActionStateMessageModel $message) use ($onlyCritical): bool
|
||||||
|
{
|
||||||
|
// - сравниваю тип сообщения
|
||||||
|
if ($message->MessageType != MessageType::Error)
|
||||||
|
// -- если не совпадает, то возвращаю false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// - если нужно выводить только критические ошибки, а сообщение не критическое
|
||||||
|
if ($onlyCritical && !$message->IsCritical)
|
||||||
|
// -- то возвращаю false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Возвращаю true
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, есть ли предупреждения.
|
||||||
|
*
|
||||||
|
* @return bool Наличие предупреждений
|
||||||
|
*/
|
||||||
|
public function HasWarnings (): bool
|
||||||
|
{
|
||||||
|
return $this->Count(fn (ActionStateMessageModel $message) => $message->MessageType == MessageType::Warning) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function Serialize (): string
|
||||||
|
{
|
||||||
|
// Создаю список сообщений
|
||||||
|
$list = [];
|
||||||
|
|
||||||
|
// Для каждого сообщения
|
||||||
|
foreach ($this->Messages as $message)
|
||||||
|
// - сериализую его и добавляю в список
|
||||||
|
$list[] = $message->Serialize();
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return serialize($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function UnSerialize (string $serialized): void
|
||||||
|
{
|
||||||
|
// Очищаю список сообщений
|
||||||
|
$this->Clear(fn (ActionStateMessageModel $message) => true);
|
||||||
|
|
||||||
|
// Десериализую список сообщений
|
||||||
|
$list = unserialize($serialized);
|
||||||
|
|
||||||
|
// Для каждого сообщения
|
||||||
|
foreach ($list as $messageSerialized) {
|
||||||
|
// - создаю новое сообщение
|
||||||
|
$message = new ActionStateMessageModel();
|
||||||
|
// - десериализую его
|
||||||
|
$message->UnSerialize($messageSerialized);
|
||||||
|
// - добавляю в список
|
||||||
|
$this->Add($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
335
sources/classes/ClassMapper.php
Normal file
335
sources/classes/ClassMapper.php
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\classes;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use Exception;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionException;
|
||||||
|
use stdClass;
|
||||||
|
use UnitEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс сопоставлений классов и объектов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ClassMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array $DefaultOptions Настройки
|
||||||
|
*/
|
||||||
|
public const array DefaultOptions = [
|
||||||
|
'ignored' => [],
|
||||||
|
'allowed' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Передаёт одинаковые параметры из класса $from в класс $to, учитывая игнорируемые ($ignoredProperties) и
|
||||||
|
* разрешенные ($allowedProperties) свойства.
|
||||||
|
*
|
||||||
|
* @param object $from Класс-донор
|
||||||
|
* @param object $to Класс-приемник
|
||||||
|
* @param array $options Параметры привязки свойств (см атрибут Bind).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function MapClass (object $from, object $to, array $options = self::DefaultOptions): void
|
||||||
|
{
|
||||||
|
// Если есть игнорируемые или разрешенные свойства
|
||||||
|
if (!(count($options['ignored']) == 0 && count($options['allowed']) == 0))
|
||||||
|
// -- то для каждого игнорируемого свойства
|
||||||
|
foreach ($options['ignored'] as $ignoredProperty)
|
||||||
|
// --- и если оно есть в массиве разрешенных
|
||||||
|
if (in_array($ignoredProperty, $options['allowed']))
|
||||||
|
// ---- то исключаю его из массива разрешенных
|
||||||
|
unset($options['allowed'][array_search($ignoredProperty, $options['allowed'])]);
|
||||||
|
|
||||||
|
// Получаю массив свойств
|
||||||
|
$properties = get_class_vars(get_class($from));
|
||||||
|
|
||||||
|
// Для каждого элемента массива
|
||||||
|
foreach ($properties as $name => $value) {
|
||||||
|
// - если свойство игнорируется
|
||||||
|
if (in_array($name, $options['ignored']))
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если свойство не разрешено
|
||||||
|
if (count($options['allowed']) > 0 && !in_array($name, $options['allowed']))
|
||||||
|
// -- пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если свойство есть в объекте
|
||||||
|
if (property_exists($to, $name))
|
||||||
|
// -- то присваиваю значение
|
||||||
|
$to->$name = $from->$name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подготавливает значения свойств класса.
|
||||||
|
*
|
||||||
|
* @param array $params Данные запроса.
|
||||||
|
* @param ReflectionClass $classReflector Анализатор класса.
|
||||||
|
* @param array $options Массив свойств привязки.
|
||||||
|
*
|
||||||
|
* @return array Массив данных класса.
|
||||||
|
*/
|
||||||
|
public static function PrepareClassProperties (array $params, ReflectionClass $classReflector,
|
||||||
|
array $options = self::DefaultOptions): array
|
||||||
|
{
|
||||||
|
// Создаю массив данных класса
|
||||||
|
$classData = [];
|
||||||
|
|
||||||
|
// Для каждого свойства класса
|
||||||
|
foreach ($classReflector->getProperties() as $property) {
|
||||||
|
// - получаю имя свойства
|
||||||
|
$propertyName = $property->getName();
|
||||||
|
|
||||||
|
// - если это свойство задано в массиве параметров
|
||||||
|
if (array_key_exists($propertyName, $params)) {
|
||||||
|
// -- если задан массив разрешённых свойств
|
||||||
|
if (!empty($options["allowed"]))
|
||||||
|
// --- если свойство не разрешено
|
||||||
|
if (!in_array($propertyName, $options["allowed"]))
|
||||||
|
// ---- то пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// -- если задан массив запрещённых свойств
|
||||||
|
if (!empty($options["ignored"]))
|
||||||
|
// --- если свойство должно игнорироваться
|
||||||
|
if (in_array($propertyName, $options["ignored"]))
|
||||||
|
// ---- то пропускаю
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// -- добавляю значение свойства в результат
|
||||||
|
$classData[$propertyName] = $params[$propertyName];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// - в противном случае, пробегаю массив параметров
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
// -- если в имени параметра есть разделитель "_"
|
||||||
|
if (str_starts_with($key, $propertyName . "_")) {
|
||||||
|
// -- разбиваю имя параметра на части
|
||||||
|
$keyParts = explode("_", $key);
|
||||||
|
|
||||||
|
// -- добавляю значение свойства в результат
|
||||||
|
self::GetClassParametersArrayParser($classData, $keyParts, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю массив данных класса
|
||||||
|
return $classData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Парсит массив свойств класса.
|
||||||
|
*
|
||||||
|
* @param array $source Исходный массив (он же и результат парсинга).
|
||||||
|
* @param array $parametersKeys Массив имен свойств. Например, Page_Meta_Id должен быть разбит на
|
||||||
|
* ["Page", "Meta", "Id"].
|
||||||
|
* @param mixed $value Значение свойства.
|
||||||
|
* @param array $options Массив параметров привязки свойств.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function GetClassParametersArrayParser (array &$source, array $parametersKeys, mixed $value,
|
||||||
|
array $options = self::DefaultOptions): void
|
||||||
|
{
|
||||||
|
// Если массив имен свойств пустой
|
||||||
|
if (empty($parametersKeys))
|
||||||
|
// - то прерываю парсинг
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Получаю имя текущего свойства
|
||||||
|
$currentName = array_shift($parametersKeys);
|
||||||
|
|
||||||
|
// Если текущего свойства нет в массиве
|
||||||
|
if (!isset($source[$currentName]))
|
||||||
|
// - то создаю его
|
||||||
|
$source[$currentName] = [];
|
||||||
|
|
||||||
|
// Если массив имен свойств содержит только одно свойство
|
||||||
|
if (count($parametersKeys) === 0) {
|
||||||
|
// - если задан массив разрешённых свойств
|
||||||
|
if (!empty($options["allowed"]))
|
||||||
|
// --- если свойство не разрешено
|
||||||
|
if (!in_array($currentName, $options["allowed"]))
|
||||||
|
// ---- то пропускаю
|
||||||
|
return;
|
||||||
|
|
||||||
|
// -- если задан массив запрещённых свойств
|
||||||
|
if (!empty($options["ignored"]))
|
||||||
|
// --- если свойство должно игнорироваться
|
||||||
|
if (in_array($currentName, $options["ignored"]))
|
||||||
|
// ---- то пропускаю
|
||||||
|
return;
|
||||||
|
|
||||||
|
// - добавляю значение свойства в результат
|
||||||
|
$source[$currentName] = $value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// - иначе продолжаю парсинг
|
||||||
|
self::GetClassParametersArrayParser($source[$currentName], $parametersKeys, $value, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Переводит данные из массива в объект класса.
|
||||||
|
*
|
||||||
|
* @param string $className Имя класса
|
||||||
|
* @param array $properties Массив данных
|
||||||
|
*
|
||||||
|
* @return mixed Объект класса
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function MapToClassProperty (string $className, array $properties): mixed
|
||||||
|
{
|
||||||
|
// Создаю
|
||||||
|
try {
|
||||||
|
$classReflector = new ReflectionClass($className);
|
||||||
|
|
||||||
|
// Создаю объект класса
|
||||||
|
$classObj = new $className();
|
||||||
|
|
||||||
|
// Для каждого свойства класса
|
||||||
|
foreach ($properties as $key => $value) {
|
||||||
|
// - проверяю наличие свойства
|
||||||
|
if (!$classReflector->hasProperty($key))
|
||||||
|
// -- иду к следующему
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - получаю данные про свойство
|
||||||
|
// -- само свойство
|
||||||
|
$property = $classReflector->getProperty($key);
|
||||||
|
// -- тип свойства
|
||||||
|
$propertyType = $property->getType();
|
||||||
|
|
||||||
|
// - если значение является классом
|
||||||
|
if (!$propertyType->isBuiltin() && is_array($value)) {
|
||||||
|
// -- присваиваю объект
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj,
|
||||||
|
self::MapToClassProperty($propertyType->getName(), $value));
|
||||||
|
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если значение является датой
|
||||||
|
if ($classObj->$key instanceof DateTimeInterface) {
|
||||||
|
// -- получаю дату
|
||||||
|
$dateValue = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $value . " 00:00:00");
|
||||||
|
|
||||||
|
// -- если не получилось
|
||||||
|
if ($dateValue === false)
|
||||||
|
// --- то добавляю дату по умолчанию (1970-01-01 00:00:00)
|
||||||
|
$dateValue = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', "1970-01-01 00:00:00");
|
||||||
|
|
||||||
|
// -- присваиваю дату
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj, $dateValue);
|
||||||
|
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если значение является перечислением
|
||||||
|
if ($classObj->$key instanceof UnitEnum) {
|
||||||
|
// -- если значение уже является перечислением
|
||||||
|
if ($value instanceof UnitEnum)
|
||||||
|
// --- присваиваю перечисление
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj, $value);
|
||||||
|
else
|
||||||
|
// -- иначе
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj,
|
||||||
|
is_numeric($value) ? $classObj->$key::FromInt($value) : $classObj->$key::FromName($value));
|
||||||
|
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если значение является NULL
|
||||||
|
if ($value == "null") {
|
||||||
|
// -- присваиваю NULL
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj,
|
||||||
|
is_array($key) ? [] : null);
|
||||||
|
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - присваиваю значение
|
||||||
|
self::SetParameterToClass($classReflector, $key, $classObj, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю объект класса
|
||||||
|
return $classObj;
|
||||||
|
}
|
||||||
|
catch (Exception $exception) {
|
||||||
|
throw new Exception($exception->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Присваивает значение параметра объекту класса.
|
||||||
|
*
|
||||||
|
* @param ReflectionClass $classReflector Рефлектор класса.
|
||||||
|
* @param string $propertyName Имя свойства.
|
||||||
|
* @param mixed $classObj Объект класса.
|
||||||
|
* @param mixed $value Значение.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function SetParameterToClass (ReflectionClass $classReflector, string $propertyName,
|
||||||
|
mixed $classObj, mixed $value): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Получаю свойство
|
||||||
|
$property = $classReflector->getProperty($propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Устанавливаю доступ значения свойства.
|
||||||
|
*
|
||||||
|
* @noinspection PhpExpressionResultUnusedInspection
|
||||||
|
*/
|
||||||
|
$property->setAccessible(true);
|
||||||
|
|
||||||
|
// Если значение null
|
||||||
|
if ($value == null || $value == "null")
|
||||||
|
// - то присваиваю значение по умолчанию
|
||||||
|
$value = self::GetDefaults($property->getType()->getName());
|
||||||
|
|
||||||
|
// Присваиваю значение
|
||||||
|
$property->setValue($classObj, $value);
|
||||||
|
}
|
||||||
|
catch (ReflectionException $exception) {
|
||||||
|
// Выбрасываю исключение
|
||||||
|
throw new Exception($exception->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает значение по умолчанию для разных типов данных.
|
||||||
|
*
|
||||||
|
* @param string $typeName Имя типа данных.
|
||||||
|
*
|
||||||
|
* @return mixed|null Результат.
|
||||||
|
*/
|
||||||
|
public static function GetDefaults (string $typeName): mixed
|
||||||
|
{
|
||||||
|
return match ($typeName) {
|
||||||
|
'int' => 0,
|
||||||
|
'float' => 0.0,
|
||||||
|
'bool' => false,
|
||||||
|
'string' => '',
|
||||||
|
'array' => [],
|
||||||
|
'object' => new stdClass(),
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
60
sources/classes/ObjectArray.php
Normal file
60
sources/classes/ObjectArray.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\classes;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use Countable;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\ISerializable;
|
||||||
|
use goodboyalex\php_components_pack\traits\ObjectArray\ObjectArrayBasicTrait;
|
||||||
|
use goodboyalex\php_components_pack\traits\ObjectArray\ObjectArrayConstantsTrait;
|
||||||
|
use goodboyalex\php_components_pack\traits\ObjectArray\ObjectArrayLINQTrait;
|
||||||
|
use goodboyalex\php_components_pack\traits\ObjectArray\ObjectArraySearchAndSortTrait;
|
||||||
|
use IteratorAggregate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс, описывающий массив объектов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ObjectArray implements ArrayAccess, IteratorAggregate, Countable, ISerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array $Container Массив объектов, хранящихся в данном классе.
|
||||||
|
*/
|
||||||
|
private array $Container;
|
||||||
|
|
||||||
|
// Реализация наследуемых интерфейсов и классов
|
||||||
|
use ObjectArrayBasicTrait;
|
||||||
|
|
||||||
|
// Константы
|
||||||
|
use ObjectArrayConstantsTrait;
|
||||||
|
|
||||||
|
// Поиск элемента
|
||||||
|
use ObjectArraySearchAndSortTrait;
|
||||||
|
|
||||||
|
// LINQ-подобные методы
|
||||||
|
use ObjectArrayLINQTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор класса.
|
||||||
|
*
|
||||||
|
* @param array $array Массив объектов, который будет храниться в данном классе.
|
||||||
|
*/
|
||||||
|
public function __construct (array $array = [])
|
||||||
|
{
|
||||||
|
$this->Container = $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает массив объектов, хранящихся в данном классе.
|
||||||
|
*
|
||||||
|
* @return array Массив объектов, хранящихся в данном классе.
|
||||||
|
*/
|
||||||
|
public function ToArray (): array
|
||||||
|
{
|
||||||
|
return $this->Container;
|
||||||
|
}
|
||||||
|
}
|
39
sources/enums/MessageType.php
Normal file
39
sources/enums/MessageType.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\enums;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\traits\EnumExtensionsTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Перечисление типов сообщений.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
enum MessageType: int
|
||||||
|
{
|
||||||
|
// Подключаю расширение для Enum
|
||||||
|
use EnumExtensionsTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Успех
|
||||||
|
*/
|
||||||
|
case Success = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Информация
|
||||||
|
*/
|
||||||
|
case Info = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Предупреждение
|
||||||
|
*/
|
||||||
|
case Warning = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ошибка
|
||||||
|
*/
|
||||||
|
case Error = 3;
|
||||||
|
}
|
60
sources/extensions/ArrayExtension.php
Normal file
60
sources/extensions/ArrayExtension.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\extensions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Расширение массивов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ArrayExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Удаляет пустые строки в массиве.
|
||||||
|
*
|
||||||
|
* @param array $array Исходный массив
|
||||||
|
* @param bool $reOrder Переиндексировать массив
|
||||||
|
*
|
||||||
|
* @return array Результирующим массив без пустых строк
|
||||||
|
*/
|
||||||
|
public static function RemoveEmpties (array $array, bool $reOrder = false): array
|
||||||
|
{
|
||||||
|
// Удаляем пустые строки
|
||||||
|
$result = array_filter($array, fn ($value) => !is_null($value) && $value !== '');
|
||||||
|
|
||||||
|
// Переиндексируем массив
|
||||||
|
if ($reOrder)
|
||||||
|
$result = array_values($result);
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выделяет в смешанном массиве ассоциативный массив
|
||||||
|
*
|
||||||
|
* @param array $array Исходный массив
|
||||||
|
*
|
||||||
|
* @return array Ассоциативный массив, содержащийся в исходном массиве
|
||||||
|
*/
|
||||||
|
public static function GetAssociativePart (array $array): array
|
||||||
|
{
|
||||||
|
// Фильтруем массив, оставляя только элементы со строковыми ключами
|
||||||
|
return array_filter($array, fn ($key) => self::IsStringKey($key), ARRAY_FILTER_USE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Функция для проверки, является ли ключ строковым
|
||||||
|
*
|
||||||
|
* @param mixed $key Ключ
|
||||||
|
*
|
||||||
|
* @return bool Является ли ключ строковым типом
|
||||||
|
*/
|
||||||
|
public static function IsStringKey (mixed $key): bool
|
||||||
|
{
|
||||||
|
return !is_int($key);
|
||||||
|
}
|
||||||
|
}
|
147
sources/extensions/GUIDExtension.php
Normal file
147
sources/extensions/GUIDExtension.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\extensions;
|
||||||
|
|
||||||
|
use Random\RandomException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Расширение Guid.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class GUIDExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Пустой Guid.
|
||||||
|
*/
|
||||||
|
public const string GUIDEmpty = "00000000-0000-0000-0000-000000000000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует Guid.
|
||||||
|
*
|
||||||
|
* @return string Сгенерированный Guid.
|
||||||
|
*/
|
||||||
|
public static function Generate (): string
|
||||||
|
{
|
||||||
|
// Цикл создания Guid
|
||||||
|
do
|
||||||
|
$guid = self::DoGenerate();
|
||||||
|
// - пока Guid не будет корректен
|
||||||
|
while (!self::Validate($guid));
|
||||||
|
|
||||||
|
// Возвращаем Guid
|
||||||
|
return $guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерирует Guid.
|
||||||
|
*
|
||||||
|
* @return string Сгенерированный Guid.
|
||||||
|
*/
|
||||||
|
private static function DoGenerate (): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return sprintf(
|
||||||
|
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||||
|
// 32 bits for "time_low"
|
||||||
|
random_int(0, 0xffff),
|
||||||
|
random_int(0, 0xffff),
|
||||||
|
|
||||||
|
// 16 bits for "time_mid"
|
||||||
|
random_int(0, 0xffff),
|
||||||
|
|
||||||
|
// 16 bits for "time_hi_and_version",
|
||||||
|
// four most significant bits holds version number 4
|
||||||
|
random_int(0, 0x0fff) | 0x4000,
|
||||||
|
|
||||||
|
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||||
|
// 8 bits for "clk_seq_low",
|
||||||
|
// two most significant bits holds zero and one for variant DCE1.1
|
||||||
|
random_int(0, 0x3fff) | 0x8000,
|
||||||
|
|
||||||
|
// 48 bits for "node"
|
||||||
|
random_int(0, 0xffff),
|
||||||
|
random_int(0, 0xffff),
|
||||||
|
random_int(0, 0xffff)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (RandomException) {
|
||||||
|
return self::GUIDEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет Guid на корректность.
|
||||||
|
*
|
||||||
|
* @param string|null $str Guid на проверку
|
||||||
|
*
|
||||||
|
* @return bool Корректен ли Guid.
|
||||||
|
*/
|
||||||
|
public static function Validate (?string $str): bool
|
||||||
|
{
|
||||||
|
// Если Guid пустой
|
||||||
|
if (StringExtension::IsNullOrWhitespace($str))
|
||||||
|
// - возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Проверяем длину
|
||||||
|
$isLenCorrect = strlen($str) == 36;
|
||||||
|
|
||||||
|
// Если длина не корректна
|
||||||
|
if (!$isLenCorrect)
|
||||||
|
// - возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Разбиваем на части
|
||||||
|
$explodedStr = explode("-", $str);
|
||||||
|
|
||||||
|
// Если количество частей не равно 5
|
||||||
|
if (count($explodedStr) !== 5)
|
||||||
|
// - возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Проверяем длину каждой части
|
||||||
|
// - первая часть должна быть длиной 8 символов
|
||||||
|
if (strlen($explodedStr[0]) !== 8)
|
||||||
|
// -- возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// - вторая часть должна быть длиной 4 символа
|
||||||
|
if (strlen($explodedStr[1]) !== 4)
|
||||||
|
// -- возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// - третья часть должна быть длиной 4 символа
|
||||||
|
if (strlen($explodedStr[2]) !== 4)
|
||||||
|
// -- возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// - четвертая часть должна быть длиной 4 символа
|
||||||
|
if (strlen($explodedStr[3]) !== 4)
|
||||||
|
// -- возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// - пятая часть должна быть длиной 12 символов
|
||||||
|
if (strlen($explodedStr[4]) !== 12)
|
||||||
|
// -- возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Проверка пройдена
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет Guid на пустоту.
|
||||||
|
*
|
||||||
|
* @param string|null $str Guid на проверку
|
||||||
|
*
|
||||||
|
* @return bool Пустой ли GUID
|
||||||
|
*/
|
||||||
|
public static function IsNotValidOrEmpty (?string $str): bool
|
||||||
|
{
|
||||||
|
return !self::Validate($str) || $str == self::GUIDEmpty;
|
||||||
|
}
|
||||||
|
}
|
210
sources/extensions/StringExtension.php
Normal file
210
sources/extensions/StringExtension.php
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\extensions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Расширение строк.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class StringExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array|string[] $RussianLetters Набор русских букв
|
||||||
|
*/
|
||||||
|
private static array $RussianLetters =
|
||||||
|
[
|
||||||
|
'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й',
|
||||||
|
'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф',
|
||||||
|
'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я',
|
||||||
|
'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',
|
||||||
|
'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',
|
||||||
|
'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array|string[] $RussianLettersTransliteration Набор русских букв в транслитерации
|
||||||
|
*/
|
||||||
|
private static array $RussianLettersTransliteration =
|
||||||
|
[
|
||||||
|
"a", "b", "v", "g", "d", "e", "yo", "zh", "z", "i", "j",
|
||||||
|
"k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "f",
|
||||||
|
"h", "c", "ch", "sh", "sch", "j", "i", "j", "e", "yu", "ya",
|
||||||
|
"A", "B", "V", "G", "D", "E", "Yo", "Zh", "Z", "I", "J",
|
||||||
|
"K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "F",
|
||||||
|
"H", "C", "Ch", "Sh", "Sch", "J", "I", "J", "E", "Yu", "Ya"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сравнивает две строки.
|
||||||
|
*
|
||||||
|
* @param string|null $str1 Первая строка.
|
||||||
|
* @param string|null $str2 Вторая строка.
|
||||||
|
* @param bool $ignoreCase Игнорировать регистр.
|
||||||
|
*
|
||||||
|
* @return int Результат сравнения. Возвращаемые значения:
|
||||||
|
*
|
||||||
|
* -1 | значение $str1 меньше значения $str2.
|
||||||
|
* 0 | значения $str1 и $str2 равны.
|
||||||
|
* 1 | значение $str1 больше значения $str2.
|
||||||
|
*/
|
||||||
|
public static function Compare (string|null $str1, string|null $str2, bool $ignoreCase = false): int
|
||||||
|
{
|
||||||
|
// Если оба пусты
|
||||||
|
if (self::IsNullOrWhitespace($str1) && self::IsNullOrWhitespace($str2))
|
||||||
|
// - то равны
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Если первый из них не пуст, а второй пуст
|
||||||
|
if (!self::IsNullOrWhitespace($str1) && self::IsNullOrWhitespace($str2))
|
||||||
|
// - то первый больше
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Если первый из них пуст, а второй не пуст
|
||||||
|
if (!self::IsNullOrWhitespace($str1) && self::IsNullOrWhitespace($str2))
|
||||||
|
// - то первый меньше
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Если нужно игнорировать регистр
|
||||||
|
if ($ignoreCase)
|
||||||
|
// - то сравниваем по "человечески" без учёта регистра
|
||||||
|
return strnatcasecmp($str1, $str2);
|
||||||
|
|
||||||
|
// Иначе сравниваем по "человечески" с учётом регистра
|
||||||
|
return strnatcmp($str1, $str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, пуста ли строка, содержит ли вместо текста только пробелы.
|
||||||
|
*
|
||||||
|
* @param string|null $str Проверяемая строка.
|
||||||
|
*
|
||||||
|
* @return bool Результат проверки.
|
||||||
|
*/
|
||||||
|
public static function IsNullOrWhitespace (string|null $str): bool
|
||||||
|
{
|
||||||
|
return self::IsNullOrEmpty($str) || trim($str) === '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, пуста ли строка.
|
||||||
|
*
|
||||||
|
* @param string|null $str Проверяемая строка.
|
||||||
|
*
|
||||||
|
* @return bool Результат проверки.
|
||||||
|
*/
|
||||||
|
public static function IsNullOrEmpty (string|null $str): bool
|
||||||
|
{
|
||||||
|
return is_null($str) || $str === '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конвертация в латиницу.
|
||||||
|
*
|
||||||
|
* @param string $source Исходное слово или выражение
|
||||||
|
*
|
||||||
|
* @return string Транслитерированное слово или выражение
|
||||||
|
*/
|
||||||
|
public static function ConvertToLatin (string $source): string
|
||||||
|
{
|
||||||
|
// Создаю результат
|
||||||
|
$result = "";
|
||||||
|
|
||||||
|
// Длина исходного слова
|
||||||
|
$length = mb_strlen($source);
|
||||||
|
|
||||||
|
// Для каждой буквы или символа из слова
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
// - получаю букву или символ
|
||||||
|
$letter = mb_substr($source, $i, 1);
|
||||||
|
|
||||||
|
// - если это буква из русского алфавита
|
||||||
|
if (self::IsRussianLetter($letter)) {
|
||||||
|
// -- транслитерирую эту букву
|
||||||
|
$resultTransliteration = self::TransliterationFromRussian($letter);
|
||||||
|
|
||||||
|
// -- если транслитерация не удалась
|
||||||
|
if ($resultTransliteration === false)
|
||||||
|
// --- вывожу оригинальную букву
|
||||||
|
$result = $result . $letter;
|
||||||
|
else
|
||||||
|
// --- вывожу транслитерированную букву
|
||||||
|
$result = $result . $resultTransliteration;
|
||||||
|
|
||||||
|
// -- и иду к следующей букве или символу
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если до сих пор буква или символ не обработаны, то возвращаю их
|
||||||
|
$result = $result . $letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, является ли буква русской.
|
||||||
|
*
|
||||||
|
* @param string $letter Буква
|
||||||
|
*
|
||||||
|
* @return bool Является ли буква русской
|
||||||
|
*/
|
||||||
|
private static function IsRussianLetter (string $letter): bool
|
||||||
|
{
|
||||||
|
return in_array($letter, self::$RussianLetters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получаю транслитерированную букву русского алфавита.
|
||||||
|
*
|
||||||
|
* @param string $letter Буква
|
||||||
|
*
|
||||||
|
* @return false|string Транслитерированная буква или false, если массивы не совпадают или буква не содержится
|
||||||
|
* в массивах.
|
||||||
|
*/
|
||||||
|
private static function TransliterationFromRussian (string $letter): false|string
|
||||||
|
{
|
||||||
|
// Если размерность массивов разная
|
||||||
|
if (count(self::$RussianLetters) !== count(self::$RussianLettersTransliteration))
|
||||||
|
// - то вывожу ошибку
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Получаю индекс буквы
|
||||||
|
$ind = array_search($letter, self::$RussianLetters, true);
|
||||||
|
|
||||||
|
// Если буква не найдена
|
||||||
|
if ($ind === false)
|
||||||
|
// - то вывожу ошибку
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Получаю транслитерированную букву
|
||||||
|
return self::$RussianLettersTransliteration[$ind];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрезает строку до указанных в параметре $maxLength символов
|
||||||
|
*
|
||||||
|
* @param string $text Исходный текст
|
||||||
|
* @param int $maxLength Максимальная длина текста
|
||||||
|
* @param string $endDots Суффикс, которым завершается обрезанная строка
|
||||||
|
*
|
||||||
|
* @return string Обрезанный текст
|
||||||
|
*/
|
||||||
|
public static function GetShortText (string $text, int $maxLength, string $endDots = ''): string
|
||||||
|
{
|
||||||
|
// Если длина текста меньше максимальной
|
||||||
|
if (mb_strlen($text) <= $maxLength)
|
||||||
|
// - то возвращаю исходный текст
|
||||||
|
return $text;
|
||||||
|
|
||||||
|
// Если длина текста больше максимальной, то получаю длину текста без суффикса
|
||||||
|
$lengthWithoutEndDots = $maxLength - mb_strlen($endDots);
|
||||||
|
|
||||||
|
// Возвращаю обрезанный текст
|
||||||
|
return mb_substr($text, 0, $lengthWithoutEndDots) . $endDots;
|
||||||
|
}
|
||||||
|
}
|
30
sources/interfaces/ISerializable.php
Normal file
30
sources/interfaces/ISerializable.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\interfaces;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Интерфейс поддержки правильной сериализации объектов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
interface ISerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Сериализация модели
|
||||||
|
*
|
||||||
|
* @return string Сериализованная модель
|
||||||
|
*/
|
||||||
|
public function Serialize (): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Десериализует модель
|
||||||
|
*
|
||||||
|
* @param string $serialized Сериализованная модель
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function UnSerialize (string $serialized): void;
|
||||||
|
}
|
108
sources/models/ActionStateMessageModel.php
Normal file
108
sources/models/ActionStateMessageModel.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\models;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use goodboyalex\php_components_pack\classes\ClassMapper;
|
||||||
|
use goodboyalex\php_components_pack\enums\MessageType;
|
||||||
|
use goodboyalex\php_components_pack\interfaces\ISerializable;
|
||||||
|
use UnitEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс сообщения состояния.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
final class ActionStateMessageModel implements ISerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var MessageType $MessageType Тип сообщения
|
||||||
|
*/
|
||||||
|
public MessageType $MessageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool $IsCritical Критичность сообщения
|
||||||
|
*/
|
||||||
|
public bool $IsCritical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $Message Текст сообщения
|
||||||
|
*/
|
||||||
|
public string $Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор
|
||||||
|
*
|
||||||
|
* @param MessageType $type Тип сообщения
|
||||||
|
* @param bool $isCritical Критичность сообщения
|
||||||
|
* @param string $message Текст сообщения
|
||||||
|
*/
|
||||||
|
public function __construct (MessageType $type = MessageType::Info, bool $isCritical = false, string $message = "")
|
||||||
|
{
|
||||||
|
$this->MessageType = $type;
|
||||||
|
$this->IsCritical = $isCritical;
|
||||||
|
$this->Message = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function UnSerialize (string $serialized): void
|
||||||
|
{
|
||||||
|
// Десериализую массив
|
||||||
|
$thisNew = unserialize($serialized);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Получаю класс
|
||||||
|
$class = ClassMapper::MapToClassProperty(get_class($this), $thisNew);
|
||||||
|
}
|
||||||
|
catch (Exception) {
|
||||||
|
$class = new ActionStateMessageModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заполняю текущий класс
|
||||||
|
ClassMapper::MapClass($class, $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function Serialize (): string
|
||||||
|
{
|
||||||
|
// Создаю массив результата
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Получаю свойства класса
|
||||||
|
$properties = get_object_vars($this);
|
||||||
|
|
||||||
|
// Для каждого свойства класса
|
||||||
|
foreach ($properties as $key => $value) {
|
||||||
|
|
||||||
|
// - если значение является перечислением
|
||||||
|
if ($value instanceof UnitEnum) {
|
||||||
|
// -- получаю перечисление
|
||||||
|
$result[$key] = $value->name;
|
||||||
|
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - если значение является NULL
|
||||||
|
if ($value == null) {
|
||||||
|
// -- присваиваю NULL
|
||||||
|
$result[$key] = "null";
|
||||||
|
// -- следующий элемент
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - присваиваю значение
|
||||||
|
$result[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сериализую массив и вывожу его
|
||||||
|
return serialize($result);
|
||||||
|
}
|
||||||
|
}
|
80
sources/traits/EnumExtensionsTrait.php
Normal file
80
sources/traits/EnumExtensionsTrait.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\traits;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\enums\MessageType;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use ReflectionEnum;
|
||||||
|
use ReflectionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Расширение перечислений.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait EnumExtensionsTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Получает значение перечисления по его имени.
|
||||||
|
*
|
||||||
|
* @param string $name Имя значения перечисления
|
||||||
|
*
|
||||||
|
* @return MessageType|EnumExtensionsTrait Перечисление
|
||||||
|
*/
|
||||||
|
public static function FromName (string $name): self
|
||||||
|
{
|
||||||
|
// Создаём экземпляр
|
||||||
|
$reflection = new ReflectionEnum(static::class);
|
||||||
|
|
||||||
|
// Проверяем, есть ли такая переменная
|
||||||
|
if (!$reflection->hasCase($name))
|
||||||
|
// - если нет - ошибка
|
||||||
|
throw new InvalidArgumentException(sprintf("Enumeration name '%s' does not exist!", $name));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $reflection->getCase($name)->getValue();
|
||||||
|
}
|
||||||
|
catch (ReflectionException) {
|
||||||
|
|
||||||
|
$result = new static();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает значение перечисления
|
||||||
|
*
|
||||||
|
* @return string Значение перечисления
|
||||||
|
*/
|
||||||
|
public function GetValue (): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конвертирует в перечисление из int.
|
||||||
|
*
|
||||||
|
* @param int $value Значение перечисления в формате int
|
||||||
|
*
|
||||||
|
* @return MessageType|EnumExtensionsTrait Объект
|
||||||
|
* перечисления
|
||||||
|
*/
|
||||||
|
public static function FromInt (int $value): self
|
||||||
|
{
|
||||||
|
return self::tryFrom($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Переводит тип в INT
|
||||||
|
*
|
||||||
|
* @return int Значение типа в INT
|
||||||
|
*/
|
||||||
|
public function ToInt (): int
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
}
|
90
sources/traits/ObjectArray/ObjectArrayBasicTrait.php
Normal file
90
sources/traits/ObjectArray/ObjectArrayBasicTrait.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\traits\ObjectArray;
|
||||||
|
|
||||||
|
use ArrayIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Часть кода класса ObjectArray, отвечающая за функции из наследуемых интерфейсов и классов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ObjectArrayBasicTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetExists (mixed $offset): bool
|
||||||
|
{
|
||||||
|
return isset($this->Container[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetGet (mixed $offset): mixed
|
||||||
|
{
|
||||||
|
return $this->container[$offset] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetSet (mixed $offset, mixed $value): void
|
||||||
|
{
|
||||||
|
// Если смещение не указано
|
||||||
|
if (is_null($offset))
|
||||||
|
// - то добавляем объект в конец массива.
|
||||||
|
$this->Container[] = $value;
|
||||||
|
else
|
||||||
|
// - иначе добавляем объект по указанному смещению.
|
||||||
|
$this->Container[$offset] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function offsetUnset (mixed $offset): void
|
||||||
|
{
|
||||||
|
unset($this->Container[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getIterator (): ArrayIterator
|
||||||
|
{
|
||||||
|
return new ArrayIterator($this->Container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Существует ли элемент по указанному смещению.
|
||||||
|
*
|
||||||
|
* @param mixed $offset Смещение.
|
||||||
|
*
|
||||||
|
* @return bool Существует ли элемент по указанному смещению.
|
||||||
|
*/
|
||||||
|
public function __isset (mixed $offset): bool
|
||||||
|
{
|
||||||
|
return isset($this->data[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function Serialize (): string
|
||||||
|
{
|
||||||
|
return serialize($this->Container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function UnSerialize (string $serialized): void
|
||||||
|
{
|
||||||
|
$this->Container = unserialize($serialized);
|
||||||
|
}
|
||||||
|
}
|
26
sources/traits/ObjectArray/ObjectArrayConstantsTrait.php
Normal file
26
sources/traits/ObjectArray/ObjectArrayConstantsTrait.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\traits\ObjectArray;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Часть кода класса ObjectArray, отвечающая за константы.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ObjectArrayConstantsTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Closure Функция сравнения объектов по умолчанию.
|
||||||
|
*/
|
||||||
|
public Closure $DefaultComparerFunction {
|
||||||
|
get {
|
||||||
|
return fn (mixed $currentPropertyValue, mixed $searchPropertyValue): bool
|
||||||
|
=> $currentPropertyValue === $searchPropertyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
283
sources/traits/ObjectArray/ObjectArrayLINQTrait.php
Normal file
283
sources/traits/ObjectArray/ObjectArrayLINQTrait.php
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\traits\ObjectArray;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\ObjectArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Часть кода класса ObjectArray, отвечающая за LINQ-подобные операции.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ObjectArrayLINQTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Возвращает объект, значение свойства которого минимально.
|
||||||
|
*
|
||||||
|
* @param callable $itemValuePredicate Функция, возвращающая значение свойства объекта.
|
||||||
|
* Параметром является объект массива.
|
||||||
|
*
|
||||||
|
* @return mixed|null Объект, значение свойства которого минимально
|
||||||
|
*/
|
||||||
|
public function MinBy (callable $itemValuePredicate): mixed
|
||||||
|
{
|
||||||
|
return array_reduce($this->Container,
|
||||||
|
fn ($min, $item) => $min === null || $itemValuePredicate($item) < $itemValuePredicate($min) ? $item : $min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает объект, значение свойства которого максимально.
|
||||||
|
*
|
||||||
|
* @param callable $itemValuePredicate Функция, возвращающая значение свойства объекта.
|
||||||
|
* Параметром является объект массива.
|
||||||
|
*
|
||||||
|
* @return mixed|null Объект, значение свойства которого максимально.
|
||||||
|
*/
|
||||||
|
public function MaxBy (callable $itemValuePredicate): mixed
|
||||||
|
{
|
||||||
|
return array_reduce($this->Container,
|
||||||
|
fn ($max, $item) => $max === null || $itemValuePredicate($item) > $itemValuePredicate($max) ? $item : $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выделяет из массива объектов объект, удовлетворяющий условию. Если объектов несколько, то выбирается первый
|
||||||
|
* встречающийся объект из них. Если объектов нет, вернёт false.
|
||||||
|
*
|
||||||
|
* @param callable|null $selectCondition Функция выборки объектов <code>fn (mixed $item): bool</code>. Вместо неё
|
||||||
|
* можно использовать null, тогда функция выберет текущий объект. По умолчанию, null.
|
||||||
|
*
|
||||||
|
* @return false|mixed Выбранный объект, удовлетворяющий условию, или false, если таких нет.
|
||||||
|
*/
|
||||||
|
public function GetRow (?callable $selectCondition = null): mixed
|
||||||
|
{
|
||||||
|
// Если условие не задано
|
||||||
|
if ($selectCondition === null || !is_callable($selectCondition)) {
|
||||||
|
// - то если массив не пуст
|
||||||
|
if (count($this->Container) > 0)
|
||||||
|
// -- возвращаем первый элемент
|
||||||
|
return $this->Container[0];
|
||||||
|
else
|
||||||
|
// -- иначе возвращаем false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем результаты выборки из массива по условию $selectCondition
|
||||||
|
$result = $this->GetRows($selectCondition);
|
||||||
|
|
||||||
|
// Если результат не найден
|
||||||
|
if (count($result) == 0)
|
||||||
|
// - возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выделяет из массива объектов объекты, удовлетворяющие условию.
|
||||||
|
*
|
||||||
|
* @param callable|null $selectCondition Функция выборки объектов <code>fn (mixed $item): bool</code>. Вместо неё
|
||||||
|
* можно использовать null, тогда функция будет выбирать все объекты. По умолчанию, null.
|
||||||
|
*
|
||||||
|
* @return ObjectArray Массив объектов, удовлетворяющих условию
|
||||||
|
*/
|
||||||
|
public function GetRows (?callable $selectCondition = null): ObjectArray
|
||||||
|
{
|
||||||
|
// Если условие не задано
|
||||||
|
if ($selectCondition === null || !is_callable($selectCondition))
|
||||||
|
// - то возвращаем все элементы
|
||||||
|
return new ObjectArray($this->Container);
|
||||||
|
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Проходим по массиву
|
||||||
|
foreach ($this->Container as $item) {
|
||||||
|
// - пропускаем не объекты
|
||||||
|
if (!is_object($item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если объект удовлетворяет условию
|
||||||
|
if ($selectCondition($item))
|
||||||
|
// -- добавляем его в результат
|
||||||
|
$result[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return new ObjectArray($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получение значение единичного поля. Если полей по выборке будет больше одного, то вернёт первое из них.
|
||||||
|
*
|
||||||
|
* @param string $column Требуемый столбец
|
||||||
|
* @param callable|null $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
|
||||||
|
* подходит элемент или нет.
|
||||||
|
*
|
||||||
|
* @return mixed|null Результат запроса или null в случае ошибки
|
||||||
|
*/
|
||||||
|
public function GetValue (string $column, ?callable $wherePredicate = null): mixed
|
||||||
|
{
|
||||||
|
// Получаю колонку
|
||||||
|
$result = $this->GetColumn($column, $wherePredicate);
|
||||||
|
|
||||||
|
// Если результат пуст
|
||||||
|
if (count($result) == 0)
|
||||||
|
// -- возвращаю null
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получает колонку в массиве данных.
|
||||||
|
*
|
||||||
|
* @param string $column Имя колонки.
|
||||||
|
* @param callable|null $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
|
||||||
|
* подходит элемент или нет.
|
||||||
|
*
|
||||||
|
* @return array Ассоциированный массив с результатом выборки.
|
||||||
|
*/
|
||||||
|
public function GetColumn (string $column, ?callable $wherePredicate = null): array
|
||||||
|
{
|
||||||
|
// Создаю результат
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Прохожу по массиву
|
||||||
|
foreach ($this->Container as $item) {
|
||||||
|
// - пропускаю не объекты
|
||||||
|
if (!is_object($item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - пропускаю не имеющие требуемого свойства
|
||||||
|
if (!property_exists($item, $column))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - пропускаю не удовлетворяющие условию
|
||||||
|
if ($wherePredicate !== null && !$wherePredicate($item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - добавляю значение свойства в результат
|
||||||
|
$result[] = $item->$column;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Заменяет данные в строке\ массива.
|
||||||
|
*
|
||||||
|
* @param mixed $setItem Заменяемые элемент.
|
||||||
|
* @param callable $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
|
||||||
|
* подходит элемент или нет.
|
||||||
|
*
|
||||||
|
* @return bool Результат выполнения
|
||||||
|
*/
|
||||||
|
public function Update (array $setItems, callable $wherePredicate): bool
|
||||||
|
{
|
||||||
|
// Удаляю элементы
|
||||||
|
$result = $this->Delete($wherePredicate);
|
||||||
|
|
||||||
|
// Добавляю новые элементы
|
||||||
|
foreach ($setItems as $item)
|
||||||
|
$this->Container[] = $item;
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Удаляет строки по условию.
|
||||||
|
*
|
||||||
|
* @param callable|null $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
|
||||||
|
* подходит элемент или нет.
|
||||||
|
*
|
||||||
|
* @return bool Результат выполнения. Будет true, если все строки, удовлетворяющие условию удалены успешно,
|
||||||
|
* иначе false.
|
||||||
|
*/
|
||||||
|
public function Delete (?callable $wherePredicate = null): bool
|
||||||
|
{
|
||||||
|
// Задаю результат
|
||||||
|
$result = true;
|
||||||
|
|
||||||
|
// Получаю массив строк
|
||||||
|
$array = $this->GetRows($wherePredicate);
|
||||||
|
|
||||||
|
// Каждый элемент в этих строках
|
||||||
|
foreach ($array as $item) {
|
||||||
|
// - получаю его индекс в основном массиве
|
||||||
|
$key = array_search($item, $this->Container);
|
||||||
|
|
||||||
|
// - и если индекс найден
|
||||||
|
if ($key !== false) {
|
||||||
|
// -- удаляю элемент из основного массива
|
||||||
|
$resultArray = array_splice($this->Container, $key, 1);
|
||||||
|
|
||||||
|
// -- и если удаление прошло успешно, то будет true
|
||||||
|
$result = $result && count($resultArray) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаю результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, существует ли объект в массиве.
|
||||||
|
*
|
||||||
|
* @param callable|null $where Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет, подходит ли
|
||||||
|
* объект или нет. Может принимать вместо замыкания null, тогда вернёт false. По умолчанию null.
|
||||||
|
*
|
||||||
|
* @return bool Результат проверки
|
||||||
|
*/
|
||||||
|
public function IsExist (?callable $where = null): bool
|
||||||
|
{
|
||||||
|
// Если условие не задано
|
||||||
|
if ($where === null || !is_callable($where))
|
||||||
|
// - то возвращаем false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Вывожу результат
|
||||||
|
return $this->Count($where) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считает количество объектов в массиве, удовлетворяющих условию.
|
||||||
|
*
|
||||||
|
* @param callable|null $predicate Функция, возвращающая bool: true, если объект удовлетворяет условию, false, если
|
||||||
|
* не удовлетворяет. Параметром является объект массива. Вместо функции можно передать null, тогда результатом
|
||||||
|
* будет общее количество объектов в массиве. По умолчанию, null.
|
||||||
|
*
|
||||||
|
* @return int Количество объектов, удовлетворяющих условию
|
||||||
|
*/
|
||||||
|
public function Count (?callable $predicate = null): int
|
||||||
|
{
|
||||||
|
// Если условие не задано
|
||||||
|
if ($predicate === null || !is_callable($predicate))
|
||||||
|
// - то возвращаем общее количество объектов
|
||||||
|
return count($this->Container);
|
||||||
|
|
||||||
|
// Создаём результирующее число
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
// Проходим по массиву
|
||||||
|
foreach ($this->Container as $item) {
|
||||||
|
// - пропускаем не объекты
|
||||||
|
if (!is_object($item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если элемент удовлетворяет условию
|
||||||
|
if ($predicate($item))
|
||||||
|
// -- добавляем счётчик
|
||||||
|
$result++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
129
sources/traits/ObjectArray/ObjectArraySearchAndSortTrait.php
Normal file
129
sources/traits/ObjectArray/ObjectArraySearchAndSortTrait.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\traits\ObjectArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Часть кода класса ObjectArray, отвечающая за поиск и исключение объектов.
|
||||||
|
*
|
||||||
|
* @author Александр Бабаев
|
||||||
|
* @package php_components_pack
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
trait ObjectArraySearchAndSortTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Сортирует массив объектов, по пользовательской функции.
|
||||||
|
*
|
||||||
|
* @param callable $objectPropertyValuePredicate Функция <code>fn (mixed $item): mixed => $item-><PROPERTY></code>,
|
||||||
|
* возвращающая сравниваемый объект. Возвращаемое значение должно быть значением свойства этого объекта.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* class Demo;
|
||||||
|
* {
|
||||||
|
* public string $Property1;
|
||||||
|
* public string $Property2;
|
||||||
|
* public function __construct(string $Property1, string $Property2)
|
||||||
|
* {
|
||||||
|
* $this->Property1 = $Property1;
|
||||||
|
* $this->Property2 = $Property2;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* $array = new ObjectArray (
|
||||||
|
* [
|
||||||
|
* new Demo('1', '2'),
|
||||||
|
* new Demo('5', '6'),
|
||||||
|
* new Demo('3', '4')
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // output:
|
||||||
|
* // [Demo('1', '2'), Demo('3', '4'), Demo('5', '6')]
|
||||||
|
* $result = $array->SortCallback($array, fn ($item): mixed => $item->Property1);
|
||||||
|
* </code>
|
||||||
|
* @param bool $descending Направление сортировки
|
||||||
|
*
|
||||||
|
* @return array Отсортированный массив объектов
|
||||||
|
*/
|
||||||
|
public function SortCallback (callable $objectPropertyValuePredicate, bool $descending = false): array
|
||||||
|
{
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = array_merge($this->Container, []);
|
||||||
|
|
||||||
|
// Сортируем массив
|
||||||
|
usort($result,
|
||||||
|
fn ($a, $b)
|
||||||
|
=> !$descending
|
||||||
|
? $objectPropertyValuePredicate($a) <=> $objectPropertyValuePredicate($b)
|
||||||
|
: $objectPropertyValuePredicate($b) <=> $objectPropertyValuePredicate($a));
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сортирует массив объектов, по значению свойства объекта.
|
||||||
|
*
|
||||||
|
* @param string $objectProperty Имя свойства объекта
|
||||||
|
* @param bool $descending Направление сортировки
|
||||||
|
*
|
||||||
|
* @return array Отсортированный массив объектов
|
||||||
|
*/
|
||||||
|
public function Sort (string $objectProperty, bool $descending = false): array
|
||||||
|
{
|
||||||
|
// Создаём результирующий массив
|
||||||
|
$result = array_merge($this->Container, []);
|
||||||
|
|
||||||
|
// Сортируем массив
|
||||||
|
usort($result,
|
||||||
|
fn ($a, $b)
|
||||||
|
=> !$descending
|
||||||
|
? $a->$objectProperty <=> $b->$objectProperty
|
||||||
|
: $b->$objectProperty <=> $a->$objectProperty);
|
||||||
|
|
||||||
|
// Возвращаем результат
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск объекта в массиве объектов по значению свойства объекта.
|
||||||
|
*
|
||||||
|
* @param string $forProperty Имя искомого свойства объекта.
|
||||||
|
* @param mixed $searchValue Искомое значение свойства объекта.
|
||||||
|
* @param callable|null $compareFunction Функция сравнения, принимающая два параметра: mixed $currentPropertyValue
|
||||||
|
* (текущее значение свойства) и mixed $searchPropertyValue (поисковое значение свойства) и возвращает bool -
|
||||||
|
* true, если значение свойства совпадает с искомым, false - если не совпадает. Если передаётся null, то будет
|
||||||
|
* использоваться DefaultComparerFunction. По умолчанию, null.
|
||||||
|
*
|
||||||
|
* @return mixed Объект, найденный по значению свойства или null, если не найден
|
||||||
|
*/
|
||||||
|
public function Search (string $forProperty, mixed $searchValue, ?callable $compareFunction = null): mixed
|
||||||
|
{
|
||||||
|
// Проходим по массиву
|
||||||
|
foreach ($this->Container as $item) {
|
||||||
|
// - пропускаем не объекты
|
||||||
|
if (!is_object($item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - пропускаем, если значение свойства нет в этом объекте
|
||||||
|
if (!property_exists($item, $forProperty))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - пропускаем, если значение свойства не задано
|
||||||
|
if (!isset($item->$forProperty))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// - если не задана функция сравнения
|
||||||
|
if (is_null($compareFunction) || !is_callable($compareFunction))
|
||||||
|
// -- то устанавливаем функцию сравнения по умолчанию
|
||||||
|
$compareFunction = $this->DefaultComparerFunction;
|
||||||
|
|
||||||
|
// - если значение свойства совпадает с искомым
|
||||||
|
if ($compareFunction($item->$forProperty, $searchValue))
|
||||||
|
// -- возвращаем объект
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если мы сюда дошли, значить объект не найден - возвращаем null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
30
tests/classes/ClassMapperTest.php
Normal file
30
tests/classes/ClassMapperTest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\classes;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\classes\ClassMapper;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ClassMapperTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testMapClass ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$a = new \goodboyalex\php_components_pack\tests\data\A();
|
||||||
|
$a->a = 'a';
|
||||||
|
$a->b = 2;
|
||||||
|
$a->c = true;
|
||||||
|
|
||||||
|
$b = new B();
|
||||||
|
ClassMapper::MapClass($a, $b);
|
||||||
|
|
||||||
|
$this->assertEquals('a', $b->a);
|
||||||
|
$this->assertEquals(2, $b->b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function PrepareForTest (): void
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/../../sources/classes/classMapper.php';
|
||||||
|
}
|
||||||
|
}
|
10
tests/data/A.php
Normal file
10
tests/data/A.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\data;
|
||||||
|
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
public string $a;
|
||||||
|
public int $b;
|
||||||
|
public bool $c;
|
||||||
|
}
|
10
tests/data/B.php
Normal file
10
tests/data/B.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\classes;
|
||||||
|
|
||||||
|
class B
|
||||||
|
{
|
||||||
|
public string $a;
|
||||||
|
public int $b;
|
||||||
|
public string $d;
|
||||||
|
}
|
67
tests/extensions/ArrayExtensionTest.php
Normal file
67
tests/extensions/ArrayExtensionTest.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\extensions;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\extensions\ArrayExtension;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ArrayExtensionTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testRemoveEmpties ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$array = [
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
'c' => '',
|
||||||
|
'd' => null,
|
||||||
|
'e' => 0,
|
||||||
|
'f' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
'e' => 0,
|
||||||
|
'f' => false
|
||||||
|
], ArrayExtension::RemoveEmpties($array));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function PrepareForTest (): void
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/../../sources/extensions/ArrayExtension.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsStringKey ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertTrue(ArrayExtension::IsStringKey('a'));
|
||||||
|
$this->assertFalse(ArrayExtension::IsStringKey(1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAssociativePart ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$array = [
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
'c' => 'c',
|
||||||
|
'd' => 'd',
|
||||||
|
'e',
|
||||||
|
'f'
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => 'b',
|
||||||
|
'c' => 'c',
|
||||||
|
'd' => 'd'
|
||||||
|
], ArrayExtension::GetAssociativePart($array));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
51
tests/extensions/GUIDExtensionTest.php
Normal file
51
tests/extensions/GUIDExtensionTest.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\extensions;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\extensions\GUIDExtension;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class GUIDExtensionTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGenerate ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$guid = GUIDExtension::Generate();
|
||||||
|
$this->assertTrue(strlen($guid) === 36);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsNotValidOrEmpty ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$guid = GUIDExtension::Generate();
|
||||||
|
$this->assertFalse(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
|
||||||
|
$guid = '12345678-91101-1121-3141-516171819202';
|
||||||
|
$this->assertTrue(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
|
||||||
|
$guid = GUIDExtension::GUIDEmpty;
|
||||||
|
$this->assertTrue(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidate ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$guid = GUIDExtension::Generate();
|
||||||
|
$this->assertFalse(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
|
||||||
|
$guid = '12345678-91101-1121-3141-516171819202';
|
||||||
|
$this->assertTrue(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
|
||||||
|
$guid = GUIDExtension::GUIDEmpty;
|
||||||
|
$this->assertTrue(GUIDExtension::IsNotValidOrEmpty($guid));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function PrepareForTest (): void
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/../../sources/extensions/StringExtension.php';
|
||||||
|
require_once __DIR__ . '/../../sources/extensions/GUIDExtension.php';
|
||||||
|
}
|
||||||
|
}
|
66
tests/extensions/StringExtensionTest.php
Normal file
66
tests/extensions/StringExtensionTest.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace goodboyalex\php_components_pack\tests\extensions;
|
||||||
|
|
||||||
|
use goodboyalex\php_components_pack\extensions\StringExtension;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StringExtensionTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testIsNullOrWhitespace ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertTrue(StringExtension::isNullOrWhitespace(''));
|
||||||
|
$this->assertTrue(StringExtension::isNullOrWhitespace(' '));
|
||||||
|
$this->assertTrue(StringExtension::isNullOrWhitespace(null));
|
||||||
|
$this->assertFalse(StringExtension::isNullOrWhitespace('TEST'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function PrepareForTest (): void
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/../../sources/extensions/StringExtension.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConvertToLatin ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertEquals('test', StringExtension::ConvertToLatin('тест'));
|
||||||
|
$this->assertEquals('test', StringExtension::ConvertToLatin('test'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsNullOrEmpty ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertTrue(StringExtension::isNullOrEmpty(''));
|
||||||
|
$this->assertTrue(StringExtension::isNullOrEmpty(null));
|
||||||
|
$this->assertFalse(StringExtension::isNullOrEmpty('TEST'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCompare ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertEquals(0, StringExtension::Compare('test', 'test'));
|
||||||
|
$this->assertEquals(-1, StringExtension::Compare('test', 'test1'));
|
||||||
|
$this->assertEquals(1, StringExtension::Compare('test2', 'test'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetShortText ()
|
||||||
|
{
|
||||||
|
$this->PrepareForTest();
|
||||||
|
|
||||||
|
$this->assertEquals('test', StringExtension::GetShortText('test', 4));
|
||||||
|
$this->assertEquals('test', StringExtension::GetShortText('test', 10));
|
||||||
|
$this->assertEquals('test', StringExtension::GetShortText('test of this', 4));
|
||||||
|
$this->assertEquals('t', StringExtension::GetShortText('test', 1));
|
||||||
|
$this->assertEquals('', StringExtension::GetShortText('test', 0));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
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 ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55::getLoader();
|
119
vendor/bin/php-parse
vendored
Normal file
119
vendor/bin/php-parse
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 (../nikic/php-parser/bin/php-parse)
|
||||||
|
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
||||||
|
*
|
||||||
|
* @generated
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
||||||
|
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 80000) {
|
||||||
|
if (!class_exists('Composer\BinProxyWrapper')) {
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class BinProxyWrapper
|
||||||
|
{
|
||||||
|
private $handle;
|
||||||
|
private $position;
|
||||||
|
private $realpath;
|
||||||
|
|
||||||
|
public function stream_open($path, $mode, $options, &$opened_path)
|
||||||
|
{
|
||||||
|
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
||||||
|
$opened_path = substr($path, 17);
|
||||||
|
$this->realpath = realpath($opened_path) ?: $opened_path;
|
||||||
|
$opened_path = $this->realpath;
|
||||||
|
$this->handle = fopen($this->realpath, $mode);
|
||||||
|
$this->position = 0;
|
||||||
|
|
||||||
|
return (bool) $this->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_read($count)
|
||||||
|
{
|
||||||
|
$data = fread($this->handle, $count);
|
||||||
|
|
||||||
|
if ($this->position === 0) {
|
||||||
|
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->position += strlen($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_cast($castAs)
|
||||||
|
{
|
||||||
|
return $this->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_close()
|
||||||
|
{
|
||||||
|
fclose($this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_lock($operation)
|
||||||
|
{
|
||||||
|
return $operation ? flock($this->handle, $operation) : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_seek($offset, $whence)
|
||||||
|
{
|
||||||
|
if (0 === fseek($this->handle, $offset, $whence)) {
|
||||||
|
$this->position = ftell($this->handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_tell()
|
||||||
|
{
|
||||||
|
return $this->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_eof()
|
||||||
|
{
|
||||||
|
return feof($this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_stat()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stream_set_option($option, $arg1, $arg2)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function url_stat($path, $flags)
|
||||||
|
{
|
||||||
|
$path = substr($path, 17);
|
||||||
|
if (file_exists($path)) {
|
||||||
|
return stat($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
||||||
|
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
||||||
|
) {
|
||||||
|
return include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse';
|
5
vendor/bin/php-parse.bat
vendored
Normal file
5
vendor/bin/php-parse.bat
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/php-parse
|
||||||
|
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
|
||||||
|
php "%BIN_TARGET%" %*
|
122
vendor/bin/phpunit
vendored
Normal file
122
vendor/bin/phpunit
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy PHP file generated by Composer
|
||||||
|
*
|
||||||
|
* This file includes the referenced bin path (../phpunit/phpunit/phpunit)
|
||||||
|
* 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';
|
||||||
|
$GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] = $GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'] = array(realpath(__DIR__ . '/..'.'/phpunit/phpunit/phpunit'));
|
||||||
|
|
||||||
|
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 = 'phpvfscomposer://'.$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);
|
||||||
|
}
|
||||||
|
$data = str_replace('__DIR__', var_export(dirname($this->realpath), true), $data);
|
||||||
|
$data = str_replace('__FILE__', var_export($this->realpath, true), $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__ . '/..'.'/phpunit/phpunit/phpunit');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return include __DIR__ . '/..'.'/phpunit/phpunit/phpunit';
|
5
vendor/bin/phpunit.bat
vendored
Normal file
5
vendor/bin/phpunit.bat
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
setlocal DISABLEDELAYEDEXPANSION
|
||||||
|
SET BIN_TARGET=%~dp0/phpunit
|
||||||
|
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
|
||||||
|
php "%BIN_TARGET%" %*
|
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);
|
||||||
|
}
|
||||||
|
}
|
359
vendor/composer/InstalledVersions.php
vendored
Normal file
359
vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
<?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|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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
/** @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';
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||||
|
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||||
|
self::$installed = $installed[count($installed) - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
/** @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()) {
|
||||||
|
$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.
|
||||||
|
|
1519
vendor/composer/autoload_classmap.php
vendored
Normal file
1519
vendor/composer/autoload_classmap.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11
vendor/composer/autoload_files.php
vendored
Normal file
11
vendor/composer/autoload_files.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php',
|
||||||
|
'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.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(
|
||||||
|
);
|
18
vendor/composer/autoload_psr4.php
vendored
Normal file
18
vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'goodboyalex\\php_components_pack\\traits\\' => array($baseDir . '/sources/traits'),
|
||||||
|
'goodboyalex\\php_components_pack\\tests\\' => array($baseDir . '/tests'),
|
||||||
|
'goodboyalex\\php_components_pack\\models\\' => array($baseDir . '/sources/models'),
|
||||||
|
'goodboyalex\\php_components_pack\\interfaces\\' => array($baseDir . '/sources/interfaces'),
|
||||||
|
'goodboyalex\\php_components_pack\\extensions\\' => array($baseDir . '/sources/extensions'),
|
||||||
|
'goodboyalex\\php_components_pack\\enums\\' => array($baseDir . '/sources/enums'),
|
||||||
|
'goodboyalex\\php_components_pack\\' => array($baseDir . '/sources'),
|
||||||
|
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
|
||||||
|
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
|
||||||
|
);
|
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 ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55
|
||||||
|
{
|
||||||
|
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('ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInitc00e5b601adae61bbbc3f6be4864ef55::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
$filesToLoad = \Composer\Autoload\ComposerStaticInitc00e5b601adae61bbbc3f6be4864ef55::$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;
|
||||||
|
}
|
||||||
|
}
|
1596
vendor/composer/autoload_static.php
vendored
Normal file
1596
vendor/composer/autoload_static.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1698
vendor/composer/installed.json
vendored
Normal file
1698
vendor/composer/installed.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
288
vendor/composer/installed.php
vendored
Normal file
288
vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => 'goodboyalex/php_components_pack',
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => 'f1a79d66ec29418af66448e6eca584eddfe31d4d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'goodboyalex/php_components_pack' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => 'f1a79d66ec29418af66448e6eca584eddfe31d4d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'myclabs/deep-copy' => array(
|
||||||
|
'pretty_version' => '1.x-dev',
|
||||||
|
'version' => '1.9999999.9999999.9999999-dev',
|
||||||
|
'reference' => '4764e040f8743e92b86c36f488f32d0265dd1dae',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../myclabs/deep-copy',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'nikic/php-parser' => array(
|
||||||
|
'pretty_version' => 'v5.4.0',
|
||||||
|
'version' => '5.4.0.0',
|
||||||
|
'reference' => '447a020a1f875a434d62f2a401f53b82a396e494',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../nikic/php-parser',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phar-io/manifest' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '54750ef60c58e43759730615a392c31c80e23176',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phar-io/manifest',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '2.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phar-io/version' => array(
|
||||||
|
'pretty_version' => '3.2.1',
|
||||||
|
'version' => '3.2.1.0',
|
||||||
|
'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phar-io/version',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/php-code-coverage' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '30b614244b02907cf0b2edc559fd5e24bd05ea57',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/php-code-coverage',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '12.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/php-file-iterator' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'a1339a60b2206324e440c4a3806bbd873fda0860',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/php-file-iterator',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '6.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/php-invoker' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'a79e641e661a20d3b8c264b0b3b9eb0d98f98506',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/php-invoker',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '6.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/php-text-template' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '0199874fd3f2ae19aa9813bdfcb68e67671eee64',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/php-text-template',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '5.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/php-timer' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'aa0f95babbd87f096f1c20364204f195dd4b4608',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/php-timer',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '8.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'phpunit/phpunit' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '9f2ebaf18f7741a5ee587f80a42632edaa42d424',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpunit/phpunit',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '12.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/cli-parser' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '7f79d38ab02a0cb4089f31207ca11b74f49c7848',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/cli-parser',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '4.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/comparator' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '07f683f544931bc816c47faf894e387f2216a1e9',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/comparator',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '7.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/complexity' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'eec688b04904c5ecfa3b94f59bc60485209805a9',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/complexity',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '5.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/diff' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '87a9594e6994ba8ee9010836903305a64c895083',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/diff',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '7.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/environment' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '92b1a897b49e191a8fbca823d75bc0e157ff7cdb',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/environment',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '8.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/exporter' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '17e38c7a602c690c6f097b6aeaf47d0771ace9ca',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/exporter',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '7.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/global-state' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '8a089e5a2a118a6725b603a47be1d1a9da1b9a68',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/global-state',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '8.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/lines-of-code' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'fe8070ab1160c447839048ab240c07c448caa2b2',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/lines-of-code',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '4.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/object-enumerator' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '250d806a14baca8c4b37823426277dbcb8d4440d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/object-enumerator',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '7.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/object-reflector' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '7dddd66b56ba05cb474de46b2b623e92b42bff3a',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/object-reflector',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '5.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/recursion-context' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'c9442e27dc9965ad453397725830d8ecb5497410',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/recursion-context',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '7.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/type' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'b07de32ccc63961cfcf87c4531816388dbaf264f',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/type',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '6.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'sebastian/version' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => '3e8786f0e004140c3be066577af51e7ea0446e54',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sebastian/version',
|
||||||
|
'aliases' => array(
|
||||||
|
0 => '6.0.x-dev',
|
||||||
|
),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'staabm/side-effects-detector' => array(
|
||||||
|
'pretty_version' => '1.0.5',
|
||||||
|
'version' => '1.0.5.0',
|
||||||
|
'reference' => 'd8334211a140ce329c13726d4a715adbddd0a163',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../staabm/side-effects-detector',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
'theseer/tokenizer' => array(
|
||||||
|
'pretty_version' => '1.2.3',
|
||||||
|
'version' => '1.2.3.0',
|
||||||
|
'reference' => '737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../theseer/tokenizer',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
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 >= 80400)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.4.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
20
vendor/myclabs/deep-copy/LICENSE
vendored
Normal file
20
vendor/myclabs/deep-copy/LICENSE
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 My C-Sense
|
||||||
|
|
||||||
|
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.
|
406
vendor/myclabs/deep-copy/README.md
vendored
Normal file
406
vendor/myclabs/deep-copy/README.md
vendored
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
# DeepCopy
|
||||||
|
|
||||||
|
DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.
|
||||||
|
|
||||||
|
[](https://packagist.org/packages/myclabs/deep-copy)
|
||||||
|
[](https://github.com/myclabs/DeepCopy/actions/workflows/ci.yaml)
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [How](#how)
|
||||||
|
1. [Why](#why)
|
||||||
|
1. [Using simply `clone`](#using-simply-clone)
|
||||||
|
1. [Overriding `__clone()`](#overriding-__clone)
|
||||||
|
1. [With `DeepCopy`](#with-deepcopy)
|
||||||
|
1. [How it works](#how-it-works)
|
||||||
|
1. [Going further](#going-further)
|
||||||
|
1. [Matchers](#matchers)
|
||||||
|
1. [Property name](#property-name)
|
||||||
|
1. [Specific property](#specific-property)
|
||||||
|
1. [Type](#type)
|
||||||
|
1. [Filters](#filters)
|
||||||
|
1. [`SetNullFilter`](#setnullfilter-filter)
|
||||||
|
1. [`KeepFilter`](#keepfilter-filter)
|
||||||
|
1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter)
|
||||||
|
1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter)
|
||||||
|
1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter)
|
||||||
|
1. [`ReplaceFilter`](#replacefilter-type-filter)
|
||||||
|
1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter)
|
||||||
|
1. [Edge cases](#edge-cases)
|
||||||
|
1. [Contributing](#contributing)
|
||||||
|
1. [Tests](#tests)
|
||||||
|
|
||||||
|
|
||||||
|
## How?
|
||||||
|
|
||||||
|
Install with Composer:
|
||||||
|
|
||||||
|
```
|
||||||
|
composer require myclabs/deep-copy
|
||||||
|
```
|
||||||
|
|
||||||
|
Use it:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$myCopy = $copier->copy($myObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
- How do you create copies of your objects?
|
||||||
|
|
||||||
|
```php
|
||||||
|
$myCopy = clone $myObject;
|
||||||
|
```
|
||||||
|
|
||||||
|
- How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)?
|
||||||
|
|
||||||
|
You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior
|
||||||
|
yourself.
|
||||||
|
|
||||||
|
- But how do you handle **cycles** in the association graph?
|
||||||
|
|
||||||
|
Now you're in for a big mess :(
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### Using simply `clone`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### Overriding `__clone()`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
### With `DeepCopy`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it
|
||||||
|
keeps a hash map of all instances and thus preserves the object graph.
|
||||||
|
|
||||||
|
To use it:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use function DeepCopy\deep_copy;
|
||||||
|
|
||||||
|
$copy = deep_copy($var);
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can create your own `DeepCopy` instance to configure it differently for example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
|
||||||
|
$copier = new DeepCopy(true);
|
||||||
|
|
||||||
|
$copy = $copier->copy($var);
|
||||||
|
```
|
||||||
|
|
||||||
|
You may want to roll your own deep copy function:
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace Acme;
|
||||||
|
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
|
||||||
|
function deep_copy($var)
|
||||||
|
{
|
||||||
|
static $copier = null;
|
||||||
|
|
||||||
|
if (null === $copier) {
|
||||||
|
$copier = new DeepCopy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $copier->copy($var);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Going further
|
||||||
|
|
||||||
|
You can add filters to customize the copy process.
|
||||||
|
|
||||||
|
The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`,
|
||||||
|
with `$filter` implementing `DeepCopy\Filter\Filter`
|
||||||
|
and `$matcher` implementing `DeepCopy\Matcher\Matcher`.
|
||||||
|
|
||||||
|
We provide some generic filters and matchers.
|
||||||
|
|
||||||
|
|
||||||
|
### Matchers
|
||||||
|
|
||||||
|
- `DeepCopy\Matcher` applies on a object attribute.
|
||||||
|
- `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements.
|
||||||
|
|
||||||
|
|
||||||
|
#### Property name
|
||||||
|
|
||||||
|
The `PropertyNameMatcher` will match a property by its name:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\Matcher\PropertyNameMatcher;
|
||||||
|
|
||||||
|
// Will apply a filter to any property of any objects named "id"
|
||||||
|
$matcher = new PropertyNameMatcher('id');
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Specific property
|
||||||
|
|
||||||
|
The `PropertyMatcher` will match a specific property of a specific class:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\Matcher\PropertyMatcher;
|
||||||
|
|
||||||
|
// Will apply a filter to the property "id" of any objects of the class "MyClass"
|
||||||
|
$matcher = new PropertyMatcher('MyClass', 'id');
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Type
|
||||||
|
|
||||||
|
The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of
|
||||||
|
[gettype()](http://php.net/manual/en/function.gettype.php) function):
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\TypeMatcher\TypeMatcher;
|
||||||
|
|
||||||
|
// Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection
|
||||||
|
$matcher = new TypeMatcher('Doctrine\Common\Collections\Collection');
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
|
||||||
|
- `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher`
|
||||||
|
- `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher`
|
||||||
|
|
||||||
|
By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied).
|
||||||
|
Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters.
|
||||||
|
|
||||||
|
|
||||||
|
#### `SetNullFilter` (filter)
|
||||||
|
|
||||||
|
Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have
|
||||||
|
any ID:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\SetNullFilter;
|
||||||
|
use DeepCopy\Matcher\PropertyNameMatcher;
|
||||||
|
|
||||||
|
$object = MyClass::load(123);
|
||||||
|
echo $object->id; // 123
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
|
||||||
|
echo $copy->id; // null
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `KeepFilter` (filter)
|
||||||
|
|
||||||
|
If you want a property to remain untouched (for example, an association to an object):
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\KeepFilter;
|
||||||
|
use DeepCopy\Matcher\PropertyMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
// $copy->category has not been touched
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `ChainableFilter` (filter)
|
||||||
|
|
||||||
|
If you use cloning on proxy classes, you might want to apply two filters for:
|
||||||
|
1. loading the data
|
||||||
|
2. applying a transformation
|
||||||
|
|
||||||
|
You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e.
|
||||||
|
the next ones may be applied).
|
||||||
|
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\ChainableFilter;
|
||||||
|
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
|
||||||
|
use DeepCopy\Filter\SetNullFilter;
|
||||||
|
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
|
||||||
|
use DeepCopy\Matcher\PropertyNameMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());
|
||||||
|
$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
|
||||||
|
echo $copy->id; // null
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `DoctrineCollectionFilter` (filter)
|
||||||
|
|
||||||
|
If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter;
|
||||||
|
use DeepCopy\Matcher\PropertyTypeMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `DoctrineEmptyCollectionFilter` (filter)
|
||||||
|
|
||||||
|
If you use Doctrine and want to copy an entity who contains a `Collection` that you want to be reset, you can use the
|
||||||
|
`DoctrineEmptyCollectionFilter`
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter;
|
||||||
|
use DeepCopy\Matcher\PropertyMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
|
||||||
|
// $copy->myProperty will return an empty collection
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `DoctrineProxyFilter` (filter)
|
||||||
|
|
||||||
|
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
|
||||||
|
Doctrine proxy class (...\\\_\_CG\_\_\Proxy).
|
||||||
|
You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.
|
||||||
|
**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded
|
||||||
|
before other filters are applied!**
|
||||||
|
We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the
|
||||||
|
cloned lazy loaded entities.
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
|
||||||
|
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
|
||||||
|
// $copy should now contain a clone of all entities, including those that were not yet fully loaded.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### `ReplaceFilter` (type filter)
|
||||||
|
|
||||||
|
1. If you want to replace the value of a property:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\Filter\ReplaceFilter;
|
||||||
|
use DeepCopy\Matcher\PropertyMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$callback = function ($currentValue) {
|
||||||
|
return $currentValue . ' (copy)'
|
||||||
|
};
|
||||||
|
$copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
|
||||||
|
|
||||||
|
$copy = $copier->copy($object);
|
||||||
|
|
||||||
|
// $copy->title will contain the data returned by the callback, e.g. 'The title (copy)'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. If you want to replace whole element:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\TypeFilter\ReplaceFilter;
|
||||||
|
use DeepCopy\TypeMatcher\TypeMatcher;
|
||||||
|
|
||||||
|
$copier = new DeepCopy();
|
||||||
|
$callback = function (MyClass $myClass) {
|
||||||
|
return get_class($myClass);
|
||||||
|
};
|
||||||
|
$copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
|
||||||
|
|
||||||
|
$copy = $copier->copy([new MyClass, 'some string', new MyClass]);
|
||||||
|
|
||||||
|
// $copy will contain ['MyClass', 'some string', 'MyClass']
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable.
|
||||||
|
|
||||||
|
|
||||||
|
#### `ShallowCopyFilter` (type filter)
|
||||||
|
|
||||||
|
Stop *DeepCopy* from recursively copying element, using standard `clone` instead:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\TypeFilter\ShallowCopyFilter;
|
||||||
|
use DeepCopy\TypeMatcher\TypeMatcher;
|
||||||
|
use Mockery as m;
|
||||||
|
|
||||||
|
$this->deepCopy = new DeepCopy();
|
||||||
|
$this->deepCopy->addTypeFilter(
|
||||||
|
new ShallowCopyFilter,
|
||||||
|
new TypeMatcher(m\MockInterface::class)
|
||||||
|
);
|
||||||
|
|
||||||
|
$myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class));
|
||||||
|
// All mocks will be just cloned, not deep copied
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Edge cases
|
||||||
|
|
||||||
|
The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are
|
||||||
|
not applied. There is two ways for you to handle them:
|
||||||
|
|
||||||
|
- Implement your own `__clone()` method
|
||||||
|
- Use a filter with a type matcher
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
DeepCopy is distributed under the MIT license.
|
||||||
|
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
Running the tests is simple:
|
||||||
|
|
||||||
|
```php
|
||||||
|
vendor/bin/phpunit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Support
|
||||||
|
|
||||||
|
Get professional support via [the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-myclabs-deep-copy?utm_source=packagist-myclabs-deep-copy&utm_medium=referral&utm_campaign=readme).
|
43
vendor/myclabs/deep-copy/composer.json
vendored
Normal file
43
vendor/myclabs/deep-copy/composer.json
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "myclabs/deep-copy",
|
||||||
|
"description": "Create deep copies (clones) of your objects",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "library",
|
||||||
|
"keywords": [
|
||||||
|
"clone",
|
||||||
|
"copy",
|
||||||
|
"duplicate",
|
||||||
|
"object",
|
||||||
|
"object graph"
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/collections": "^1.6.8",
|
||||||
|
"doctrine/common": "^2.13.3 || ^3.2.2",
|
||||||
|
"phpspec/prophecy": "^1.10",
|
||||||
|
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/collections": "<1.6.8",
|
||||||
|
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"DeepCopy\\": "src/DeepCopy/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/DeepCopy/deep_copy.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"DeepCopyTest\\": "tests/DeepCopyTest/",
|
||||||
|
"DeepCopy\\": "fixtures/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"sort-packages": true
|
||||||
|
}
|
||||||
|
}
|
316
vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
vendored
Normal file
316
vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
vendored
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy;
|
||||||
|
|
||||||
|
use ArrayObject;
|
||||||
|
use DateInterval;
|
||||||
|
use DatePeriod;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use DateTimeZone;
|
||||||
|
use DeepCopy\Exception\CloneException;
|
||||||
|
use DeepCopy\Filter\ChainableFilter;
|
||||||
|
use DeepCopy\Filter\Filter;
|
||||||
|
use DeepCopy\Matcher\Matcher;
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
|
||||||
|
use DeepCopy\TypeFilter\Date\DatePeriodFilter;
|
||||||
|
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
|
||||||
|
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
|
||||||
|
use DeepCopy\TypeFilter\TypeFilter;
|
||||||
|
use DeepCopy\TypeMatcher\TypeMatcher;
|
||||||
|
use ReflectionObject;
|
||||||
|
use ReflectionProperty;
|
||||||
|
use SplDoublyLinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DeepCopy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var object[] List of objects copied.
|
||||||
|
*/
|
||||||
|
private $hashMap = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters to apply.
|
||||||
|
*
|
||||||
|
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||||
|
*/
|
||||||
|
private $filters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type Filters to apply.
|
||||||
|
*
|
||||||
|
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||||
|
*/
|
||||||
|
private $typeFilters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $skipUncloneable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $useCloneMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used
|
||||||
|
* instead of the regular deep cloning.
|
||||||
|
*/
|
||||||
|
public function __construct($useCloneMethod = false)
|
||||||
|
{
|
||||||
|
$this->useCloneMethod = $useCloneMethod;
|
||||||
|
|
||||||
|
$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
|
||||||
|
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
|
||||||
|
$this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class));
|
||||||
|
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If enabled, will not throw an exception when coming across an uncloneable property.
|
||||||
|
*
|
||||||
|
* @param $skipUncloneable
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function skipUncloneable($skipUncloneable = true)
|
||||||
|
{
|
||||||
|
$this->skipUncloneable = $skipUncloneable;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deep copies the given object.
|
||||||
|
*
|
||||||
|
* @param mixed $object
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function copy($object)
|
||||||
|
{
|
||||||
|
$this->hashMap = [];
|
||||||
|
|
||||||
|
return $this->recursiveCopy($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFilter(Filter $filter, Matcher $matcher)
|
||||||
|
{
|
||||||
|
$this->filters[] = [
|
||||||
|
'matcher' => $matcher,
|
||||||
|
'filter' => $filter,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prependFilter(Filter $filter, Matcher $matcher)
|
||||||
|
{
|
||||||
|
array_unshift($this->filters, [
|
||||||
|
'matcher' => $matcher,
|
||||||
|
'filter' => $filter,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
|
||||||
|
{
|
||||||
|
$this->typeFilters[] = [
|
||||||
|
'matcher' => $matcher,
|
||||||
|
'filter' => $filter,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function recursiveCopy($var)
|
||||||
|
{
|
||||||
|
// Matches Type Filter
|
||||||
|
if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) {
|
||||||
|
return $filter->apply($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resource
|
||||||
|
if (is_resource($var)) {
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array
|
||||||
|
if (is_array($var)) {
|
||||||
|
return $this->copyArray($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scalar
|
||||||
|
if (! is_object($var)) {
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enum
|
||||||
|
if (PHP_VERSION_ID >= 80100 && enum_exists(get_class($var))) {
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object
|
||||||
|
return $this->copyObject($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy an array
|
||||||
|
* @param array $array
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function copyArray(array $array)
|
||||||
|
{
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
$array[$key] = $this->recursiveCopy($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies an object.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
*
|
||||||
|
* @throws CloneException
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
private function copyObject($object)
|
||||||
|
{
|
||||||
|
$objectHash = spl_object_hash($object);
|
||||||
|
|
||||||
|
if (isset($this->hashMap[$objectHash])) {
|
||||||
|
return $this->hashMap[$objectHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflectedObject = new ReflectionObject($object);
|
||||||
|
$isCloneable = $reflectedObject->isCloneable();
|
||||||
|
|
||||||
|
if (false === $isCloneable) {
|
||||||
|
if ($this->skipUncloneable) {
|
||||||
|
$this->hashMap[$objectHash] = $object;
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CloneException(
|
||||||
|
sprintf(
|
||||||
|
'The class "%s" is not cloneable.',
|
||||||
|
$reflectedObject->getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newObject = clone $object;
|
||||||
|
$this->hashMap[$objectHash] = $newObject;
|
||||||
|
|
||||||
|
if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) {
|
||||||
|
return $newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) {
|
||||||
|
return $newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ReflectionHelper::getProperties($reflectedObject) as $property) {
|
||||||
|
$this->copyObjectProperty($newObject, $property);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function copyObjectProperty($object, ReflectionProperty $property)
|
||||||
|
{
|
||||||
|
// Ignore static properties
|
||||||
|
if ($property->isStatic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore readonly properties
|
||||||
|
if (method_exists($property, 'isReadOnly') && $property->isReadOnly()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the filters
|
||||||
|
foreach ($this->filters as $item) {
|
||||||
|
/** @var Matcher $matcher */
|
||||||
|
$matcher = $item['matcher'];
|
||||||
|
/** @var Filter $filter */
|
||||||
|
$filter = $item['filter'];
|
||||||
|
|
||||||
|
if ($matcher->matches($object, $property->getName())) {
|
||||||
|
$filter->apply(
|
||||||
|
$object,
|
||||||
|
$property->getName(),
|
||||||
|
function ($object) {
|
||||||
|
return $this->recursiveCopy($object);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($filter instanceof ChainableFilter) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a filter matches, we stop processing this property
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setAccessible(true);
|
||||||
|
|
||||||
|
// Ignore uninitialized properties (for PHP >7.4)
|
||||||
|
if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$propertyValue = $property->getValue($object);
|
||||||
|
|
||||||
|
// Copy the property
|
||||||
|
$property->setValue($object, $this->recursiveCopy($propertyValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first filter that matches variable, `null` if no such filter found.
|
||||||
|
*
|
||||||
|
* @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and
|
||||||
|
* 'matcher' with value of type {@see TypeMatcher}
|
||||||
|
* @param mixed $var
|
||||||
|
*
|
||||||
|
* @return TypeFilter|null
|
||||||
|
*/
|
||||||
|
private function getFirstMatchedTypeFilter(array $filterRecords, $var)
|
||||||
|
{
|
||||||
|
$matched = $this->first(
|
||||||
|
$filterRecords,
|
||||||
|
function (array $record) use ($var) {
|
||||||
|
/* @var TypeMatcher $matcher */
|
||||||
|
$matcher = $record['matcher'];
|
||||||
|
|
||||||
|
return $matcher->matches($var);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return isset($matched) ? $matched['filter'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns first element that matches predicate, `null` if no such element found.
|
||||||
|
*
|
||||||
|
* @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||||
|
* @param callable $predicate Predicate arguments are: element.
|
||||||
|
*
|
||||||
|
* @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher'
|
||||||
|
* with value of type {@see TypeMatcher} or `null`.
|
||||||
|
*/
|
||||||
|
private function first(array $elements, callable $predicate)
|
||||||
|
{
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
if (call_user_func($predicate, $element)) {
|
||||||
|
return $element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
9
vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php
vendored
Normal file
9
vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Exception;
|
||||||
|
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
class CloneException extends UnexpectedValueException
|
||||||
|
{
|
||||||
|
}
|
9
vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php
vendored
Normal file
9
vendor/myclabs/deep-copy/src/DeepCopy/Exception/PropertyException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Exception;
|
||||||
|
|
||||||
|
use ReflectionException;
|
||||||
|
|
||||||
|
class PropertyException extends ReflectionException
|
||||||
|
{
|
||||||
|
}
|
24
vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php
vendored
Normal file
24
vendor/myclabs/deep-copy/src/DeepCopy/Filter/ChainableFilter.php
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a decorator filter that will not stop the chain of filters.
|
||||||
|
*/
|
||||||
|
class ChainableFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Filter
|
||||||
|
*/
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
|
public function __construct(Filter $filter)
|
||||||
|
{
|
||||||
|
$this->filter = $filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$this->filter->apply($object, $property, $objectCopier);
|
||||||
|
}
|
||||||
|
}
|
33
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
vendored
Normal file
33
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter\Doctrine;
|
||||||
|
|
||||||
|
use DeepCopy\Filter\Filter;
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DoctrineCollectionFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Copies the object property doctrine collection.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||||
|
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
$oldCollection = $reflectionProperty->getValue($object);
|
||||||
|
|
||||||
|
$newCollection = $oldCollection->map(
|
||||||
|
function ($item) use ($objectCopier) {
|
||||||
|
return $objectCopier($item);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$reflectionProperty->setValue($object, $newCollection);
|
||||||
|
}
|
||||||
|
}
|
28
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
vendored
Normal file
28
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter\Doctrine;
|
||||||
|
|
||||||
|
use DeepCopy\Filter\Filter;
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DoctrineEmptyCollectionFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the object property to an empty doctrine collection.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string $property
|
||||||
|
* @param callable $objectCopier
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
|
||||||
|
$reflectionProperty->setValue($object, new ArrayCollection());
|
||||||
|
}
|
||||||
|
}
|
22
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php
vendored
Normal file
22
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter\Doctrine;
|
||||||
|
|
||||||
|
use DeepCopy\Filter\Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DoctrineProxyFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Triggers the magic method __load() on a Doctrine Proxy class to load the
|
||||||
|
* actual entity from the database.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$object->__load();
|
||||||
|
}
|
||||||
|
}
|
18
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php
vendored
Normal file
18
vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to apply to a property while copying an object
|
||||||
|
*/
|
||||||
|
interface Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Applies the filter to the object.
|
||||||
|
*
|
||||||
|
* @param object $object
|
||||||
|
* @param string $property
|
||||||
|
* @param callable $objectCopier
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier);
|
||||||
|
}
|
16
vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php
vendored
Normal file
16
vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter;
|
||||||
|
|
||||||
|
class KeepFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Keeps the value of the object property.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
}
|
39
vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php
vendored
Normal file
39
vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter;
|
||||||
|
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class ReplaceFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var callable
|
||||||
|
*/
|
||||||
|
protected $callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable $callable Will be called to get the new value for each property to replace
|
||||||
|
*/
|
||||||
|
public function __construct(callable $callable)
|
||||||
|
{
|
||||||
|
$this->callback = $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the object property by the result of the callback called with the object property.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
|
||||||
|
$value = call_user_func($this->callback, $reflectionProperty->getValue($object));
|
||||||
|
|
||||||
|
$reflectionProperty->setValue($object, $value);
|
||||||
|
}
|
||||||
|
}
|
24
vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php
vendored
Normal file
24
vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Filter;
|
||||||
|
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class SetNullFilter implements Filter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the object property to null.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($object, $property, $objectCopier)
|
||||||
|
{
|
||||||
|
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||||
|
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
$reflectionProperty->setValue($object, null);
|
||||||
|
}
|
||||||
|
}
|
22
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php
vendored
Normal file
22
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Matcher\Doctrine;
|
||||||
|
|
||||||
|
use DeepCopy\Matcher\Matcher;
|
||||||
|
use Doctrine\Persistence\Proxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DoctrineProxyMatcher implements Matcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Matches a Doctrine Proxy class.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function matches($object, $property)
|
||||||
|
{
|
||||||
|
return $object instanceof Proxy;
|
||||||
|
}
|
||||||
|
}
|
14
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php
vendored
Normal file
14
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.php
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Matcher;
|
||||||
|
|
||||||
|
interface Matcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param object $object
|
||||||
|
* @param string $property
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function matches($object, $property);
|
||||||
|
}
|
39
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php
vendored
Normal file
39
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Matcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class PropertyMatcher implements Matcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class Class name
|
||||||
|
* @param string $property Property name
|
||||||
|
*/
|
||||||
|
public function __construct($class, $property)
|
||||||
|
{
|
||||||
|
$this->class = $class;
|
||||||
|
$this->property = $property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a specific property of a specific class.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function matches($object, $property)
|
||||||
|
{
|
||||||
|
return ($object instanceof $this->class) && $property == $this->property;
|
||||||
|
}
|
||||||
|
}
|
32
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php
vendored
Normal file
32
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Matcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class PropertyNameMatcher implements Matcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $property Property name
|
||||||
|
*/
|
||||||
|
public function __construct($property)
|
||||||
|
{
|
||||||
|
$this->property = $property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a property by its name.
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function matches($object, $property)
|
||||||
|
{
|
||||||
|
return $property == $this->property;
|
||||||
|
}
|
||||||
|
}
|
52
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php
vendored
Normal file
52
vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Matcher;
|
||||||
|
|
||||||
|
use DeepCopy\Reflection\ReflectionHelper;
|
||||||
|
use ReflectionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a property by its type.
|
||||||
|
*
|
||||||
|
* It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences
|
||||||
|
* of given type in copied context (eg. array elements), not just on object properties.
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class PropertyTypeMatcher implements Matcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $propertyType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $propertyType Property type
|
||||||
|
*/
|
||||||
|
public function __construct($propertyType)
|
||||||
|
{
|
||||||
|
$this->propertyType = $propertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function matches($object, $property)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||||
|
} catch (ReflectionException $exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
|
||||||
|
// Uninitialized properties (for PHP >7.4)
|
||||||
|
if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) {
|
||||||
|
// null instanceof $this->propertyType
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reflectionProperty->getValue($object) instanceof $this->propertyType;
|
||||||
|
}
|
||||||
|
}
|
78
vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php
vendored
Normal file
78
vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\Reflection;
|
||||||
|
|
||||||
|
use DeepCopy\Exception\PropertyException;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionObject;
|
||||||
|
use ReflectionProperty;
|
||||||
|
|
||||||
|
class ReflectionHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Retrieves all properties (including private ones), from object and all its ancestors.
|
||||||
|
*
|
||||||
|
* Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes.
|
||||||
|
*
|
||||||
|
* @author muratyaman@gmail.com
|
||||||
|
* @see http://php.net/manual/en/reflectionclass.getproperties.php
|
||||||
|
*
|
||||||
|
* @param ReflectionClass $ref
|
||||||
|
*
|
||||||
|
* @return ReflectionProperty[]
|
||||||
|
*/
|
||||||
|
public static function getProperties(ReflectionClass $ref)
|
||||||
|
{
|
||||||
|
$props = $ref->getProperties();
|
||||||
|
$propsArr = array();
|
||||||
|
|
||||||
|
foreach ($props as $prop) {
|
||||||
|
$propertyName = $prop->getName();
|
||||||
|
$propsArr[$propertyName] = $prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parentClass = $ref->getParentClass()) {
|
||||||
|
$parentPropsArr = self::getProperties($parentClass);
|
||||||
|
foreach ($propsArr as $key => $property) {
|
||||||
|
$parentPropsArr[$key] = $property;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parentPropsArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $propsArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves property by name from object and all its ancestors.
|
||||||
|
*
|
||||||
|
* @param object|string $object
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @throws PropertyException
|
||||||
|
* @throws ReflectionException
|
||||||
|
*
|
||||||
|
* @return ReflectionProperty
|
||||||
|
*/
|
||||||
|
public static function getProperty($object, $name)
|
||||||
|
{
|
||||||
|
$reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object);
|
||||||
|
|
||||||
|
if ($reflection->hasProperty($name)) {
|
||||||
|
return $reflection->getProperty($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parentClass = $reflection->getParentClass()) {
|
||||||
|
return self::getProperty($parentClass->getName(), $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PropertyException(
|
||||||
|
sprintf(
|
||||||
|
'The class "%s" doesn\'t have a property with the given name: "%s".',
|
||||||
|
is_object($object) ? get_class($object) : $object,
|
||||||
|
$name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
33
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php
vendored
Normal file
33
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DateIntervalFilter.php
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter\Date;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DeepCopy\TypeFilter\TypeFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*
|
||||||
|
* @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+.
|
||||||
|
*/
|
||||||
|
class DateIntervalFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param DateInterval $element
|
||||||
|
*
|
||||||
|
* @see http://news.php.net/php.bugs/205076
|
||||||
|
*/
|
||||||
|
public function apply($element)
|
||||||
|
{
|
||||||
|
$copy = new DateInterval('P0D');
|
||||||
|
|
||||||
|
foreach ($element as $propertyName => $propertyValue) {
|
||||||
|
$copy->{$propertyName} = $propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $copy;
|
||||||
|
}
|
||||||
|
}
|
42
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php
vendored
Normal file
42
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter\Date;
|
||||||
|
|
||||||
|
use DatePeriod;
|
||||||
|
use DeepCopy\TypeFilter\TypeFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class DatePeriodFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param DatePeriod $element
|
||||||
|
*
|
||||||
|
* @see http://news.php.net/php.bugs/205076
|
||||||
|
*/
|
||||||
|
public function apply($element)
|
||||||
|
{
|
||||||
|
$options = 0;
|
||||||
|
if (PHP_VERSION_ID >= 80200 && $element->include_end_date) {
|
||||||
|
$options |= DatePeriod::INCLUDE_END_DATE;
|
||||||
|
}
|
||||||
|
if (!$element->include_start_date) {
|
||||||
|
$options |= DatePeriod::EXCLUDE_START_DATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($element->getEndDate()) {
|
||||||
|
return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID >= 70217) {
|
||||||
|
$recurrences = $element->getRecurrences();
|
||||||
|
} else {
|
||||||
|
$recurrences = $element->recurrences - $element->include_start_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options);
|
||||||
|
}
|
||||||
|
}
|
30
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php
vendored
Normal file
30
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class ReplaceFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var callable
|
||||||
|
*/
|
||||||
|
protected $callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable $callable Will be called to get the new value for each element to replace
|
||||||
|
*/
|
||||||
|
public function __construct(callable $callable)
|
||||||
|
{
|
||||||
|
$this->callback = $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($element)
|
||||||
|
{
|
||||||
|
return call_user_func($this->callback, $element);
|
||||||
|
}
|
||||||
|
}
|
17
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php
vendored
Normal file
17
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class ShallowCopyFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($element)
|
||||||
|
{
|
||||||
|
return clone $element;
|
||||||
|
}
|
||||||
|
}
|
36
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php
vendored
Normal file
36
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
namespace DeepCopy\TypeFilter\Spl;
|
||||||
|
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\TypeFilter\TypeFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In PHP 7.4 the storage of an ArrayObject isn't returned as
|
||||||
|
* ReflectionProperty. So we deep copy its array copy.
|
||||||
|
*/
|
||||||
|
final class ArrayObjectFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var DeepCopy
|
||||||
|
*/
|
||||||
|
private $copier;
|
||||||
|
|
||||||
|
public function __construct(DeepCopy $copier)
|
||||||
|
{
|
||||||
|
$this->copier = $copier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($arrayObject)
|
||||||
|
{
|
||||||
|
$clone = clone $arrayObject;
|
||||||
|
foreach ($arrayObject->getArrayCopy() as $k => $v) {
|
||||||
|
$clone->offsetSet($k, $this->copier->copy($v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
10
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php
vendored
Normal file
10
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter\Spl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@see SplDoublyLinkedListFilter} instead.
|
||||||
|
*/
|
||||||
|
class SplDoublyLinkedList extends SplDoublyLinkedListFilter
|
||||||
|
{
|
||||||
|
}
|
51
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php
vendored
Normal file
51
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter\Spl;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use DeepCopy\DeepCopy;
|
||||||
|
use DeepCopy\TypeFilter\TypeFilter;
|
||||||
|
use SplDoublyLinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class SplDoublyLinkedListFilter implements TypeFilter
|
||||||
|
{
|
||||||
|
private $copier;
|
||||||
|
|
||||||
|
public function __construct(DeepCopy $copier)
|
||||||
|
{
|
||||||
|
$this->copier = $copier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply($element)
|
||||||
|
{
|
||||||
|
$newElement = clone $element;
|
||||||
|
|
||||||
|
$copy = $this->createCopyClosure();
|
||||||
|
|
||||||
|
return $copy($newElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createCopyClosure()
|
||||||
|
{
|
||||||
|
$copier = $this->copier;
|
||||||
|
|
||||||
|
$copy = function (SplDoublyLinkedList $list) use ($copier) {
|
||||||
|
// Replace each element in the list with a deep copy of itself
|
||||||
|
for ($i = 1; $i <= $list->count(); $i++) {
|
||||||
|
$copy = $copier->recursiveCopy($list->shift());
|
||||||
|
|
||||||
|
$list->push($copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Closure::bind($copy, null, DeepCopy::class);
|
||||||
|
}
|
||||||
|
}
|
13
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php
vendored
Normal file
13
vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.php
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeFilter;
|
||||||
|
|
||||||
|
interface TypeFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Applies the filter to the object.
|
||||||
|
*
|
||||||
|
* @param mixed $element
|
||||||
|
*/
|
||||||
|
public function apply($element);
|
||||||
|
}
|
29
vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php
vendored
Normal file
29
vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy\TypeMatcher;
|
||||||
|
|
||||||
|
class TypeMatcher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
*/
|
||||||
|
public function __construct($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $element
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function matches($element)
|
||||||
|
{
|
||||||
|
return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type;
|
||||||
|
}
|
||||||
|
}
|
20
vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php
vendored
Normal file
20
vendor/myclabs/deep-copy/src/DeepCopy/deep_copy.php
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DeepCopy;
|
||||||
|
|
||||||
|
use function function_exists;
|
||||||
|
|
||||||
|
if (false === function_exists('DeepCopy\deep_copy')) {
|
||||||
|
/**
|
||||||
|
* Deep copies the given value.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
* @param bool $useCloneMethod
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function deep_copy($value, $useCloneMethod = false)
|
||||||
|
{
|
||||||
|
return (new DeepCopy($useCloneMethod))->copy($value);
|
||||||
|
}
|
||||||
|
}
|
29
vendor/nikic/php-parser/LICENSE
vendored
Normal file
29
vendor/nikic/php-parser/LICENSE
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2011, Nikita Popov
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
233
vendor/nikic/php-parser/README.md
vendored
Normal file
233
vendor/nikic/php-parser/README.md
vendored
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
PHP Parser
|
||||||
|
==========
|
||||||
|
|
||||||
|
[](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
|
||||||
|
|
||||||
|
This is a PHP parser written in PHP. Its purpose is to simplify static code analysis and
|
||||||
|
manipulation.
|
||||||
|
|
||||||
|
[**Documentation for version 5.x**][doc_master] (current; for running on PHP >= 7.4; for parsing PHP 7.0 to PHP 8.4, with limited support for parsing PHP 5.x).
|
||||||
|
|
||||||
|
[Documentation for version 4.x][doc_4_x] (supported; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.3).
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
The main features provided by this library are:
|
||||||
|
|
||||||
|
* Parsing PHP 7, and PHP 8 code into an abstract syntax tree (AST).
|
||||||
|
* Invalid code can be parsed into a partial AST.
|
||||||
|
* The AST contains accurate location information.
|
||||||
|
* Dumping the AST in human-readable form.
|
||||||
|
* Converting an AST back to PHP code.
|
||||||
|
* Formatting can be preserved for partially changed ASTs.
|
||||||
|
* Infrastructure to traverse and modify ASTs.
|
||||||
|
* Resolution of namespaced names.
|
||||||
|
* Evaluation of constant expressions.
|
||||||
|
* Builders to simplify AST construction for code generation.
|
||||||
|
* Converting an AST into JSON and back.
|
||||||
|
|
||||||
|
Quick Start
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Install the library using [composer](https://getcomposer.org):
|
||||||
|
|
||||||
|
php composer.phar require nikic/php-parser
|
||||||
|
|
||||||
|
Parse some PHP code into an AST and dump the result in human-readable form:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
use PhpParser\Error;
|
||||||
|
use PhpParser\NodeDumper;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
|
||||||
|
$code = <<<'CODE'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test($foo)
|
||||||
|
{
|
||||||
|
var_dump($foo);
|
||||||
|
}
|
||||||
|
CODE;
|
||||||
|
|
||||||
|
$parser = (new ParserFactory())->createForNewestSupportedVersion();
|
||||||
|
try {
|
||||||
|
$ast = $parser->parse($code);
|
||||||
|
} catch (Error $error) {
|
||||||
|
echo "Parse error: {$error->getMessage()}\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dumper = new NodeDumper;
|
||||||
|
echo $dumper->dump($ast) . "\n";
|
||||||
|
```
|
||||||
|
|
||||||
|
This dumps an AST looking something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
array(
|
||||||
|
0: Stmt_Function(
|
||||||
|
attrGroups: array(
|
||||||
|
)
|
||||||
|
byRef: false
|
||||||
|
name: Identifier(
|
||||||
|
name: test
|
||||||
|
)
|
||||||
|
params: array(
|
||||||
|
0: Param(
|
||||||
|
attrGroups: array(
|
||||||
|
)
|
||||||
|
flags: 0
|
||||||
|
type: null
|
||||||
|
byRef: false
|
||||||
|
variadic: false
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
0: Stmt_Expression(
|
||||||
|
expr: Expr_FuncCall(
|
||||||
|
name: Name(
|
||||||
|
name: var_dump
|
||||||
|
)
|
||||||
|
args: array(
|
||||||
|
0: Arg(
|
||||||
|
name: null
|
||||||
|
value: Expr_Variable(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
byRef: false
|
||||||
|
unpack: false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's traverse the AST and perform some kind of modification. For example, drop all function bodies:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt\Function_;
|
||||||
|
use PhpParser\NodeTraverser;
|
||||||
|
use PhpParser\NodeVisitorAbstract;
|
||||||
|
|
||||||
|
$traverser = new NodeTraverser();
|
||||||
|
$traverser->addVisitor(new class extends NodeVisitorAbstract {
|
||||||
|
public function enterNode(Node $node) {
|
||||||
|
if ($node instanceof Function_) {
|
||||||
|
// Clean out the function body
|
||||||
|
$node->stmts = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$ast = $traverser->traverse($ast);
|
||||||
|
echo $dumper->dump($ast) . "\n";
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives us an AST where the `Function_::$stmts` are empty:
|
||||||
|
|
||||||
|
```
|
||||||
|
array(
|
||||||
|
0: Stmt_Function(
|
||||||
|
attrGroups: array(
|
||||||
|
)
|
||||||
|
byRef: false
|
||||||
|
name: Identifier(
|
||||||
|
name: test
|
||||||
|
)
|
||||||
|
params: array(
|
||||||
|
0: Param(
|
||||||
|
attrGroups: array(
|
||||||
|
)
|
||||||
|
type: null
|
||||||
|
byRef: false
|
||||||
|
variadic: false
|
||||||
|
var: Expr_Variable(
|
||||||
|
name: foo
|
||||||
|
)
|
||||||
|
default: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
returnType: null
|
||||||
|
stmts: array(
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we can convert the new AST back to PHP code:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use PhpParser\PrettyPrinter;
|
||||||
|
|
||||||
|
$prettyPrinter = new PrettyPrinter\Standard;
|
||||||
|
echo $prettyPrinter->prettyPrintFile($ast);
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives us our original code, minus the `var_dump()` call inside the function:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function test($foo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For a more comprehensive introduction, see the documentation.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
1. [Introduction](doc/0_Introduction.markdown)
|
||||||
|
2. [Usage of basic components](doc/2_Usage_of_basic_components.markdown)
|
||||||
|
|
||||||
|
Component documentation:
|
||||||
|
|
||||||
|
* [Walking the AST](doc/component/Walking_the_AST.markdown)
|
||||||
|
* Node visitors
|
||||||
|
* Modifying the AST from a visitor
|
||||||
|
* Short-circuiting traversals
|
||||||
|
* Interleaved visitors
|
||||||
|
* Simple node finding API
|
||||||
|
* Parent and sibling references
|
||||||
|
* [Name resolution](doc/component/Name_resolution.markdown)
|
||||||
|
* Name resolver options
|
||||||
|
* Name resolution context
|
||||||
|
* [Pretty printing](doc/component/Pretty_printing.markdown)
|
||||||
|
* Converting AST back to PHP code
|
||||||
|
* Customizing formatting
|
||||||
|
* Formatting-preserving code transformations
|
||||||
|
* [AST builders](doc/component/AST_builders.markdown)
|
||||||
|
* Fluent builders for AST nodes
|
||||||
|
* [Lexer](doc/component/Lexer.markdown)
|
||||||
|
* Emulation
|
||||||
|
* Tokens, positions and attributes
|
||||||
|
* [Error handling](doc/component/Error_handling.markdown)
|
||||||
|
* Column information for errors
|
||||||
|
* Error recovery (parsing of syntactically incorrect code)
|
||||||
|
* [Constant expression evaluation](doc/component/Constant_expression_evaluation.markdown)
|
||||||
|
* Evaluating constant/property/etc initializers
|
||||||
|
* Handling errors and unsupported expressions
|
||||||
|
* [JSON representation](doc/component/JSON_representation.markdown)
|
||||||
|
* JSON encoding and decoding of ASTs
|
||||||
|
* [Performance](doc/component/Performance.markdown)
|
||||||
|
* Disabling Xdebug
|
||||||
|
* Reusing objects
|
||||||
|
* Garbage collection impact
|
||||||
|
* [Frequently asked questions](doc/component/FAQ.markdown)
|
||||||
|
* Parent and sibling references
|
||||||
|
|
||||||
|
[doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc
|
||||||
|
[doc_4_x]: https://github.com/nikic/PHP-Parser/tree/4.x/doc
|
||||||
|
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc
|
206
vendor/nikic/php-parser/bin/php-parse
vendored
Normal file
206
vendor/nikic/php-parser/bin/php-parse
vendored
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
require $file;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set('xdebug.max_nesting_level', 3000);
|
||||||
|
|
||||||
|
// Disable Xdebug var_dump() output truncation
|
||||||
|
ini_set('xdebug.var_display_max_children', -1);
|
||||||
|
ini_set('xdebug.var_display_max_data', -1);
|
||||||
|
ini_set('xdebug.var_display_max_depth', -1);
|
||||||
|
|
||||||
|
list($operations, $files, $attributes) = parseArgs($argv);
|
||||||
|
|
||||||
|
/* Dump nodes by default */
|
||||||
|
if (empty($operations)) {
|
||||||
|
$operations[] = 'dump';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($files)) {
|
||||||
|
showHelp("Must specify at least one file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$parser = (new PhpParser\ParserFactory())->createForVersion($attributes['version']);
|
||||||
|
$dumper = new PhpParser\NodeDumper([
|
||||||
|
'dumpComments' => true,
|
||||||
|
'dumpPositions' => $attributes['with-positions'],
|
||||||
|
]);
|
||||||
|
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
||||||
|
|
||||||
|
$traverser = new PhpParser\NodeTraverser();
|
||||||
|
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver);
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if ($file === '-') {
|
||||||
|
$code = file_get_contents('php://stdin');
|
||||||
|
fwrite(STDERR, "====> Stdin:\n");
|
||||||
|
} else if (strpos($file, '<?php') === 0) {
|
||||||
|
$code = $file;
|
||||||
|
fwrite(STDERR, "====> Code $code\n");
|
||||||
|
} else {
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
fwrite(STDERR, "File $file does not exist.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = file_get_contents($file);
|
||||||
|
fwrite(STDERR, "====> File $file:\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($attributes['with-recovery']) {
|
||||||
|
$errorHandler = new PhpParser\ErrorHandler\Collecting;
|
||||||
|
$stmts = $parser->parse($code, $errorHandler);
|
||||||
|
foreach ($errorHandler->getErrors() as $error) {
|
||||||
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
||||||
|
fwrite(STDERR, $message . "\n");
|
||||||
|
}
|
||||||
|
if (null === $stmts) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$stmts = $parser->parse($code);
|
||||||
|
} catch (PhpParser\Error $error) {
|
||||||
|
$message = formatErrorMessage($error, $code, $attributes['with-column-info']);
|
||||||
|
fwrite(STDERR, $message . "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($operations as $operation) {
|
||||||
|
if ('dump' === $operation) {
|
||||||
|
fwrite(STDERR, "==> Node dump:\n");
|
||||||
|
echo $dumper->dump($stmts, $code), "\n";
|
||||||
|
} elseif ('pretty-print' === $operation) {
|
||||||
|
fwrite(STDERR, "==> Pretty print:\n");
|
||||||
|
echo $prettyPrinter->prettyPrintFile($stmts), "\n";
|
||||||
|
} elseif ('json-dump' === $operation) {
|
||||||
|
fwrite(STDERR, "==> JSON dump:\n");
|
||||||
|
echo json_encode($stmts, JSON_PRETTY_PRINT), "\n";
|
||||||
|
} elseif ('var-dump' === $operation) {
|
||||||
|
fwrite(STDERR, "==> var_dump():\n");
|
||||||
|
var_dump($stmts);
|
||||||
|
} elseif ('resolve-names' === $operation) {
|
||||||
|
fwrite(STDERR, "==> Resolved names.\n");
|
||||||
|
$stmts = $traverser->traverse($stmts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) {
|
||||||
|
if ($withColumnInfo && $e->hasColumnInfo()) {
|
||||||
|
return $e->getMessageWithColumnInfo($code);
|
||||||
|
} else {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showHelp($error = '') {
|
||||||
|
if ($error) {
|
||||||
|
fwrite(STDERR, $error . "\n\n");
|
||||||
|
}
|
||||||
|
fwrite($error ? STDERR : STDOUT, <<<'OUTPUT'
|
||||||
|
Usage: php-parse [operations] file1.php [file2.php ...]
|
||||||
|
or: php-parse [operations] "<?php code"
|
||||||
|
Turn PHP source code into an abstract syntax tree.
|
||||||
|
|
||||||
|
Operations is a list of the following options (--dump by default):
|
||||||
|
|
||||||
|
-d, --dump Dump nodes using NodeDumper
|
||||||
|
-p, --pretty-print Pretty print file using PrettyPrinter\Standard
|
||||||
|
-j, --json-dump Print json_encode() result
|
||||||
|
--var-dump var_dump() nodes (for exact structure)
|
||||||
|
-N, --resolve-names Resolve names using NodeVisitor\NameResolver
|
||||||
|
-c, --with-column-info Show column-numbers for errors (if available)
|
||||||
|
-P, --with-positions Show positions in node dumps
|
||||||
|
-r, --with-recovery Use parsing with error recovery
|
||||||
|
--version=VERSION Target specific PHP version (default: newest)
|
||||||
|
-h, --help Display this page
|
||||||
|
|
||||||
|
Example:
|
||||||
|
php-parse -d -p -N -d file.php
|
||||||
|
|
||||||
|
Dumps nodes, pretty prints them, then resolves names and dumps them again.
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT
|
||||||
|
);
|
||||||
|
exit($error ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseArgs($args) {
|
||||||
|
$operations = [];
|
||||||
|
$files = [];
|
||||||
|
$attributes = [
|
||||||
|
'with-column-info' => false,
|
||||||
|
'with-positions' => false,
|
||||||
|
'with-recovery' => false,
|
||||||
|
'version' => PhpParser\PhpVersion::getNewestSupported(),
|
||||||
|
];
|
||||||
|
|
||||||
|
array_shift($args);
|
||||||
|
$parseOptions = true;
|
||||||
|
foreach ($args as $arg) {
|
||||||
|
if (!$parseOptions) {
|
||||||
|
$files[] = $arg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($arg) {
|
||||||
|
case '--dump':
|
||||||
|
case '-d':
|
||||||
|
$operations[] = 'dump';
|
||||||
|
break;
|
||||||
|
case '--pretty-print':
|
||||||
|
case '-p':
|
||||||
|
$operations[] = 'pretty-print';
|
||||||
|
break;
|
||||||
|
case '--json-dump':
|
||||||
|
case '-j':
|
||||||
|
$operations[] = 'json-dump';
|
||||||
|
break;
|
||||||
|
case '--var-dump':
|
||||||
|
$operations[] = 'var-dump';
|
||||||
|
break;
|
||||||
|
case '--resolve-names':
|
||||||
|
case '-N';
|
||||||
|
$operations[] = 'resolve-names';
|
||||||
|
break;
|
||||||
|
case '--with-column-info':
|
||||||
|
case '-c';
|
||||||
|
$attributes['with-column-info'] = true;
|
||||||
|
break;
|
||||||
|
case '--with-positions':
|
||||||
|
case '-P':
|
||||||
|
$attributes['with-positions'] = true;
|
||||||
|
break;
|
||||||
|
case '--with-recovery':
|
||||||
|
case '-r':
|
||||||
|
$attributes['with-recovery'] = true;
|
||||||
|
break;
|
||||||
|
case '--help':
|
||||||
|
case '-h';
|
||||||
|
showHelp();
|
||||||
|
break;
|
||||||
|
case '--':
|
||||||
|
$parseOptions = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (preg_match('/^--version=(.*)$/', $arg, $matches)) {
|
||||||
|
$attributes['version'] = PhpParser\PhpVersion::fromString($matches[1]);
|
||||||
|
} elseif ($arg[0] === '-' && \strlen($arg[0]) > 1) {
|
||||||
|
showHelp("Invalid operation $arg.");
|
||||||
|
} else {
|
||||||
|
$files[] = $arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$operations, $files, $attributes];
|
||||||
|
}
|
43
vendor/nikic/php-parser/composer.json
vendored
Normal file
43
vendor/nikic/php-parser/composer.json
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "nikic/php-parser",
|
||||||
|
"type": "library",
|
||||||
|
"description": "A PHP parser written in PHP",
|
||||||
|
"keywords": [
|
||||||
|
"php",
|
||||||
|
"parser"
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nikita Popov"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.4",
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-ctype": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0",
|
||||||
|
"ircmaxell/php-yacc": "^0.0.7"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "5.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpParser\\": "lib/PhpParser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpParser\\": "test/PhpParser/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/php-parse"
|
||||||
|
]
|
||||||
|
}
|
12
vendor/nikic/php-parser/lib/PhpParser/Builder.php
vendored
Normal file
12
vendor/nikic/php-parser/lib/PhpParser/Builder.php
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser;
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
/**
|
||||||
|
* Returns the built node.
|
||||||
|
*
|
||||||
|
* @return Node The built node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node;
|
||||||
|
}
|
150
vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php
vendored
Normal file
150
vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Const_;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class ClassConst implements PhpParser\Builder {
|
||||||
|
protected int $flags = 0;
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
protected array $attributes = [];
|
||||||
|
/** @var list<Const_> */
|
||||||
|
protected array $constants = [];
|
||||||
|
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
/** @var Identifier|Node\Name|Node\ComplexType|null */
|
||||||
|
protected ?Node $type = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a class constant builder
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||||
|
*/
|
||||||
|
public function __construct($name, $value) {
|
||||||
|
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add another constant to const group
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addConst($name, $value) {
|
||||||
|
$this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the constant public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the constant protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the constant private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the constant final.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeFinal() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doc comment for the constant.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDocComment($docComment) {
|
||||||
|
$this->attributes = [
|
||||||
|
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the constant type.
|
||||||
|
*
|
||||||
|
* @param string|Node\Name|Identifier|Node\ComplexType $type
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setType($type) {
|
||||||
|
$this->type = BuilderHelpers::normalizeType($type);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built class node.
|
||||||
|
*
|
||||||
|
* @return Stmt\ClassConst The built constant node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\ClassConst(
|
||||||
|
$this->constants,
|
||||||
|
$this->flags,
|
||||||
|
$this->attributes,
|
||||||
|
$this->attributeGroups,
|
||||||
|
$this->type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
151
vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php
vendored
Normal file
151
vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Class_ extends Declaration {
|
||||||
|
protected string $name;
|
||||||
|
protected ?Name $extends = null;
|
||||||
|
/** @var list<Name> */
|
||||||
|
protected array $implements = [];
|
||||||
|
protected int $flags = 0;
|
||||||
|
/** @var list<Stmt\TraitUse> */
|
||||||
|
protected array $uses = [];
|
||||||
|
/** @var list<Stmt\ClassConst> */
|
||||||
|
protected array $constants = [];
|
||||||
|
/** @var list<Stmt\Property> */
|
||||||
|
protected array $properties = [];
|
||||||
|
/** @var list<Stmt\ClassMethod> */
|
||||||
|
protected array $methods = [];
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a class builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the class
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends a class.
|
||||||
|
*
|
||||||
|
* @param Name|string $class Name of class to extend
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function extend($class) {
|
||||||
|
$this->extends = BuilderHelpers::normalizeName($class);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements one or more interfaces.
|
||||||
|
*
|
||||||
|
* @param Name|string ...$interfaces Names of interfaces to implement
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function implement(...$interfaces) {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
$this->implements[] = BuilderHelpers::normalizeName($interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the class abstract.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeAbstract() {
|
||||||
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::ABSTRACT);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the class final.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeFinal() {
|
||||||
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the class readonly.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeReadonly() {
|
||||||
|
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::READONLY);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$stmt = BuilderHelpers::normalizeNode($stmt);
|
||||||
|
|
||||||
|
if ($stmt instanceof Stmt\Property) {
|
||||||
|
$this->properties[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
||||||
|
$this->methods[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\TraitUse) {
|
||||||
|
$this->uses[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassConst) {
|
||||||
|
$this->constants[] = $stmt;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built class node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Class_ The built class node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\Class_($this->name, [
|
||||||
|
'flags' => $this->flags,
|
||||||
|
'extends' => $this->extends,
|
||||||
|
'implements' => $this->implements,
|
||||||
|
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
50
vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php
vendored
Normal file
50
vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
|
||||||
|
abstract class Declaration implements PhpParser\Builder {
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
protected array $attributes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Node\Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
abstract public function addStmt($stmt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds multiple statements.
|
||||||
|
*
|
||||||
|
* @param (PhpParser\Node\Stmt|PhpParser\Builder)[] $stmts The statements to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmts(array $stmts) {
|
||||||
|
foreach ($stmts as $stmt) {
|
||||||
|
$this->addStmt($stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doc comment for the declaration.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDocComment($docComment) {
|
||||||
|
$this->attributes['comments'] = [
|
||||||
|
BuilderHelpers::normalizeDocComment($docComment)
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
86
vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php
vendored
Normal file
86
vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class EnumCase implements PhpParser\Builder {
|
||||||
|
/** @var Identifier|string */
|
||||||
|
protected $name;
|
||||||
|
protected ?Node\Expr $value = null;
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
protected array $attributes = [];
|
||||||
|
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum case builder.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
*/
|
||||||
|
public function __construct($name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value.
|
||||||
|
*
|
||||||
|
* @param Node\Expr|string|int $value
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setValue($value) {
|
||||||
|
$this->value = BuilderHelpers::normalizeValue($value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doc comment for the constant.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDocComment($docComment) {
|
||||||
|
$this->attributes = [
|
||||||
|
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built enum case node.
|
||||||
|
*
|
||||||
|
* @return Stmt\EnumCase The built constant node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\EnumCase(
|
||||||
|
$this->name,
|
||||||
|
$this->value,
|
||||||
|
$this->attributeGroups,
|
||||||
|
$this->attributes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
116
vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php
vendored
Normal file
116
vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Enum_ extends Declaration {
|
||||||
|
protected string $name;
|
||||||
|
protected ?Identifier $scalarType = null;
|
||||||
|
/** @var list<Name> */
|
||||||
|
protected array $implements = [];
|
||||||
|
/** @var list<Stmt\TraitUse> */
|
||||||
|
protected array $uses = [];
|
||||||
|
/** @var list<Stmt\EnumCase> */
|
||||||
|
protected array $enumCases = [];
|
||||||
|
/** @var list<Stmt\ClassConst> */
|
||||||
|
protected array $constants = [];
|
||||||
|
/** @var list<Stmt\ClassMethod> */
|
||||||
|
protected array $methods = [];
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the enum
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scalar type.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $scalarType
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setScalarType($scalarType) {
|
||||||
|
$this->scalarType = BuilderHelpers::normalizeType($scalarType);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements one or more interfaces.
|
||||||
|
*
|
||||||
|
* @param Name|string ...$interfaces Names of interfaces to implement
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function implement(...$interfaces) {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
$this->implements[] = BuilderHelpers::normalizeName($interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$stmt = BuilderHelpers::normalizeNode($stmt);
|
||||||
|
|
||||||
|
if ($stmt instanceof Stmt\EnumCase) {
|
||||||
|
$this->enumCases[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
||||||
|
$this->methods[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\TraitUse) {
|
||||||
|
$this->uses[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassConst) {
|
||||||
|
$this->constants[] = $stmt;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built class node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Enum_ The built enum node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\Enum_($this->name, [
|
||||||
|
'scalarType' => $this->scalarType,
|
||||||
|
'implements' => $this->implements,
|
||||||
|
'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods),
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
73
vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php
vendored
Normal file
73
vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
|
||||||
|
abstract class FunctionLike extends Declaration {
|
||||||
|
protected bool $returnByRef = false;
|
||||||
|
/** @var Node\Param[] */
|
||||||
|
protected array $params = [];
|
||||||
|
|
||||||
|
/** @var Node\Identifier|Node\Name|Node\ComplexType|null */
|
||||||
|
protected ?Node $returnType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the function return by reference.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeReturnByRef() {
|
||||||
|
$this->returnByRef = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a parameter.
|
||||||
|
*
|
||||||
|
* @param Node\Param|Param $param The parameter to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addParam($param) {
|
||||||
|
$param = BuilderHelpers::normalizeNode($param);
|
||||||
|
|
||||||
|
if (!$param instanceof Node\Param) {
|
||||||
|
throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->params[] = $param;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds multiple parameters.
|
||||||
|
*
|
||||||
|
* @param (Node\Param|Param)[] $params The parameters to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addParams(array $params) {
|
||||||
|
foreach ($params as $param) {
|
||||||
|
$this->addParam($param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the return type for PHP 7.
|
||||||
|
*
|
||||||
|
* @param string|Node\Name|Node\Identifier|Node\ComplexType $type
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setReturnType($type) {
|
||||||
|
$this->returnType = BuilderHelpers::normalizeType($type);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
67
vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php
vendored
Normal file
67
vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Function_ extends FunctionLike {
|
||||||
|
protected string $name;
|
||||||
|
/** @var list<Stmt> */
|
||||||
|
protected array $stmts = [];
|
||||||
|
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a function builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the function
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built function node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Function_ The built function node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Stmt\Function_($this->name, [
|
||||||
|
'byRef' => $this->returnByRef,
|
||||||
|
'params' => $this->params,
|
||||||
|
'returnType' => $this->returnType,
|
||||||
|
'stmts' => $this->stmts,
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
94
vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php
vendored
Normal file
94
vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Interface_ extends Declaration {
|
||||||
|
protected string $name;
|
||||||
|
/** @var list<Name> */
|
||||||
|
protected array $extends = [];
|
||||||
|
/** @var list<Stmt\ClassConst> */
|
||||||
|
protected array $constants = [];
|
||||||
|
/** @var list<Stmt\ClassMethod> */
|
||||||
|
protected array $methods = [];
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an interface builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the interface
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends one or more interfaces.
|
||||||
|
*
|
||||||
|
* @param Name|string ...$interfaces Names of interfaces to extend
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function extend(...$interfaces) {
|
||||||
|
foreach ($interfaces as $interface) {
|
||||||
|
$this->extends[] = BuilderHelpers::normalizeName($interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$stmt = BuilderHelpers::normalizeNode($stmt);
|
||||||
|
|
||||||
|
if ($stmt instanceof Stmt\ClassConst) {
|
||||||
|
$this->constants[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
||||||
|
// we erase all statements in the body of an interface method
|
||||||
|
$stmt->stmts = null;
|
||||||
|
$this->methods[] = $stmt;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built interface node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Interface_ The built interface node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\Interface_($this->name, [
|
||||||
|
'extends' => $this->extends,
|
||||||
|
'stmts' => array_merge($this->constants, $this->methods),
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
147
vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php
vendored
Normal file
147
vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Method extends FunctionLike {
|
||||||
|
protected string $name;
|
||||||
|
|
||||||
|
protected int $flags = 0;
|
||||||
|
|
||||||
|
/** @var list<Stmt>|null */
|
||||||
|
protected ?array $stmts = [];
|
||||||
|
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a method builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the method
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method static.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeStatic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method abstract.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeAbstract() {
|
||||||
|
if (!empty($this->stmts)) {
|
||||||
|
throw new \LogicException('Cannot make method with statements abstract');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
|
||||||
|
$this->stmts = null; // abstract methods don't have statements
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the method final.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeFinal() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
if (null === $this->stmts) {
|
||||||
|
throw new \LogicException('Cannot add statements to an abstract method');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built method node.
|
||||||
|
*
|
||||||
|
* @return Stmt\ClassMethod The built method node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Stmt\ClassMethod($this->name, [
|
||||||
|
'flags' => $this->flags,
|
||||||
|
'byRef' => $this->returnByRef,
|
||||||
|
'params' => $this->params,
|
||||||
|
'returnType' => $this->returnType,
|
||||||
|
'stmts' => $this->stmts,
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
45
vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php
vendored
Normal file
45
vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Namespace_ extends Declaration {
|
||||||
|
private ?Node\Name $name;
|
||||||
|
/** @var Stmt[] */
|
||||||
|
private array $stmts = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a namespace builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string|null $name Name of the namespace
|
||||||
|
*/
|
||||||
|
public function __construct($name) {
|
||||||
|
$this->name = null !== $name ? BuilderHelpers::normalizeName($name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Node|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Namespace_ The built node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes);
|
||||||
|
}
|
||||||
|
}
|
171
vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php
vendored
Normal file
171
vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php
vendored
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
|
||||||
|
class Param implements PhpParser\Builder {
|
||||||
|
protected string $name;
|
||||||
|
protected ?Node\Expr $default = null;
|
||||||
|
/** @var Node\Identifier|Node\Name|Node\ComplexType|null */
|
||||||
|
protected ?Node $type = null;
|
||||||
|
protected bool $byRef = false;
|
||||||
|
protected int $flags = 0;
|
||||||
|
protected bool $variadic = false;
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a parameter builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the parameter
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets default value for the parameter.
|
||||||
|
*
|
||||||
|
* @param mixed $value Default value to use
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDefault($value) {
|
||||||
|
$this->default = BuilderHelpers::normalizeValue($value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets type for the parameter.
|
||||||
|
*
|
||||||
|
* @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setType($type) {
|
||||||
|
$this->type = BuilderHelpers::normalizeType($type);
|
||||||
|
if ($this->type == 'void') {
|
||||||
|
throw new \LogicException('Parameter type cannot be void');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the parameter accept the value by reference.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeByRef() {
|
||||||
|
$this->byRef = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the parameter variadic
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeVariadic() {
|
||||||
|
$this->variadic = true;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the (promoted) parameter readonly.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeReadonly() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the promoted property private(set) visibility.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivateSet() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the promoted property protected(set) visibility.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtectedSet() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built parameter node.
|
||||||
|
*
|
||||||
|
* @return Node\Param The built parameter node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Node\Param(
|
||||||
|
new Node\Expr\Variable($this->name),
|
||||||
|
$this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
223
vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php
vendored
Normal file
223
vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
use PhpParser\Node\ComplexType;
|
||||||
|
|
||||||
|
class Property implements PhpParser\Builder {
|
||||||
|
protected string $name;
|
||||||
|
|
||||||
|
protected int $flags = 0;
|
||||||
|
|
||||||
|
protected ?Node\Expr $default = null;
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
protected array $attributes = [];
|
||||||
|
/** @var null|Identifier|Name|ComplexType */
|
||||||
|
protected ?Node $type = null;
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
/** @var list<Node\PropertyHook> */
|
||||||
|
protected array $hooks = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a property builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the property
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property static.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeStatic() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property readonly.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeReadonly() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property abstract. Requires at least one property hook to be specified as well.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeAbstract() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the property final.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeFinal() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the property private(set) visibility.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivateSet() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives the property protected(set) visibility.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtectedSet() {
|
||||||
|
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets default value for the property.
|
||||||
|
*
|
||||||
|
* @param mixed $value Default value to use
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDefault($value) {
|
||||||
|
$this->default = BuilderHelpers::normalizeValue($value);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets doc comment for the property.
|
||||||
|
*
|
||||||
|
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function setDocComment($docComment) {
|
||||||
|
$this->attributes = [
|
||||||
|
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the property type for PHP 7.4+.
|
||||||
|
*
|
||||||
|
* @param string|Name|Identifier|ComplexType $type
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setType($type) {
|
||||||
|
$this->type = BuilderHelpers::normalizeType($type);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a property hook.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addHook(Node\PropertyHook $hook) {
|
||||||
|
$this->hooks[] = $hook;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built class node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Property The built property node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) {
|
||||||
|
throw new PhpParser\Error('Only hooked properties may be declared abstract');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Stmt\Property(
|
||||||
|
$this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,
|
||||||
|
[
|
||||||
|
new Node\PropertyItem($this->name, $this->default)
|
||||||
|
],
|
||||||
|
$this->attributes,
|
||||||
|
$this->type,
|
||||||
|
$this->attributeGroups,
|
||||||
|
$this->hooks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
65
vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php
vendored
Normal file
65
vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Builder;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class TraitUse implements Builder {
|
||||||
|
/** @var Node\Name[] */
|
||||||
|
protected array $traits = [];
|
||||||
|
/** @var Stmt\TraitUseAdaptation[] */
|
||||||
|
protected array $adaptations = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a trait use builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string ...$traits Names of used traits
|
||||||
|
*/
|
||||||
|
public function __construct(...$traits) {
|
||||||
|
foreach ($traits as $trait) {
|
||||||
|
$this->and($trait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds used trait.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string $trait Trait name
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function and($trait) {
|
||||||
|
$this->traits[] = BuilderHelpers::normalizeName($trait);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds trait adaptation.
|
||||||
|
*
|
||||||
|
* @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function with($adaptation) {
|
||||||
|
$adaptation = BuilderHelpers::normalizeNode($adaptation);
|
||||||
|
|
||||||
|
if (!$adaptation instanceof Stmt\TraitUseAdaptation) {
|
||||||
|
throw new \LogicException('Adaptation must have type TraitUseAdaptation');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->adaptations[] = $adaptation;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built node.
|
||||||
|
*
|
||||||
|
* @return Node The built node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Stmt\TraitUse($this->traits, $this->adaptations);
|
||||||
|
}
|
||||||
|
}
|
145
vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php
vendored
Normal file
145
vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php
vendored
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Builder;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Modifiers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class TraitUseAdaptation implements Builder {
|
||||||
|
private const TYPE_UNDEFINED = 0;
|
||||||
|
private const TYPE_ALIAS = 1;
|
||||||
|
private const TYPE_PRECEDENCE = 2;
|
||||||
|
|
||||||
|
protected int $type;
|
||||||
|
protected ?Node\Name $trait;
|
||||||
|
protected Node\Identifier $method;
|
||||||
|
protected ?int $modifier = null;
|
||||||
|
protected ?Node\Identifier $alias = null;
|
||||||
|
/** @var Node\Name[] */
|
||||||
|
protected array $insteadof = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a trait use adaptation builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string|null $trait Name of adapted trait
|
||||||
|
* @param Node\Identifier|string $method Name of adapted method
|
||||||
|
*/
|
||||||
|
public function __construct($trait, $method) {
|
||||||
|
$this->type = self::TYPE_UNDEFINED;
|
||||||
|
|
||||||
|
$this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait);
|
||||||
|
$this->method = BuilderHelpers::normalizeIdentifier($method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets alias of method.
|
||||||
|
*
|
||||||
|
* @param Node\Identifier|string $alias Alias for adapted method
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function as($alias) {
|
||||||
|
if ($this->type === self::TYPE_UNDEFINED) {
|
||||||
|
$this->type = self::TYPE_ALIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->type !== self::TYPE_ALIAS) {
|
||||||
|
throw new \LogicException('Cannot set alias for not alias adaptation buider');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->alias = BuilderHelpers::normalizeIdentifier($alias);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets adapted method public.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePublic() {
|
||||||
|
$this->setModifier(Modifiers::PUBLIC);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets adapted method protected.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makeProtected() {
|
||||||
|
$this->setModifier(Modifiers::PROTECTED);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets adapted method private.
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function makePrivate() {
|
||||||
|
$this->setModifier(Modifiers::PRIVATE);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds overwritten traits.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string ...$traits Traits for overwrite
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function insteadof(...$traits) {
|
||||||
|
if ($this->type === self::TYPE_UNDEFINED) {
|
||||||
|
if (is_null($this->trait)) {
|
||||||
|
throw new \LogicException('Precedence adaptation must have trait');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->type = self::TYPE_PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->type !== self::TYPE_PRECEDENCE) {
|
||||||
|
throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($traits as $trait) {
|
||||||
|
$this->insteadof[] = BuilderHelpers::normalizeName($trait);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setModifier(int $modifier): void {
|
||||||
|
if ($this->type === self::TYPE_UNDEFINED) {
|
||||||
|
$this->type = self::TYPE_ALIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->type !== self::TYPE_ALIAS) {
|
||||||
|
throw new \LogicException('Cannot set access modifier for not alias adaptation buider');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($this->modifier)) {
|
||||||
|
$this->modifier = $modifier;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException('Multiple access type modifiers are not allowed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built node.
|
||||||
|
*
|
||||||
|
* @return Node The built node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
switch ($this->type) {
|
||||||
|
case self::TYPE_ALIAS:
|
||||||
|
return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias);
|
||||||
|
case self::TYPE_PRECEDENCE:
|
||||||
|
return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof);
|
||||||
|
default:
|
||||||
|
throw new \LogicException('Type of adaptation is not defined');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php
vendored
Normal file
83
vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Trait_ extends Declaration {
|
||||||
|
protected string $name;
|
||||||
|
/** @var list<Stmt\TraitUse> */
|
||||||
|
protected array $uses = [];
|
||||||
|
/** @var list<Stmt\ClassConst> */
|
||||||
|
protected array $constants = [];
|
||||||
|
/** @var list<Stmt\Property> */
|
||||||
|
protected array $properties = [];
|
||||||
|
/** @var list<Stmt\ClassMethod> */
|
||||||
|
protected array $methods = [];
|
||||||
|
/** @var list<Node\AttributeGroup> */
|
||||||
|
protected array $attributeGroups = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an interface builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the interface
|
||||||
|
*/
|
||||||
|
public function __construct(string $name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a statement.
|
||||||
|
*
|
||||||
|
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addStmt($stmt) {
|
||||||
|
$stmt = BuilderHelpers::normalizeNode($stmt);
|
||||||
|
|
||||||
|
if ($stmt instanceof Stmt\Property) {
|
||||||
|
$this->properties[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
||||||
|
$this->methods[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\TraitUse) {
|
||||||
|
$this->uses[] = $stmt;
|
||||||
|
} elseif ($stmt instanceof Stmt\ClassConst) {
|
||||||
|
$this->constants[] = $stmt;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an attribute group.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function addAttribute($attribute) {
|
||||||
|
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built trait node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Trait_ The built interface node
|
||||||
|
*/
|
||||||
|
public function getNode(): PhpParser\Node {
|
||||||
|
return new Stmt\Trait_(
|
||||||
|
$this->name, [
|
||||||
|
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
|
||||||
|
'attrGroups' => $this->attributeGroups,
|
||||||
|
], $this->attributes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
49
vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php
vendored
Normal file
49
vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser\Builder;
|
||||||
|
|
||||||
|
use PhpParser\Builder;
|
||||||
|
use PhpParser\BuilderHelpers;
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
class Use_ implements Builder {
|
||||||
|
protected Node\Name $name;
|
||||||
|
/** @var Stmt\Use_::TYPE_* */
|
||||||
|
protected int $type;
|
||||||
|
protected ?string $alias = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a name use (alias) builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string $name Name of the entity (namespace, class, function, constant) to alias
|
||||||
|
* @param Stmt\Use_::TYPE_* $type One of the Stmt\Use_::TYPE_* constants
|
||||||
|
*/
|
||||||
|
public function __construct($name, int $type) {
|
||||||
|
$this->name = BuilderHelpers::normalizeName($name);
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets alias for used name.
|
||||||
|
*
|
||||||
|
* @param string $alias Alias to use (last component of full name by default)
|
||||||
|
*
|
||||||
|
* @return $this The builder instance (for fluid interface)
|
||||||
|
*/
|
||||||
|
public function as(string $alias) {
|
||||||
|
$this->alias = $alias;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built node.
|
||||||
|
*
|
||||||
|
* @return Stmt\Use_ The built node
|
||||||
|
*/
|
||||||
|
public function getNode(): Node {
|
||||||
|
return new Stmt\Use_([
|
||||||
|
new Node\UseItem($this->name, $this->alias)
|
||||||
|
], $this->type);
|
||||||
|
}
|
||||||
|
}
|
375
vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php
vendored
Normal file
375
vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php
vendored
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser;
|
||||||
|
|
||||||
|
use PhpParser\Node\Arg;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Scalar\String_;
|
||||||
|
use PhpParser\Node\Stmt\Use_;
|
||||||
|
|
||||||
|
class BuilderFactory {
|
||||||
|
/**
|
||||||
|
* Creates an attribute node.
|
||||||
|
*
|
||||||
|
* @param string|Name $name Name of the attribute
|
||||||
|
* @param array $args Attribute named arguments
|
||||||
|
*/
|
||||||
|
public function attribute($name, array $args = []): Node\Attribute {
|
||||||
|
return new Node\Attribute(
|
||||||
|
BuilderHelpers::normalizeName($name),
|
||||||
|
$this->args($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a namespace builder.
|
||||||
|
*
|
||||||
|
* @param null|string|Node\Name $name Name of the namespace
|
||||||
|
*
|
||||||
|
* @return Builder\Namespace_ The created namespace builder
|
||||||
|
*/
|
||||||
|
public function namespace($name): Builder\Namespace_ {
|
||||||
|
return new Builder\Namespace_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a class builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the class
|
||||||
|
*
|
||||||
|
* @return Builder\Class_ The created class builder
|
||||||
|
*/
|
||||||
|
public function class(string $name): Builder\Class_ {
|
||||||
|
return new Builder\Class_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an interface builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the interface
|
||||||
|
*
|
||||||
|
* @return Builder\Interface_ The created interface builder
|
||||||
|
*/
|
||||||
|
public function interface(string $name): Builder\Interface_ {
|
||||||
|
return new Builder\Interface_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a trait builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the trait
|
||||||
|
*
|
||||||
|
* @return Builder\Trait_ The created trait builder
|
||||||
|
*/
|
||||||
|
public function trait(string $name): Builder\Trait_ {
|
||||||
|
return new Builder\Trait_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the enum
|
||||||
|
*
|
||||||
|
* @return Builder\Enum_ The created enum builder
|
||||||
|
*/
|
||||||
|
public function enum(string $name): Builder\Enum_ {
|
||||||
|
return new Builder\Enum_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a trait use builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string ...$traits Trait names
|
||||||
|
*
|
||||||
|
* @return Builder\TraitUse The created trait use builder
|
||||||
|
*/
|
||||||
|
public function useTrait(...$traits): Builder\TraitUse {
|
||||||
|
return new Builder\TraitUse(...$traits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a trait use adaptation builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string|null $trait Trait name
|
||||||
|
* @param Node\Identifier|string $method Method name
|
||||||
|
*
|
||||||
|
* @return Builder\TraitUseAdaptation The created trait use adaptation builder
|
||||||
|
*/
|
||||||
|
public function traitUseAdaptation($trait, $method = null): Builder\TraitUseAdaptation {
|
||||||
|
if ($method === null) {
|
||||||
|
$method = $trait;
|
||||||
|
$trait = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Builder\TraitUseAdaptation($trait, $method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a method builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the method
|
||||||
|
*
|
||||||
|
* @return Builder\Method The created method builder
|
||||||
|
*/
|
||||||
|
public function method(string $name): Builder\Method {
|
||||||
|
return new Builder\Method($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a parameter builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the parameter
|
||||||
|
*
|
||||||
|
* @return Builder\Param The created parameter builder
|
||||||
|
*/
|
||||||
|
public function param(string $name): Builder\Param {
|
||||||
|
return new Builder\Param($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a property builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the property
|
||||||
|
*
|
||||||
|
* @return Builder\Property The created property builder
|
||||||
|
*/
|
||||||
|
public function property(string $name): Builder\Property {
|
||||||
|
return new Builder\Property($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a function builder.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the function
|
||||||
|
*
|
||||||
|
* @return Builder\Function_ The created function builder
|
||||||
|
*/
|
||||||
|
public function function(string $name): Builder\Function_ {
|
||||||
|
return new Builder\Function_($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a namespace/class use builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string $name Name of the entity (namespace or class) to alias
|
||||||
|
*
|
||||||
|
* @return Builder\Use_ The created use builder
|
||||||
|
*/
|
||||||
|
public function use($name): Builder\Use_ {
|
||||||
|
return new Builder\Use_($name, Use_::TYPE_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a function use builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string $name Name of the function to alias
|
||||||
|
*
|
||||||
|
* @return Builder\Use_ The created use function builder
|
||||||
|
*/
|
||||||
|
public function useFunction($name): Builder\Use_ {
|
||||||
|
return new Builder\Use_($name, Use_::TYPE_FUNCTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a constant use builder.
|
||||||
|
*
|
||||||
|
* @param Node\Name|string $name Name of the const to alias
|
||||||
|
*
|
||||||
|
* @return Builder\Use_ The created use const builder
|
||||||
|
*/
|
||||||
|
public function useConst($name): Builder\Use_ {
|
||||||
|
return new Builder\Use_($name, Use_::TYPE_CONSTANT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a class constant builder.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
||||||
|
*
|
||||||
|
* @return Builder\ClassConst The created use const builder
|
||||||
|
*/
|
||||||
|
public function classConst($name, $value): Builder\ClassConst {
|
||||||
|
return new Builder\ClassConst($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an enum case builder.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name Name
|
||||||
|
*
|
||||||
|
* @return Builder\EnumCase The created use const builder
|
||||||
|
*/
|
||||||
|
public function enumCase($name): Builder\EnumCase {
|
||||||
|
return new Builder\EnumCase($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates node a for a literal value.
|
||||||
|
*
|
||||||
|
* @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value
|
||||||
|
*/
|
||||||
|
public function val($value): Expr {
|
||||||
|
return BuilderHelpers::normalizeValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates variable node.
|
||||||
|
*
|
||||||
|
* @param string|Expr $name Name
|
||||||
|
*/
|
||||||
|
public function var($name): Expr\Variable {
|
||||||
|
if (!\is_string($name) && !$name instanceof Expr) {
|
||||||
|
throw new \LogicException('Variable name must be string or Expr');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Expr\Variable($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes an argument list.
|
||||||
|
*
|
||||||
|
* Creates Arg nodes for all arguments and converts literal values to expressions.
|
||||||
|
*
|
||||||
|
* @param array $args List of arguments to normalize
|
||||||
|
*
|
||||||
|
* @return list<Arg>
|
||||||
|
*/
|
||||||
|
public function args(array $args): array {
|
||||||
|
$normalizedArgs = [];
|
||||||
|
foreach ($args as $key => $arg) {
|
||||||
|
if (!($arg instanceof Arg)) {
|
||||||
|
$arg = new Arg(BuilderHelpers::normalizeValue($arg));
|
||||||
|
}
|
||||||
|
if (\is_string($key)) {
|
||||||
|
$arg->name = BuilderHelpers::normalizeIdentifier($key);
|
||||||
|
}
|
||||||
|
$normalizedArgs[] = $arg;
|
||||||
|
}
|
||||||
|
return $normalizedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a function call node.
|
||||||
|
*
|
||||||
|
* @param string|Name|Expr $name Function name
|
||||||
|
* @param array $args Function arguments
|
||||||
|
*/
|
||||||
|
public function funcCall($name, array $args = []): Expr\FuncCall {
|
||||||
|
return new Expr\FuncCall(
|
||||||
|
BuilderHelpers::normalizeNameOrExpr($name),
|
||||||
|
$this->args($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a method call node.
|
||||||
|
*
|
||||||
|
* @param Expr $var Variable the method is called on
|
||||||
|
* @param string|Identifier|Expr $name Method name
|
||||||
|
* @param array $args Method arguments
|
||||||
|
*/
|
||||||
|
public function methodCall(Expr $var, $name, array $args = []): Expr\MethodCall {
|
||||||
|
return new Expr\MethodCall(
|
||||||
|
$var,
|
||||||
|
BuilderHelpers::normalizeIdentifierOrExpr($name),
|
||||||
|
$this->args($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a static method call node.
|
||||||
|
*
|
||||||
|
* @param string|Name|Expr $class Class name
|
||||||
|
* @param string|Identifier|Expr $name Method name
|
||||||
|
* @param array $args Method arguments
|
||||||
|
*/
|
||||||
|
public function staticCall($class, $name, array $args = []): Expr\StaticCall {
|
||||||
|
return new Expr\StaticCall(
|
||||||
|
BuilderHelpers::normalizeNameOrExpr($class),
|
||||||
|
BuilderHelpers::normalizeIdentifierOrExpr($name),
|
||||||
|
$this->args($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an object creation node.
|
||||||
|
*
|
||||||
|
* @param string|Name|Expr $class Class name
|
||||||
|
* @param array $args Constructor arguments
|
||||||
|
*/
|
||||||
|
public function new($class, array $args = []): Expr\New_ {
|
||||||
|
return new Expr\New_(
|
||||||
|
BuilderHelpers::normalizeNameOrExpr($class),
|
||||||
|
$this->args($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a constant fetch node.
|
||||||
|
*
|
||||||
|
* @param string|Name $name Constant name
|
||||||
|
*/
|
||||||
|
public function constFetch($name): Expr\ConstFetch {
|
||||||
|
return new Expr\ConstFetch(BuilderHelpers::normalizeName($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a property fetch node.
|
||||||
|
*
|
||||||
|
* @param Expr $var Variable holding object
|
||||||
|
* @param string|Identifier|Expr $name Property name
|
||||||
|
*/
|
||||||
|
public function propertyFetch(Expr $var, $name): Expr\PropertyFetch {
|
||||||
|
return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a class constant fetch node.
|
||||||
|
*
|
||||||
|
* @param string|Name|Expr $class Class name
|
||||||
|
* @param string|Identifier|Expr $name Constant name
|
||||||
|
*/
|
||||||
|
public function classConstFetch($class, $name): Expr\ClassConstFetch {
|
||||||
|
return new Expr\ClassConstFetch(
|
||||||
|
BuilderHelpers::normalizeNameOrExpr($class),
|
||||||
|
BuilderHelpers::normalizeIdentifierOrExpr($name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates nested Concat nodes from a list of expressions.
|
||||||
|
*
|
||||||
|
* @param Expr|string ...$exprs Expressions or literal strings
|
||||||
|
*/
|
||||||
|
public function concat(...$exprs): Concat {
|
||||||
|
$numExprs = count($exprs);
|
||||||
|
if ($numExprs < 2) {
|
||||||
|
throw new \LogicException('Expected at least two expressions');
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastConcat = $this->normalizeStringExpr($exprs[0]);
|
||||||
|
for ($i = 1; $i < $numExprs; $i++) {
|
||||||
|
$lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i]));
|
||||||
|
}
|
||||||
|
return $lastConcat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|Expr $expr
|
||||||
|
*/
|
||||||
|
private function normalizeStringExpr($expr): Expr {
|
||||||
|
if ($expr instanceof Expr) {
|
||||||
|
return $expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_string($expr)) {
|
||||||
|
return new String_($expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Expected string or Expr');
|
||||||
|
}
|
||||||
|
}
|
338
vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php
vendored
Normal file
338
vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php
vendored
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace PhpParser;
|
||||||
|
|
||||||
|
use PhpParser\Node\ComplexType;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Name\FullyQualified;
|
||||||
|
use PhpParser\Node\NullableType;
|
||||||
|
use PhpParser\Node\Scalar;
|
||||||
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class defines helpers used in the implementation of builders. Don't use it directly.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class BuilderHelpers {
|
||||||
|
/**
|
||||||
|
* Normalizes a node: Converts builder objects to nodes.
|
||||||
|
*
|
||||||
|
* @param Node|Builder $node The node to normalize
|
||||||
|
*
|
||||||
|
* @return Node The normalized node
|
||||||
|
*/
|
||||||
|
public static function normalizeNode($node): Node {
|
||||||
|
if ($node instanceof Builder) {
|
||||||
|
return $node->getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof Node) {
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Expected node or builder object');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a node to a statement.
|
||||||
|
*
|
||||||
|
* Expressions are wrapped in a Stmt\Expression node.
|
||||||
|
*
|
||||||
|
* @param Node|Builder $node The node to normalize
|
||||||
|
*
|
||||||
|
* @return Stmt The normalized statement node
|
||||||
|
*/
|
||||||
|
public static function normalizeStmt($node): Stmt {
|
||||||
|
$node = self::normalizeNode($node);
|
||||||
|
if ($node instanceof Stmt) {
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof Expr) {
|
||||||
|
return new Stmt\Expression($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Expected statement or expression node');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes strings to Identifier.
|
||||||
|
*
|
||||||
|
* @param string|Identifier $name The identifier to normalize
|
||||||
|
*
|
||||||
|
* @return Identifier The normalized identifier
|
||||||
|
*/
|
||||||
|
public static function normalizeIdentifier($name): Identifier {
|
||||||
|
if ($name instanceof Identifier) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_string($name)) {
|
||||||
|
return new Identifier($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Expected string or instance of Node\Identifier');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes strings to Identifier, also allowing expressions.
|
||||||
|
*
|
||||||
|
* @param string|Identifier|Expr $name The identifier to normalize
|
||||||
|
*
|
||||||
|
* @return Identifier|Expr The normalized identifier or expression
|
||||||
|
*/
|
||||||
|
public static function normalizeIdentifierOrExpr($name) {
|
||||||
|
if ($name instanceof Identifier || $name instanceof Expr) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_string($name)) {
|
||||||
|
return new Identifier($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Expected string or instance of Node\Identifier or Node\Expr');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a name: Converts string names to Name nodes.
|
||||||
|
*
|
||||||
|
* @param Name|string $name The name to normalize
|
||||||
|
*
|
||||||
|
* @return Name The normalized name
|
||||||
|
*/
|
||||||
|
public static function normalizeName($name): Name {
|
||||||
|
if ($name instanceof Name) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($name)) {
|
||||||
|
if (!$name) {
|
||||||
|
throw new \LogicException('Name cannot be empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($name[0] === '\\') {
|
||||||
|
return new Name\FullyQualified(substr($name, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === strpos($name, 'namespace\\')) {
|
||||||
|
return new Name\Relative(substr($name, strlen('namespace\\')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Name($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Name must be a string or an instance of Node\Name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a name: Converts string names to Name nodes, while also allowing expressions.
|
||||||
|
*
|
||||||
|
* @param Expr|Name|string $name The name to normalize
|
||||||
|
*
|
||||||
|
* @return Name|Expr The normalized name or expression
|
||||||
|
*/
|
||||||
|
public static function normalizeNameOrExpr($name) {
|
||||||
|
if ($name instanceof Expr) {
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($name) && !($name instanceof Name)) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Name must be a string or an instance of Node\Name or Node\Expr'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::normalizeName($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a type: Converts plain-text type names into proper AST representation.
|
||||||
|
*
|
||||||
|
* In particular, builtin types become Identifiers, custom types become Names and nullables
|
||||||
|
* are wrapped in NullableType nodes.
|
||||||
|
*
|
||||||
|
* @param string|Name|Identifier|ComplexType $type The type to normalize
|
||||||
|
*
|
||||||
|
* @return Name|Identifier|ComplexType The normalized type
|
||||||
|
*/
|
||||||
|
public static function normalizeType($type) {
|
||||||
|
if (!is_string($type)) {
|
||||||
|
if (
|
||||||
|
!$type instanceof Name && !$type instanceof Identifier &&
|
||||||
|
!$type instanceof ComplexType
|
||||||
|
) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Type must be a string, or an instance of Name, Identifier or ComplexType'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nullable = false;
|
||||||
|
if (strlen($type) > 0 && $type[0] === '?') {
|
||||||
|
$nullable = true;
|
||||||
|
$type = substr($type, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$builtinTypes = [
|
||||||
|
'array',
|
||||||
|
'callable',
|
||||||
|
'bool',
|
||||||
|
'int',
|
||||||
|
'float',
|
||||||
|
'string',
|
||||||
|
'iterable',
|
||||||
|
'void',
|
||||||
|
'object',
|
||||||
|
'null',
|
||||||
|
'false',
|
||||||
|
'mixed',
|
||||||
|
'never',
|
||||||
|
'true',
|
||||||
|
];
|
||||||
|
|
||||||
|
$lowerType = strtolower($type);
|
||||||
|
if (in_array($lowerType, $builtinTypes)) {
|
||||||
|
$type = new Identifier($lowerType);
|
||||||
|
} else {
|
||||||
|
$type = self::normalizeName($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$notNullableTypes = [
|
||||||
|
'void', 'mixed', 'never',
|
||||||
|
];
|
||||||
|
if ($nullable && in_array((string) $type, $notNullableTypes)) {
|
||||||
|
throw new \LogicException(sprintf('%s type cannot be nullable', $type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nullable ? new NullableType($type) : $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a value: Converts nulls, booleans, integers,
|
||||||
|
* floats, strings and arrays into their respective nodes
|
||||||
|
*
|
||||||
|
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize
|
||||||
|
*
|
||||||
|
* @return Expr The normalized value
|
||||||
|
*/
|
||||||
|
public static function normalizeValue($value): Expr {
|
||||||
|
if ($value instanceof Node\Expr) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($value)) {
|
||||||
|
return new Expr\ConstFetch(
|
||||||
|
new Name('null')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_bool($value)) {
|
||||||
|
return new Expr\ConstFetch(
|
||||||
|
new Name($value ? 'true' : 'false')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_int($value)) {
|
||||||
|
return new Scalar\Int_($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_float($value)) {
|
||||||
|
return new Scalar\Float_($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value)) {
|
||||||
|
return new Scalar\String_($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
$items = [];
|
||||||
|
$lastKey = -1;
|
||||||
|
foreach ($value as $itemKey => $itemValue) {
|
||||||
|
// for consecutive, numeric keys don't generate keys
|
||||||
|
if (null !== $lastKey && ++$lastKey === $itemKey) {
|
||||||
|
$items[] = new Node\ArrayItem(
|
||||||
|
self::normalizeValue($itemValue)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$lastKey = null;
|
||||||
|
$items[] = new Node\ArrayItem(
|
||||||
|
self::normalizeValue($itemValue),
|
||||||
|
self::normalizeValue($itemKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Expr\Array_($items);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof \UnitEnum) {
|
||||||
|
return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Invalid value');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
|
||||||
|
*
|
||||||
|
* @param Comment\Doc|string $docComment The doc comment to normalize
|
||||||
|
*
|
||||||
|
* @return Comment\Doc The normalized doc comment
|
||||||
|
*/
|
||||||
|
public static function normalizeDocComment($docComment): Comment\Doc {
|
||||||
|
if ($docComment instanceof Comment\Doc) {
|
||||||
|
return $docComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($docComment)) {
|
||||||
|
return new Comment\Doc($docComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a attribute: Converts attribute to the Attribute Group if needed.
|
||||||
|
*
|
||||||
|
* @param Node\Attribute|Node\AttributeGroup $attribute
|
||||||
|
*
|
||||||
|
* @return Node\AttributeGroup The Attribute Group
|
||||||
|
*/
|
||||||
|
public static function normalizeAttribute($attribute): Node\AttributeGroup {
|
||||||
|
if ($attribute instanceof Node\AttributeGroup) {
|
||||||
|
return $attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($attribute instanceof Node\Attribute)) {
|
||||||
|
throw new \LogicException('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Node\AttributeGroup([$attribute]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a modifier and returns new modifier bitmask.
|
||||||
|
*
|
||||||
|
* @param int $modifiers Existing modifiers
|
||||||
|
* @param int $modifier Modifier to set
|
||||||
|
*
|
||||||
|
* @return int New modifiers
|
||||||
|
*/
|
||||||
|
public static function addModifier(int $modifiers, int $modifier): int {
|
||||||
|
Modifiers::verifyModifier($modifiers, $modifier);
|
||||||
|
return $modifiers | $modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a modifier and returns new modifier bitmask.
|
||||||
|
* @return int New modifiers
|
||||||
|
*/
|
||||||
|
public static function addClassModifier(int $existingModifiers, int $modifierToSet): int {
|
||||||
|
Modifiers::verifyClassModifier($existingModifiers, $modifierToSet);
|
||||||
|
return $existingModifiers | $modifierToSet;
|
||||||
|
}
|
||||||
|
}
|
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