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