From 6cce3165b5af0920a5acbe8e3bd0db9898deb31c Mon Sep 17 00:00:00 2001 From: nilsteampassnet Date: Fri, 27 Sep 2024 13:15:29 +0200 Subject: [PATCH 1/4] 3.1.2 Fixing vulnerability regarding API authorize process --- api/Model/AuthModel.php | 47 +++------------------------------- includes/config/include.php | 2 +- includes/tables_integrity.json | 4 +-- 3 files changed, 6 insertions(+), 47 deletions(-) diff --git a/api/Model/AuthModel.php b/api/Model/AuthModel.php index bcf45dc4d..49afb61a3 100755 --- a/api/Model/AuthModel.php +++ b/api/Model/AuthModel.php @@ -68,53 +68,12 @@ public function getUserAuth(string $login, string $password, string $apikey): ar if (empty($inputData['login']) === true || empty($inputData['apikey']) === true) { return ["error" => "Login failed.", "info" => "Empty entry"]; } - + // Check apikey if (empty($inputData['password']) === true) { // case where it is a generic key - $apiInfo = $this->select("SELECT * FROM " . prefixTable('api') . " WHERE value='".$inputData['apikey']."' AND label='".$inputData['login']."'"); - $apiInfo = $apiInfo[0]; - if (WIP === true) { - if (isset($apiInfo['increment_id']) === false) { - return ["error" => "Login failed.", "info" => "apikey : Not valid"]; - } - - // Check if user is enabled - if ((int) $apiInfo['enabled'] === 0) { - return ["error" => "Login failed.", "info" => "User not allowed to use API"]; - } - - // Load config - $configManager = new ConfigManager(); - $SETTINGS = $configManager->getAllSettings(); - - // Log user - logEvents($SETTINGS, 'api', 'user_connection', (string) $apiInfo['increment_id'], stripslashes($inputData['login'])); - - // create JWT - return $this->createUserJWT( - $apiInfo['increment_id'], - $inputData['login'], - 0, - '', - '', - '', - '', - '', - 0, - 0, - 1, - 0, - '', - $apiInfo['allowed_folders'], - $apiInfo['allowed_to_create'], - $apiInfo['allowed_to_read'], - $apiInfo['allowed_to_update'], - $apiInfo['allowed_to_delete'], - ); - } else { - return ["error" => "Login failed.", "info" => "Not managed."]; - } + // Not allowed to use this API + return ["error" => "Login failed.", "info" => "User password is requested"]; } else { // case where it is a user api key // Check if user exists diff --git a/includes/config/include.php b/includes/config/include.php index 81a55d7ac..877e617c9 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1727110744"); -define('TP_VERSION_MINOR', '120'); +define('TP_VERSION_MINOR', '121'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/tables_integrity.json b/includes/tables_integrity.json index 699096a89..c353b6202 100644 --- a/includes/tables_integrity.json +++ b/includes/tables_integrity.json @@ -17,7 +17,7 @@ }, { "table_name": "background_tasks_logs", - "structure_hash": "7604d29e5fb4a5f2c1d7f04b49b693ff6081c600faac604e27a5612cd64c85c9" + "structure_hash": "054357d89683470ebe98982957804f230f6c54afffc7dfb5c4b07d149112b14a" }, { "table_name": "cache", @@ -101,7 +101,7 @@ }, { "table_name": "log_system", - "structure_hash": "329cda48e82f22915c742510656d849e75ce756ac62b414d1371ffb61a161d1b" + "structure_hash": "19dacf60bcbbe2d6718582ab586683c7fad6fa81e3dadca965d80fde13a2ff00" }, { "table_name": "misc", From e52720dce61f060ee1b87695c22d3194472366cb Mon Sep 17 00:00:00 2001 From: nilsteampassnet Date: Fri, 27 Sep 2024 16:31:26 +0200 Subject: [PATCH 2/4] 3.1.2 Grouping 2 conditions into 1 unique as suggested --- api/Model/AuthModel.php | 7 ++----- includes/config/include.php | 2 +- includes/tables_integrity.json | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/api/Model/AuthModel.php b/api/Model/AuthModel.php index 49afb61a3..d5e1df3fd 100755 --- a/api/Model/AuthModel.php +++ b/api/Model/AuthModel.php @@ -65,12 +65,9 @@ public function getUserAuth(string $login, string $password, string $apikey): ar 'apikey' => 'trim|escape|strip_tags', ] ); - if (empty($inputData['login']) === true || empty($inputData['apikey']) === true) { - return ["error" => "Login failed.", "info" => "Empty entry"]; - } - // Check apikey - if (empty($inputData['password']) === true) { + // Check apikey and credentials + if (empty($inputData['login']) === true || empty($inputData['apikey']) === true || empty($inputData['password']) === true) { // case where it is a generic key // Not allowed to use this API return ["error" => "Login failed.", "info" => "User password is requested"]; diff --git a/includes/config/include.php b/includes/config/include.php index 877e617c9..97e864f0a 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1727110744"); -define('TP_VERSION_MINOR', '121'); +define('TP_VERSION_MINOR', '122'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/tables_integrity.json b/includes/tables_integrity.json index c353b6202..3c0b5230e 100644 --- a/includes/tables_integrity.json +++ b/includes/tables_integrity.json @@ -17,7 +17,7 @@ }, { "table_name": "background_tasks_logs", - "structure_hash": "054357d89683470ebe98982957804f230f6c54afffc7dfb5c4b07d149112b14a" + "structure_hash": "cdaab9275f583dc301dd1dfdbeca2354f9171990d5cef6569cae8361d084f1f7" }, { "table_name": "cache", From 40f8fcadee9ea13256cc469b37f66f2e3dd1787c Mon Sep 17 00:00:00 2001 From: nilsteampassnet Date: Sat, 28 Sep 2024 07:35:32 +0200 Subject: [PATCH 3/4] 3.1.2 Remplaced existing API database class by MeekroDB library as in Teampass core --- api/Model/AuthModel.php | 74 +++++++++++++++----------- api/Model/Database.php | 94 ---------------------------------- api/Model/FolderModel.php | 40 +++++---------- api/Model/ItemModel.php | 26 +++++----- api/Model/UserModel.php | 10 ++-- includes/config/include.php | 2 +- includes/core/otv.php | 4 +- includes/tables_integrity.json | 6 +-- 8 files changed, 85 insertions(+), 171 deletions(-) delete mode 100755 api/Model/Database.php diff --git a/api/Model/AuthModel.php b/api/Model/AuthModel.php index d5e1df3fd..eb799b749 100755 --- a/api/Model/AuthModel.php +++ b/api/Model/AuthModel.php @@ -34,10 +34,7 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; -require_once API_ROOT_PATH . "/Model/Database.php"; - - -class AuthModel extends Database +class AuthModel { @@ -70,20 +67,21 @@ public function getUserAuth(string $login, string $password, string $apikey): ar if (empty($inputData['login']) === true || empty($inputData['apikey']) === true || empty($inputData['password']) === true) { // case where it is a generic key // Not allowed to use this API + return ["error" => "Login failed.", "info" => "User password is requested"]; } else { // case where it is a user api key // Check if user exists - $userInfoRes = $this->select( + $userInfo = DB::queryfirstrow( "SELECT u.id, u.pw, u.login, u.admin, u.gestionnaire, u.can_manage_all_users, u.fonction_id, u.can_create_root_folder, u.public_key, u.private_key, u.personal_folder, u.fonction_id, u.groupes_visibles, u.groupes_interdits, a.value AS user_api_key, a.allowed_folders as user_api_allowed_folders, a.enabled, a.allowed_to_create, a.allowed_to_read, a.allowed_to_update, a.allowed_to_delete FROM " . prefixTable('users') . " AS u INNER JOIN " . prefixTable('api') . " AS a ON (a.user_id=u.id) - WHERE login='".$inputData['login']."'"); - if (count($userInfoRes) === 0) { + WHERE login = %s", + $inputData['login'] + ); + if (DB::count() === 0) { return ["error" => "Login failed.", "info" => "apikey : Not valid"]; } - $userInfoRes[0]['special'] = ''; - $userInfo = $userInfoRes[0]; // Check if user is enabled if ((int) $userInfo['enabled'] === 0) { @@ -104,10 +102,13 @@ public function getUserAuth(string $login, string $password, string $apikey): ar // Update user's key_tempo $keyTempo = bin2hex(random_bytes(16)); - $this->update( - "UPDATE " . prefixTable('users') . " - SET key_tempo='".$keyTempo."' - WHERE id=".$userInfo['id'] + DB::update( + prefixTable('users'), + [ + 'key_tempo' => $keyTempo, + ], + 'id = %i', + $userInfo['id'] ); // get user folders list @@ -244,11 +245,16 @@ private function buildUserFoldersList(array $userInfo): array $restrictedItems = []; $personalFolders = []; - $userFunctionId = str_replace(";", ",", $userInfo['fonction_id']); + $userFunctionId = explode(";", $userInfo['fonction_id']); // Get folders from the roles - if (empty($userFunctionId) === false) { - $rows = $this->select("SELECT * FROM " . prefixTable('roles_values') . " WHERE role_id IN (".$userFunctionId.") AND type IN ('W', 'ND', 'NE', 'NDNE', 'R')"); + if (count($userFunctionId) > 0) { + $rows = DB::query( + 'SELECT * + FROM ' . prefixTable('roles_values') . ' + WHERE role_id IN %li AND type IN ("W", "ND", "NE", "NDNE", "R")', + $userFunctionId + ); foreach ($rows as $record) { if ($record['type'] === 'R') { array_push($readOnlyFolders, $record['folder_id']); @@ -266,11 +272,17 @@ private function buildUserFoldersList(array $userInfo): array } } } - + //error_log(print_r($userFunctionId, true)); // Does this user is allowed to see other items $inc = 0; - $rows = $this->select("SELECT id, id_tree FROM " . prefixTable('items') . " WHERE restricted_to LIKE '".$userInfo['id']."'". - (empty($userFunctionId) === false ? ' AND id_tree NOT IN ('.$userFunctionId.')' : '')); + $rows = DB::query( + 'SELECT id, id_tree + FROM ' . prefixTable('items') . ' + WHERE restricted_to LIKE %s'. + (count($userFunctionId) > 0 ? ' AND id_tree NOT IN %li' : ''), + $userInfo['id'], + count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0') + ); foreach ($rows as $record) { // Exclude restriction on item if folder is fully accessible $restrictedFoldersForItems[$inc] = $record['id_tree']; @@ -278,11 +290,14 @@ private function buildUserFoldersList(array $userInfo): array } // Check for the users roles if some specific rights exist on items - $rows = $this->select("SELECT i.id_tree, r.item_id - FROM " . prefixTable('items') . " as i - INNER JOIN " . prefixTable('restriction_to_roles') . " as r ON (r.item_id=i.id) - WHERE ".(empty($userFunctionId) === false ? ' id_tree NOT IN ('.$userFunctionId.') AND ' : '')." i.id_tree != '' - ORDER BY i.id_tree ASC"); + $rows = DB::query( + 'SELECT i.id_tree, r.item_id + FROM ' . prefixTable('items') . ' AS i + INNER JOIN ' . prefixTable('restriction_to_roles') . ' AS r ON (r.item_id=i.id) + WHERE '.(count($userFunctionId) > 0 ? ' id_tree NOT IN %li AND ' : '').' i.id_tree != "" + ORDER BY i.id_tree ASC', + count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0') + ); foreach ($rows as $record) { $foldersLimited[$record['id_tree']][$inc] = $record['item_id']; //array_push($foldersLimitedFull, $record['item_id']); @@ -292,12 +307,13 @@ private function buildUserFoldersList(array $userInfo): array } // Add all personal folders - $rows = $this->select( - 'SELECT id + $rows = DB::queryFirstRow( + 'SELECT id FROM ' . prefixTable('nested_tree') . ' - WHERE title = '.$userInfo['id'].' AND personal_folder = 1'. - (empty($userFunctionId) === false ? ' AND id NOT IN ('.$userFunctionId.')' : ''). - ' LIMIT 0,1' + WHERE title = %i AND personal_folder = 1'. + (count($userFunctionId) > 0 ? ' AND id NOT IN %li' : ''), + $userInfo['id'], + count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0') ); if (empty($rows['id']) === false) { array_push($personalFolders, $rows['id']); diff --git a/api/Model/Database.php b/api/Model/Database.php deleted file mode 100755 index b85ef76f7..000000000 --- a/api/Model/Database.php +++ /dev/null @@ -1,94 +0,0 @@ -connection = new \mysqli(DB_HOST, DB_USER, DB_PASSWD_CLEAR, DB_NAME); - - if ( mysqli_connect_errno()) { - throw new Exception("Could not connect to database."); - } - } catch (Exception $e) { - throw new Exception($e->getMessage()); - } - } - - public function select($query = "" , $params = []) - { - try { - $stmt = $this->executeStatement( $query , $params ); - $result = $stmt->get_result()->fetch_all(MYSQLI_ASSOC); - $stmt->close(); - - return $result; - } catch(Exception $e) { - throw New Exception( $e->getMessage() ); - } - } - - public function update($query = "", $params = []) - { - try { - $stmt = $this->executeStatement($query, $params); - $affectedRows = $stmt->affected_rows; - $stmt->close(); - - return $affectedRows; - } catch (Exception $e) { - throw new Exception($e->getMessage()); - } - } - - - private function executeStatement($query = "", $params = []) - { - try { - $stmt = $this->connection->prepare($query); - - if ($stmt === false) { - throw new Exception("Unable to do prepared statement: " . $query); - } - - if ($params) { - // Supposons que $params[0] contient les types des paramètres comme une chaîne ("ssi") - // et $params[1...] contiennent les valeurs - $types = $params[0]; - $values = array_slice($params, 1); - $stmt->bind_param($types, ...$values); - } - - $stmt->execute(); - - return $stmt; - } catch (Exception $e) { - throw new Exception($e->getMessage()); - } - } - -} \ No newline at end of file diff --git a/api/Model/FolderModel.php b/api/Model/FolderModel.php index 55849ba41..926c15faf 100755 --- a/api/Model/FolderModel.php +++ b/api/Model/FolderModel.php @@ -30,12 +30,17 @@ use TeampassClasses\Language\Language; -require_once API_ROOT_PATH . "/Model/Database.php"; -class FolderModel extends Database +class FolderModel { public function getFoldersInfo(array $foldersId): array { - $rows = $this->select( "SELECT id, title FROM " . prefixTable('nested_tree') . " WHERE nlevel=1" ); + // Get folders + $rows = DB::query( + 'SELECT id, title + FROM ' . prefixTable('nested_tree') . ' + WHERE nlevel = %i', + 1 + ); $ret = []; @@ -62,7 +67,12 @@ public function getFoldersInfo(array $foldersId): array private function getFoldersChildren(int $parentId, array $foldersId): array { $ret = []; - $childrens = $this->select('SELECT id, title FROM ' . prefixTable('nested_tree') . ' WHERE parent_id=' . $parentId); + $childrens = DB::query( + 'SELECT id, title + FROM ' . prefixTable('nested_tree') . ' + WHERE parent_id = %i', + $parentId + ); if ( count($childrens) > 0) { foreach ($childrens as $children) { @@ -174,28 +184,6 @@ public function createFolder( ];} // Create folder - /* - require_once TEAMPASS_ROOT_PATH.'/sources/folders.functions.php'; - $creationStatus = createNewFolder( - (string) $title, - (int) $parent_id, - (int) $complexity, - (int) $duration, - (int) $create_auth_without, - (int) $edit_auth_without, - (string) $icon, - (string) $icon_selected, - (string) $access_rights, - (int) $is_admin, - (array) $foldersId, - (int) $is_manager, - (int) $user_can_create_root_folder, - (int) $user_can_manage_all_users, - (int) $user_id, - (string) $user_roles - ); - */ - require_once TEAMPASS_ROOT_PATH.'/sources/folders.class.php'; $lang = new Language(); $folderManager = new FolderManager($lang); diff --git a/api/Model/ItemModel.php b/api/Model/ItemModel.php index 458b42fce..3a1f730f8 100755 --- a/api/Model/ItemModel.php +++ b/api/Model/ItemModel.php @@ -32,12 +32,9 @@ use TeampassClasses\ConfigManager\ConfigManager; use ZxcvbnPhp\Zxcvbn; -require_once API_ROOT_PATH . "/Model/Database.php"; - -class ItemModel extends Database +class ItemModel { - /** * Get the list of items to return * @@ -50,23 +47,26 @@ class ItemModel extends Database */ public function getItems(string $sqlExtra, int $limit, string $userPrivateKey, int $userId): array { - $rows = $this->select( - "SELECT i.id, label, description, i.pw, i.url, i.id_tree, i.login, i.email, i.viewed_no, i.fa_icon, i.inactif, i.perso, t.title as folder_label - FROM ".prefixTable('items')." as i - LEFT JOIN ".prefixTable('nested_tree')." as t ON (t.id = i.id_tree) ". + // Get items + $rows = DB::query( + 'SELECT i.id, label, description, i.pw, i.url, i.id_tree, i.login, i.email, i.viewed_no, i.fa_icon, i.inactif, i.perso, t.title as folder_label + FROM ' . prefixTable('items') . ' AS i + LEFT JOIN '.prefixTable('nested_tree').' as t ON (t.id = i.id_tree) '. $sqlExtra . " ORDER BY i.id ASC" . - //($limit > 0 ? " LIMIT ?". ["i", $limit] : '') ($limit > 0 ? " LIMIT ". $limit : '') ); + $ret = []; foreach ($rows as $row) { - $userKey = $this->select( + $userKey = DB::queryfirstrow( 'SELECT share_key FROM ' . prefixTable('sharekeys_items') . ' - WHERE user_id = '.$userId.' AND object_id = '.$row['id'] + WHERE user_id = %i AND object_id = %i', + $userId, + $row['id'] ); - if (count($userKey) === 0 || empty($row['pw']) === true) { + if (DB::count() === 0 || empty($row['pw']) === true) { // No share key found // Exit this item continue; @@ -78,7 +78,7 @@ public function getItems(string $sqlExtra, int $limit, string $userPrivateKey, i (string) doDataDecryption( $row['pw'], decryptUserObjectKey( - $userKey[0]['share_key'], + $userKey['share_key'], $userPrivateKey ) ) diff --git a/api/Model/UserModel.php b/api/Model/UserModel.php index 73f82e28a..f86966bd2 100755 --- a/api/Model/UserModel.php +++ b/api/Model/UserModel.php @@ -22,12 +22,16 @@ * * @see https://www.teampass.net */ -require_once API_ROOT_PATH . "/Model/Database.php"; -class UserModel extends Database +class UserModel { public function getUsers($limit) { - return $this->select("SELECT * FROM ".prefixTable('users')." ORDER BY id ASC LIMIT ?", ["i", $limit]); + return DB::query( + 'SELECT * + FROM ' . prefixTable('users') . ' + ORDER BY id ASC LIMIT %i', + $limit + ); } } \ No newline at end of file diff --git a/includes/config/include.php b/includes/config/include.php index 97e864f0a..e38e3bcc7 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1727110744"); -define('TP_VERSION_MINOR', '122'); +define('TP_VERSION_MINOR', '124'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/core/otv.php b/includes/core/otv.php index 3cb4e086b..86d2157c8 100755 --- a/includes/core/otv.php +++ b/includes/core/otv.php @@ -127,7 +127,7 @@ if ((int) $dataDelete['del_type'] === 1 && (int) $dataDelete['del_value'] >= 1) { // decrease counter DB::update( - $pre.'automatic_del', + prefixTable('automatic_del'), [ 'del_value' => $dataDelete['del_value'] - 1, ], @@ -138,7 +138,7 @@ || ((int) $dataDelete['del_type'] === 2 && (int) $dataDelete['del_value'] < time()) ) { // delete item - DB::delete($pre.'automatic_del', 'item_id = %i', $data['item_id']); + DB::delete(prefixTable('automatic_del'), 'item_id = %i', $data['item_id']); // make inactive object DB::update( prefixTable('items'), diff --git a/includes/tables_integrity.json b/includes/tables_integrity.json index 3c0b5230e..5c0f796ad 100644 --- a/includes/tables_integrity.json +++ b/includes/tables_integrity.json @@ -13,11 +13,11 @@ }, { "table_name": "background_tasks", - "structure_hash": "7f1a40046084e0ab5cd5980a5d4d2f5dad9c24950ad818ca7acfa7e7090544e1" + "structure_hash": "019216c55451e2995810d42c1dfd236a3bd57993a963e6d93468ac65fa802529" }, { "table_name": "background_tasks_logs", - "structure_hash": "cdaab9275f583dc301dd1dfdbeca2354f9171990d5cef6569cae8361d084f1f7" + "structure_hash": "580c4986b33e6644dc3682b31edf7efc59b03d3cd428e0ffebe703e4d8662a1f" }, { "table_name": "cache", @@ -101,7 +101,7 @@ }, { "table_name": "log_system", - "structure_hash": "19dacf60bcbbe2d6718582ab586683c7fad6fa81e3dadca965d80fde13a2ff00" + "structure_hash": "1e6bc407e3d9084514392f7aee11af12344d6c86c735ec613319cbbf0444bd52" }, { "table_name": "misc", From 166094bb69c41eceebda823879687d25cbc98f7a Mon Sep 17 00:00:00 2001 From: nilsteampassnet Date: Sat, 28 Sep 2024 08:41:41 +0200 Subject: [PATCH 4/4] 3.1.2 Debug command removal --- api/Model/AuthModel.php | 2 +- composer.json | 3 + composer.lock | 466 +++- includes/config/include.php | 2 +- includes/tables_integrity.json | 2 +- vendor/bin/composer-license-checker | 119 + vendor/bin/composer-license-checker.bat | 5 + vendor/composer/autoload_classmap.php | 195 ++ vendor/composer/autoload_files.php | 11 +- vendor/composer/autoload_psr4.php | 6 + vendor/composer/autoload_real.php | 2 +- vendor/composer/autoload_static.php | 239 +- vendor/composer/ca-bundle/composer.json | 6 +- vendor/composer/ca-bundle/res/cacert.pem | 102 +- vendor/composer/installed.json | 492 +++- vendor/composer/installed.php | 84 +- .../src/Models/Concerns/HasAttributes.php | 5 +- .../FilesystemCache/+/Q/uKaF0vXuJ+AuwTzHzQcw | Bin 0 -> 1249 bytes .../FilesystemCache/5/D/ZlfYo+SbPwmbb-yZtf4A | Bin 0 -> 1479 bytes .../FilesystemCache/A/L/lDsO0qHVWrvZ4ekiDAyw | Bin 0 -> 340 bytes .../FilesystemCache/B/Y/GcmaOPmavMkaLvigZ1Mg | Bin 0 -> 1643 bytes .../FilesystemCache/C/8/N4GTBNtOwJqF+Lxdqwkw | Bin 0 -> 1534 bytes .../FilesystemCache/H/4/x1j2IN4fQFg0xayUIapw | Bin 0 -> 1748 bytes .../FilesystemCache/I/H/0pwehagyyPWxEKfn0arQ | Bin 0 -> 1788 bytes .../FilesystemCache/T/I/tkH8Ws6TWfeWNL-dARxg | Bin 0 -> 1275 bytes .../FilesystemCache/Y/3/kBejHh0OnATVtV7ViTgQ | Bin 0 -> 1325 bytes .../FilesystemCache/Z/J/5wQjQJ00a9VgCiAYVumw | Bin 0 -> 1144 bytes .../.github/workflows/run-tests.yml | 36 + .../composer-license-checker/.styleci.yml | 4 + .../composer-license-checker/CHANGELOG.md | 113 + .../composer-license-checker/CONTRIBUTING.md | 55 + .../composer-license-checker/LICENSE.md | 21 + .../composer-license-checker/README.md | 74 + .../composer-license-checker | 49 + .../composer-license-checker/composer.json | 57 + .../src/CheckCommand.php | 180 ++ .../src/ConstraintViolation.php | 42 + .../src/ConstraintViolationDetector.php | 168 ++ .../src/Contracts/CacheAwareContract.php | 12 + .../src/Contracts/DependencyLoader.php | 15 + .../src/Contracts/DependencyLoaderAware.php | 10 + .../src/Contracts/DependencyParser.php | 15 + .../src/Contracts/LicenseConstraintAware.php | 10 + .../Contracts/LicenseConstraintHandler.php | 26 + .../src/Contracts/LicenseLookup.php | 12 + .../src/Contracts/LicenseLookupAware.php | 10 + .../src/Dependency.php | 101 + .../src/DependencyLoader.php | 57 + .../Exceptions/CommandExecutionException.php | 9 + .../ComposerLicenseCheckerException.php | 11 + .../src/Exceptions/LogicException.php | 9 + .../Exceptions/NoLookupPossibleException.php | 9 + .../src/JSONDependencyParser.php | 25 + .../composer-license-checker/src/License.php | 142 ++ .../src/LicenseLookup.php | 178 ++ .../src/NoLookupLicenses.php | 20 + .../src/ReportCommand.php | 232 ++ .../src/Traits/DependencyLoaderAwareTrait.php | 18 + .../Traits/LicenseConstraintAwareTrait.php | 23 + .../src/Traits/LicenseLookupAwareTrait.php | 18 + .../composer-license-checker/src/helpers.php | 21 + vendor/masterminds/html5/CREDITS | 11 + vendor/masterminds/html5/LICENSE.txt | 66 + vendor/masterminds/html5/README.md | 270 ++ vendor/masterminds/html5/RELEASE.md | 157 ++ vendor/masterminds/html5/UPGRADING.md | 21 + vendor/masterminds/html5/bin/entities.php | 26 + vendor/masterminds/html5/composer.json | 40 + vendor/masterminds/html5/src/HTML5.php | 246 ++ .../masterminds/html5/src/HTML5/Elements.php | 637 +++++ .../masterminds/html5/src/HTML5/Entities.php | 2236 +++++++++++++++++ .../masterminds/html5/src/HTML5/Exception.php | 10 + .../html5/src/HTML5/InstructionProcessor.php | 41 + .../src/HTML5/Parser/CharacterReference.php | 61 + .../html5/src/HTML5/Parser/DOMTreeBuilder.php | 715 ++++++ .../html5/src/HTML5/Parser/EventHandler.php | 114 + .../src/HTML5/Parser/FileInputStream.php | 33 + .../html5/src/HTML5/Parser/InputStream.php | 87 + .../html5/src/HTML5/Parser/ParseError.php | 10 + .../html5/src/HTML5/Parser/README.md | 53 + .../html5/src/HTML5/Parser/Scanner.php | 416 +++ .../src/HTML5/Parser/StringInputStream.php | 336 +++ .../html5/src/HTML5/Parser/Tokenizer.php | 1214 +++++++++ .../src/HTML5/Parser/TreeBuildingRules.php | 127 + .../html5/src/HTML5/Parser/UTF8Utils.php | 177 ++ .../src/HTML5/Serializer/HTML5Entities.php | 1533 +++++++++++ .../src/HTML5/Serializer/OutputRules.php | 553 ++++ .../html5/src/HTML5/Serializer/README.md | 33 + .../src/HTML5/Serializer/RulesInterface.php | 99 + .../html5/src/HTML5/Serializer/Traverser.php | 142 ++ .../symfony/cache/Adapter/AbstractAdapter.php | 188 ++ .../cache/Adapter/AbstractTagAwareAdapter.php | 320 +++ .../cache/Adapter/AdapterInterface.php | 35 + vendor/symfony/cache/Adapter/ApcuAdapter.php | 119 + vendor/symfony/cache/Adapter/ArrayAdapter.php | 366 +++ vendor/symfony/cache/Adapter/ChainAdapter.php | 294 +++ .../cache/Adapter/CouchbaseBucketAdapter.php | 232 ++ .../Adapter/CouchbaseCollectionAdapter.php | 199 ++ .../cache/Adapter/DoctrineDbalAdapter.php | 413 +++ .../cache/Adapter/FilesystemAdapter.php | 29 + .../Adapter/FilesystemTagAwareAdapter.php | 267 ++ .../cache/Adapter/MemcachedAdapter.php | 332 +++ vendor/symfony/cache/Adapter/NullAdapter.php | 105 + .../cache/Adapter/ParameterNormalizer.php | 35 + vendor/symfony/cache/Adapter/PdoAdapter.php | 388 +++ .../symfony/cache/Adapter/PhpArrayAdapter.php | 389 +++ .../symfony/cache/Adapter/PhpFilesAdapter.php | 318 +++ vendor/symfony/cache/Adapter/ProxyAdapter.php | 206 ++ vendor/symfony/cache/Adapter/Psr16Adapter.php | 71 + vendor/symfony/cache/Adapter/RedisAdapter.php | 25 + .../cache/Adapter/RedisTagAwareAdapter.php | 308 +++ .../symfony/cache/Adapter/TagAwareAdapter.php | 375 +++ .../Adapter/TagAwareAdapterInterface.php | 31 + .../cache/Adapter/TraceableAdapter.php | 262 ++ .../Adapter/TraceableTagAwareAdapter.php | 35 + vendor/symfony/cache/CHANGELOG.md | 132 + vendor/symfony/cache/CacheItem.php | 198 ++ .../DataCollector/CacheDataCollector.php | 184 ++ .../CacheCollectorPass.php | 78 + .../CachePoolClearerPass.php | 41 + .../DependencyInjection/CachePoolPass.php | 246 ++ .../CachePoolPrunerPass.php | 51 + .../cache/Exception/CacheException.php | 25 + .../Exception/InvalidArgumentException.php | 25 + .../cache/Exception/LogicException.php | 25 + vendor/symfony/cache/LICENSE | 19 + vendor/symfony/cache/LockRegistry.php | 166 ++ .../cache/Marshaller/DefaultMarshaller.php | 98 + .../cache/Marshaller/DeflateMarshaller.php | 47 + .../cache/Marshaller/MarshallerInterface.php | 38 + .../cache/Marshaller/SodiumMarshaller.php | 74 + .../cache/Marshaller/TagAwareMarshaller.php | 83 + .../Messenger/EarlyExpirationDispatcher.php | 64 + .../Messenger/EarlyExpirationHandler.php | 85 + .../Messenger/EarlyExpirationMessage.php | 100 + vendor/symfony/cache/PruneableInterface.php | 20 + vendor/symfony/cache/Psr16Cache.php | 240 ++ vendor/symfony/cache/README.md | 19 + vendor/symfony/cache/ResettableInterface.php | 21 + .../cache/Traits/AbstractAdapterTrait.php | 380 +++ .../symfony/cache/Traits/ContractsTrait.php | 113 + .../cache/Traits/FilesystemCommonTrait.php | 197 ++ .../symfony/cache/Traits/FilesystemTrait.php | 113 + vendor/symfony/cache/Traits/ProxyTrait.php | 37 + vendor/symfony/cache/Traits/Redis5Proxy.php | 1228 +++++++++ vendor/symfony/cache/Traits/Redis6Proxy.php | 1269 ++++++++++ .../symfony/cache/Traits/Redis6ProxyTrait.php | 81 + .../cache/Traits/RedisCluster5Proxy.php | 983 ++++++++ .../cache/Traits/RedisCluster6Proxy.php | 1139 +++++++++ .../cache/Traits/RedisCluster6ProxyTrait.php | 46 + .../cache/Traits/RedisClusterNodeProxy.php | 47 + .../cache/Traits/RedisClusterProxy.php | 23 + vendor/symfony/cache/Traits/RedisProxy.php | 23 + vendor/symfony/cache/Traits/RedisTrait.php | 676 +++++ vendor/symfony/cache/Traits/RelayProxy.php | 1319 ++++++++++ .../symfony/cache/Traits/RelayProxyTrait.php | 156 ++ vendor/symfony/cache/Traits/ValueWrapper.php | 81 + vendor/symfony/cache/composer.json | 59 + vendor/symfony/css-selector/CHANGELOG.md | 23 + .../css-selector/CssSelectorConverter.php | 67 + .../Exception/ExceptionInterface.php | 24 + .../Exception/ExpressionErrorException.php | 24 + .../Exception/InternalErrorException.php | 24 + .../css-selector/Exception/ParseException.php | 24 + .../Exception/SyntaxErrorException.php | 55 + vendor/symfony/css-selector/LICENSE | 19 + .../css-selector/Node/AbstractNode.php | 32 + .../css-selector/Node/AttributeNode.php | 79 + .../symfony/css-selector/Node/ClassNode.php | 54 + .../Node/CombinedSelectorNode.php | 63 + .../symfony/css-selector/Node/ElementNode.php | 56 + .../css-selector/Node/FunctionNode.php | 71 + vendor/symfony/css-selector/Node/HashNode.php | 54 + .../css-selector/Node/NegationNode.php | 54 + .../css-selector/Node/NodeInterface.php | 29 + .../symfony/css-selector/Node/PseudoNode.php | 54 + .../css-selector/Node/SelectorNode.php | 54 + .../symfony/css-selector/Node/Specificity.php | 73 + .../Parser/Handler/CommentHandler.php | 45 + .../Parser/Handler/HandlerInterface.php | 30 + .../Parser/Handler/HashHandler.php | 55 + .../Parser/Handler/IdentifierHandler.php | 55 + .../Parser/Handler/NumberHandler.php | 51 + .../Parser/Handler/StringHandler.php | 74 + .../Parser/Handler/WhitespaceHandler.php | 43 + vendor/symfony/css-selector/Parser/Parser.php | 359 +++ .../css-selector/Parser/ParserInterface.php | 34 + vendor/symfony/css-selector/Parser/Reader.php | 86 + .../Parser/Shortcut/ClassParser.php | 48 + .../Parser/Shortcut/ElementParser.php | 44 + .../Parser/Shortcut/EmptyStringParser.php | 43 + .../Parser/Shortcut/HashParser.php | 48 + vendor/symfony/css-selector/Parser/Token.php | 111 + .../css-selector/Parser/TokenStream.php | 156 ++ .../Parser/Tokenizer/Tokenizer.php | 73 + .../Parser/Tokenizer/TokenizerEscaping.php | 65 + .../Parser/Tokenizer/TokenizerPatterns.php | 89 + vendor/symfony/css-selector/README.md | 20 + .../XPath/Extension/AbstractExtension.php | 50 + .../Extension/AttributeMatchingExtension.php | 113 + .../XPath/Extension/CombinationExtension.php | 65 + .../XPath/Extension/ExtensionInterface.php | 67 + .../XPath/Extension/FunctionExtension.php | 165 ++ .../XPath/Extension/HtmlExtension.php | 178 ++ .../XPath/Extension/NodeExtension.php | 191 ++ .../XPath/Extension/PseudoClassExtension.php | 122 + .../symfony/css-selector/XPath/Translator.php | 224 ++ .../XPath/TranslatorInterface.php | 37 + .../symfony/css-selector/XPath/XPathExpr.php | 111 + vendor/symfony/css-selector/composer.json | 32 + .../dom-crawler/AbstractUriElement.php | 123 + vendor/symfony/dom-crawler/CHANGELOG.md | 124 + vendor/symfony/dom-crawler/Crawler.php | 1265 ++++++++++ .../dom-crawler/Field/ChoiceFormField.php | 305 +++ .../dom-crawler/Field/FileFormField.php | 112 + .../symfony/dom-crawler/Field/FormField.php | 125 + .../dom-crawler/Field/InputFormField.php | 48 + .../dom-crawler/Field/TextareaFormField.php | 39 + vendor/symfony/dom-crawler/Form.php | 470 ++++ .../symfony/dom-crawler/FormFieldRegistry.php | 175 ++ vendor/symfony/dom-crawler/Image.php | 40 + vendor/symfony/dom-crawler/LICENSE | 19 + vendor/symfony/dom-crawler/Link.php | 37 + vendor/symfony/dom-crawler/README.md | 13 + .../CrawlerAnySelectorTextContains.php | 69 + .../Constraint/CrawlerAnySelectorTextSame.php | 57 + .../CrawlerSelectorAttributeValueSame.php | 55 + .../Test/Constraint/CrawlerSelectorCount.php | 45 + .../Test/Constraint/CrawlerSelectorExists.php | 46 + .../CrawlerSelectorTextContains.php | 64 + .../Constraint/CrawlerSelectorTextSame.php | 53 + vendor/symfony/dom-crawler/UriResolver.php | 140 ++ vendor/symfony/dom-crawler/composer.json | 34 + vendor/symfony/var-exporter/CHANGELOG.md | 25 + .../Exception/ClassNotFoundException.php | 20 + .../Exception/ExceptionInterface.php | 16 + .../var-exporter/Exception/LogicException.php | 16 + .../NotInstantiableTypeException.php | 20 + vendor/symfony/var-exporter/Hydrator.php | 78 + vendor/symfony/var-exporter/Instantiator.php | 59 + .../var-exporter/Internal/Exporter.php | 419 +++ .../var-exporter/Internal/Hydrator.php | 308 +++ .../Internal/LazyObjectRegistry.php | 146 ++ .../var-exporter/Internal/LazyObjectState.php | 133 + .../var-exporter/Internal/LazyObjectTrait.php | 34 + .../var-exporter/Internal/Reference.php | 28 + .../var-exporter/Internal/Registry.php | 144 ++ .../symfony/var-exporter/Internal/Values.php | 27 + vendor/symfony/var-exporter/LICENSE | 19 + .../symfony/var-exporter/LazyGhostTrait.php | 403 +++ .../var-exporter/LazyObjectInterface.php | 32 + .../symfony/var-exporter/LazyProxyTrait.php | 349 +++ vendor/symfony/var-exporter/ProxyHelper.php | 413 +++ vendor/symfony/var-exporter/README.md | 137 + vendor/symfony/var-exporter/VarExporter.php | 114 + vendor/symfony/var-exporter/composer.json | 34 + 256 files changed, 38572 insertions(+), 55 deletions(-) create mode 100755 vendor/bin/composer-license-checker create mode 100755 vendor/bin/composer-license-checker.bat create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/+/Q/uKaF0vXuJ+AuwTzHzQcw create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/5/D/ZlfYo+SbPwmbb-yZtf4A create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/A/L/lDsO0qHVWrvZ4ekiDAyw create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/B/Y/GcmaOPmavMkaLvigZ1Mg create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/C/8/N4GTBNtOwJqF+Lxdqwkw create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/H/4/x1j2IN4fQFg0xayUIapw create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/I/H/0pwehagyyPWxEKfn0arQ create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/T/I/tkH8Ws6TWfeWNL-dARxg create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/Y/3/kBejHh0OnATVtV7ViTgQ create mode 100644 vendor/dominikb/composer-license-checker/.cache/FilesystemCache/Z/J/5wQjQJ00a9VgCiAYVumw create mode 100644 vendor/dominikb/composer-license-checker/.github/workflows/run-tests.yml create mode 100644 vendor/dominikb/composer-license-checker/.styleci.yml create mode 100644 vendor/dominikb/composer-license-checker/CHANGELOG.md create mode 100644 vendor/dominikb/composer-license-checker/CONTRIBUTING.md create mode 100644 vendor/dominikb/composer-license-checker/LICENSE.md create mode 100644 vendor/dominikb/composer-license-checker/README.md create mode 100755 vendor/dominikb/composer-license-checker/composer-license-checker create mode 100644 vendor/dominikb/composer-license-checker/composer.json create mode 100644 vendor/dominikb/composer-license-checker/src/CheckCommand.php create mode 100644 vendor/dominikb/composer-license-checker/src/ConstraintViolation.php create mode 100644 vendor/dominikb/composer-license-checker/src/ConstraintViolationDetector.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/DependencyLoader.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/DependencyLoaderAware.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/DependencyParser.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/LicenseConstraintAware.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/LicenseConstraintHandler.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/LicenseLookup.php create mode 100644 vendor/dominikb/composer-license-checker/src/Contracts/LicenseLookupAware.php create mode 100644 vendor/dominikb/composer-license-checker/src/Dependency.php create mode 100644 vendor/dominikb/composer-license-checker/src/DependencyLoader.php create mode 100644 vendor/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php create mode 100644 vendor/dominikb/composer-license-checker/src/Exceptions/ComposerLicenseCheckerException.php create mode 100644 vendor/dominikb/composer-license-checker/src/Exceptions/LogicException.php create mode 100644 vendor/dominikb/composer-license-checker/src/Exceptions/NoLookupPossibleException.php create mode 100644 vendor/dominikb/composer-license-checker/src/JSONDependencyParser.php create mode 100644 vendor/dominikb/composer-license-checker/src/License.php create mode 100644 vendor/dominikb/composer-license-checker/src/LicenseLookup.php create mode 100644 vendor/dominikb/composer-license-checker/src/NoLookupLicenses.php create mode 100644 vendor/dominikb/composer-license-checker/src/ReportCommand.php create mode 100644 vendor/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php create mode 100644 vendor/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php create mode 100644 vendor/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php create mode 100644 vendor/dominikb/composer-license-checker/src/helpers.php create mode 100644 vendor/masterminds/html5/CREDITS create mode 100644 vendor/masterminds/html5/LICENSE.txt create mode 100644 vendor/masterminds/html5/README.md create mode 100644 vendor/masterminds/html5/RELEASE.md create mode 100644 vendor/masterminds/html5/UPGRADING.md create mode 100644 vendor/masterminds/html5/bin/entities.php create mode 100644 vendor/masterminds/html5/composer.json create mode 100644 vendor/masterminds/html5/src/HTML5.php create mode 100644 vendor/masterminds/html5/src/HTML5/Elements.php create mode 100644 vendor/masterminds/html5/src/HTML5/Entities.php create mode 100644 vendor/masterminds/html5/src/HTML5/Exception.php create mode 100644 vendor/masterminds/html5/src/HTML5/InstructionProcessor.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/CharacterReference.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/DOMTreeBuilder.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/InputStream.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/ParseError.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/README.md create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/Scanner.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php create mode 100644 vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php create mode 100644 vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php create mode 100644 vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php create mode 100644 vendor/masterminds/html5/src/HTML5/Serializer/README.md create mode 100644 vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php create mode 100644 vendor/masterminds/html5/src/HTML5/Serializer/Traverser.php create mode 100644 vendor/symfony/cache/Adapter/AbstractAdapter.php create mode 100644 vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php create mode 100644 vendor/symfony/cache/Adapter/AdapterInterface.php create mode 100644 vendor/symfony/cache/Adapter/ApcuAdapter.php create mode 100644 vendor/symfony/cache/Adapter/ArrayAdapter.php create mode 100644 vendor/symfony/cache/Adapter/ChainAdapter.php create mode 100644 vendor/symfony/cache/Adapter/CouchbaseBucketAdapter.php create mode 100644 vendor/symfony/cache/Adapter/CouchbaseCollectionAdapter.php create mode 100644 vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php create mode 100644 vendor/symfony/cache/Adapter/FilesystemAdapter.php create mode 100644 vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php create mode 100644 vendor/symfony/cache/Adapter/MemcachedAdapter.php create mode 100644 vendor/symfony/cache/Adapter/NullAdapter.php create mode 100644 vendor/symfony/cache/Adapter/ParameterNormalizer.php create mode 100644 vendor/symfony/cache/Adapter/PdoAdapter.php create mode 100644 vendor/symfony/cache/Adapter/PhpArrayAdapter.php create mode 100644 vendor/symfony/cache/Adapter/PhpFilesAdapter.php create mode 100644 vendor/symfony/cache/Adapter/ProxyAdapter.php create mode 100644 vendor/symfony/cache/Adapter/Psr16Adapter.php create mode 100644 vendor/symfony/cache/Adapter/RedisAdapter.php create mode 100644 vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php create mode 100644 vendor/symfony/cache/Adapter/TagAwareAdapter.php create mode 100644 vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php create mode 100644 vendor/symfony/cache/Adapter/TraceableAdapter.php create mode 100644 vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php create mode 100644 vendor/symfony/cache/CHANGELOG.md create mode 100644 vendor/symfony/cache/CacheItem.php create mode 100644 vendor/symfony/cache/DataCollector/CacheDataCollector.php create mode 100644 vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php create mode 100644 vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php create mode 100644 vendor/symfony/cache/DependencyInjection/CachePoolPass.php create mode 100644 vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php create mode 100644 vendor/symfony/cache/Exception/CacheException.php create mode 100644 vendor/symfony/cache/Exception/InvalidArgumentException.php create mode 100644 vendor/symfony/cache/Exception/LogicException.php create mode 100644 vendor/symfony/cache/LICENSE create mode 100644 vendor/symfony/cache/LockRegistry.php create mode 100644 vendor/symfony/cache/Marshaller/DefaultMarshaller.php create mode 100644 vendor/symfony/cache/Marshaller/DeflateMarshaller.php create mode 100644 vendor/symfony/cache/Marshaller/MarshallerInterface.php create mode 100644 vendor/symfony/cache/Marshaller/SodiumMarshaller.php create mode 100644 vendor/symfony/cache/Marshaller/TagAwareMarshaller.php create mode 100644 vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php create mode 100644 vendor/symfony/cache/Messenger/EarlyExpirationHandler.php create mode 100644 vendor/symfony/cache/Messenger/EarlyExpirationMessage.php create mode 100644 vendor/symfony/cache/PruneableInterface.php create mode 100644 vendor/symfony/cache/Psr16Cache.php create mode 100644 vendor/symfony/cache/README.md create mode 100644 vendor/symfony/cache/ResettableInterface.php create mode 100644 vendor/symfony/cache/Traits/AbstractAdapterTrait.php create mode 100644 vendor/symfony/cache/Traits/ContractsTrait.php create mode 100644 vendor/symfony/cache/Traits/FilesystemCommonTrait.php create mode 100644 vendor/symfony/cache/Traits/FilesystemTrait.php create mode 100644 vendor/symfony/cache/Traits/ProxyTrait.php create mode 100644 vendor/symfony/cache/Traits/Redis5Proxy.php create mode 100644 vendor/symfony/cache/Traits/Redis6Proxy.php create mode 100644 vendor/symfony/cache/Traits/Redis6ProxyTrait.php create mode 100644 vendor/symfony/cache/Traits/RedisCluster5Proxy.php create mode 100644 vendor/symfony/cache/Traits/RedisCluster6Proxy.php create mode 100644 vendor/symfony/cache/Traits/RedisCluster6ProxyTrait.php create mode 100644 vendor/symfony/cache/Traits/RedisClusterNodeProxy.php create mode 100644 vendor/symfony/cache/Traits/RedisClusterProxy.php create mode 100644 vendor/symfony/cache/Traits/RedisProxy.php create mode 100644 vendor/symfony/cache/Traits/RedisTrait.php create mode 100644 vendor/symfony/cache/Traits/RelayProxy.php create mode 100644 vendor/symfony/cache/Traits/RelayProxyTrait.php create mode 100644 vendor/symfony/cache/Traits/ValueWrapper.php create mode 100644 vendor/symfony/cache/composer.json create mode 100644 vendor/symfony/css-selector/CHANGELOG.md create mode 100644 vendor/symfony/css-selector/CssSelectorConverter.php create mode 100644 vendor/symfony/css-selector/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/css-selector/Exception/ExpressionErrorException.php create mode 100644 vendor/symfony/css-selector/Exception/InternalErrorException.php create mode 100644 vendor/symfony/css-selector/Exception/ParseException.php create mode 100644 vendor/symfony/css-selector/Exception/SyntaxErrorException.php create mode 100644 vendor/symfony/css-selector/LICENSE create mode 100644 vendor/symfony/css-selector/Node/AbstractNode.php create mode 100644 vendor/symfony/css-selector/Node/AttributeNode.php create mode 100644 vendor/symfony/css-selector/Node/ClassNode.php create mode 100644 vendor/symfony/css-selector/Node/CombinedSelectorNode.php create mode 100644 vendor/symfony/css-selector/Node/ElementNode.php create mode 100644 vendor/symfony/css-selector/Node/FunctionNode.php create mode 100644 vendor/symfony/css-selector/Node/HashNode.php create mode 100644 vendor/symfony/css-selector/Node/NegationNode.php create mode 100644 vendor/symfony/css-selector/Node/NodeInterface.php create mode 100644 vendor/symfony/css-selector/Node/PseudoNode.php create mode 100644 vendor/symfony/css-selector/Node/SelectorNode.php create mode 100644 vendor/symfony/css-selector/Node/Specificity.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/CommentHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/HashHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/NumberHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/StringHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php create mode 100644 vendor/symfony/css-selector/Parser/Parser.php create mode 100644 vendor/symfony/css-selector/Parser/ParserInterface.php create mode 100644 vendor/symfony/css-selector/Parser/Reader.php create mode 100644 vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php create mode 100644 vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php create mode 100644 vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php create mode 100644 vendor/symfony/css-selector/Parser/Shortcut/HashParser.php create mode 100644 vendor/symfony/css-selector/Parser/Token.php create mode 100644 vendor/symfony/css-selector/Parser/TokenStream.php create mode 100644 vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php create mode 100644 vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php create mode 100644 vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php create mode 100644 vendor/symfony/css-selector/README.md create mode 100644 vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/NodeExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php create mode 100644 vendor/symfony/css-selector/XPath/Translator.php create mode 100644 vendor/symfony/css-selector/XPath/TranslatorInterface.php create mode 100644 vendor/symfony/css-selector/XPath/XPathExpr.php create mode 100644 vendor/symfony/css-selector/composer.json create mode 100644 vendor/symfony/dom-crawler/AbstractUriElement.php create mode 100644 vendor/symfony/dom-crawler/CHANGELOG.md create mode 100644 vendor/symfony/dom-crawler/Crawler.php create mode 100644 vendor/symfony/dom-crawler/Field/ChoiceFormField.php create mode 100644 vendor/symfony/dom-crawler/Field/FileFormField.php create mode 100644 vendor/symfony/dom-crawler/Field/FormField.php create mode 100644 vendor/symfony/dom-crawler/Field/InputFormField.php create mode 100644 vendor/symfony/dom-crawler/Field/TextareaFormField.php create mode 100644 vendor/symfony/dom-crawler/Form.php create mode 100644 vendor/symfony/dom-crawler/FormFieldRegistry.php create mode 100644 vendor/symfony/dom-crawler/Image.php create mode 100644 vendor/symfony/dom-crawler/LICENSE create mode 100644 vendor/symfony/dom-crawler/Link.php create mode 100644 vendor/symfony/dom-crawler/README.md create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php create mode 100644 vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php create mode 100644 vendor/symfony/dom-crawler/UriResolver.php create mode 100644 vendor/symfony/dom-crawler/composer.json create mode 100644 vendor/symfony/var-exporter/CHANGELOG.md create mode 100644 vendor/symfony/var-exporter/Exception/ClassNotFoundException.php create mode 100644 vendor/symfony/var-exporter/Exception/ExceptionInterface.php create mode 100644 vendor/symfony/var-exporter/Exception/LogicException.php create mode 100644 vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php create mode 100644 vendor/symfony/var-exporter/Hydrator.php create mode 100644 vendor/symfony/var-exporter/Instantiator.php create mode 100644 vendor/symfony/var-exporter/Internal/Exporter.php create mode 100644 vendor/symfony/var-exporter/Internal/Hydrator.php create mode 100644 vendor/symfony/var-exporter/Internal/LazyObjectRegistry.php create mode 100644 vendor/symfony/var-exporter/Internal/LazyObjectState.php create mode 100644 vendor/symfony/var-exporter/Internal/LazyObjectTrait.php create mode 100644 vendor/symfony/var-exporter/Internal/Reference.php create mode 100644 vendor/symfony/var-exporter/Internal/Registry.php create mode 100644 vendor/symfony/var-exporter/Internal/Values.php create mode 100644 vendor/symfony/var-exporter/LICENSE create mode 100644 vendor/symfony/var-exporter/LazyGhostTrait.php create mode 100644 vendor/symfony/var-exporter/LazyObjectInterface.php create mode 100644 vendor/symfony/var-exporter/LazyProxyTrait.php create mode 100644 vendor/symfony/var-exporter/ProxyHelper.php create mode 100644 vendor/symfony/var-exporter/README.md create mode 100644 vendor/symfony/var-exporter/VarExporter.php create mode 100644 vendor/symfony/var-exporter/composer.json diff --git a/api/Model/AuthModel.php b/api/Model/AuthModel.php index eb799b749..0fb2bcbcf 100755 --- a/api/Model/AuthModel.php +++ b/api/Model/AuthModel.php @@ -272,7 +272,7 @@ private function buildUserFoldersList(array $userInfo): array } } } - //error_log(print_r($userFunctionId, true)); + // Does this user is allowed to see other items $inc = 0; $rows = DB::query( diff --git a/composer.json b/composer.json index 65c94e00b..47056de60 100755 --- a/composer.json +++ b/composer.json @@ -183,5 +183,8 @@ "thenetworg/oauth2-azure": "^2.2", "symfony/console": "^6.4", "composer/composer": "^2.7" + }, + "require-dev": { + "dominikb/composer-license-checker": "^2.6" } } diff --git a/composer.lock b/composer.lock index f55f5e68b..28da360e1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e37582c47b15ebf4c74f281058322ade", + "content-hash": "64ee2e1d0026c68c1f41f48c7dcec2ad", "packages": [ { "name": "bjeavons/zxcvbn-php", @@ -192,16 +192,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.1", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/48a792895a2b7a6ee65dd5442c299d7b835b6137", + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137", "shasum": "" }, "require": { @@ -211,8 +211,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", @@ -248,7 +248,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.1" + "source": "https://github.com/composer/ca-bundle/tree/1.5.2" }, "funding": [ { @@ -264,7 +264,7 @@ "type": "tidelift" } ], - "time": "2024-07-08T15:28:20+00:00" + "time": "2024-09-25T07:49:53+00:00" }, { "name": "composer/class-map-generator", @@ -897,16 +897,16 @@ }, { "name": "directorytree/ldaprecord", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/DirectoryTree/LdapRecord.git", - "reference": "4113aa08f72bbc76630fad3b05d57cd431fb0839" + "reference": "9b5f53d820a490fdb0c7a098c93f3b83b74455dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/4113aa08f72bbc76630fad3b05d57cd431fb0839", - "reference": "4113aa08f72bbc76630fad3b05d57cd431fb0839", + "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/9b5f53d820a490fdb0c7a098c93f3b83b74455dd", + "reference": "9b5f53d820a490fdb0c7a098c93f3b83b74455dd", "shasum": "" }, "require": { @@ -969,7 +969,7 @@ "type": "github" } ], - "time": "2024-07-26T21:20:12+00:00" + "time": "2024-09-23T03:45:43+00:00" }, { "name": "dittertp/gibberish-aes-php", @@ -6725,7 +6725,445 @@ "time": "2022-06-03T18:03:27+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "dominikb/composer-license-checker", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/dominikb/composer-license-checker.git", + "reference": "22c2bb46acc5ab71d828ab9589be5a2820f8b221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dominikb/composer-license-checker/zipball/22c2bb46acc5ab71d828ab9589be5a2820f8b221", + "reference": "22c2bb46acc5ab71d828ab9589be5a2820f8b221", + "shasum": "" + }, + "require": { + "composer/composer": "~2.2.23 || ^2.7.0", + "ext-json": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "php": "^7.3 || ^8.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "~4.2.12 || ^4.3.8 || ^5.2 || ^6.0 || ^7.0", + "symfony/console": "^5.3 || ^6.0 || ^7.0", + "symfony/css-selector": "^4.2 || ^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "phpunit/phpunit": "^9.3", + "symfony/var-dumper": "^4.2 || ^5.2 || ^6.0 || ^7.0" + }, + "bin": [ + "composer-license-checker" + ], + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Dominikb\\ComposerLicenseChecker\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dominik Bauernfeind", + "email": "bauernfeind.dominik@gmail.com", + "role": "Developer" + } + ], + "description": "Utility to check for licenses of dependencies and block/allow them.", + "homepage": "https://github.com/dominikb/composer-license-checker", + "keywords": [ + "composer-license-checker", + "dominikb" + ], + "support": { + "issues": "https://github.com/dominikb/composer-license-checker/issues", + "source": "https://github.com/dominikb/composer-license-checker/tree/2.6.0" + }, + "time": "2024-07-06T14:35:50+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + }, + "time": "2024-03-31T07:05:07+00:00" + }, + { + "name": "symfony/cache", + "version": "v6.4.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.3.6|^7.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/var-dumper": "<5.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v6.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-16T16:01:33+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v6.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v6.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:49:08+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v6.4.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/9d307ecbcb917001692be333cdc58f474fdb37f0", + "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-15T06:35:36+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v6.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f9a060622e0d93777b7f8687ec4860191e16802e", + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v6.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-24T15:53:56+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": { diff --git a/includes/config/include.php b/includes/config/include.php index e38e3bcc7..aad0fbc9d 100755 --- a/includes/config/include.php +++ b/includes/config/include.php @@ -28,7 +28,7 @@ define('TP_VERSION', '3.1.2'); define("UPGRADE_MIN_DATE", "1727110744"); -define('TP_VERSION_MINOR', '124'); +define('TP_VERSION_MINOR', '126'); define('TP_TOOL_NAME', 'Teampass'); define('TP_ONE_DAY_SECONDS', 86400); define('TP_ONE_WEEK_SECONDS', 604800); diff --git a/includes/tables_integrity.json b/includes/tables_integrity.json index 5c0f796ad..5924a93b2 100644 --- a/includes/tables_integrity.json +++ b/includes/tables_integrity.json @@ -17,7 +17,7 @@ }, { "table_name": "background_tasks_logs", - "structure_hash": "580c4986b33e6644dc3682b31edf7efc59b03d3cd428e0ffebe703e4d8662a1f" + "structure_hash": "8f780290562b44d9d4f369afedfbfb15321a14ffe2203a76309751d80c6bfb4c" }, { "table_name": "cache", diff --git a/vendor/bin/composer-license-checker b/vendor/bin/composer-license-checker new file mode 100755 index 000000000..8572a5de4 --- /dev/null +++ b/vendor/bin/composer-license-checker @@ -0,0 +1,119 @@ +#!/usr/bin/env php +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__ . '/..'.'/dominikb/composer-license-checker/composer-license-checker'); + } +} + +return include __DIR__ . '/..'.'/dominikb/composer-license-checker/composer-license-checker'; diff --git a/vendor/bin/composer-license-checker.bat b/vendor/bin/composer-license-checker.bat new file mode 100755 index 000000000..2933399e2 --- /dev/null +++ b/vendor/bin/composer-license-checker.bat @@ -0,0 +1,5 @@ +@ECHO OFF +setlocal DISABLEDELAYEDEXPANSION +SET BIN_TARGET=%~dp0/composer-license-checker +SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 +php "%BIN_TARGET%" %* diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index f9631950c..0f27ba153 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -514,6 +514,31 @@ 'Doctrine\\Inflector\\Rules\\Word' => $vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php', 'Doctrine\\Inflector\\RulesetInflector' => $vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php', 'Doctrine\\Inflector\\WordInflector' => $vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php', + 'Dominikb\\ComposerLicenseChecker\\CheckCommand' => $vendorDir . '/dominikb/composer-license-checker/src/CheckCommand.php', + 'Dominikb\\ComposerLicenseChecker\\ConstraintViolation' => $vendorDir . '/dominikb/composer-license-checker/src/ConstraintViolation.php', + 'Dominikb\\ComposerLicenseChecker\\ConstraintViolationDetector' => $vendorDir . '/dominikb/composer-license-checker/src/ConstraintViolationDetector.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\CacheAwareContract' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyLoader' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/DependencyLoader.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyLoaderAware' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/DependencyLoaderAware.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyParser' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/DependencyParser.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseConstraintAware' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/LicenseConstraintAware.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseConstraintHandler' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/LicenseConstraintHandler.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseLookup' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/LicenseLookup.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseLookupAware' => $vendorDir . '/dominikb/composer-license-checker/src/Contracts/LicenseLookupAware.php', + 'Dominikb\\ComposerLicenseChecker\\Dependency' => $vendorDir . '/dominikb/composer-license-checker/src/Dependency.php', + 'Dominikb\\ComposerLicenseChecker\\DependencyLoader' => $vendorDir . '/dominikb/composer-license-checker/src/DependencyLoader.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\CommandExecutionException' => $vendorDir . '/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\ComposerLicenseCheckerException' => $vendorDir . '/dominikb/composer-license-checker/src/Exceptions/ComposerLicenseCheckerException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\LogicException' => $vendorDir . '/dominikb/composer-license-checker/src/Exceptions/LogicException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\NoLookupPossibleException' => $vendorDir . '/dominikb/composer-license-checker/src/Exceptions/NoLookupPossibleException.php', + 'Dominikb\\ComposerLicenseChecker\\JSONDependencyParser' => $vendorDir . '/dominikb/composer-license-checker/src/JSONDependencyParser.php', + 'Dominikb\\ComposerLicenseChecker\\License' => $vendorDir . '/dominikb/composer-license-checker/src/License.php', + 'Dominikb\\ComposerLicenseChecker\\LicenseLookup' => $vendorDir . '/dominikb/composer-license-checker/src/LicenseLookup.php', + 'Dominikb\\ComposerLicenseChecker\\NoLookupLicenses' => $vendorDir . '/dominikb/composer-license-checker/src/NoLookupLicenses.php', + 'Dominikb\\ComposerLicenseChecker\\ReportCommand' => $vendorDir . '/dominikb/composer-license-checker/src/ReportCommand.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\DependencyLoaderAwareTrait' => $vendorDir . '/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\LicenseConstraintAwareTrait' => $vendorDir . '/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\LicenseLookupAwareTrait' => $vendorDir . '/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php', 'Duo\\DuoUniversal\\Client' => $vendorDir . '/duosecurity/duo_universal_php/src/Client.php', 'Duo\\DuoUniversal\\DuoException' => $vendorDir . '/duosecurity/duo_universal_php/src/DuoException.php', 'EZimuel\\PHPSecureSession\\SecureHandler' => $vendorDir . '/ezimuel/php-secure-session/src/SecureHandler.php', @@ -1327,6 +1352,26 @@ 'League\\OAuth2\\Client\\Tool\\RequestFactory' => $vendorDir . '/league/oauth2-client/src/Tool/RequestFactory.php', 'League\\OAuth2\\Client\\Tool\\RequiredParameterTrait' => $vendorDir . '/league/oauth2-client/src/Tool/RequiredParameterTrait.php', 'LoggerInterface' => $vendorDir . '/owasp/csrf-protector-php/libs/csrf/LoggerInterface.php', + 'Masterminds\\HTML5' => $vendorDir . '/masterminds/html5/src/HTML5.php', + 'Masterminds\\HTML5\\Elements' => $vendorDir . '/masterminds/html5/src/HTML5/Elements.php', + 'Masterminds\\HTML5\\Entities' => $vendorDir . '/masterminds/html5/src/HTML5/Entities.php', + 'Masterminds\\HTML5\\Exception' => $vendorDir . '/masterminds/html5/src/HTML5/Exception.php', + 'Masterminds\\HTML5\\InstructionProcessor' => $vendorDir . '/masterminds/html5/src/HTML5/InstructionProcessor.php', + 'Masterminds\\HTML5\\Parser\\CharacterReference' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/CharacterReference.php', + 'Masterminds\\HTML5\\Parser\\DOMTreeBuilder' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/DOMTreeBuilder.php', + 'Masterminds\\HTML5\\Parser\\EventHandler' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/EventHandler.php', + 'Masterminds\\HTML5\\Parser\\FileInputStream' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/FileInputStream.php', + 'Masterminds\\HTML5\\Parser\\InputStream' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/InputStream.php', + 'Masterminds\\HTML5\\Parser\\ParseError' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/ParseError.php', + 'Masterminds\\HTML5\\Parser\\Scanner' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/Scanner.php', + 'Masterminds\\HTML5\\Parser\\StringInputStream' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/StringInputStream.php', + 'Masterminds\\HTML5\\Parser\\Tokenizer' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/Tokenizer.php', + 'Masterminds\\HTML5\\Parser\\TreeBuildingRules' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php', + 'Masterminds\\HTML5\\Parser\\UTF8Utils' => $vendorDir . '/masterminds/html5/src/HTML5/Parser/UTF8Utils.php', + 'Masterminds\\HTML5\\Serializer\\HTML5Entities' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php', + 'Masterminds\\HTML5\\Serializer\\OutputRules' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/OutputRules.php', + 'Masterminds\\HTML5\\Serializer\\RulesInterface' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/RulesInterface.php', + 'Masterminds\\HTML5\\Serializer\\Traverser' => $vendorDir . '/masterminds/html5/src/HTML5/Serializer/Traverser.php', 'Math_BigInteger' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php', 'MeekroDB' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => $vendorDir . '/sergeytsalkov/meekrodb/db.class.php', @@ -1494,6 +1539,69 @@ 'Seld\\PharUtils\\Timestamps' => $vendorDir . '/seld/phar-utils/src/Timestamps.php', 'Seld\\Signal\\SignalHandler' => $vendorDir . '/seld/signal-handler/src/SignalHandler.php', 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => $vendorDir . '/symfony/cache/Adapter/AdapterInterface.php', + 'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => $vendorDir . '/symfony/cache/Adapter/ApcuAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/ArrayAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => $vendorDir . '/symfony/cache/Adapter/ChainAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\CouchbaseBucketAdapter' => $vendorDir . '/symfony/cache/Adapter/CouchbaseBucketAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\CouchbaseCollectionAdapter' => $vendorDir . '/symfony/cache/Adapter/CouchbaseCollectionAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter' => $vendorDir . '/symfony/cache/Adapter/DoctrineDbalAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => $vendorDir . '/symfony/cache/Adapter/MemcachedAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => $vendorDir . '/symfony/cache/Adapter/NullAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ParameterNormalizer' => $vendorDir . '/symfony/cache/Adapter/ParameterNormalizer.php', + 'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => $vendorDir . '/symfony/cache/Adapter/PdoAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpArrayAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => $vendorDir . '/symfony/cache/Adapter/PhpFilesAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => $vendorDir . '/symfony/cache/Adapter/ProxyAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => $vendorDir . '/symfony/cache/Adapter/Psr16Adapter.php', + 'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/RedisTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => $vendorDir . '/symfony/cache/Adapter/TagAwareAdapterInterface.php', + 'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => $vendorDir . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\CacheItem' => $vendorDir . '/symfony/cache/CacheItem.php', + 'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => $vendorDir . '/symfony/cache/DataCollector/CacheDataCollector.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => $vendorDir . '/symfony/cache/DependencyInjection/CacheCollectorPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => $vendorDir . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php', + 'Symfony\\Component\\Cache\\Exception\\CacheException' => $vendorDir . '/symfony/cache/Exception/CacheException.php', + 'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/cache/Exception/InvalidArgumentException.php', + 'Symfony\\Component\\Cache\\Exception\\LogicException' => $vendorDir . '/symfony/cache/Exception/LogicException.php', + 'Symfony\\Component\\Cache\\LockRegistry' => $vendorDir . '/symfony/cache/LockRegistry.php', + 'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DefaultMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => $vendorDir . '/symfony/cache/Marshaller/DeflateMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => $vendorDir . '/symfony/cache/Marshaller/MarshallerInterface.php', + 'Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller' => $vendorDir . '/symfony/cache/Marshaller/SodiumMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => $vendorDir . '/symfony/cache/Marshaller/TagAwareMarshaller.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationDispatcher' => $vendorDir . '/symfony/cache/Messenger/EarlyExpirationDispatcher.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationHandler' => $vendorDir . '/symfony/cache/Messenger/EarlyExpirationHandler.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationMessage' => $vendorDir . '/symfony/cache/Messenger/EarlyExpirationMessage.php', + 'Symfony\\Component\\Cache\\PruneableInterface' => $vendorDir . '/symfony/cache/PruneableInterface.php', + 'Symfony\\Component\\Cache\\Psr16Cache' => $vendorDir . '/symfony/cache/Psr16Cache.php', + 'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php', + 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => $vendorDir . '/symfony/cache/Traits/AbstractAdapterTrait.php', + 'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => $vendorDir . '/symfony/cache/Traits/ContractsTrait.php', + 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php', + 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php', + 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => $vendorDir . '/symfony/cache/Traits/Redis5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => $vendorDir . '/symfony/cache/Traits/Redis6Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis6ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster6Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterNodeProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RelayProxy' => $vendorDir . '/symfony/cache/Traits/RelayProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => $vendorDir . '/symfony/cache/Traits/RelayProxyTrait.php', 'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php', 'Symfony\\Component\\Console\\Attribute\\AsCommand' => $vendorDir . '/symfony/console/Attribute/AsCommand.php', 'Symfony\\Component\\Console\\CI\\GithubActionReporter' => $vendorDir . '/symfony/console/CI/GithubActionReporter.php', @@ -1612,6 +1720,73 @@ 'Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php', 'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => $vendorDir . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', 'Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php', + 'Symfony\\Component\\CssSelector\\CssSelectorConverter' => $vendorDir . '/symfony/css-selector/CssSelectorConverter.php', + 'Symfony\\Component\\CssSelector\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/css-selector/Exception/ExceptionInterface.php', + 'Symfony\\Component\\CssSelector\\Exception\\ExpressionErrorException' => $vendorDir . '/symfony/css-selector/Exception/ExpressionErrorException.php', + 'Symfony\\Component\\CssSelector\\Exception\\InternalErrorException' => $vendorDir . '/symfony/css-selector/Exception/InternalErrorException.php', + 'Symfony\\Component\\CssSelector\\Exception\\ParseException' => $vendorDir . '/symfony/css-selector/Exception/ParseException.php', + 'Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException' => $vendorDir . '/symfony/css-selector/Exception/SyntaxErrorException.php', + 'Symfony\\Component\\CssSelector\\Node\\AbstractNode' => $vendorDir . '/symfony/css-selector/Node/AbstractNode.php', + 'Symfony\\Component\\CssSelector\\Node\\AttributeNode' => $vendorDir . '/symfony/css-selector/Node/AttributeNode.php', + 'Symfony\\Component\\CssSelector\\Node\\ClassNode' => $vendorDir . '/symfony/css-selector/Node/ClassNode.php', + 'Symfony\\Component\\CssSelector\\Node\\CombinedSelectorNode' => $vendorDir . '/symfony/css-selector/Node/CombinedSelectorNode.php', + 'Symfony\\Component\\CssSelector\\Node\\ElementNode' => $vendorDir . '/symfony/css-selector/Node/ElementNode.php', + 'Symfony\\Component\\CssSelector\\Node\\FunctionNode' => $vendorDir . '/symfony/css-selector/Node/FunctionNode.php', + 'Symfony\\Component\\CssSelector\\Node\\HashNode' => $vendorDir . '/symfony/css-selector/Node/HashNode.php', + 'Symfony\\Component\\CssSelector\\Node\\NegationNode' => $vendorDir . '/symfony/css-selector/Node/NegationNode.php', + 'Symfony\\Component\\CssSelector\\Node\\NodeInterface' => $vendorDir . '/symfony/css-selector/Node/NodeInterface.php', + 'Symfony\\Component\\CssSelector\\Node\\PseudoNode' => $vendorDir . '/symfony/css-selector/Node/PseudoNode.php', + 'Symfony\\Component\\CssSelector\\Node\\SelectorNode' => $vendorDir . '/symfony/css-selector/Node/SelectorNode.php', + 'Symfony\\Component\\CssSelector\\Node\\Specificity' => $vendorDir . '/symfony/css-selector/Node/Specificity.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\CommentHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/CommentHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\HandlerInterface' => $vendorDir . '/symfony/css-selector/Parser/Handler/HandlerInterface.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\HashHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/HashHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\IdentifierHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/IdentifierHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\NumberHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/NumberHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\StringHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/StringHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\WhitespaceHandler' => $vendorDir . '/symfony/css-selector/Parser/Handler/WhitespaceHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Parser' => $vendorDir . '/symfony/css-selector/Parser/Parser.php', + 'Symfony\\Component\\CssSelector\\Parser\\ParserInterface' => $vendorDir . '/symfony/css-selector/Parser/ParserInterface.php', + 'Symfony\\Component\\CssSelector\\Parser\\Reader' => $vendorDir . '/symfony/css-selector/Parser/Reader.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ClassParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/ClassParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ElementParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/ElementParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\EmptyStringParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\HashParser' => $vendorDir . '/symfony/css-selector/Parser/Shortcut/HashParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Token' => $vendorDir . '/symfony/css-selector/Parser/Token.php', + 'Symfony\\Component\\CssSelector\\Parser\\TokenStream' => $vendorDir . '/symfony/css-selector/Parser/TokenStream.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\Tokenizer' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/Tokenizer.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerEscaping' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerPatterns' => $vendorDir . '/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\AbstractExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/AbstractExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\AttributeMatchingExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\CombinationExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/CombinationExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\ExtensionInterface' => $vendorDir . '/symfony/css-selector/XPath/Extension/ExtensionInterface.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\FunctionExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/FunctionExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\HtmlExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/HtmlExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\NodeExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/NodeExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\PseudoClassExtension' => $vendorDir . '/symfony/css-selector/XPath/Extension/PseudoClassExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Translator' => $vendorDir . '/symfony/css-selector/XPath/Translator.php', + 'Symfony\\Component\\CssSelector\\XPath\\TranslatorInterface' => $vendorDir . '/symfony/css-selector/XPath/TranslatorInterface.php', + 'Symfony\\Component\\CssSelector\\XPath\\XPathExpr' => $vendorDir . '/symfony/css-selector/XPath/XPathExpr.php', + 'Symfony\\Component\\DomCrawler\\AbstractUriElement' => $vendorDir . '/symfony/dom-crawler/AbstractUriElement.php', + 'Symfony\\Component\\DomCrawler\\Crawler' => $vendorDir . '/symfony/dom-crawler/Crawler.php', + 'Symfony\\Component\\DomCrawler\\Field\\ChoiceFormField' => $vendorDir . '/symfony/dom-crawler/Field/ChoiceFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\FileFormField' => $vendorDir . '/symfony/dom-crawler/Field/FileFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\FormField' => $vendorDir . '/symfony/dom-crawler/Field/FormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\InputFormField' => $vendorDir . '/symfony/dom-crawler/Field/InputFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\TextareaFormField' => $vendorDir . '/symfony/dom-crawler/Field/TextareaFormField.php', + 'Symfony\\Component\\DomCrawler\\Form' => $vendorDir . '/symfony/dom-crawler/Form.php', + 'Symfony\\Component\\DomCrawler\\FormFieldRegistry' => $vendorDir . '/symfony/dom-crawler/FormFieldRegistry.php', + 'Symfony\\Component\\DomCrawler\\Image' => $vendorDir . '/symfony/dom-crawler/Image.php', + 'Symfony\\Component\\DomCrawler\\Link' => $vendorDir . '/symfony/dom-crawler/Link.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerAnySelectorTextContains' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerAnySelectorTextSame' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorAttributeValueSame' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorCount' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorExists' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextContains' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextSame' => $vendorDir . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php', + 'Symfony\\Component\\DomCrawler\\UriResolver' => $vendorDir . '/symfony/dom-crawler/UriResolver.php', 'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php', 'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php', 'Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php', @@ -1970,6 +2145,25 @@ 'Symfony\\Component\\Translation\\Util\\XliffUtils' => $vendorDir . '/symfony/translation/Util/XliffUtils.php', 'Symfony\\Component\\Translation\\Writer\\TranslationWriter' => $vendorDir . '/symfony/translation/Writer/TranslationWriter.php', 'Symfony\\Component\\Translation\\Writer\\TranslationWriterInterface' => $vendorDir . '/symfony/translation/Writer/TranslationWriterInterface.php', + 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => $vendorDir . '/symfony/var-exporter/Exception/ClassNotFoundException.php', + 'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/var-exporter/Exception/ExceptionInterface.php', + 'Symfony\\Component\\VarExporter\\Exception\\LogicException' => $vendorDir . '/symfony/var-exporter/Exception/LogicException.php', + 'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => $vendorDir . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php', + 'Symfony\\Component\\VarExporter\\Hydrator' => $vendorDir . '/symfony/var-exporter/Hydrator.php', + 'Symfony\\Component\\VarExporter\\Instantiator' => $vendorDir . '/symfony/var-exporter/Instantiator.php', + 'Symfony\\Component\\VarExporter\\Internal\\Exporter' => $vendorDir . '/symfony/var-exporter/Internal/Exporter.php', + 'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => $vendorDir . '/symfony/var-exporter/Internal/Hydrator.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectRegistry' => $vendorDir . '/symfony/var-exporter/Internal/LazyObjectRegistry.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectState' => $vendorDir . '/symfony/var-exporter/Internal/LazyObjectState.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectTrait' => $vendorDir . '/symfony/var-exporter/Internal/LazyObjectTrait.php', + 'Symfony\\Component\\VarExporter\\Internal\\Reference' => $vendorDir . '/symfony/var-exporter/Internal/Reference.php', + 'Symfony\\Component\\VarExporter\\Internal\\Registry' => $vendorDir . '/symfony/var-exporter/Internal/Registry.php', + 'Symfony\\Component\\VarExporter\\Internal\\Values' => $vendorDir . '/symfony/var-exporter/Internal/Values.php', + 'Symfony\\Component\\VarExporter\\LazyGhostTrait' => $vendorDir . '/symfony/var-exporter/LazyGhostTrait.php', + 'Symfony\\Component\\VarExporter\\LazyObjectInterface' => $vendorDir . '/symfony/var-exporter/LazyObjectInterface.php', + 'Symfony\\Component\\VarExporter\\LazyProxyTrait' => $vendorDir . '/symfony/var-exporter/LazyProxyTrait.php', + 'Symfony\\Component\\VarExporter\\ProxyHelper' => $vendorDir . '/symfony/var-exporter/ProxyHelper.php', + 'Symfony\\Component\\VarExporter\\VarExporter' => $vendorDir . '/symfony/var-exporter/VarExporter.php', 'Symfony\\Contracts\\Cache\\CacheInterface' => $vendorDir . '/symfony/contracts/Cache/CacheInterface.php', 'Symfony\\Contracts\\Cache\\CacheTrait' => $vendorDir . '/symfony/contracts/Cache/CacheTrait.php', 'Symfony\\Contracts\\Cache\\CallbackInterface' => $vendorDir . '/symfony/contracts/Cache/CallbackInterface.php', @@ -2095,4 +2289,5 @@ 'voku\\helper\\AntiXSS' => $vendorDir . '/voku/anti-xss/src/voku/helper/AntiXSS.php', 'voku\\helper\\Bootup' => $vendorDir . '/voku/portable-utf8/src/voku/helper/Bootup.php', 'voku\\helper\\UTF8' => $vendorDir . '/voku/portable-utf8/src/voku/helper/UTF8.php', + '' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 2af05c40f..a98dcaf50 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -9,22 +9,23 @@ '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', - 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php', - 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', '06a34129a50df3d9257ee706cf3c875b' => $vendorDir . '/illuminate/filesystem/functions.php', '662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php', - '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', - 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php', - 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', 'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php', + 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php', '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', 'b46ad4fe52f4d1899a2951c7e6ea56b0' => $vendorDir . '/voku/portable-utf8/bootstrap.php', + 'a2317519146f89bafaee186bdfa8e099' => $vendorDir . '/dominikb/composer-license-checker/src/helpers.php', 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', '3919eeb97e98d4648304477f8ef734ba' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', '2324d0e5cadd603331d27de142371f0b' => $vendorDir . '/symfony/contracts/Deprecation/function.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 8af0dcf31..767a1ef4e 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -34,6 +34,7 @@ 'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'), 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), 'Symfony\\Contracts\\' => array($vendorDir . '/symfony/contracts'), + 'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), 'Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), @@ -42,7 +43,10 @@ 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'), + 'Symfony\\Component\\DomCrawler\\' => array($vendorDir . '/symfony/dom-crawler'), + 'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'), 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), + 'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'), 'Seld\\Signal\\' => array($vendorDir . '/seld/signal-handler/src'), 'Seld\\PharUtils\\' => array($vendorDir . '/seld/phar-utils/src'), 'Seld\\JsonLint\\' => array($vendorDir . '/seld/jsonlint/src/Seld/JsonLint'), @@ -59,6 +63,7 @@ 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'OTPHP\\' => array($vendorDir . '/spomky-labs/otphp/src'), + 'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'), 'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src'), 'LdapRecord\\' => array($vendorDir . '/directorytree/ldaprecord/src'), 'JsonSchema\\' => array($vendorDir . '/justinrainbow/json-schema/src/JsonSchema'), @@ -78,6 +83,7 @@ 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/src'), 'EZimuel\\PHPSecureSession\\' => array($vendorDir . '/ezimuel/php-secure-session/src'), 'Duo\\DuoUniversal\\' => array($vendorDir . '/duosecurity/duo_universal_php/src'), + 'Dominikb\\ComposerLicenseChecker\\' => array($vendorDir . '/dominikb/composer-license-checker/src'), 'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'), 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'), 'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index d33ac3863..3c34ee654 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -35,7 +35,7 @@ public static function getLoader() require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11::getInitializer($loader)); - $loader->setApcuPrefix('1d12379e544b5ce13ce6'); + $loader->setApcuPrefix('b95328986d6b35bd5725'); $loader->register(true); $filesToLoad = \Composer\Autoload\ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11::$files; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 21e591369..76720977c 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -10,22 +10,23 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', - 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php', - 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', '06a34129a50df3d9257ee706cf3c875b' => __DIR__ . '/..' . '/illuminate/filesystem/functions.php', '662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php', - '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', - 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php', - 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php', + 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php', '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php', 'b46ad4fe52f4d1899a2951c7e6ea56b0' => __DIR__ . '/..' . '/voku/portable-utf8/bootstrap.php', + 'a2317519146f89bafaee186bdfa8e099' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/helpers.php', 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', '3919eeb97e98d4648304477f8ef734ba' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', '2324d0e5cadd603331d27de142371f0b' => __DIR__ . '/..' . '/symfony/contracts/Deprecation/function.php', @@ -74,6 +75,7 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Symfony\\Polyfill\\Iconv\\' => 23, 'Symfony\\Polyfill\\Ctype\\' => 23, 'Symfony\\Contracts\\' => 18, + 'Symfony\\Component\\VarExporter\\' => 30, 'Symfony\\Component\\Translation\\' => 30, 'Symfony\\Component\\String\\' => 25, 'Symfony\\Component\\Process\\' => 26, @@ -82,7 +84,10 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Symfony\\Component\\HttpFoundation\\' => 33, 'Symfony\\Component\\Finder\\' => 25, 'Symfony\\Component\\Filesystem\\' => 29, + 'Symfony\\Component\\DomCrawler\\' => 29, + 'Symfony\\Component\\CssSelector\\' => 30, 'Symfony\\Component\\Console\\' => 26, + 'Symfony\\Component\\Cache\\' => 24, 'Seld\\Signal\\' => 12, 'Seld\\PharUtils\\' => 15, 'Seld\\JsonLint\\' => 14, @@ -109,6 +114,10 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 array ( 'OTPHP\\' => 6, ), + 'M' => + array ( + 'Masterminds\\' => 12, + ), 'L' => array ( 'League\\OAuth2\\Client\\' => 21, @@ -151,6 +160,7 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'D' => array ( 'Duo\\DuoUniversal\\' => 17, + 'Dominikb\\ComposerLicenseChecker\\' => 32, 'Doctrine\\Inflector\\' => 19, 'Doctrine\\Common\\Lexer\\' => 22, 'Defuse\\Crypto\\' => 14, @@ -289,6 +299,10 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 array ( 0 => __DIR__ . '/..' . '/symfony/contracts', ), + 'Symfony\\Component\\VarExporter\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-exporter', + ), 'Symfony\\Component\\Translation\\' => array ( 0 => __DIR__ . '/..' . '/symfony/translation', @@ -321,10 +335,22 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 array ( 0 => __DIR__ . '/..' . '/symfony/filesystem', ), + 'Symfony\\Component\\DomCrawler\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/dom-crawler', + ), + 'Symfony\\Component\\CssSelector\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/css-selector', + ), 'Symfony\\Component\\Console\\' => array ( 0 => __DIR__ . '/..' . '/symfony/console', ), + 'Symfony\\Component\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/cache', + ), 'Seld\\Signal\\' => array ( 0 => __DIR__ . '/..' . '/seld/signal-handler/src', @@ -390,6 +416,10 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 array ( 0 => __DIR__ . '/..' . '/spomky-labs/otphp/src', ), + 'Masterminds\\' => + array ( + 0 => __DIR__ . '/..' . '/masterminds/html5/src', + ), 'League\\OAuth2\\Client\\' => array ( 0 => __DIR__ . '/..' . '/league/oauth2-client/src', @@ -469,6 +499,10 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 array ( 0 => __DIR__ . '/..' . '/duosecurity/duo_universal_php/src', ), + 'Dominikb\\ComposerLicenseChecker\\' => + array ( + 0 => __DIR__ . '/..' . '/dominikb/composer-license-checker/src', + ), 'Doctrine\\Inflector\\' => array ( 0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector', @@ -1100,6 +1134,31 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Doctrine\\Inflector\\Rules\\Word' => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php', 'Doctrine\\Inflector\\RulesetInflector' => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php', 'Doctrine\\Inflector\\WordInflector' => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php', + 'Dominikb\\ComposerLicenseChecker\\CheckCommand' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/CheckCommand.php', + 'Dominikb\\ComposerLicenseChecker\\ConstraintViolation' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/ConstraintViolation.php', + 'Dominikb\\ComposerLicenseChecker\\ConstraintViolationDetector' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/ConstraintViolationDetector.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\CacheAwareContract' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyLoader' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/DependencyLoader.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyLoaderAware' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/DependencyLoaderAware.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\DependencyParser' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/DependencyParser.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseConstraintAware' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/LicenseConstraintAware.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseConstraintHandler' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/LicenseConstraintHandler.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseLookup' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/LicenseLookup.php', + 'Dominikb\\ComposerLicenseChecker\\Contracts\\LicenseLookupAware' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Contracts/LicenseLookupAware.php', + 'Dominikb\\ComposerLicenseChecker\\Dependency' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Dependency.php', + 'Dominikb\\ComposerLicenseChecker\\DependencyLoader' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/DependencyLoader.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\CommandExecutionException' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\ComposerLicenseCheckerException' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Exceptions/ComposerLicenseCheckerException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\LogicException' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Exceptions/LogicException.php', + 'Dominikb\\ComposerLicenseChecker\\Exceptions\\NoLookupPossibleException' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Exceptions/NoLookupPossibleException.php', + 'Dominikb\\ComposerLicenseChecker\\JSONDependencyParser' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/JSONDependencyParser.php', + 'Dominikb\\ComposerLicenseChecker\\License' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/License.php', + 'Dominikb\\ComposerLicenseChecker\\LicenseLookup' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/LicenseLookup.php', + 'Dominikb\\ComposerLicenseChecker\\NoLookupLicenses' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/NoLookupLicenses.php', + 'Dominikb\\ComposerLicenseChecker\\ReportCommand' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/ReportCommand.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\DependencyLoaderAwareTrait' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\LicenseConstraintAwareTrait' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php', + 'Dominikb\\ComposerLicenseChecker\\Traits\\LicenseLookupAwareTrait' => __DIR__ . '/..' . '/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php', 'Duo\\DuoUniversal\\Client' => __DIR__ . '/..' . '/duosecurity/duo_universal_php/src/Client.php', 'Duo\\DuoUniversal\\DuoException' => __DIR__ . '/..' . '/duosecurity/duo_universal_php/src/DuoException.php', 'EZimuel\\PHPSecureSession\\SecureHandler' => __DIR__ . '/..' . '/ezimuel/php-secure-session/src/SecureHandler.php', @@ -1913,6 +1972,26 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'League\\OAuth2\\Client\\Tool\\RequestFactory' => __DIR__ . '/..' . '/league/oauth2-client/src/Tool/RequestFactory.php', 'League\\OAuth2\\Client\\Tool\\RequiredParameterTrait' => __DIR__ . '/..' . '/league/oauth2-client/src/Tool/RequiredParameterTrait.php', 'LoggerInterface' => __DIR__ . '/..' . '/owasp/csrf-protector-php/libs/csrf/LoggerInterface.php', + 'Masterminds\\HTML5' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5.php', + 'Masterminds\\HTML5\\Elements' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Elements.php', + 'Masterminds\\HTML5\\Entities' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Entities.php', + 'Masterminds\\HTML5\\Exception' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Exception.php', + 'Masterminds\\HTML5\\InstructionProcessor' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/InstructionProcessor.php', + 'Masterminds\\HTML5\\Parser\\CharacterReference' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/CharacterReference.php', + 'Masterminds\\HTML5\\Parser\\DOMTreeBuilder' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/DOMTreeBuilder.php', + 'Masterminds\\HTML5\\Parser\\EventHandler' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/EventHandler.php', + 'Masterminds\\HTML5\\Parser\\FileInputStream' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/FileInputStream.php', + 'Masterminds\\HTML5\\Parser\\InputStream' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/InputStream.php', + 'Masterminds\\HTML5\\Parser\\ParseError' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/ParseError.php', + 'Masterminds\\HTML5\\Parser\\Scanner' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/Scanner.php', + 'Masterminds\\HTML5\\Parser\\StringInputStream' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/StringInputStream.php', + 'Masterminds\\HTML5\\Parser\\Tokenizer' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/Tokenizer.php', + 'Masterminds\\HTML5\\Parser\\TreeBuildingRules' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php', + 'Masterminds\\HTML5\\Parser\\UTF8Utils' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Parser/UTF8Utils.php', + 'Masterminds\\HTML5\\Serializer\\HTML5Entities' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php', + 'Masterminds\\HTML5\\Serializer\\OutputRules' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/OutputRules.php', + 'Masterminds\\HTML5\\Serializer\\RulesInterface' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/RulesInterface.php', + 'Masterminds\\HTML5\\Serializer\\Traverser' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Serializer/Traverser.php', 'Math_BigInteger' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php', 'MeekroDB' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', 'MeekroDBEval' => __DIR__ . '/..' . '/sergeytsalkov/meekrodb/db.class.php', @@ -2080,6 +2159,69 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Seld\\PharUtils\\Timestamps' => __DIR__ . '/..' . '/seld/phar-utils/src/Timestamps.php', 'Seld\\Signal\\SignalHandler' => __DIR__ . '/..' . '/seld/signal-handler/src/SignalHandler.php', 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'Symfony\\Component\\Cache\\Adapter\\AbstractAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\AbstractTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/AbstractTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\AdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/AdapterInterface.php', + 'Symfony\\Component\\Cache\\Adapter\\ApcuAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ApcuAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ArrayAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ChainAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ChainAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\CouchbaseBucketAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/CouchbaseBucketAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\CouchbaseCollectionAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/CouchbaseCollectionAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\DoctrineDbalAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/DoctrineDbalAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\FilesystemTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/FilesystemTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\MemcachedAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/MemcachedAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\NullAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/NullAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ParameterNormalizer' => __DIR__ . '/..' . '/symfony/cache/Adapter/ParameterNormalizer.php', + 'Symfony\\Component\\Cache\\Adapter\\PdoAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PdoAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\PhpArrayAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpArrayAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\PhpFilesAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/PhpFilesAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\ProxyAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/ProxyAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\Psr16Adapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/Psr16Adapter.php', + 'Symfony\\Component\\Cache\\Adapter\\RedisAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\RedisTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/RedisTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface' => __DIR__ . '/..' . '/symfony/cache/Adapter/TagAwareAdapterInterface.php', + 'Symfony\\Component\\Cache\\Adapter\\TraceableAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableAdapter.php', + 'Symfony\\Component\\Cache\\Adapter\\TraceableTagAwareAdapter' => __DIR__ . '/..' . '/symfony/cache/Adapter/TraceableTagAwareAdapter.php', + 'Symfony\\Component\\Cache\\CacheItem' => __DIR__ . '/..' . '/symfony/cache/CacheItem.php', + 'Symfony\\Component\\Cache\\DataCollector\\CacheDataCollector' => __DIR__ . '/..' . '/symfony/cache/DataCollector/CacheDataCollector.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CacheCollectorPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CacheCollectorPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolClearerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolClearerPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPass.php', + 'Symfony\\Component\\Cache\\DependencyInjection\\CachePoolPrunerPass' => __DIR__ . '/..' . '/symfony/cache/DependencyInjection/CachePoolPrunerPass.php', + 'Symfony\\Component\\Cache\\Exception\\CacheException' => __DIR__ . '/..' . '/symfony/cache/Exception/CacheException.php', + 'Symfony\\Component\\Cache\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/cache/Exception/InvalidArgumentException.php', + 'Symfony\\Component\\Cache\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/cache/Exception/LogicException.php', + 'Symfony\\Component\\Cache\\LockRegistry' => __DIR__ . '/..' . '/symfony/cache/LockRegistry.php', + 'Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DefaultMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\DeflateMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/DeflateMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\MarshallerInterface' => __DIR__ . '/..' . '/symfony/cache/Marshaller/MarshallerInterface.php', + 'Symfony\\Component\\Cache\\Marshaller\\SodiumMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/SodiumMarshaller.php', + 'Symfony\\Component\\Cache\\Marshaller\\TagAwareMarshaller' => __DIR__ . '/..' . '/symfony/cache/Marshaller/TagAwareMarshaller.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationDispatcher' => __DIR__ . '/..' . '/symfony/cache/Messenger/EarlyExpirationDispatcher.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationHandler' => __DIR__ . '/..' . '/symfony/cache/Messenger/EarlyExpirationHandler.php', + 'Symfony\\Component\\Cache\\Messenger\\EarlyExpirationMessage' => __DIR__ . '/..' . '/symfony/cache/Messenger/EarlyExpirationMessage.php', + 'Symfony\\Component\\Cache\\PruneableInterface' => __DIR__ . '/..' . '/symfony/cache/PruneableInterface.php', + 'Symfony\\Component\\Cache\\Psr16Cache' => __DIR__ . '/..' . '/symfony/cache/Psr16Cache.php', + 'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php', + 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractAdapterTrait.php', + 'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ContractsTrait.php', + 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php', + 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php', + 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterNodeProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RelayProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxy.php', + 'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxyTrait.php', 'Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php', 'Symfony\\Component\\Console\\Attribute\\AsCommand' => __DIR__ . '/..' . '/symfony/console/Attribute/AsCommand.php', 'Symfony\\Component\\Console\\CI\\GithubActionReporter' => __DIR__ . '/..' . '/symfony/console/CI/GithubActionReporter.php', @@ -2198,6 +2340,73 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php', 'Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => __DIR__ . '/..' . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', 'Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php', + 'Symfony\\Component\\CssSelector\\CssSelectorConverter' => __DIR__ . '/..' . '/symfony/css-selector/CssSelectorConverter.php', + 'Symfony\\Component\\CssSelector\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ExceptionInterface.php', + 'Symfony\\Component\\CssSelector\\Exception\\ExpressionErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ExpressionErrorException.php', + 'Symfony\\Component\\CssSelector\\Exception\\InternalErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/InternalErrorException.php', + 'Symfony\\Component\\CssSelector\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/ParseException.php', + 'Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException' => __DIR__ . '/..' . '/symfony/css-selector/Exception/SyntaxErrorException.php', + 'Symfony\\Component\\CssSelector\\Node\\AbstractNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/AbstractNode.php', + 'Symfony\\Component\\CssSelector\\Node\\AttributeNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/AttributeNode.php', + 'Symfony\\Component\\CssSelector\\Node\\ClassNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/ClassNode.php', + 'Symfony\\Component\\CssSelector\\Node\\CombinedSelectorNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/CombinedSelectorNode.php', + 'Symfony\\Component\\CssSelector\\Node\\ElementNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/ElementNode.php', + 'Symfony\\Component\\CssSelector\\Node\\FunctionNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/FunctionNode.php', + 'Symfony\\Component\\CssSelector\\Node\\HashNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/HashNode.php', + 'Symfony\\Component\\CssSelector\\Node\\NegationNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/NegationNode.php', + 'Symfony\\Component\\CssSelector\\Node\\NodeInterface' => __DIR__ . '/..' . '/symfony/css-selector/Node/NodeInterface.php', + 'Symfony\\Component\\CssSelector\\Node\\PseudoNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/PseudoNode.php', + 'Symfony\\Component\\CssSelector\\Node\\SelectorNode' => __DIR__ . '/..' . '/symfony/css-selector/Node/SelectorNode.php', + 'Symfony\\Component\\CssSelector\\Node\\Specificity' => __DIR__ . '/..' . '/symfony/css-selector/Node/Specificity.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\CommentHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/CommentHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\HandlerInterface' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/HandlerInterface.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\HashHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/HashHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\IdentifierHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/IdentifierHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\NumberHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/NumberHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\StringHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/StringHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Handler\\WhitespaceHandler' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Handler/WhitespaceHandler.php', + 'Symfony\\Component\\CssSelector\\Parser\\Parser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Parser.php', + 'Symfony\\Component\\CssSelector\\Parser\\ParserInterface' => __DIR__ . '/..' . '/symfony/css-selector/Parser/ParserInterface.php', + 'Symfony\\Component\\CssSelector\\Parser\\Reader' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Reader.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ClassParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/ClassParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\ElementParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/ElementParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\EmptyStringParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Shortcut\\HashParser' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Shortcut/HashParser.php', + 'Symfony\\Component\\CssSelector\\Parser\\Token' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Token.php', + 'Symfony\\Component\\CssSelector\\Parser\\TokenStream' => __DIR__ . '/..' . '/symfony/css-selector/Parser/TokenStream.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\Tokenizer' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/Tokenizer.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerEscaping' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php', + 'Symfony\\Component\\CssSelector\\Parser\\Tokenizer\\TokenizerPatterns' => __DIR__ . '/..' . '/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\AbstractExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/AbstractExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\AttributeMatchingExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\CombinationExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/CombinationExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\ExtensionInterface' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/ExtensionInterface.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\FunctionExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/FunctionExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\HtmlExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/HtmlExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\NodeExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/NodeExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Extension\\PseudoClassExtension' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Extension/PseudoClassExtension.php', + 'Symfony\\Component\\CssSelector\\XPath\\Translator' => __DIR__ . '/..' . '/symfony/css-selector/XPath/Translator.php', + 'Symfony\\Component\\CssSelector\\XPath\\TranslatorInterface' => __DIR__ . '/..' . '/symfony/css-selector/XPath/TranslatorInterface.php', + 'Symfony\\Component\\CssSelector\\XPath\\XPathExpr' => __DIR__ . '/..' . '/symfony/css-selector/XPath/XPathExpr.php', + 'Symfony\\Component\\DomCrawler\\AbstractUriElement' => __DIR__ . '/..' . '/symfony/dom-crawler/AbstractUriElement.php', + 'Symfony\\Component\\DomCrawler\\Crawler' => __DIR__ . '/..' . '/symfony/dom-crawler/Crawler.php', + 'Symfony\\Component\\DomCrawler\\Field\\ChoiceFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/ChoiceFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\FileFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/FileFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\FormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/FormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\InputFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/InputFormField.php', + 'Symfony\\Component\\DomCrawler\\Field\\TextareaFormField' => __DIR__ . '/..' . '/symfony/dom-crawler/Field/TextareaFormField.php', + 'Symfony\\Component\\DomCrawler\\Form' => __DIR__ . '/..' . '/symfony/dom-crawler/Form.php', + 'Symfony\\Component\\DomCrawler\\FormFieldRegistry' => __DIR__ . '/..' . '/symfony/dom-crawler/FormFieldRegistry.php', + 'Symfony\\Component\\DomCrawler\\Image' => __DIR__ . '/..' . '/symfony/dom-crawler/Image.php', + 'Symfony\\Component\\DomCrawler\\Link' => __DIR__ . '/..' . '/symfony/dom-crawler/Link.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerAnySelectorTextContains' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerAnySelectorTextSame' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorAttributeValueSame' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorCount' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorExists' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextContains' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php', + 'Symfony\\Component\\DomCrawler\\Test\\Constraint\\CrawlerSelectorTextSame' => __DIR__ . '/..' . '/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php', + 'Symfony\\Component\\DomCrawler\\UriResolver' => __DIR__ . '/..' . '/symfony/dom-crawler/UriResolver.php', 'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php', 'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php', 'Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php', @@ -2556,6 +2765,25 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'Symfony\\Component\\Translation\\Util\\XliffUtils' => __DIR__ . '/..' . '/symfony/translation/Util/XliffUtils.php', 'Symfony\\Component\\Translation\\Writer\\TranslationWriter' => __DIR__ . '/..' . '/symfony/translation/Writer/TranslationWriter.php', 'Symfony\\Component\\Translation\\Writer\\TranslationWriterInterface' => __DIR__ . '/..' . '/symfony/translation/Writer/TranslationWriterInterface.php', + 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ClassNotFoundException.php', + 'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ExceptionInterface.php', + 'Symfony\\Component\\VarExporter\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/LogicException.php', + 'Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php', + 'Symfony\\Component\\VarExporter\\Hydrator' => __DIR__ . '/..' . '/symfony/var-exporter/Hydrator.php', + 'Symfony\\Component\\VarExporter\\Instantiator' => __DIR__ . '/..' . '/symfony/var-exporter/Instantiator.php', + 'Symfony\\Component\\VarExporter\\Internal\\Exporter' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Exporter.php', + 'Symfony\\Component\\VarExporter\\Internal\\Hydrator' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Hydrator.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectRegistry' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/LazyObjectRegistry.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectState' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/LazyObjectState.php', + 'Symfony\\Component\\VarExporter\\Internal\\LazyObjectTrait' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/LazyObjectTrait.php', + 'Symfony\\Component\\VarExporter\\Internal\\Reference' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Reference.php', + 'Symfony\\Component\\VarExporter\\Internal\\Registry' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Registry.php', + 'Symfony\\Component\\VarExporter\\Internal\\Values' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Values.php', + 'Symfony\\Component\\VarExporter\\LazyGhostTrait' => __DIR__ . '/..' . '/symfony/var-exporter/LazyGhostTrait.php', + 'Symfony\\Component\\VarExporter\\LazyObjectInterface' => __DIR__ . '/..' . '/symfony/var-exporter/LazyObjectInterface.php', + 'Symfony\\Component\\VarExporter\\LazyProxyTrait' => __DIR__ . '/..' . '/symfony/var-exporter/LazyProxyTrait.php', + 'Symfony\\Component\\VarExporter\\ProxyHelper' => __DIR__ . '/..' . '/symfony/var-exporter/ProxyHelper.php', + 'Symfony\\Component\\VarExporter\\VarExporter' => __DIR__ . '/..' . '/symfony/var-exporter/VarExporter.php', 'Symfony\\Contracts\\Cache\\CacheInterface' => __DIR__ . '/..' . '/symfony/contracts/Cache/CacheInterface.php', 'Symfony\\Contracts\\Cache\\CacheTrait' => __DIR__ . '/..' . '/symfony/contracts/Cache/CacheTrait.php', 'Symfony\\Contracts\\Cache\\CallbackInterface' => __DIR__ . '/..' . '/symfony/contracts/Cache/CallbackInterface.php', @@ -2681,6 +2909,7 @@ class ComposerStaticInite3f3ee27f81ca21f7bd7499d7b935c11 'voku\\helper\\AntiXSS' => __DIR__ . '/..' . '/voku/anti-xss/src/voku/helper/AntiXSS.php', 'voku\\helper\\Bootup' => __DIR__ . '/..' . '/voku/portable-utf8/src/voku/helper/Bootup.php', 'voku\\helper\\UTF8' => __DIR__ . '/..' . '/voku/portable-utf8/src/voku/helper/UTF8.php', + '' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/ca-bundle/composer.json b/vendor/composer/ca-bundle/composer.json index c2ed5ac51..c2ce2bb8e 100644 --- a/vendor/composer/ca-bundle/composer.json +++ b/vendor/composer/ca-bundle/composer.json @@ -27,7 +27,7 @@ "php": "^7.2 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.2 || ^5", + "phpunit/phpunit": "^8 || ^9", "phpstan/phpstan": "^1.10", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" @@ -48,7 +48,7 @@ } }, "scripts": { - "test": "vendor/bin/simple-phpunit", - "phpstan": "vendor/bin/phpstan analyse" + "test": "@php phpunit", + "phpstan": "@php phpstan analyse" } } diff --git a/vendor/composer/ca-bundle/res/cacert.pem b/vendor/composer/ca-bundle/res/cacert.pem index 86d6cd80c..f2c24a589 100644 --- a/vendor/composer/ca-bundle/res/cacert.pem +++ b/vendor/composer/ca-bundle/res/cacert.pem @@ -1,7 +1,9 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue Jul 2 03:12:04 2024 GMT +## Certificate data from Mozilla as of: Tue Sep 24 03:12:04 2024 GMT +## +## Find updated versions here: https://curl.se/docs/caextract.html ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +16,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 456ff095dde6dd73354c5c28c73d9c06f53b61a803963414cb91a1d92945cdd3 +## SHA256: 36105b01631f9fc03b1eca779b44a30a1a5890b9bf8dc07ccb001a07301e01cf ## @@ -3566,3 +3568,99 @@ Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ pYXFuXqUPoeovQA= -----END CERTIFICATE----- + +TWCA CYBER Root CA +================== +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG +EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB +IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s +Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh +V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT +o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT +Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK +/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH +IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM +fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF +2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR +wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83 +QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN +c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x +X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR +IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq +/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R +FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe +Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv +It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl +IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE----- + +SecureSign Root CA12 +==================== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3 +emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc +J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl +fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF +EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef +NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC +AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi +LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce +mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS +vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga +aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA== +-----END CERTIFICATE----- + +SecureSign Root CA14 +==================== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG +A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT +ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ +BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU +U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh +1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn +bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb +1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa +/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE +kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx +jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz +ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0 +dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY +AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq +YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA +ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds +Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG +FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q +nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/ +OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa +OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO +pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN +eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S +-----END CERTIFICATE----- + +SecureSign Root CA15 +==================== +-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE +BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1 +cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV +BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj +dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G +dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB +2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J +fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ +SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE----- diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index ce5ca782e..452d1f942 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -195,17 +195,17 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.1", - "version_normalized": "1.5.1.0", + "version": "1.5.2", + "version_normalized": "1.5.2.0", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a" + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/063d9aa8696582f5a41dffbbaf3c81024f0a604a", - "reference": "063d9aa8696582f5a41dffbbaf3c81024f0a604a", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/48a792895a2b7a6ee65dd5442c299d7b835b6137", + "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137", "shasum": "" }, "require": { @@ -215,11 +215,11 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, - "time": "2024-07-08T15:28:20+00:00", + "time": "2024-09-25T07:49:53+00:00", "type": "library", "extra": { "branch-alias": { @@ -254,7 +254,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.1" + "source": "https://github.com/composer/ca-bundle/tree/1.5.2" }, "funding": [ { @@ -927,17 +927,17 @@ }, { "name": "directorytree/ldaprecord", - "version": "v3.7.0", - "version_normalized": "3.7.0.0", + "version": "v3.7.1", + "version_normalized": "3.7.1.0", "source": { "type": "git", "url": "https://github.com/DirectoryTree/LdapRecord.git", - "reference": "4113aa08f72bbc76630fad3b05d57cd431fb0839" + "reference": "9b5f53d820a490fdb0c7a098c93f3b83b74455dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/4113aa08f72bbc76630fad3b05d57cd431fb0839", - "reference": "4113aa08f72bbc76630fad3b05d57cd431fb0839", + "url": "https://api.github.com/repos/DirectoryTree/LdapRecord/zipball/9b5f53d820a490fdb0c7a098c93f3b83b74455dd", + "reference": "9b5f53d820a490fdb0c7a098c93f3b83b74455dd", "shasum": "" }, "require": { @@ -958,7 +958,7 @@ "phpunit/phpunit": "^9.0", "spatie/ray": "^1.24" }, - "time": "2024-07-26T21:20:12+00:00", + "time": "2024-09-23T03:45:43+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1232,6 +1232,74 @@ ], "install-path": "../doctrine/lexer" }, + { + "name": "dominikb/composer-license-checker", + "version": "2.6.0", + "version_normalized": "2.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/dominikb/composer-license-checker.git", + "reference": "22c2bb46acc5ab71d828ab9589be5a2820f8b221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dominikb/composer-license-checker/zipball/22c2bb46acc5ab71d828ab9589be5a2820f8b221", + "reference": "22c2bb46acc5ab71d828ab9589be5a2820f8b221", + "shasum": "" + }, + "require": { + "composer/composer": "~2.2.23 || ^2.7.0", + "ext-json": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "php": "^7.3 || ^8.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "~4.2.12 || ^4.3.8 || ^5.2 || ^6.0 || ^7.0", + "symfony/console": "^5.3 || ^6.0 || ^7.0", + "symfony/css-selector": "^4.2 || ^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "phpunit/phpunit": "^9.3", + "symfony/var-dumper": "^4.2 || ^5.2 || ^6.0 || ^7.0" + }, + "time": "2024-07-06T14:35:50+00:00", + "bin": [ + "composer-license-checker" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Dominikb\\ComposerLicenseChecker\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dominik Bauernfeind", + "email": "bauernfeind.dominik@gmail.com", + "role": "Developer" + } + ], + "description": "Utility to check for licenses of dependencies and block/allow them.", + "homepage": "https://github.com/dominikb/composer-license-checker", + "keywords": [ + "composer-license-checker", + "dominikb" + ], + "support": { + "issues": "https://github.com/dominikb/composer-license-checker/issues", + "source": "https://github.com/dominikb/composer-license-checker/tree/2.6.0" + }, + "install-path": "../dominikb/composer-license-checker" + }, { "name": "dragonmantank/cron-expression", "version": "v3.3.3", @@ -2694,6 +2762,76 @@ }, "install-path": "../league/oauth2-client" }, + { + "name": "masterminds/html5", + "version": "2.9.0", + "version_normalized": "2.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "time": "2024-03-31T07:05:07+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + }, + "install-path": "../masterminds/html5" + }, { "name": "moxiecode/plupload", "version": "v3.1.5", @@ -4390,6 +4528,105 @@ ], "install-path": "../spomky-labs/otphp" }, + { + "name": "symfony/cache", + "version": "v6.4.12", + "version_normalized": "6.4.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.3.6|^7.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/var-dumper": "<5.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "time": "2024-09-16T16:01:33+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v6.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/cache" + }, { "name": "symfony/console", "version": "v6.4.12", @@ -4585,6 +4822,144 @@ ], "install-path": "../symfony/contracts" }, + { + "name": "symfony/css-selector", + "version": "v6.4.8", + "version_normalized": "6.4.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "time": "2024-05-31T14:49:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v6.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/css-selector" + }, + { + "name": "symfony/dom-crawler", + "version": "v6.4.12", + "version_normalized": "6.4.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/9d307ecbcb917001692be333cdc58f474fdb37f0", + "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0" + }, + "time": "2024-09-15T06:35:36+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/dom-crawler" + }, { "name": "symfony/filesystem", "version": "v6.4.12", @@ -6101,6 +6476,86 @@ ], "install-path": "../symfony/translation" }, + { + "name": "symfony/var-exporter", + "version": "v6.4.9", + "version_normalized": "6.4.9.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f9a060622e0d93777b7f8687ec4860191e16802e", + "reference": "f9a060622e0d93777b7f8687ec4860191e16802e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "time": "2024-06-24T15:53:56+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v6.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/var-exporter" + }, { "name": "teampassclasses/configmanager", "version": "dev-master", @@ -7031,5 +7486,12 @@ } ], "dev": true, - "dev-package-names": [] + "dev-package-names": [ + "dominikb/composer-license-checker", + "masterminds/html5", + "symfony/cache", + "symfony/css-selector", + "symfony/dom-crawler", + "symfony/var-exporter" + ] } diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index df93e47cf..119990612 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -38,9 +38,9 @@ 'dev_requirement' => false, ), 'composer/ca-bundle' => array( - 'pretty_version' => '1.5.1', - 'version' => '1.5.1.0', - 'reference' => '063d9aa8696582f5a41dffbbaf3c81024f0a604a', + 'pretty_version' => '1.5.2', + 'version' => '1.5.2.0', + 'reference' => '48a792895a2b7a6ee65dd5442c299d7b835b6137', 'type' => 'library', 'install_path' => __DIR__ . '/./ca-bundle', 'aliases' => array(), @@ -119,9 +119,9 @@ 'dev_requirement' => false, ), 'directorytree/ldaprecord' => array( - 'pretty_version' => 'v3.7.0', - 'version' => '3.7.0.0', - 'reference' => '4113aa08f72bbc76630fad3b05d57cd431fb0839', + 'pretty_version' => 'v3.7.1', + 'version' => '3.7.1.0', + 'reference' => '9b5f53d820a490fdb0c7a098c93f3b83b74455dd', 'type' => 'library', 'install_path' => __DIR__ . '/../directorytree/ldaprecord', 'aliases' => array(), @@ -154,6 +154,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'dominikb/composer-license-checker' => array( + 'pretty_version' => '2.6.0', + 'version' => '2.6.0.0', + 'reference' => '22c2bb46acc5ab71d828ab9589be5a2820f8b221', + 'type' => 'library', + 'install_path' => __DIR__ . '/../dominikb/composer-license-checker', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'dragonmantank/cron-expression' => array( 'pretty_version' => 'v3.3.3', 'version' => '3.3.3.0', @@ -352,6 +361,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'masterminds/html5' => array( + 'pretty_version' => '2.9.0', + 'version' => '2.9.0.0', + 'reference' => 'f5ac2c0b0a2eefca70b2ce32a5809992227e75a6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../masterminds/html5', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'moxiecode/plupload' => array( 'pretty_version' => 'v3.1.5', 'version' => '3.1.5.0', @@ -466,6 +484,12 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/cache-implementation' => array( + 'dev_requirement' => true, + 'provided' => array( + 0 => '2.0|3.0', + ), + ), 'psr/clock' => array( 'pretty_version' => '1.0.0', 'version' => '1.0.0.0', @@ -574,6 +598,12 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/simple-cache-implementation' => array( + 'dev_requirement' => true, + 'provided' => array( + 0 => '1.0|2.0|3.0', + ), + ), 'ralouphie/getallheaders' => array( 'pretty_version' => '3.0.3', 'version' => '3.0.3.0', @@ -646,12 +676,27 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/cache' => array( + 'pretty_version' => 'v6.4.12', + 'version' => '6.4.12.0', + 'reference' => 'a463451b7f6ac4a47b98dbfc78ec2d3560c759d8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/cache', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'symfony/cache-contracts' => array( 'dev_requirement' => false, 'replaced' => array( 0 => 'v3.5.0', ), ), + 'symfony/cache-implementation' => array( + 'dev_requirement' => true, + 'provided' => array( + 0 => '1.1|2.0|3.0', + ), + ), 'symfony/console' => array( 'pretty_version' => 'v6.4.12', 'version' => '6.4.12.0', @@ -670,12 +715,30 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/css-selector' => array( + 'pretty_version' => 'v6.4.8', + 'version' => '6.4.8.0', + 'reference' => '4b61b02fe15db48e3687ce1c45ea385d1780fe08', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/css-selector', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'symfony/deprecation-contracts' => array( 'dev_requirement' => false, 'replaced' => array( 0 => 'v3.5.0', ), ), + 'symfony/dom-crawler' => array( + 'pretty_version' => 'v6.4.12', + 'version' => '6.4.12.0', + 'reference' => '9d307ecbcb917001692be333cdc58f474fdb37f0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/dom-crawler', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'symfony/event-dispatcher-contracts' => array( 'dev_requirement' => false, 'replaced' => array( @@ -877,6 +940,15 @@ 0 => '2.3|3.0', ), ), + 'symfony/var-exporter' => array( + 'pretty_version' => 'v6.4.9', + 'version' => '6.4.9.0', + 'reference' => 'f9a060622e0d93777b7f8687ec4860191e16802e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-exporter', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'teampassclasses/configmanager' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', diff --git a/vendor/directorytree/ldaprecord/src/Models/Concerns/HasAttributes.php b/vendor/directorytree/ldaprecord/src/Models/Concerns/HasAttributes.php index a34d7dd18..67b4cf703 100644 --- a/vendor/directorytree/ldaprecord/src/Models/Concerns/HasAttributes.php +++ b/vendor/directorytree/ldaprecord/src/Models/Concerns/HasAttributes.php @@ -10,6 +10,7 @@ use LdapRecord\Models\Attributes\Timestamp; use LdapRecord\Models\DetectsResetIntegers; use LdapRecord\Support\Arr; +use RuntimeException; trait HasAttributes { @@ -356,7 +357,9 @@ public function getDates(): array protected function getDateCasts(): array { return array_map(function (string $cast) { - return explode(':', $cast, 2)[1]; + return explode(':', $cast, 2)[1] ?? throw new RuntimeException( + "Invalid date cast [$cast]. A date cast must be in the format 'datetime:format'." + ); }, array_filter($this->getCasts(), function ($cast) { return $this->isDateTimeCast($cast); })); diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/+/Q/uKaF0vXuJ+AuwTzHzQcw b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/+/Q/uKaF0vXuJ+AuwTzHzQcw new file mode 100644 index 0000000000000000000000000000000000000000..3f03694cb2d2bc19aca6a1c6e2426e4fe97f45f2 GIT binary patch literal 1249 zcmaJ=VNcsI6y!6%!it0j(?ZjkFIS?hDa}u_qdYSfkI&z4yVvu>J3cz+$+c;umdn}W zm1$PSk-e2AX-8Kzl}oaZ+t-9o_#elIIZqBg9=O_A|4lTMTsWSOcyhdBV#cy9%Sre= zi5;cT$%WwK2y(^~ur*{$DHLNrT*R56@|s*}<%}HjH8C-hO8O1+hP963ku!6@7M9o? zH02It)!Hz3`o*>AhkYX7w=(LFQu4WE~Lg#KyOSX=aMRRT#=Pe!pkQ*VQXWT z9Sb18hLTO(a{A8j5eaKxrI-1Iu2^YFcw#&F-T3$IOm#*C^a8T~Uz#Ap#3f^2Ml%-AXZ2QMc*%EiuFoJR24kkn>mA zgPzl@HNhUC*^F3O3%h`fVbn@AV$r*V+`xMFU`0iZu*5o zJ8zA3ADBiC-6!UI7#GY_W?_Pw*tLkeHm%#+6bVE?N`=U>CrSt#YwuT%4+dUUR?$MJQ{0u_o`ES9d6tjU>^#kLtTiTWi}e6y9@xh491J22O0};#PecDQtyoEwp7Xg`vpDwx}!_Np6;n{`Vcpc3RVQ z5D1pf`Of(+a++uPD#_D4JK27@-o}era&ko%XEeIdjZorYcfZk1t1XzV;GisQYTyrG z?uW;SuIV33(~L&%KE1QGHtsuXAUe17ltv?_e_V$O&Qx^H=rS~|XoTnu7%rG3^Z3j>3d;qScg=>^&?{ohM7tW%LXkQQCP^vS12Q zyXkgAr57$oZ~r~eYk$z4_oea!=kUt`s>aCB?%#L=N4J72X-cE7S{7t0*iQCQL8j9Y zM+)8rQBF|iBf8!zK=+v4d7#;JHjrEel6ZEhxa%E4CkfrC8S}<4=tD?`TPjWC0-M9 zqdUWU3nl>`nR|BwO^k5gfhPt5eH-38#K%$uRPCC*HM*AWgSEA{@--m39SN~ z^{Wsl;9%`=^TpuTt`nG@_e2aZ{(ppdnd^Q>FH??;Yv)=^=W{0uBcWn)h98YFNb^c{ zF)K?jI<5dS#bn%uI}i_1iys#;t6CW^;v~4-fA9LwL-852b461O)df0qD;l_Ln$CrE z(}fQlQY-M4Z_QBXEXkH}au#Q&Bw17ZrP(aW&yw{rfTPzAL4IomKi#3lHbEEIiXx8Z Oz7EUoZZ~+9pZ)@52l9ge literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/A/L/lDsO0qHVWrvZ4ekiDAyw b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/A/L/lDsO0qHVWrvZ4ekiDAyw new file mode 100644 index 0000000000000000000000000000000000000000..d225a535eced2c7cf9cd0f2fce4a9641a472e181 GIT binary patch literal 340 zcmYk0!D_=W5JYp%SCl;#l2~$TJL^+%E``!u(p#V?@)Da^mXYK`8~pEGxq%b}VrOUG zj>u*HlH?*QmdgXCJA}P8ZQowcr^=eadUEfrrruN4kiL>T-ABL-Zytq2SUfL$V_o=A zhM@GAAjB`5H(K>jD%Nh3N5-?6rQU{zn$M~k{Xgx`>FwzB%#;G531RTK*@Uik9bHtn z*4D&J_Y&HX3RJ%`=755!dmfLip*Lg3pw1lurm^%Eq2^VLN^U6=xm_i@l`Ni;4C5=- kLKb-D6MkEI&!}NuC~FtYlH+C_73IZ^iUXB$u{PMm;Sa=eAi{kM3F(Xgtnq zES}Ik_CFIb6Mwy!WFk5EeBf*A!i{V&Ij6N$Bs*DNnZ-?oG|9OXc|3O_5-QN3E0oj# zKYTnoqn(%N3#S(7A=C(Rp|lDc2o_q8amm{%tffP!tb<}FvT7YS?2r1A-)*U?P5g2C zj%*XR?JG-DLg7#bgc6;4mO(xD!tCx+`9LkUAvT@A*L1nv3f8HmGUS%pjztxg@NuXA z3D(v(`rqNS52jPZ9sG9aNp&i^pW0bB$$ITp#CmIcC3 z>G)Vjistfm71CJ6?SwvV2W$3JhiYXfKOy-@4u|2s%ZY|N?k6#{36(?C8(6DQ+cv-! zr7}xUp(~S%gt7y7G%6EduBB>x#P!Mu(XRuAihMX(1R@Ko?o<&^fvqS_rW>qvaVJwN zY>8Cs#S6L}ly!=+v4NAE#Uzu_Z&sIZt>i+-K%5fVeTZ9T94uAsaT^a)vTK7BXlYLSS+ODM`kL0TLOzeMeAHdLM^LYsNhLDV9_g?qbN7*PH^-J`Xd+J~0?)54! zXneO~LX*2B3=gWotEOo~OsbgjRLNLLfAP_b>||+nJW9_-*(szmL7z!_G|TdAI*H;0 fG?2(2Yw%attmv2$Q#wis7}j|ohxB1i7GM4W&%!9j literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/C/8/N4GTBNtOwJqF+Lxdqwkw b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/C/8/N4GTBNtOwJqF+Lxdqwkw new file mode 100644 index 0000000000000000000000000000000000000000..e437764975ca4156ae737d726496edfa7eb035d5 GIT binary patch literal 1534 zcmaJ>TWi}e6z+3>g)kJ_K@!`|t?JWA$5u#}LRcdfqP7$yxmh;)-}fCkP8R42 zA>iYqbH1CLOw!3Ho+Oj_^emlzy`T5eetee3#^P`B!Un$CH#tC!bDSX{`S)Y8hRlHs;a!ZUr-zVf+QvQATSf zbaXBFFq|Io2y1F-GbJj^am@g$0OI0bqW!|vH$xw1;uzuoW0rCr5E~yrPd);j z?^_{=DwGCWzz$25%-Q*2{sr3@`_jTshCI5jL?+n}VXe@<vaA%gfS3d-7quvYSD-lw zH0#C%lA}NpZr$pvYI4aIJ4c9Wk^h9>jMXk^wf zv-Cpg?j$WIjE5lPY@>X6M5`5t+*K~C5MuUV8k@BO9mT7|McRkanA@H}#X@a5hTUL? zRvkP#tbS)HB)p5ui=m-y#7?D~Y6FD|j$ab@lj(Fa jjKgp!>M`WE(ekI?u5nE9OB{t)U7h;S_VhTzMSuGXC)5N@ literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/H/4/x1j2IN4fQFg0xayUIapw b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/H/4/x1j2IN4fQFg0xayUIapw new file mode 100644 index 0000000000000000000000000000000000000000..eeb3cadd306ebec7db2a24e0f3141557ef19e6ec GIT binary patch literal 1748 zcmaJ>U2oGm80MN^VdVnBk+L>P*N$+7IteBXHVM$VK{|31H?ii}k?pJ$#DC{`?WA1< z2dPq3_x*Uj>}->7E|;5ZQ#^lnf14H;%hYIfe12CJugm1xbW+QQ-Pf(@dgFw>m6gy= zY+F%12>W&XnUw4DhbyzZOrHJo%(ce)kGvDfn|StgFrBSKS;ckohL@M2^Ri5^q7$}~ zTru{=h2}LXuZ63u+zH2gD;VENCH;|k!v-h9ku!UL;8w7`v8*}|=?6=Y-Nm@_gQ?~I z7=B#+Wo#G9=99UuS!D(Hg4M#xNABh0I5=BkmUJEv2OmIh{sy`}l`>;xBQ@9pc33J! z&0e18zhVbtA0qs0RVMd}SAzY^t>xNB9#HLn<>^B?gbC%$=s6`7jjV$@*``b&IlBi# z?b%jw**Q{b^VKl# z6;z$CILSqh%l&N1Vw!FaS|Dj$vmJP~+%_G|1{X-i`+;QK=t>Q> zV0WYYL^aES?F{753ZSPf_Y$#(phV^rmx&eSMrtH)fDJ|mrOnQBsi#g_P8iRjtJy*N zc1A0TQ$T)C`QEl%g9E`@!F)QDx?xT>TJ9xCd!kGwtmEJTsV6{j5+z2uO5y6UPiC-H zlzMh4CWho<011S#11A;(sVzi?p;QOA&m{f;A4?};Z)32Dz~xDAqCg_<2c?)tUP#r+ zPY8Cpe{(MIa2mTc{V`-e44yq86PuY!FfZ0ef^fkK@-`UWO);G*xzOxm*k zEuLCb!nyJNlVg&0gG8!dge=gQriH55SJe^a-7mXfL zg;m0)jX>JDO8am-(^0hau}D?ZtF)kjx7jLRUCdY6DtmhK?&D3GpJl05a(H@IoWClPE8PkucAL*@-FDh?b0bQw zEMGUg+;Q{y@G&Wt#dlj|d67JM@x(UTxLelp&cJv5k!hhM8^TU2GgVP(ICGpTZp0&V;_*;8o1>Pn4iI}6K(GDo22Hks#YQvP9@vn|!07i#&|BdHzBn|}q zum$9Xco0Qt=XE&`x@1N2UdxJZ1l!0k-sR%=#vtGK8OYNlwkNe`V^6(T9P%(l8%|}z zOpR$h)QYvN9?66a?j6`InUn*Xs-2%T%e@yTAM6_r_$Ks`Vq=&Yro!;4kf|_BN;x z7YmNMR;BDKPIm{_L|!1zpS+a16Id4=m6&Wc%I*Co6dc=^PH2U_(xf+z2?b_Crf=?L zI-0ejy>QKmvXKv<9g(edHvn7%+_tzlS+QRgoA97njHj`m;T{FAVrh6`EIr;CUwGmI zq69$OUP^K>xu1Bn8-|&7Y8-qji+wF6P6OTR-jvbRCrdlx^=lNsfr*%b7lXy|Xr@(PA_^=CGnxVhh_V*fWMu%TONLoWjTUjjY^iEJ{Fs zBn20elH0q7>-F1&w%+AIIOgJkg5HGvhC4*`ljnL`{y3M%wt}vWbDb?_Gbbw}dClY* z7H8b&S*`k1a*N-DwB}fCCetn)sPrH~`k1F#D(gbM~#?U{00_-kcV*mgE literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/T/I/tkH8Ws6TWfeWNL-dARxg b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/T/I/tkH8Ws6TWfeWNL-dARxg new file mode 100644 index 0000000000000000000000000000000000000000..aa9b076b124f423041463df4cea0923ce0b46454 GIT binary patch literal 1275 zcmaJ>O>f&U4DGqULhxlDSen>rKB}I!`hzLx9*AF7-@SKpSs+(rRmtG9cIY&%hV7JJJ%9Ll@~S+;a3D)K(Ku|oe-BjafzV(oM+#RkidQj zPh}lbsLRV;5Mz_lk@}R*oIOJAyD5Z!3>?jb)4w9Bw(&TTEA$%JJkFj)&wYXzVxA z_Q`zD3~^8_xYo-=8BJQpxCwkXj7E6_l`v;`;d*w4Wl;El$n<~=_6-Ie9&`YeChgvb z?k1^^xc?2$k(ec3tUKMnRnxRFDa6NQ57bEE5tSCWO))CY2cwHYF=wMGr*D2XnO@|@ iIDw;=B7*#O7JkOv2Fo-bV=0c^$0?62ceg-KKK=z_7OK+# literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/Y/3/kBejHh0OnATVtV7ViTgQ b/vendor/dominikb/composer-license-checker/.cache/FilesystemCache/Y/3/kBejHh0OnATVtV7ViTgQ new file mode 100644 index 0000000000000000000000000000000000000000..739539ad38daf34aafc1e38ba52d35019315e0fa GIT binary patch literal 1325 zcmaJ>%Wm5+5X?DWvCyRtRDMW~l`yBm2HF5_Qy}RrKtW3@i7-V9Bo)^!^6y$ z0Uh+<%G|f88~d%|_&? zEUs$IcW54l$A~T2Z_DNhi_YGk*;*U-l{Xk&)4PmCC+z;iGMvr1imo|Z1o(_acimR@ zCH$F;2-j$HBerP4)d+kmq;Ll)wSj}~z-g!qS8j?w9jXF23~>L&1FSCHo*SGDHNWUW zl!x$e`7d&UHsRP2190Nc4bpg^KqDTx6OU*E@tj&;3+t%S&IR2W>HB-@#9llf1#Ltn z6qj_<7Zq5*+ZX1v>Lrn{*62AVz0wc{BCMTjEt^iAER4j8%L%1yv}CHZid&;g z;bPsQibuY9C>E#jELN06>F+$}@H6QbuJ}k3xeY&)HSOQMXz-?KIv0Y%f_D^^fCd4_}(-5!i`QN|Q-0iA7=~+bPSc{_i^*0%e+z zcp&!qdv~AjU7RJ^EXv|EyM0`(Z=cxYjs;8A3MsammxXF~%AkG_IZA_z8uKmcm*Z!^ zQubz8oUq{L%Z;g(w%>V+!M$M<7Lc6#m-@?`%ix}~nU9~bfP`Drx!?`Jv+++-id>?} zwb-BmTO;s|XoT&-D(DRQBcn>Y=Nh3@8uGKquG6kiGd`w#RD~#e|1rNJ+xoCeWiAWI zHFAqkpcb#(ir1rX9FdkVmP+ibFFLzcba4s=r9~wqbxURYqyh{0bk_e2d!@IB@?Dmn z-KIG(cRgf8`2T1ehF*0JQKh-GA^x^V4RAOHlbY9mBHJfa$O zpwx&>4|`#2)mb?8Dr5!1Qkr+eXq0F$$a|@*vp@FsQ}S=BDd0iyP2(xfr~mdx9=mpW zaBhh5qJ?m1P3;hGu z%o6fE9Rul)D2?iL?vYK2Vr}iturRbup&P7tGp3Cg=!C7XqYpE5+|t8j7hkE}Cl(Wj zB@Oyow76>9&U!;=dEX2pOA5MjR1zvaiIV9kx*H{Ph*IW$*?1C7l62xCV%m30B7c;` ZU$)=TGr=ZwK|F_Z7e`^w>jllm`(Gzpej)$> literal 0 HcmV?d00001 diff --git a/vendor/dominikb/composer-license-checker/.github/workflows/run-tests.yml b/vendor/dominikb/composer-license-checker/.github/workflows/run-tests.yml new file mode 100644 index 000000000..f4e6eb29c --- /dev/null +++ b/vendor/dominikb/composer-license-checker/.github/workflows/run-tests.yml @@ -0,0 +1,36 @@ +name: run-tests +on: + push: + workflow_dispatch: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + stability: [prefer-lowest, prefer-stable] + name: P${{ matrix.php }} - ${{ matrix.stability }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: phpunit + + - name: Setup problem matchers + run: | + echo "::add-matcher::${{ runner.tool_cache }}/php.json" + echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Install dependencies + run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction + + - name: Execute tests + run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover diff --git a/vendor/dominikb/composer-license-checker/.styleci.yml b/vendor/dominikb/composer-license-checker/.styleci.yml new file mode 100644 index 000000000..f4d3cbc61 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/.styleci.yml @@ -0,0 +1,4 @@ +preset: laravel + +disabled: + - single_class_element_per_statement diff --git a/vendor/dominikb/composer-license-checker/CHANGELOG.md b/vendor/dominikb/composer-license-checker/CHANGELOG.md new file mode 100644 index 000000000..280d6c6a2 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/CHANGELOG.md @@ -0,0 +1,113 @@ +# Changelog + +All notable changes to `composer-license-checker` will be documented in this file + +## 2.6.0 2024-07-06 + +### Added + +- Add documentation on exit codes to expect from any `composer-license-checker` command. ([#41](https://github.com/dominikb/composer-license-checker/pull/41)) +- Verify the exist code of the internal call to `composer licenses` to determine if the command was successful. ([#41](https://github.com/dominikb/composer-license-checker/pull/41)) + +### Changed + +- Improve type documentation and clean up `composer.json` configuration. ([#40](https://github.com/dominikb/composer-license-checker/pull/40)) + +Thanks to: [SvenRtbg](https://github.com/SvenRtbg) + +## 2.5.1 - 2024-01-05 + +### Changed + +- Use JSON format when generating output with `composer licenses` instead of parsing text output. ([#33](https://github.com/dominikb/composer-license-checker/pull/37)) + +## 2.5.0 - 2023-11-16 + +### Added + +- Add support for Symfony 7. ([#32](https://github.com/dominikb/composer-license-checker/pull/32)) + +Thanks to: [keulinho](https://github.com/keulinho) + +## 2.4.3 - 2023-10-04 + +### Change + +- Update required composer version to mitigate CVE exposure. ([#29](https://github.com/dominikb/composer-license-checker/pull/29)) + +Thanks to: [phansys](https://github.com/phansys) + +## 2.4.2 - 2023-08-13 + +### Change + +- Update integration with [tldrlegal](https://www.tldrlegal.com/) to work with their new website. + +## 2.4.1 - 2023-05-19 + +### Change + +- Use `--dev` flag in documentation for installing the package. +- Fix deprecation warning ([#24](https://github.com/dominikb/composer-license-checker/pull/24)) + +Thanks to: [manavo](https://github.com/manavo) + +## 2.4.0 - 2022-04-30 + +### Added +- __--show-packages__ and __--grouped__ options for the report command ([#22](https://github.com/dominikb/composer-license-checker/pull/22)) +- __--filter__ to restrict queried and displayed licenses ([#22](https://github.com/dominikb/composer-license-checker/pull/22)) + +Thanks to: [dkemper](https://github.com/dkemper) + +## 2.3.0 - 2022-03-02 + +### Change +- Composer: allow for `psr/simple-cache` versions 2 and 3 +- Allow for `v6` of all symfony dependencies + +## 2.2.0 - 2021-06-02 + +### Added +- __--allow__ option to always allow a specific package or author/vendor + +## 2.1.0 - 2020-12-31 + +### Added +- Support for PHP 8 + +### Changed +- Upgrade PHPUnit major version from `7` to `9` +- Upgraded several dependencies to work with newer PHP versions. Major version bump includes [symfony/dom-crawler](https://github.com/symfony/dom-crawler). + +### Removed +- Dropped support for PHP 7.1 and 7.2 [(see: supported versions)](https://www.php.net/supported-versions.php) + +## 2.0.0 - 2020-06-17 + +### Changed +- Terminology for black/whitelist changed to block/allowlist (This changes the CLI interface of the `CheckCommand` ) +- `Command` classes now return an integer exist code + +## 1.0.1 - 2019-04-06 + +### Added +- Added Scrutinizer code coverage + +### Changed +- Fixed path to autoloader when installed with composer + +### Removed + +## 1.0.0 - 2019-04-06 + +Initial Release + +### Added +- `check` and `report` commands +- summary lookup on tldrlegal +- caching of lookups + +### Changed + +### Removed diff --git a/vendor/dominikb/composer-license-checker/CONTRIBUTING.md b/vendor/dominikb/composer-license-checker/CONTRIBUTING.md new file mode 100644 index 000000000..b4ae1c4a7 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/vendor/dominikb/composer-license-checker/LICENSE.md b/vendor/dominikb/composer-license-checker/LICENSE.md new file mode 100644 index 000000000..084b9f37b --- /dev/null +++ b/vendor/dominikb/composer-license-checker/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Dominik Bauernfeind + +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. diff --git a/vendor/dominikb/composer-license-checker/README.md b/vendor/dominikb/composer-license-checker/README.md new file mode 100644 index 000000000..27d87bf13 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/README.md @@ -0,0 +1,74 @@ +# Composer License Checker + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/dominikb/composer-license-checker.svg?style=flat-square)](https://packagist.org/packages/dominikb/composer-license-checker) +[![Build Status](https://img.shields.io/github/workflow/status/dominikb/composer-license-checker/run-tests?style=flat-square)]() +[![Quality Score](https://img.shields.io/scrutinizer/g/dominikb/composer-license-checker.svg?style=flat-square)](https://scrutinizer-ci.com/g/dominikb/composer-license-checker) +[![Scrutinizer coverage](https://img.shields.io/scrutinizer/coverage/g/dominikb/composer-license-checker.svg?style=flat-square)](https://scrutinizer-ci.com/g/dominikb/composer-license-checker) +[![Total Downloads](https://img.shields.io/packagist/dt/dominikb/composer-license-checker.svg?style=flat-square)](https://packagist.org/packages/dominikb/composer-license-checker) + +Quickly scan your dependencies, see what licenses they use or check in your CI that no unwanted licenses were merged. + +The lookup of the summaries for every license done on [https://tldrlegal.com/](https://tldrlegal.com/). +Please inform yourself in more detail about the licenses you use and do not use the provided summary as your sole information. + +## Installation + +You can install the package via composer: + +```bash +composer require --dev dominikb/composer-license-checker +``` + +## Usage + +Two separate commands are provided: +* `./composer-license-checker check` +* `./composer-license-checker report` + +Use `./composer-license-checker help` to get info about general usage or use the syntax `./composer-license-checker help COMMAND_NAME` to see more information about a specific command available. + +``` bash +./vendor/bin/composer-license-checker check \ + --allowlist MIT \ # Fail if anything but MIT license is used + --blocklist GPL \ # Fail if any dependency uses GPL + --allow dominikb/composer-license-checker # Always allow this dependency regardless of its license + +vendor/bin/composer-license-checker report -p /path/to/your/project -c /path/to/composer.phar +``` + +### Exit codes + +Any command returns with one of these exit codes: + +- 0: Ok +- 1: Offending licenses found in check, or a problem occurred when creating a report +- 2: Internal error when executing the command, may indicate problems calling Composer internally + +### Testing + +``` bash +composer test +``` + +Code coverage reports are output to the `build` folder. See `.phpunit.xml.dist` for more testing configuration. + +### Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +### Security + +If you discover any security related issues, please email bauernfeind.dominik@gmail.com instead of using the issue tracker. + +## Credits + +- [Dominik Bauernfeind](https://github.com/dominikb) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/vendor/dominikb/composer-license-checker/composer-license-checker b/vendor/dominikb/composer-license-checker/composer-license-checker new file mode 100755 index 000000000..261e31bc4 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/composer-license-checker @@ -0,0 +1,49 @@ +#!/usr/bin/env php +setLicenseLookup($licenceLookUp); +$checkCommand->setLicenseConstraintHandler(new ConstraintViolationDetector); +$checkCommand->setDependencyLoader(new DependencyLoader(new JSONDependencyParser())); + +$reportCommand = new ReportCommand; +$reportCommand->setLicenseLookup($licenceLookUp); +$reportCommand->setDependencyLoader(new DependencyLoader(new JSONDependencyParser())); + +$application = new Application('composer-license-checker', '2.6.0'); + +$application->addCommands([$checkCommand, $reportCommand]); + +$application->run(); diff --git a/vendor/dominikb/composer-license-checker/composer.json b/vendor/dominikb/composer-license-checker/composer.json new file mode 100644 index 000000000..5d9682c4a --- /dev/null +++ b/vendor/dominikb/composer-license-checker/composer.json @@ -0,0 +1,57 @@ +{ + "name": "dominikb/composer-license-checker", + "description": "Utility to check for licenses of dependencies and block/allow them.", + "keywords": [ + "dominikb", + "composer-license-checker" + ], + "homepage": "https://github.com/dominikb/composer-license-checker", + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Dominik Bauernfeind", + "email": "bauernfeind.dominik@gmail.com", + "role": "Developer" + } + ], + "require": { + "php": "^7.3 || ^8.0", + "ext-json": "*", + "composer/composer": "~2.2.23 || ^2.7.0", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "~4.2.12 || ^4.3.8 || ^5.2 || ^6.0 || ^7.0", + "symfony/console": "^5.3 || ^6.0 || ^7.0", + "symfony/css-selector": "^4.2 || ^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "phpunit/phpunit": "^9.3", + "symfony/var-dumper": "^4.2 || ^5.2 || ^6.0 || ^7.0" + }, + "autoload": { + "psr-4": { + "Dominikb\\ComposerLicenseChecker\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Dominikb\\ComposerLicenseChecker\\Tests\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-clover build/logs/coverage.xml" + }, + "config": { + "sort-packages": true + }, + "bin": [ + "composer-license-checker" + ] +} diff --git a/vendor/dominikb/composer-license-checker/src/CheckCommand.php b/vendor/dominikb/composer-license-checker/src/CheckCommand.php new file mode 100644 index 000000000..1f6b22674 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/CheckCommand.php @@ -0,0 +1,180 @@ +setDefinition(new InputDefinition([ + new InputOption( + 'project-path', + 'p', + InputOption::VALUE_OPTIONAL, + 'Path to directory of composer.json file', + realpath('.') + ), + new InputOption( + 'composer', + 'c', + InputOption::VALUE_OPTIONAL, + 'Path to composer executable', + realpath('./vendor/bin/composer') + ), + new InputOption( + 'allowlist', + 'a', + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Set a license you want to permit for usage' + ), + new InputOption( + 'blocklist', + 'b', + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Mark a specific license prohibited for usage' + ), + new InputOption( + 'allow', + '', + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Determine a vendor or package to always be allowed and never trigger violations' + ), + ])); + } + + public static function getDefaultName(): ?string + { + return 'check'; + } + + /** + * @throws CommandExecutionException + */ + public function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + + $this->io->title('Reading through dependencies and checking their licenses ...'); + + $this->ensureCommandCanBeExecuted(); + + $dependencies = $this->dependencyLoader->loadDependencies( + $input->getOption('composer'), + $input->getOption('project-path') + ); + + $this->io->writeln(count($dependencies).' dependencies were found ...'); + $this->io->newLine(); + + $violations = $this->determineViolations($dependencies, + $input->getOption('blocklist'), + $input->getOption('allowlist'), + $input->getOption('allow') + ); + + try { + $this->handleViolations($violations); + $this->io->success('Command finished successfully. No violations detected!'); + } catch (CommandExecutionException $exception) { + $this->io->error($exception->getMessage()); + + return self::FAILURE; + } + + return self::SUCCESS; + } + + /** + * @throws CommandExecutionException + */ + private function ensureCommandCanBeExecuted(): void + { + if (! $this->licenseLookup) { + throw new CommandExecutionException('LicenseLookup must be set via setLicenseLookup() before the command can be executed!'); + } + + if (! $this->dependencyLoader) { + throw new CommandExecutionException('DependencyLoader must be set via setDependencyLoader() before the command can be executed!'); + } + } + + private function determineViolations(array $dependencies, array $blocklist, array $allowlist, array $allowed): array + { + $this->licenseConstraintHandler->setBlocklist($blocklist); + $this->licenseConstraintHandler->setAllowlist($allowlist); + + $this->licenseConstraintHandler->allow(array_map(function ($dependency) { + return new Dependency($dependency); + }, $allowed)); + + return $this->licenseConstraintHandler->detectViolations($dependencies); + } + + /** + * @param ConstraintViolation[] $violations + * + * @throws CommandExecutionException + */ + private function handleViolations(array $violations): void + { + $violationsFound = false; + + foreach ($violations as $violation) { + if ($violation->hasViolators()) { + $this->io->error($violation->getTitle()); + $this->reportViolators($violation->getViolators()); + $violationsFound = true; + } + } + + if ($violationsFound) { + throw new CommandExecutionException('Violators found during execution!'); + } + } + + /** + * @param Dependency[] $violators + */ + private function reportViolators(array $violators): void + { + $byLicense = []; + foreach ($violators as $violator) { + $license = $violator->getLicenses()[0]; + + if (! isset($byLicense[$license])) { + $byLicense[$license] = []; + } + $byLicense[$license][] = $violator; + } + + foreach ($byLicense as $license => $violators) { + $violatorNames = array_map(function (Dependency $dependency) { + return sprintf('"%s [%s]"', $dependency->getName(), $dependency->getVersion()); + }, $violators); + + $this->io->title($license); + $this->io->writeln(implode(', ', $violatorNames)); + } + } +} diff --git a/vendor/dominikb/composer-license-checker/src/ConstraintViolation.php b/vendor/dominikb/composer-license-checker/src/ConstraintViolation.php new file mode 100644 index 000000000..594d9ea3f --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/ConstraintViolation.php @@ -0,0 +1,42 @@ +title = $title; + } + + public function add(Dependency $violator): void + { + $this->violators[] = $violator; + } + + public function getTitle(): string + { + return $this->title; + } + + /** + * @return Dependency[] + */ + public function getViolators(): array + { + return $this->violators; + } + + public function hasViolators(): bool + { + return count($this->violators) > 0; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/ConstraintViolationDetector.php b/vendor/dominikb/composer-license-checker/src/ConstraintViolationDetector.php new file mode 100644 index 000000000..ee9ed3d50 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/ConstraintViolationDetector.php @@ -0,0 +1,168 @@ +blocklist = $licenses; + } + + public function setAllowlist(array $licenses): void + { + $this->allowlist = $licenses; + } + + public function allow($dependencies): void + { + if (! is_array($dependencies)) { + $dependencies = [$dependencies]; + } + + foreach ($dependencies as $allowed) { + $this->alwaysAllowed[] = $allowed; + } + } + + /** + * @param Dependency[] $dependencies + * @return ConstraintViolation[] + * + * @throws LogicException + */ + public function detectViolations(array $dependencies): array + { + $this->ensureConfigurationIsValid(); + + $possibleViolators = $this->exceptAllowed($dependencies); + + return [ + $this->detectBlocklistViolation($possibleViolators), + $this->detectAllowlistViolation($possibleViolators), + ]; + } + + /** + * @throws LogicException + */ + public function ensureConfigurationIsValid(): void + { + $overlap = array_intersect($this->blocklist, $this->allowlist); + + if (count($overlap) > 0) { + $invalidLicenseConditionals = sprintf('"%s"', implode('", "', $overlap)); + throw new LogicException("Licenses must not be on the block- and allowlist at the same time: {$invalidLicenseConditionals}"); + } + } + + /** + * @param Dependency[] $dependencies + */ + private function detectBlocklistViolation(array $dependencies): ConstraintViolation + { + $violation = new ConstraintViolation('Blocked license found!'); + + if (! empty($this->blocklist)) { + foreach ($dependencies as $dependency) { + if ($this->allLicensesOnList($dependency->getLicenses(), $this->blocklist)) { + $violation->add($dependency); + } + } + } + + return $violation; + } + + /** + * @param Dependency[] $dependencies + */ + private function detectAllowlistViolation(array $dependencies): ConstraintViolation + { + $violation = new ConstraintViolation('Unallowed license found!'); + + if (! empty($this->allowlist)) { + foreach ($dependencies as $dependency) { + if (! $this->anyLicenseOnList($dependency->getLicenses(), $this->allowlist)) { + $violation->add($dependency); + } + } + } + + return $violation; + } + + private function allLicensesOnList(array $licenses, array $list): bool + { + return count(array_intersect($licenses, $list)) === count($licenses); + } + + private function anyLicenseOnList(array $licenses, array $list): bool + { + return count(array_intersect($licenses, $list)) > 0; + } + + /** + * @param Dependency[] $dependencies + * @return Dependency[] + */ + private function exceptAllowed(array $dependencies): array + { + $possiblyViolating = []; + + if (empty($this->alwaysAllowed)) { + return $dependencies; + } + + foreach ($dependencies as $dependency) { + foreach ($this->alwaysAllowed as $allowedDependency) { + if ($this->matches($allowedDependency, $dependency)) { + continue 2; // Outer for: test next dependency + } + } + + $possiblyViolating[] = $dependency; + } + + return $possiblyViolating; + } + + /** + * Determine if the $original author and package name match for $tryMatch. + * An empty string for either the author or package gets interpreted as a wilcard. + * + * @param Dependency $original + * @param Dependency $tryMatch + * @return bool + */ + private function matches(Dependency $original, Dependency $tryMatch): bool + { + if ($original->getAuthorName()) { + if (! ($original->getAuthorName() === $tryMatch->getAuthorName())) { + return false; + } + } + + if ($original->getPackageName()) { + if (! ($original->getPackageName() === $tryMatch->getPackageName())) { + return false; + } + } + + return true; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php b/vendor/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php new file mode 100644 index 000000000..b7d30704a --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/Contracts/CacheAwareContract.php @@ -0,0 +1,12 @@ +name = $name; + $this->version = $version; + $this->licenses = $licenses; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } + + /** + * @return string + */ + public function getVersion(): string + { + return $this->version; + } + + /** + * @param string $version + */ + public function setVersion(string $version): self + { + $this->version = $version; + + return $this; + } + + /** + * @return string[] + */ + public function getLicenses(): array + { + return $this->licenses; + } + + /** + * @param string[] $licenses + */ + public function setLicenses(array $licenses): self + { + $this->licenses = $licenses; + + return $this; + } + + public function getAuthorName(): string + { + return explode('/', $this->name)[0]; + } + + public function getPackageName(): string + { + $parts = explode('/', $this->name); + + if (count($parts) != 2) { + return ''; + } + + return $parts[1]; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/DependencyLoader.php b/vendor/dominikb/composer-license-checker/src/DependencyLoader.php new file mode 100644 index 000000000..5b82ed735 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/DependencyLoader.php @@ -0,0 +1,57 @@ +dependencyParser = $dependencyParser; + } + + /** + * @throws CommandExecutionException + */ + public function loadDependencies(string $composer, string $project): array + { + $commandOutput = $this->runComposerLicenseCommand($composer, $project); + + return $this->dependencyParser->parse(join(PHP_EOL, $commandOutput)); + } + + /** + * @throws CommandExecutionException + */ + private function runComposerLicenseCommand(string $composer, string $project): array + { + $command = sprintf('%s licenses --format json --working-dir %s', escapeshellarg($composer), escapeshellarg($project)); + + return $this->exec($command); + } + + /** + * @throws CommandExecutionException + */ + protected function exec(string $command): array + { + exec($command, $output, $exitCode); + + if ($exitCode !== 0) { + throw new CommandExecutionException('Error when trying to fetch licenses from Composer', Command::INVALID); + } + + return $output; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php b/vendor/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php new file mode 100644 index 000000000..38ca958f0 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/Exceptions/CommandExecutionException.php @@ -0,0 +1,9 @@ + $info) { + $parsed[] = (new Dependency) + ->setName($name) + ->setVersion($info['version']) + ->setLicenses($info['license']); + } + + return $parsed; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/License.php b/vendor/dominikb/composer-license-checker/src/License.php new file mode 100644 index 000000000..ee67494a3 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/License.php @@ -0,0 +1,142 @@ +shortName = $shortName; + } + + /** + * @return string + */ + public function getShortName(): string + { + return $this->shortName; + } + + /** + * @param string $shortName + * @return License + */ + public function setShortName(string $shortName): self + { + $this->shortName = $shortName; + + return $this; + } + + /** + * @return string[] + */ + public function getCan(): array + { + return $this->can; + } + + /** + * @param string[] $can + * @return License + */ + public function setCan(array $can): self + { + $this->can = $can; + + return $this; + } + + /** + * @return string[] + */ + public function getCannot(): array + { + return $this->cannot; + } + + /** + * @param string[] $cannot + * @return License + */ + public function setCannot(array $cannot): self + { + $this->cannot = $cannot; + + return $this; + } + + /** + * @return string[] + */ + public function getMust(): array + { + return $this->must; + } + + /** + * @param string[] $must + * @return License + */ + public function setMust(array $must): self + { + $this->must = $must; + + return $this; + } + + /** + * @return string + */ + public function getSource(): string + { + return $this->source; + } + + /** + * @param string $source + * @return License + */ + public function setSource(string $source): self + { + $this->source = $source; + + return $this; + } + + /** + * @return DateTimeInterface + */ + public function getCreatedAt(): DateTimeInterface + { + return $this->createdAt; + } + + /** + * @param DateTimeInterface $createdAt + * @return License + */ + public function setCreatedAt(DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/LicenseLookup.php b/vendor/dominikb/composer-license-checker/src/LicenseLookup.php new file mode 100644 index 000000000..3e727ab7a --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/LicenseLookup.php @@ -0,0 +1,178 @@ +http = $http; + $this->cache = $cache ?? new FilesystemAdapter('FilesystemCache', 3600, __DIR__.'/../.cache'); + } + + public function lookUp(string $licenseName): License + { + return $this->cache->get($licenseName, function () use ($licenseName) { + try { + $detailsPageUrl = $this->queryForDetailPageUrl($licenseName); + + $license = $this->resolveLicenseInformation($licenseName, $detailsPageUrl); + } catch (NoLookupPossibleException $exception) { + $license = new NoLookupLicenses($licenseName); + } + + return $license; + }); + } + + /** + * @param string $licenseShortName + * @return string + * + * @throws NoLookupPossibleException + */ + private function queryForDetailPageUrl(string $licenseShortName): string + { + if (in_array($licenseShortName, self::$noLookup)) { + throw new NoLookupPossibleException; + } + + $searchUrl = sprintf('%s/search?query=%s', static::API_HOST, $licenseShortName); + + try { + $response = $this->http->request('get', $searchUrl); + } catch (GuzzleException $exception) { + throw new NoLookupPossibleException($exception->getMessage(), $exception->getCode(), $exception); + } + + $crawler = $this->makeCrawler($response->getBody()->getContents()); + + $headings = $crawler->filter('div.search-result-items .cc-semibold')->extract(['_text']); + $links = $crawler->filter('div.search-result-items .c-link-arrow')->extract(['href']); + + $zipped = array_map(null, $headings, $links); + + $relativeUrl = $this->findBestMatch($zipped, $licenseShortName); + + return static::API_HOST.$relativeUrl; + } + + private function makeCrawler(string $html): Crawler + { + return new Crawler($html); + } + + /** + * @param string $licenseShortName + * @param string $detailsPageUrl + * @return License + * + * @throws NoLookupPossibleException + */ + private function resolveLicenseInformation(string $licenseShortName, string $detailsPageUrl): License + { + try { + $response = $this->http->request('get', $detailsPageUrl); + $pageContent = $response->getBody()->getContents(); + + $crawler = $this->makeCrawler($pageContent); + + $license = (new License($licenseShortName)) + ->setCan($this->extractCans($crawler)) + ->setCannot($this->extractCannots($crawler)) + ->setMust($this->extractMusts($crawler)) + ->setSource($detailsPageUrl) + ->setCreatedAt(new DateTimeImmutable); + + return $license; + } catch (GuzzleException $exception) { + throw new NoLookupPossibleException($exception->getMessage(), $exception->getCode(), $exception); + } + } + + private function extractCans(Crawler $crawler): array + { + return $this->extractListByIndex($crawler, 1); + } + + private function extractCannots(Crawler $crawler): array + { + return $this->extractListByIndex($crawler, 3); + } + + private function extractMusts(Crawler $crawler): array + { + return $this->extractListByIndex($crawler, 5); + } + + // Index is the offset as children of div.features + private function extractListByIndex(Crawler $crawler, $index): array + { + $headings = $crawler->filter('div.c-feature:nth-child('.$index.') .c-text-md.cc-semibold') + ->each(function (Crawler $crawler) { + return $crawler->getNode(0)->textContent; + }); + + $bodies = $crawler->filter('div.c-feature:nth-child('.$index.') .c-text-sm') + ->each(function (Crawler $crawler) { + return $crawler->getNode(0)->textContent; + }); + + return array_combine($headings, $bodies); + } + + /** + * Find the best matching link by comparing the similarity of the link and text. + * + * @param array $zipped + * @param string $licenseShortName + * @return string + */ + private function findBestMatch(array $zipped, string $licenseShortName): string + { + $bestMatch = 0; + $matchingLink = ''; + + foreach ($zipped as [$title, $link]) { + $titleMatch = similar_text($title, $licenseShortName); + $linkMatch = similar_text($link, $licenseShortName); + + $totalMatch = $titleMatch + $linkMatch; + + if ($totalMatch > $bestMatch) { + $bestMatch = $totalMatch; + $matchingLink = $link; + } + } + + return $matchingLink; + } + + public function setCache(CacheInterface $cache): void + { + $this->cache = $cache; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/NoLookupLicenses.php b/vendor/dominikb/composer-license-checker/src/NoLookupLicenses.php new file mode 100644 index 000000000..f7eb3bbde --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/NoLookupLicenses.php @@ -0,0 +1,20 @@ +setShortName($shortName); + $this->setCan([]); + $this->setCannot([]); + $this->setMust([]); + $this->setSource('-'); + $this->setCreatedAt(new DateTimeImmutable); + } +} diff --git a/vendor/dominikb/composer-license-checker/src/ReportCommand.php b/vendor/dominikb/composer-license-checker/src/ReportCommand.php new file mode 100644 index 000000000..d6a2f25d7 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/ReportCommand.php @@ -0,0 +1,232 @@ +setDefinition(new InputDefinition([ + new InputOption( + 'project-path', + 'p', + InputOption::VALUE_OPTIONAL, + 'Path to directory of composer.json file', + realpath('.') + ), + new InputOption( + 'composer', + 'c', + InputOption::VALUE_OPTIONAL, + 'Path to composer executable', + realpath('./vendor/bin/composer') + ), + new InputOption( + 'no-cache', + null, + InputOption::VALUE_NONE, + 'Disables caching of license lookups' + ), + new InputOption( + 'show-packages', + null, + InputOption::VALUE_NONE, + 'Shows the packages for each license.' + ), + new InputOption( + 'grouped', + null, + InputOption::VALUE_NONE, + 'Display the packages grouped. Only valid with the \'show-packages\' option.' + ), + new InputOption( + 'filter', + null, + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Filter for specific licences.' + ), + ])); + } + + public static function getDefaultName(): ?string + { + return 'report'; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + if ($input->getOption('grouped') && ! $input->getOption('show-packages')) { + throw new \InvalidArgumentException('The option "grouped" is only allowed with "show-packages" option'); + } + + $dependencies = $this->dependencyLoader->loadDependencies( + $input->getOption('composer'), + $input->getOption('project-path') + ); + + $dependencies = $this->filterLicenses($dependencies, $input->getOption('filter')); + + $groupedByName = $this->groupDependenciesByLicense($dependencies); + + $shouldCache = ! $input->getOption('no-cache'); + + $licenses = $this->lookUpLicenses(array_keys($groupedByName), $output, $shouldCache); + + /* @var License $license */ + $this->outputFormattedLicenses($output, $input, $licenses, $groupedByName); + + return self::SUCCESS; + } + + /** + * @param Dependency[] $dependencies + * @return array + */ + private function groupDependenciesByLicense(array $dependencies): array + { + $grouped = []; + + foreach ($dependencies as $dependency) { + [$license] = $dependency->getLicenses(); + + if (! isset($grouped[$license])) { + $grouped[$license] = []; + } + $grouped[$license][] = $dependency; + } + + return $grouped; + } + + /** + * @param Dependency[] $dependencies + * @param string[] $filters + * @return array + */ + private function filterLicenses(array $dependencies, array $filters): array + { + if ($filters === []) { + return $dependencies; + } + + $validLicences = []; + + foreach ($dependencies as $dependency) { + foreach ($dependency->getLicenses() as $license) { + if (in_array(strtolower($license), array_map('strtolower', $filters))) { + $validLicences[] = $dependency; + continue 2; + } + } + } + + return $validLicences; + } + + private function lookUpLicenses(array $licenses, OutputInterface $output, $useCache = true): array + { + if (! $useCache) { + $this->licenseLookup->setCache(new NullAdapter); + } + + $lookedUp = []; + foreach ($licenses as $license) { + $output->writeln("Looking up $license ..."); + $lookedUp[$license] = $this->licenseLookup->lookUp($license); + } + + return $lookedUp; + } + + /** + * @param OutputInterface $output + * @param InputInterface $input + * @param License[] $licenses + * @param array $groupedByName + */ + protected function outputFormattedLicenses(OutputInterface $output, InputInterface $input, array $licenses, array $groupedByName): void + { + foreach ($licenses as $license) { + $dependencies = $groupedByName[$license->getShortName()]; + + $usageCount = count($dependencies); + $headline = sprintf(PHP_EOL.'Count %d - %s (%s)', $usageCount, $license->getShortName(), + $license->getSource()); + $output->writeln($headline); + $licenseTable = new Table($output); + $licenseTable->setHeaders(['CAN', 'CAN NOT', 'MUST']); + + $can = $license->getCan(); + $cannot = $license->getCannot(); + $must = $license->getMust(); + $columnWidth = max(count($can), count($cannot), count($must)); + + $can = array_pad($can, $columnWidth, null); + $cannot = array_pad($cannot, $columnWidth, null); + $must = array_pad($must, $columnWidth, null); + + $inlineHeading = function ($key) { + return is_string($key) ? $key : ''; + }; + + $can = array_map_keys($can, $inlineHeading); + $cannot = array_map_keys($cannot, $inlineHeading); + $must = array_map_keys($must, $inlineHeading); + + for ($i = 0; $i < $columnWidth; $i++) { + $licenseTable->addRow([ + 'CAN' => $can[$i], + 'CANNOT' => $cannot[$i], + 'MUST' => $must[$i], + ]); + } + $licenseTable->render(); + + if ($input->getOption('show-packages') || $output->isVerbose()) { + $output->writeln(''); + $output->writeln($this->outputFormatPackages($input, $dependencies)); + } + } + } + + /** + * Generates a output string for the 'show-packages' option. + * + * @param InputInterface $input + * @param array $dependencies + * @return string + */ + protected function outputFormatPackages(InputInterface $input, array $dependencies): string + { + $packages = []; + if ($input->getOption('grouped')) { + foreach ($dependencies as $dependency) { + $packages[] = $dependency->getName(); + } + + return 'packages: '.implode(', ', $packages); + } + + foreach ($dependencies as $dependency) { + $packages[] = sprintf('%s (%s)', $dependency->getName(), $dependency->getVersion()); + } + + return implode(PHP_EOL, $packages); + } +} diff --git a/vendor/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php b/vendor/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php new file mode 100644 index 000000000..f596b93b0 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/Traits/DependencyLoaderAwareTrait.php @@ -0,0 +1,18 @@ +dependencyLoader = $loader; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php b/vendor/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php new file mode 100644 index 000000000..1059902d4 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/Traits/LicenseConstraintAwareTrait.php @@ -0,0 +1,23 @@ +licenseConstraintHandler = $handler; + } + + private function shouldHandleConstraints(): bool + { + return isset($this->licenseConstraintHandler); + } +} diff --git a/vendor/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php b/vendor/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php new file mode 100644 index 000000000..f02e00d85 --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/Traits/LicenseLookupAwareTrait.php @@ -0,0 +1,18 @@ +licenseLookup = $licenseLookup; + } +} diff --git a/vendor/dominikb/composer-license-checker/src/helpers.php b/vendor/dominikb/composer-license-checker/src/helpers.php new file mode 100644 index 000000000..dbcc5249f --- /dev/null +++ b/vendor/dominikb/composer-license-checker/src/helpers.php @@ -0,0 +1,21 @@ + $value) { + $output[] = $callback($key, $value); + } + + return $output; + } +} diff --git a/vendor/masterminds/html5/CREDITS b/vendor/masterminds/html5/CREDITS new file mode 100644 index 000000000..c2dbc4b64 --- /dev/null +++ b/vendor/masterminds/html5/CREDITS @@ -0,0 +1,11 @@ +Matt Butcher [technosophos] (lead) +Matt Farina [mattfarina] (lead) +Asmir Mustafic [goetas] (contributor) +Edward Z. Yang [ezyang] (contributor) +Geoffrey Sneddon [gsnedders] (contributor) +Kukhar Vasily [ngreduce] (contributor) +Rune Christensen [MrElectronic] (contributor) +Mišo Belica [miso-belica] (contributor) +Asmir Mustafic [goetas] (contributor) +KITAITI Makoto [KitaitiMakoto] (contributor) +Jacob Floyd [cognifloyd] (contributor) diff --git a/vendor/masterminds/html5/LICENSE.txt b/vendor/masterminds/html5/LICENSE.txt new file mode 100644 index 000000000..3c275b54a --- /dev/null +++ b/vendor/masterminds/html5/LICENSE.txt @@ -0,0 +1,66 @@ +## HTML5-PHP License + +Copyright (c) 2013 The Authors of HTML5-PHP + +Matt Butcher - mattbutcher@google.com +Matt Farina - matt@mattfarina.com +Asmir Mustafic - goetas@gmail.com + +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. + +## HTML5Lib License + +Portions of this are based on html5lib's PHP version, which was a +sub-project of html5lib. The following is the list of contributors from +html5lib: + +html5lib: + +Copyright (c) 2006-2009 The Authors + +Contributors: +James Graham - jg307@cam.ac.uk +Anne van Kesteren - annevankesteren@gmail.com +Lachlan Hunt - lachlan.hunt@lachy.id.au +Matt McDonald - kanashii@kanashii.ca +Sam Ruby - rubys@intertwingly.net +Ian Hickson (Google) - ian@hixie.ch +Thomas Broyer - t.broyer@ltgt.net +Jacques Distler - distler@golem.ph.utexas.edu +Henri Sivonen - hsivonen@iki.fi +Adam Barth - abarth@webkit.org +Eric Seidel - eric@webkit.org +The Mozilla Foundation (contributions from Henri Sivonen since 2008) +David Flanagan (Mozilla) - dflanagan@mozilla.com + +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. diff --git a/vendor/masterminds/html5/README.md b/vendor/masterminds/html5/README.md new file mode 100644 index 000000000..fb6e56256 --- /dev/null +++ b/vendor/masterminds/html5/README.md @@ -0,0 +1,270 @@ +> # UKRAINE NEEDS YOUR HELP NOW! +> +> On 24 February 2022, Russian [President Vladimir Putin ordered an invasion of Ukraine by Russian Armed Forces](https://www.bbc.com/news/world-europe-60504334). +> +> Your support is urgently needed. +> +> - Donate to the volunteers. Here is the volunteer fund helping the Ukrainian army to provide all the necessary equipment: +> https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi or https://savelife.in.ua/en/donate/ +> - Triple-check social media sources. Russian disinformation is attempting to coverup and distort the reality in Ukraine. +> - Help Ukrainian refugees who are fleeing Russian attacks and shellings: https://www.globalcitizen.org/en/content/ways-to-help-ukraine-conflict/ +> - Put pressure on your political representatives to provide help to Ukraine. +> - Believe in the Ukrainian people, they will not surrender, they don't have another Ukraine. +> +> THANK YOU! +---- + +# HTML5-PHP + +HTML5 is a standards-compliant HTML5 parser and writer written entirely in PHP. +It is stable and used in many production websites, and has +well over [five million downloads](https://packagist.org/packages/masterminds/html5). + +HTML5 provides the following features. + +- An HTML5 serializer +- Support for PHP namespaces +- Composer support +- Event-based (SAX-like) parser +- A DOM tree builder +- Interoperability with [QueryPath](https://github.com/technosophos/querypath) +- Runs on **PHP** 5.3.0 or newer + +[![CI](https://github.com/Masterminds/html5-php/actions/workflows/ci.yaml/badge.svg)](https://github.com/Masterminds/html5-php/actions/workflows/ci.yaml) +[![Latest Stable Version](https://poser.pugx.org/masterminds/html5/v/stable.png)](https://packagist.org/packages/masterminds/html5) +[![Code Coverage](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master) +[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html) + +## Installation + +Install HTML5-PHP using [composer](http://getcomposer.org/). + +By adding the `masterminds/html5` dependency to your `composer.json` file: + +```json +{ + "require" : { + "masterminds/html5": "^2.0" + }, +} +``` + +By invoking require command via composer executable: + +```bash +composer require masterminds/html5 +``` + +## Basic Usage + +HTML5-PHP has a high-level API and a low-level API. + +Here is how you use the high-level `HTML5` library API: + +```php + + + TEST + + +

Hello World

+

This is a test of the HTML5 parser.

+ + +HERE; + +// Parse the document. $dom is a DOMDocument. +$html5 = new HTML5(); +$dom = $html5->loadHTML($html); + +// Render it as HTML5: +print $html5->saveHTML($dom); + +// Or save it to a file: +$html5->save($dom, 'out.html'); +``` + +The `$dom` created by the parser is a full `DOMDocument` object. And the +`save()` and `saveHTML()` methods will take any DOMDocument. + +### Options + +It is possible to pass in an array of configuration options when loading +an HTML5 document. + +```php +// An associative array of options +$options = array( + 'option_name' => 'option_value', +); + +// Provide the options to the constructor +$html5 = new HTML5($options); + +$dom = $html5->loadHTML($html); +``` + +The following options are supported: + +* `encode_entities` (boolean): Indicates that the serializer should aggressively + encode characters as entities. Without this, it only encodes the bare + minimum. +* `disable_html_ns` (boolean): Prevents the parser from automatically + assigning the HTML5 namespace to the DOM document. This is for + non-namespace aware DOM tools. +* `target_document` (\DOMDocument): A DOM document that will be used as the + destination for the parsed nodes. +* `implicit_namespaces` (array): An assoc array of namespaces that should be + used by the parser. Name is tag prefix, value is NS URI. + +## The Low-Level API + +This library provides the following low-level APIs that you can use to +create more customized HTML5 tools: + +- A SAX-like event-based parser that you can hook into for special kinds +of parsing. +- A flexible error-reporting mechanism that can be tuned to document +syntax checking. +- A DOM implementation that uses PHP's built-in DOM library. + +The unit tests exercise each piece of the API, and every public function +is well-documented. + +### Parser Design + +The parser is designed as follows: + +- The `Scanner` handles scanning on behalf of the parser. +- The `Tokenizer` requests data off of the scanner, parses it, clasifies +it, and sends it to an `EventHandler`. It is a *recursive descent parser.* +- The `EventHandler` receives notifications and data for each specific +semantic event that occurs during tokenization. +- The `DOMBuilder` is an `EventHandler` that listens for tokenizing +events and builds a document tree (`DOMDocument`) based on the events. + +### Serializer Design + +The serializer takes a data structure (the `DOMDocument`) and transforms +it into a character representation -- an HTML5 document. + +The serializer is broken into three parts: + +- The `OutputRules` contain the rules to turn DOM elements into strings. The +rules are an implementation of the interface `RulesInterface` allowing for +different rule sets to be used. +- The `Traverser`, which is a special-purpose tree walker. It visits +each node node in the tree and uses the `OutputRules` to transform the node +into a string. +- `HTML5` manages the `Traverser` and stores the resultant data +in the correct place. + +The serializer (`save()`, `saveHTML()`) follows the +[section 8.9 of the HTML 5.0 spec](http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#serializing-html-fragments). +So tags are serialized according to these rules: + +- A tag with children: <foo>CHILDREN</foo> +- A tag that cannot have content: <foo> (no closing tag) +- A tag that could have content, but doesn't: <foo></foo> + +## Known Issues (Or, Things We Designed Against the Spec) + +Please check the issue queue for a full list, but the following are +issues known issues that are not presently on the roadmap: + +- Namespaces: HTML5 only [supports a selected list of namespaces](http://www.w3.org/TR/html5/infrastructure.html#namespaces) + and they do not operate in the same way as XML namespaces. A `:` has no special + meaning. + By default the parser does not support XML style namespaces via `:`; + to enable the XML namespaces see the [XML Namespaces section](#xml-namespaces) +- Scripts: This parser does not contain a JavaScript or a CSS + interpreter. While one may be supplied, not all features will be + supported. +- Reentrance: The current parser is not re-entrant. (Thus you can't pause + the parser to modify the HTML string mid-parse.) +- Validation: The current tree builder is **not** a validating parser. + While it will correct some HTML, it does not check that the HTML + conforms to the standard. (Should you wish, you can build a validating + parser by extending DOMTree or building your own EventHandler + implementation.) + * There is limited support for insertion modes. + * Some autocorrection is done automatically. + * Per the spec, many legacy tags are admitted and correctly handled, + even though they are technically not part of HTML5. +- Attribute names and values: Due to the implementation details of the + PHP implementation of DOM, attribute names that do not follow the + XML 1.0 standard are not inserted into the DOM. (Effectively, they + are ignored.) If you've got a clever fix for this, jump in! +- Processor Instructions: The HTML5 spec does not allow processor + instructions. We do. Since this is a server-side library, we think + this is useful. And that means, dear reader, that in some cases you + can parse the HTML from a mixed PHP/HTML document. This, however, + is an incidental feature, not a core feature. +- HTML manifests: Unsupported. +- PLAINTEXT: Unsupported. +- Adoption Agency Algorithm: Not yet implemented. (8.2.5.4.7) + +## XML Namespaces + +To use XML style namespaces you have to configure well the main `HTML5` instance. + +```php +use Masterminds\HTML5; +$html = new HTML5(array( + "xmlNamespaces" => true +)); + +$dom = $html->loadHTML(''); + +$dom->documentElement->namespaceURI; // http://www.example.com + +``` + +You can also add some default prefixes that will not require the namespace declaration, +but its elements will be namespaced. + +```php +use Masterminds\HTML5; +$html = new HTML5(array( + "implicitNamespaces"=>array( + "t"=>"http://www.example.com" + ) +)); + +$dom = $html->loadHTML(''); + +$dom->documentElement->namespaceURI; // http://www.example.com + +``` + +## Thanks to... + +The dedicated (and patient) contributors of patches small and large, +who have already made this library better.See the CREDITS file for +a list of contributors. + +We owe a huge debt of gratitude to the original authors of html5lib. + +While not much of the original parser remains, we learned a lot from +reading the html5lib library. And some pieces remain here. In +particular, much of the UTF-8 and Unicode handling is derived from the +html5lib project. + +## License + +This software is released under the MIT license. The original html5lib +library was also released under the MIT license. + +See LICENSE.txt + +Certain files contain copyright assertions by specific individuals +involved with html5lib. Those have been retained where appropriate. diff --git a/vendor/masterminds/html5/RELEASE.md b/vendor/masterminds/html5/RELEASE.md new file mode 100644 index 000000000..33007ed69 --- /dev/null +++ b/vendor/masterminds/html5/RELEASE.md @@ -0,0 +1,157 @@ +# Release Notes + +2.7.6 (2021-08-18) + +- #218: Address comment handling issues + +2.7.5 (2021-07-01) + +- #204: Travis: Enable tests on PHP 8.0 +- #207: Fix PHP 8.1 deprecations + +2.7.4 (2020-10-01) + +- #191: Fix travisci build +- #195: Add .gitattributes file with export-ignore rules +- #194: Fix query parameter parsed as character entity + +2.7.3 (2020-07-05) + +- #190: mitigate cyclic reference between output rules and the traverser objects + +2.7.2 (2020-07-01) + +- #187: Fixed memory leak in HTML5::saveHTML() +- #186: Add special case for end tag
+ +2.7.1 (2020-06-14) + +- #171: add PHP 7.4 job +- #178: Prevent infinite loop on un-terminated entity declaration at EOF + +2.7.0 (2019-07-25) + +- #164: Drop HHVM support +- #168: Set default encoding in the DOMDocument object + +2.6.0 (2019-03-10) + +- #163: Allow to pass a charset to the Scanner + +2.5.0 (2018-12-27) + +- #162, #161, #155, #154, #153, #151: big performance improvements +- #156: fixed typos +- #160: adopt and enforce code style +- #159: remove deprecated php unit base test case +- #150: backport changes from old master branch + +2.4.0 (2018-11-17) + +- #148: Improve performance by moving sequence matching +- #147: Improve the Tokenizer performance +- #146: Improve performance by relying on a native string instead of InputStream +- #144: Add DOM extension in composer.json +- #145: Add more extensions on composer.json, improve phpdocs and remove dead code +- #143: Remove experimental comment + +2.3.1 (2018-10-18) + +- #121: Audio is not a block tag (fixed by #141) +- #136: Handle illegal self-closing according to spec (fixed by #137) +- #141: Minor fixes in the README + +2.3.0 (2017-09-04) + +- #129: image within inline svg breaks system (fixed by #133) +- #131: ² does not work (fixed by #132) +- #134: Improve tokenizer performance by 20% (alternative version of #130 thanks to @MichaelHeerklotz) +- #135: Raw & in attributes + +2.2.2 (2016-09-22) + +- #116: In XML mode, tags are case sensitive +- #115: Fix PHP Notice in OutputRules +- #112: fix parsing of options of an optgroup +- #111: Adding test for the address tag + +2.2.1 (2016-05-10) + +- #109: Fixed issue where address tag could be written without closing tag (thanks sylus) + +2.2.0 (2016-04-11) + +- #105: Enable composer cache (for CI/CD) +- #100: Use mb_substitute_character inset of ini_set for environments where ini_set is disable (e.g., shared hosting) +- #98: Allow link, meta, style tags in noscript tags +- #96: Fixed xml:href on svgs that use the "use" breaking +- #94: Counting UTF8 characters performance improvement +- #93: Use newer version of coveralls package +- #90: Remove duplicate test +- #87: Allow multiple root nodes + +2.1.2 (2015-06-07) +- #82: Support for PHP7 +- #84: Improved boolean attribute handling + +2.1.1 (2015-03-23) +- #78: Fixes bug where unmatched entity like string drops everything after &. + +2.1.0 (2015-02-01) +- #74: Added `disable_html_ns` and `target_doc` dom parsing options +- Unified option names +- #73: Fixed alphabet, ß now can be detected +- #75 and #76: Allow whitespace in RCDATA tags +- #77: Fixed parsing blunder for json embeds +- #72: Add options to HTML methods + +2.0.2 (2014-12-17) +- #50: empty document handling +- #63: tags with strange capitalization +- #65: dashes and underscores as allowed characters in tag names +- #68: Fixed issue with non-inline elements inside inline containers + +2.0.1 (2014-09-23) +- #59: Fixed issue parsing some fragments. +- #56: Incorrectly saw 0 as empty string +- Sami as new documentation generator + +2.0.0 (2014-07-28) +- #53: Improved boolean attributes handling +- #52: Facebook HHVM compatibility +- #48: Adopted PSR-2 as coding standard +- #47: Moved everything to Masterminds namespace +- #45: Added custom namespaces +- #44: Added support to XML-style namespaces +- #37: Refactored HTML5 class removing static methods + +1.0.5 (2014-06-10) +- #38: Set the dev-master branch as the 1.0.x branch for composer (goetas) +- #34: Tests use PSR-4 for autoloading. (goetas) +- #40, #41: Fix entity handling in RCDATA sections. (KitaitiMakoto) +- #32: Fixed issue where wharacter references were being incorrectly encoded in style tags. + +1.0.4 (2014-04-29) +- #30/#31 Don't throw an exception for invalid tag names. + +1.0.3 (2014-02-28) +- #23 and #29: Ignore attributes with illegal chars in name for the PHP DOM. + +1.0.2 (2014-02-12) +- #23: Handle missing tag close in attribute list. +- #25: Fixed text escaping in the serializer (HTML% 8.3). +- #27: Fixed tests on Windows: changed "\n" -> PHP_EOL. +- #28: Fixed infinite loop for char "&" in unquoted attribute in parser. +- #26: Updated tag name case handling to deal with uppercase usage. +- #24: Newlines and tabs are allowed inside quoted attributes (HTML5 8.2.4). +- Fixed Travis CI testing. + +1.0.1 (2013-11-07) +- CDATA encoding is improved. (Non-standard; Issue #19) +- Some parser rules were not returning the new current element. (Issue #20) +- Added, to the README, details on code test coverage and to packagist version. +- Fixed processor instructions. +- Improved test coverage and documentation coverage. + +1.0.0 (2013-10-02) +- Initial release. diff --git a/vendor/masterminds/html5/UPGRADING.md b/vendor/masterminds/html5/UPGRADING.md new file mode 100644 index 000000000..76e3a19bc --- /dev/null +++ b/vendor/masterminds/html5/UPGRADING.md @@ -0,0 +1,21 @@ +From 1.x to 2.x +================= + +- All classes uses `Masterminds` namespace. +- All public static methods has been removed from `HTML5` class and the general API to access the HTML5 functionalities has changed. + + Before: + + $dom = \HTML5::loadHTML('....'); + \HTML5::saveHTML($dom); + + After: + + use Masterminds\HTML5; + + $html5 = new HTML5(); + + $dom = $html5->loadHTML('....'); + echo $html5->saveHTML($dom); + + diff --git a/vendor/masterminds/html5/bin/entities.php b/vendor/masterminds/html5/bin/entities.php new file mode 100644 index 000000000..56323a341 --- /dev/null +++ b/vendor/masterminds/html5/bin/entities.php @@ -0,0 +1,26 @@ + $obj) { + $sname = substr($name, 1, -1); + $table[$sname] = $obj->characters; +} + +echo '=5.3.0" + }, + "require-dev": { + "phpunit/phpunit" : "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "autoload": { + "psr-4": {"Masterminds\\": "src"} + }, + "autoload-dev": { + "psr-4": {"Masterminds\\HTML5\\Tests\\": "test/HTML5"} + }, + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/vendor/masterminds/html5/src/HTML5.php b/vendor/masterminds/html5/src/HTML5.php new file mode 100644 index 000000000..c857145fb --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5.php @@ -0,0 +1,246 @@ + false, + + // Prevents the parser from automatically assigning the HTML5 namespace to the DOM document. + 'disable_html_ns' => false, + ); + + protected $errors = array(); + + public function __construct(array $defaultOptions = array()) + { + $this->defaultOptions = array_merge($this->defaultOptions, $defaultOptions); + } + + /** + * Get the current default options. + * + * @return array + */ + public function getOptions() + { + return $this->defaultOptions; + } + + /** + * Load and parse an HTML file. + * + * This will apply the HTML5 parser, which is tolerant of many + * varieties of HTML, including XHTML 1, HTML 4, and well-formed HTML + * 3. Note that in these cases, not all of the old data will be + * preserved. For example, XHTML's XML declaration will be removed. + * + * The rules governing parsing are set out in the HTML 5 spec. + * + * @param string|resource $file The path to the file to parse. If this is a resource, it is + * assumed to be an open stream whose pointer is set to the first + * byte of input. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. These object type is defined by the libxml + * library, and should have been included with your version of PHP. + */ + public function load($file, array $options = array()) + { + // Handle the case where file is a resource. + if (is_resource($file)) { + return $this->parse(stream_get_contents($file), $options); + } + + return $this->parse(file_get_contents($file), $options); + } + + /** + * Parse a HTML Document from a string. + * + * Take a string of HTML 5 (or earlier) and parse it into a + * DOMDocument. + * + * @param string $string A html5 document as a string. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. DOM is part of libxml, which is included with + * almost all distribtions of PHP. + */ + public function loadHTML($string, array $options = array()) + { + return $this->parse($string, $options); + } + + /** + * Convenience function to load an HTML file. + * + * This is here to provide backwards compatibility with the + * PHP DOM implementation. It simply calls load(). + * + * @param string $file The path to the file to parse. If this is a resource, it is + * assumed to be an open stream whose pointer is set to the first + * byte of input. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. These object type is defined by the libxml + * library, and should have been included with your version of PHP. + */ + public function loadHTMLFile($file, array $options = array()) + { + return $this->load($file, $options); + } + + /** + * Parse a HTML fragment from a string. + * + * @param string $string the HTML5 fragment as a string + * @param array $options Configuration options when parsing the HTML + * + * @return \DOMDocumentFragment A DOM fragment. The DOM is part of libxml, which is included with + * almost all distributions of PHP. + */ + public function loadHTMLFragment($string, array $options = array()) + { + return $this->parseFragment($string, $options); + } + + /** + * Return all errors encountered into parsing phase. + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return true it some errors were encountered into parsing phase. + * + * @return bool + */ + public function hasErrors() + { + return count($this->errors) > 0; + } + + /** + * Parse an input string. + * + * @param string $input + * @param array $options + * + * @return \DOMDocument + */ + public function parse($input, array $options = array()) + { + $this->errors = array(); + $options = array_merge($this->defaultOptions, $options); + $events = new DOMTreeBuilder(false, $options); + $scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'); + $parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML); + + $parser->parse(); + $this->errors = $events->getErrors(); + + return $events->document(); + } + + /** + * Parse an input stream where the stream is a fragment. + * + * Lower-level loading function. This requires an input stream instead + * of a string, file, or resource. + * + * @param string $input The input data to parse in the form of a string. + * @param array $options An array of options. + * + * @return \DOMDocumentFragment + */ + public function parseFragment($input, array $options = array()) + { + $options = array_merge($this->defaultOptions, $options); + $events = new DOMTreeBuilder(true, $options); + $scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'); + $parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML); + + $parser->parse(); + $this->errors = $events->getErrors(); + + return $events->fragment(); + } + + /** + * Save a DOM into a given file as HTML5. + * + * @param mixed $dom The DOM to be serialized. + * @param string|resource $file The filename to be written or resource to write to. + * @param array $options Configuration options when serializing the DOM. These include: + * - encode_entities: Text written to the output is escaped by default and not all + * entities are encoded. If this is set to true all entities will be encoded. + * Defaults to false. + */ + public function save($dom, $file, $options = array()) + { + $close = true; + if (is_resource($file)) { + $stream = $file; + $close = false; + } else { + $stream = fopen($file, 'wb'); + } + $options = array_merge($this->defaultOptions, $options); + $rules = new OutputRules($stream, $options); + $trav = new Traverser($dom, $stream, $rules, $options); + + $trav->walk(); + /* + * release the traverser to avoid cyclic references and allow PHP to free memory without waiting for gc_collect_cycles + */ + $rules->unsetTraverser(); + if ($close) { + fclose($stream); + } + } + + /** + * Convert a DOM into an HTML5 string. + * + * @param mixed $dom The DOM to be serialized. + * @param array $options Configuration options when serializing the DOM. These include: + * - encode_entities: Text written to the output is escaped by default and not all + * entities are encoded. If this is set to true all entities will be encoded. + * Defaults to false. + * + * @return string A HTML5 documented generated from the DOM. + */ + public function saveHTML($dom, $options = array()) + { + $stream = fopen('php://temp', 'wb'); + $this->save($dom, $stream, array_merge($this->defaultOptions, $options)); + + $html = stream_get_contents($stream, -1, 0); + + fclose($stream); + + return $html; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Elements.php b/vendor/masterminds/html5/src/HTML5/Elements.php new file mode 100644 index 000000000..5d8cfd442 --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Elements.php @@ -0,0 +1,637 @@ + [PARENT-TAG-NAME-TO-CLOSE1, PARENT-TAG-NAME-TO-CLOSE2, ...]. + * + * Order is important, after auto-closing one parent with might have to close also their parent. + * + * @var array + */ + public static $optionalEndElementsParentsToClose = array( + 'tr' => array('td', 'tr'), + 'td' => array('td', 'th'), + 'th' => array('td', 'th'), + 'tfoot' => array('td', 'th', 'tr', 'tbody', 'thead'), + 'tbody' => array('td', 'th', 'tr', 'thead'), + ); + + /** + * The HTML5 elements as defined in http://dev.w3.org/html5/markup/elements.html. + * + * @var array + */ + public static $html5 = array( + 'a' => 1, + 'abbr' => 1, + 'address' => 65, // NORMAL | BLOCK_TAG + 'area' => 9, // NORMAL | VOID_TAG + 'article' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'aside' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'audio' => 1, // NORMAL + 'b' => 1, + 'base' => 9, // NORMAL | VOID_TAG + 'bdi' => 1, + 'bdo' => 1, + 'blockquote' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'body' => 1, + 'br' => 9, // NORMAL | VOID_TAG + 'button' => 1, + 'canvas' => 65, // NORMAL | BLOCK_TAG + 'caption' => 1, + 'cite' => 1, + 'code' => 1, + 'col' => 9, // NORMAL | VOID_TAG + 'colgroup' => 1, + 'command' => 9, // NORMAL | VOID_TAG + // "data" => 1, // This is highly experimental and only part of the whatwg spec (not w3c). See https://developer.mozilla.org/en-US/docs/HTML/Element/data + 'datalist' => 1, + 'dd' => 65, // NORMAL | BLOCK_TAG + 'del' => 1, + 'details' => 17, // NORMAL | AUTOCLOSE_P, + 'dfn' => 1, + 'dialog' => 17, // NORMAL | AUTOCLOSE_P, + 'div' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'dl' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'dt' => 1, + 'em' => 1, + 'embed' => 9, // NORMAL | VOID_TAG + 'fieldset' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'figcaption' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'figure' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'footer' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'form' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h1' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h2' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h3' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h4' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h5' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h6' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'head' => 1, + 'header' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'hgroup' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'hr' => 73, // NORMAL | VOID_TAG + 'html' => 1, + 'i' => 1, + 'iframe' => 3, // NORMAL | TEXT_RAW + 'img' => 9, // NORMAL | VOID_TAG + 'input' => 9, // NORMAL | VOID_TAG + 'kbd' => 1, + 'ins' => 1, + 'keygen' => 9, // NORMAL | VOID_TAG + 'label' => 1, + 'legend' => 1, + 'li' => 1, + 'link' => 9, // NORMAL | VOID_TAG + 'map' => 1, + 'mark' => 1, + 'menu' => 17, // NORMAL | AUTOCLOSE_P, + 'meta' => 9, // NORMAL | VOID_TAG + 'meter' => 1, + 'nav' => 17, // NORMAL | AUTOCLOSE_P, + 'noscript' => 65, // NORMAL | BLOCK_TAG + 'object' => 1, + 'ol' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'optgroup' => 1, + 'option' => 1, + 'output' => 65, // NORMAL | BLOCK_TAG + 'p' => 209, // NORMAL | AUTOCLOSE_P | BLOCK_TAG | BLOCK_ONLY_INLINE + 'param' => 9, // NORMAL | VOID_TAG + 'pre' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'progress' => 1, + 'q' => 1, + 'rp' => 1, + 'rt' => 1, + 'ruby' => 1, + 's' => 1, + 'samp' => 1, + 'script' => 3, // NORMAL | TEXT_RAW + 'section' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'select' => 1, + 'small' => 1, + 'source' => 9, // NORMAL | VOID_TAG + 'span' => 1, + 'strong' => 1, + 'style' => 3, // NORMAL | TEXT_RAW + 'sub' => 1, + 'summary' => 17, // NORMAL | AUTOCLOSE_P, + 'sup' => 1, + 'table' => 65, // NORMAL | BLOCK_TAG + 'tbody' => 1, + 'td' => 1, + 'textarea' => 5, // NORMAL | TEXT_RCDATA + 'tfoot' => 65, // NORMAL | BLOCK_TAG + 'th' => 1, + 'thead' => 1, + 'time' => 1, + 'title' => 5, // NORMAL | TEXT_RCDATA + 'tr' => 1, + 'track' => 9, // NORMAL | VOID_TAG + 'u' => 1, + 'ul' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'var' => 1, + 'video' => 1, + 'wbr' => 9, // NORMAL | VOID_TAG + + // Legacy? + 'basefont' => 8, // VOID_TAG + 'bgsound' => 8, // VOID_TAG + 'noframes' => 2, // RAW_TEXT + 'frame' => 9, // NORMAL | VOID_TAG + 'frameset' => 1, + 'center' => 16, + 'dir' => 16, + 'listing' => 16, // AUTOCLOSE_P + 'plaintext' => 48, // AUTOCLOSE_P | TEXT_PLAINTEXT + 'applet' => 0, + 'marquee' => 0, + 'isindex' => 8, // VOID_TAG + 'xmp' => 20, // AUTOCLOSE_P | VOID_TAG | RAW_TEXT + 'noembed' => 2, // RAW_TEXT + ); + + /** + * The MathML elements. + * See http://www.w3.org/wiki/MathML/Elements. + * + * In our case we are only concerned with presentation MathML and not content + * MathML. There is a nice list of this subset at https://developer.mozilla.org/en-US/docs/MathML/Element. + * + * @var array + */ + public static $mathml = array( + 'maction' => 1, + 'maligngroup' => 1, + 'malignmark' => 1, + 'math' => 1, + 'menclose' => 1, + 'merror' => 1, + 'mfenced' => 1, + 'mfrac' => 1, + 'mglyph' => 1, + 'mi' => 1, + 'mlabeledtr' => 1, + 'mlongdiv' => 1, + 'mmultiscripts' => 1, + 'mn' => 1, + 'mo' => 1, + 'mover' => 1, + 'mpadded' => 1, + 'mphantom' => 1, + 'mroot' => 1, + 'mrow' => 1, + 'ms' => 1, + 'mscarries' => 1, + 'mscarry' => 1, + 'msgroup' => 1, + 'msline' => 1, + 'mspace' => 1, + 'msqrt' => 1, + 'msrow' => 1, + 'mstack' => 1, + 'mstyle' => 1, + 'msub' => 1, + 'msup' => 1, + 'msubsup' => 1, + 'mtable' => 1, + 'mtd' => 1, + 'mtext' => 1, + 'mtr' => 1, + 'munder' => 1, + 'munderover' => 1, + ); + + /** + * The svg elements. + * + * The Mozilla documentation has a good list at https://developer.mozilla.org/en-US/docs/SVG/Element. + * The w3c list appears to be lacking in some areas like filter effect elements. + * That list can be found at http://www.w3.org/wiki/SVG/Elements. + * + * Note, FireFox appears to do a better job rendering filter effects than chrome. + * While they are in the spec I'm not sure how widely implemented they are. + * + * @var array + */ + public static $svg = array( + 'a' => 1, + 'altGlyph' => 1, + 'altGlyphDef' => 1, + 'altGlyphItem' => 1, + 'animate' => 1, + 'animateColor' => 1, + 'animateMotion' => 1, + 'animateTransform' => 1, + 'circle' => 1, + 'clipPath' => 1, + 'color-profile' => 1, + 'cursor' => 1, + 'defs' => 1, + 'desc' => 1, + 'ellipse' => 1, + 'feBlend' => 1, + 'feColorMatrix' => 1, + 'feComponentTransfer' => 1, + 'feComposite' => 1, + 'feConvolveMatrix' => 1, + 'feDiffuseLighting' => 1, + 'feDisplacementMap' => 1, + 'feDistantLight' => 1, + 'feFlood' => 1, + 'feFuncA' => 1, + 'feFuncB' => 1, + 'feFuncG' => 1, + 'feFuncR' => 1, + 'feGaussianBlur' => 1, + 'feImage' => 1, + 'feMerge' => 1, + 'feMergeNode' => 1, + 'feMorphology' => 1, + 'feOffset' => 1, + 'fePointLight' => 1, + 'feSpecularLighting' => 1, + 'feSpotLight' => 1, + 'feTile' => 1, + 'feTurbulence' => 1, + 'filter' => 1, + 'font' => 1, + 'font-face' => 1, + 'font-face-format' => 1, + 'font-face-name' => 1, + 'font-face-src' => 1, + 'font-face-uri' => 1, + 'foreignObject' => 1, + 'g' => 1, + 'glyph' => 1, + 'glyphRef' => 1, + 'hkern' => 1, + 'image' => 1, + 'line' => 1, + 'linearGradient' => 1, + 'marker' => 1, + 'mask' => 1, + 'metadata' => 1, + 'missing-glyph' => 1, + 'mpath' => 1, + 'path' => 1, + 'pattern' => 1, + 'polygon' => 1, + 'polyline' => 1, + 'radialGradient' => 1, + 'rect' => 1, + 'script' => 3, // NORMAL | RAW_TEXT + 'set' => 1, + 'stop' => 1, + 'style' => 3, // NORMAL | RAW_TEXT + 'svg' => 1, + 'switch' => 1, + 'symbol' => 1, + 'text' => 1, + 'textPath' => 1, + 'title' => 1, + 'tref' => 1, + 'tspan' => 1, + 'use' => 1, + 'view' => 1, + 'vkern' => 1, + ); + + /** + * Some attributes in SVG are case sensitive. + * + * This map contains key/value pairs with the key as the lowercase attribute + * name and the value with the correct casing. + */ + public static $svgCaseSensitiveAttributeMap = array( + 'attributename' => 'attributeName', + 'attributetype' => 'attributeType', + 'basefrequency' => 'baseFrequency', + 'baseprofile' => 'baseProfile', + 'calcmode' => 'calcMode', + 'clippathunits' => 'clipPathUnits', + 'contentscripttype' => 'contentScriptType', + 'contentstyletype' => 'contentStyleType', + 'diffuseconstant' => 'diffuseConstant', + 'edgemode' => 'edgeMode', + 'externalresourcesrequired' => 'externalResourcesRequired', + 'filterres' => 'filterRes', + 'filterunits' => 'filterUnits', + 'glyphref' => 'glyphRef', + 'gradienttransform' => 'gradientTransform', + 'gradientunits' => 'gradientUnits', + 'kernelmatrix' => 'kernelMatrix', + 'kernelunitlength' => 'kernelUnitLength', + 'keypoints' => 'keyPoints', + 'keysplines' => 'keySplines', + 'keytimes' => 'keyTimes', + 'lengthadjust' => 'lengthAdjust', + 'limitingconeangle' => 'limitingConeAngle', + 'markerheight' => 'markerHeight', + 'markerunits' => 'markerUnits', + 'markerwidth' => 'markerWidth', + 'maskcontentunits' => 'maskContentUnits', + 'maskunits' => 'maskUnits', + 'numoctaves' => 'numOctaves', + 'pathlength' => 'pathLength', + 'patterncontentunits' => 'patternContentUnits', + 'patterntransform' => 'patternTransform', + 'patternunits' => 'patternUnits', + 'pointsatx' => 'pointsAtX', + 'pointsaty' => 'pointsAtY', + 'pointsatz' => 'pointsAtZ', + 'preservealpha' => 'preserveAlpha', + 'preserveaspectratio' => 'preserveAspectRatio', + 'primitiveunits' => 'primitiveUnits', + 'refx' => 'refX', + 'refy' => 'refY', + 'repeatcount' => 'repeatCount', + 'repeatdur' => 'repeatDur', + 'requiredextensions' => 'requiredExtensions', + 'requiredfeatures' => 'requiredFeatures', + 'specularconstant' => 'specularConstant', + 'specularexponent' => 'specularExponent', + 'spreadmethod' => 'spreadMethod', + 'startoffset' => 'startOffset', + 'stddeviation' => 'stdDeviation', + 'stitchtiles' => 'stitchTiles', + 'surfacescale' => 'surfaceScale', + 'systemlanguage' => 'systemLanguage', + 'tablevalues' => 'tableValues', + 'targetx' => 'targetX', + 'targety' => 'targetY', + 'textlength' => 'textLength', + 'viewbox' => 'viewBox', + 'viewtarget' => 'viewTarget', + 'xchannelselector' => 'xChannelSelector', + 'ychannelselector' => 'yChannelSelector', + 'zoomandpan' => 'zoomAndPan', + ); + + /** + * Some SVG elements are case sensitive. + * This map contains these. + * + * The map contains key/value store of the name is lowercase as the keys and + * the correct casing as the value. + */ + public static $svgCaseSensitiveElementMap = array( + 'altglyph' => 'altGlyph', + 'altglyphdef' => 'altGlyphDef', + 'altglyphitem' => 'altGlyphItem', + 'animatecolor' => 'animateColor', + 'animatemotion' => 'animateMotion', + 'animatetransform' => 'animateTransform', + 'clippath' => 'clipPath', + 'feblend' => 'feBlend', + 'fecolormatrix' => 'feColorMatrix', + 'fecomponenttransfer' => 'feComponentTransfer', + 'fecomposite' => 'feComposite', + 'feconvolvematrix' => 'feConvolveMatrix', + 'fediffuselighting' => 'feDiffuseLighting', + 'fedisplacementmap' => 'feDisplacementMap', + 'fedistantlight' => 'feDistantLight', + 'feflood' => 'feFlood', + 'fefunca' => 'feFuncA', + 'fefuncb' => 'feFuncB', + 'fefuncg' => 'feFuncG', + 'fefuncr' => 'feFuncR', + 'fegaussianblur' => 'feGaussianBlur', + 'feimage' => 'feImage', + 'femerge' => 'feMerge', + 'femergenode' => 'feMergeNode', + 'femorphology' => 'feMorphology', + 'feoffset' => 'feOffset', + 'fepointlight' => 'fePointLight', + 'fespecularlighting' => 'feSpecularLighting', + 'fespotlight' => 'feSpotLight', + 'fetile' => 'feTile', + 'feturbulence' => 'feTurbulence', + 'foreignobject' => 'foreignObject', + 'glyphref' => 'glyphRef', + 'lineargradient' => 'linearGradient', + 'radialgradient' => 'radialGradient', + 'textpath' => 'textPath', + ); + + /** + * Check whether the given element meets the given criterion. + * + * Example: + * + * Elements::isA('script', Elements::TEXT_RAW); // Returns true. + * + * Elements::isA('script', Elements::TEXT_RCDATA); // Returns false. + * + * @param string $name The element name. + * @param int $mask One of the constants on this class. + * + * @return bool true if the element matches the mask, false otherwise. + */ + public static function isA($name, $mask) + { + return (static::element($name) & $mask) === $mask; + } + + /** + * Test if an element is a valid html5 element. + * + * @param string $name The name of the element. + * + * @return bool true if a html5 element and false otherwise. + */ + public static function isHtml5Element($name) + { + // html5 element names are case insensitive. Forcing lowercase for the check. + // Do we need this check or will all data passed here already be lowercase? + return isset(static::$html5[strtolower($name)]); + } + + /** + * Test if an element name is a valid MathML presentation element. + * + * @param string $name The name of the element. + * + * @return bool true if a MathML name and false otherwise. + */ + public static function isMathMLElement($name) + { + // MathML is case-sensitive unlike html5 elements. + return isset(static::$mathml[$name]); + } + + /** + * Test if an element is a valid SVG element. + * + * @param string $name The name of the element. + * + * @return bool true if a SVG element and false otherise. + */ + public static function isSvgElement($name) + { + // SVG is case-sensitive unlike html5 elements. + return isset(static::$svg[$name]); + } + + /** + * Is an element name valid in an html5 document. + * This includes html5 elements along with other allowed embedded content + * such as svg and mathml. + * + * @param string $name The name of the element. + * + * @return bool true if valid and false otherwise. + */ + public static function isElement($name) + { + return static::isHtml5Element($name) || static::isMathMLElement($name) || static::isSvgElement($name); + } + + /** + * Get the element mask for the given element name. + * + * @param string $name The name of the element. + * + * @return int the element mask. + */ + public static function element($name) + { + if (isset(static::$html5[$name])) { + return static::$html5[$name]; + } + if (isset(static::$svg[$name])) { + return static::$svg[$name]; + } + if (isset(static::$mathml[$name])) { + return static::$mathml[$name]; + } + + return 0; + } + + /** + * Normalize a SVG element name to its proper case and form. + * + * @param string $name The name of the element. + * + * @return string the normalized form of the element name. + */ + public static function normalizeSvgElement($name) + { + $name = strtolower($name); + if (isset(static::$svgCaseSensitiveElementMap[$name])) { + $name = static::$svgCaseSensitiveElementMap[$name]; + } + + return $name; + } + + /** + * Normalize a SVG attribute name to its proper case and form. + * + * @param string $name The name of the attribute. + * + * @return string The normalized form of the attribute name. + */ + public static function normalizeSvgAttribute($name) + { + $name = strtolower($name); + if (isset(static::$svgCaseSensitiveAttributeMap[$name])) { + $name = static::$svgCaseSensitiveAttributeMap[$name]; + } + + return $name; + } + + /** + * Normalize a MathML attribute name to its proper case and form. + * Note, all MathML element names are lowercase. + * + * @param string $name The name of the attribute. + * + * @return string The normalized form of the attribute name. + */ + public static function normalizeMathMlAttribute($name) + { + $name = strtolower($name); + + // Only one attribute has a mixed case form for MathML. + if ('definitionurl' === $name) { + $name = 'definitionURL'; + } + + return $name; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Entities.php b/vendor/masterminds/html5/src/HTML5/Entities.php new file mode 100644 index 000000000..0e7227dc1 --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Entities.php @@ -0,0 +1,2236 @@ + 'Á', + 'Aacut' => 'Á', + 'aacute' => 'á', + 'aacut' => 'á', + 'Abreve' => 'Ă', + 'abreve' => 'ă', + 'ac' => '∾', + 'acd' => '∿', + 'acE' => '∾̳', + 'Acirc' => 'Â', + 'Acir' => 'Â', + 'acirc' => 'â', + 'acir' => 'â', + 'acute' => '´', + 'acut' => '´', + 'Acy' => 'А', + 'acy' => 'а', + 'AElig' => 'Æ', + 'AEli' => 'Æ', + 'aelig' => 'æ', + 'aeli' => 'æ', + 'af' => '⁡', + 'Afr' => '𝔄', + 'afr' => '𝔞', + 'Agrave' => 'À', + 'Agrav' => 'À', + 'agrave' => 'à', + 'agrav' => 'à', + 'alefsym' => 'ℵ', + 'aleph' => 'ℵ', + 'Alpha' => 'Α', + 'alpha' => 'α', + 'Amacr' => 'Ā', + 'amacr' => 'ā', + 'amalg' => '⨿', + 'AMP' => '&', + 'AM' => '&', + 'amp' => '&', + 'am' => '&', + 'And' => '⩓', + 'and' => '∧', + 'andand' => '⩕', + 'andd' => '⩜', + 'andslope' => '⩘', + 'andv' => '⩚', + 'ang' => '∠', + 'ange' => '⦤', + 'angle' => '∠', + 'angmsd' => '∡', + 'angmsdaa' => '⦨', + 'angmsdab' => '⦩', + 'angmsdac' => '⦪', + 'angmsdad' => '⦫', + 'angmsdae' => '⦬', + 'angmsdaf' => '⦭', + 'angmsdag' => '⦮', + 'angmsdah' => '⦯', + 'angrt' => '∟', + 'angrtvb' => '⊾', + 'angrtvbd' => '⦝', + 'angsph' => '∢', + 'angst' => 'Å', + 'angzarr' => '⍼', + 'Aogon' => 'Ą', + 'aogon' => 'ą', + 'Aopf' => '𝔸', + 'aopf' => '𝕒', + 'ap' => '≈', + 'apacir' => '⩯', + 'apE' => '⩰', + 'ape' => '≊', + 'apid' => '≋', + 'apos' => '\'', + 'ApplyFunction' => '⁡', + 'approx' => '≈', + 'approxeq' => '≊', + 'Aring' => 'Å', + 'Arin' => 'Å', + 'aring' => 'å', + 'arin' => 'å', + 'Ascr' => '𝒜', + 'ascr' => '𝒶', + 'Assign' => '≔', + 'ast' => '*', + 'asymp' => '≈', + 'asympeq' => '≍', + 'Atilde' => 'Ã', + 'Atild' => 'Ã', + 'atilde' => 'ã', + 'atild' => 'ã', + 'Auml' => 'Ä', + 'Aum' => 'Ä', + 'auml' => 'ä', + 'aum' => 'ä', + 'awconint' => '∳', + 'awint' => '⨑', + 'backcong' => '≌', + 'backepsilon' => '϶', + 'backprime' => '‵', + 'backsim' => '∽', + 'backsimeq' => '⋍', + 'Backslash' => '∖', + 'Barv' => '⫧', + 'barvee' => '⊽', + 'Barwed' => '⌆', + 'barwed' => '⌅', + 'barwedge' => '⌅', + 'bbrk' => '⎵', + 'bbrktbrk' => '⎶', + 'bcong' => '≌', + 'Bcy' => 'Б', + 'bcy' => 'б', + 'bdquo' => '„', + 'becaus' => '∵', + 'Because' => '∵', + 'because' => '∵', + 'bemptyv' => '⦰', + 'bepsi' => '϶', + 'bernou' => 'ℬ', + 'Bernoullis' => 'ℬ', + 'Beta' => 'Β', + 'beta' => 'β', + 'beth' => 'ℶ', + 'between' => '≬', + 'Bfr' => '𝔅', + 'bfr' => '𝔟', + 'bigcap' => '⋂', + 'bigcirc' => '◯', + 'bigcup' => '⋃', + 'bigodot' => '⨀', + 'bigoplus' => '⨁', + 'bigotimes' => '⨂', + 'bigsqcup' => '⨆', + 'bigstar' => '★', + 'bigtriangledown' => '▽', + 'bigtriangleup' => '△', + 'biguplus' => '⨄', + 'bigvee' => '⋁', + 'bigwedge' => '⋀', + 'bkarow' => '⤍', + 'blacklozenge' => '⧫', + 'blacksquare' => '▪', + 'blacktriangle' => '▴', + 'blacktriangledown' => '▾', + 'blacktriangleleft' => '◂', + 'blacktriangleright' => '▸', + 'blank' => '␣', + 'blk12' => '▒', + 'blk14' => '░', + 'blk34' => '▓', + 'block' => '█', + 'bne' => '=⃥', + 'bnequiv' => '≡⃥', + 'bNot' => '⫭', + 'bnot' => '⌐', + 'Bopf' => '𝔹', + 'bopf' => '𝕓', + 'bot' => '⊥', + 'bottom' => '⊥', + 'bowtie' => '⋈', + 'boxbox' => '⧉', + 'boxDL' => '╗', + 'boxDl' => '╖', + 'boxdL' => '╕', + 'boxdl' => '┐', + 'boxDR' => '╔', + 'boxDr' => '╓', + 'boxdR' => '╒', + 'boxdr' => '┌', + 'boxH' => '═', + 'boxh' => '─', + 'boxHD' => '╦', + 'boxHd' => '╤', + 'boxhD' => '╥', + 'boxhd' => '┬', + 'boxHU' => '╩', + 'boxHu' => '╧', + 'boxhU' => '╨', + 'boxhu' => '┴', + 'boxminus' => '⊟', + 'boxplus' => '⊞', + 'boxtimes' => '⊠', + 'boxUL' => '╝', + 'boxUl' => '╜', + 'boxuL' => '╛', + 'boxul' => '┘', + 'boxUR' => '╚', + 'boxUr' => '╙', + 'boxuR' => '╘', + 'boxur' => '└', + 'boxV' => '║', + 'boxv' => '│', + 'boxVH' => '╬', + 'boxVh' => '╫', + 'boxvH' => '╪', + 'boxvh' => '┼', + 'boxVL' => '╣', + 'boxVl' => '╢', + 'boxvL' => '╡', + 'boxvl' => '┤', + 'boxVR' => '╠', + 'boxVr' => '╟', + 'boxvR' => '╞', + 'boxvr' => '├', + 'bprime' => '‵', + 'Breve' => '˘', + 'breve' => '˘', + 'brvbar' => '¦', + 'brvba' => '¦', + 'Bscr' => 'ℬ', + 'bscr' => '𝒷', + 'bsemi' => '⁏', + 'bsim' => '∽', + 'bsime' => '⋍', + 'bsol' => '\\', + 'bsolb' => '⧅', + 'bsolhsub' => '⟈', + 'bull' => '•', + 'bullet' => '•', + 'bump' => '≎', + 'bumpE' => '⪮', + 'bumpe' => '≏', + 'Bumpeq' => '≎', + 'bumpeq' => '≏', + 'Cacute' => 'Ć', + 'cacute' => 'ć', + 'Cap' => '⋒', + 'cap' => '∩', + 'capand' => '⩄', + 'capbrcup' => '⩉', + 'capcap' => '⩋', + 'capcup' => '⩇', + 'capdot' => '⩀', + 'CapitalDifferentialD' => 'ⅅ', + 'caps' => '∩︀', + 'caret' => '⁁', + 'caron' => 'ˇ', + 'Cayleys' => 'ℭ', + 'ccaps' => '⩍', + 'Ccaron' => 'Č', + 'ccaron' => 'č', + 'Ccedil' => 'Ç', + 'Ccedi' => 'Ç', + 'ccedil' => 'ç', + 'ccedi' => 'ç', + 'Ccirc' => 'Ĉ', + 'ccirc' => 'ĉ', + 'Cconint' => '∰', + 'ccups' => '⩌', + 'ccupssm' => '⩐', + 'Cdot' => 'Ċ', + 'cdot' => 'ċ', + 'cedil' => '¸', + 'cedi' => '¸', + 'Cedilla' => '¸', + 'cemptyv' => '⦲', + 'cent' => '¢', + 'cen' => '¢', + 'CenterDot' => '·', + 'centerdot' => '·', + 'Cfr' => 'ℭ', + 'cfr' => '𝔠', + 'CHcy' => 'Ч', + 'chcy' => 'ч', + 'check' => '✓', + 'checkmark' => '✓', + 'Chi' => 'Χ', + 'chi' => 'χ', + 'cir' => '○', + 'circ' => 'ˆ', + 'circeq' => '≗', + 'circlearrowleft' => '↺', + 'circlearrowright' => '↻', + 'circledast' => '⊛', + 'circledcirc' => '⊚', + 'circleddash' => '⊝', + 'CircleDot' => '⊙', + 'circledR' => '®', + 'circledS' => 'Ⓢ', + 'CircleMinus' => '⊖', + 'CirclePlus' => '⊕', + 'CircleTimes' => '⊗', + 'cirE' => '⧃', + 'cire' => '≗', + 'cirfnint' => '⨐', + 'cirmid' => '⫯', + 'cirscir' => '⧂', + 'ClockwiseContourIntegral' => '∲', + 'CloseCurlyDoubleQuote' => '”', + 'CloseCurlyQuote' => '’', + 'clubs' => '♣', + 'clubsuit' => '♣', + 'Colon' => '∷', + 'colon' => ':', + 'Colone' => '⩴', + 'colone' => '≔', + 'coloneq' => '≔', + 'comma' => ',', + 'commat' => '@', + 'comp' => '∁', + 'compfn' => '∘', + 'complement' => '∁', + 'complexes' => 'ℂ', + 'cong' => '≅', + 'congdot' => '⩭', + 'Congruent' => '≡', + 'Conint' => '∯', + 'conint' => '∮', + 'ContourIntegral' => '∮', + 'Copf' => 'ℂ', + 'copf' => '𝕔', + 'coprod' => '∐', + 'Coproduct' => '∐', + 'COPY' => '©', + 'COP' => '©', + 'copy' => '©', + 'cop' => '©', + 'copysr' => '℗', + 'CounterClockwiseContourIntegral' => '∳', + 'crarr' => '↵', + 'Cross' => '⨯', + 'cross' => '✗', + 'Cscr' => '𝒞', + 'cscr' => '𝒸', + 'csub' => '⫏', + 'csube' => '⫑', + 'csup' => '⫐', + 'csupe' => '⫒', + 'ctdot' => '⋯', + 'cudarrl' => '⤸', + 'cudarrr' => '⤵', + 'cuepr' => '⋞', + 'cuesc' => '⋟', + 'cularr' => '↶', + 'cularrp' => '⤽', + 'Cup' => '⋓', + 'cup' => '∪', + 'cupbrcap' => '⩈', + 'CupCap' => '≍', + 'cupcap' => '⩆', + 'cupcup' => '⩊', + 'cupdot' => '⊍', + 'cupor' => '⩅', + 'cups' => '∪︀', + 'curarr' => '↷', + 'curarrm' => '⤼', + 'curlyeqprec' => '⋞', + 'curlyeqsucc' => '⋟', + 'curlyvee' => '⋎', + 'curlywedge' => '⋏', + 'curren' => '¤', + 'curre' => '¤', + 'curvearrowleft' => '↶', + 'curvearrowright' => '↷', + 'cuvee' => '⋎', + 'cuwed' => '⋏', + 'cwconint' => '∲', + 'cwint' => '∱', + 'cylcty' => '⌭', + 'Dagger' => '‡', + 'dagger' => '†', + 'daleth' => 'ℸ', + 'Darr' => '↡', + 'dArr' => '⇓', + 'darr' => '↓', + 'dash' => '‐', + 'Dashv' => '⫤', + 'dashv' => '⊣', + 'dbkarow' => '⤏', + 'dblac' => '˝', + 'Dcaron' => 'Ď', + 'dcaron' => 'ď', + 'Dcy' => 'Д', + 'dcy' => 'д', + 'DD' => 'ⅅ', + 'dd' => 'ⅆ', + 'ddagger' => '‡', + 'ddarr' => '⇊', + 'DDotrahd' => '⤑', + 'ddotseq' => '⩷', + 'deg' => '°', + 'de' => '°', + 'Del' => '∇', + 'Delta' => 'Δ', + 'delta' => 'δ', + 'demptyv' => '⦱', + 'dfisht' => '⥿', + 'Dfr' => '𝔇', + 'dfr' => '𝔡', + 'dHar' => '⥥', + 'dharl' => '⇃', + 'dharr' => '⇂', + 'DiacriticalAcute' => '´', + 'DiacriticalDot' => '˙', + 'DiacriticalDoubleAcute' => '˝', + 'DiacriticalGrave' => '`', + 'DiacriticalTilde' => '˜', + 'diam' => '⋄', + 'Diamond' => '⋄', + 'diamond' => '⋄', + 'diamondsuit' => '♦', + 'diams' => '♦', + 'die' => '¨', + 'DifferentialD' => 'ⅆ', + 'digamma' => 'ϝ', + 'disin' => '⋲', + 'div' => '÷', + 'divide' => '÷', + 'divid' => '÷', + 'divideontimes' => '⋇', + 'divonx' => '⋇', + 'DJcy' => 'Ђ', + 'djcy' => 'ђ', + 'dlcorn' => '⌞', + 'dlcrop' => '⌍', + 'dollar' => '$', + 'Dopf' => '𝔻', + 'dopf' => '𝕕', + 'Dot' => '¨', + 'dot' => '˙', + 'DotDot' => '⃜', + 'doteq' => '≐', + 'doteqdot' => '≑', + 'DotEqual' => '≐', + 'dotminus' => '∸', + 'dotplus' => '∔', + 'dotsquare' => '⊡', + 'doublebarwedge' => '⌆', + 'DoubleContourIntegral' => '∯', + 'DoubleDot' => '¨', + 'DoubleDownArrow' => '⇓', + 'DoubleLeftArrow' => '⇐', + 'DoubleLeftRightArrow' => '⇔', + 'DoubleLeftTee' => '⫤', + 'DoubleLongLeftArrow' => '⟸', + 'DoubleLongLeftRightArrow' => '⟺', + 'DoubleLongRightArrow' => '⟹', + 'DoubleRightArrow' => '⇒', + 'DoubleRightTee' => '⊨', + 'DoubleUpArrow' => '⇑', + 'DoubleUpDownArrow' => '⇕', + 'DoubleVerticalBar' => '∥', + 'DownArrow' => '↓', + 'Downarrow' => '⇓', + 'downarrow' => '↓', + 'DownArrowBar' => '⤓', + 'DownArrowUpArrow' => '⇵', + 'DownBreve' => '̑', + 'downdownarrows' => '⇊', + 'downharpoonleft' => '⇃', + 'downharpoonright' => '⇂', + 'DownLeftRightVector' => '⥐', + 'DownLeftTeeVector' => '⥞', + 'DownLeftVector' => '↽', + 'DownLeftVectorBar' => '⥖', + 'DownRightTeeVector' => '⥟', + 'DownRightVector' => '⇁', + 'DownRightVectorBar' => '⥗', + 'DownTee' => '⊤', + 'DownTeeArrow' => '↧', + 'drbkarow' => '⤐', + 'drcorn' => '⌟', + 'drcrop' => '⌌', + 'Dscr' => '𝒟', + 'dscr' => '𝒹', + 'DScy' => 'Ѕ', + 'dscy' => 'ѕ', + 'dsol' => '⧶', + 'Dstrok' => 'Đ', + 'dstrok' => 'đ', + 'dtdot' => '⋱', + 'dtri' => '▿', + 'dtrif' => '▾', + 'duarr' => '⇵', + 'duhar' => '⥯', + 'dwangle' => '⦦', + 'DZcy' => 'Џ', + 'dzcy' => 'џ', + 'dzigrarr' => '⟿', + 'Eacute' => 'É', + 'Eacut' => 'É', + 'eacute' => 'é', + 'eacut' => 'é', + 'easter' => '⩮', + 'Ecaron' => 'Ě', + 'ecaron' => 'ě', + 'ecir' => 'ê', + 'Ecirc' => 'Ê', + 'Ecir' => 'Ê', + 'ecirc' => 'ê', + 'ecolon' => '≕', + 'Ecy' => 'Э', + 'ecy' => 'э', + 'eDDot' => '⩷', + 'Edot' => 'Ė', + 'eDot' => '≑', + 'edot' => 'ė', + 'ee' => 'ⅇ', + 'efDot' => '≒', + 'Efr' => '𝔈', + 'efr' => '𝔢', + 'eg' => '⪚', + 'Egrave' => 'È', + 'Egrav' => 'È', + 'egrave' => 'è', + 'egrav' => 'è', + 'egs' => '⪖', + 'egsdot' => '⪘', + 'el' => '⪙', + 'Element' => '∈', + 'elinters' => '⏧', + 'ell' => 'ℓ', + 'els' => '⪕', + 'elsdot' => '⪗', + 'Emacr' => 'Ē', + 'emacr' => 'ē', + 'empty' => '∅', + 'emptyset' => '∅', + 'EmptySmallSquare' => '◻', + 'emptyv' => '∅', + 'EmptyVerySmallSquare' => '▫', + 'emsp' => ' ', + 'emsp13' => ' ', + 'emsp14' => ' ', + 'ENG' => 'Ŋ', + 'eng' => 'ŋ', + 'ensp' => ' ', + 'Eogon' => 'Ę', + 'eogon' => 'ę', + 'Eopf' => '𝔼', + 'eopf' => '𝕖', + 'epar' => '⋕', + 'eparsl' => '⧣', + 'eplus' => '⩱', + 'epsi' => 'ε', + 'Epsilon' => 'Ε', + 'epsilon' => 'ε', + 'epsiv' => 'ϵ', + 'eqcirc' => '≖', + 'eqcolon' => '≕', + 'eqsim' => '≂', + 'eqslantgtr' => '⪖', + 'eqslantless' => '⪕', + 'Equal' => '⩵', + 'equals' => '=', + 'EqualTilde' => '≂', + 'equest' => '≟', + 'Equilibrium' => '⇌', + 'equiv' => '≡', + 'equivDD' => '⩸', + 'eqvparsl' => '⧥', + 'erarr' => '⥱', + 'erDot' => '≓', + 'Escr' => 'ℰ', + 'escr' => 'ℯ', + 'esdot' => '≐', + 'Esim' => '⩳', + 'esim' => '≂', + 'Eta' => 'Η', + 'eta' => 'η', + 'ETH' => 'Ð', + 'ET' => 'Ð', + 'eth' => 'ð', + 'et' => 'ð', + 'Euml' => 'Ë', + 'Eum' => 'Ë', + 'euml' => 'ë', + 'eum' => 'ë', + 'euro' => '€', + 'excl' => '!', + 'exist' => '∃', + 'Exists' => '∃', + 'expectation' => 'ℰ', + 'ExponentialE' => 'ⅇ', + 'exponentiale' => 'ⅇ', + 'fallingdotseq' => '≒', + 'Fcy' => 'Ф', + 'fcy' => 'ф', + 'female' => '♀', + 'ffilig' => 'ffi', + 'fflig' => 'ff', + 'ffllig' => 'ffl', + 'Ffr' => '𝔉', + 'ffr' => '𝔣', + 'filig' => 'fi', + 'FilledSmallSquare' => '◼', + 'FilledVerySmallSquare' => '▪', + 'fjlig' => 'fj', + 'flat' => '♭', + 'fllig' => 'fl', + 'fltns' => '▱', + 'fnof' => 'ƒ', + 'Fopf' => '𝔽', + 'fopf' => '𝕗', + 'ForAll' => '∀', + 'forall' => '∀', + 'fork' => '⋔', + 'forkv' => '⫙', + 'Fouriertrf' => 'ℱ', + 'fpartint' => '⨍', + 'frac12' => '½', + 'frac1' => '¼', + 'frac13' => '⅓', + 'frac14' => '¼', + 'frac15' => '⅕', + 'frac16' => '⅙', + 'frac18' => '⅛', + 'frac23' => '⅔', + 'frac25' => '⅖', + 'frac34' => '¾', + 'frac3' => '¾', + 'frac35' => '⅗', + 'frac38' => '⅜', + 'frac45' => '⅘', + 'frac56' => '⅚', + 'frac58' => '⅝', + 'frac78' => '⅞', + 'frasl' => '⁄', + 'frown' => '⌢', + 'Fscr' => 'ℱ', + 'fscr' => '𝒻', + 'gacute' => 'ǵ', + 'Gamma' => 'Γ', + 'gamma' => 'γ', + 'Gammad' => 'Ϝ', + 'gammad' => 'ϝ', + 'gap' => '⪆', + 'Gbreve' => 'Ğ', + 'gbreve' => 'ğ', + 'Gcedil' => 'Ģ', + 'Gcirc' => 'Ĝ', + 'gcirc' => 'ĝ', + 'Gcy' => 'Г', + 'gcy' => 'г', + 'Gdot' => 'Ġ', + 'gdot' => 'ġ', + 'gE' => '≧', + 'ge' => '≥', + 'gEl' => '⪌', + 'gel' => '⋛', + 'geq' => '≥', + 'geqq' => '≧', + 'geqslant' => '⩾', + 'ges' => '⩾', + 'gescc' => '⪩', + 'gesdot' => '⪀', + 'gesdoto' => '⪂', + 'gesdotol' => '⪄', + 'gesl' => '⋛︀', + 'gesles' => '⪔', + 'Gfr' => '𝔊', + 'gfr' => '𝔤', + 'Gg' => '⋙', + 'gg' => '≫', + 'ggg' => '⋙', + 'gimel' => 'ℷ', + 'GJcy' => 'Ѓ', + 'gjcy' => 'ѓ', + 'gl' => '≷', + 'gla' => '⪥', + 'glE' => '⪒', + 'glj' => '⪤', + 'gnap' => '⪊', + 'gnapprox' => '⪊', + 'gnE' => '≩', + 'gne' => '⪈', + 'gneq' => '⪈', + 'gneqq' => '≩', + 'gnsim' => '⋧', + 'Gopf' => '𝔾', + 'gopf' => '𝕘', + 'grave' => '`', + 'GreaterEqual' => '≥', + 'GreaterEqualLess' => '⋛', + 'GreaterFullEqual' => '≧', + 'GreaterGreater' => '⪢', + 'GreaterLess' => '≷', + 'GreaterSlantEqual' => '⩾', + 'GreaterTilde' => '≳', + 'Gscr' => '𝒢', + 'gscr' => 'ℊ', + 'gsim' => '≳', + 'gsime' => '⪎', + 'gsiml' => '⪐', + 'GT' => '>', + 'G' => '>', + 'Gt' => '≫', + 'gt' => '>', + 'g' => '>', + 'gtcc' => '⪧', + 'gtcir' => '⩺', + 'gtdot' => '⋗', + 'gtlPar' => '⦕', + 'gtquest' => '⩼', + 'gtrapprox' => '⪆', + 'gtrarr' => '⥸', + 'gtrdot' => '⋗', + 'gtreqless' => '⋛', + 'gtreqqless' => '⪌', + 'gtrless' => '≷', + 'gtrsim' => '≳', + 'gvertneqq' => '≩︀', + 'gvnE' => '≩︀', + 'Hacek' => 'ˇ', + 'hairsp' => ' ', + 'half' => '½', + 'hamilt' => 'ℋ', + 'HARDcy' => 'Ъ', + 'hardcy' => 'ъ', + 'hArr' => '⇔', + 'harr' => '↔', + 'harrcir' => '⥈', + 'harrw' => '↭', + 'Hat' => '^', + 'hbar' => 'ℏ', + 'Hcirc' => 'Ĥ', + 'hcirc' => 'ĥ', + 'hearts' => '♥', + 'heartsuit' => '♥', + 'hellip' => '…', + 'hercon' => '⊹', + 'Hfr' => 'ℌ', + 'hfr' => '𝔥', + 'HilbertSpace' => 'ℋ', + 'hksearow' => '⤥', + 'hkswarow' => '⤦', + 'hoarr' => '⇿', + 'homtht' => '∻', + 'hookleftarrow' => '↩', + 'hookrightarrow' => '↪', + 'Hopf' => 'ℍ', + 'hopf' => '𝕙', + 'horbar' => '―', + 'HorizontalLine' => '─', + 'Hscr' => 'ℋ', + 'hscr' => '𝒽', + 'hslash' => 'ℏ', + 'Hstrok' => 'Ħ', + 'hstrok' => 'ħ', + 'HumpDownHump' => '≎', + 'HumpEqual' => '≏', + 'hybull' => '⁃', + 'hyphen' => '‐', + 'Iacute' => 'Í', + 'Iacut' => 'Í', + 'iacute' => 'í', + 'iacut' => 'í', + 'ic' => '⁣', + 'Icirc' => 'Î', + 'Icir' => 'Î', + 'icirc' => 'î', + 'icir' => 'î', + 'Icy' => 'И', + 'icy' => 'и', + 'Idot' => 'İ', + 'IEcy' => 'Е', + 'iecy' => 'е', + 'iexcl' => '¡', + 'iexc' => '¡', + 'iff' => '⇔', + 'Ifr' => 'ℑ', + 'ifr' => '𝔦', + 'Igrave' => 'Ì', + 'Igrav' => 'Ì', + 'igrave' => 'ì', + 'igrav' => 'ì', + 'ii' => 'ⅈ', + 'iiiint' => '⨌', + 'iiint' => '∭', + 'iinfin' => '⧜', + 'iiota' => '℩', + 'IJlig' => 'IJ', + 'ijlig' => 'ij', + 'Im' => 'ℑ', + 'Imacr' => 'Ī', + 'imacr' => 'ī', + 'image' => 'ℑ', + 'ImaginaryI' => 'ⅈ', + 'imagline' => 'ℐ', + 'imagpart' => 'ℑ', + 'imath' => 'ı', + 'imof' => '⊷', + 'imped' => 'Ƶ', + 'Implies' => '⇒', + 'in' => '∈', + 'incare' => '℅', + 'infin' => '∞', + 'infintie' => '⧝', + 'inodot' => 'ı', + 'Int' => '∬', + 'int' => '∫', + 'intcal' => '⊺', + 'integers' => 'ℤ', + 'Integral' => '∫', + 'intercal' => '⊺', + 'Intersection' => '⋂', + 'intlarhk' => '⨗', + 'intprod' => '⨼', + 'InvisibleComma' => '⁣', + 'InvisibleTimes' => '⁢', + 'IOcy' => 'Ё', + 'iocy' => 'ё', + 'Iogon' => 'Į', + 'iogon' => 'į', + 'Iopf' => '𝕀', + 'iopf' => '𝕚', + 'Iota' => 'Ι', + 'iota' => 'ι', + 'iprod' => '⨼', + 'iquest' => '¿', + 'iques' => '¿', + 'Iscr' => 'ℐ', + 'iscr' => '𝒾', + 'isin' => '∈', + 'isindot' => '⋵', + 'isinE' => '⋹', + 'isins' => '⋴', + 'isinsv' => '⋳', + 'isinv' => '∈', + 'it' => '⁢', + 'Itilde' => 'Ĩ', + 'itilde' => 'ĩ', + 'Iukcy' => 'І', + 'iukcy' => 'і', + 'Iuml' => 'Ï', + 'Ium' => 'Ï', + 'iuml' => 'ï', + 'ium' => 'ï', + 'Jcirc' => 'Ĵ', + 'jcirc' => 'ĵ', + 'Jcy' => 'Й', + 'jcy' => 'й', + 'Jfr' => '𝔍', + 'jfr' => '𝔧', + 'jmath' => 'ȷ', + 'Jopf' => '𝕁', + 'jopf' => '𝕛', + 'Jscr' => '𝒥', + 'jscr' => '𝒿', + 'Jsercy' => 'Ј', + 'jsercy' => 'ј', + 'Jukcy' => 'Є', + 'jukcy' => 'є', + 'Kappa' => 'Κ', + 'kappa' => 'κ', + 'kappav' => 'ϰ', + 'Kcedil' => 'Ķ', + 'kcedil' => 'ķ', + 'Kcy' => 'К', + 'kcy' => 'к', + 'Kfr' => '𝔎', + 'kfr' => '𝔨', + 'kgreen' => 'ĸ', + 'KHcy' => 'Х', + 'khcy' => 'х', + 'KJcy' => 'Ќ', + 'kjcy' => 'ќ', + 'Kopf' => '𝕂', + 'kopf' => '𝕜', + 'Kscr' => '𝒦', + 'kscr' => '𝓀', + 'lAarr' => '⇚', + 'Lacute' => 'Ĺ', + 'lacute' => 'ĺ', + 'laemptyv' => '⦴', + 'lagran' => 'ℒ', + 'Lambda' => 'Λ', + 'lambda' => 'λ', + 'Lang' => '⟪', + 'lang' => '⟨', + 'langd' => '⦑', + 'langle' => '⟨', + 'lap' => '⪅', + 'Laplacetrf' => 'ℒ', + 'laquo' => '«', + 'laqu' => '«', + 'Larr' => '↞', + 'lArr' => '⇐', + 'larr' => '←', + 'larrb' => '⇤', + 'larrbfs' => '⤟', + 'larrfs' => '⤝', + 'larrhk' => '↩', + 'larrlp' => '↫', + 'larrpl' => '⤹', + 'larrsim' => '⥳', + 'larrtl' => '↢', + 'lat' => '⪫', + 'lAtail' => '⤛', + 'latail' => '⤙', + 'late' => '⪭', + 'lates' => '⪭︀', + 'lBarr' => '⤎', + 'lbarr' => '⤌', + 'lbbrk' => '❲', + 'lbrace' => '{', + 'lbrack' => '[', + 'lbrke' => '⦋', + 'lbrksld' => '⦏', + 'lbrkslu' => '⦍', + 'Lcaron' => 'Ľ', + 'lcaron' => 'ľ', + 'Lcedil' => 'Ļ', + 'lcedil' => 'ļ', + 'lceil' => '⌈', + 'lcub' => '{', + 'Lcy' => 'Л', + 'lcy' => 'л', + 'ldca' => '⤶', + 'ldquo' => '“', + 'ldquor' => '„', + 'ldrdhar' => '⥧', + 'ldrushar' => '⥋', + 'ldsh' => '↲', + 'lE' => '≦', + 'le' => '≤', + 'LeftAngleBracket' => '⟨', + 'LeftArrow' => '←', + 'Leftarrow' => '⇐', + 'leftarrow' => '←', + 'LeftArrowBar' => '⇤', + 'LeftArrowRightArrow' => '⇆', + 'leftarrowtail' => '↢', + 'LeftCeiling' => '⌈', + 'LeftDoubleBracket' => '⟦', + 'LeftDownTeeVector' => '⥡', + 'LeftDownVector' => '⇃', + 'LeftDownVectorBar' => '⥙', + 'LeftFloor' => '⌊', + 'leftharpoondown' => '↽', + 'leftharpoonup' => '↼', + 'leftleftarrows' => '⇇', + 'LeftRightArrow' => '↔', + 'Leftrightarrow' => '⇔', + 'leftrightarrow' => '↔', + 'leftrightarrows' => '⇆', + 'leftrightharpoons' => '⇋', + 'leftrightsquigarrow' => '↭', + 'LeftRightVector' => '⥎', + 'LeftTee' => '⊣', + 'LeftTeeArrow' => '↤', + 'LeftTeeVector' => '⥚', + 'leftthreetimes' => '⋋', + 'LeftTriangle' => '⊲', + 'LeftTriangleBar' => '⧏', + 'LeftTriangleEqual' => '⊴', + 'LeftUpDownVector' => '⥑', + 'LeftUpTeeVector' => '⥠', + 'LeftUpVector' => '↿', + 'LeftUpVectorBar' => '⥘', + 'LeftVector' => '↼', + 'LeftVectorBar' => '⥒', + 'lEg' => '⪋', + 'leg' => '⋚', + 'leq' => '≤', + 'leqq' => '≦', + 'leqslant' => '⩽', + 'les' => '⩽', + 'lescc' => '⪨', + 'lesdot' => '⩿', + 'lesdoto' => '⪁', + 'lesdotor' => '⪃', + 'lesg' => '⋚︀', + 'lesges' => '⪓', + 'lessapprox' => '⪅', + 'lessdot' => '⋖', + 'lesseqgtr' => '⋚', + 'lesseqqgtr' => '⪋', + 'LessEqualGreater' => '⋚', + 'LessFullEqual' => '≦', + 'LessGreater' => '≶', + 'lessgtr' => '≶', + 'LessLess' => '⪡', + 'lesssim' => '≲', + 'LessSlantEqual' => '⩽', + 'LessTilde' => '≲', + 'lfisht' => '⥼', + 'lfloor' => '⌊', + 'Lfr' => '𝔏', + 'lfr' => '𝔩', + 'lg' => '≶', + 'lgE' => '⪑', + 'lHar' => '⥢', + 'lhard' => '↽', + 'lharu' => '↼', + 'lharul' => '⥪', + 'lhblk' => '▄', + 'LJcy' => 'Љ', + 'ljcy' => 'љ', + 'Ll' => '⋘', + 'll' => '≪', + 'llarr' => '⇇', + 'llcorner' => '⌞', + 'Lleftarrow' => '⇚', + 'llhard' => '⥫', + 'lltri' => '◺', + 'Lmidot' => 'Ŀ', + 'lmidot' => 'ŀ', + 'lmoust' => '⎰', + 'lmoustache' => '⎰', + 'lnap' => '⪉', + 'lnapprox' => '⪉', + 'lnE' => '≨', + 'lne' => '⪇', + 'lneq' => '⪇', + 'lneqq' => '≨', + 'lnsim' => '⋦', + 'loang' => '⟬', + 'loarr' => '⇽', + 'lobrk' => '⟦', + 'LongLeftArrow' => '⟵', + 'Longleftarrow' => '⟸', + 'longleftarrow' => '⟵', + 'LongLeftRightArrow' => '⟷', + 'Longleftrightarrow' => '⟺', + 'longleftrightarrow' => '⟷', + 'longmapsto' => '⟼', + 'LongRightArrow' => '⟶', + 'Longrightarrow' => '⟹', + 'longrightarrow' => '⟶', + 'looparrowleft' => '↫', + 'looparrowright' => '↬', + 'lopar' => '⦅', + 'Lopf' => '𝕃', + 'lopf' => '𝕝', + 'loplus' => '⨭', + 'lotimes' => '⨴', + 'lowast' => '∗', + 'lowbar' => '_', + 'LowerLeftArrow' => '↙', + 'LowerRightArrow' => '↘', + 'loz' => '◊', + 'lozenge' => '◊', + 'lozf' => '⧫', + 'lpar' => '(', + 'lparlt' => '⦓', + 'lrarr' => '⇆', + 'lrcorner' => '⌟', + 'lrhar' => '⇋', + 'lrhard' => '⥭', + 'lrm' => '‎', + 'lrtri' => '⊿', + 'lsaquo' => '‹', + 'Lscr' => 'ℒ', + 'lscr' => '𝓁', + 'Lsh' => '↰', + 'lsh' => '↰', + 'lsim' => '≲', + 'lsime' => '⪍', + 'lsimg' => '⪏', + 'lsqb' => '[', + 'lsquo' => '‘', + 'lsquor' => '‚', + 'Lstrok' => 'Ł', + 'lstrok' => 'ł', + 'LT' => '<', + 'L' => '<', + 'Lt' => '≪', + 'lt' => '<', + 'l' => '<', + 'ltcc' => '⪦', + 'ltcir' => '⩹', + 'ltdot' => '⋖', + 'lthree' => '⋋', + 'ltimes' => '⋉', + 'ltlarr' => '⥶', + 'ltquest' => '⩻', + 'ltri' => '◃', + 'ltrie' => '⊴', + 'ltrif' => '◂', + 'ltrPar' => '⦖', + 'lurdshar' => '⥊', + 'luruhar' => '⥦', + 'lvertneqq' => '≨︀', + 'lvnE' => '≨︀', + 'macr' => '¯', + 'mac' => '¯', + 'male' => '♂', + 'malt' => '✠', + 'maltese' => '✠', + 'Map' => '⤅', + 'map' => '↦', + 'mapsto' => '↦', + 'mapstodown' => '↧', + 'mapstoleft' => '↤', + 'mapstoup' => '↥', + 'marker' => '▮', + 'mcomma' => '⨩', + 'Mcy' => 'М', + 'mcy' => 'м', + 'mdash' => '—', + 'mDDot' => '∺', + 'measuredangle' => '∡', + 'MediumSpace' => ' ', + 'Mellintrf' => 'ℳ', + 'Mfr' => '𝔐', + 'mfr' => '𝔪', + 'mho' => '℧', + 'micro' => 'µ', + 'micr' => 'µ', + 'mid' => '∣', + 'midast' => '*', + 'midcir' => '⫰', + 'middot' => '·', + 'middo' => '·', + 'minus' => '−', + 'minusb' => '⊟', + 'minusd' => '∸', + 'minusdu' => '⨪', + 'MinusPlus' => '∓', + 'mlcp' => '⫛', + 'mldr' => '…', + 'mnplus' => '∓', + 'models' => '⊧', + 'Mopf' => '𝕄', + 'mopf' => '𝕞', + 'mp' => '∓', + 'Mscr' => 'ℳ', + 'mscr' => '𝓂', + 'mstpos' => '∾', + 'Mu' => 'Μ', + 'mu' => 'μ', + 'multimap' => '⊸', + 'mumap' => '⊸', + 'nabla' => '∇', + 'Nacute' => 'Ń', + 'nacute' => 'ń', + 'nang' => '∠⃒', + 'nap' => '≉', + 'napE' => '⩰̸', + 'napid' => '≋̸', + 'napos' => 'ʼn', + 'napprox' => '≉', + 'natur' => '♮', + 'natural' => '♮', + 'naturals' => 'ℕ', + 'nbsp' => ' ', + 'nbs' => ' ', + 'nbump' => '≎̸', + 'nbumpe' => '≏̸', + 'ncap' => '⩃', + 'Ncaron' => 'Ň', + 'ncaron' => 'ň', + 'Ncedil' => 'Ņ', + 'ncedil' => 'ņ', + 'ncong' => '≇', + 'ncongdot' => '⩭̸', + 'ncup' => '⩂', + 'Ncy' => 'Н', + 'ncy' => 'н', + 'ndash' => '–', + 'ne' => '≠', + 'nearhk' => '⤤', + 'neArr' => '⇗', + 'nearr' => '↗', + 'nearrow' => '↗', + 'nedot' => '≐̸', + 'NegativeMediumSpace' => '​', + 'NegativeThickSpace' => '​', + 'NegativeThinSpace' => '​', + 'NegativeVeryThinSpace' => '​', + 'nequiv' => '≢', + 'nesear' => '⤨', + 'nesim' => '≂̸', + 'NestedGreaterGreater' => '≫', + 'NestedLessLess' => '≪', + 'NewLine' => ' +', + 'nexist' => '∄', + 'nexists' => '∄', + 'Nfr' => '𝔑', + 'nfr' => '𝔫', + 'ngE' => '≧̸', + 'nge' => '≱', + 'ngeq' => '≱', + 'ngeqq' => '≧̸', + 'ngeqslant' => '⩾̸', + 'nges' => '⩾̸', + 'nGg' => '⋙̸', + 'ngsim' => '≵', + 'nGt' => '≫⃒', + 'ngt' => '≯', + 'ngtr' => '≯', + 'nGtv' => '≫̸', + 'nhArr' => '⇎', + 'nharr' => '↮', + 'nhpar' => '⫲', + 'ni' => '∋', + 'nis' => '⋼', + 'nisd' => '⋺', + 'niv' => '∋', + 'NJcy' => 'Њ', + 'njcy' => 'њ', + 'nlArr' => '⇍', + 'nlarr' => '↚', + 'nldr' => '‥', + 'nlE' => '≦̸', + 'nle' => '≰', + 'nLeftarrow' => '⇍', + 'nleftarrow' => '↚', + 'nLeftrightarrow' => '⇎', + 'nleftrightarrow' => '↮', + 'nleq' => '≰', + 'nleqq' => '≦̸', + 'nleqslant' => '⩽̸', + 'nles' => '⩽̸', + 'nless' => '≮', + 'nLl' => '⋘̸', + 'nlsim' => '≴', + 'nLt' => '≪⃒', + 'nlt' => '≮', + 'nltri' => '⋪', + 'nltrie' => '⋬', + 'nLtv' => '≪̸', + 'nmid' => '∤', + 'NoBreak' => '⁠', + 'NonBreakingSpace' => ' ', + 'Nopf' => 'ℕ', + 'nopf' => '𝕟', + 'Not' => '⫬', + 'not' => '¬', + 'no' => '¬', + 'NotCongruent' => '≢', + 'NotCupCap' => '≭', + 'NotDoubleVerticalBar' => '∦', + 'NotElement' => '∉', + 'NotEqual' => '≠', + 'NotEqualTilde' => '≂̸', + 'NotExists' => '∄', + 'NotGreater' => '≯', + 'NotGreaterEqual' => '≱', + 'NotGreaterFullEqual' => '≧̸', + 'NotGreaterGreater' => '≫̸', + 'NotGreaterLess' => '≹', + 'NotGreaterSlantEqual' => '⩾̸', + 'NotGreaterTilde' => '≵', + 'NotHumpDownHump' => '≎̸', + 'NotHumpEqual' => '≏̸', + 'notin' => '∉', + 'notindot' => '⋵̸', + 'notinE' => '⋹̸', + 'notinva' => '∉', + 'notinvb' => '⋷', + 'notinvc' => '⋶', + 'NotLeftTriangle' => '⋪', + 'NotLeftTriangleBar' => '⧏̸', + 'NotLeftTriangleEqual' => '⋬', + 'NotLess' => '≮', + 'NotLessEqual' => '≰', + 'NotLessGreater' => '≸', + 'NotLessLess' => '≪̸', + 'NotLessSlantEqual' => '⩽̸', + 'NotLessTilde' => '≴', + 'NotNestedGreaterGreater' => '⪢̸', + 'NotNestedLessLess' => '⪡̸', + 'notni' => '∌', + 'notniva' => '∌', + 'notnivb' => '⋾', + 'notnivc' => '⋽', + 'NotPrecedes' => '⊀', + 'NotPrecedesEqual' => '⪯̸', + 'NotPrecedesSlantEqual' => '⋠', + 'NotReverseElement' => '∌', + 'NotRightTriangle' => '⋫', + 'NotRightTriangleBar' => '⧐̸', + 'NotRightTriangleEqual' => '⋭', + 'NotSquareSubset' => '⊏̸', + 'NotSquareSubsetEqual' => '⋢', + 'NotSquareSuperset' => '⊐̸', + 'NotSquareSupersetEqual' => '⋣', + 'NotSubset' => '⊂⃒', + 'NotSubsetEqual' => '⊈', + 'NotSucceeds' => '⊁', + 'NotSucceedsEqual' => '⪰̸', + 'NotSucceedsSlantEqual' => '⋡', + 'NotSucceedsTilde' => '≿̸', + 'NotSuperset' => '⊃⃒', + 'NotSupersetEqual' => '⊉', + 'NotTilde' => '≁', + 'NotTildeEqual' => '≄', + 'NotTildeFullEqual' => '≇', + 'NotTildeTilde' => '≉', + 'NotVerticalBar' => '∤', + 'npar' => '∦', + 'nparallel' => '∦', + 'nparsl' => '⫽⃥', + 'npart' => '∂̸', + 'npolint' => '⨔', + 'npr' => '⊀', + 'nprcue' => '⋠', + 'npre' => '⪯̸', + 'nprec' => '⊀', + 'npreceq' => '⪯̸', + 'nrArr' => '⇏', + 'nrarr' => '↛', + 'nrarrc' => '⤳̸', + 'nrarrw' => '↝̸', + 'nRightarrow' => '⇏', + 'nrightarrow' => '↛', + 'nrtri' => '⋫', + 'nrtrie' => '⋭', + 'nsc' => '⊁', + 'nsccue' => '⋡', + 'nsce' => '⪰̸', + 'Nscr' => '𝒩', + 'nscr' => '𝓃', + 'nshortmid' => '∤', + 'nshortparallel' => '∦', + 'nsim' => '≁', + 'nsime' => '≄', + 'nsimeq' => '≄', + 'nsmid' => '∤', + 'nspar' => '∦', + 'nsqsube' => '⋢', + 'nsqsupe' => '⋣', + 'nsub' => '⊄', + 'nsubE' => '⫅̸', + 'nsube' => '⊈', + 'nsubset' => '⊂⃒', + 'nsubseteq' => '⊈', + 'nsubseteqq' => '⫅̸', + 'nsucc' => '⊁', + 'nsucceq' => '⪰̸', + 'nsup' => '⊅', + 'nsupE' => '⫆̸', + 'nsupe' => '⊉', + 'nsupset' => '⊃⃒', + 'nsupseteq' => '⊉', + 'nsupseteqq' => '⫆̸', + 'ntgl' => '≹', + 'Ntilde' => 'Ñ', + 'Ntild' => 'Ñ', + 'ntilde' => 'ñ', + 'ntild' => 'ñ', + 'ntlg' => '≸', + 'ntriangleleft' => '⋪', + 'ntrianglelefteq' => '⋬', + 'ntriangleright' => '⋫', + 'ntrianglerighteq' => '⋭', + 'Nu' => 'Ν', + 'nu' => 'ν', + 'num' => '#', + 'numero' => '№', + 'numsp' => ' ', + 'nvap' => '≍⃒', + 'nVDash' => '⊯', + 'nVdash' => '⊮', + 'nvDash' => '⊭', + 'nvdash' => '⊬', + 'nvge' => '≥⃒', + 'nvgt' => '>⃒', + 'nvHarr' => '⤄', + 'nvinfin' => '⧞', + 'nvlArr' => '⤂', + 'nvle' => '≤⃒', + 'nvlt' => '<⃒', + 'nvltrie' => '⊴⃒', + 'nvrArr' => '⤃', + 'nvrtrie' => '⊵⃒', + 'nvsim' => '∼⃒', + 'nwarhk' => '⤣', + 'nwArr' => '⇖', + 'nwarr' => '↖', + 'nwarrow' => '↖', + 'nwnear' => '⤧', + 'Oacute' => 'Ó', + 'Oacut' => 'Ó', + 'oacute' => 'ó', + 'oacut' => 'ó', + 'oast' => '⊛', + 'ocir' => 'ô', + 'Ocirc' => 'Ô', + 'Ocir' => 'Ô', + 'ocirc' => 'ô', + 'Ocy' => 'О', + 'ocy' => 'о', + 'odash' => '⊝', + 'Odblac' => 'Ő', + 'odblac' => 'ő', + 'odiv' => '⨸', + 'odot' => '⊙', + 'odsold' => '⦼', + 'OElig' => 'Œ', + 'oelig' => 'œ', + 'ofcir' => '⦿', + 'Ofr' => '𝔒', + 'ofr' => '𝔬', + 'ogon' => '˛', + 'Ograve' => 'Ò', + 'Ograv' => 'Ò', + 'ograve' => 'ò', + 'ograv' => 'ò', + 'ogt' => '⧁', + 'ohbar' => '⦵', + 'ohm' => 'Ω', + 'oint' => '∮', + 'olarr' => '↺', + 'olcir' => '⦾', + 'olcross' => '⦻', + 'oline' => '‾', + 'olt' => '⧀', + 'Omacr' => 'Ō', + 'omacr' => 'ō', + 'Omega' => 'Ω', + 'omega' => 'ω', + 'Omicron' => 'Ο', + 'omicron' => 'ο', + 'omid' => '⦶', + 'ominus' => '⊖', + 'Oopf' => '𝕆', + 'oopf' => '𝕠', + 'opar' => '⦷', + 'OpenCurlyDoubleQuote' => '“', + 'OpenCurlyQuote' => '‘', + 'operp' => '⦹', + 'oplus' => '⊕', + 'Or' => '⩔', + 'or' => '∨', + 'orarr' => '↻', + 'ord' => 'º', + 'order' => 'ℴ', + 'orderof' => 'ℴ', + 'ordf' => 'ª', + 'ordm' => 'º', + 'origof' => '⊶', + 'oror' => '⩖', + 'orslope' => '⩗', + 'orv' => '⩛', + 'oS' => 'Ⓢ', + 'Oscr' => '𝒪', + 'oscr' => 'ℴ', + 'Oslash' => 'Ø', + 'Oslas' => 'Ø', + 'oslash' => 'ø', + 'oslas' => 'ø', + 'osol' => '⊘', + 'Otilde' => 'Õ', + 'Otild' => 'Õ', + 'otilde' => 'õ', + 'otild' => 'õ', + 'Otimes' => '⨷', + 'otimes' => '⊗', + 'otimesas' => '⨶', + 'Ouml' => 'Ö', + 'Oum' => 'Ö', + 'ouml' => 'ö', + 'oum' => 'ö', + 'ovbar' => '⌽', + 'OverBar' => '‾', + 'OverBrace' => '⏞', + 'OverBracket' => '⎴', + 'OverParenthesis' => '⏜', + 'par' => '¶', + 'para' => '¶', + 'parallel' => '∥', + 'parsim' => '⫳', + 'parsl' => '⫽', + 'part' => '∂', + 'PartialD' => '∂', + 'Pcy' => 'П', + 'pcy' => 'п', + 'percnt' => '%', + 'period' => '.', + 'permil' => '‰', + 'perp' => '⊥', + 'pertenk' => '‱', + 'Pfr' => '𝔓', + 'pfr' => '𝔭', + 'Phi' => 'Φ', + 'phi' => 'φ', + 'phiv' => 'ϕ', + 'phmmat' => 'ℳ', + 'phone' => '☎', + 'Pi' => 'Π', + 'pi' => 'π', + 'pitchfork' => '⋔', + 'piv' => 'ϖ', + 'planck' => 'ℏ', + 'planckh' => 'ℎ', + 'plankv' => 'ℏ', + 'plus' => '+', + 'plusacir' => '⨣', + 'plusb' => '⊞', + 'pluscir' => '⨢', + 'plusdo' => '∔', + 'plusdu' => '⨥', + 'pluse' => '⩲', + 'PlusMinus' => '±', + 'plusmn' => '±', + 'plusm' => '±', + 'plussim' => '⨦', + 'plustwo' => '⨧', + 'pm' => '±', + 'Poincareplane' => 'ℌ', + 'pointint' => '⨕', + 'Popf' => 'ℙ', + 'popf' => '𝕡', + 'pound' => '£', + 'poun' => '£', + 'Pr' => '⪻', + 'pr' => '≺', + 'prap' => '⪷', + 'prcue' => '≼', + 'prE' => '⪳', + 'pre' => '⪯', + 'prec' => '≺', + 'precapprox' => '⪷', + 'preccurlyeq' => '≼', + 'Precedes' => '≺', + 'PrecedesEqual' => '⪯', + 'PrecedesSlantEqual' => '≼', + 'PrecedesTilde' => '≾', + 'preceq' => '⪯', + 'precnapprox' => '⪹', + 'precneqq' => '⪵', + 'precnsim' => '⋨', + 'precsim' => '≾', + 'Prime' => '″', + 'prime' => '′', + 'primes' => 'ℙ', + 'prnap' => '⪹', + 'prnE' => '⪵', + 'prnsim' => '⋨', + 'prod' => '∏', + 'Product' => '∏', + 'profalar' => '⌮', + 'profline' => '⌒', + 'profsurf' => '⌓', + 'prop' => '∝', + 'Proportion' => '∷', + 'Proportional' => '∝', + 'propto' => '∝', + 'prsim' => '≾', + 'prurel' => '⊰', + 'Pscr' => '𝒫', + 'pscr' => '𝓅', + 'Psi' => 'Ψ', + 'psi' => 'ψ', + 'puncsp' => ' ', + 'Qfr' => '𝔔', + 'qfr' => '𝔮', + 'qint' => '⨌', + 'Qopf' => 'ℚ', + 'qopf' => '𝕢', + 'qprime' => '⁗', + 'Qscr' => '𝒬', + 'qscr' => '𝓆', + 'quaternions' => 'ℍ', + 'quatint' => '⨖', + 'quest' => '?', + 'questeq' => '≟', + 'QUOT' => '"', + 'QUO' => '"', + 'quot' => '"', + 'quo' => '"', + 'rAarr' => '⇛', + 'race' => '∽̱', + 'Racute' => 'Ŕ', + 'racute' => 'ŕ', + 'radic' => '√', + 'raemptyv' => '⦳', + 'Rang' => '⟫', + 'rang' => '⟩', + 'rangd' => '⦒', + 'range' => '⦥', + 'rangle' => '⟩', + 'raquo' => '»', + 'raqu' => '»', + 'Rarr' => '↠', + 'rArr' => '⇒', + 'rarr' => '→', + 'rarrap' => '⥵', + 'rarrb' => '⇥', + 'rarrbfs' => '⤠', + 'rarrc' => '⤳', + 'rarrfs' => '⤞', + 'rarrhk' => '↪', + 'rarrlp' => '↬', + 'rarrpl' => '⥅', + 'rarrsim' => '⥴', + 'Rarrtl' => '⤖', + 'rarrtl' => '↣', + 'rarrw' => '↝', + 'rAtail' => '⤜', + 'ratail' => '⤚', + 'ratio' => '∶', + 'rationals' => 'ℚ', + 'RBarr' => '⤐', + 'rBarr' => '⤏', + 'rbarr' => '⤍', + 'rbbrk' => '❳', + 'rbrace' => '}', + 'rbrack' => ']', + 'rbrke' => '⦌', + 'rbrksld' => '⦎', + 'rbrkslu' => '⦐', + 'Rcaron' => 'Ř', + 'rcaron' => 'ř', + 'Rcedil' => 'Ŗ', + 'rcedil' => 'ŗ', + 'rceil' => '⌉', + 'rcub' => '}', + 'Rcy' => 'Р', + 'rcy' => 'р', + 'rdca' => '⤷', + 'rdldhar' => '⥩', + 'rdquo' => '”', + 'rdquor' => '”', + 'rdsh' => '↳', + 'Re' => 'ℜ', + 'real' => 'ℜ', + 'realine' => 'ℛ', + 'realpart' => 'ℜ', + 'reals' => 'ℝ', + 'rect' => '▭', + 'REG' => '®', + 'RE' => '®', + 'reg' => '®', + 're' => '®', + 'ReverseElement' => '∋', + 'ReverseEquilibrium' => '⇋', + 'ReverseUpEquilibrium' => '⥯', + 'rfisht' => '⥽', + 'rfloor' => '⌋', + 'Rfr' => 'ℜ', + 'rfr' => '𝔯', + 'rHar' => '⥤', + 'rhard' => '⇁', + 'rharu' => '⇀', + 'rharul' => '⥬', + 'Rho' => 'Ρ', + 'rho' => 'ρ', + 'rhov' => 'ϱ', + 'RightAngleBracket' => '⟩', + 'RightArrow' => '→', + 'Rightarrow' => '⇒', + 'rightarrow' => '→', + 'RightArrowBar' => '⇥', + 'RightArrowLeftArrow' => '⇄', + 'rightarrowtail' => '↣', + 'RightCeiling' => '⌉', + 'RightDoubleBracket' => '⟧', + 'RightDownTeeVector' => '⥝', + 'RightDownVector' => '⇂', + 'RightDownVectorBar' => '⥕', + 'RightFloor' => '⌋', + 'rightharpoondown' => '⇁', + 'rightharpoonup' => '⇀', + 'rightleftarrows' => '⇄', + 'rightleftharpoons' => '⇌', + 'rightrightarrows' => '⇉', + 'rightsquigarrow' => '↝', + 'RightTee' => '⊢', + 'RightTeeArrow' => '↦', + 'RightTeeVector' => '⥛', + 'rightthreetimes' => '⋌', + 'RightTriangle' => '⊳', + 'RightTriangleBar' => '⧐', + 'RightTriangleEqual' => '⊵', + 'RightUpDownVector' => '⥏', + 'RightUpTeeVector' => '⥜', + 'RightUpVector' => '↾', + 'RightUpVectorBar' => '⥔', + 'RightVector' => '⇀', + 'RightVectorBar' => '⥓', + 'ring' => '˚', + 'risingdotseq' => '≓', + 'rlarr' => '⇄', + 'rlhar' => '⇌', + 'rlm' => '‏', + 'rmoust' => '⎱', + 'rmoustache' => '⎱', + 'rnmid' => '⫮', + 'roang' => '⟭', + 'roarr' => '⇾', + 'robrk' => '⟧', + 'ropar' => '⦆', + 'Ropf' => 'ℝ', + 'ropf' => '𝕣', + 'roplus' => '⨮', + 'rotimes' => '⨵', + 'RoundImplies' => '⥰', + 'rpar' => ')', + 'rpargt' => '⦔', + 'rppolint' => '⨒', + 'rrarr' => '⇉', + 'Rrightarrow' => '⇛', + 'rsaquo' => '›', + 'Rscr' => 'ℛ', + 'rscr' => '𝓇', + 'Rsh' => '↱', + 'rsh' => '↱', + 'rsqb' => ']', + 'rsquo' => '’', + 'rsquor' => '’', + 'rthree' => '⋌', + 'rtimes' => '⋊', + 'rtri' => '▹', + 'rtrie' => '⊵', + 'rtrif' => '▸', + 'rtriltri' => '⧎', + 'RuleDelayed' => '⧴', + 'ruluhar' => '⥨', + 'rx' => '℞', + 'Sacute' => 'Ś', + 'sacute' => 'ś', + 'sbquo' => '‚', + 'Sc' => '⪼', + 'sc' => '≻', + 'scap' => '⪸', + 'Scaron' => 'Š', + 'scaron' => 'š', + 'sccue' => '≽', + 'scE' => '⪴', + 'sce' => '⪰', + 'Scedil' => 'Ş', + 'scedil' => 'ş', + 'Scirc' => 'Ŝ', + 'scirc' => 'ŝ', + 'scnap' => '⪺', + 'scnE' => '⪶', + 'scnsim' => '⋩', + 'scpolint' => '⨓', + 'scsim' => '≿', + 'Scy' => 'С', + 'scy' => 'с', + 'sdot' => '⋅', + 'sdotb' => '⊡', + 'sdote' => '⩦', + 'searhk' => '⤥', + 'seArr' => '⇘', + 'searr' => '↘', + 'searrow' => '↘', + 'sect' => '§', + 'sec' => '§', + 'semi' => ';', + 'seswar' => '⤩', + 'setminus' => '∖', + 'setmn' => '∖', + 'sext' => '✶', + 'Sfr' => '𝔖', + 'sfr' => '𝔰', + 'sfrown' => '⌢', + 'sharp' => '♯', + 'SHCHcy' => 'Щ', + 'shchcy' => 'щ', + 'SHcy' => 'Ш', + 'shcy' => 'ш', + 'ShortDownArrow' => '↓', + 'ShortLeftArrow' => '←', + 'shortmid' => '∣', + 'shortparallel' => '∥', + 'ShortRightArrow' => '→', + 'ShortUpArrow' => '↑', + 'shy' => '­', + 'sh' => '­', + 'Sigma' => 'Σ', + 'sigma' => 'σ', + 'sigmaf' => 'ς', + 'sigmav' => 'ς', + 'sim' => '∼', + 'simdot' => '⩪', + 'sime' => '≃', + 'simeq' => '≃', + 'simg' => '⪞', + 'simgE' => '⪠', + 'siml' => '⪝', + 'simlE' => '⪟', + 'simne' => '≆', + 'simplus' => '⨤', + 'simrarr' => '⥲', + 'slarr' => '←', + 'SmallCircle' => '∘', + 'smallsetminus' => '∖', + 'smashp' => '⨳', + 'smeparsl' => '⧤', + 'smid' => '∣', + 'smile' => '⌣', + 'smt' => '⪪', + 'smte' => '⪬', + 'smtes' => '⪬︀', + 'SOFTcy' => 'Ь', + 'softcy' => 'ь', + 'sol' => '/', + 'solb' => '⧄', + 'solbar' => '⌿', + 'Sopf' => '𝕊', + 'sopf' => '𝕤', + 'spades' => '♠', + 'spadesuit' => '♠', + 'spar' => '∥', + 'sqcap' => '⊓', + 'sqcaps' => '⊓︀', + 'sqcup' => '⊔', + 'sqcups' => '⊔︀', + 'Sqrt' => '√', + 'sqsub' => '⊏', + 'sqsube' => '⊑', + 'sqsubset' => '⊏', + 'sqsubseteq' => '⊑', + 'sqsup' => '⊐', + 'sqsupe' => '⊒', + 'sqsupset' => '⊐', + 'sqsupseteq' => '⊒', + 'squ' => '□', + 'Square' => '□', + 'square' => '□', + 'SquareIntersection' => '⊓', + 'SquareSubset' => '⊏', + 'SquareSubsetEqual' => '⊑', + 'SquareSuperset' => '⊐', + 'SquareSupersetEqual' => '⊒', + 'SquareUnion' => '⊔', + 'squarf' => '▪', + 'squf' => '▪', + 'srarr' => '→', + 'Sscr' => '𝒮', + 'sscr' => '𝓈', + 'ssetmn' => '∖', + 'ssmile' => '⌣', + 'sstarf' => '⋆', + 'Star' => '⋆', + 'star' => '☆', + 'starf' => '★', + 'straightepsilon' => 'ϵ', + 'straightphi' => 'ϕ', + 'strns' => '¯', + 'Sub' => '⋐', + 'sub' => '⊂', + 'subdot' => '⪽', + 'subE' => '⫅', + 'sube' => '⊆', + 'subedot' => '⫃', + 'submult' => '⫁', + 'subnE' => '⫋', + 'subne' => '⊊', + 'subplus' => '⪿', + 'subrarr' => '⥹', + 'Subset' => '⋐', + 'subset' => '⊂', + 'subseteq' => '⊆', + 'subseteqq' => '⫅', + 'SubsetEqual' => '⊆', + 'subsetneq' => '⊊', + 'subsetneqq' => '⫋', + 'subsim' => '⫇', + 'subsub' => '⫕', + 'subsup' => '⫓', + 'succ' => '≻', + 'succapprox' => '⪸', + 'succcurlyeq' => '≽', + 'Succeeds' => '≻', + 'SucceedsEqual' => '⪰', + 'SucceedsSlantEqual' => '≽', + 'SucceedsTilde' => '≿', + 'succeq' => '⪰', + 'succnapprox' => '⪺', + 'succneqq' => '⪶', + 'succnsim' => '⋩', + 'succsim' => '≿', + 'SuchThat' => '∋', + 'Sum' => '∑', + 'sum' => '∑', + 'sung' => '♪', + 'Sup' => '⋑', + 'sup' => '³', + 'sup1' => '¹', + 'sup2' => '²', + 'sup3' => '³', + 'supdot' => '⪾', + 'supdsub' => '⫘', + 'supE' => '⫆', + 'supe' => '⊇', + 'supedot' => '⫄', + 'Superset' => '⊃', + 'SupersetEqual' => '⊇', + 'suphsol' => '⟉', + 'suphsub' => '⫗', + 'suplarr' => '⥻', + 'supmult' => '⫂', + 'supnE' => '⫌', + 'supne' => '⊋', + 'supplus' => '⫀', + 'Supset' => '⋑', + 'supset' => '⊃', + 'supseteq' => '⊇', + 'supseteqq' => '⫆', + 'supsetneq' => '⊋', + 'supsetneqq' => '⫌', + 'supsim' => '⫈', + 'supsub' => '⫔', + 'supsup' => '⫖', + 'swarhk' => '⤦', + 'swArr' => '⇙', + 'swarr' => '↙', + 'swarrow' => '↙', + 'swnwar' => '⤪', + 'szlig' => 'ß', + 'szli' => 'ß', + 'Tab' => ' ', + 'target' => '⌖', + 'Tau' => 'Τ', + 'tau' => 'τ', + 'tbrk' => '⎴', + 'Tcaron' => 'Ť', + 'tcaron' => 'ť', + 'Tcedil' => 'Ţ', + 'tcedil' => 'ţ', + 'Tcy' => 'Т', + 'tcy' => 'т', + 'tdot' => '⃛', + 'telrec' => '⌕', + 'Tfr' => '𝔗', + 'tfr' => '𝔱', + 'there4' => '∴', + 'Therefore' => '∴', + 'therefore' => '∴', + 'Theta' => 'Θ', + 'theta' => 'θ', + 'thetasym' => 'ϑ', + 'thetav' => 'ϑ', + 'thickapprox' => '≈', + 'thicksim' => '∼', + 'ThickSpace' => '  ', + 'thinsp' => ' ', + 'ThinSpace' => ' ', + 'thkap' => '≈', + 'thksim' => '∼', + 'THORN' => 'Þ', + 'THOR' => 'Þ', + 'thorn' => 'þ', + 'thor' => 'þ', + 'Tilde' => '∼', + 'tilde' => '˜', + 'TildeEqual' => '≃', + 'TildeFullEqual' => '≅', + 'TildeTilde' => '≈', + 'times' => '×', + 'time' => '×', + 'timesb' => '⊠', + 'timesbar' => '⨱', + 'timesd' => '⨰', + 'tint' => '∭', + 'toea' => '⤨', + 'top' => '⊤', + 'topbot' => '⌶', + 'topcir' => '⫱', + 'Topf' => '𝕋', + 'topf' => '𝕥', + 'topfork' => '⫚', + 'tosa' => '⤩', + 'tprime' => '‴', + 'TRADE' => '™', + 'trade' => '™', + 'triangle' => '▵', + 'triangledown' => '▿', + 'triangleleft' => '◃', + 'trianglelefteq' => '⊴', + 'triangleq' => '≜', + 'triangleright' => '▹', + 'trianglerighteq' => '⊵', + 'tridot' => '◬', + 'trie' => '≜', + 'triminus' => '⨺', + 'TripleDot' => '⃛', + 'triplus' => '⨹', + 'trisb' => '⧍', + 'tritime' => '⨻', + 'trpezium' => '⏢', + 'Tscr' => '𝒯', + 'tscr' => '𝓉', + 'TScy' => 'Ц', + 'tscy' => 'ц', + 'TSHcy' => 'Ћ', + 'tshcy' => 'ћ', + 'Tstrok' => 'Ŧ', + 'tstrok' => 'ŧ', + 'twixt' => '≬', + 'twoheadleftarrow' => '↞', + 'twoheadrightarrow' => '↠', + 'Uacute' => 'Ú', + 'Uacut' => 'Ú', + 'uacute' => 'ú', + 'uacut' => 'ú', + 'Uarr' => '↟', + 'uArr' => '⇑', + 'uarr' => '↑', + 'Uarrocir' => '⥉', + 'Ubrcy' => 'Ў', + 'ubrcy' => 'ў', + 'Ubreve' => 'Ŭ', + 'ubreve' => 'ŭ', + 'Ucirc' => 'Û', + 'Ucir' => 'Û', + 'ucirc' => 'û', + 'ucir' => 'û', + 'Ucy' => 'У', + 'ucy' => 'у', + 'udarr' => '⇅', + 'Udblac' => 'Ű', + 'udblac' => 'ű', + 'udhar' => '⥮', + 'ufisht' => '⥾', + 'Ufr' => '𝔘', + 'ufr' => '𝔲', + 'Ugrave' => 'Ù', + 'Ugrav' => 'Ù', + 'ugrave' => 'ù', + 'ugrav' => 'ù', + 'uHar' => '⥣', + 'uharl' => '↿', + 'uharr' => '↾', + 'uhblk' => '▀', + 'ulcorn' => '⌜', + 'ulcorner' => '⌜', + 'ulcrop' => '⌏', + 'ultri' => '◸', + 'Umacr' => 'Ū', + 'umacr' => 'ū', + 'uml' => '¨', + 'um' => '¨', + 'UnderBar' => '_', + 'UnderBrace' => '⏟', + 'UnderBracket' => '⎵', + 'UnderParenthesis' => '⏝', + 'Union' => '⋃', + 'UnionPlus' => '⊎', + 'Uogon' => 'Ų', + 'uogon' => 'ų', + 'Uopf' => '𝕌', + 'uopf' => '𝕦', + 'UpArrow' => '↑', + 'Uparrow' => '⇑', + 'uparrow' => '↑', + 'UpArrowBar' => '⤒', + 'UpArrowDownArrow' => '⇅', + 'UpDownArrow' => '↕', + 'Updownarrow' => '⇕', + 'updownarrow' => '↕', + 'UpEquilibrium' => '⥮', + 'upharpoonleft' => '↿', + 'upharpoonright' => '↾', + 'uplus' => '⊎', + 'UpperLeftArrow' => '↖', + 'UpperRightArrow' => '↗', + 'Upsi' => 'ϒ', + 'upsi' => 'υ', + 'upsih' => 'ϒ', + 'Upsilon' => 'Υ', + 'upsilon' => 'υ', + 'UpTee' => '⊥', + 'UpTeeArrow' => '↥', + 'upuparrows' => '⇈', + 'urcorn' => '⌝', + 'urcorner' => '⌝', + 'urcrop' => '⌎', + 'Uring' => 'Ů', + 'uring' => 'ů', + 'urtri' => '◹', + 'Uscr' => '𝒰', + 'uscr' => '𝓊', + 'utdot' => '⋰', + 'Utilde' => 'Ũ', + 'utilde' => 'ũ', + 'utri' => '▵', + 'utrif' => '▴', + 'uuarr' => '⇈', + 'Uuml' => 'Ü', + 'Uum' => 'Ü', + 'uuml' => 'ü', + 'uum' => 'ü', + 'uwangle' => '⦧', + 'vangrt' => '⦜', + 'varepsilon' => 'ϵ', + 'varkappa' => 'ϰ', + 'varnothing' => '∅', + 'varphi' => 'ϕ', + 'varpi' => 'ϖ', + 'varpropto' => '∝', + 'vArr' => '⇕', + 'varr' => '↕', + 'varrho' => 'ϱ', + 'varsigma' => 'ς', + 'varsubsetneq' => '⊊︀', + 'varsubsetneqq' => '⫋︀', + 'varsupsetneq' => '⊋︀', + 'varsupsetneqq' => '⫌︀', + 'vartheta' => 'ϑ', + 'vartriangleleft' => '⊲', + 'vartriangleright' => '⊳', + 'Vbar' => '⫫', + 'vBar' => '⫨', + 'vBarv' => '⫩', + 'Vcy' => 'В', + 'vcy' => 'в', + 'VDash' => '⊫', + 'Vdash' => '⊩', + 'vDash' => '⊨', + 'vdash' => '⊢', + 'Vdashl' => '⫦', + 'Vee' => '⋁', + 'vee' => '∨', + 'veebar' => '⊻', + 'veeeq' => '≚', + 'vellip' => '⋮', + 'Verbar' => '‖', + 'verbar' => '|', + 'Vert' => '‖', + 'vert' => '|', + 'VerticalBar' => '∣', + 'VerticalLine' => '|', + 'VerticalSeparator' => '❘', + 'VerticalTilde' => '≀', + 'VeryThinSpace' => ' ', + 'Vfr' => '𝔙', + 'vfr' => '𝔳', + 'vltri' => '⊲', + 'vnsub' => '⊂⃒', + 'vnsup' => '⊃⃒', + 'Vopf' => '𝕍', + 'vopf' => '𝕧', + 'vprop' => '∝', + 'vrtri' => '⊳', + 'Vscr' => '𝒱', + 'vscr' => '𝓋', + 'vsubnE' => '⫋︀', + 'vsubne' => '⊊︀', + 'vsupnE' => '⫌︀', + 'vsupne' => '⊋︀', + 'Vvdash' => '⊪', + 'vzigzag' => '⦚', + 'Wcirc' => 'Ŵ', + 'wcirc' => 'ŵ', + 'wedbar' => '⩟', + 'Wedge' => '⋀', + 'wedge' => '∧', + 'wedgeq' => '≙', + 'weierp' => '℘', + 'Wfr' => '𝔚', + 'wfr' => '𝔴', + 'Wopf' => '𝕎', + 'wopf' => '𝕨', + 'wp' => '℘', + 'wr' => '≀', + 'wreath' => '≀', + 'Wscr' => '𝒲', + 'wscr' => '𝓌', + 'xcap' => '⋂', + 'xcirc' => '◯', + 'xcup' => '⋃', + 'xdtri' => '▽', + 'Xfr' => '𝔛', + 'xfr' => '𝔵', + 'xhArr' => '⟺', + 'xharr' => '⟷', + 'Xi' => 'Ξ', + 'xi' => 'ξ', + 'xlArr' => '⟸', + 'xlarr' => '⟵', + 'xmap' => '⟼', + 'xnis' => '⋻', + 'xodot' => '⨀', + 'Xopf' => '𝕏', + 'xopf' => '𝕩', + 'xoplus' => '⨁', + 'xotime' => '⨂', + 'xrArr' => '⟹', + 'xrarr' => '⟶', + 'Xscr' => '𝒳', + 'xscr' => '𝓍', + 'xsqcup' => '⨆', + 'xuplus' => '⨄', + 'xutri' => '△', + 'xvee' => '⋁', + 'xwedge' => '⋀', + 'Yacute' => 'Ý', + 'Yacut' => 'Ý', + 'yacute' => 'ý', + 'yacut' => 'ý', + 'YAcy' => 'Я', + 'yacy' => 'я', + 'Ycirc' => 'Ŷ', + 'ycirc' => 'ŷ', + 'Ycy' => 'Ы', + 'ycy' => 'ы', + 'yen' => '¥', + 'ye' => '¥', + 'Yfr' => '𝔜', + 'yfr' => '𝔶', + 'YIcy' => 'Ї', + 'yicy' => 'ї', + 'Yopf' => '𝕐', + 'yopf' => '𝕪', + 'Yscr' => '𝒴', + 'yscr' => '𝓎', + 'YUcy' => 'Ю', + 'yucy' => 'ю', + 'Yuml' => 'Ÿ', + 'yuml' => 'ÿ', + 'yum' => 'ÿ', + 'Zacute' => 'Ź', + 'zacute' => 'ź', + 'Zcaron' => 'Ž', + 'zcaron' => 'ž', + 'Zcy' => 'З', + 'zcy' => 'з', + 'Zdot' => 'Ż', + 'zdot' => 'ż', + 'zeetrf' => 'ℨ', + 'ZeroWidthSpace' => '​', + 'Zeta' => 'Ζ', + 'zeta' => 'ζ', + 'Zfr' => 'ℨ', + 'zfr' => '𝔷', + 'ZHcy' => 'Ж', + 'zhcy' => 'ж', + 'zigrarr' => '⇝', + 'Zopf' => 'ℤ', + 'zopf' => '𝕫', + 'Zscr' => '𝒵', + 'zscr' => '𝓏', + 'zwj' => '‍', + 'zwnj' => '‌', + ); +} diff --git a/vendor/masterminds/html5/src/HTML5/Exception.php b/vendor/masterminds/html5/src/HTML5/Exception.php new file mode 100644 index 000000000..64e97e6ff --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Exception.php @@ -0,0 +1,10 @@ + self::NAMESPACE_HTML, + 'svg' => self::NAMESPACE_SVG, + 'math' => self::NAMESPACE_MATHML, + ); + + /** + * Holds the always available namespaces (which does not require the XMLNS declaration). + * + * @var array + */ + protected $implicitNamespaces = array( + 'xml' => self::NAMESPACE_XML, + 'xmlns' => self::NAMESPACE_XMLNS, + 'xlink' => self::NAMESPACE_XLINK, + ); + + /** + * Holds a stack of currently active namespaces. + * + * @var array + */ + protected $nsStack = array(); + + /** + * Holds the number of namespaces declared by a node. + * + * @var array + */ + protected $pushes = array(); + + /** + * Defined in 8.2.5. + */ + const IM_INITIAL = 0; + + const IM_BEFORE_HTML = 1; + + const IM_BEFORE_HEAD = 2; + + const IM_IN_HEAD = 3; + + const IM_IN_HEAD_NOSCRIPT = 4; + + const IM_AFTER_HEAD = 5; + + const IM_IN_BODY = 6; + + const IM_TEXT = 7; + + const IM_IN_TABLE = 8; + + const IM_IN_TABLE_TEXT = 9; + + const IM_IN_CAPTION = 10; + + const IM_IN_COLUMN_GROUP = 11; + + const IM_IN_TABLE_BODY = 12; + + const IM_IN_ROW = 13; + + const IM_IN_CELL = 14; + + const IM_IN_SELECT = 15; + + const IM_IN_SELECT_IN_TABLE = 16; + + const IM_AFTER_BODY = 17; + + const IM_IN_FRAMESET = 18; + + const IM_AFTER_FRAMESET = 19; + + const IM_AFTER_AFTER_BODY = 20; + + const IM_AFTER_AFTER_FRAMESET = 21; + + const IM_IN_SVG = 22; + + const IM_IN_MATHML = 23; + + protected $options = array(); + + protected $stack = array(); + + protected $current; // Pointer in the tag hierarchy. + protected $rules; + protected $doc; + + protected $frag; + + protected $processor; + + protected $insertMode = 0; + + /** + * Track if we are in an element that allows only inline child nodes. + * + * @var string|null + */ + protected $onlyInline; + + /** + * Quirks mode is enabled by default. + * Any document that is missing the DT will be considered to be in quirks mode. + */ + protected $quirks = true; + + protected $errors = array(); + + public function __construct($isFragment = false, array $options = array()) + { + $this->options = $options; + + if (isset($options[self::OPT_TARGET_DOC])) { + $this->doc = $options[self::OPT_TARGET_DOC]; + } else { + $impl = new \DOMImplementation(); + // XXX: + // Create the doctype. For now, we are always creating HTML5 + // documents, and attempting to up-convert any older DTDs to HTML5. + $dt = $impl->createDocumentType('html'); + // $this->doc = \DOMImplementation::createDocument(NULL, 'html', $dt); + $this->doc = $impl->createDocument(null, '', $dt); + $this->doc->encoding = !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'; + } + + $this->errors = array(); + + $this->current = $this->doc; // ->documentElement; + + // Create a rules engine for tags. + $this->rules = new TreeBuildingRules(); + + $implicitNS = array(); + if (isset($this->options[self::OPT_IMPLICIT_NS])) { + $implicitNS = $this->options[self::OPT_IMPLICIT_NS]; + } elseif (isset($this->options['implicitNamespaces'])) { + $implicitNS = $this->options['implicitNamespaces']; + } + + // Fill $nsStack with the defalut HTML5 namespaces, plus the "implicitNamespaces" array taken form $options + array_unshift($this->nsStack, $implicitNS + array('' => self::NAMESPACE_HTML) + $this->implicitNamespaces); + + if ($isFragment) { + $this->insertMode = static::IM_IN_BODY; + $this->frag = $this->doc->createDocumentFragment(); + $this->current = $this->frag; + } + } + + /** + * Get the document. + */ + public function document() + { + return $this->doc; + } + + /** + * Get the DOM fragment for the body. + * + * This returns a DOMNodeList because a fragment may have zero or more + * DOMNodes at its root. + * + * @see http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#concept-frag-parse-context + * + * @return \DOMDocumentFragment + */ + public function fragment() + { + return $this->frag; + } + + /** + * Provide an instruction processor. + * + * This is used for handling Processor Instructions as they are + * inserted. If omitted, PI's are inserted directly into the DOM tree. + * + * @param InstructionProcessor $proc + */ + public function setInstructionProcessor(InstructionProcessor $proc) + { + $this->processor = $proc; + } + + public function doctype($name, $idType = 0, $id = null, $quirks = false) + { + // This is used solely for setting quirks mode. Currently we don't + // try to preserve the inbound DT. We convert it to HTML5. + $this->quirks = $quirks; + + if ($this->insertMode > static::IM_INITIAL) { + $this->parseError('Illegal placement of DOCTYPE tag. Ignoring: ' . $name); + + return; + } + + $this->insertMode = static::IM_BEFORE_HTML; + } + + /** + * Process the start tag. + * + * @todo - XMLNS namespace handling (we need to parse, even if it's not valid) + * - XLink, MathML and SVG namespace handling + * - Omission rules: 8.1.2.4 Optional tags + * + * @param string $name + * @param array $attributes + * @param bool $selfClosing + * + * @return int + */ + public function startTag($name, $attributes = array(), $selfClosing = false) + { + $lname = $this->normalizeTagName($name); + + // Make sure we have an html element. + if (!$this->doc->documentElement && 'html' !== $name && !$this->frag) { + $this->startTag('html'); + } + + // Set quirks mode if we're at IM_INITIAL with no doctype. + if ($this->insertMode === static::IM_INITIAL) { + $this->quirks = true; + $this->parseError('No DOCTYPE specified.'); + } + + // SPECIAL TAG HANDLING: + // Spec says do this, and "don't ask." + // find the spec where this is defined... looks problematic + if ('image' === $name && !($this->insertMode === static::IM_IN_SVG || $this->insertMode === static::IM_IN_MATHML)) { + $name = 'img'; + } + + // Autoclose p tags where appropriate. + if ($this->insertMode >= static::IM_IN_BODY && Elements::isA($name, Elements::AUTOCLOSE_P)) { + $this->autoclose('p'); + } + + // Set insert mode: + switch ($name) { + case 'html': + $this->insertMode = static::IM_BEFORE_HEAD; + break; + case 'head': + if ($this->insertMode > static::IM_BEFORE_HEAD) { + $this->parseError('Unexpected head tag outside of head context.'); + } else { + $this->insertMode = static::IM_IN_HEAD; + } + break; + case 'body': + $this->insertMode = static::IM_IN_BODY; + break; + case 'svg': + $this->insertMode = static::IM_IN_SVG; + break; + case 'math': + $this->insertMode = static::IM_IN_MATHML; + break; + case 'noscript': + if ($this->insertMode === static::IM_IN_HEAD) { + $this->insertMode = static::IM_IN_HEAD_NOSCRIPT; + } + break; + } + + // Special case handling for SVG. + if ($this->insertMode === static::IM_IN_SVG) { + $lname = Elements::normalizeSvgElement($lname); + } + + $pushes = 0; + // when we found a tag thats appears inside $nsRoots, we have to switch the defalut namespace + if (isset($this->nsRoots[$lname]) && $this->nsStack[0][''] !== $this->nsRoots[$lname]) { + array_unshift($this->nsStack, array( + '' => $this->nsRoots[$lname], + ) + $this->nsStack[0]); + ++$pushes; + } + $needsWorkaround = false; + if (isset($this->options['xmlNamespaces']) && $this->options['xmlNamespaces']) { + // when xmlNamespaces is true a and we found a 'xmlns' or 'xmlns:*' attribute, we should add a new item to the $nsStack + foreach ($attributes as $aName => $aVal) { + if ('xmlns' === $aName) { + $needsWorkaround = $aVal; + array_unshift($this->nsStack, array( + '' => $aVal, + ) + $this->nsStack[0]); + ++$pushes; + } elseif ('xmlns' === (($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : '')) { + array_unshift($this->nsStack, array( + substr($aName, $pos + 1) => $aVal, + ) + $this->nsStack[0]); + ++$pushes; + } + } + } + + if ($this->onlyInline && Elements::isA($lname, Elements::BLOCK_TAG)) { + $this->autoclose($this->onlyInline); + $this->onlyInline = null; + } + + // some elements as table related tags might have optional end tags that force us to auto close multiple tags + // https://www.w3.org/TR/html401/struct/tables.html + if ($this->current instanceof \DOMElement && isset(Elements::$optionalEndElementsParentsToClose[$lname])) { + foreach (Elements::$optionalEndElementsParentsToClose[$lname] as $parentElName) { + if ($this->current instanceof \DOMElement && $this->current->tagName === $parentElName) { + $this->autoclose($parentElName); + } + } + } + + try { + $prefix = ($pos = strpos($lname, ':')) ? substr($lname, 0, $pos) : ''; + + if (false !== $needsWorkaround) { + $xml = "<$lname xmlns=\"$needsWorkaround\" " . (strlen($prefix) && isset($this->nsStack[0][$prefix]) ? ("xmlns:$prefix=\"" . $this->nsStack[0][$prefix] . '"') : '') . '/>'; + + $frag = new \DOMDocument('1.0', 'UTF-8'); + $frag->loadXML($xml); + + $ele = $this->doc->importNode($frag->documentElement, true); + } else { + if (!isset($this->nsStack[0][$prefix]) || ('' === $prefix && isset($this->options[self::OPT_DISABLE_HTML_NS]) && $this->options[self::OPT_DISABLE_HTML_NS])) { + $ele = $this->doc->createElement($lname); + } else { + $ele = $this->doc->createElementNS($this->nsStack[0][$prefix], $lname); + } + } + } catch (\DOMException $e) { + $this->parseError("Illegal tag name: <$lname>. Replaced with ."); + $ele = $this->doc->createElement('invalid'); + } + + if (Elements::isA($lname, Elements::BLOCK_ONLY_INLINE)) { + $this->onlyInline = $lname; + } + + // When we add some namespacess, we have to track them. Later, when "endElement" is invoked, we have to remove them. + // When we are on a void tag, we do not need to care about namesapce nesting. + if ($pushes > 0 && !Elements::isA($name, Elements::VOID_TAG)) { + // PHP tends to free the memory used by DOM, + // to avoid spl_object_hash collisions whe have to avoid garbage collection of $ele storing it into $pushes + // see https://bugs.php.net/bug.php?id=67459 + $this->pushes[spl_object_hash($ele)] = array($pushes, $ele); + } + + foreach ($attributes as $aName => $aVal) { + // xmlns attributes can't be set + if ('xmlns' === $aName) { + continue; + } + + if ($this->insertMode === static::IM_IN_SVG) { + $aName = Elements::normalizeSvgAttribute($aName); + } elseif ($this->insertMode === static::IM_IN_MATHML) { + $aName = Elements::normalizeMathMlAttribute($aName); + } + + $aVal = (string) $aVal; + + try { + $prefix = ($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : false; + + if ('xmlns' === $prefix) { + $ele->setAttributeNS(self::NAMESPACE_XMLNS, $aName, $aVal); + } elseif (false !== $prefix && isset($this->nsStack[0][$prefix])) { + $ele->setAttributeNS($this->nsStack[0][$prefix], $aName, $aVal); + } else { + $ele->setAttribute($aName, $aVal); + } + } catch (\DOMException $e) { + $this->parseError("Illegal attribute name for tag $name. Ignoring: $aName"); + continue; + } + + // This is necessary on a non-DTD schema, like HTML5. + if ('id' === $aName) { + $ele->setIdAttribute('id', true); + } + } + + if ($this->frag !== $this->current && $this->rules->hasRules($name)) { + // Some elements have special processing rules. Handle those separately. + $this->current = $this->rules->evaluate($ele, $this->current); + } else { + // Otherwise, it's a standard element. + $this->current->appendChild($ele); + + if (!Elements::isA($name, Elements::VOID_TAG)) { + $this->current = $ele; + } + + // Self-closing tags should only be respected on foreign elements + // (and are implied on void elements) + // See: https://www.w3.org/TR/html5/syntax.html#start-tags + if (Elements::isHtml5Element($name)) { + $selfClosing = false; + } + } + + // This is sort of a last-ditch attempt to correct for cases where no head/body + // elements are provided. + if ($this->insertMode <= static::IM_BEFORE_HEAD && 'head' !== $name && 'html' !== $name) { + $this->insertMode = static::IM_IN_BODY; + } + + // When we are on a void tag, we do not need to care about namesapce nesting, + // but we have to remove the namespaces pushed to $nsStack. + if ($pushes > 0 && Elements::isA($name, Elements::VOID_TAG)) { + // remove the namespaced definded by current node + for ($i = 0; $i < $pushes; ++$i) { + array_shift($this->nsStack); + } + } + + if ($selfClosing) { + $this->endTag($name); + } + + // Return the element mask, which the tokenizer can then use to set + // various processing rules. + return Elements::element($name); + } + + public function endTag($name) + { + $lname = $this->normalizeTagName($name); + + // Special case within 12.2.6.4.7: An end tag whose tag name is "br" should be treated as an opening tag + if ('br' === $name) { + $this->parseError('Closing tag encountered for void element br.'); + + $this->startTag('br'); + } + // Ignore closing tags for other unary elements. + elseif (Elements::isA($name, Elements::VOID_TAG)) { + return; + } + + if ($this->insertMode <= static::IM_BEFORE_HTML) { + // 8.2.5.4.2 + if (in_array($name, array( + 'html', + 'br', + 'head', + 'title', + ))) { + $this->startTag('html'); + $this->endTag($name); + $this->insertMode = static::IM_BEFORE_HEAD; + + return; + } + + // Ignore the tag. + $this->parseError('Illegal closing tag at global scope.'); + + return; + } + + // Special case handling for SVG. + if ($this->insertMode === static::IM_IN_SVG) { + $lname = Elements::normalizeSvgElement($lname); + } + + $cid = spl_object_hash($this->current); + + // XXX: HTML has no parent. What do we do, though, + // if this element appears in the wrong place? + if ('html' === $lname) { + return; + } + + // remove the namespaced definded by current node + if (isset($this->pushes[$cid])) { + for ($i = 0; $i < $this->pushes[$cid][0]; ++$i) { + array_shift($this->nsStack); + } + unset($this->pushes[$cid]); + } + + if (!$this->autoclose($lname)) { + $this->parseError('Could not find closing tag for ' . $lname); + } + + switch ($lname) { + case 'head': + $this->insertMode = static::IM_AFTER_HEAD; + break; + case 'body': + $this->insertMode = static::IM_AFTER_BODY; + break; + case 'svg': + case 'mathml': + $this->insertMode = static::IM_IN_BODY; + break; + } + } + + public function comment($cdata) + { + // TODO: Need to handle case where comment appears outside of the HTML tag. + $node = $this->doc->createComment($cdata); + $this->current->appendChild($node); + } + + public function text($data) + { + // XXX: Hmmm.... should we really be this strict? + if ($this->insertMode < static::IM_IN_HEAD) { + // Per '8.2.5.4.3 The "before head" insertion mode' the characters + // " \t\n\r\f" should be ignored but no mention of a parse error. This is + // practical as most documents contain these characters. Other text is not + // expected here so recording a parse error is necessary. + $dataTmp = trim($data, " \t\n\r\f"); + if (!empty($dataTmp)) { + // fprintf(STDOUT, "Unexpected insert mode: %d", $this->insertMode); + $this->parseError('Unexpected text. Ignoring: ' . $dataTmp); + } + + return; + } + // fprintf(STDOUT, "Appending text %s.", $data); + $node = $this->doc->createTextNode($data); + $this->current->appendChild($node); + } + + public function eof() + { + // If the $current isn't the $root, do we need to do anything? + } + + public function parseError($msg, $line = 0, $col = 0) + { + $this->errors[] = sprintf('Line %d, Col %d: %s', $line, $col, $msg); + } + + public function getErrors() + { + return $this->errors; + } + + public function cdata($data) + { + $node = $this->doc->createCDATASection($data); + $this->current->appendChild($node); + } + + public function processingInstruction($name, $data = null) + { + // XXX: Ignore initial XML declaration, per the spec. + if ($this->insertMode === static::IM_INITIAL && 'xml' === strtolower($name)) { + return; + } + + // Important: The processor may modify the current DOM tree however it sees fit. + if ($this->processor instanceof InstructionProcessor) { + $res = $this->processor->process($this->current, $name, $data); + if (!empty($res)) { + $this->current = $res; + } + + return; + } + + // Otherwise, this is just a dumb PI element. + $node = $this->doc->createProcessingInstruction($name, $data); + + $this->current->appendChild($node); + } + + // ========================================================================== + // UTILITIES + // ========================================================================== + + /** + * Apply normalization rules to a tag name. + * See sections 2.9 and 8.1.2. + * + * @param string $tagName + * + * @return string The normalized tag name. + */ + protected function normalizeTagName($tagName) + { + /* + * Section 2.9 suggests that we should not do this. if (strpos($name, ':') !== false) { // We know from the grammar that there must be at least one other // char besides :, since : is not a legal tag start. $parts = explode(':', $name); return array_pop($parts); } + */ + return $tagName; + } + + protected function quirksTreeResolver($name) + { + throw new \Exception('Not implemented.'); + } + + /** + * Automatically climb the tree and close the closest node with the matching $tag. + * + * @param string $tagName + * + * @return bool + */ + protected function autoclose($tagName) + { + $working = $this->current; + do { + if (XML_ELEMENT_NODE !== $working->nodeType) { + return false; + } + if ($working->tagName === $tagName) { + $this->current = $working->parentNode; + + return true; + } + } while ($working = $working->parentNode); + + return false; + } + + /** + * Checks if the given tagname is an ancestor of the present candidate. + * + * If $this->current or anything above $this->current matches the given tag + * name, this returns true. + * + * @param string $tagName + * + * @return bool + */ + protected function isAncestor($tagName) + { + $candidate = $this->current; + while (XML_ELEMENT_NODE === $candidate->nodeType) { + if ($candidate->tagName === $tagName) { + return true; + } + $candidate = $candidate->parentNode; + } + + return false; + } + + /** + * Returns true if the immediate parent element is of the given tagname. + * + * @param string $tagName + * + * @return bool + */ + protected function isParent($tagName) + { + return $this->current->tagName === $tagName; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php b/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php new file mode 100644 index 000000000..9893a718b --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php @@ -0,0 +1,114 @@ +). + * + * @return int one of the Tokenizer::TEXTMODE_* constants + */ + public function startTag($name, $attributes = array(), $selfClosing = false); + + /** + * An end-tag. + */ + public function endTag($name); + + /** + * A comment section (unparsed character data). + */ + public function comment($cdata); + + /** + * A unit of parsed character data. + * + * Entities in this text are *already decoded*. + */ + public function text($cdata); + + /** + * Indicates that the document has been entirely processed. + */ + public function eof(); + + /** + * Emitted when the parser encounters an error condition. + */ + public function parseError($msg, $line, $col); + + /** + * A CDATA section. + * + * @param string $data + * The unparsed character data + */ + public function cdata($data); + + /** + * This is a holdover from the XML spec. + * + * While user agents don't get PIs, server-side does. + * + * @param string $name The name of the processor (e.g. 'php'). + * @param string $data The unparsed data. + */ + public function processingInstruction($name, $data = null); +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php b/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php new file mode 100644 index 000000000..b081ed96b --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php @@ -0,0 +1,33 @@ +errors = UTF8Utils::checkForIllegalCodepoints($data); + + $data = $this->replaceLinefeeds($data); + + $this->data = $data; + $this->char = 0; + $this->EOF = strlen($data); + } + + /** + * Check if upcomming chars match the given sequence. + * + * This will read the stream for the $sequence. If it's + * found, this will return true. If not, return false. + * Since this unconsumes any chars it reads, the caller + * will still need to read the next sequence, even if + * this returns true. + * + * Example: $this->scanner->sequenceMatches('') will + * see if the input stream is at the start of a + * '' string. + * + * @param string $sequence + * @param bool $caseSensitive + * + * @return bool + */ + public function sequenceMatches($sequence, $caseSensitive = true) + { + $portion = substr($this->data, $this->char, strlen($sequence)); + + return $caseSensitive ? $portion === $sequence : 0 === strcasecmp($portion, $sequence); + } + + /** + * Get the current position. + * + * @return int The current intiger byte position. + */ + public function position() + { + return $this->char; + } + + /** + * Take a peek at the next character in the data. + * + * @return string The next character. + */ + public function peek() + { + if (($this->char + 1) < $this->EOF) { + return $this->data[$this->char + 1]; + } + + return false; + } + + /** + * Get the next character. + * Note: This advances the pointer. + * + * @return string The next character. + */ + public function next() + { + ++$this->char; + + if ($this->char < $this->EOF) { + return $this->data[$this->char]; + } + + return false; + } + + /** + * Get the current character. + * Note, this does not advance the pointer. + * + * @return string The current character. + */ + public function current() + { + if ($this->char < $this->EOF) { + return $this->data[$this->char]; + } + + return false; + } + + /** + * Silently consume N chars. + * + * @param int $count + */ + public function consume($count = 1) + { + $this->char += $count; + } + + /** + * Unconsume some of the data. + * This moves the data pointer backwards. + * + * @param int $howMany The number of characters to move the pointer back. + */ + public function unconsume($howMany = 1) + { + if (($this->char - $howMany) >= 0) { + $this->char -= $howMany; + } + } + + /** + * Get the next group of that contains hex characters. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group that is hex characters. + */ + public function getHex() + { + return $this->doCharsWhile(static::CHARS_HEX); + } + + /** + * Get the next group of characters that are ASCII Alpha characters. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of ASCII alpha characters. + */ + public function getAsciiAlpha() + { + return $this->doCharsWhile(static::CHARS_ALPHA); + } + + /** + * Get the next group of characters that are ASCII Alpha characters and numbers. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of ASCII alpha characters and numbers. + */ + public function getAsciiAlphaNum() + { + return $this->doCharsWhile(static::CHARS_ALNUM); + } + + /** + * Get the next group of numbers. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of numbers. + */ + public function getNumeric() + { + return $this->doCharsWhile('0123456789'); + } + + /** + * Consume whitespace. + * Whitespace in HTML5 is: formfeed, tab, newline, space. + * + * @return int The length of the matched whitespaces. + */ + public function whitespace() + { + if ($this->char >= $this->EOF) { + return false; + } + + $len = strspn($this->data, "\n\t\f ", $this->char); + + $this->char += $len; + + return $len; + } + + /** + * Returns the current line that is being consumed. + * + * @return int The current line number. + */ + public function currentLine() + { + if (empty($this->EOF) || 0 === $this->char) { + return 1; + } + + // Add one to $this->char because we want the number for the next + // byte to be processed. + return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; + } + + /** + * Read chars until something in the mask is encountered. + * + * @param string $mask + * + * @return mixed + */ + public function charsUntil($mask) + { + return $this->doCharsUntil($mask); + } + + /** + * Read chars as long as the mask matches. + * + * @param string $mask + * + * @return int + */ + public function charsWhile($mask) + { + return $this->doCharsWhile($mask); + } + + /** + * Returns the current column of the current line that the tokenizer is at. + * + * Newlines are column 0. The first char after a newline is column 1. + * + * @return int The column number. + */ + public function columnOffset() + { + // Short circuit for the first char. + if (0 === $this->char) { + return 0; + } + + // strrpos is weird, and the offset needs to be negative for what we + // want (i.e., the last \n before $this->char). This needs to not have + // one (to make it point to the next character, the one we want the + // position of) added to it because strrpos's behaviour includes the + // final offset byte. + $backwardFrom = $this->char - 1 - strlen($this->data); + $lastLine = strrpos($this->data, "\n", $backwardFrom); + + // However, for here we want the length up until the next byte to be + // processed, so add one to the current byte ($this->char). + if (false !== $lastLine) { + $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); + } else { + // After a newline. + $findLengthOf = substr($this->data, 0, $this->char); + } + + return UTF8Utils::countChars($findLengthOf); + } + + /** + * Get all characters until EOF. + * + * This consumes characters until the EOF. + * + * @return int The number of characters remaining. + */ + public function remainingChars() + { + if ($this->char < $this->EOF) { + $data = substr($this->data, $this->char); + $this->char = $this->EOF; + + return $data; + } + + return ''; // false; + } + + /** + * Replace linefeed characters according to the spec. + * + * @param $data + * + * @return string + */ + private function replaceLinefeeds($data) + { + /* + * U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially. + * Any CR characters that are followed by LF characters must be removed, and any CR characters not + * followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are + * represented by LF characters, and there are never any CR characters in the input to the tokenization + * stage. + */ + $crlfTable = array( + "\0" => "\xEF\xBF\xBD", + "\r\n" => "\n", + "\r" => "\n", + ); + + return strtr($data, $crlfTable); + } + + /** + * Read to a particular match (or until $max bytes are consumed). + * + * This operates on byte sequences, not characters. + * + * Matches as far as possible until we reach a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes Bytes to match. + * @param int $max Maximum number of bytes to scan. + * + * @return mixed Index or false if no match is found. You should use strong + * equality when checking the result, since index could be 0. + */ + private function doCharsUntil($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strcspn($this->data, $bytes, $this->char, $max); + } else { + $len = strcspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Returns the string so long as $bytes matches. + * + * Matches as far as possible with a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the + * current char, the pointer advances and the char is part of the + * substring. + * @param int $max The max number of chars to read. + * + * @return string + */ + private function doCharsWhile($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strspn($this->data, $bytes, $this->char, $max); + } else { + $len = strspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php b/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php new file mode 100644 index 000000000..75b088610 --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php @@ -0,0 +1,336 @@ + + +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. + +*/ + +// Some conventions: +// - /* */ indicates verbatim text from the HTML 5 specification +// MPB: Not sure which version of the spec. Moving from HTML5lib to +// HTML5-PHP, I have been using this version: +// http://www.w3.org/TR/2012/CR-html5-20121217/Overview.html#contents +// +// - // indicates regular comments + +/** + * @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead. + */ +class StringInputStream implements InputStream +{ + /** + * The string data we're parsing. + */ + private $data; + + /** + * The current integer byte position we are in $data. + */ + private $char; + + /** + * Length of $data; when $char === $data, we are at the end-of-file. + */ + private $EOF; + + /** + * Parse errors. + */ + public $errors = array(); + + /** + * Create a new InputStream wrapper. + * + * @param string $data Data to parse. + * @param string $encoding The encoding to use for the data. + * @param string $debug A fprintf format to use to echo the data on stdout. + */ + public function __construct($data, $encoding = 'UTF-8', $debug = '') + { + $data = UTF8Utils::convertToUTF8($data, $encoding); + if ($debug) { + fprintf(STDOUT, $debug, $data, strlen($data)); + } + + // There is good reason to question whether it makes sense to + // do this here, since most of these checks are done during + // parsing, and since this check doesn't actually *do* anything. + $this->errors = UTF8Utils::checkForIllegalCodepoints($data); + + $data = $this->replaceLinefeeds($data); + + $this->data = $data; + $this->char = 0; + $this->EOF = strlen($data); + } + + public function __toString() + { + return $this->data; + } + + /** + * Replace linefeed characters according to the spec. + */ + protected function replaceLinefeeds($data) + { + /* + * U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially. + * Any CR characters that are followed by LF characters must be removed, and any CR characters not + * followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are + * represented by LF characters, and there are never any CR characters in the input to the tokenization + * stage. + */ + $crlfTable = array( + "\0" => "\xEF\xBF\xBD", + "\r\n" => "\n", + "\r" => "\n", + ); + + return strtr($data, $crlfTable); + } + + /** + * Returns the current line that the tokenizer is at. + */ + public function currentLine() + { + if (empty($this->EOF) || 0 === $this->char) { + return 1; + } + // Add one to $this->char because we want the number for the next + // byte to be processed. + return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; + } + + /** + * @deprecated + */ + public function getCurrentLine() + { + return $this->currentLine(); + } + + /** + * Returns the current column of the current line that the tokenizer is at. + * Newlines are column 0. The first char after a newline is column 1. + * + * @return int The column number. + */ + public function columnOffset() + { + // Short circuit for the first char. + if (0 === $this->char) { + return 0; + } + // strrpos is weird, and the offset needs to be negative for what we + // want (i.e., the last \n before $this->char). This needs to not have + // one (to make it point to the next character, the one we want the + // position of) added to it because strrpos's behaviour includes the + // final offset byte. + $backwardFrom = $this->char - 1 - strlen($this->data); + $lastLine = strrpos($this->data, "\n", $backwardFrom); + + // However, for here we want the length up until the next byte to be + // processed, so add one to the current byte ($this->char). + if (false !== $lastLine) { + $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); + } else { + // After a newline. + $findLengthOf = substr($this->data, 0, $this->char); + } + + return UTF8Utils::countChars($findLengthOf); + } + + /** + * @deprecated + */ + public function getColumnOffset() + { + return $this->columnOffset(); + } + + /** + * Get the current character. + * + * @return string The current character. + */ + #[\ReturnTypeWillChange] + public function current() + { + return $this->data[$this->char]; + } + + /** + * Advance the pointer. + * This is part of the Iterator interface. + */ + #[\ReturnTypeWillChange] + public function next() + { + ++$this->char; + } + + /** + * Rewind to the start of the string. + */ + #[\ReturnTypeWillChange] + public function rewind() + { + $this->char = 0; + } + + /** + * Is the current pointer location valid. + * + * @return bool Whether the current pointer location is valid. + */ + #[\ReturnTypeWillChange] + public function valid() + { + return $this->char < $this->EOF; + } + + /** + * Get all characters until EOF. + * + * This reads to the end of the file, and sets the read marker at the + * end of the file. + * + * Note this performs bounds checking. + * + * @return string Returns the remaining text. If called when the InputStream is + * already exhausted, it returns an empty string. + */ + public function remainingChars() + { + if ($this->char < $this->EOF) { + $data = substr($this->data, $this->char); + $this->char = $this->EOF; + + return $data; + } + + return ''; // false; + } + + /** + * Read to a particular match (or until $max bytes are consumed). + * + * This operates on byte sequences, not characters. + * + * Matches as far as possible until we reach a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes Bytes to match. + * @param int $max Maximum number of bytes to scan. + * + * @return mixed Index or false if no match is found. You should use strong + * equality when checking the result, since index could be 0. + */ + public function charsUntil($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strcspn($this->data, $bytes, $this->char, $max); + } else { + $len = strcspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Returns the string so long as $bytes matches. + * + * Matches as far as possible with a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the + * current char, the pointer advances and the char is part of the + * substring. + * @param int $max The max number of chars to read. + * + * @return string + */ + public function charsWhile($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strspn($this->data, $bytes, $this->char, $max); + } else { + $len = strspn($this->data, $bytes, $this->char); + } + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Unconsume characters. + * + * @param int $howMany The number of characters to unconsume. + */ + public function unconsume($howMany = 1) + { + if (($this->char - $howMany) >= 0) { + $this->char -= $howMany; + } + } + + /** + * Look ahead without moving cursor. + */ + public function peek() + { + if (($this->char + 1) <= $this->EOF) { + return $this->data[$this->char + 1]; + } + + return false; + } + + #[\ReturnTypeWillChange] + public function key() + { + return $this->char; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php b/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php new file mode 100644 index 000000000..e8b4aa098 --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php @@ -0,0 +1,1214 @@ +scanner = $scanner; + $this->events = $eventHandler; + $this->mode = $mode; + } + + /** + * Begin parsing. + * + * This will begin scanning the document, tokenizing as it goes. + * Tokens are emitted into the event handler. + * + * Tokenizing will continue until the document is completely + * read. Errors are emitted into the event handler, but + * the parser will attempt to continue parsing until the + * entire input stream is read. + */ + public function parse() + { + do { + $this->consumeData(); + // FIXME: Add infinite loop protection. + } while ($this->carryOn); + } + + /** + * Set the text mode for the character data reader. + * + * HTML5 defines three different modes for reading text: + * - Normal: Read until a tag is encountered. + * - RCDATA: Read until a tag is encountered, but skip a few otherwise- + * special characters. + * - Raw: Read until a special closing tag is encountered (viz. pre, script) + * + * This allows those modes to be set. + * + * Normally, setting is done by the event handler via a special return code on + * startTag(), but it can also be set manually using this function. + * + * @param int $textmode One of Elements::TEXT_*. + * @param string $untilTag The tag that should stop RAW or RCDATA mode. Normal mode does not + * use this indicator. + */ + public function setTextMode($textmode, $untilTag = null) + { + $this->textMode = $textmode & (Elements::TEXT_RAW | Elements::TEXT_RCDATA); + $this->untilTag = $untilTag; + } + + /** + * Consume a character and make a move. + * HTML5 8.2.4.1. + */ + protected function consumeData() + { + $tok = $this->scanner->current(); + + if ('&' === $tok) { + // Character reference + $ref = $this->decodeCharacterReference(); + $this->buffer($ref); + + $tok = $this->scanner->current(); + } + + // Parse tag + if ('<' === $tok) { + // Any buffered text data can go out now. + $this->flushBuffer(); + + $tok = $this->scanner->next(); + + if (false === $tok) { + // end of string + $this->parseError('Illegal tag opening'); + } elseif ('!' === $tok) { + $this->markupDeclaration(); + } elseif ('/' === $tok) { + $this->endTag(); + } elseif ('?' === $tok) { + $this->processingInstruction(); + } elseif ($this->is_alpha($tok)) { + $this->tagName(); + } else { + $this->parseError('Illegal tag opening'); + // TODO is this necessary ? + $this->characterData(); + } + + $tok = $this->scanner->current(); + } + + if (false === $tok) { + // Handle end of document + $this->eof(); + } else { + // Parse character + switch ($this->textMode) { + case Elements::TEXT_RAW: + $this->rawText($tok); + break; + + case Elements::TEXT_RCDATA: + $this->rcdata($tok); + break; + + default: + if ('<' === $tok || '&' === $tok) { + break; + } + + // NULL character + if ("\00" === $tok) { + $this->parseError('Received null character.'); + + $this->text .= $tok; + $this->scanner->consume(); + + break; + } + + $this->text .= $this->scanner->charsUntil("<&\0"); + } + } + + return $this->carryOn; + } + + /** + * Parse anything that looks like character data. + * + * Different rules apply based on the current text mode. + * + * @see Elements::TEXT_RAW Elements::TEXT_RCDATA. + */ + protected function characterData() + { + $tok = $this->scanner->current(); + if (false === $tok) { + return false; + } + switch ($this->textMode) { + case Elements::TEXT_RAW: + return $this->rawText($tok); + case Elements::TEXT_RCDATA: + return $this->rcdata($tok); + default: + if ('<' === $tok || '&' === $tok) { + return false; + } + + return $this->text($tok); + } + } + + /** + * This buffers the current token as character data. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function text($tok) + { + // This should never happen... + if (false === $tok) { + return false; + } + + // NULL character + if ("\00" === $tok) { + $this->parseError('Received null character.'); + } + + $this->buffer($tok); + $this->scanner->consume(); + + return true; + } + + /** + * Read text in RAW mode. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function rawText($tok) + { + if (is_null($this->untilTag)) { + return $this->text($tok); + } + + $sequence = 'untilTag . '>'; + $txt = $this->readUntilSequence($sequence); + $this->events->text($txt); + $this->setTextMode(0); + + return $this->endTag(); + } + + /** + * Read text in RCDATA mode. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function rcdata($tok) + { + if (is_null($this->untilTag)) { + return $this->text($tok); + } + + $sequence = 'untilTag; + $txt = ''; + + $caseSensitive = !Elements::isHtml5Element($this->untilTag); + while (false !== $tok && !('<' == $tok && ($this->scanner->sequenceMatches($sequence, $caseSensitive)))) { + if ('&' == $tok) { + $txt .= $this->decodeCharacterReference(); + $tok = $this->scanner->current(); + } else { + $txt .= $tok; + $tok = $this->scanner->next(); + } + } + $len = strlen($sequence); + $this->scanner->consume($len); + $len += $this->scanner->whitespace(); + if ('>' !== $this->scanner->current()) { + $this->parseError('Unclosed RCDATA end tag'); + } + + $this->scanner->unconsume($len); + $this->events->text($txt); + $this->setTextMode(0); + + return $this->endTag(); + } + + /** + * If the document is read, emit an EOF event. + */ + protected function eof() + { + // fprintf(STDOUT, "EOF"); + $this->flushBuffer(); + $this->events->eof(); + $this->carryOn = false; + } + + /** + * Look for markup. + */ + protected function markupDeclaration() + { + $tok = $this->scanner->next(); + + // Comment: + if ('-' == $tok && '-' == $this->scanner->peek()) { + $this->scanner->consume(2); + + return $this->comment(); + } elseif ('D' == $tok || 'd' == $tok) { // Doctype + return $this->doctype(); + } elseif ('[' == $tok) { // CDATA section + return $this->cdataSection(); + } + + // FINISH + $this->parseError('Expected . Emit an empty comment because 8.2.4.46 says to. + if ('>' == $tok) { + // Parse error. Emit the comment token. + $this->parseError("Expected comment data, got '>'"); + $this->events->comment(''); + $this->scanner->consume(); + + return true; + } + + // Replace NULL with the replacement char. + if ("\0" == $tok) { + $tok = UTF8Utils::FFFD; + } + while (!$this->isCommentEnd()) { + $comment .= $tok; + $tok = $this->scanner->next(); + } + + $this->events->comment($comment); + $this->scanner->consume(); + + return true; + } + + /** + * Check if the scanner has reached the end of a comment. + * + * @return bool + */ + protected function isCommentEnd() + { + $tok = $this->scanner->current(); + + // EOF + if (false === $tok) { + // Hit the end. + $this->parseError('Unexpected EOF in a comment.'); + + return true; + } + + // If next two tokens are not '--', not the end. + if ('-' != $tok || '-' != $this->scanner->peek()) { + return false; + } + + $this->scanner->consume(2); // Consume '-' and one of '!' or '>' + + // Test for '>' + if ('>' == $this->scanner->current()) { + return true; + } + // Test for '!>' + if ('!' == $this->scanner->current() && '>' == $this->scanner->peek()) { + $this->scanner->consume(); // Consume the last '>' + return true; + } + // Unread '-' and one of '!' or '>'; + $this->scanner->unconsume(2); + + return false; + } + + /** + * Parse a DOCTYPE. + * + * Parse a DOCTYPE declaration. This method has strong bearing on whether or + * not Quirksmode is enabled on the event handler. + * + * @todo This method is a little long. Should probably refactor. + * + * @return bool + */ + protected function doctype() + { + // Check that string is DOCTYPE. + if ($this->scanner->sequenceMatches('DOCTYPE', false)) { + $this->scanner->consume(7); + } else { + $chars = $this->scanner->charsWhile('DOCTYPEdoctype'); + $this->parseError('Expected DOCTYPE, got %s', $chars); + + return $this->bogusComment('scanner->whitespace(); + $tok = $this->scanner->current(); + + // EOF: die. + if (false === $tok) { + $this->events->doctype('html5', EventHandler::DOCTYPE_NONE, '', true); + $this->eof(); + + return true; + } + + // NULL char: convert. + if ("\0" === $tok) { + $this->parseError('Unexpected null character in DOCTYPE.'); + } + + $stop = " \n\f>"; + $doctypeName = $this->scanner->charsUntil($stop); + // Lowercase ASCII, replace \0 with FFFD + $doctypeName = strtolower(strtr($doctypeName, "\0", UTF8Utils::FFFD)); + + $tok = $this->scanner->current(); + + // If false, emit a parse error, DOCTYPE, and return. + if (false === $tok) { + $this->parseError('Unexpected EOF in DOCTYPE declaration.'); + $this->events->doctype($doctypeName, EventHandler::DOCTYPE_NONE, null, true); + + return true; + } + + // Short DOCTYPE, like + if ('>' == $tok) { + // DOCTYPE without a name. + if (0 == strlen($doctypeName)) { + $this->parseError('Expected a DOCTYPE name. Got nothing.'); + $this->events->doctype($doctypeName, 0, null, true); + $this->scanner->consume(); + + return true; + } + $this->events->doctype($doctypeName); + $this->scanner->consume(); + + return true; + } + $this->scanner->whitespace(); + + $pub = strtoupper($this->scanner->getAsciiAlpha()); + $white = $this->scanner->whitespace(); + + // Get ID, and flag it as pub or system. + if (('PUBLIC' == $pub || 'SYSTEM' == $pub) && $white > 0) { + // Get the sys ID. + $type = 'PUBLIC' == $pub ? EventHandler::DOCTYPE_PUBLIC : EventHandler::DOCTYPE_SYSTEM; + $id = $this->quotedString("\0>"); + if (false === $id) { + $this->events->doctype($doctypeName, $type, $pub, false); + + return true; + } + + // Premature EOF. + if (false === $this->scanner->current()) { + $this->parseError('Unexpected EOF in DOCTYPE'); + $this->events->doctype($doctypeName, $type, $id, true); + + return true; + } + + // Well-formed complete DOCTYPE. + $this->scanner->whitespace(); + if ('>' == $this->scanner->current()) { + $this->events->doctype($doctypeName, $type, $id, false); + $this->scanner->consume(); + + return true; + } + + // If we get here, we have scanner->charsUntil('>'); + $this->parseError('Malformed DOCTYPE.'); + $this->events->doctype($doctypeName, $type, $id, true); + $this->scanner->consume(); + + return true; + } + + // Else it's a bogus DOCTYPE. + // Consume to > and trash. + $this->scanner->charsUntil('>'); + + $this->parseError('Expected PUBLIC or SYSTEM. Got %s.', $pub); + $this->events->doctype($doctypeName, 0, null, true); + $this->scanner->consume(); + + return true; + } + + /** + * Utility for reading a quoted string. + * + * @param string $stopchars Characters (in addition to a close-quote) that should stop the string. + * E.g. sometimes '>' is higher precedence than '"' or "'". + * + * @return mixed String if one is found (quotations omitted). + */ + protected function quotedString($stopchars) + { + $tok = $this->scanner->current(); + if ('"' == $tok || "'" == $tok) { + $this->scanner->consume(); + $ret = $this->scanner->charsUntil($tok . $stopchars); + if ($this->scanner->current() == $tok) { + $this->scanner->consume(); + } else { + // Parse error because no close quote. + $this->parseError('Expected %s, got %s', $tok, $this->scanner->current()); + } + + return $ret; + } + + return false; + } + + /** + * Handle a CDATA section. + * + * @return bool + */ + protected function cdataSection() + { + $cdata = ''; + $this->scanner->consume(); + + $chars = $this->scanner->charsWhile('CDAT'); + if ('CDATA' != $chars || '[' != $this->scanner->current()) { + $this->parseError('Expected [CDATA[, got %s', $chars); + + return $this->bogusComment('scanner->next(); + do { + if (false === $tok) { + $this->parseError('Unexpected EOF inside CDATA.'); + $this->bogusComment('scanner->next(); + } while (!$this->scanner->sequenceMatches(']]>')); + + // Consume ]]> + $this->scanner->consume(3); + + $this->events->cdata($cdata); + + return true; + } + + // ================================================================ + // Non-HTML5 + // ================================================================ + + /** + * Handle a processing instruction. + * + * XML processing instructions are supposed to be ignored in HTML5, + * treated as "bogus comments". However, since we're not a user + * agent, we allow them. We consume until ?> and then issue a + * EventListener::processingInstruction() event. + * + * @return bool + */ + protected function processingInstruction() + { + if ('?' != $this->scanner->current()) { + return false; + } + + $tok = $this->scanner->next(); + $procName = $this->scanner->getAsciiAlpha(); + $white = $this->scanner->whitespace(); + + // If not a PI, send to bogusComment. + if (0 == strlen($procName) || 0 == $white || false == $this->scanner->current()) { + $this->parseError("Expected processing instruction name, got $tok"); + $this->bogusComment('. + while (!('?' == $this->scanner->current() && '>' == $this->scanner->peek())) { + $data .= $this->scanner->current(); + + $tok = $this->scanner->next(); + if (false === $tok) { + $this->parseError('Unexpected EOF in processing instruction.'); + $this->events->processingInstruction($procName, $data); + + return true; + } + } + + $this->scanner->consume(2); // Consume the closing tag + $this->events->processingInstruction($procName, $data); + + return true; + } + + // ================================================================ + // UTILITY FUNCTIONS + // ================================================================ + + /** + * Read from the input stream until we get to the desired sequene + * or hit the end of the input stream. + * + * @param string $sequence + * + * @return string + */ + protected function readUntilSequence($sequence) + { + $buffer = ''; + + // Optimization for reading larger blocks faster. + $first = substr($sequence, 0, 1); + while (false !== $this->scanner->current()) { + $buffer .= $this->scanner->charsUntil($first); + + // Stop as soon as we hit the stopping condition. + if ($this->scanner->sequenceMatches($sequence, false)) { + return $buffer; + } + $buffer .= $this->scanner->current(); + $this->scanner->consume(); + } + + // If we get here, we hit the EOF. + $this->parseError('Unexpected EOF during text read.'); + + return $buffer; + } + + /** + * Check if upcomming chars match the given sequence. + * + * This will read the stream for the $sequence. If it's + * found, this will return true. If not, return false. + * Since this unconsumes any chars it reads, the caller + * will still need to read the next sequence, even if + * this returns true. + * + * Example: $this->scanner->sequenceMatches('') will + * see if the input stream is at the start of a + * '' string. + * + * @param string $sequence + * @param bool $caseSensitive + * + * @return bool + */ + protected function sequenceMatches($sequence, $caseSensitive = true) + { + @trigger_error(__METHOD__ . ' method is deprecated since version 2.4 and will be removed in 3.0. Use Scanner::sequenceMatches() instead.', E_USER_DEPRECATED); + + return $this->scanner->sequenceMatches($sequence, $caseSensitive); + } + + /** + * Send a TEXT event with the contents of the text buffer. + * + * This emits an EventHandler::text() event with the current contents of the + * temporary text buffer. (The buffer is used to group as much PCDATA + * as we can instead of emitting lots and lots of TEXT events.) + */ + protected function flushBuffer() + { + if ('' === $this->text) { + return; + } + $this->events->text($this->text); + $this->text = ''; + } + + /** + * Add text to the temporary buffer. + * + * @see flushBuffer() + * + * @param string $str + */ + protected function buffer($str) + { + $this->text .= $str; + } + + /** + * Emit a parse error. + * + * A parse error always returns false because it never consumes any + * characters. + * + * @param string $msg + * + * @return string + */ + protected function parseError($msg) + { + $args = func_get_args(); + + if (count($args) > 1) { + array_shift($args); + $msg = vsprintf($msg, $args); + } + + $line = $this->scanner->currentLine(); + $col = $this->scanner->columnOffset(); + $this->events->parseError($msg, $line, $col); + + return false; + } + + /** + * Decode a character reference and return the string. + * + * If $inAttribute is set to true, a bare & will be returned as-is. + * + * @param bool $inAttribute Set to true if the text is inside of an attribute value. + * false otherwise. + * + * @return string + */ + protected function decodeCharacterReference($inAttribute = false) + { + // Next char after &. + $tok = $this->scanner->next(); + $start = $this->scanner->position(); + + if (false === $tok) { + return '&'; + } + + // These indicate not an entity. We return just + // the &. + if ("\t" === $tok || "\n" === $tok || "\f" === $tok || ' ' === $tok || '&' === $tok || '<' === $tok) { + // $this->scanner->next(); + return '&'; + } + + // Numeric entity + if ('#' === $tok) { + $tok = $this->scanner->next(); + + if (false === $tok) { + $this->parseError('Expected &#DEC; &#HEX;, got EOF'); + $this->scanner->unconsume(1); + + return '&'; + } + + // Hexidecimal encoding. + // X[0-9a-fA-F]+; + // x[0-9a-fA-F]+; + if ('x' === $tok || 'X' === $tok) { + $tok = $this->scanner->next(); // Consume x + + // Convert from hex code to char. + $hex = $this->scanner->getHex(); + if (empty($hex)) { + $this->parseError('Expected &#xHEX;, got &#x%s', $tok); + // We unconsume because we don't know what parser rules might + // be in effect for the remaining chars. For example. '&#>' + // might result in a specific parsing rule inside of tag + // contexts, while not inside of pcdata context. + $this->scanner->unconsume(2); + + return '&'; + } + $entity = CharacterReference::lookupHex($hex); + } // Decimal encoding. + // [0-9]+; + else { + // Convert from decimal to char. + $numeric = $this->scanner->getNumeric(); + if (false === $numeric) { + $this->parseError('Expected &#DIGITS;, got &#%s', $tok); + $this->scanner->unconsume(2); + + return '&'; + } + $entity = CharacterReference::lookupDecimal($numeric); + } + } elseif ('=' === $tok && $inAttribute) { + return '&'; + } else { // String entity. + // Attempt to consume a string up to a ';'. + // [a-zA-Z0-9]+; + $cname = $this->scanner->getAsciiAlphaNum(); + $entity = CharacterReference::lookupName($cname); + + // When no entity is found provide the name of the unmatched string + // and continue on as the & is not part of an entity. The & will + // be converted to & elsewhere. + if (null === $entity) { + if (!$inAttribute || '' === $cname) { + $this->parseError("No match in entity table for '%s'", $cname); + } + $this->scanner->unconsume($this->scanner->position() - $start); + + return '&'; + } + } + + // The scanner has advanced the cursor for us. + $tok = $this->scanner->current(); + + // We have an entity. We're done here. + if (';' === $tok) { + $this->scanner->consume(); + + return $entity; + } + + // Failing to match ; means unconsume the entire string. + $this->scanner->unconsume($this->scanner->position() - $start); + + $this->parseError('Expected &ENTITY;, got &ENTITY%s (no trailing ;) ', $tok); + + return '&'; + } + + /** + * Checks whether a (single-byte) character is an ASCII letter or not. + * + * @param string $input A single-byte string + * + * @return bool True if it is a letter, False otherwise + */ + protected function is_alpha($input) + { + $code = ord($input); + + return ($code >= 97 && $code <= 122) || ($code >= 65 && $code <= 90); + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php b/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php new file mode 100644 index 000000000..00d3951fd --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php @@ -0,0 +1,127 @@ + 1, + 'dd' => 1, + 'dt' => 1, + 'rt' => 1, + 'rp' => 1, + 'tr' => 1, + 'th' => 1, + 'td' => 1, + 'thead' => 1, + 'tfoot' => 1, + 'tbody' => 1, + 'table' => 1, + 'optgroup' => 1, + 'option' => 1, + ); + + /** + * Returns true if the given tagname has special processing rules. + */ + public function hasRules($tagname) + { + return isset(static::$tags[$tagname]); + } + + /** + * Evaluate the rule for the current tag name. + * + * This may modify the existing DOM. + * + * @return \DOMElement The new Current DOM element. + */ + public function evaluate($new, $current) + { + switch ($new->tagName) { + case 'li': + return $this->handleLI($new, $current); + case 'dt': + case 'dd': + return $this->handleDT($new, $current); + case 'rt': + case 'rp': + return $this->handleRT($new, $current); + case 'optgroup': + return $this->closeIfCurrentMatches($new, $current, array( + 'optgroup', + )); + case 'option': + return $this->closeIfCurrentMatches($new, $current, array( + 'option', + )); + case 'tr': + return $this->closeIfCurrentMatches($new, $current, array( + 'tr', + )); + case 'td': + case 'th': + return $this->closeIfCurrentMatches($new, $current, array( + 'th', + 'td', + )); + case 'tbody': + case 'thead': + case 'tfoot': + case 'table': // Spec isn't explicit about this, but it's necessary. + + return $this->closeIfCurrentMatches($new, $current, array( + 'thead', + 'tfoot', + 'tbody', + )); + } + + return $current; + } + + protected function handleLI($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'li', + )); + } + + protected function handleDT($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'dt', + 'dd', + )); + } + + protected function handleRT($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'rt', + 'rp', + )); + } + + protected function closeIfCurrentMatches($ele, $current, $match) + { + if (in_array($current->tagName, $match, true)) { + $current->parentNode->appendChild($ele); + } else { + $current->appendChild($ele); + } + + return $ele; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php b/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php new file mode 100644 index 000000000..4405e4cc0 --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php @@ -0,0 +1,177 @@ + + +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. +*/ + +use Masterminds\HTML5\Exception; + +class UTF8Utils +{ + /** + * The Unicode replacement character. + */ + const FFFD = "\xEF\xBF\xBD"; + + /** + * Count the number of characters in a string. + * UTF-8 aware. This will try (in order) iconv, MB, and finally a custom counter. + * + * @param string $string + * + * @return int + */ + public static function countChars($string) + { + // Get the length for the string we need. + if (function_exists('mb_strlen')) { + return mb_strlen($string, 'utf-8'); + } + + if (function_exists('iconv_strlen')) { + return iconv_strlen($string, 'utf-8'); + } + + $count = count_chars($string); + + // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range) + // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range) + return array_sum(array_slice($count, 0, 0x80)) + array_sum(array_slice($count, 0xC2, 0x33)); + } + + /** + * Convert data from the given encoding to UTF-8. + * + * This has not yet been tested with charactersets other than UTF-8. + * It should work with ISO-8859-1/-13 and standard Latin Win charsets. + * + * @param string $data The data to convert + * @param string $encoding A valid encoding. Examples: http://www.php.net/manual/en/mbstring.supported-encodings.php + * + * @return string + */ + public static function convertToUTF8($data, $encoding = 'UTF-8') + { + /* + * From the HTML5 spec: Given an encoding, the bytes in the input stream must be converted + * to Unicode characters for the tokeniser, as described by the rules for that encoding, + * except that the leading U+FEFF BYTE ORDER MARK character, if any, must not be stripped + * by the encoding layer (it is stripped by the rule below). Bytes or sequences of bytes + * in the original byte stream that could not be converted to Unicode characters must be + * converted to U+FFFD REPLACEMENT CHARACTER code points. + */ + + // mb_convert_encoding is chosen over iconv because of a bug. The best + // details for the bug are on http://us1.php.net/manual/en/function.iconv.php#108643 + // which contains links to the actual but reports as well as work around + // details. + if (function_exists('mb_convert_encoding')) { + // mb library has the following behaviors: + // - UTF-16 surrogates result in false. + // - Overlongs and outside Plane 16 result in empty strings. + + // Before we run mb_convert_encoding we need to tell it what to do with + // characters it does not know. This could be different than the parent + // application executing this library so we store the value, change it + // to our needs, and then change it back when we are done. This feels + // a little excessive and it would be great if there was a better way. + $save = mb_substitute_character(); + mb_substitute_character('none'); + $data = mb_convert_encoding($data, 'UTF-8', $encoding); + mb_substitute_character($save); + } + // @todo Get iconv running in at least some environments if that is possible. + elseif (function_exists('iconv') && 'auto' !== $encoding) { + // fprintf(STDOUT, "iconv found\n"); + // iconv has the following behaviors: + // - Overlong representations are ignored. + // - Beyond Plane 16 is replaced with a lower char. + // - Incomplete sequences generate a warning. + $data = @iconv($encoding, 'UTF-8//IGNORE', $data); + } else { + throw new Exception('Not implemented, please install mbstring or iconv'); + } + + /* + * One leading U+FEFF BYTE ORDER MARK character must be ignored if any are present. + */ + if ("\xEF\xBB\xBF" === substr($data, 0, 3)) { + $data = substr($data, 3); + } + + return $data; + } + + /** + * Checks for Unicode code points that are not valid in a document. + * + * @param string $data A string to analyze + * + * @return array An array of (string) error messages produced by the scanning + */ + public static function checkForIllegalCodepoints($data) + { + // Vestigal error handling. + $errors = array(); + + /* + * All U+0000 null characters in the input must be replaced by U+FFFD REPLACEMENT CHARACTERs. + * Any occurrences of such characters is a parse error. + */ + for ($i = 0, $count = substr_count($data, "\0"); $i < $count; ++$i) { + $errors[] = 'null-character'; + } + + /* + * Any occurrences of any characters in the ranges U+0001 to U+0008, U+000B, U+000E to U+001F, U+007F + * to U+009F, U+D800 to U+DFFF , U+FDD0 to U+FDEF, and characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, + * U+2FFFE, U+2FFFF, U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, U+6FFFF, U+7FFFE, + * U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, + * U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and U+10FFFF are parse errors. + * (These are all control characters or permanently undefined Unicode characters.) + */ + // Check PCRE is loaded. + $count = preg_match_all( + '/(?: + [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F + | + \xC2[\x80-\x9F] # U+0080 to U+009F + | + \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF + | + \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF + | + \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF + | + [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16}) + )/x', $data, $matches); + for ($i = 0; $i < $count; ++$i) { + $errors[] = 'invalid-codepoint'; + } + + return $errors; + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php b/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php new file mode 100644 index 000000000..e9421a12d --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php @@ -0,0 +1,1533 @@ + ' ', + "\n" => ' ', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + '\'' => ''', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '.' => '.', + '/' => '/', + ':' => ':', + ';' => ';', + '<' => '<', + '<⃒' => '&nvlt', + '=' => '=', + '=⃥' => '&bne', + '>' => '>', + '>⃒' => '&nvgt', + '?' => '?', + '@' => '@', + '[' => '[', + '\\' => '\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'fj' => '&fjlig', + '{' => '{', + '|' => '|', + '}' => '}', + ' ' => ' ', + '¡' => '¡', + '¢' => '¢', + '£' => '£', + '¤' => '¤', + '¥' => '¥', + '¦' => '¦', + '§' => '§', + '¨' => '¨', + '©' => '©', + 'ª' => 'ª', + '«' => '«', + '¬' => '¬', + '­' => '­', + '®' => '®', + '¯' => '¯', + '°' => '°', + '±' => '±', + '²' => '²', + '³' => '³', + '´' => '´', + 'µ' => 'µ', + '¶' => '¶', + '·' => '·', + '¸' => '¸', + '¹' => '¹', + 'º' => 'º', + '»' => '»', + '¼' => '¼', + '½' => '½', + '¾' => '¾', + '¿' => '¿', + 'À' => 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Æ' => 'Æ', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ð' => 'Ð', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + '×' => '×', + 'Ø' => 'Ø', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'Þ' => 'Þ', + 'ß' => 'ß', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'æ' => 'æ', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ð' => 'ð', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + '÷' => '÷', + 'ø' => 'ø', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'þ' => 'þ', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Đ' => 'Đ', + 'đ' => 'đ', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ħ' => 'Ħ', + 'ħ' => 'ħ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'ı' => 'ı', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'ĸ' => 'ĸ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ŀ' => 'Ŀ', + 'ŀ' => 'ŀ', + 'Ł' => 'Ł', + 'ł' => 'ł', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'ʼn' => 'ʼn', + 'Ŋ' => 'Ŋ', + 'ŋ' => 'ŋ', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Œ' => 'Œ', + 'œ' => 'œ', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ŧ' => 'Ŧ', + 'ŧ' => 'ŧ', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'ƒ' => 'ƒ', + 'Ƶ' => 'Ƶ', + 'ǵ' => 'ǵ', + 'ȷ' => 'ȷ', + 'ˆ' => 'ˆ', + 'ˇ' => 'ˇ', + '˘' => '˘', + '˙' => '˙', + '˚' => '˚', + '˛' => '˛', + '˜' => '˜', + '˝' => '˝', + '̑' => '̑', + 'Α' => 'Α', + 'Β' => 'Β', + 'Γ' => 'Γ', + 'Δ' => 'Δ', + 'Ε' => 'Ε', + 'Ζ' => 'Ζ', + 'Η' => 'Η', + 'Θ' => 'Θ', + 'Ι' => 'Ι', + 'Κ' => 'Κ', + 'Λ' => 'Λ', + 'Μ' => 'Μ', + 'Ν' => 'Ν', + 'Ξ' => 'Ξ', + 'Ο' => 'Ο', + 'Π' => 'Π', + 'Ρ' => 'Ρ', + 'Σ' => 'Σ', + 'Τ' => 'Τ', + 'Υ' => 'Υ', + 'Φ' => 'Φ', + 'Χ' => 'Χ', + 'Ψ' => 'Ψ', + 'Ω' => 'Ω', + 'α' => 'α', + 'β' => 'β', + 'γ' => 'γ', + 'δ' => 'δ', + 'ε' => 'ε', + 'ζ' => 'ζ', + 'η' => 'η', + 'θ' => 'θ', + 'ι' => 'ι', + 'κ' => 'κ', + 'λ' => 'λ', + 'μ' => 'μ', + 'ν' => 'ν', + 'ξ' => 'ξ', + 'ο' => 'ο', + 'π' => 'π', + 'ρ' => 'ρ', + 'ς' => 'ς', + 'σ' => 'σ', + 'τ' => 'τ', + 'υ' => 'υ', + 'φ' => 'φ', + 'χ' => 'χ', + 'ψ' => 'ψ', + 'ω' => 'ω', + 'ϑ' => 'ϑ', + 'ϒ' => 'ϒ', + 'ϕ' => 'ϕ', + 'ϖ' => 'ϖ', + 'Ϝ' => 'Ϝ', + 'ϝ' => 'ϝ', + 'ϰ' => 'ϰ', + 'ϱ' => 'ϱ', + 'ϵ' => 'ϵ', + '϶' => '϶', + 'Ё' => 'Ё', + 'Ђ' => 'Ђ', + 'Ѓ' => 'Ѓ', + 'Є' => 'Є', + 'Ѕ' => 'Ѕ', + 'І' => 'І', + 'Ї' => 'Ї', + 'Ј' => 'Ј', + 'Љ' => 'Љ', + 'Њ' => 'Њ', + 'Ћ' => 'Ћ', + 'Ќ' => 'Ќ', + 'Ў' => 'Ў', + 'Џ' => 'Џ', + 'А' => 'А', + 'Б' => 'Б', + 'В' => 'В', + 'Г' => 'Г', + 'Д' => 'Д', + 'Е' => 'Е', + 'Ж' => 'Ж', + 'З' => 'З', + 'И' => 'И', + 'Й' => 'Й', + 'К' => 'К', + 'Л' => 'Л', + 'М' => 'М', + 'Н' => 'Н', + 'О' => 'О', + 'П' => 'П', + 'Р' => 'Р', + 'С' => 'С', + 'Т' => 'Т', + 'У' => 'У', + 'Ф' => 'Ф', + 'Х' => 'Х', + 'Ц' => 'Ц', + 'Ч' => 'Ч', + 'Ш' => 'Ш', + 'Щ' => 'Щ', + 'Ъ' => 'Ъ', + 'Ы' => 'Ы', + 'Ь' => 'Ь', + 'Э' => 'Э', + 'Ю' => 'Ю', + 'Я' => 'Я', + 'а' => 'а', + 'б' => 'б', + 'в' => 'в', + 'г' => 'г', + 'д' => 'д', + 'е' => 'е', + 'ж' => 'ж', + 'з' => 'з', + 'и' => 'и', + 'й' => 'й', + 'к' => 'к', + 'л' => 'л', + 'м' => 'м', + 'н' => 'н', + 'о' => 'о', + 'п' => 'п', + 'р' => 'р', + 'с' => 'с', + 'т' => 'т', + 'у' => 'у', + 'ф' => 'ф', + 'х' => 'х', + 'ц' => 'ц', + 'ч' => 'ч', + 'ш' => 'ш', + 'щ' => 'щ', + 'ъ' => 'ъ', + 'ы' => 'ы', + 'ь' => 'ь', + 'э' => 'э', + 'ю' => 'ю', + 'я' => 'я', + 'ё' => 'ё', + 'ђ' => 'ђ', + 'ѓ' => 'ѓ', + 'є' => 'є', + 'ѕ' => 'ѕ', + 'і' => 'і', + 'ї' => 'ї', + 'ј' => 'ј', + 'љ' => 'љ', + 'њ' => 'њ', + 'ћ' => 'ћ', + 'ќ' => 'ќ', + 'ў' => 'ў', + 'џ' => 'џ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '​' => '​', + '‌' => '‌', + '‍' => '‍', + '‎' => '‎', + '‏' => '‏', + '‐' => '‐', + '–' => '–', + '—' => '—', + '―' => '―', + '‖' => '‖', + '‘' => '‘', + '’' => '’', + '‚' => '‚', + '“' => '“', + '”' => '”', + '„' => '„', + '†' => '†', + '‡' => '‡', + '•' => '•', + '‥' => '‥', + '…' => '…', + '‰' => '‰', + '‱' => '‱', + '′' => '′', + '″' => '″', + '‴' => '‴', + '‵' => '‵', + '‹' => '‹', + '›' => '›', + '‾' => '‾', + '⁁' => '⁁', + '⁃' => '⁃', + '⁄' => '⁄', + '⁏' => '⁏', + '⁗' => '⁗', + ' ' => ' ', + '  ' => '&ThickSpace', + '⁠' => '⁠', + '⁡' => '⁡', + '⁢' => '⁢', + '⁣' => '⁣', + '€' => '€', + '⃛' => '⃛', + '⃜' => '⃜', + 'ℂ' => 'ℂ', + '℅' => '℅', + 'ℊ' => 'ℊ', + 'ℋ' => 'ℋ', + 'ℌ' => 'ℌ', + 'ℍ' => 'ℍ', + 'ℎ' => 'ℎ', + 'ℏ' => 'ℏ', + 'ℐ' => 'ℐ', + 'ℑ' => 'ℑ', + 'ℒ' => 'ℒ', + 'ℓ' => 'ℓ', + 'ℕ' => 'ℕ', + '№' => '№', + '℗' => '℗', + '℘' => '℘', + 'ℙ' => 'ℙ', + 'ℚ' => 'ℚ', + 'ℛ' => 'ℛ', + 'ℜ' => 'ℜ', + 'ℝ' => 'ℝ', + '℞' => '℞', + '™' => '™', + 'ℤ' => 'ℤ', + '℧' => '℧', + 'ℨ' => 'ℨ', + '℩' => '℩', + 'ℬ' => 'ℬ', + 'ℭ' => 'ℭ', + 'ℯ' => 'ℯ', + 'ℰ' => 'ℰ', + 'ℱ' => 'ℱ', + 'ℳ' => 'ℳ', + 'ℴ' => 'ℴ', + 'ℵ' => 'ℵ', + 'ℶ' => 'ℶ', + 'ℷ' => 'ℷ', + 'ℸ' => 'ℸ', + 'ⅅ' => 'ⅅ', + 'ⅆ' => 'ⅆ', + 'ⅇ' => 'ⅇ', + 'ⅈ' => 'ⅈ', + '⅓' => '⅓', + '⅔' => '⅔', + '⅕' => '⅕', + '⅖' => '⅖', + '⅗' => '⅗', + '⅘' => '⅘', + '⅙' => '⅙', + '⅚' => '⅚', + '⅛' => '⅛', + '⅜' => '⅜', + '⅝' => '⅝', + '⅞' => '⅞', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '↔' => '↔', + '↕' => '↕', + '↖' => '↖', + '↗' => '↗', + '↘' => '↘', + '↙' => '↙', + '↚' => '↚', + '↛' => '↛', + '↝' => '↝', + '↝̸' => '&nrarrw', + '↞' => '↞', + '↟' => '↟', + '↠' => '↠', + '↡' => '↡', + '↢' => '↢', + '↣' => '↣', + '↤' => '↤', + '↥' => '↥', + '↦' => '↦', + '↧' => '↧', + '↩' => '↩', + '↪' => '↪', + '↫' => '↫', + '↬' => '↬', + '↭' => '↭', + '↮' => '↮', + '↰' => '↰', + '↱' => '↱', + '↲' => '↲', + '↳' => '↳', + '↵' => '↵', + '↶' => '↶', + '↷' => '↷', + '↺' => '↺', + '↻' => '↻', + '↼' => '↼', + '↽' => '↽', + '↾' => '↾', + '↿' => '↿', + '⇀' => '⇀', + '⇁' => '⇁', + '⇂' => '⇂', + '⇃' => '⇃', + '⇄' => '⇄', + '⇅' => '⇅', + '⇆' => '⇆', + '⇇' => '⇇', + '⇈' => '⇈', + '⇉' => '⇉', + '⇊' => '⇊', + '⇋' => '⇋', + '⇌' => '⇌', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '⇐' => '⇐', + '⇑' => '⇑', + '⇒' => '⇒', + '⇓' => '⇓', + '⇔' => '⇔', + '⇕' => '⇕', + '⇖' => '⇖', + '⇗' => '⇗', + '⇘' => '⇘', + '⇙' => '⇙', + '⇚' => '⇚', + '⇛' => '⇛', + '⇝' => '⇝', + '⇤' => '⇤', + '⇥' => '⇥', + '⇵' => '⇵', + '⇽' => '⇽', + '⇾' => '⇾', + '⇿' => '⇿', + '∀' => '∀', + '∁' => '∁', + '∂' => '∂', + '∂̸' => '&npart', + '∃' => '∃', + '∄' => '∄', + '∅' => '∅', + '∇' => '∇', + '∈' => '∈', + '∉' => '∉', + '∋' => '∋', + '∌' => '∌', + '∏' => '∏', + '∐' => '∐', + '∑' => '∑', + '−' => '−', + '∓' => '∓', + '∔' => '∔', + '∖' => '∖', + '∗' => '∗', + '∘' => '∘', + '√' => '√', + '∝' => '∝', + '∞' => '∞', + '∟' => '∟', + '∠' => '∠', + '∠⃒' => '&nang', + '∡' => '∡', + '∢' => '∢', + '∣' => '∣', + '∤' => '∤', + '∥' => '∥', + '∦' => '∦', + '∧' => '∧', + '∨' => '∨', + '∩' => '∩', + '∩︀' => '&caps', + '∪' => '∪', + '∪︀' => '&cups', + '∫' => '∫', + '∬' => '∬', + '∭' => '∭', + '∮' => '∮', + '∯' => '∯', + '∰' => '∰', + '∱' => '∱', + '∲' => '∲', + '∳' => '∳', + '∴' => '∴', + '∵' => '∵', + '∶' => '∶', + '∷' => '∷', + '∸' => '∸', + '∺' => '∺', + '∻' => '∻', + '∼' => '∼', + '∼⃒' => '&nvsim', + '∽' => '∽', + '∽̱' => '&race', + '∾' => '∾', + '∾̳' => '&acE', + '∿' => '∿', + '≀' => '≀', + '≁' => '≁', + '≂' => '≂', + '≂̸' => '&nesim', + '≃' => '≃', + '≄' => '≄', + '≅' => '≅', + '≆' => '≆', + '≇' => '≇', + '≈' => '≈', + '≉' => '≉', + '≊' => '≊', + '≋' => '≋', + '≋̸' => '&napid', + '≌' => '≌', + '≍' => '≍', + '≍⃒' => '&nvap', + '≎' => '≎', + '≎̸' => '&nbump', + '≏' => '≏', + '≏̸' => '&nbumpe', + '≐' => '≐', + '≐̸' => '&nedot', + '≑' => '≑', + '≒' => '≒', + '≓' => '≓', + '≔' => '≔', + '≕' => '≕', + '≖' => '≖', + '≗' => '≗', + '≙' => '≙', + '≚' => '≚', + '≜' => '≜', + '≟' => '≟', + '≠' => '≠', + '≡' => '≡', + '≡⃥' => '&bnequiv', + '≢' => '≢', + '≤' => '≤', + '≤⃒' => '&nvle', + '≥' => '≥', + '≥⃒' => '&nvge', + '≦' => '≦', + '≦̸' => '&nlE', + '≧' => '≧', + '≧̸' => '&NotGreaterFullEqual', + '≨' => '≨', + '≨︀' => '&lvertneqq', + '≩' => '≩', + '≩︀' => '&gvertneqq', + '≪' => '≪', + '≪̸' => '&nLtv', + '≪⃒' => '&nLt', + '≫' => '≫', + '≫̸' => '&NotGreaterGreater', + '≫⃒' => '&nGt', + '≬' => '≬', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≲' => '≲', + '≳' => '≳', + '≴' => '≴', + '≵' => '≵', + '≶' => '≶', + '≷' => '≷', + '≸' => '≸', + '≹' => '≹', + '≺' => '≺', + '≻' => '≻', + '≼' => '≼', + '≽' => '≽', + '≾' => '≾', + '≿' => '≿', + '≿̸' => '&NotSucceedsTilde', + '⊀' => '⊀', + '⊁' => '⊁', + '⊂' => '⊂', + '⊂⃒' => '&vnsub', + '⊃' => '⊃', + '⊃⃒' => '&nsupset', + '⊄' => '⊄', + '⊅' => '⊅', + '⊆' => '⊆', + '⊇' => '⊇', + '⊈' => '⊈', + '⊉' => '⊉', + '⊊' => '⊊', + '⊊︀' => '&vsubne', + '⊋' => '⊋', + '⊋︀' => '&vsupne', + '⊍' => '⊍', + '⊎' => '⊎', + '⊏' => '⊏', + '⊏̸' => '&NotSquareSubset', + '⊐' => '⊐', + '⊐̸' => '&NotSquareSuperset', + '⊑' => '⊑', + '⊒' => '⊒', + '⊓' => '⊓', + '⊓︀' => '&sqcaps', + '⊔' => '⊔', + '⊔︀' => '&sqcups', + '⊕' => '⊕', + '⊖' => '⊖', + '⊗' => '⊗', + '⊘' => '⊘', + '⊙' => '⊙', + '⊚' => '⊚', + '⊛' => '⊛', + '⊝' => '⊝', + '⊞' => '⊞', + '⊟' => '⊟', + '⊠' => '⊠', + '⊡' => '⊡', + '⊢' => '⊢', + '⊣' => '⊣', + '⊤' => '⊤', + '⊥' => '⊥', + '⊧' => '⊧', + '⊨' => '⊨', + '⊩' => '⊩', + '⊪' => '⊪', + '⊫' => '⊫', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⊰' => '⊰', + '⊲' => '⊲', + '⊳' => '⊳', + '⊴' => '⊴', + '⊴⃒' => '&nvltrie', + '⊵' => '⊵', + '⊵⃒' => '&nvrtrie', + '⊶' => '⊶', + '⊷' => '⊷', + '⊸' => '⊸', + '⊹' => '⊹', + '⊺' => '⊺', + '⊻' => '⊻', + '⊽' => '⊽', + '⊾' => '⊾', + '⊿' => '⊿', + '⋀' => '⋀', + '⋁' => '⋁', + '⋂' => '⋂', + '⋃' => '⋃', + '⋄' => '⋄', + '⋅' => '⋅', + '⋆' => '⋆', + '⋇' => '⋇', + '⋈' => '⋈', + '⋉' => '⋉', + '⋊' => '⋊', + '⋋' => '⋋', + '⋌' => '⋌', + '⋍' => '⋍', + '⋎' => '⋎', + '⋏' => '⋏', + '⋐' => '⋐', + '⋑' => '⋑', + '⋒' => '⋒', + '⋓' => '⋓', + '⋔' => '⋔', + '⋕' => '⋕', + '⋖' => '⋖', + '⋗' => '⋗', + '⋘' => '⋘', + '⋘̸' => '&nLl', + '⋙' => '⋙', + '⋙̸' => '&nGg', + '⋚' => '⋚', + '⋚︀' => '&lesg', + '⋛' => '⋛', + '⋛︀' => '&gesl', + '⋞' => '⋞', + '⋟' => '⋟', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋦' => '⋦', + '⋧' => '⋧', + '⋨' => '⋨', + '⋩' => '⋩', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '⋮' => '⋮', + '⋯' => '⋯', + '⋰' => '⋰', + '⋱' => '⋱', + '⋲' => '⋲', + '⋳' => '⋳', + '⋴' => '⋴', + '⋵' => '⋵', + '⋵̸' => '¬indot', + '⋶' => '⋶', + '⋷' => '⋷', + '⋹' => '⋹', + '⋹̸' => '¬inE', + '⋺' => '⋺', + '⋻' => '⋻', + '⋼' => '⋼', + '⋽' => '⋽', + '⋾' => '⋾', + '⌅' => '⌅', + '⌆' => '⌆', + '⌈' => '⌈', + '⌉' => '⌉', + '⌊' => '⌊', + '⌋' => '⌋', + '⌌' => '⌌', + '⌍' => '⌍', + '⌎' => '⌎', + '⌏' => '⌏', + '⌐' => '⌐', + '⌒' => '⌒', + '⌓' => '⌓', + '⌕' => '⌕', + '⌖' => '⌖', + '⌜' => '⌜', + '⌝' => '⌝', + '⌞' => '⌞', + '⌟' => '⌟', + '⌢' => '⌢', + '⌣' => '⌣', + '⌭' => '⌭', + '⌮' => '⌮', + '⌶' => '⌶', + '⌽' => '⌽', + '⌿' => '⌿', + '⍼' => '⍼', + '⎰' => '⎰', + '⎱' => '⎱', + '⎴' => '⎴', + '⎵' => '⎵', + '⎶' => '⎶', + '⏜' => '⏜', + '⏝' => '⏝', + '⏞' => '⏞', + '⏟' => '⏟', + '⏢' => '⏢', + '⏧' => '⏧', + '␣' => '␣', + 'Ⓢ' => 'Ⓢ', + '─' => '─', + '│' => '│', + '┌' => '┌', + '┐' => '┐', + '└' => '└', + '┘' => '┘', + '├' => '├', + '┤' => '┤', + '┬' => '┬', + '┴' => '┴', + '┼' => '┼', + '═' => '═', + '║' => '║', + '╒' => '╒', + '╓' => '╓', + '╔' => '╔', + '╕' => '╕', + '╖' => '╖', + '╗' => '╗', + '╘' => '╘', + '╙' => '╙', + '╚' => '╚', + '╛' => '╛', + '╜' => '╜', + '╝' => '╝', + '╞' => '╞', + '╟' => '╟', + '╠' => '╠', + '╡' => '╡', + '╢' => '╢', + '╣' => '╣', + '╤' => '╤', + '╥' => '╥', + '╦' => '╦', + '╧' => '╧', + '╨' => '╨', + '╩' => '╩', + '╪' => '╪', + '╫' => '╫', + '╬' => '╬', + '▀' => '▀', + '▄' => '▄', + '█' => '█', + '░' => '░', + '▒' => '▒', + '▓' => '▓', + '□' => '□', + '▪' => '▪', + '▫' => '▫', + '▭' => '▭', + '▮' => '▮', + '▱' => '▱', + '△' => '△', + '▴' => '▴', + '▵' => '▵', + '▸' => '▸', + '▹' => '▹', + '▽' => '▽', + '▾' => '▾', + '▿' => '▿', + '◂' => '◂', + '◃' => '◃', + '◊' => '◊', + '○' => '○', + '◬' => '◬', + '◯' => '◯', + '◸' => '◸', + '◹' => '◹', + '◺' => '◺', + '◻' => '◻', + '◼' => '◼', + '★' => '★', + '☆' => '☆', + '☎' => '☎', + '♀' => '♀', + '♂' => '♂', + '♠' => '♠', + '♣' => '♣', + '♥' => '♥', + '♦' => '♦', + '♪' => '♪', + '♭' => '♭', + '♮' => '♮', + '♯' => '♯', + '✓' => '✓', + '✗' => '✗', + '✠' => '✠', + '✶' => '✶', + '❘' => '❘', + '❲' => '❲', + '❳' => '❳', + '⟈' => '⟈', + '⟉' => '⟉', + '⟦' => '⟦', + '⟧' => '⟧', + '⟨' => '⟨', + '⟩' => '⟩', + '⟪' => '⟪', + '⟫' => '⟫', + '⟬' => '⟬', + '⟭' => '⟭', + '⟵' => '⟵', + '⟶' => '⟶', + '⟷' => '⟷', + '⟸' => '⟸', + '⟹' => '⟹', + '⟺' => '⟺', + '⟼' => '⟼', + '⟿' => '⟿', + '⤂' => '⤂', + '⤃' => '⤃', + '⤄' => '⤄', + '⤅' => '⤅', + '⤌' => '⤌', + '⤍' => '⤍', + '⤎' => '⤎', + '⤏' => '⤏', + '⤐' => '⤐', + '⤑' => '⤑', + '⤒' => '⤒', + '⤓' => '⤓', + '⤖' => '⤖', + '⤙' => '⤙', + '⤚' => '⤚', + '⤛' => '⤛', + '⤜' => '⤜', + '⤝' => '⤝', + '⤞' => '⤞', + '⤟' => '⤟', + '⤠' => '⤠', + '⤣' => '⤣', + '⤤' => '⤤', + '⤥' => '⤥', + '⤦' => '⤦', + '⤧' => '⤧', + '⤨' => '⤨', + '⤩' => '⤩', + '⤪' => '⤪', + '⤳' => '⤳', + '⤳̸' => '&nrarrc', + '⤵' => '⤵', + '⤶' => '⤶', + '⤷' => '⤷', + '⤸' => '⤸', + '⤹' => '⤹', + '⤼' => '⤼', + '⤽' => '⤽', + '⥅' => '⥅', + '⥈' => '⥈', + '⥉' => '⥉', + '⥊' => '⥊', + '⥋' => '⥋', + '⥎' => '⥎', + '⥏' => '⥏', + '⥐' => '⥐', + '⥑' => '⥑', + '⥒' => '⥒', + '⥓' => '⥓', + '⥔' => '⥔', + '⥕' => '⥕', + '⥖' => '⥖', + '⥗' => '⥗', + '⥘' => '⥘', + '⥙' => '⥙', + '⥚' => '⥚', + '⥛' => '⥛', + '⥜' => '⥜', + '⥝' => '⥝', + '⥞' => '⥞', + '⥟' => '⥟', + '⥠' => '⥠', + '⥡' => '⥡', + '⥢' => '⥢', + '⥣' => '⥣', + '⥤' => '⥤', + '⥥' => '⥥', + '⥦' => '⥦', + '⥧' => '⥧', + '⥨' => '⥨', + '⥩' => '⥩', + '⥪' => '⥪', + '⥫' => '⥫', + '⥬' => '⥬', + '⥭' => '⥭', + '⥮' => '⥮', + '⥯' => '⥯', + '⥰' => '⥰', + '⥱' => '⥱', + '⥲' => '⥲', + '⥳' => '⥳', + '⥴' => '⥴', + '⥵' => '⥵', + '⥶' => '⥶', + '⥸' => '⥸', + '⥹' => '⥹', + '⥻' => '⥻', + '⥼' => '⥼', + '⥽' => '⥽', + '⥾' => '⥾', + '⥿' => '⥿', + '⦅' => '⦅', + '⦆' => '⦆', + '⦋' => '⦋', + '⦌' => '⦌', + '⦍' => '⦍', + '⦎' => '⦎', + '⦏' => '⦏', + '⦐' => '⦐', + '⦑' => '⦑', + '⦒' => '⦒', + '⦓' => '⦓', + '⦔' => '⦔', + '⦕' => '⦕', + '⦖' => '⦖', + '⦚' => '⦚', + '⦜' => '⦜', + '⦝' => '⦝', + '⦤' => '⦤', + '⦥' => '⦥', + '⦦' => '⦦', + '⦧' => '⦧', + '⦨' => '⦨', + '⦩' => '⦩', + '⦪' => '⦪', + '⦫' => '⦫', + '⦬' => '⦬', + '⦭' => '⦭', + '⦮' => '⦮', + '⦯' => '⦯', + '⦰' => '⦰', + '⦱' => '⦱', + '⦲' => '⦲', + '⦳' => '⦳', + '⦴' => '⦴', + '⦵' => '⦵', + '⦶' => '⦶', + '⦷' => '⦷', + '⦹' => '⦹', + '⦻' => '⦻', + '⦼' => '⦼', + '⦾' => '⦾', + '⦿' => '⦿', + '⧀' => '⧀', + '⧁' => '⧁', + '⧂' => '⧂', + '⧃' => '⧃', + '⧄' => '⧄', + '⧅' => '⧅', + '⧉' => '⧉', + '⧍' => '⧍', + '⧎' => '⧎', + '⧏' => '⧏', + '⧏̸' => '&NotLeftTriangleBar', + '⧐' => '⧐', + '⧐̸' => '&NotRightTriangleBar', + '⧜' => '⧜', + '⧝' => '⧝', + '⧞' => '⧞', + '⧣' => '⧣', + '⧤' => '⧤', + '⧥' => '⧥', + '⧫' => '⧫', + '⧴' => '⧴', + '⧶' => '⧶', + '⨀' => '⨀', + '⨁' => '⨁', + '⨂' => '⨂', + '⨄' => '⨄', + '⨆' => '⨆', + '⨌' => '⨌', + '⨍' => '⨍', + '⨐' => '⨐', + '⨑' => '⨑', + '⨒' => '⨒', + '⨓' => '⨓', + '⨔' => '⨔', + '⨕' => '⨕', + '⨖' => '⨖', + '⨗' => '⨗', + '⨢' => '⨢', + '⨣' => '⨣', + '⨤' => '⨤', + '⨥' => '⨥', + '⨦' => '⨦', + '⨧' => '⨧', + '⨩' => '⨩', + '⨪' => '⨪', + '⨭' => '⨭', + '⨮' => '⨮', + '⨯' => '⨯', + '⨰' => '⨰', + '⨱' => '⨱', + '⨳' => '⨳', + '⨴' => '⨴', + '⨵' => '⨵', + '⨶' => '⨶', + '⨷' => '⨷', + '⨸' => '⨸', + '⨹' => '⨹', + '⨺' => '⨺', + '⨻' => '⨻', + '⨼' => '⨼', + '⨿' => '⨿', + '⩀' => '⩀', + '⩂' => '⩂', + '⩃' => '⩃', + '⩄' => '⩄', + '⩅' => '⩅', + '⩆' => '⩆', + '⩇' => '⩇', + '⩈' => '⩈', + '⩉' => '⩉', + '⩊' => '⩊', + '⩋' => '⩋', + '⩌' => '⩌', + '⩍' => '⩍', + '⩐' => '⩐', + '⩓' => '⩓', + '⩔' => '⩔', + '⩕' => '⩕', + '⩖' => '⩖', + '⩗' => '⩗', + '⩘' => '⩘', + '⩚' => '⩚', + '⩛' => '⩛', + '⩜' => '⩜', + '⩝' => '⩝', + '⩟' => '⩟', + '⩦' => '⩦', + '⩪' => '⩪', + '⩭' => '⩭', + '⩭̸' => '&ncongdot', + '⩮' => '⩮', + '⩯' => '⩯', + '⩰' => '⩰', + '⩰̸' => '&napE', + '⩱' => '⩱', + '⩲' => '⩲', + '⩳' => '⩳', + '⩴' => '⩴', + '⩵' => '⩵', + '⩷' => '⩷', + '⩸' => '⩸', + '⩹' => '⩹', + '⩺' => '⩺', + '⩻' => '⩻', + '⩼' => '⩼', + '⩽' => '⩽', + '⩽̸' => '&nles', + '⩾' => '⩾', + '⩾̸' => '&nges', + '⩿' => '⩿', + '⪀' => '⪀', + '⪁' => '⪁', + '⪂' => '⪂', + '⪃' => '⪃', + '⪄' => '⪄', + '⪅' => '⪅', + '⪆' => '⪆', + '⪇' => '⪇', + '⪈' => '⪈', + '⪉' => '⪉', + '⪊' => '⪊', + '⪋' => '⪋', + '⪌' => '⪌', + '⪍' => '⪍', + '⪎' => '⪎', + '⪏' => '⪏', + '⪐' => '⪐', + '⪑' => '⪑', + '⪒' => '⪒', + '⪓' => '⪓', + '⪔' => '⪔', + '⪕' => '⪕', + '⪖' => '⪖', + '⪗' => '⪗', + '⪘' => '⪘', + '⪙' => '⪙', + '⪚' => '⪚', + '⪝' => '⪝', + '⪞' => '⪞', + '⪟' => '⪟', + '⪠' => '⪠', + '⪡' => '⪡', + '⪡̸' => '&NotNestedLessLess', + '⪢' => '⪢', + '⪢̸' => '&NotNestedGreaterGreater', + '⪤' => '⪤', + '⪥' => '⪥', + '⪦' => '⪦', + '⪧' => '⪧', + '⪨' => '⪨', + '⪩' => '⪩', + '⪪' => '⪪', + '⪫' => '⪫', + '⪬' => '⪬', + '⪬︀' => '&smtes', + '⪭' => '⪭', + '⪭︀' => '&lates', + '⪮' => '⪮', + '⪯' => '⪯', + '⪯̸' => '&NotPrecedesEqual', + '⪰' => '⪰', + '⪰̸' => '&NotSucceedsEqual', + '⪳' => '⪳', + '⪴' => '⪴', + '⪵' => '⪵', + '⪶' => '⪶', + '⪷' => '⪷', + '⪸' => '⪸', + '⪹' => '⪹', + '⪺' => '⪺', + '⪻' => '⪻', + '⪼' => '⪼', + '⪽' => '⪽', + '⪾' => '⪾', + '⪿' => '⪿', + '⫀' => '⫀', + '⫁' => '⫁', + '⫂' => '⫂', + '⫃' => '⫃', + '⫄' => '⫄', + '⫅' => '⫅', + '⫅̸' => '&nsubE', + '⫆' => '⫆', + '⫆̸' => '&nsupseteqq', + '⫇' => '⫇', + '⫈' => '⫈', + '⫋' => '⫋', + '⫋︀' => '&vsubnE', + '⫌' => '⫌', + '⫌︀' => '&varsupsetneqq', + '⫏' => '⫏', + '⫐' => '⫐', + '⫑' => '⫑', + '⫒' => '⫒', + '⫓' => '⫓', + '⫔' => '⫔', + '⫕' => '⫕', + '⫖' => '⫖', + '⫗' => '⫗', + '⫘' => '⫘', + '⫙' => '⫙', + '⫚' => '⫚', + '⫛' => '⫛', + '⫤' => '⫤', + '⫦' => '⫦', + '⫧' => '⫧', + '⫨' => '⫨', + '⫩' => '⫩', + '⫫' => '⫫', + '⫬' => '⫬', + '⫭' => '⫭', + '⫮' => '⫮', + '⫯' => '⫯', + '⫰' => '⫰', + '⫱' => '⫱', + '⫲' => '⫲', + '⫳' => '⫳', + '⫽︀' => '&varsupsetneqq', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + '𝒜' => '𝒜', + '𝒞' => '𝒞', + '𝒟' => '𝒟', + '𝒢' => '𝒢', + '𝒥' => '𝒥', + '𝒦' => '𝒦', + '𝒩' => '𝒩', + '𝒪' => '𝒪', + '𝒫' => '𝒫', + '𝒬' => '𝒬', + '𝒮' => '𝒮', + '𝒯' => '𝒯', + '𝒰' => '𝒰', + '𝒱' => '𝒱', + '𝒲' => '𝒲', + '𝒳' => '𝒳', + '𝒴' => '𝒴', + '𝒵' => '𝒵', + '𝒶' => '𝒶', + '𝒷' => '𝒷', + '𝒸' => '𝒸', + '𝒹' => '𝒹', + '𝒻' => '𝒻', + '𝒽' => '𝒽', + '𝒾' => '𝒾', + '𝒿' => '𝒿', + '𝓀' => '𝓀', + '𝓁' => '𝓁', + '𝓂' => '𝓂', + '𝓃' => '𝓃', + '𝓅' => '𝓅', + '𝓆' => '𝓆', + '𝓇' => '𝓇', + '𝓈' => '𝓈', + '𝓉' => '𝓉', + '𝓊' => '𝓊', + '𝓋' => '𝓋', + '𝓌' => '𝓌', + '𝓍' => '𝓍', + '𝓎' => '𝓎', + '𝓏' => '𝓏', + '𝔄' => '𝔄', + '𝔅' => '𝔅', + '𝔇' => '𝔇', + '𝔈' => '𝔈', + '𝔉' => '𝔉', + '𝔊' => '𝔊', + '𝔍' => '𝔍', + '𝔎' => '𝔎', + '𝔏' => '𝔏', + '𝔐' => '𝔐', + '𝔑' => '𝔑', + '𝔒' => '𝔒', + '𝔓' => '𝔓', + '𝔔' => '𝔔', + '𝔖' => '𝔖', + '𝔗' => '𝔗', + '𝔘' => '𝔘', + '𝔙' => '𝔙', + '𝔚' => '𝔚', + '𝔛' => '𝔛', + '𝔜' => '𝔜', + '𝔞' => '𝔞', + '𝔟' => '𝔟', + '𝔠' => '𝔠', + '𝔡' => '𝔡', + '𝔢' => '𝔢', + '𝔣' => '𝔣', + '𝔤' => '𝔤', + '𝔥' => '𝔥', + '𝔦' => '𝔦', + '𝔧' => '𝔧', + '𝔨' => '𝔨', + '𝔩' => '𝔩', + '𝔪' => '𝔪', + '𝔫' => '𝔫', + '𝔬' => '𝔬', + '𝔭' => '𝔭', + '𝔮' => '𝔮', + '𝔯' => '𝔯', + '𝔰' => '𝔰', + '𝔱' => '𝔱', + '𝔲' => '𝔲', + '𝔳' => '𝔳', + '𝔴' => '𝔴', + '𝔵' => '𝔵', + '𝔶' => '𝔶', + '𝔷' => '𝔷', + '𝔸' => '𝔸', + '𝔹' => '𝔹', + '𝔻' => '𝔻', + '𝔼' => '𝔼', + '𝔽' => '𝔽', + '𝔾' => '𝔾', + '𝕀' => '𝕀', + '𝕁' => '𝕁', + '𝕂' => '𝕂', + '𝕃' => '𝕃', + '𝕄' => '𝕄', + '𝕆' => '𝕆', + '𝕊' => '𝕊', + '𝕋' => '𝕋', + '𝕌' => '𝕌', + '𝕍' => '𝕍', + '𝕎' => '𝕎', + '𝕏' => '𝕏', + '𝕐' => '𝕐', + '𝕒' => '𝕒', + '𝕓' => '𝕓', + '𝕔' => '𝕔', + '𝕕' => '𝕕', + '𝕖' => '𝕖', + '𝕗' => '𝕗', + '𝕘' => '𝕘', + '𝕙' => '𝕙', + '𝕚' => '𝕚', + '𝕛' => '𝕛', + '𝕜' => '𝕜', + '𝕝' => '𝕝', + '𝕞' => '𝕞', + '𝕟' => '𝕟', + '𝕠' => '𝕠', + '𝕡' => '𝕡', + '𝕢' => '𝕢', + '𝕣' => '𝕣', + '𝕤' => '𝕤', + '𝕥' => '𝕥', + '𝕦' => '𝕦', + '𝕧' => '𝕧', + '𝕨' => '𝕨', + '𝕩' => '𝕩', + '𝕪' => '𝕪', + '𝕫' => '𝕫', + ); +} diff --git a/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php b/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php new file mode 100644 index 000000000..ec467f22c --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php @@ -0,0 +1,553 @@ +'http://www.w3.org/1999/xhtml', + 'attrNamespace'=>'http://www.w3.org/1999/xhtml', + + 'nodeName'=>'img', 'nodeName'=>array('img', 'a'), + 'attrName'=>'alt', 'attrName'=>array('title', 'alt'), + ), + */ + array( + 'nodeNamespace' => 'http://www.w3.org/1999/xhtml', + 'attrName' => array('href', + 'hreflang', + 'http-equiv', + 'icon', + 'id', + 'keytype', + 'kind', + 'label', + 'lang', + 'language', + 'list', + 'maxlength', + 'media', + 'method', + 'name', + 'placeholder', + 'rel', + 'rows', + 'rowspan', + 'sandbox', + 'spellcheck', + 'scope', + 'seamless', + 'shape', + 'size', + 'sizes', + 'span', + 'src', + 'srcdoc', + 'srclang', + 'srcset', + 'start', + 'step', + 'style', + 'summary', + 'tabindex', + 'target', + 'title', + 'type', + 'value', + 'width', + 'border', + 'charset', + 'cite', + 'class', + 'code', + 'codebase', + 'color', + 'cols', + 'colspan', + 'content', + 'coords', + 'data', + 'datetime', + 'default', + 'dir', + 'dirname', + 'enctype', + 'for', + 'form', + 'formaction', + 'headers', + 'height', + 'accept', + 'accept-charset', + 'accesskey', + 'action', + 'align', + 'alt', + 'bgcolor', + ), + ), + array( + 'nodeNamespace' => 'http://www.w3.org/1999/xhtml', + 'xpath' => 'starts-with(local-name(), \'data-\')', + ), + ); + + const DOCTYPE = ''; + + public function __construct($output, $options = array()) + { + if (isset($options['encode_entities'])) { + $this->encode = $options['encode_entities']; + } + + $this->outputMode = static::IM_IN_HTML; + $this->out = $output; + $this->hasHTML5 = defined('ENT_HTML5'); + } + + public function addRule(array $rule) + { + $this->nonBooleanAttributes[] = $rule; + } + + public function setTraverser(Traverser $traverser) + { + $this->traverser = $traverser; + + return $this; + } + + public function unsetTraverser() + { + $this->traverser = null; + + return $this; + } + + public function document($dom) + { + $this->doctype(); + if ($dom->documentElement) { + foreach ($dom->childNodes as $node) { + $this->traverser->node($node); + } + $this->nl(); + } + } + + protected function doctype() + { + $this->wr(static::DOCTYPE); + $this->nl(); + } + + public function element($ele) + { + $name = $ele->tagName; + + // Per spec: + // If the element has a declared namespace in the HTML, MathML or + // SVG namespaces, we use the lname instead of the tagName. + if ($this->traverser->isLocalElement($ele)) { + $name = $ele->localName; + } + + // If we are in SVG or MathML there is special handling. + // Using if/elseif instead of switch because it's faster in PHP. + if ('svg' == $name) { + $this->outputMode = static::IM_IN_SVG; + $name = Elements::normalizeSvgElement($name); + } elseif ('math' == $name) { + $this->outputMode = static::IM_IN_MATHML; + } + + $this->openTag($ele); + if (Elements::isA($name, Elements::TEXT_RAW)) { + foreach ($ele->childNodes as $child) { + if ($child instanceof \DOMCharacterData) { + $this->wr($child->data); + } elseif ($child instanceof \DOMElement) { + $this->element($child); + } + } + } else { + // Handle children. + if ($ele->hasChildNodes()) { + $this->traverser->children($ele->childNodes); + } + + // Close out the SVG or MathML special handling. + if ('svg' == $name || 'math' == $name) { + $this->outputMode = static::IM_IN_HTML; + } + } + + // If not unary, add a closing tag. + if (!Elements::isA($name, Elements::VOID_TAG)) { + $this->closeTag($ele); + } + } + + /** + * Write a text node. + * + * @param \DOMText $ele The text node to write. + */ + public function text($ele) + { + if (isset($ele->parentNode) && isset($ele->parentNode->tagName) && Elements::isA($ele->parentNode->localName, Elements::TEXT_RAW)) { + $this->wr($ele->data); + + return; + } + + // FIXME: This probably needs some flags set. + $this->wr($this->enc($ele->data)); + } + + public function cdata($ele) + { + // This encodes CDATA. + $this->wr($ele->ownerDocument->saveXML($ele)); + } + + public function comment($ele) + { + // These produce identical output. + // $this->wr(''); + $this->wr($ele->ownerDocument->saveXML($ele)); + } + + public function processorInstruction($ele) + { + $this->wr('wr($ele->target) + ->wr(' ') + ->wr($ele->data) + ->wr('?>'); + } + + /** + * Write the namespace attributes. + * + * @param \DOMNode $ele The element being written. + */ + protected function namespaceAttrs($ele) + { + if (!$this->xpath || $this->xpath->document !== $ele->ownerDocument) { + $this->xpath = new \DOMXPath($ele->ownerDocument); + } + + foreach ($this->xpath->query('namespace::*[not(.=../../namespace::*)]', $ele) as $nsNode) { + if (!in_array($nsNode->nodeValue, $this->implicitNamespaces)) { + $this->wr(' ')->wr($nsNode->nodeName)->wr('="')->wr($nsNode->nodeValue)->wr('"'); + } + } + } + + /** + * Write the opening tag. + * + * Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the + * qualified name (8.3). + * + * @param \DOMNode $ele The element being written. + */ + protected function openTag($ele) + { + $this->wr('<')->wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName); + + $this->attrs($ele); + $this->namespaceAttrs($ele); + + if ($this->outputMode == static::IM_IN_HTML) { + $this->wr('>'); + } // If we are not in html mode we are in SVG, MathML, or XML embedded content. + else { + if ($ele->hasChildNodes()) { + $this->wr('>'); + } // If there are no children this is self closing. + else { + $this->wr(' />'); + } + } + } + + protected function attrs($ele) + { + // FIXME: Needs support for xml, xmlns, xlink, and namespaced elements. + if (!$ele->hasAttributes()) { + return $this; + } + + // TODO: Currently, this always writes name="value", and does not do + // value-less attributes. + $map = $ele->attributes; + $len = $map->length; + for ($i = 0; $i < $len; ++$i) { + $node = $map->item($i); + $val = $this->enc($node->value, true); + + // XXX: The spec says that we need to ensure that anything in + // the XML, XMLNS, or XLink NS's should use the canonical + // prefix. It seems that DOM does this for us already, but there + // may be exceptions. + $name = $node->nodeName; + + // Special handling for attributes in SVG and MathML. + // Using if/elseif instead of switch because it's faster in PHP. + if ($this->outputMode == static::IM_IN_SVG) { + $name = Elements::normalizeSvgAttribute($name); + } elseif ($this->outputMode == static::IM_IN_MATHML) { + $name = Elements::normalizeMathMlAttribute($name); + } + + $this->wr(' ')->wr($name); + + if ((isset($val) && '' !== $val) || $this->nonBooleanAttribute($node)) { + $this->wr('="')->wr($val)->wr('"'); + } + } + } + + protected function nonBooleanAttribute(\DOMAttr $attr) + { + $ele = $attr->ownerElement; + foreach ($this->nonBooleanAttributes as $rule) { + if (isset($rule['nodeNamespace']) && $rule['nodeNamespace'] !== $ele->namespaceURI) { + continue; + } + if (isset($rule['attNamespace']) && $rule['attNamespace'] !== $attr->namespaceURI) { + continue; + } + if (isset($rule['nodeName']) && !is_array($rule['nodeName']) && $rule['nodeName'] !== $ele->localName) { + continue; + } + if (isset($rule['nodeName']) && is_array($rule['nodeName']) && !in_array($ele->localName, $rule['nodeName'], true)) { + continue; + } + if (isset($rule['attrName']) && !is_array($rule['attrName']) && $rule['attrName'] !== $attr->localName) { + continue; + } + if (isset($rule['attrName']) && is_array($rule['attrName']) && !in_array($attr->localName, $rule['attrName'], true)) { + continue; + } + if (isset($rule['xpath'])) { + $xp = $this->getXPath($attr); + if (isset($rule['prefixes'])) { + foreach ($rule['prefixes'] as $nsPrefix => $ns) { + $xp->registerNamespace($nsPrefix, $ns); + } + } + if (!$xp->evaluate($rule['xpath'], $attr)) { + continue; + } + } + + return true; + } + + return false; + } + + private function getXPath(\DOMNode $node) + { + if (!$this->xpath) { + $this->xpath = new \DOMXPath($node->ownerDocument); + } + + return $this->xpath; + } + + /** + * Write the closing tag. + * + * Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the + * qualified name (8.3). + * + * @param \DOMNode $ele The element being written. + */ + protected function closeTag($ele) + { + if ($this->outputMode == static::IM_IN_HTML || $ele->hasChildNodes()) { + $this->wr('wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName)->wr('>'); + } + } + + /** + * Write to the output. + * + * @param string $text The string to put into the output + * + * @return $this + */ + protected function wr($text) + { + fwrite($this->out, $text); + + return $this; + } + + /** + * Write a new line character. + * + * @return $this + */ + protected function nl() + { + fwrite($this->out, PHP_EOL); + + return $this; + } + + /** + * Encode text. + * + * When encode is set to false, the default value, the text passed in is + * escaped per section 8.3 of the html5 spec. For details on how text is + * escaped see the escape() method. + * + * When encoding is set to true the text is converted to named character + * references where appropriate. Section 8.1.4 Character references of the + * html5 spec refers to using named character references. This is useful for + * characters that can't otherwise legally be used in the text. + * + * The named character references are listed in section 8.5. + * + * @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#named-character-references True encoding will turn all named character references into their entities. + * This includes such characters as +.# and many other common ones. By default + * encoding here will just escape &'<>". + * + * Note, PHP 5.4+ has better html5 encoding. + * + * @todo Use the Entities class in php 5.3 to have html5 entities. + * + * @param string $text Text to encode. + * @param bool $attribute True if we are encoding an attrubute, false otherwise. + * + * @return string The encoded text. + */ + protected function enc($text, $attribute = false) + { + // Escape the text rather than convert to named character references. + if (!$this->encode) { + return $this->escape($text, $attribute); + } + + // If we are in PHP 5.4+ we can use the native html5 entity functionality to + // convert the named character references. + + if ($this->hasHTML5) { + return htmlentities($text, ENT_HTML5 | ENT_SUBSTITUTE | ENT_QUOTES, 'UTF-8', false); + } // If a version earlier than 5.4 html5 entities are not entirely handled. + // This manually handles them. + else { + return strtr($text, HTML5Entities::$map); + } + } + + /** + * Escape test. + * + * According to the html5 spec section 8.3 Serializing HTML fragments, text + * within tags that are not style, script, xmp, iframe, noembed, and noframes + * need to be properly escaped. + * + * The & should be converted to &, no breaking space unicode characters + * converted to  , when in attribute mode the " should be converted to + * ", and when not in attribute mode the < and > should be converted to + * < and >. + * + * @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#escapingString + * + * @param string $text Text to escape. + * @param bool $attribute True if we are escaping an attrubute, false otherwise. + */ + protected function escape($text, $attribute = false) + { + // Not using htmlspecialchars because, while it does escaping, it doesn't + // match the requirements of section 8.5. For example, it doesn't handle + // non-breaking spaces. + if ($attribute) { + $replace = array( + '"' => '"', + '&' => '&', + "\xc2\xa0" => ' ', + ); + } else { + $replace = array( + '<' => '<', + '>' => '>', + '&' => '&', + "\xc2\xa0" => ' ', + ); + } + + return strtr($text, $replace); + } +} diff --git a/vendor/masterminds/html5/src/HTML5/Serializer/README.md b/vendor/masterminds/html5/src/HTML5/Serializer/README.md new file mode 100644 index 000000000..849a47f3a --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Serializer/README.md @@ -0,0 +1,33 @@ +# The Serializer (Writer) Model + +The serializer roughly follows sections _8.1 Writing HTML documents_ and section +_8.3 Serializing HTML fragments_ by converting DOMDocument, DOMDocumentFragment, +and DOMNodeList into HTML5. + + [ HTML5 ] // Interface for saving. + || + [ Traverser ] // Walk the DOM + || + [ Rules ] // Convert DOM elements into strings. + || + [ HTML5 ] // HTML5 document or fragment in text. + + +## HTML5 Class + +Provides the top level interface for saving. + +## The Traverser + +Walks the DOM finding each element and passing it off to the output rules to +convert to HTML5. + +## Output Rules + +The output rules are defined in the RulesInterface which can have multiple +implementations. Currently, the OutputRules is the default implementation that +converts a DOM as is into HTML5. + +## HTML5 String + +The output of the process it HTML5 as a string or saved to a file. \ No newline at end of file diff --git a/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php b/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php new file mode 100644 index 000000000..69a6ecdad --- /dev/null +++ b/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php @@ -0,0 +1,99 @@ + 'html', + 'http://www.w3.org/1998/Math/MathML' => 'math', + 'http://www.w3.org/2000/svg' => 'svg', + ); + + protected $dom; + + protected $options; + + protected $encode = false; + + protected $rules; + + protected $out; + + /** + * Create a traverser. + * + * @param \DOMNode|\DOMNodeList $dom The document or node to traverse. + * @param resource $out A stream that allows writing. The traverser will output into this + * stream. + * @param array $options An array of options for the traverser as key/value pairs. These include: + * - encode_entities: A bool to specify if full encding should happen for all named + * charachter references. Defaults to false which escapes &'<>". + * - output_rules: The path to the class handling the output rules. + */ + public function __construct($dom, $out, RulesInterface $rules, $options = array()) + { + $this->dom = $dom; + $this->out = $out; + $this->rules = $rules; + $this->options = $options; + + $this->rules->setTraverser($this); + } + + /** + * Tell the traverser to walk the DOM. + * + * @return resource $out Returns the output stream. + */ + public function walk() + { + if ($this->dom instanceof \DOMDocument) { + $this->rules->document($this->dom); + } elseif ($this->dom instanceof \DOMDocumentFragment) { + // Document fragments are a special case. Only the children need to + // be serialized. + if ($this->dom->hasChildNodes()) { + $this->children($this->dom->childNodes); + } + } // If NodeList, loop + elseif ($this->dom instanceof \DOMNodeList) { + // If this is a NodeList of DOMDocuments this will not work. + $this->children($this->dom); + } // Else assume this is a DOMNode-like datastructure. + else { + $this->node($this->dom); + } + + return $this->out; + } + + /** + * Process a node in the DOM. + * + * @param mixed $node A node implementing \DOMNode. + */ + public function node($node) + { + // A listing of types is at http://php.net/manual/en/dom.constants.php + switch ($node->nodeType) { + case XML_ELEMENT_NODE: + $this->rules->element($node); + break; + case XML_TEXT_NODE: + $this->rules->text($node); + break; + case XML_CDATA_SECTION_NODE: + $this->rules->cdata($node); + break; + case XML_PI_NODE: + $this->rules->processorInstruction($node); + break; + case XML_COMMENT_NODE: + $this->rules->comment($node); + break; + // Currently we don't support embedding DTDs. + default: + //print ''; + break; + } + } + + /** + * Walk through all the nodes on a node list. + * + * @param \DOMNodeList $nl A list of child elements to walk through. + */ + public function children($nl) + { + foreach ($nl as $node) { + $this->node($node); + } + } + + /** + * Is an element local? + * + * @param mixed $ele An element that implement \DOMNode. + * + * @return bool true if local and false otherwise. + */ + public function isLocalElement($ele) + { + $uri = $ele->namespaceURI; + if (empty($uri)) { + return false; + } + + return isset(static::$local_ns[$uri]); + } +} diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php new file mode 100644 index 000000000..7525fe039 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -0,0 +1,188 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * @author Nicolas Grekas + */ +abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + /** + * @internal + */ + protected const NS_SEPARATOR = ':'; + + private static bool $apcuSupported; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR; + $this->defaultLifetime = $defaultLifetime; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + self::$createCacheItem ??= \Closure::bind( + static function ($key, $value, $isHit) { + $item = new CacheItem(); + $item->key = $key; + $item->value = $value; + $item->isHit = $isHit; + $item->unpack(); + + return $item; + }, + null, + CacheItem::class + ); + self::$mergeByLifetime ??= \Closure::bind( + static function ($deferred, $namespace, &$expiredIds, $getId, $defaultLifetime) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; + } elseif (!$item->expiry) { + $ttl = 0; + } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + $byLifetime[$ttl][$getId($key)] = $item->pack(); + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Returns the best possible adapter that your runtime supports. + * + * Using ApcuAdapter makes system caches compatible with read-only filesystems. + */ + public static function createSystemCache(string $namespace, int $defaultLifetime, string $version, string $directory, ?LoggerInterface $logger = null): AdapterInterface + { + $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); + if (null !== $logger) { + $opcache->setLogger($logger); + } + + if (!self::$apcuSupported ??= ApcuAdapter::isSupported()) { + return $opcache; + } + + if ('cli' === \PHP_SAPI && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) { + return $opcache; + } + + $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version); + if (null !== $logger) { + $apcu->setLogger($logger); + } + + return new ChainAdapter([$apcu, $opcache]); + } + + public static function createConnection(#[\SensitiveParameter] string $dsn, array $options = []): mixed + { + if (str_starts_with($dsn, 'redis:') || str_starts_with($dsn, 'rediss:')) { + return RedisAdapter::createConnection($dsn, $options); + } + if (str_starts_with($dsn, 'memcached:')) { + return MemcachedAdapter::createConnection($dsn, $options); + } + if (str_starts_with($dsn, 'couchbase:')) { + if (CouchbaseBucketAdapter::isSupported()) { + return CouchbaseBucketAdapter::createConnection($dsn, $options); + } + + return CouchbaseCollectionAdapter::createConnection($dsn, $options); + } + + throw new InvalidArgumentException('Unsupported DSN: it does not start with "redis[s]:", "memcached:" nor "couchbase:".'); + } + + public function commit(): bool + { + $ok = true; + $byLifetime = (self::$mergeByLifetime)($this->deferred, $this->namespace, $expiredIds, $this->getId(...), $this->defaultLifetime); + $retry = $this->deferred = []; + + if ($expiredIds) { + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + } + foreach ($byLifetime as $lifetime => $values) { + try { + $e = $this->doSave($values, $lifetime); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $e = $this->doSave([$id => $v], $lifetime); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } + + return $ok; + } +} diff --git a/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php new file mode 100644 index 000000000..ef62b4fb2 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,320 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Abstract for native TagAware adapters. + * + * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids + * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate(). + * + * @author Nicolas Grekas + * @author André Rømcke + * + * @internal + */ +abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + private const TAGS_PREFIX = "\1tags\1"; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; + $this->defaultLifetime = $defaultLifetime; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + self::$createCacheItem ??= \Closure::bind( + static function ($key, $value, $isHit) { + $item = new CacheItem(); + $item->key = $key; + $item->isTaggable = true; + // If structure does not match what we expect return item as is (no value and not a hit) + if (!\is_array($value) || !\array_key_exists('value', $value)) { + return $item; + } + $item->isHit = $isHit; + // Extract value, tags and meta data from the cache value + $item->value = $value['value']; + $item->metadata[CacheItem::METADATA_TAGS] = isset($value['tags']) ? array_combine($value['tags'], $value['tags']) : []; + if (isset($value['meta'])) { + // For compactness these values are packed, & expiry is offset to reduce size + $v = unpack('Ve/Nc', $value['meta']); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } + + return $item; + }, + null, + CacheItem::class + ); + self::$mergeByLifetime ??= \Closure::bind( + static function ($deferred, &$expiredIds, $getId, $tagPrefix, $defaultLifetime) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; + } elseif (!$item->expiry) { + $ttl = 0; + } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + // Store Value and Tags on the cache value + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + $value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]]; + unset($metadata[CacheItem::METADATA_TAGS]); + } else { + $value = ['value' => $item->value, 'tags' => []]; + } + + if ($metadata) { + // For compactness, expiry and creation duration are packed, using magic numbers as separators + $value['meta'] = pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME]); + } + + // Extract tag changes, these should be removed from values in doSave() + $value['tag-operations'] = ['add' => [], 'remove' => []]; + $oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? []; + foreach (array_diff_key($value['tags'], $oldTags) as $addedTag) { + $value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag); + } + foreach (array_diff_key($oldTags, $value['tags']) as $removedTag) { + $value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag); + } + $value['tags'] = array_keys($value['tags']); + + $byLifetime[$ttl][$getId($key)] = $value; + $item->metadata = $item->newMetadata; + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Persists several cache items immediately. + * + * @param array $values The values to cache, indexed by their cache identifier + * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning + * @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag + * @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag + * + * @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not + */ + abstract protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array; + + /** + * Removes multiple items from the pool and their corresponding tags. + * + * @param array $ids An array of identifiers that should be removed from the pool + */ + abstract protected function doDelete(array $ids): bool; + + /** + * Removes relations between tags and deleted items. + * + * @param array $tagData Array of tag => key identifiers that should be removed from the pool + */ + abstract protected function doDeleteTagRelations(array $tagData): bool; + + /** + * Invalidates cached items using tags. + * + * @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id + */ + abstract protected function doInvalidate(array $tagIds): bool; + + /** + * Delete items and yields the tags they were bound to. + */ + protected function doDeleteYieldTags(array $ids): iterable + { + foreach ($this->doFetch($ids) as $id => $value) { + yield $id => \is_array($value) && \is_array($value['tags'] ?? null) ? $value['tags'] : []; + } + + $this->doDelete($ids); + } + + public function commit(): bool + { + $ok = true; + $byLifetime = (self::$mergeByLifetime)($this->deferred, $expiredIds, $this->getId(...), self::TAGS_PREFIX, $this->defaultLifetime); + $retry = $this->deferred = []; + + if ($expiredIds) { + // Tags are not cleaned up in this case, however that is done on invalidateTags(). + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + } + foreach ($byLifetime as $lifetime => $values) { + try { + $values = $this->extractTagData($values, $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $values = $this->extractTagData([$id => $v], $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = get_debug_type($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } + + return $ok; + } + + public function deleteItems(array $keys): bool + { + if (!$keys) { + return true; + } + + $ok = true; + $ids = []; + $tagData = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + try { + foreach ($this->doDeleteYieldTags(array_values($ids)) as $id => $tags) { + foreach ($tags as $tag) { + $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id; + } + } + } catch (\Exception) { + $ok = false; + } + + try { + if ((!$tagData || $this->doDeleteTagRelations($tagData)) && $ok) { + return true; + } + } catch (\Exception) { + } + + // When bulk-delete failed, retry each item individually + foreach ($ids as $key => $id) { + try { + $e = null; + if ($this->doDelete([$id])) { + continue; + } + } catch (\Exception $e) { + } + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + $ok = false; + } + + return $ok; + } + + public function invalidateTags(array $tags): bool + { + if (!$tags) { + return false; + } + + $tagIds = []; + foreach (array_unique($tags) as $tag) { + $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag); + } + + try { + if ($this->doInvalidate($tagIds)) { + return true; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to invalidate tags: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + + return false; + } + + /** + * Extracts tags operation data from $values set in mergeByLifetime, and returns values without it. + */ + private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array + { + $addTagData = $removeTagData = []; + foreach ($values as $id => $value) { + foreach ($value['tag-operations']['add'] as $tag => $tagId) { + $addTagData[$tagId][] = $id; + } + + foreach ($value['tag-operations']['remove'] as $tag => $tagId) { + $removeTagData[$tagId][] = $id; + } + + unset($values[$id]['tag-operations']); + } + + return $values; + } +} diff --git a/vendor/symfony/cache/Adapter/AdapterInterface.php b/vendor/symfony/cache/Adapter/AdapterInterface.php new file mode 100644 index 000000000..e55672093 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AdapterInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\CacheItem; + +// Help opcache.preload discover always-needed symbols +class_exists(CacheItem::class); + +/** + * Interface for adapters managing instances of Symfony's CacheItem. + * + * @author Kévin Dunglas + */ +interface AdapterInterface extends CacheItemPoolInterface +{ + public function getItem(mixed $key): CacheItem; + + /** + * @return iterable + */ + public function getItems(array $keys = []): iterable; + + public function clear(string $prefix = ''): bool; +} diff --git a/vendor/symfony/cache/Adapter/ApcuAdapter.php b/vendor/symfony/cache/Adapter/ApcuAdapter.php new file mode 100644 index 000000000..2eddb49a7 --- /dev/null +++ b/vendor/symfony/cache/Adapter/ApcuAdapter.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Nicolas Grekas + */ +class ApcuAdapter extends AbstractAdapter +{ + private ?MarshallerInterface $marshaller; + + /** + * @throws CacheException if APCu is not enabled + */ + public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $version = null, ?MarshallerInterface $marshaller = null) + { + if (!static::isSupported()) { + throw new CacheException('APCu is not enabled.'); + } + if ('cli' === \PHP_SAPI) { + ini_set('apc.use_request_time', 0); + } + parent::__construct($namespace, $defaultLifetime); + + if (null !== $version) { + CacheItem::validateKey($version); + + if (!apcu_exists($version.'@'.$namespace)) { + $this->doClear($namespace); + apcu_add($version.'@'.$namespace, null); + } + } + + $this->marshaller = $marshaller; + } + + /** + * @return bool + */ + public static function isSupported() + { + return \function_exists('apcu_fetch') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL); + } + + protected function doFetch(array $ids): iterable + { + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); + try { + $values = []; + foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) { + if (null !== $v || $ok) { + $values[$k] = null !== $this->marshaller ? $this->marshaller->unmarshall($v) : $v; + } + } + + return $values; + } catch (\Error $e) { + throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); + } + } + + protected function doHave(string $id): bool + { + return apcu_exists($id); + } + + protected function doClear(string $namespace): bool + { + return isset($namespace[0]) && class_exists(\APCUIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) + ? apcu_delete(new \APCUIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) + : apcu_clear_cache(); + } + + protected function doDelete(array $ids): bool + { + foreach ($ids as $id) { + apcu_delete($id); + } + + return true; + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (null !== $this->marshaller && (!$values = $this->marshaller->marshall($values, $failed))) { + return $failed; + } + + try { + if (false === $failures = apcu_store($values, null, $lifetime)) { + $failures = $values; + } + + return array_keys($failures); + } catch (\Throwable $e) { + if (1 === \count($values)) { + // Workaround https://github.com/krakjoe/apcu/issues/170 + apcu_delete(array_key_first($values)); + } + + throw $e; + } + } +} diff --git a/vendor/symfony/cache/Adapter/ArrayAdapter.php b/vendor/symfony/cache/Adapter/ArrayAdapter.php new file mode 100644 index 000000000..660a52646 --- /dev/null +++ b/vendor/symfony/cache/Adapter/ArrayAdapter.php @@ -0,0 +1,366 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * An in-memory cache storage. + * + * Acts as a least-recently-used (LRU) storage when configured with a maximum number of items. + * + * @author Nicolas Grekas + */ +class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface +{ + use LoggerAwareTrait; + + private bool $storeSerialized; + private array $values = []; + private array $tags = []; + private array $expiries = []; + private int $defaultLifetime; + private float $maxLifetime; + private int $maxItems; + + private static \Closure $createCacheItem; + + /** + * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise + */ + public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true, float $maxLifetime = 0, int $maxItems = 0) + { + if (0 > $maxLifetime) { + throw new InvalidArgumentException(sprintf('Argument $maxLifetime must be positive, %F passed.', $maxLifetime)); + } + + if (0 > $maxItems) { + throw new InvalidArgumentException(sprintf('Argument $maxItems must be a positive integer, %d passed.', $maxItems)); + } + + $this->defaultLifetime = $defaultLifetime; + $this->storeSerialized = $storeSerialized; + $this->maxLifetime = $maxLifetime; + $this->maxItems = $maxItems; + self::$createCacheItem ??= \Closure::bind( + static function ($key, $value, $isHit, $tags) { + $item = new CacheItem(); + $item->key = $key; + $item->value = $value; + $item->isHit = $isHit; + if (null !== $tags) { + $item->metadata[CacheItem::METADATA_TAGS] = $tags; + } + + return $item; + }, + null, + CacheItem::class + ); + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + $item = $this->getItem($key); + $metadata = $item->getMetadata(); + + // ArrayAdapter works in memory, we don't care about stampede protection + if (\INF === $beta || !$item->isHit()) { + $save = true; + $item->set($callback($item, $save)); + if ($save) { + $this->save($item); + } + } + + return $item->get(); + } + + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + + public function hasItem(mixed $key): bool + { + if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) { + if ($this->maxItems) { + // Move the item last in the storage + $value = $this->values[$key]; + unset($this->values[$key]); + $this->values[$key] = $value; + } + + return true; + } + \assert('' !== CacheItem::validateKey($key)); + + return isset($this->expiries[$key]) && !$this->deleteItem($key); + } + + public function getItem(mixed $key): CacheItem + { + if (!$isHit = $this->hasItem($key)) { + $value = null; + + if (!$this->maxItems) { + // Track misses in non-LRU mode only + $this->values[$key] = null; + } + } else { + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; + } + + return (self::$createCacheItem)($key, $value, $isHit, $this->tags[$key] ?? null); + } + + public function getItems(array $keys = []): iterable + { + \assert(self::validateKeys($keys)); + + return $this->generateItems($keys, microtime(true), self::$createCacheItem); + } + + public function deleteItem(mixed $key): bool + { + \assert('' !== CacheItem::validateKey($key)); + unset($this->values[$key], $this->tags[$key], $this->expiries[$key]); + + return true; + } + + public function deleteItems(array $keys): bool + { + foreach ($keys as $key) { + $this->deleteItem($key); + } + + return true; + } + + public function save(CacheItemInterface $item): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $item = (array) $item; + $key = $item["\0*\0key"]; + $value = $item["\0*\0value"]; + $expiry = $item["\0*\0expiry"]; + + $now = microtime(true); + + if (null !== $expiry) { + if (!$expiry) { + $expiry = \PHP_INT_MAX; + } elseif ($expiry <= $now) { + $this->deleteItem($key); + + return true; + } + } + if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) { + return false; + } + if (null === $expiry && 0 < $this->defaultLifetime) { + $expiry = $this->defaultLifetime; + $expiry = $now + ($expiry > ($this->maxLifetime ?: $expiry) ? $this->maxLifetime : $expiry); + } elseif ($this->maxLifetime && (null === $expiry || $expiry > $now + $this->maxLifetime)) { + $expiry = $now + $this->maxLifetime; + } + + if ($this->maxItems) { + unset($this->values[$key], $this->tags[$key]); + + // Iterate items and vacuum expired ones while we are at it + foreach ($this->values as $k => $v) { + if ($this->expiries[$k] > $now && \count($this->values) < $this->maxItems) { + break; + } + + unset($this->values[$k], $this->tags[$k], $this->expiries[$k]); + } + } + + $this->values[$key] = $value; + $this->expiries[$key] = $expiry ?? \PHP_INT_MAX; + + if (null === $this->tags[$key] = $item["\0*\0newMetadata"][CacheItem::METADATA_TAGS] ?? null) { + unset($this->tags[$key]); + } + + return true; + } + + public function saveDeferred(CacheItemInterface $item): bool + { + return $this->save($item); + } + + public function commit(): bool + { + return true; + } + + public function clear(string $prefix = ''): bool + { + if ('' !== $prefix) { + $now = microtime(true); + + foreach ($this->values as $key => $value) { + if (!isset($this->expiries[$key]) || $this->expiries[$key] <= $now || str_starts_with($key, $prefix)) { + unset($this->values[$key], $this->tags[$key], $this->expiries[$key]); + } + } + + if ($this->values) { + return true; + } + } + + $this->values = $this->tags = $this->expiries = []; + + return true; + } + + /** + * Returns all cached values, with cache miss as null. + */ + public function getValues(): array + { + if (!$this->storeSerialized) { + return $this->values; + } + + $values = $this->values; + foreach ($values as $k => $v) { + if (null === $v || 'N;' === $v) { + continue; + } + if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) { + $values[$k] = serialize($v); + } + } + + return $values; + } + + /** + * @return void + */ + public function reset() + { + $this->clear(); + } + + private function generateItems(array $keys, float $now, \Closure $f): \Generator + { + foreach ($keys as $i => $key) { + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) { + $value = null; + + if (!$this->maxItems) { + // Track misses in non-LRU mode only + $this->values[$key] = null; + } + } else { + if ($this->maxItems) { + // Move the item last in the storage + $value = $this->values[$key]; + unset($this->values[$key]); + $this->values[$key] = $value; + } + + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; + } + unset($keys[$i]); + + yield $key => $f($key, $value, $isHit, $this->tags[$key] ?? null); + } + + foreach ($keys as $key) { + yield $key => $f($key, null, false); + } + } + + private function freeze($value, string $key): string|int|float|bool|array|\UnitEnum|null + { + if (null === $value) { + return 'N;'; + } + if (\is_string($value)) { + // Serialize strings if they could be confused with serialized objects or arrays + if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { + return serialize($value); + } + } elseif (!\is_scalar($value)) { + try { + $serialized = serialize($value); + } catch (\Exception $e) { + unset($this->values[$key], $this->tags[$key]); + $type = get_debug_type($value); + $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + + return null; + } + // Keep value serialized if it contains any objects or any internal references + if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) { + return $serialized; + } + } + + return $value; + } + + private function unfreeze(string $key, bool &$isHit): mixed + { + if ('N;' === $value = $this->values[$key]) { + return null; + } + if (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + try { + $value = unserialize($value); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + $value = false; + } + if (false === $value) { + $value = null; + $isHit = false; + + if (!$this->maxItems) { + $this->values[$key] = null; + } + } + } + + return $value; + } + + private function validateKeys(array $keys): bool + { + foreach ($keys as $key) { + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } + } + + return true; + } +} diff --git a/vendor/symfony/cache/Adapter/ChainAdapter.php b/vendor/symfony/cache/Adapter/ChainAdapter.php new file mode 100644 index 000000000..221b1fb5d --- /dev/null +++ b/vendor/symfony/cache/Adapter/ChainAdapter.php @@ -0,0 +1,294 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Chains several adapters together. + * + * Cached items are fetched from the first adapter having them in its data store. + * They are saved and deleted in all adapters at once. + * + * @author Kévin Dunglas + */ +class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface +{ + use ContractsTrait; + + private array $adapters = []; + private int $adapterCount; + private int $defaultLifetime; + + private static \Closure $syncItem; + + /** + * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items + * @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones + */ + public function __construct(array $adapters, int $defaultLifetime = 0) + { + if (!$adapters) { + throw new InvalidArgumentException('At least one adapter must be specified.'); + } + + foreach ($adapters as $adapter) { + if (!$adapter instanceof CacheItemPoolInterface) { + throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_debug_type($adapter), CacheItemPoolInterface::class)); + } + if ('cli' === \PHP_SAPI && $adapter instanceof ApcuAdapter && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) { + continue; // skip putting APCu in the chain when the backend is disabled + } + + if ($adapter instanceof AdapterInterface) { + $this->adapters[] = $adapter; + } else { + $this->adapters[] = new ProxyAdapter($adapter); + } + } + $this->adapterCount = \count($this->adapters); + $this->defaultLifetime = $defaultLifetime; + + self::$syncItem ??= \Closure::bind( + static function ($sourceItem, $item, $defaultLifetime, $sourceMetadata = null) { + $sourceItem->isTaggable = false; + $sourceMetadata ??= $sourceItem->metadata; + + $item->value = $sourceItem->value; + $item->isHit = $sourceItem->isHit; + $item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata; + + if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) { + $item->expiresAt(\DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY]))); + } elseif (0 < $defaultLifetime) { + $item->expiresAfter($defaultLifetime); + } + + return $item; + }, + null, + CacheItem::class + ); + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + $doSave = true; + $callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) { + $value = $callback($item, $save); + $doSave = $save; + + return $value; + }; + + $wrap = function (?CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$doSave, &$metadata) { + static $lastItem; + static $i = 0; + $adapter = $this->adapters[$i]; + if (isset($this->adapters[++$i])) { + $callback = $wrap; + $beta = \INF === $beta ? \INF : 0; + } + if ($adapter instanceof CacheInterface) { + $value = $adapter->get($key, $callback, $beta, $metadata); + } else { + $value = $this->doGet($adapter, $key, $callback, $beta, $metadata); + } + if (null !== $item) { + (self::$syncItem)($lastItem ??= $item, $item, $this->defaultLifetime, $metadata); + } + $save = $doSave; + + return $value; + }; + + return $wrap(); + } + + public function getItem(mixed $key): CacheItem + { + $syncItem = self::$syncItem; + $misses = []; + + foreach ($this->adapters as $i => $adapter) { + $item = $adapter->getItem($key); + + if ($item->isHit()) { + while (0 <= --$i) { + $this->adapters[$i]->save($syncItem($item, $misses[$i], $this->defaultLifetime)); + } + + return $item; + } + + $misses[$i] = $item; + } + + return $item; + } + + public function getItems(array $keys = []): iterable + { + return $this->generateItems($this->adapters[0]->getItems($keys), 0); + } + + private function generateItems(iterable $items, int $adapterIndex): \Generator + { + $missing = []; + $misses = []; + $nextAdapterIndex = $adapterIndex + 1; + $nextAdapter = $this->adapters[$nextAdapterIndex] ?? null; + + foreach ($items as $k => $item) { + if (!$nextAdapter || $item->isHit()) { + yield $k => $item; + } else { + $missing[] = $k; + $misses[$k] = $item; + } + } + + if ($missing) { + $syncItem = self::$syncItem; + $adapter = $this->adapters[$adapterIndex]; + $items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex); + + foreach ($items as $k => $item) { + if ($item->isHit()) { + $adapter->save($syncItem($item, $misses[$k], $this->defaultLifetime)); + } + + yield $k => $item; + } + } + } + + public function hasItem(mixed $key): bool + { + foreach ($this->adapters as $adapter) { + if ($adapter->hasItem($key)) { + return true; + } + } + + return false; + } + + public function clear(string $prefix = ''): bool + { + $cleared = true; + $i = $this->adapterCount; + + while ($i--) { + if ($this->adapters[$i] instanceof AdapterInterface) { + $cleared = $this->adapters[$i]->clear($prefix) && $cleared; + } else { + $cleared = $this->adapters[$i]->clear() && $cleared; + } + } + + return $cleared; + } + + public function deleteItem(mixed $key): bool + { + $deleted = true; + $i = $this->adapterCount; + + while ($i--) { + $deleted = $this->adapters[$i]->deleteItem($key) && $deleted; + } + + return $deleted; + } + + public function deleteItems(array $keys): bool + { + $deleted = true; + $i = $this->adapterCount; + + while ($i--) { + $deleted = $this->adapters[$i]->deleteItems($keys) && $deleted; + } + + return $deleted; + } + + public function save(CacheItemInterface $item): bool + { + $saved = true; + $i = $this->adapterCount; + + while ($i--) { + $saved = $this->adapters[$i]->save($item) && $saved; + } + + return $saved; + } + + public function saveDeferred(CacheItemInterface $item): bool + { + $saved = true; + $i = $this->adapterCount; + + while ($i--) { + $saved = $this->adapters[$i]->saveDeferred($item) && $saved; + } + + return $saved; + } + + public function commit(): bool + { + $committed = true; + $i = $this->adapterCount; + + while ($i--) { + $committed = $this->adapters[$i]->commit() && $committed; + } + + return $committed; + } + + public function prune(): bool + { + $pruned = true; + + foreach ($this->adapters as $adapter) { + if ($adapter instanceof PruneableInterface) { + $pruned = $adapter->prune() && $pruned; + } + } + + return $pruned; + } + + /** + * @return void + */ + public function reset() + { + foreach ($this->adapters as $adapter) { + if ($adapter instanceof ResetInterface) { + $adapter->reset(); + } + } + } +} diff --git a/vendor/symfony/cache/Adapter/CouchbaseBucketAdapter.php b/vendor/symfony/cache/Adapter/CouchbaseBucketAdapter.php new file mode 100644 index 000000000..18136da17 --- /dev/null +++ b/vendor/symfony/cache/Adapter/CouchbaseBucketAdapter.php @@ -0,0 +1,232 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Antonio Jose Cerezo Aranda + */ +class CouchbaseBucketAdapter extends AbstractAdapter +{ + private const THIRTY_DAYS_IN_SECONDS = 2592000; + private const MAX_KEY_LENGTH = 250; + private const KEY_NOT_FOUND = 13; + private const VALID_DSN_OPTIONS = [ + 'operationTimeout', + 'configTimeout', + 'configNodeTimeout', + 'n1qlTimeout', + 'httpTimeout', + 'configDelay', + 'htconfigIdleTimeout', + 'durabilityInterval', + 'durabilityTimeout', + ]; + + private \CouchbaseBucket $bucket; + private MarshallerInterface $marshaller; + + public function __construct(\CouchbaseBucket $bucket, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) + { + if (!static::isSupported()) { + throw new CacheException('Couchbase >= 2.6.0 < 3.0.0 is required.'); + } + + $this->maxIdLength = static::MAX_KEY_LENGTH; + + $this->bucket = $bucket; + + parent::__construct($namespace, $defaultLifetime); + $this->enableVersioning(); + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + public static function createConnection(#[\SensitiveParameter] array|string $servers, array $options = []): \CouchbaseBucket + { + if (\is_string($servers)) { + $servers = [$servers]; + } + + if (!static::isSupported()) { + throw new CacheException('Couchbase >= 2.6.0 < 3.0.0 is required.'); + } + + set_error_handler(static fn ($type, $msg, $file, $line) => throw new \ErrorException($msg, 0, $type, $file, $line)); + + $dsnPattern = '/^(?couchbase(?:s)?)\:\/\/(?:(?[^\:]+)\:(?[^\@]{6,})@)?' + .'(?[^\:]+(?:\:\d+)?)(?:\/(?[^\?]+))(?:\?(?.*))?$/i'; + + $newServers = []; + $protocol = 'couchbase'; + try { + $options = self::initOptions($options); + $username = $options['username']; + $password = $options['password']; + + foreach ($servers as $dsn) { + if (!str_starts_with($dsn, 'couchbase:')) { + throw new InvalidArgumentException('Invalid Couchbase DSN: it does not start with "couchbase:".'); + } + + preg_match($dsnPattern, $dsn, $matches); + + $username = $matches['username'] ?: $username; + $password = $matches['password'] ?: $password; + $protocol = $matches['protocol'] ?: $protocol; + + if (isset($matches['options'])) { + $optionsInDsn = self::getOptions($matches['options']); + + foreach ($optionsInDsn as $parameter => $value) { + $options[$parameter] = $value; + } + } + + $newServers[] = $matches['host']; + } + + $connectionString = $protocol.'://'.implode(',', $newServers); + + $client = new \CouchbaseCluster($connectionString); + $client->authenticateAs($username, $password); + + $bucket = $client->openBucket($matches['bucketName']); + + unset($options['username'], $options['password']); + foreach ($options as $option => $value) { + if (!empty($value)) { + $bucket->$option = $value; + } + } + + return $bucket; + } finally { + restore_error_handler(); + } + } + + public static function isSupported(): bool + { + return \extension_loaded('couchbase') && version_compare(phpversion('couchbase'), '2.6.0', '>=') && version_compare(phpversion('couchbase'), '3.0', '<'); + } + + private static function getOptions(string $options): array + { + $results = []; + $optionsInArray = explode('&', $options); + + foreach ($optionsInArray as $option) { + [$key, $value] = explode('=', $option); + + if (\in_array($key, static::VALID_DSN_OPTIONS, true)) { + $results[$key] = $value; + } + } + + return $results; + } + + private static function initOptions(array $options): array + { + $options['username'] ??= ''; + $options['password'] ??= ''; + $options['operationTimeout'] ??= 0; + $options['configTimeout'] ??= 0; + $options['configNodeTimeout'] ??= 0; + $options['n1qlTimeout'] ??= 0; + $options['httpTimeout'] ??= 0; + $options['configDelay'] ??= 0; + $options['htconfigIdleTimeout'] ??= 0; + $options['durabilityInterval'] ??= 0; + $options['durabilityTimeout'] ??= 0; + + return $options; + } + + protected function doFetch(array $ids): iterable + { + $resultsCouchbase = $this->bucket->get($ids); + + $results = []; + foreach ($resultsCouchbase as $key => $value) { + if (null !== $value->error) { + continue; + } + $results[$key] = $this->marshaller->unmarshall($value->value); + } + + return $results; + } + + protected function doHave(string $id): bool + { + return false !== $this->bucket->get($id); + } + + protected function doClear(string $namespace): bool + { + if ('' === $namespace) { + $this->bucket->manager()->flush(); + + return true; + } + + return false; + } + + protected function doDelete(array $ids): bool + { + $results = $this->bucket->remove(array_values($ids)); + + foreach ($results as $key => $result) { + if (null !== $result->error && static::KEY_NOT_FOUND !== $result->error->getCode()) { + continue; + } + unset($results[$key]); + } + + return 0 === \count($results); + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + $lifetime = $this->normalizeExpiry($lifetime); + + $ko = []; + foreach ($values as $key => $value) { + $result = $this->bucket->upsert($key, $value, ['expiry' => $lifetime]); + + if (null !== $result->error) { + $ko[$key] = $result; + } + } + + return [] === $ko ? true : $ko; + } + + private function normalizeExpiry(int $expiry): int + { + if ($expiry && $expiry > static::THIRTY_DAYS_IN_SECONDS) { + $expiry += time(); + } + + return $expiry; + } +} diff --git a/vendor/symfony/cache/Adapter/CouchbaseCollectionAdapter.php b/vendor/symfony/cache/Adapter/CouchbaseCollectionAdapter.php new file mode 100644 index 000000000..a1cfb0843 --- /dev/null +++ b/vendor/symfony/cache/Adapter/CouchbaseCollectionAdapter.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Couchbase\Bucket; +use Couchbase\Cluster; +use Couchbase\ClusterOptions; +use Couchbase\Collection; +use Couchbase\DocumentNotFoundException; +use Couchbase\UpsertOptions; +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Antonio Jose Cerezo Aranda + */ +class CouchbaseCollectionAdapter extends AbstractAdapter +{ + private const MAX_KEY_LENGTH = 250; + + private Collection $connection; + private MarshallerInterface $marshaller; + + public function __construct(Collection $connection, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) + { + if (!static::isSupported()) { + throw new CacheException('Couchbase >= 3.0.5 < 4.0.0 is required.'); + } + + $this->maxIdLength = static::MAX_KEY_LENGTH; + + $this->connection = $connection; + + parent::__construct($namespace, $defaultLifetime); + $this->enableVersioning(); + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + public static function createConnection(#[\SensitiveParameter] array|string $dsn, array $options = []): Bucket|Collection + { + if (\is_string($dsn)) { + $dsn = [$dsn]; + } + + if (!static::isSupported()) { + throw new CacheException('Couchbase >= 3.0.5 < 4.0.0 is required.'); + } + + set_error_handler(static fn ($type, $msg, $file, $line) => throw new \ErrorException($msg, 0, $type, $file, $line)); + + $dsnPattern = '/^(?couchbase(?:s)?)\:\/\/(?:(?[^\:]+)\:(?[^\@]{6,})@)?' + .'(?[^\:]+(?:\:\d+)?)(?:\/(?[^\/\?]+))(?:(?:\/(?[^\/]+))' + .'(?:\/(?[^\/\?]+)))?(?:\/)?(?:\?(?.*))?$/i'; + + $newServers = []; + $protocol = 'couchbase'; + try { + $username = $options['username'] ?? ''; + $password = $options['password'] ?? ''; + + foreach ($dsn as $server) { + if (!str_starts_with($server, 'couchbase:')) { + throw new InvalidArgumentException('Invalid Couchbase DSN: it does not start with "couchbase:".'); + } + + preg_match($dsnPattern, $server, $matches); + + $username = $matches['username'] ?: $username; + $password = $matches['password'] ?: $password; + $protocol = $matches['protocol'] ?: $protocol; + + if (isset($matches['options'])) { + $optionsInDsn = self::getOptions($matches['options']); + + foreach ($optionsInDsn as $parameter => $value) { + $options[$parameter] = $value; + } + } + + $newServers[] = $matches['host']; + } + + $option = isset($matches['options']) ? '?'.$matches['options'] : ''; + $connectionString = $protocol.'://'.implode(',', $newServers).$option; + + $clusterOptions = new ClusterOptions(); + $clusterOptions->credentials($username, $password); + + $client = new Cluster($connectionString, $clusterOptions); + + $bucket = $client->bucket($matches['bucketName']); + $collection = $bucket->defaultCollection(); + if (!empty($matches['scopeName'])) { + $scope = $bucket->scope($matches['scopeName']); + $collection = $scope->collection($matches['collectionName']); + } + + return $collection; + } finally { + restore_error_handler(); + } + } + + public static function isSupported(): bool + { + return \extension_loaded('couchbase') && version_compare(phpversion('couchbase'), '3.0.5', '>=') && version_compare(phpversion('couchbase'), '4.0', '<'); + } + + private static function getOptions(string $options): array + { + $results = []; + $optionsInArray = explode('&', $options); + + foreach ($optionsInArray as $option) { + [$key, $value] = explode('=', $option); + + $results[$key] = $value; + } + + return $results; + } + + protected function doFetch(array $ids): array + { + $results = []; + foreach ($ids as $id) { + try { + $resultCouchbase = $this->connection->get($id); + } catch (DocumentNotFoundException) { + continue; + } + + $content = $resultCouchbase->value ?? $resultCouchbase->content(); + + $results[$id] = $this->marshaller->unmarshall($content); + } + + return $results; + } + + protected function doHave($id): bool + { + return $this->connection->exists($id)->exists(); + } + + protected function doClear($namespace): bool + { + return false; + } + + protected function doDelete(array $ids): bool + { + $idsErrors = []; + foreach ($ids as $id) { + try { + $result = $this->connection->remove($id); + + if (null === $result->mutationToken()) { + $idsErrors[] = $id; + } + } catch (DocumentNotFoundException) { + } + } + + return 0 === \count($idsErrors); + } + + protected function doSave(array $values, $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + $upsertOptions = new UpsertOptions(); + $upsertOptions->expiry($lifetime); + + $ko = []; + foreach ($values as $key => $value) { + try { + $this->connection->upsert($key, $value, $upsertOptions); + } catch (\Exception) { + $ko[$key] = ''; + } + } + + return [] === $ko ? true : $ko; + } +} diff --git a/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php b/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php new file mode 100644 index 000000000..9d02be3aa --- /dev/null +++ b/vendor/symfony/cache/Adapter/DoctrineDbalAdapter.php @@ -0,0 +1,413 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Doctrine\DBAL\ArrayParameterType; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\ParameterType; +use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\ServerVersionProvider; +use Doctrine\DBAL\Tools\DsnParser; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\PruneableInterface; + +class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface +{ + private const MAX_KEY_LENGTH = 255; + + private MarshallerInterface $marshaller; + private Connection $conn; + private string $platformName; + private string $serverVersion; + private string $table = 'cache_items'; + private string $idCol = 'item_id'; + private string $dataCol = 'item_data'; + private string $lifetimeCol = 'item_lifetime'; + private string $timeCol = 'item_time'; + private string $namespace; + + /** + * You can either pass an existing database Doctrine DBAL Connection or + * a DSN string that will be used to connect to the database. + * + * The cache table is created automatically when possible. + * Otherwise, use the createTable() method. + * + * List of available options: + * * db_table: The name of the table [default: cache_items] + * * db_id_col: The column where to store the cache id [default: item_id] + * * db_data_col: The column where to store the cache data [default: item_data] + * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime] + * * db_time_col: The column where to store the timestamp [default: item_time] + * + * @throws InvalidArgumentException When namespace contains invalid characters + */ + public function __construct(Connection|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null) + { + if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { + throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); + } + + if ($connOrDsn instanceof Connection) { + $this->conn = $connOrDsn; + } else { + if (!class_exists(DriverManager::class)) { + throw new InvalidArgumentException('Failed to parse DSN. Try running "composer require doctrine/dbal".'); + } + if (class_exists(DsnParser::class)) { + $params = (new DsnParser([ + 'db2' => 'ibm_db2', + 'mssql' => 'pdo_sqlsrv', + 'mysql' => 'pdo_mysql', + 'mysql2' => 'pdo_mysql', + 'postgres' => 'pdo_pgsql', + 'postgresql' => 'pdo_pgsql', + 'pgsql' => 'pdo_pgsql', + 'sqlite' => 'pdo_sqlite', + 'sqlite3' => 'pdo_sqlite', + ]))->parse($connOrDsn); + } else { + $params = ['url' => $connOrDsn]; + } + + $config = new Configuration(); + if (class_exists(DefaultSchemaManagerFactory::class)) { + $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); + } + + $this->conn = DriverManager::getConnection($params, $config); + } + + $this->maxIdLength = self::MAX_KEY_LENGTH; + $this->table = $options['db_table'] ?? $this->table; + $this->idCol = $options['db_id_col'] ?? $this->idCol; + $this->dataCol = $options['db_data_col'] ?? $this->dataCol; + $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; + $this->timeCol = $options['db_time_col'] ?? $this->timeCol; + $this->namespace = $namespace; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + + parent::__construct($namespace, $defaultLifetime); + } + + /** + * Creates the table to store cache items which can be called once for setup. + * + * Cache ID are saved in a column of maximum length 255. Cache data is + * saved in a BLOB. + * + * @throws DBALException When the table already exists + */ + public function createTable(): void + { + $schema = new Schema(); + $this->addTableToSchema($schema); + + foreach ($schema->toSql($this->conn->getDatabasePlatform()) as $sql) { + $this->conn->executeStatement($sql); + } + } + + /** + * @param \Closure $isSameDatabase + */ + public function configureSchema(Schema $schema, Connection $forConnection/* , \Closure $isSameDatabase */): void + { + if ($schema->hasTable($this->table)) { + return; + } + + $isSameDatabase = 2 < \func_num_args() ? func_get_arg(2) : static fn () => false; + + if ($forConnection !== $this->conn && !$isSameDatabase($this->conn->executeStatement(...))) { + return; + } + + $this->addTableToSchema($schema); + } + + public function prune(): bool + { + $deleteSql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ?"; + $params = [time()]; + $paramTypes = [ParameterType::INTEGER]; + + if ('' !== $this->namespace) { + $deleteSql .= " AND $this->idCol LIKE ?"; + $params[] = sprintf('%s%%', $this->namespace); + $paramTypes[] = ParameterType::STRING; + } + + try { + $this->conn->executeStatement($deleteSql, $params, $paramTypes); + } catch (TableNotFoundException) { + } + + return true; + } + + protected function doFetch(array $ids): iterable + { + $now = time(); + $expired = []; + + $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN (?)"; + $result = $this->conn->executeQuery($sql, [ + $now, + $ids, + ], [ + ParameterType::INTEGER, + class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY, + ])->iterateNumeric(); + + foreach ($result as $row) { + if (null === $row[1]) { + $expired[] = $row[0]; + } else { + yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); + } + } + + if ($expired) { + $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN (?)"; + $this->conn->executeStatement($sql, [ + $now, + $expired, + ], [ + ParameterType::INTEGER, + class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY, + ]); + } + } + + protected function doHave(string $id): bool + { + $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = ? AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ?)"; + $result = $this->conn->executeQuery($sql, [ + $id, + time(), + ], [ + ParameterType::STRING, + ParameterType::INTEGER, + ]); + + return (bool) $result->fetchOne(); + } + + protected function doClear(string $namespace): bool + { + if ('' === $namespace) { + $sql = $this->conn->getDatabasePlatform()->getTruncateTableSQL($this->table); + } else { + $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'"; + } + + try { + $this->conn->executeStatement($sql); + } catch (TableNotFoundException) { + } + + return true; + } + + protected function doDelete(array $ids): bool + { + $sql = "DELETE FROM $this->table WHERE $this->idCol IN (?)"; + try { + $this->conn->executeStatement($sql, [array_values($ids)], [class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY]); + } catch (TableNotFoundException) { + } + + return true; + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + $platformName = $this->getPlatformName(); + $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?)"; + + switch (true) { + case 'mysql' === $platformName: + $sql = $insertSql." ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; + break; + case 'oci' === $platformName: + // DUAL is Oracle specific dummy table + $sql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?"; + break; + case 'sqlsrv' === $platformName && version_compare($this->getServerVersion(), '10', '>='): + // MERGE is only available since SQL Server 2008 and must be terminated by semicolon + // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx + $sql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; + break; + case 'sqlite' === $platformName: + $sql = 'INSERT OR REPLACE'.substr($insertSql, 6); + break; + case 'pgsql' === $platformName && version_compare($this->getServerVersion(), '9.5', '>='): + $sql = $insertSql." ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; + break; + default: + $platformName = null; + $sql = "UPDATE $this->table SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ? WHERE $this->idCol = ?"; + break; + } + + $now = time(); + $lifetime = $lifetime ?: null; + try { + $stmt = $this->conn->prepare($sql); + } catch (TableNotFoundException) { + if (!$this->conn->isTransactionActive() || \in_array($platformName, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $stmt = $this->conn->prepare($sql); + } + + if ('sqlsrv' === $platformName || 'oci' === $platformName) { + $bind = static function ($id, $data) use ($stmt) { + $stmt->bindValue(1, $id); + $stmt->bindValue(2, $id); + $stmt->bindValue(3, $data, ParameterType::LARGE_OBJECT); + $stmt->bindValue(6, $data, ParameterType::LARGE_OBJECT); + }; + $stmt->bindValue(4, $lifetime, ParameterType::INTEGER); + $stmt->bindValue(5, $now, ParameterType::INTEGER); + $stmt->bindValue(7, $lifetime, ParameterType::INTEGER); + $stmt->bindValue(8, $now, ParameterType::INTEGER); + } elseif (null !== $platformName) { + $bind = static function ($id, $data) use ($stmt) { + $stmt->bindValue(1, $id); + $stmt->bindValue(2, $data, ParameterType::LARGE_OBJECT); + }; + $stmt->bindValue(3, $lifetime, ParameterType::INTEGER); + $stmt->bindValue(4, $now, ParameterType::INTEGER); + } else { + $stmt->bindValue(2, $lifetime, ParameterType::INTEGER); + $stmt->bindValue(3, $now, ParameterType::INTEGER); + + $insertStmt = $this->conn->prepare($insertSql); + $insertStmt->bindValue(3, $lifetime, ParameterType::INTEGER); + $insertStmt->bindValue(4, $now, ParameterType::INTEGER); + + $bind = static function ($id, $data) use ($stmt, $insertStmt) { + $stmt->bindValue(1, $data, ParameterType::LARGE_OBJECT); + $stmt->bindValue(4, $id); + $insertStmt->bindValue(1, $id); + $insertStmt->bindValue(2, $data, ParameterType::LARGE_OBJECT); + }; + } + + foreach ($values as $id => $data) { + $bind($id, $data); + try { + $rowCount = $stmt->executeStatement(); + } catch (TableNotFoundException) { + if (!$this->conn->isTransactionActive() || \in_array($platformName, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $rowCount = $stmt->executeStatement(); + } + if (null === $platformName && 0 === $rowCount) { + try { + $insertStmt->executeStatement(); + } catch (DBALException) { + // A concurrent write won, let it be + } + } + } + + return $failed; + } + + /** + * @internal + */ + protected function getId(mixed $key): string + { + if ('pgsql' !== $this->platformName ??= $this->getPlatformName()) { + return parent::getId($key); + } + + if (str_contains($key, "\0") || str_contains($key, '%') || !preg_match('//u', $key)) { + $key = rawurlencode($key); + } + + return parent::getId($key); + } + + private function getPlatformName(): string + { + if (isset($this->platformName)) { + return $this->platformName; + } + + $platform = $this->conn->getDatabasePlatform(); + + return $this->platformName = match (true) { + $platform instanceof \Doctrine\DBAL\Platforms\MySQLPlatform, + $platform instanceof \Doctrine\DBAL\Platforms\MySQL57Platform => 'mysql', + $platform instanceof \Doctrine\DBAL\Platforms\SqlitePlatform => 'sqlite', + $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform, + $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQL94Platform => 'pgsql', + $platform instanceof \Doctrine\DBAL\Platforms\OraclePlatform => 'oci', + $platform instanceof \Doctrine\DBAL\Platforms\SQLServerPlatform, + $platform instanceof \Doctrine\DBAL\Platforms\SQLServer2012Platform => 'sqlsrv', + default => $platform::class, + }; + } + + private function getServerVersion(): string + { + if (isset($this->serverVersion)) { + return $this->serverVersion; + } + + if ($this->conn instanceof ServerVersionProvider || $this->conn instanceof ServerInfoAwareConnection) { + return $this->serverVersion = $this->conn->getServerVersion(); + } + + // The condition should be removed once support for DBAL <3.3 is dropped + $conn = method_exists($this->conn, 'getNativeConnection') ? $this->conn->getNativeConnection() : $this->conn->getWrappedConnection(); + + return $this->serverVersion = $conn->getAttribute(\PDO::ATTR_SERVER_VERSION); + } + + private function addTableToSchema(Schema $schema): void + { + $types = [ + 'mysql' => 'binary', + 'sqlite' => 'text', + ]; + + $table = $schema->createTable($this->table); + $table->addColumn($this->idCol, $types[$this->getPlatformName()] ?? 'string', ['length' => 255]); + $table->addColumn($this->dataCol, 'blob', ['length' => 16777215]); + $table->addColumn($this->lifetimeCol, 'integer', ['unsigned' => true, 'notnull' => false]); + $table->addColumn($this->timeCol, 'integer', ['unsigned' => true]); + $table->setPrimaryKey([$this->idCol]); + } +} diff --git a/vendor/symfony/cache/Adapter/FilesystemAdapter.php b/vendor/symfony/cache/Adapter/FilesystemAdapter.php new file mode 100644 index 000000000..13daa568c --- /dev/null +++ b/vendor/symfony/cache/Adapter/FilesystemAdapter.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemTrait; + +class FilesystemAdapter extends AbstractAdapter implements PruneableInterface +{ + use FilesystemTrait; + + public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null) + { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } +} diff --git a/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php new file mode 100644 index 000000000..80edee433 --- /dev/null +++ b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php @@ -0,0 +1,267 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Marshaller\TagAwareMarshaller; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemTrait; + +/** + * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. + * + * @author Nicolas Grekas + * @author André Rømcke + */ +class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface +{ + use FilesystemTrait { + prune as private doPrune; + doClear as private doClearCache; + doSave as private doSaveCache; + } + + /** + * Folder used for tag symlinks. + */ + private const TAG_FOLDER = 'tags'; + + public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, ?MarshallerInterface $marshaller = null) + { + $this->marshaller = new TagAwareMarshaller($marshaller); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } + + public function prune(): bool + { + $ok = $this->doPrune(); + + set_error_handler(static function () {}); + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + try { + foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) { + $dir .= \DIRECTORY_SEPARATOR; + $keepDir = false; + for ($i = 0; $i < 38; ++$i) { + if (!is_dir($dir.$chars[$i])) { + continue; + } + for ($j = 0; $j < 38; ++$j) { + if (!is_dir($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + foreach (scandir($d, \SCANDIR_SORT_NONE) ?: [] as $link) { + if ('.' === $link || '..' === $link) { + continue; + } + if ('_' !== $dir[-2] && realpath($d.\DIRECTORY_SEPARATOR.$link)) { + $keepDir = true; + } else { + unlink($d.\DIRECTORY_SEPARATOR.$link); + } + } + $keepDir ?: rmdir($d); + } + $keepDir ?: rmdir($dir.$chars[$i]); + } + $keepDir ?: rmdir($dir); + } + } finally { + restore_error_handler(); + } + + return $ok; + } + + protected function doClear(string $namespace): bool + { + $ok = $this->doClearCache($namespace); + + if ('' !== $namespace) { + return $ok; + } + + set_error_handler(static function () {}); + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + $this->tmpSuffix ??= str_replace('/', '-', base64_encode(random_bytes(6))); + + try { + foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) { + if (rename($dir, $renamed = substr_replace($dir, $this->tmpSuffix.'_', -9))) { + $dir = $renamed.\DIRECTORY_SEPARATOR; + } else { + $dir .= \DIRECTORY_SEPARATOR; + $renamed = null; + } + + for ($i = 0; $i < 38; ++$i) { + if (!is_dir($dir.$chars[$i])) { + continue; + } + for ($j = 0; $j < 38; ++$j) { + if (!is_dir($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + foreach (scandir($d, \SCANDIR_SORT_NONE) ?: [] as $link) { + if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) { + unlink($d.\DIRECTORY_SEPARATOR.$link); + } + } + null === $renamed ?: rmdir($d); + } + null === $renamed ?: rmdir($dir.$chars[$i]); + } + null === $renamed ?: rmdir($renamed); + } + } finally { + restore_error_handler(); + } + + return $ok; + } + + protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array + { + $failed = $this->doSaveCache($values, $lifetime); + + // Add Tags as symlinks + foreach ($addTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $file = $this->getFile($id); + + if (!@symlink($file, $tagLink = $this->getFile($id, true, $tagFolder)) && !is_link($tagLink)) { + @unlink($file); + $failed[] = $id; + } + } + } + + // Unlink removed Tags + foreach ($removeTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + @unlink($this->getFile($id, false, $tagFolder)); + } + } + + return $failed; + } + + protected function doDeleteYieldTags(array $ids): iterable + { + foreach ($ids as $id) { + $file = $this->getFile($id); + if (!is_file($file) || !$h = @fopen($file, 'r')) { + continue; + } + + if (!@unlink($file)) { + fclose($h); + continue; + } + + $meta = explode("\n", fread($h, 4096), 3)[2] ?? ''; + + // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (13 < \strlen($meta) && "\x9D" === $meta[0] && "\0" === $meta[5] && "\x5F" === $meta[9]) { + $meta[9] = "\0"; + $tagLen = unpack('Nlen', $meta, 9)['len']; + $meta = substr($meta, 13, $tagLen); + + if (0 < $tagLen -= \strlen($meta)) { + $meta .= fread($h, $tagLen); + } + + try { + yield $id => '' === $meta ? [] : $this->marshaller->unmarshall($meta); + } catch (\Exception) { + yield $id => []; + } + } + + fclose($h); + } + } + + protected function doDeleteTagRelations(array $tagData): bool + { + foreach ($tagData as $tagId => $idList) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($idList as $id) { + @unlink($this->getFile($id, false, $tagFolder)); + } + } + + return true; + } + + protected function doInvalidate(array $tagIds): bool + { + foreach ($tagIds as $tagId) { + if (!is_dir($tagFolder = $this->getTagFolder($tagId))) { + continue; + } + + $this->tmpSuffix ??= str_replace('/', '-', base64_encode(random_bytes(6))); + + set_error_handler(static function () {}); + + try { + if (rename($tagFolder, $renamed = substr_replace($tagFolder, $this->tmpSuffix.'_', -10))) { + $tagFolder = $renamed.\DIRECTORY_SEPARATOR; + } else { + $renamed = null; + } + + foreach ($this->scanHashDir($tagFolder) as $itemLink) { + unlink(realpath($itemLink) ?: $itemLink); + unlink($itemLink); + } + + if (null === $renamed) { + continue; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + for ($j = 0; $j < 38; ++$j) { + rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]); + } + rmdir($tagFolder.$chars[$i]); + } + rmdir($renamed); + } finally { + restore_error_handler(); + } + } + + return true; + } + + private function getTagFolder(string $tagId): string + { + return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR; + } +} diff --git a/vendor/symfony/cache/Adapter/MemcachedAdapter.php b/vendor/symfony/cache/Adapter/MemcachedAdapter.php new file mode 100644 index 000000000..0efa152ee --- /dev/null +++ b/vendor/symfony/cache/Adapter/MemcachedAdapter.php @@ -0,0 +1,332 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Rob Frawley 2nd + * @author Nicolas Grekas + */ +class MemcachedAdapter extends AbstractAdapter +{ + /** + * We are replacing characters that are illegal in Memcached keys with reserved characters from + * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached. + * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}. + */ + private const RESERVED_MEMCACHED = " \n\r\t\v\f\0"; + private const RESERVED_PSR6 = '@()\{}/'; + private const MAX_KEY_LENGTH = 250; + + private MarshallerInterface $marshaller; + private \Memcached $client; + private \Memcached $lazyClient; + + /** + * Using a MemcachedAdapter with a TagAwareAdapter for storing tags is discouraged. + * Using a RedisAdapter is recommended instead. If you cannot do otherwise, be aware that: + * - the Memcached::OPT_BINARY_PROTOCOL must be enabled + * (that's the default when using MemcachedAdapter::createConnection()); + * - tags eviction by Memcached's LRU algorithm will break by-tags invalidation; + * your Memcached memory should be large enough to never trigger LRU. + * + * Using a MemcachedAdapter as a pure items store is fine. + */ + public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) + { + if (!static::isSupported()) { + throw new CacheException('Memcached > 3.1.5 is required.'); + } + $this->maxIdLength = self::MAX_KEY_LENGTH; + + if ('Memcached' === $client::class) { + $opt = $client->getOption(\Memcached::OPT_SERIALIZER); + if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) { + throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".'); + } + $this->maxIdLength -= \strlen($client->getOption(\Memcached::OPT_PREFIX_KEY)); + $this->client = $client; + } else { + $this->lazyClient = $client; + } + + parent::__construct($namespace, $defaultLifetime); + $this->enableVersioning(); + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + /** + * @return bool + */ + public static function isSupported() + { + return \extension_loaded('memcached') && version_compare(phpversion('memcached'), '3.1.6', '>='); + } + + /** + * Creates a Memcached instance. + * + * By default, the binary protocol, no block, and libketama compatible options are enabled. + * + * Examples for servers: + * - 'memcached://user:pass@localhost?weight=33' + * - [['localhost', 11211, 33]] + * + * @param array[]|string|string[] $servers An array of servers, a DSN, or an array of DSNs + * + * @throws \ErrorException When invalid options or servers are provided + */ + public static function createConnection(#[\SensitiveParameter] array|string $servers, array $options = []): \Memcached + { + if (\is_string($servers)) { + $servers = [$servers]; + } + if (!static::isSupported()) { + throw new CacheException('Memcached > 3.1.5 is required.'); + } + set_error_handler(static fn ($type, $msg, $file, $line) => throw new \ErrorException($msg, 0, $type, $file, $line)); + try { + $client = new \Memcached($options['persistent_id'] ?? null); + $username = $options['username'] ?? null; + $password = $options['password'] ?? null; + + // parse any DSN in $servers + foreach ($servers as $i => $dsn) { + if (\is_array($dsn)) { + continue; + } + if (!str_starts_with($dsn, 'memcached:')) { + throw new InvalidArgumentException('Invalid Memcached DSN: it does not start with "memcached:".'); + } + $params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) { + if (!empty($m[2])) { + [$username, $password] = explode(':', $m[2], 2) + [1 => null]; + $username = rawurldecode($username); + $password = null !== $password ? rawurldecode($password) : null; + } + + return 'file:'.($m[1] ?? ''); + }, $dsn); + if (false === $params = parse_url($params)) { + throw new InvalidArgumentException('Invalid Memcached DSN.'); + } + $query = $hosts = []; + if (isset($params['query'])) { + parse_str($params['query'], $query); + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException('Invalid Memcached DSN: query parameter "host" must be an array.'); + } + foreach ($hosts as $host => $weight) { + if (false === $port = strrpos($host, ':')) { + $hosts[$host] = [$host, 11211, (int) $weight]; + } else { + $hosts[$host] = [substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight]; + } + } + $hosts = array_values($hosts); + unset($query['host']); + } + if ($hosts && !isset($params['host']) && !isset($params['path'])) { + unset($servers[$i]); + $servers = array_merge($servers, $hosts); + continue; + } + } + if (!isset($params['host']) && !isset($params['path'])) { + throw new InvalidArgumentException('Invalid Memcached DSN: missing host or path.'); + } + if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) { + $params['weight'] = $m[1]; + $params['path'] = substr($params['path'], 0, -\strlen($m[0])); + } + $params += [ + 'host' => $params['host'] ?? $params['path'], + 'port' => isset($params['host']) ? 11211 : null, + 'weight' => 0, + ]; + if ($query) { + $params += $query; + $options = $query + $options; + } + + $servers[$i] = [$params['host'], $params['port'], $params['weight']]; + + if ($hosts) { + $servers = array_merge($servers, $hosts); + } + } + + // set client's options + unset($options['persistent_id'], $options['username'], $options['password'], $options['weight'], $options['lazy']); + $options = array_change_key_case($options, \CASE_UPPER); + $client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); + $client->setOption(\Memcached::OPT_NO_BLOCK, true); + $client->setOption(\Memcached::OPT_TCP_NODELAY, true); + if (!\array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !\array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) { + $client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true); + } + foreach ($options as $name => $value) { + if (\is_int($name)) { + continue; + } + if ('HASH' === $name || 'SERIALIZER' === $name || 'DISTRIBUTION' === $name) { + $value = \constant('Memcached::'.$name.'_'.strtoupper($value)); + } + unset($options[$name]); + + if (\defined('Memcached::OPT_'.$name)) { + $options[\constant('Memcached::OPT_'.$name)] = $value; + } + } + $client->setOptions($options + [\Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP]); + + // set client's servers, taking care of persistent connections + if (!$client->isPristine()) { + $oldServers = []; + foreach ($client->getServerList() as $server) { + $oldServers[] = [$server['host'], $server['port']]; + } + + $newServers = []; + foreach ($servers as $server) { + if (1 < \count($server)) { + $server = array_values($server); + unset($server[2]); + $server[1] = (int) $server[1]; + } + $newServers[] = $server; + } + + if ($oldServers !== $newServers) { + $client->resetServerList(); + $client->addServers($servers); + } + } else { + $client->addServers($servers); + } + + if (null !== $username || null !== $password) { + if (!method_exists($client, 'setSaslAuthData')) { + trigger_error('Missing SASL support: the memcached extension must be compiled with --enable-memcached-sasl.'); + } + $client->setSaslAuthData($username, $password); + } + + return $client; + } finally { + restore_error_handler(); + } + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + if ($lifetime && $lifetime > 30 * 86400) { + $lifetime += time(); + } + + $encodedValues = []; + foreach ($values as $key => $value) { + $encodedValues[self::encodeKey($key)] = $value; + } + + return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false; + } + + protected function doFetch(array $ids): iterable + { + try { + $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids); + + $encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds)); + + $result = []; + foreach ($encodedResult as $key => $value) { + $result[self::decodeKey($key)] = $this->marshaller->unmarshall($value); + } + + return $result; + } catch (\Error $e) { + throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); + } + } + + protected function doHave(string $id): bool + { + return false !== $this->getClient()->get(self::encodeKey($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode()); + } + + protected function doDelete(array $ids): bool + { + $ok = true; + $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids); + foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) { + if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) { + $ok = false; + } + } + + return $ok; + } + + protected function doClear(string $namespace): bool + { + return '' === $namespace && $this->getClient()->flush(); + } + + private function checkResultCode(mixed $result): mixed + { + $code = $this->client->getResultCode(); + + if (\Memcached::RES_SUCCESS === $code || \Memcached::RES_NOTFOUND === $code) { + return $result; + } + + throw new CacheException('MemcachedAdapter client error: '.strtolower($this->client->getResultMessage())); + } + + private function getClient(): \Memcached + { + if (isset($this->client)) { + return $this->client; + } + + $opt = $this->lazyClient->getOption(\Memcached::OPT_SERIALIZER); + if (\Memcached::SERIALIZER_PHP !== $opt && \Memcached::SERIALIZER_IGBINARY !== $opt) { + throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".'); + } + if ('' !== $prefix = (string) $this->lazyClient->getOption(\Memcached::OPT_PREFIX_KEY)) { + throw new CacheException(sprintf('MemcachedAdapter: "prefix_key" option must be empty when using proxified connections, "%s" given.', $prefix)); + } + + return $this->client = $this->lazyClient; + } + + private static function encodeKey(string $key): string + { + return strtr($key, self::RESERVED_MEMCACHED, self::RESERVED_PSR6); + } + + private static function decodeKey(string $key): string + { + return strtr($key, self::RESERVED_PSR6, self::RESERVED_MEMCACHED); + } +} diff --git a/vendor/symfony/cache/Adapter/NullAdapter.php b/vendor/symfony/cache/Adapter/NullAdapter.php new file mode 100644 index 000000000..d5d2ef6b4 --- /dev/null +++ b/vendor/symfony/cache/Adapter/NullAdapter.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * @author Titouan Galopin + */ +class NullAdapter implements AdapterInterface, CacheInterface +{ + private static \Closure $createCacheItem; + + public function __construct() + { + self::$createCacheItem ??= \Closure::bind( + static function ($key) { + $item = new CacheItem(); + $item->key = $key; + $item->isHit = false; + + return $item; + }, + null, + CacheItem::class + ); + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + $save = true; + + return $callback((self::$createCacheItem)($key), $save); + } + + public function getItem(mixed $key): CacheItem + { + return (self::$createCacheItem)($key); + } + + public function getItems(array $keys = []): iterable + { + return $this->generateItems($keys); + } + + public function hasItem(mixed $key): bool + { + return false; + } + + public function clear(string $prefix = ''): bool + { + return true; + } + + public function deleteItem(mixed $key): bool + { + return true; + } + + public function deleteItems(array $keys): bool + { + return true; + } + + public function save(CacheItemInterface $item): bool + { + return true; + } + + public function saveDeferred(CacheItemInterface $item): bool + { + return true; + } + + public function commit(): bool + { + return true; + } + + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + + private function generateItems(array $keys): \Generator + { + $f = self::$createCacheItem; + + foreach ($keys as $key) { + yield $key => $f($key); + } + } +} diff --git a/vendor/symfony/cache/Adapter/ParameterNormalizer.php b/vendor/symfony/cache/Adapter/ParameterNormalizer.php new file mode 100644 index 000000000..a6896402f --- /dev/null +++ b/vendor/symfony/cache/Adapter/ParameterNormalizer.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +/** + * @author Lars Strojny + */ +final class ParameterNormalizer +{ + public static function normalizeDuration(string $duration): int + { + if (is_numeric($duration)) { + return $duration; + } + + if (false !== $time = strtotime($duration, 0)) { + return $time; + } + + try { + return \DateTimeImmutable::createFromFormat('U', 0)->add(new \DateInterval($duration))->getTimestamp(); + } catch (\Exception $e) { + throw new \InvalidArgumentException(sprintf('Cannot parse date interval "%s".', $duration), 0, $e); + } + } +} diff --git a/vendor/symfony/cache/Adapter/PdoAdapter.php b/vendor/symfony/cache/Adapter/PdoAdapter.php new file mode 100644 index 000000000..c79b73959 --- /dev/null +++ b/vendor/symfony/cache/Adapter/PdoAdapter.php @@ -0,0 +1,388 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\PruneableInterface; + +class PdoAdapter extends AbstractAdapter implements PruneableInterface +{ + private const MAX_KEY_LENGTH = 255; + + private MarshallerInterface $marshaller; + private \PDO $conn; + private string $dsn; + private string $driver; + private string $serverVersion; + private string $table = 'cache_items'; + private string $idCol = 'item_id'; + private string $dataCol = 'item_data'; + private string $lifetimeCol = 'item_lifetime'; + private string $timeCol = 'item_time'; + private ?string $username = null; + private ?string $password = null; + private array $connectionOptions = []; + private string $namespace; + + /** + * You can either pass an existing database connection as PDO instance or + * a DSN string that will be used to lazy-connect to the database when the + * cache is actually used. + * + * List of available options: + * * db_table: The name of the table [default: cache_items] + * * db_id_col: The column where to store the cache id [default: item_id] + * * db_data_col: The column where to store the cache data [default: item_data] + * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime] + * * db_time_col: The column where to store the timestamp [default: item_time] + * * db_username: The username when lazy-connect [default: ''] + * * db_password: The password when lazy-connect [default: ''] + * * db_connection_options: An array of driver-specific connection options [default: []] + * + * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string + * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION + * @throws InvalidArgumentException When namespace contains invalid characters + */ + public function __construct(#[\SensitiveParameter] \PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null) + { + if (\is_string($connOrDsn) && str_contains($connOrDsn, '://')) { + throw new InvalidArgumentException(sprintf('Usage of Doctrine DBAL URL with "%s" is not supported. Use a PDO DSN or "%s" instead.', __CLASS__, DoctrineDbalAdapter::class)); + } + + if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { + throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); + } + + if ($connOrDsn instanceof \PDO) { + if (\PDO::ERRMODE_EXCEPTION !== $connOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) { + throw new InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); + } + + $this->conn = $connOrDsn; + } else { + $this->dsn = $connOrDsn; + } + + $this->maxIdLength = self::MAX_KEY_LENGTH; + $this->table = $options['db_table'] ?? $this->table; + $this->idCol = $options['db_id_col'] ?? $this->idCol; + $this->dataCol = $options['db_data_col'] ?? $this->dataCol; + $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; + $this->timeCol = $options['db_time_col'] ?? $this->timeCol; + $this->username = $options['db_username'] ?? $this->username; + $this->password = $options['db_password'] ?? $this->password; + $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions; + $this->namespace = $namespace; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + + parent::__construct($namespace, $defaultLifetime); + } + + /** + * Creates the table to store cache items which can be called once for setup. + * + * Cache ID are saved in a column of maximum length 255. Cache data is + * saved in a BLOB. + * + * @return void + * + * @throws \PDOException When the table already exists + * @throws \DomainException When an unsupported PDO driver is used + */ + public function createTable() + { + $sql = match ($driver = $this->getDriver()) { + // We use varbinary for the ID column because it prevents unwanted conversions: + // - character set conversions between server and client + // - trailing space removal + // - case-insensitivity + // - language processing like é == e + 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB", + 'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", + 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", + 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(255) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", + 'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", + default => throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $driver)), + }; + + $this->getConnection()->exec($sql); + } + + public function prune(): bool + { + $deleteSql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= :time"; + + if ('' !== $this->namespace) { + $deleteSql .= " AND $this->idCol LIKE :namespace"; + } + + $connection = $this->getConnection(); + + try { + $delete = $connection->prepare($deleteSql); + } catch (\PDOException) { + return true; + } + $delete->bindValue(':time', time(), \PDO::PARAM_INT); + + if ('' !== $this->namespace) { + $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); + } + try { + return $delete->execute(); + } catch (\PDOException) { + return true; + } + } + + protected function doFetch(array $ids): iterable + { + $connection = $this->getConnection(); + + $now = time(); + $expired = []; + + $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); + $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)"; + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + foreach ($ids as $id) { + $stmt->bindValue(++$i, $id); + } + $result = $stmt->execute(); + + if (\is_object($result)) { + $result = $result->iterateNumeric(); + } else { + $stmt->setFetchMode(\PDO::FETCH_NUM); + $result = $stmt; + } + + foreach ($result as $row) { + if (null === $row[1]) { + $expired[] = $row[0]; + } else { + yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); + } + } + + if ($expired) { + $sql = str_pad('', (\count($expired) << 1) - 1, '?,'); + $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)"; + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + foreach ($expired as $id) { + $stmt->bindValue(++$i, $id); + } + $stmt->execute(); + } + } + + protected function doHave(string $id): bool + { + $connection = $this->getConnection(); + + $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)"; + $stmt = $connection->prepare($sql); + + $stmt->bindValue(':id', $id); + $stmt->bindValue(':time', time(), \PDO::PARAM_INT); + $stmt->execute(); + + return (bool) $stmt->fetchColumn(); + } + + protected function doClear(string $namespace): bool + { + $conn = $this->getConnection(); + + if ('' === $namespace) { + if ('sqlite' === $this->getDriver()) { + $sql = "DELETE FROM $this->table"; + } else { + $sql = "TRUNCATE TABLE $this->table"; + } + } else { + $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'"; + } + + try { + $conn->exec($sql); + } catch (\PDOException) { + } + + return true; + } + + protected function doDelete(array $ids): bool + { + $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); + $sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)"; + try { + $stmt = $this->getConnection()->prepare($sql); + $stmt->execute(array_values($ids)); + } catch (\PDOException) { + } + + return true; + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + $conn = $this->getConnection(); + + $driver = $this->getDriver(); + $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; + + switch (true) { + case 'mysql' === $driver: + $sql = $insertSql." ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; + break; + case 'oci' === $driver: + // DUAL is Oracle specific dummy table + $sql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?"; + break; + case 'sqlsrv' === $driver && version_compare($this->getServerVersion(), '10', '>='): + // MERGE is only available since SQL Server 2008 and must be terminated by semicolon + // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx + $sql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; + break; + case 'sqlite' === $driver: + $sql = 'INSERT OR REPLACE'.substr($insertSql, 6); + break; + case 'pgsql' === $driver && version_compare($this->getServerVersion(), '9.5', '>='): + $sql = $insertSql." ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; + break; + default: + $driver = null; + $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id"; + break; + } + + $now = time(); + $lifetime = $lifetime ?: null; + try { + $stmt = $conn->prepare($sql); + } catch (\PDOException $e) { + if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) { + $this->createTable(); + } + $stmt = $conn->prepare($sql); + } + + // $id and $data are defined later in the loop. Binding is done by reference, values are read on execution. + if ('sqlsrv' === $driver || 'oci' === $driver) { + $stmt->bindParam(1, $id); + $stmt->bindParam(2, $id); + $stmt->bindParam(3, $data, \PDO::PARAM_LOB); + $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT); + $stmt->bindValue(5, $now, \PDO::PARAM_INT); + $stmt->bindParam(6, $data, \PDO::PARAM_LOB); + $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT); + $stmt->bindValue(8, $now, \PDO::PARAM_INT); + } else { + $stmt->bindParam(':id', $id); + $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); + $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); + $stmt->bindValue(':time', $now, \PDO::PARAM_INT); + } + if (null === $driver) { + $insertStmt = $conn->prepare($insertSql); + + $insertStmt->bindParam(':id', $id); + $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB); + $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); + $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); + } + + foreach ($values as $id => $data) { + try { + $stmt->execute(); + } catch (\PDOException $e) { + if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) { + $this->createTable(); + } + $stmt->execute(); + } + if (null === $driver && !$stmt->rowCount()) { + try { + $insertStmt->execute(); + } catch (\PDOException) { + // A concurrent write won, let it be + } + } + } + + return $failed; + } + + /** + * @internal + */ + protected function getId(mixed $key): string + { + if ('pgsql' !== $this->getDriver()) { + return parent::getId($key); + } + + if (str_contains($key, "\0") || str_contains($key, '%') || !preg_match('//u', $key)) { + $key = rawurlencode($key); + } + + return parent::getId($key); + } + + private function getConnection(): \PDO + { + if (!isset($this->conn)) { + $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions); + $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + } + + return $this->conn; + } + + private function getDriver(): string + { + return $this->driver ??= $this->getConnection()->getAttribute(\PDO::ATTR_DRIVER_NAME); + } + + private function getServerVersion(): string + { + return $this->serverVersion ??= $this->getConnection()->getAttribute(\PDO::ATTR_SERVER_VERSION); + } + + private function isTableMissing(\PDOException $exception): bool + { + $driver = $this->getDriver(); + [$sqlState, $code] = $exception->errorInfo ?? [null, $exception->getCode()]; + + return match ($driver) { + 'pgsql' => '42P01' === $sqlState, + 'sqlite' => str_contains($exception->getMessage(), 'no such table:'), + 'oci' => 942 === $code, + 'sqlsrv' => 208 === $code, + 'mysql' => 1146 === $code, + default => false, + }; + } +} diff --git a/vendor/symfony/cache/Adapter/PhpArrayAdapter.php b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php new file mode 100644 index 000000000..0cda1cce8 --- /dev/null +++ b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php @@ -0,0 +1,389 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Component\VarExporter\VarExporter; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. + * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter. + * + * @author Titouan Galopin + * @author Nicolas Grekas + */ +class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface +{ + use ContractsTrait; + use ProxyTrait; + + private string $file; + private array $keys; + private array $values; + + private static \Closure $createCacheItem; + private static array $valuesCache = []; + + /** + * @param string $file The PHP file were values are cached + * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit + */ + public function __construct(string $file, AdapterInterface $fallbackPool) + { + $this->file = $file; + $this->pool = $fallbackPool; + self::$createCacheItem ??= \Closure::bind( + static function ($key, $value, $isHit) { + $item = new CacheItem(); + $item->key = $key; + $item->value = $value; + $item->isHit = $isHit; + + return $item; + }, + null, + CacheItem::class + ); + } + + /** + * This adapter takes advantage of how PHP stores arrays in its latest versions. + * + * @param string $file The PHP file were values are cached + * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit + */ + public static function create(string $file, CacheItemPoolInterface $fallbackPool): CacheItemPoolInterface + { + if (!$fallbackPool instanceof AdapterInterface) { + $fallbackPool = new ProxyAdapter($fallbackPool); + } + + return new static($file, $fallbackPool); + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + if (!isset($this->values)) { + $this->initialize(); + } + if (!isset($this->keys[$key])) { + get_from_pool: + if ($this->pool instanceof CacheInterface) { + return $this->pool->get($key, $callback, $beta, $metadata); + } + + return $this->doGet($this->pool, $key, $callback, $beta, $metadata); + } + $value = $this->values[$this->keys[$key]]; + + if ('N;' === $value) { + return null; + } + try { + if ($value instanceof \Closure) { + return $value(); + } + } catch (\Throwable) { + unset($this->keys[$key]); + goto get_from_pool; + } + + return $value; + } + + public function getItem(mixed $key): CacheItem + { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + if (!isset($this->values)) { + $this->initialize(); + } + if (!isset($this->keys[$key])) { + return $this->pool->getItem($key); + } + + $value = $this->values[$this->keys[$key]]; + $isHit = true; + + if ('N;' === $value) { + $value = null; + } elseif ($value instanceof \Closure) { + try { + $value = $value(); + } catch (\Throwable) { + $value = null; + $isHit = false; + } + } + + return (self::$createCacheItem)($key, $value, $isHit); + } + + public function getItems(array $keys = []): iterable + { + foreach ($keys as $key) { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + } + if (!isset($this->values)) { + $this->initialize(); + } + + return $this->generateItems($keys); + } + + public function hasItem(mixed $key): bool + { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + if (!isset($this->values)) { + $this->initialize(); + } + + return isset($this->keys[$key]) || $this->pool->hasItem($key); + } + + public function deleteItem(mixed $key): bool + { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + if (!isset($this->values)) { + $this->initialize(); + } + + return !isset($this->keys[$key]) && $this->pool->deleteItem($key); + } + + public function deleteItems(array $keys): bool + { + $deleted = true; + $fallbackKeys = []; + + foreach ($keys as $key) { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + + if (isset($this->keys[$key])) { + $deleted = false; + } else { + $fallbackKeys[] = $key; + } + } + if (!isset($this->values)) { + $this->initialize(); + } + + if ($fallbackKeys) { + $deleted = $this->pool->deleteItems($fallbackKeys) && $deleted; + } + + return $deleted; + } + + public function save(CacheItemInterface $item): bool + { + if (!isset($this->values)) { + $this->initialize(); + } + + return !isset($this->keys[$item->getKey()]) && $this->pool->save($item); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + if (!isset($this->values)) { + $this->initialize(); + } + + return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item); + } + + public function commit(): bool + { + return $this->pool->commit(); + } + + public function clear(string $prefix = ''): bool + { + $this->keys = $this->values = []; + + $cleared = @unlink($this->file) || !file_exists($this->file); + unset(self::$valuesCache[$this->file]); + + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($prefix) && $cleared; + } + + return $this->pool->clear() && $cleared; + } + + /** + * Store an array of cached values. + * + * @param array $values The cached values + * + * @return string[] A list of classes to preload on PHP 7.4+ + */ + public function warmUp(array $values): array + { + if (file_exists($this->file)) { + if (!is_file($this->file)) { + throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: "%s".', $this->file)); + } + + if (!is_writable($this->file)) { + throw new InvalidArgumentException(sprintf('Cache file is not writable: "%s".', $this->file)); + } + } else { + $directory = \dirname($this->file); + + if (!is_dir($directory) && !@mkdir($directory, 0777, true)) { + throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: "%s".', $directory)); + } + + if (!is_writable($directory)) { + throw new InvalidArgumentException(sprintf('Cache directory is not writable: "%s".', $directory)); + } + } + + $preload = []; + $dumpedValues = ''; + $dumpedMap = []; + $dump = <<<'EOF' + $value) { + CacheItem::validateKey(\is_int($key) ? (string) $key : $key); + $isStaticValue = true; + + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { + try { + $value = VarExporter::export($value, $isStaticValue, $preload); + } catch (\Exception $e) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); + } + } elseif (\is_string($value)) { + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; + } + $value = var_export($value, true); + } elseif (!\is_scalar($value)) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); + } else { + $value = var_export($value, true); + } + + if (!$isStaticValue) { + $value = str_replace("\n", "\n ", $value); + $value = "static function () {\n return {$value};\n}"; + } + $hash = hash('xxh128', $value); + + if (null === $id = $dumpedMap[$hash] ?? null) { + $id = $dumpedMap[$hash] = \count($dumpedMap); + $dumpedValues .= "{$id} => {$value},\n"; + } + + $dump .= var_export($key, true)." => {$id},\n"; + } + + $dump .= "\n], [\n\n{$dumpedValues}\n]];\n"; + + $tmpFile = uniqid($this->file, true); + + file_put_contents($tmpFile, $dump); + @chmod($tmpFile, 0666 & ~umask()); + unset($serialized, $value, $dump); + + @rename($tmpFile, $this->file); + unset(self::$valuesCache[$this->file]); + + $this->initialize(); + + return $preload; + } + + /** + * Load the cache file. + */ + private function initialize(): void + { + if (isset(self::$valuesCache[$this->file])) { + $values = self::$valuesCache[$this->file]; + } elseif (!is_file($this->file)) { + $this->keys = $this->values = []; + + return; + } else { + $values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []]; + } + + if (2 !== \count($values) || !isset($values[0], $values[1])) { + $this->keys = $this->values = []; + } else { + [$this->keys, $this->values] = $values; + } + } + + private function generateItems(array $keys): \Generator + { + $f = self::$createCacheItem; + $fallbackKeys = []; + + foreach ($keys as $key) { + if (isset($this->keys[$key])) { + $value = $this->values[$this->keys[$key]]; + + if ('N;' === $value) { + yield $key => $f($key, null, true); + } elseif ($value instanceof \Closure) { + try { + yield $key => $f($key, $value(), true); + } catch (\Throwable) { + yield $key => $f($key, null, false); + } + } else { + yield $key => $f($key, $value, true); + } + } else { + $fallbackKeys[] = $key; + } + } + + if ($fallbackKeys) { + yield from $this->pool->getItems($fallbackKeys); + } + } +} diff --git a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php new file mode 100644 index 000000000..e550276df --- /dev/null +++ b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php @@ -0,0 +1,318 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemCommonTrait; +use Symfony\Component\VarExporter\VarExporter; + +/** + * @author Piotr Stankowski + * @author Nicolas Grekas + * @author Rob Frawley 2nd + */ +class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface +{ + use FilesystemCommonTrait { + doClear as private doCommonClear; + doDelete as private doCommonDelete; + } + + private \Closure $includeHandler; + private bool $appendOnly; + private array $values = []; + private array $files = []; + + private static int $startTime; + private static array $valuesCache = []; + + /** + * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire. + * Doing so is encouraged because it fits perfectly OPcache's memory model. + * + * @throws CacheException if OPcache is not enabled + */ + public function __construct(string $namespace = '', int $defaultLifetime = 0, ?string $directory = null, bool $appendOnly = false) + { + $this->appendOnly = $appendOnly; + self::$startTime ??= $_SERVER['REQUEST_TIME'] ?? time(); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + $this->includeHandler = static function ($type, $msg, $file, $line) { + throw new \ErrorException($msg, 0, $type, $file, $line); + }; + } + + /** + * @return bool + */ + public static function isSupported() + { + self::$startTime ??= $_SERVER['REQUEST_TIME'] ?? time(); + + return \function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) || filter_var(\ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOL)); + } + + public function prune(): bool + { + $time = time(); + $pruned = true; + $getExpiry = true; + + set_error_handler($this->includeHandler); + try { + foreach ($this->scanHashDir($this->directory) as $file) { + try { + if (\is_array($expiresAt = include $file)) { + $expiresAt = $expiresAt[0]; + } + } catch (\ErrorException $e) { + $expiresAt = $time; + } + + if ($time >= $expiresAt) { + $pruned = ($this->doUnlink($file) || !file_exists($file)) && $pruned; + } + } + } finally { + restore_error_handler(); + } + + return $pruned; + } + + protected function doFetch(array $ids): iterable + { + if ($this->appendOnly) { + $now = 0; + $missingIds = []; + } else { + $now = time(); + $missingIds = $ids; + $ids = []; + } + $values = []; + + begin: + $getExpiry = false; + + foreach ($ids as $id) { + if (null === $value = $this->values[$id] ?? null) { + $missingIds[] = $id; + } elseif ('N;' === $value) { + $values[$id] = null; + } elseif (!\is_object($value)) { + $values[$id] = $value; + } elseif (!$value instanceof LazyValue) { + $values[$id] = $value(); + } elseif (false === $values[$id] = include $value->file) { + unset($values[$id], $this->values[$id]); + $missingIds[] = $id; + } + if (!$this->appendOnly) { + unset($this->values[$id]); + } + } + + if (!$missingIds) { + return $values; + } + + set_error_handler($this->includeHandler); + try { + $getExpiry = true; + + foreach ($missingIds as $k => $id) { + try { + $file = $this->files[$id] ??= $this->getFile($id); + + if (isset(self::$valuesCache[$file])) { + [$expiresAt, $this->values[$id]] = self::$valuesCache[$file]; + } elseif (\is_array($expiresAt = include $file)) { + if ($this->appendOnly) { + self::$valuesCache[$file] = $expiresAt; + } + + [$expiresAt, $this->values[$id]] = $expiresAt; + } elseif ($now < $expiresAt) { + $this->values[$id] = new LazyValue($file); + } + + if ($now >= $expiresAt) { + unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]); + } + } catch (\ErrorException $e) { + unset($missingIds[$k]); + } + } + } finally { + restore_error_handler(); + } + + $ids = $missingIds; + $missingIds = []; + goto begin; + } + + protected function doHave(string $id): bool + { + if ($this->appendOnly && isset($this->values[$id])) { + return true; + } + + set_error_handler($this->includeHandler); + try { + $file = $this->files[$id] ??= $this->getFile($id); + $getExpiry = true; + + if (isset(self::$valuesCache[$file])) { + [$expiresAt, $value] = self::$valuesCache[$file]; + } elseif (\is_array($expiresAt = include $file)) { + if ($this->appendOnly) { + self::$valuesCache[$file] = $expiresAt; + } + + [$expiresAt, $value] = $expiresAt; + } elseif ($this->appendOnly) { + $value = new LazyValue($file); + } + } catch (\ErrorException) { + return false; + } finally { + restore_error_handler(); + } + if ($this->appendOnly) { + $now = 0; + $this->values[$id] = $value; + } else { + $now = time(); + } + + return $now < $expiresAt; + } + + protected function doSave(array $values, int $lifetime): array|bool + { + $ok = true; + $expiry = $lifetime ? time() + $lifetime : 'PHP_INT_MAX'; + $allowCompile = self::isSupported(); + + foreach ($values as $key => $value) { + unset($this->values[$key]); + $isStaticValue = true; + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { + try { + $value = VarExporter::export($value, $isStaticValue); + } catch (\Exception $e) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); + } + } elseif (\is_string($value)) { + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; + } + $value = var_export($value, true); + } elseif (!\is_scalar($value)) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); + } else { + $value = var_export($value, true); + } + + $encodedKey = rawurlencode($key); + + if ($isStaticValue) { + $value = "return [{$expiry}, {$value}];"; + } elseif ($this->appendOnly) { + $value = "return [{$expiry}, static fn () => {$value}];"; + } else { + // We cannot use a closure here because of https://bugs.php.net/76982 + $value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value); + $value = "namespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};"; + } + + $file = $this->files[$key] = $this->getFile($key, true); + // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past + $ok = $this->write($file, "directory)) { + throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory)); + } + + return $ok; + } + + protected function doClear(string $namespace): bool + { + $this->values = []; + + return $this->doCommonClear($namespace); + } + + protected function doDelete(array $ids): bool + { + foreach ($ids as $id) { + unset($this->values[$id]); + } + + return $this->doCommonDelete($ids); + } + + /** + * @return bool + */ + protected function doUnlink(string $file) + { + unset(self::$valuesCache[$file]); + + if (self::isSupported()) { + @opcache_invalidate($file, true); + } + + return @unlink($file); + } + + private function getFileKey(string $file): string + { + if (!$h = @fopen($file, 'r')) { + return ''; + } + + $encodedKey = substr(fgets($h), 8); + fclose($h); + + return rawurldecode(rtrim($encodedKey)); + } +} + +/** + * @internal + */ +class LazyValue +{ + public string $file; + + public function __construct(string $file) + { + $this->file = $file; + } +} diff --git a/vendor/symfony/cache/Adapter/ProxyAdapter.php b/vendor/symfony/cache/Adapter/ProxyAdapter.php new file mode 100644 index 000000000..c022dd5fa --- /dev/null +++ b/vendor/symfony/cache/Adapter/ProxyAdapter.php @@ -0,0 +1,206 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Contracts\Cache\CacheInterface; + +/** + * @author Nicolas Grekas + */ +class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface +{ + use ContractsTrait; + use ProxyTrait; + + private string $namespace = ''; + private int $namespaceLen; + private string $poolHash; + private int $defaultLifetime; + + private static \Closure $createCacheItem; + private static \Closure $setInnerItem; + + public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0) + { + $this->pool = $pool; + $this->poolHash = spl_object_hash($pool); + if ('' !== $namespace) { + \assert('' !== CacheItem::validateKey($namespace)); + $this->namespace = $namespace; + } + $this->namespaceLen = \strlen($namespace); + $this->defaultLifetime = $defaultLifetime; + self::$createCacheItem ??= \Closure::bind( + static function ($key, $innerItem, $poolHash) { + $item = new CacheItem(); + $item->key = $key; + + if (null === $innerItem) { + return $item; + } + + $item->value = $innerItem->get(); + $item->isHit = $innerItem->isHit(); + $item->innerItem = $innerItem; + $item->poolHash = $poolHash; + + if (!$item->unpack() && $innerItem instanceof CacheItem) { + $item->metadata = $innerItem->metadata; + } + $innerItem->set(null); + + return $item; + }, + null, + CacheItem::class + ); + self::$setInnerItem ??= \Closure::bind( + static function (CacheItemInterface $innerItem, CacheItem $item, $expiry = null) { + $innerItem->set($item->pack()); + $innerItem->expiresAt(($expiry ?? $item->expiry) ? \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', $expiry ?? $item->expiry)) : null); + }, + null, + CacheItem::class + ); + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + if (!$this->pool instanceof CacheInterface) { + return $this->doGet($this, $key, $callback, $beta, $metadata); + } + + return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) { + $item = (self::$createCacheItem)($key, $innerItem, $this->poolHash); + $item->set($value = $callback($item, $save)); + (self::$setInnerItem)($innerItem, $item); + + return $value; + }, $beta, $metadata); + } + + public function getItem(mixed $key): CacheItem + { + $item = $this->pool->getItem($this->getId($key)); + + return (self::$createCacheItem)($key, $item, $this->poolHash); + } + + public function getItems(array $keys = []): iterable + { + if ($this->namespaceLen) { + foreach ($keys as $i => $key) { + $keys[$i] = $this->getId($key); + } + } + + return $this->generateItems($this->pool->getItems($keys)); + } + + public function hasItem(mixed $key): bool + { + return $this->pool->hasItem($this->getId($key)); + } + + public function clear(string $prefix = ''): bool + { + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($this->namespace.$prefix); + } + + return $this->pool->clear(); + } + + public function deleteItem(mixed $key): bool + { + return $this->pool->deleteItem($this->getId($key)); + } + + public function deleteItems(array $keys): bool + { + if ($this->namespaceLen) { + foreach ($keys as $i => $key) { + $keys[$i] = $this->getId($key); + } + } + + return $this->pool->deleteItems($keys); + } + + public function save(CacheItemInterface $item): bool + { + return $this->doSave($item, __FUNCTION__); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + return $this->doSave($item, __FUNCTION__); + } + + public function commit(): bool + { + return $this->pool->commit(); + } + + private function doSave(CacheItemInterface $item, string $method): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $castItem = (array) $item; + + if (null === $castItem["\0*\0expiry"] && 0 < $this->defaultLifetime) { + $castItem["\0*\0expiry"] = microtime(true) + $this->defaultLifetime; + } + + if ($castItem["\0*\0poolHash"] === $this->poolHash && $castItem["\0*\0innerItem"]) { + $innerItem = $castItem["\0*\0innerItem"]; + } elseif ($this->pool instanceof AdapterInterface) { + // this is an optimization specific for AdapterInterface implementations + // so we can save a round-trip to the backend by just creating a new item + $innerItem = (self::$createCacheItem)($this->namespace.$castItem["\0*\0key"], null, $this->poolHash); + } else { + $innerItem = $this->pool->getItem($this->namespace.$castItem["\0*\0key"]); + } + + (self::$setInnerItem)($innerItem, $item, $castItem["\0*\0expiry"]); + + return $this->pool->$method($innerItem); + } + + private function generateItems(iterable $items): \Generator + { + $f = self::$createCacheItem; + + foreach ($items as $key => $item) { + if ($this->namespaceLen) { + $key = substr($key, $this->namespaceLen); + } + + yield $key => $f($key, $item, $this->poolHash); + } + } + + private function getId(mixed $key): string + { + \assert('' !== CacheItem::validateKey($key)); + + return $this->namespace.$key; + } +} diff --git a/vendor/symfony/cache/Adapter/Psr16Adapter.php b/vendor/symfony/cache/Adapter/Psr16Adapter.php new file mode 100644 index 000000000..a72b037b0 --- /dev/null +++ b/vendor/symfony/cache/Adapter/Psr16Adapter.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ProxyTrait; + +/** + * Turns a PSR-16 cache into a PSR-6 one. + * + * @author Nicolas Grekas + */ +class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + /** + * @internal + */ + protected const NS_SEPARATOR = '_'; + + private object $miss; + + public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0) + { + parent::__construct($namespace, $defaultLifetime); + + $this->pool = $pool; + $this->miss = new \stdClass(); + } + + protected function doFetch(array $ids): iterable + { + foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) { + if ($this->miss !== $value) { + yield $key => $value; + } + } + } + + protected function doHave(string $id): bool + { + return $this->pool->has($id); + } + + protected function doClear(string $namespace): bool + { + return $this->pool->clear(); + } + + protected function doDelete(array $ids): bool + { + return $this->pool->deleteMultiple($ids); + } + + protected function doSave(array $values, int $lifetime): array|bool + { + return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); + } +} diff --git a/vendor/symfony/cache/Adapter/RedisAdapter.php b/vendor/symfony/cache/Adapter/RedisAdapter.php new file mode 100644 index 000000000..e33f2f65f --- /dev/null +++ b/vendor/symfony/cache/Adapter/RedisAdapter.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisTrait; + +class RedisAdapter extends AbstractAdapter +{ + use RedisTrait; + + public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|\Relay\Relay $redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) + { + $this->init($redis, $namespace, $defaultLifetime, $marshaller); + } +} diff --git a/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php new file mode 100644 index 000000000..a44ef986d --- /dev/null +++ b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Connection\Aggregate\PredisCluster; +use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Response\ErrorInterface; +use Predis\Response\Status; +use Relay\Relay; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\DeflateMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Marshaller\TagAwareMarshaller; +use Symfony\Component\Cache\Traits\RedisTrait; + +/** + * Stores tag id <> cache id relationship as a Redis Set. + * + * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even + * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache + * relationship survives eviction (cache cleanup when Redis runs out of memory). + * + * Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up + * + * Design limitations: + * - Max 4 billion cache keys per cache tag as limited by Redis Set datatype. + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also. + * + * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies. + * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype. + * + * @author Nicolas Grekas + * @author André Rømcke + */ +class RedisTagAwareAdapter extends AbstractTagAwareAdapter +{ + use RedisTrait; + + /** + * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are + * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements. + */ + private const DEFAULT_CACHE_TTL = 8640000; + + /** + * detected eviction policy used on Redis server. + */ + private string $redisEvictionPolicy; + private string $namespace; + + public function __construct(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) + { + if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) { + throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection()))); + } + + $isRelay = $redis instanceof Relay; + if ($isRelay || \defined('Redis::OPT_COMPRESSION') && \in_array($redis::class, [\Redis::class, \RedisArray::class, \RedisCluster::class], true)) { + $compression = $redis->getOption($isRelay ? Relay::OPT_COMPRESSION : \Redis::OPT_COMPRESSION); + + foreach (\is_array($compression) ? $compression : [$compression] as $c) { + if ($isRelay ? Relay::COMPRESSION_NONE : \Redis::COMPRESSION_NONE !== $c) { + throw new InvalidArgumentException(sprintf('redis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class)); + } + } + } + + $this->init($redis, $namespace, $defaultLifetime, new TagAwareMarshaller($marshaller)); + $this->namespace = $namespace; + } + + protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array + { + $eviction = $this->getRedisEvictionPolicy(); + if ('noeviction' !== $eviction && !str_starts_with($eviction, 'volatile-')) { + throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); + } + + // serialize values + if (!$serialized = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op + $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) { + // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one + foreach ($serialized as $id => $value) { + yield 'setEx' => [ + $id, + 0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime, + $value, + ]; + } + + // Add and Remove Tags + foreach ($addTagData as $tagId => $ids) { + if (!$failed || $ids = array_diff($ids, $failed)) { + yield 'sAdd' => array_merge([$tagId], $ids); + } + } + + foreach ($delTagData as $tagId => $ids) { + if (!$failed || $ids = array_diff($ids, $failed)) { + yield 'sRem' => array_merge([$tagId], $ids); + } + } + }); + + foreach ($results as $id => $result) { + // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not + if (is_numeric($result)) { + continue; + } + // setEx results + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { + $failed[] = $id; + } + } + + return $failed; + } + + protected function doDeleteYieldTags(array $ids): iterable + { + $lua = <<<'EOLUA' + local v = redis.call('GET', KEYS[1]) + local e = redis.pcall('UNLINK', KEYS[1]) + + if type(e) ~= 'number' then + redis.call('DEL', KEYS[1]) + end + + if not v or v:len() <= 13 or v:byte(1) ~= 0x9D or v:byte(6) ~= 0 or v:byte(10) ~= 0x5F then + return '' + end + + return v:sub(14, 13 + v:byte(13) + v:byte(12) * 256 + v:byte(11) * 65536) +EOLUA; + + $results = $this->pipeline(function () use ($ids, $lua) { + foreach ($ids as $id) { + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id] : [$lua, [$id], 1]; + } + }); + + foreach ($results as $id => $result) { + if ($result instanceof \RedisException || $result instanceof \Relay\Exception || $result instanceof ErrorInterface) { + CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]); + + continue; + } + + try { + yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result); + } catch (\Exception) { + yield $id => []; + } + } + } + + protected function doDeleteTagRelations(array $tagData): bool + { + $results = $this->pipeline(static function () use ($tagData) { + foreach ($tagData as $tagId => $idList) { + array_unshift($idList, $tagId); + yield 'sRem' => $idList; + } + }); + foreach ($results as $result) { + // no-op + } + + return true; + } + + protected function doInvalidate(array $tagIds): bool + { + // This script scans the set of items linked to tag: it empties the set + // and removes the linked items. When the set is still not empty after + // the scan, it means we're in cluster mode and that the linked items + // are on other nodes: we move the links to a temporary set and we + // garbage collect that set from the client side. + + $lua = <<<'EOLUA' + redis.replicate_commands() + + local cursor = '0' + local id = KEYS[1] + repeat + local result = redis.call('SSCAN', id, cursor, 'COUNT', 5000); + cursor = result[1]; + local rems = {} + + for _, v in ipairs(result[2]) do + local ok, _ = pcall(redis.call, 'DEL', ARGV[1]..v) + if ok then + table.insert(rems, v) + end + end + if 0 < #rems then + redis.call('SREM', id, unpack(rems)) + end + until '0' == cursor; + + redis.call('SUNIONSTORE', '{'..id..'}'..id, id) + redis.call('DEL', id) + + return redis.call('SSCAN', '{'..id..'}'..id, '0', 'COUNT', 5000) +EOLUA; + + $results = $this->pipeline(function () use ($tagIds, $lua) { + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + } elseif (\is_array($prefix = $this->redis->getOption($this->redis instanceof Relay ? Relay::OPT_PREFIX : \Redis::OPT_PREFIX) ?? '')) { + $prefix = current($prefix); + } + + foreach ($tagIds as $id) { + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id, $prefix] : [$lua, [$id, $prefix], 1]; + } + }); + + $lua = <<<'EOLUA' + redis.replicate_commands() + + local id = KEYS[1] + local cursor = table.remove(ARGV) + redis.call('SREM', '{'..id..'}'..id, unpack(ARGV)) + + return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000) +EOLUA; + + $success = true; + foreach ($results as $id => $values) { + if ($values instanceof \RedisException || $values instanceof \Relay\Exception || $values instanceof ErrorInterface) { + CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]); + $success = false; + + continue; + } + + [$cursor, $ids] = $values; + + while ($ids || '0' !== $cursor) { + $this->doDelete($ids); + + $evalArgs = [$id, $cursor]; + array_splice($evalArgs, 1, 0, $ids); + + if ($this->redis instanceof \Predis\ClientInterface) { + array_unshift($evalArgs, $lua, 1); + } else { + $evalArgs = [$lua, $evalArgs, 1]; + } + + $results = $this->pipeline(function () use ($evalArgs) { + yield 'eval' => $evalArgs; + }); + + foreach ($results as [$cursor, $ids]) { + // no-op + } + } + } + + return $success; + } + + private function getRedisEvictionPolicy(): string + { + if (isset($this->redisEvictionPolicy)) { + return $this->redisEvictionPolicy; + } + + $hosts = $this->getHosts(); + $host = reset($hosts); + if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { + // Predis supports info command only on the master in replication environments + $hosts = [$host->getClientFor('master')]; + } + + foreach ($hosts as $host) { + $info = $host->info('Memory'); + + if (false === $info || null === $info || $info instanceof ErrorInterface) { + continue; + } + + $info = $info['Memory'] ?? $info; + + return $this->redisEvictionPolicy = $info['maxmemory_policy'] ?? ''; + } + + return $this->redisEvictionPolicy = ''; + } +} diff --git a/vendor/symfony/cache/Adapter/TagAwareAdapter.php b/vendor/symfony/cache/Adapter/TagAwareAdapter.php new file mode 100644 index 000000000..539ef1697 --- /dev/null +++ b/vendor/symfony/cache/Adapter/TagAwareAdapter.php @@ -0,0 +1,375 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Implements simple and robust tag-based invalidation suitable for use with volatile caches. + * + * This adapter works by storing a version for each tags. When saving an item, it is stored together with its tags and + * their corresponding versions. When retrieving an item, those tag versions are compared to the current version of + * each tags. Invalidation is achieved by deleting tags, thereby ensuring that their versions change even when the + * storage is out of space. When versions of non-existing tags are requested for item commits, this adapter assigns a + * new random version to them. + * + * @author Nicolas Grekas + * @author Sergey Belyshkin + */ +class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface +{ + use ContractsTrait; + use LoggerAwareTrait; + + public const TAGS_PREFIX = "\1tags\1"; + + private array $deferred = []; + private AdapterInterface $pool; + private AdapterInterface $tags; + private array $knownTagVersions = []; + private float $knownTagVersionsTtl; + + private static \Closure $setCacheItemTags; + private static \Closure $setTagVersions; + private static \Closure $getTagsByKey; + private static \Closure $saveTags; + + public function __construct(AdapterInterface $itemsPool, ?AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15) + { + $this->pool = $itemsPool; + $this->tags = $tagsPool ?? $itemsPool; + $this->knownTagVersionsTtl = $knownTagVersionsTtl; + self::$setCacheItemTags ??= \Closure::bind( + static function (array $items, array $itemTags) { + foreach ($items as $key => $item) { + $item->isTaggable = true; + + if (isset($itemTags[$key])) { + $tags = array_keys($itemTags[$key]); + $item->metadata[CacheItem::METADATA_TAGS] = array_combine($tags, $tags); + } else { + $item->value = null; + $item->isHit = false; + $item->metadata = []; + } + } + + return $items; + }, + null, + CacheItem::class + ); + self::$setTagVersions ??= \Closure::bind( + static function (array $items, array $tagVersions) { + foreach ($items as $item) { + $item->newMetadata[CacheItem::METADATA_TAGS] = array_intersect_key($tagVersions, $item->newMetadata[CacheItem::METADATA_TAGS] ?? []); + } + }, + null, + CacheItem::class + ); + self::$getTagsByKey ??= \Closure::bind( + static function ($deferred) { + $tagsByKey = []; + foreach ($deferred as $key => $item) { + $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? []; + $item->metadata = $item->newMetadata; + } + + return $tagsByKey; + }, + null, + CacheItem::class + ); + self::$saveTags ??= \Closure::bind( + static function (AdapterInterface $tagsAdapter, array $tags) { + ksort($tags); + + foreach ($tags as $v) { + $v->expiry = 0; + $tagsAdapter->saveDeferred($v); + } + + return $tagsAdapter->commit(); + }, + null, + CacheItem::class + ); + } + + public function invalidateTags(array $tags): bool + { + $ids = []; + foreach ($tags as $tag) { + \assert('' !== CacheItem::validateKey($tag)); + unset($this->knownTagVersions[$tag]); + $ids[] = $tag.static::TAGS_PREFIX; + } + + return !$tags || $this->tags->deleteItems($ids); + } + + public function hasItem(mixed $key): bool + { + return $this->getItem($key)->isHit(); + } + + public function getItem(mixed $key): CacheItem + { + foreach ($this->getItems([$key]) as $item) { + return $item; + } + } + + public function getItems(array $keys = []): iterable + { + $tagKeys = []; + $commit = false; + + foreach ($keys as $key) { + if ('' !== $key && \is_string($key)) { + $commit = $commit || isset($this->deferred[$key]); + } + } + + if ($commit) { + $this->commit(); + } + + try { + $items = $this->pool->getItems($keys); + } catch (InvalidArgumentException $e) { + $this->pool->getItems($keys); // Should throw an exception + + throw $e; + } + + $bufferedItems = $itemTags = []; + + foreach ($items as $key => $item) { + if (null !== $tags = $item->getMetadata()[CacheItem::METADATA_TAGS] ?? null) { + $itemTags[$key] = $tags; + } + + $bufferedItems[$key] = $item; + + if (null === $tags) { + $key = "\0tags\0".$key; + $tagKeys[$key] = $key; // BC with pools populated before v6.1 + } + } + + if ($tagKeys) { + foreach ($this->pool->getItems($tagKeys) as $key => $item) { + if ($item->isHit()) { + $itemTags[substr($key, \strlen("\0tags\0"))] = $item->get() ?: []; + } + } + } + + $tagVersions = $this->getTagVersions($itemTags, false); + foreach ($itemTags as $key => $tags) { + foreach ($tags as $tag => $version) { + if ($tagVersions[$tag] !== $version) { + unset($itemTags[$key]); + continue 2; + } + } + } + $tagVersions = null; + + return (self::$setCacheItemTags)($bufferedItems, $itemTags); + } + + public function clear(string $prefix = ''): bool + { + if ('' !== $prefix) { + foreach ($this->deferred as $key => $item) { + if (str_starts_with($key, $prefix)) { + unset($this->deferred[$key]); + } + } + } else { + $this->deferred = []; + } + + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($prefix); + } + + return $this->pool->clear(); + } + + public function deleteItem(mixed $key): bool + { + return $this->deleteItems([$key]); + } + + public function deleteItems(array $keys): bool + { + foreach ($keys as $key) { + if ('' !== $key && \is_string($key)) { + $keys[] = "\0tags\0".$key; // BC with pools populated before v6.1 + } + } + + return $this->pool->deleteItems($keys); + } + + public function save(CacheItemInterface $item): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return $this->commit(); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return true; + } + + public function commit(): bool + { + if (!$items = $this->deferred) { + return true; + } + + $tagVersions = $this->getTagVersions((self::$getTagsByKey)($items), true); + (self::$setTagVersions)($items, $tagVersions); + + $ok = true; + foreach ($items as $key => $item) { + if ($this->pool->saveDeferred($item)) { + unset($this->deferred[$key]); + } else { + $ok = false; + } + } + $ok = $this->pool->commit() && $ok; + + $tagVersions = array_keys($tagVersions); + (self::$setTagVersions)($items, array_combine($tagVersions, $tagVersions)); + + return $ok; + } + + public function prune(): bool + { + return $this->pool instanceof PruneableInterface && $this->pool->prune(); + } + + /** + * @return void + */ + public function reset() + { + $this->commit(); + $this->knownTagVersions = []; + $this->pool instanceof ResettableInterface && $this->pool->reset(); + $this->tags instanceof ResettableInterface && $this->tags->reset(); + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + /** + * @return void + */ + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->commit(); + } + + private function getTagVersions(array $tagsByKey, bool $persistTags): array + { + $tagVersions = []; + $fetchTagVersions = $persistTags; + + foreach ($tagsByKey as $tags) { + $tagVersions += $tags; + if ($fetchTagVersions) { + continue; + } + foreach ($tags as $tag => $version) { + if ($tagVersions[$tag] !== $version) { + $fetchTagVersions = true; + } + } + } + + if (!$tagVersions) { + return []; + } + + $now = microtime(true); + $tags = []; + foreach ($tagVersions as $tag => $version) { + $tags[$tag.static::TAGS_PREFIX] = $tag; + $knownTagVersion = $this->knownTagVersions[$tag] ?? [0, null]; + if ($fetchTagVersions || $now > $knownTagVersion[0] || $knownTagVersion[1] !== $version) { + // reuse previously fetched tag versions until the expiration + $fetchTagVersions = true; + } + } + + if (!$fetchTagVersions) { + return $tagVersions; + } + + $newTags = []; + $newVersion = null; + $expiration = $now + $this->knownTagVersionsTtl; + foreach ($this->tags->getItems(array_keys($tags)) as $tag => $version) { + unset($this->knownTagVersions[$tag = $tags[$tag]]); // update FIFO + if (null !== $tagVersions[$tag] = $version->get()) { + $this->knownTagVersions[$tag] = [$expiration, $tagVersions[$tag]]; + } elseif ($persistTags) { + $newTags[$tag] = $version->set($newVersion ??= random_bytes(6)); + $tagVersions[$tag] = $newVersion; + $this->knownTagVersions[$tag] = [$expiration, $newVersion]; + } + } + + if ($newTags) { + (self::$saveTags)($this->tags, $newTags); + } + + while ($now > ($this->knownTagVersions[$tag = array_key_first($this->knownTagVersions)][0] ?? \INF)) { + unset($this->knownTagVersions[$tag]); + } + + return $tagVersions; + } +} diff --git a/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php b/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php new file mode 100644 index 000000000..9242779c1 --- /dev/null +++ b/vendor/symfony/cache/Adapter/TagAwareAdapterInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\InvalidArgumentException; + +/** + * Interface for invalidating cached items using tags. + * + * @author Nicolas Grekas + */ +interface TagAwareAdapterInterface extends AdapterInterface +{ + /** + * Invalidates cached items using tags. + * + * @param string[] $tags An array of tags to invalidate + * + * @throws InvalidArgumentException When $tags is not valid + */ + public function invalidateTags(array $tags): bool; +} diff --git a/vendor/symfony/cache/Adapter/TraceableAdapter.php b/vendor/symfony/cache/Adapter/TraceableAdapter.php new file mode 100644 index 000000000..8569fa283 --- /dev/null +++ b/vendor/symfony/cache/Adapter/TraceableAdapter.php @@ -0,0 +1,262 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * An adapter that collects data about all cache calls. + * + * @author Aaron Scherer + * @author Tobias Nyholm + * @author Nicolas Grekas + */ +class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface +{ + protected $pool; + private array $calls = []; + + public function __construct(AdapterInterface $pool) + { + $this->pool = $pool; + } + + public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed + { + if (!$this->pool instanceof CacheInterface) { + throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class)); + } + + $isHit = true; + $callback = function (CacheItem $item, bool &$save) use ($callback, &$isHit) { + $isHit = $item->isHit(); + + return $callback($item, $save); + }; + + $event = $this->start(__FUNCTION__); + try { + $value = $this->pool->get($key, $callback, $beta, $metadata); + $event->result[$key] = get_debug_type($value); + } finally { + $event->end = microtime(true); + } + if ($isHit) { + ++$event->hits; + } else { + ++$event->misses; + } + + return $value; + } + + public function getItem(mixed $key): CacheItem + { + $event = $this->start(__FUNCTION__); + try { + $item = $this->pool->getItem($key); + } finally { + $event->end = microtime(true); + } + if ($event->result[$key] = $item->isHit()) { + ++$event->hits; + } else { + ++$event->misses; + } + + return $item; + } + + public function hasItem(mixed $key): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$key] = $this->pool->hasItem($key); + } finally { + $event->end = microtime(true); + } + } + + public function deleteItem(mixed $key): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$key] = $this->pool->deleteItem($key); + } finally { + $event->end = microtime(true); + } + } + + public function save(CacheItemInterface $item): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$item->getKey()] = $this->pool->save($item); + } finally { + $event->end = microtime(true); + } + } + + public function saveDeferred(CacheItemInterface $item): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$item->getKey()] = $this->pool->saveDeferred($item); + } finally { + $event->end = microtime(true); + } + } + + public function getItems(array $keys = []): iterable + { + $event = $this->start(__FUNCTION__); + try { + $result = $this->pool->getItems($keys); + } finally { + $event->end = microtime(true); + } + $f = function () use ($result, $event) { + $event->result = []; + foreach ($result as $key => $item) { + if ($event->result[$key] = $item->isHit()) { + ++$event->hits; + } else { + ++$event->misses; + } + yield $key => $item; + } + }; + + return $f(); + } + + public function clear(string $prefix = ''): bool + { + $event = $this->start(__FUNCTION__); + try { + if ($this->pool instanceof AdapterInterface) { + return $event->result = $this->pool->clear($prefix); + } + + return $event->result = $this->pool->clear(); + } finally { + $event->end = microtime(true); + } + } + + public function deleteItems(array $keys): bool + { + $event = $this->start(__FUNCTION__); + $event->result['keys'] = $keys; + try { + return $event->result['result'] = $this->pool->deleteItems($keys); + } finally { + $event->end = microtime(true); + } + } + + public function commit(): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result = $this->pool->commit(); + } finally { + $event->end = microtime(true); + } + } + + public function prune(): bool + { + if (!$this->pool instanceof PruneableInterface) { + return false; + } + $event = $this->start(__FUNCTION__); + try { + return $event->result = $this->pool->prune(); + } finally { + $event->end = microtime(true); + } + } + + /** + * @return void + */ + public function reset() + { + if ($this->pool instanceof ResetInterface) { + $this->pool->reset(); + } + + $this->clearCalls(); + } + + public function delete(string $key): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$key] = $this->pool->deleteItem($key); + } finally { + $event->end = microtime(true); + } + } + + /** + * @return array + */ + public function getCalls() + { + return $this->calls; + } + + /** + * @return void + */ + public function clearCalls() + { + $this->calls = []; + } + + public function getPool(): AdapterInterface + { + return $this->pool; + } + + /** + * @return TraceableAdapterEvent + */ + protected function start(string $name) + { + $this->calls[] = $event = new TraceableAdapterEvent(); + $event->name = $name; + $event->start = microtime(true); + + return $event; + } +} + +/** + * @internal + */ +class TraceableAdapterEvent +{ + public string $name; + public float $start; + public float $end; + public array|bool $result; + public int $hits = 0; + public int $misses = 0; +} diff --git a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php new file mode 100644 index 000000000..c85d199e4 --- /dev/null +++ b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * @author Robin Chalas + */ +class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface +{ + public function __construct(TagAwareAdapterInterface $pool) + { + parent::__construct($pool); + } + + public function invalidateTags(array $tags): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result = $this->pool->invalidateTags($tags); + } finally { + $event->end = microtime(true); + } + } +} diff --git a/vendor/symfony/cache/CHANGELOG.md b/vendor/symfony/cache/CHANGELOG.md new file mode 100644 index 000000000..4c1c9d420 --- /dev/null +++ b/vendor/symfony/cache/CHANGELOG.md @@ -0,0 +1,132 @@ +CHANGELOG +========= + +6.4 +--- + + * `EarlyExpirationHandler` no longer implements `MessageHandlerInterface`, rely on `AsMessageHandler` instead + +6.3 +--- + + * Add support for Relay PHP extension for Redis + * Updates to allow Redis cluster connections using predis/predis:^2.0 + * Add optional parameter `$isSameDatabase` to `DoctrineDbalAdapter::configureSchema()` + +6.1 +--- + + * Add support for ACL auth in RedisAdapter + * Improve reliability and performance of `TagAwareAdapter` by making tag versions an integral part of item value + +6.0 +--- + + * Remove `DoctrineProvider` and `DoctrineAdapter` + * Remove support of Doctrine DBAL in `PdoAdapter` + +5.4 +--- + + * Deprecate `DoctrineProvider` and `DoctrineAdapter` because these classes have been added to the `doctrine/cache` package + * Add `DoctrineDbalAdapter` identical to `PdoAdapter` for `Doctrine\DBAL\Connection` or DBAL URL + * Deprecate usage of `PdoAdapter` with `Doctrine\DBAL\Connection` or DBAL URL + +5.3 +--- + + * added support for connecting to Redis Sentinel clusters when using the Redis PHP extension + * add support for a custom serializer to the `ApcuAdapter` class + +5.2.0 +----- + + * added integration with Messenger to allow computing cached values in a worker + * allow ISO 8601 time intervals to specify default lifetime + +5.1.0 +----- + + * added max-items + LRU + max-lifetime capabilities to `ArrayCache` + * added `CouchbaseBucketAdapter` + * added context `cache-adapter` to log messages + +5.0.0 +----- + + * removed all PSR-16 implementations in the `Simple` namespace + * removed `SimpleCacheAdapter` + * removed `AbstractAdapter::unserialize()` + * removed `CacheItem::getPreviousTags()` + +4.4.0 +----- + + * added support for connecting to Redis Sentinel clusters + * added argument `$prefix` to `AdapterInterface::clear()` + * improved `RedisTagAwareAdapter` to support Redis server >= 2.8 and up to 4B items per tag + * added `TagAwareMarshaller` for optimized data storage when using `AbstractTagAwareAdapter` + * added `DeflateMarshaller` to compress serialized values + * removed support for phpredis 4 `compression` + * [BC BREAK] `RedisTagAwareAdapter` is not compatible with `RedisCluster` from `Predis` anymore, use `phpredis` instead + * Marked the `CacheDataCollector` class as `@final`. + * added `SodiumMarshaller` to encrypt/decrypt values using libsodium + +4.3.0 +----- + + * removed `psr/simple-cache` dependency, run `composer require psr/simple-cache` if you need it + * deprecated all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead + * deprecated `SimpleCacheAdapter`, use `Psr16Adapter` instead + +4.2.0 +----- + + * added support for connecting to Redis clusters via DSN + * added support for configuring multiple Memcached servers via DSN + * added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available + * implemented `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache + * added sub-second expiry accuracy for backends that support it + * added support for phpredis 4 `compression` and `tcp_keepalive` options + * added automatic table creation when using Doctrine DBAL with PDO-based backends + * throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool + * deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead + * deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods + * added `CacheCollectorPass` (originally in `FrameworkBundle`) + * added `CachePoolClearerPass` (originally in `FrameworkBundle`) + * added `CachePoolPass` (originally in `FrameworkBundle`) + * added `CachePoolPrunerPass` (originally in `FrameworkBundle`) + +3.4.0 +----- + + * added using options from Memcached DSN + * added PruneableInterface so PSR-6 or PSR-16 cache implementations can declare support for manual stale cache pruning + * added prune logic to FilesystemTrait, PhpFilesTrait, PdoTrait, TagAwareAdapter and ChainTrait + * now FilesystemAdapter, PhpFilesAdapter, FilesystemCache, PhpFilesCache, PdoAdapter, PdoCache, ChainAdapter, and + ChainCache implement PruneableInterface and support manual stale cache pruning + +3.3.0 +----- + + * added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any + * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters + * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16 + * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16) + * added TraceableAdapter (PSR-6) and TraceableCache (PSR-16) + +3.2.0 +----- + + * added TagAwareAdapter for tags-based invalidation + * added PdoAdapter with PDO and Doctrine DBAL support + * added PhpArrayAdapter and PhpFilesAdapter for OPcache-backed shared memory storage (PHP 7+ only) + * added NullAdapter + +3.1.0 +----- + + * added the component with strict PSR-6 implementations + * added ApcuAdapter, ArrayAdapter, FilesystemAdapter and RedisAdapter + * added AbstractAdapter, ChainAdapter and ProxyAdapter + * added DoctrineAdapter and DoctrineProvider for bidirectional interoperability with Doctrine Cache diff --git a/vendor/symfony/cache/CacheItem.php b/vendor/symfony/cache/CacheItem.php new file mode 100644 index 000000000..1a81706da --- /dev/null +++ b/vendor/symfony/cache/CacheItem.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * @author Nicolas Grekas + */ +final class CacheItem implements ItemInterface +{ + private const METADATA_EXPIRY_OFFSET = 1527506807; + private const VALUE_WRAPPER = "\xA9"; + + protected string $key; + protected mixed $value = null; + protected bool $isHit = false; + protected float|int|null $expiry = null; + protected array $metadata = []; + protected array $newMetadata = []; + protected ?ItemInterface $innerItem = null; + protected ?string $poolHash = null; + protected bool $isTaggable = false; + + public function getKey(): string + { + return $this->key; + } + + public function get(): mixed + { + return $this->value; + } + + public function isHit(): bool + { + return $this->isHit; + } + + /** + * @return $this + */ + public function set($value): static + { + $this->value = $value; + + return $this; + } + + /** + * @return $this + */ + public function expiresAt(?\DateTimeInterface $expiration): static + { + $this->expiry = null !== $expiration ? (float) $expiration->format('U.u') : null; + + return $this; + } + + /** + * @return $this + */ + public function expiresAfter(mixed $time): static + { + if (null === $time) { + $this->expiry = null; + } elseif ($time instanceof \DateInterval) { + $this->expiry = microtime(true) + \DateTimeImmutable::createFromFormat('U', 0)->add($time)->format('U.u'); + } elseif (\is_int($time)) { + $this->expiry = $time + microtime(true); + } else { + throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', get_debug_type($time))); + } + + return $this; + } + + public function tag(mixed $tags): static + { + if (!$this->isTaggable) { + throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key)); + } + if (!\is_array($tags) && !$tags instanceof \Traversable) { // don't use is_iterable(), it's slow + $tags = [$tags]; + } + foreach ($tags as $tag) { + if (!\is_string($tag) && !$tag instanceof \Stringable) { + throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', get_debug_type($tag))); + } + $tag = (string) $tag; + if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) { + continue; + } + if ('' === $tag) { + throw new InvalidArgumentException('Cache tag length must be greater than zero.'); + } + if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) { + throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS)); + } + $this->newMetadata[self::METADATA_TAGS][$tag] = $tag; + } + + return $this; + } + + public function getMetadata(): array + { + return $this->metadata; + } + + /** + * Validates a cache key according to PSR-6. + * + * @param mixed $key The key to validate + * + * @throws InvalidArgumentException When $key is not valid + */ + public static function validateKey($key): string + { + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + } + if ('' === $key) { + throw new InvalidArgumentException('Cache key length must be greater than zero.'); + } + if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) { + throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); + } + + return $key; + } + + /** + * Internal logging helper. + * + * @internal + */ + public static function log(?LoggerInterface $logger, string $message, array $context = []): void + { + if ($logger) { + $logger->warning($message, $context); + } else { + $replace = []; + foreach ($context as $k => $v) { + if (\is_scalar($v)) { + $replace['{'.$k.'}'] = $v; + } + } + @trigger_error(strtr($message, $replace), \E_USER_WARNING); + } + } + + private function pack(): mixed + { + if (!$m = $this->newMetadata) { + return $this->value; + } + $valueWrapper = self::VALUE_WRAPPER; + + return new $valueWrapper($this->value, $m + ['expiry' => $this->expiry]); + } + + private function unpack(): bool + { + $v = $this->value; + $valueWrapper = self::VALUE_WRAPPER; + + if ($v instanceof $valueWrapper) { + $this->value = $v->value; + $this->metadata = $v->metadata; + + return true; + } + + if (!\is_array($v) || 1 !== \count($v) || 10 !== \strlen($k = (string) array_key_first($v)) || "\x9D" !== $k[0] || "\0" !== $k[5] || "\x5F" !== $k[9]) { + return false; + } + + // BC with pools populated before v6.1 + $this->value = $v[$k]; + $this->metadata = unpack('Vexpiry/Nctime', substr($k, 1, -1)); + $this->metadata['expiry'] += self::METADATA_EXPIRY_OFFSET; + + return true; + } +} diff --git a/vendor/symfony/cache/DataCollector/CacheDataCollector.php b/vendor/symfony/cache/DataCollector/CacheDataCollector.php new file mode 100644 index 000000000..b9bcdaf13 --- /dev/null +++ b/vendor/symfony/cache/DataCollector/CacheDataCollector.php @@ -0,0 +1,184 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DataCollector; + +use Symfony\Component\Cache\Adapter\TraceableAdapter; +use Symfony\Component\Cache\Adapter\TraceableAdapterEvent; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; + +/** + * @author Aaron Scherer + * @author Tobias Nyholm + * + * @final + */ +class CacheDataCollector extends DataCollector implements LateDataCollectorInterface +{ + /** + * @var TraceableAdapter[] + */ + private array $instances = []; + + public function addInstance(string $name, TraceableAdapter $instance): void + { + $this->instances[$name] = $instance; + } + + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void + { + $empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []]; + $this->data = ['instances' => $empty, 'total' => $empty]; + foreach ($this->instances as $name => $instance) { + $this->data['instances']['calls'][$name] = $instance->getCalls(); + $this->data['instances']['adapters'][$name] = get_debug_type($instance->getPool()); + } + + $this->data['instances']['statistics'] = $this->calculateStatistics(); + $this->data['total']['statistics'] = $this->calculateTotalStatistics(); + } + + public function reset(): void + { + $this->data = []; + foreach ($this->instances as $instance) { + $instance->clearCalls(); + } + } + + public function lateCollect(): void + { + $this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']); + } + + public function getName(): string + { + return 'cache'; + } + + /** + * Method returns amount of logged Cache reads: "get" calls. + */ + public function getStatistics(): array + { + return $this->data['instances']['statistics']; + } + + /** + * Method returns the statistic totals. + */ + public function getTotals(): array + { + return $this->data['total']['statistics']; + } + + /** + * Method returns all logged Cache call objects. + */ + public function getCalls(): mixed + { + return $this->data['instances']['calls']; + } + + /** + * Method returns all logged Cache adapter classes. + */ + public function getAdapters(): array + { + return $this->data['instances']['adapters']; + } + + private function calculateStatistics(): array + { + $statistics = []; + foreach ($this->data['instances']['calls'] as $name => $calls) { + $statistics[$name] = [ + 'calls' => 0, + 'time' => 0, + 'reads' => 0, + 'writes' => 0, + 'deletes' => 0, + 'hits' => 0, + 'misses' => 0, + ]; + /** @var TraceableAdapterEvent $call */ + foreach ($calls as $call) { + ++$statistics[$name]['calls']; + $statistics[$name]['time'] += ($call->end ?? microtime(true)) - $call->start; + if ('get' === $call->name) { + ++$statistics[$name]['reads']; + if ($call->hits) { + ++$statistics[$name]['hits']; + } else { + ++$statistics[$name]['misses']; + ++$statistics[$name]['writes']; + } + } elseif ('getItem' === $call->name) { + ++$statistics[$name]['reads']; + if ($call->hits) { + ++$statistics[$name]['hits']; + } else { + ++$statistics[$name]['misses']; + } + } elseif ('getItems' === $call->name) { + $statistics[$name]['reads'] += $call->hits + $call->misses; + $statistics[$name]['hits'] += $call->hits; + $statistics[$name]['misses'] += $call->misses; + } elseif ('hasItem' === $call->name) { + ++$statistics[$name]['reads']; + foreach ($call->result ?? [] as $result) { + ++$statistics[$name][$result ? 'hits' : 'misses']; + } + } elseif ('save' === $call->name) { + ++$statistics[$name]['writes']; + } elseif ('deleteItem' === $call->name) { + ++$statistics[$name]['deletes']; + } + } + if ($statistics[$name]['reads']) { + $statistics[$name]['hit_read_ratio'] = round(100 * $statistics[$name]['hits'] / $statistics[$name]['reads'], 2); + } else { + $statistics[$name]['hit_read_ratio'] = null; + } + } + + return $statistics; + } + + private function calculateTotalStatistics(): array + { + $statistics = $this->getStatistics(); + $totals = [ + 'calls' => 0, + 'time' => 0, + 'reads' => 0, + 'writes' => 0, + 'deletes' => 0, + 'hits' => 0, + 'misses' => 0, + ]; + foreach ($statistics as $name => $values) { + foreach ($totals as $key => $value) { + $totals[$key] += $statistics[$name][$key]; + } + } + if ($totals['reads']) { + $totals['hit_read_ratio'] = round(100 * $totals['hits'] / $totals['reads'], 2); + } else { + $totals['hit_read_ratio'] = null; + } + + return $totals; + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php new file mode 100644 index 000000000..17507f1fb --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +use Symfony\Component\Cache\Adapter\TraceableAdapter; +use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Inject a data collector to all the cache services to be able to get detailed statistics. + * + * @author Tobias Nyholm + */ +class CacheCollectorPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('data_collector.cache')) { + return; + } + + foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) { + $poolName = $attributes[0]['name'] ?? $id; + + $this->addToCollector($id, $poolName, $container); + } + } + + private function addToCollector(string $id, string $name, ContainerBuilder $container): void + { + $definition = $container->getDefinition($id); + if ($definition->isAbstract()) { + return; + } + + $collectorDefinition = $container->getDefinition('data_collector.cache'); + $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class); + $recorder->setTags($definition->getTags()); + if (!$definition->isPublic() || !$definition->isPrivate()) { + $recorder->setPublic($definition->isPublic()); + } + $recorder->setArguments([new Reference($innerId = $id.'.recorder_inner')]); + + foreach ($definition->getMethodCalls() as [$method, $args]) { + if ('setCallbackWrapper' !== $method || !$args[0] instanceof Definition || !($args[0]->getArguments()[2] ?? null) instanceof Definition) { + continue; + } + if ([new Reference($id), 'setCallbackWrapper'] == $args[0]->getArguments()[2]->getFactory()) { + $args[0]->getArguments()[2]->setFactory([new Reference($innerId), 'setCallbackWrapper']); + } + } + + $definition->setTags([]); + $definition->setPublic(false); + + $container->setDefinition($innerId, $definition); + $container->setDefinition($id, $recorder); + + // Tell the collector to add the new instance + $collectorDefinition->addMethodCall('addInstance', [$name, new Reference($id)]); + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php new file mode 100644 index 000000000..6793bea94 --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas + */ +class CachePoolClearerPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + $container->getParameterBag()->remove('cache.prefix.seed'); + + foreach ($container->findTaggedServiceIds('cache.pool.clearer') as $id => $attr) { + $clearer = $container->getDefinition($id); + $pools = []; + foreach ($clearer->getArgument(0) as $name => $ref) { + if ($container->hasDefinition($ref)) { + $pools[$name] = new Reference($ref); + } + } + $clearer->replaceArgument(0, $pools); + } + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php new file mode 100644 index 000000000..f6622f27b --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php @@ -0,0 +1,246 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\ChainAdapter; +use Symfony\Component\Cache\Adapter\NullAdapter; +use Symfony\Component\Cache\Adapter\ParameterNormalizer; +use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas + */ +class CachePoolPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + if ($container->hasParameter('cache.prefix.seed')) { + $seed = $container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed')); + } else { + $seed = '_'.$container->getParameter('kernel.project_dir'); + $seed .= '.'.$container->getParameter('kernel.container_class'); + } + + $needsMessageHandler = false; + $allPools = []; + $clearers = []; + $attributes = [ + 'provider', + 'name', + 'namespace', + 'default_lifetime', + 'early_expiration_message_bus', + 'reset', + ]; + foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { + $adapter = $pool = $container->getDefinition($id); + if ($pool->isAbstract()) { + continue; + } + $class = $adapter->getClass(); + while ($adapter instanceof ChildDefinition) { + $adapter = $container->findDefinition($adapter->getParent()); + $class = $class ?: $adapter->getClass(); + if ($t = $adapter->getTag('cache.pool')) { + $tags[0] += $t[0]; + } + } + $name = $tags[0]['name'] ?? $id; + if (!isset($tags[0]['namespace'])) { + $namespaceSeed = $seed; + if (null !== $class) { + $namespaceSeed .= '.'.$class; + } + + $tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name); + } + if (isset($tags[0]['clearer'])) { + $clearer = $tags[0]['clearer']; + while ($container->hasAlias($clearer)) { + $clearer = (string) $container->getAlias($clearer); + } + } else { + $clearer = null; + } + unset($tags[0]['clearer'], $tags[0]['name']); + + if (isset($tags[0]['provider'])) { + $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider'])); + } + + if (ChainAdapter::class === $class) { + $adapters = []; + foreach ($adapter->getArgument(0) as $provider => $adapter) { + if ($adapter instanceof ChildDefinition) { + $chainedPool = $adapter; + } else { + $chainedPool = $adapter = new ChildDefinition($adapter); + } + + $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]]; + $chainedClass = ''; + + while ($adapter instanceof ChildDefinition) { + $adapter = $container->findDefinition($adapter->getParent()); + $chainedClass = $chainedClass ?: $adapter->getClass(); + if ($t = $adapter->getTag('cache.pool')) { + $chainedTags[0] += $t[0]; + } + } + + if (ChainAdapter::class === $chainedClass) { + throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent())); + } + + $i = 0; + + if (isset($chainedTags[0]['provider'])) { + $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider']))); + } + + if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) { + $chainedPool->replaceArgument($i++, $tags[0]['namespace']); + } + + if (isset($tags[0]['default_lifetime'])) { + $chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']); + } + + $adapters[] = $chainedPool; + } + + $pool->replaceArgument(0, $adapters); + unset($tags[0]['provider'], $tags[0]['namespace']); + $i = 1; + } else { + $i = 0; + } + + foreach ($attributes as $attr) { + if (!isset($tags[0][$attr])) { + // no-op + } elseif ('reset' === $attr) { + if ($tags[0][$attr]) { + $pool->addTag('kernel.reset', ['method' => $tags[0][$attr]]); + } + } elseif ('early_expiration_message_bus' === $attr) { + $needsMessageHandler = true; + $pool->addMethodCall('setCallbackWrapper', [(new Definition(EarlyExpirationDispatcher::class)) + ->addArgument(new Reference($tags[0]['early_expiration_message_bus'])) + ->addArgument(new Reference('reverse_container')) + ->addArgument((new Definition('callable')) + ->setFactory([new Reference($id), 'setCallbackWrapper']) + ->addArgument(null) + ), + ]); + $pool->addTag('container.reversible'); + } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) { + $argument = $tags[0][$attr]; + + if ('default_lifetime' === $attr && !is_numeric($argument)) { + $argument = (new Definition('int', [$argument])) + ->setFactory([ParameterNormalizer::class, 'normalizeDuration']); + } + + $pool->replaceArgument($i++, $argument); + } + unset($tags[0][$attr]); + } + if (!empty($tags[0])) { + throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime", "early_expiration_message_bus" and "reset", found "%s".', $id, implode('", "', array_keys($tags[0])))); + } + + if (null !== $clearer) { + $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + if (!$needsMessageHandler) { + $container->removeDefinition('cache.early_expiration_handler'); + } + + $notAliasedCacheClearerId = 'cache.global_clearer'; + while ($container->hasAlias($notAliasedCacheClearerId)) { + $notAliasedCacheClearerId = (string) $container->getAlias($notAliasedCacheClearerId); + } + if ($container->hasDefinition($notAliasedCacheClearerId)) { + $clearers[$notAliasedCacheClearerId] = $allPools; + } + + foreach ($clearers as $id => $pools) { + $clearer = $container->getDefinition($id); + if ($clearer instanceof ChildDefinition) { + $clearer->replaceArgument(0, $pools); + } else { + $clearer->setArgument(0, $pools); + } + $clearer->addTag('cache.pool.clearer'); + + if ('cache.system_clearer' === $id) { + $clearer->addTag('kernel.cache_clearer'); + } + } + + $allPoolsKeys = array_keys($allPools); + + if ($container->hasDefinition('console.command.cache_pool_list')) { + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, $allPoolsKeys); + } + + if ($container->hasDefinition('console.command.cache_pool_clear')) { + $container->getDefinition('console.command.cache_pool_clear')->addArgument($allPoolsKeys); + } + + if ($container->hasDefinition('console.command.cache_pool_delete')) { + $container->getDefinition('console.command.cache_pool_delete')->addArgument($allPoolsKeys); + } + } + + private function getNamespace(string $seed, string $id): string + { + return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10); + } + + /** + * @internal + */ + public static function getServiceProvider(ContainerBuilder $container, string $name): string + { + $container->resolveEnvPlaceholders($name, null, $usedEnvs); + + if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) { + $dsn = $name; + + if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) { + $definition = new Definition(AbstractAdapter::class); + $definition->setFactory([AbstractAdapter::class, 'createConnection']); + $definition->setArguments([$dsn, ['lazy' => true]]); + $container->setDefinition($name, $definition); + } + } + + return $name; + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php new file mode 100644 index 000000000..00e912686 --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Rob Frawley 2nd + */ +class CachePoolPrunerPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('console.command.cache_pool_prune')) { + return; + } + + $services = []; + + foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { + $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass()); + + if (!$reflection = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + + if ($reflection->implementsInterface(PruneableInterface::class)) { + $services[$id] = new Reference($id); + } + } + + $container->getDefinition('console.command.cache_pool_prune')->replaceArgument(0, new IteratorArgument($services)); + } +} diff --git a/vendor/symfony/cache/Exception/CacheException.php b/vendor/symfony/cache/Exception/CacheException.php new file mode 100644 index 000000000..d2e975b2b --- /dev/null +++ b/vendor/symfony/cache/Exception/CacheException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Exception; + +use Psr\Cache\CacheException as Psr6CacheInterface; +use Psr\SimpleCache\CacheException as SimpleCacheInterface; + +if (interface_exists(SimpleCacheInterface::class)) { + class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class CacheException extends \Exception implements Psr6CacheInterface + { + } +} diff --git a/vendor/symfony/cache/Exception/InvalidArgumentException.php b/vendor/symfony/cache/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..7f9584a26 --- /dev/null +++ b/vendor/symfony/cache/Exception/InvalidArgumentException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Exception; + +use Psr\Cache\InvalidArgumentException as Psr6CacheInterface; +use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface; + +if (interface_exists(SimpleCacheInterface::class)) { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface + { + } +} diff --git a/vendor/symfony/cache/Exception/LogicException.php b/vendor/symfony/cache/Exception/LogicException.php new file mode 100644 index 000000000..9ffa7ed69 --- /dev/null +++ b/vendor/symfony/cache/Exception/LogicException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Exception; + +use Psr\Cache\CacheException as Psr6CacheInterface; +use Psr\SimpleCache\CacheException as SimpleCacheInterface; + +if (interface_exists(SimpleCacheInterface::class)) { + class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class LogicException extends \LogicException implements Psr6CacheInterface + { + } +} diff --git a/vendor/symfony/cache/LICENSE b/vendor/symfony/cache/LICENSE new file mode 100644 index 000000000..0223acd4a --- /dev/null +++ b/vendor/symfony/cache/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016-present Fabien Potencier + +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. diff --git a/vendor/symfony/cache/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php new file mode 100644 index 000000000..c5c5fde89 --- /dev/null +++ b/vendor/symfony/cache/LockRegistry.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Log\LoggerInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * LockRegistry is used internally by existing adapters to protect against cache stampede. + * + * It does so by wrapping the computation of items in a pool of locks. + * Foreach each apps, there can be at most 20 concurrent processes that + * compute items at the same time and only one per cache-key. + * + * @author Nicolas Grekas + */ +final class LockRegistry +{ + private static array $openedFiles = []; + private static ?array $lockedFiles = null; + private static \Exception $signalingException; + private static \Closure $signalingCallback; + + /** + * The number of items in this list controls the max number of concurrent processes. + */ + private static array $files = [ + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'CouchbaseBucketAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'CouchbaseCollectionAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineDbalAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ParameterNormalizer.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php', + ]; + + /** + * Defines a set of existing files that will be used as keys to acquire locks. + * + * @return array The previously defined set of files + */ + public static function setFiles(array $files): array + { + $previousFiles = self::$files; + self::$files = $files; + + foreach (self::$openedFiles as $file) { + if ($file) { + flock($file, \LOCK_UN); + fclose($file); + } + } + self::$openedFiles = self::$lockedFiles = []; + + return $previousFiles; + } + + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null): mixed + { + if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) { + // disable locking on Windows by default + self::$files = self::$lockedFiles = []; + } + + $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1; + + if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) { + return $callback($item, $save); + } + + self::$signalingException ??= unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}"); + self::$signalingCallback ??= fn () => throw self::$signalingException; + + while (true) { + try { + // race to get the lock in non-blocking mode + $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock); + + if ($locked || !$wouldBlock) { + $logger?->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]); + self::$lockedFiles[$key] = true; + + $value = $callback($item, $save); + + if ($save) { + if ($setMetadata) { + $setMetadata($item); + } + + $pool->save($item->set($value)); + $save = false; + } + + return $value; + } + // if we failed the race, retry locking in blocking mode to wait for the winner + $logger?->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]); + flock($lock, \LOCK_SH); + } finally { + flock($lock, \LOCK_UN); + unset(self::$lockedFiles[$key]); + } + + try { + $value = $pool->get($item->getKey(), self::$signalingCallback, 0); + $logger?->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]); + $save = false; + + return $value; + } catch (\Exception $e) { + if (self::$signalingException !== $e) { + throw $e; + } + $logger?->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]); + } + } + + return null; + } + + /** + * @return resource|false + */ + private static function open(int $key) + { + if (null !== $h = self::$openedFiles[$key] ?? null) { + return $h; + } + set_error_handler(static fn () => null); + try { + $h = fopen(self::$files[$key], 'r+'); + } finally { + restore_error_handler(); + } + + return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r'); + } +} diff --git a/vendor/symfony/cache/Marshaller/DefaultMarshaller.php b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php new file mode 100644 index 000000000..34bbeb893 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; + +/** + * Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise. + * + * @author Nicolas Grekas + */ +class DefaultMarshaller implements MarshallerInterface +{ + private bool $useIgbinarySerialize = true; + private bool $throwOnSerializationFailure = false; + + public function __construct(?bool $useIgbinarySerialize = null, bool $throwOnSerializationFailure = false) + { + if (null === $useIgbinarySerialize) { + $useIgbinarySerialize = \extension_loaded('igbinary') && version_compare('3.1.6', phpversion('igbinary'), '<='); + } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || version_compare('3.1.6', phpversion('igbinary'), '>'))) { + throw new CacheException(\extension_loaded('igbinary') ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.'); + } + $this->useIgbinarySerialize = $useIgbinarySerialize; + $this->throwOnSerializationFailure = $throwOnSerializationFailure; + } + + public function marshall(array $values, ?array &$failed): array + { + $serialized = $failed = []; + + foreach ($values as $id => $value) { + try { + if ($this->useIgbinarySerialize) { + $serialized[$id] = igbinary_serialize($value); + } else { + $serialized[$id] = serialize($value); + } + } catch (\Exception $e) { + if ($this->throwOnSerializationFailure) { + throw new \ValueError($e->getMessage(), 0, $e); + } + $failed[] = $id; + } + } + + return $serialized; + } + + public function unmarshall(string $value): mixed + { + if ('b:0;' === $value) { + return false; + } + if ('N;' === $value) { + return null; + } + static $igbinaryNull; + if ($value === $igbinaryNull ??= \extension_loaded('igbinary') ? igbinary_serialize(null) : false) { + return null; + } + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); + try { + if (':' === ($value[1] ?? ':')) { + if (false !== $value = unserialize($value)) { + return $value; + } + } elseif (false === $igbinaryNull) { + throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?'); + } elseif (null !== $value = igbinary_unserialize($value)) { + return $value; + } + + throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.'); + } catch (\Error $e) { + throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); + } + } + + /** + * @internal + */ + public static function handleUnserializeCallback(string $class): never + { + throw new \DomainException('Class not found: '.$class); + } +} diff --git a/vendor/symfony/cache/Marshaller/DeflateMarshaller.php b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php new file mode 100644 index 000000000..35237de68 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; + +/** + * Compresses values using gzdeflate(). + * + * @author Nicolas Grekas + */ +class DeflateMarshaller implements MarshallerInterface +{ + private MarshallerInterface $marshaller; + + public function __construct(MarshallerInterface $marshaller) + { + if (!\function_exists('gzdeflate')) { + throw new CacheException('The "zlib" PHP extension is not loaded.'); + } + + $this->marshaller = $marshaller; + } + + public function marshall(array $values, ?array &$failed): array + { + return array_map('gzdeflate', $this->marshaller->marshall($values, $failed)); + } + + public function unmarshall(string $value): mixed + { + if (false !== $inflatedValue = @gzinflate($value)) { + $value = $inflatedValue; + } + + return $this->marshaller->unmarshall($value); + } +} diff --git a/vendor/symfony/cache/Marshaller/MarshallerInterface.php b/vendor/symfony/cache/Marshaller/MarshallerInterface.php new file mode 100644 index 000000000..5b81aad2d --- /dev/null +++ b/vendor/symfony/cache/Marshaller/MarshallerInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +/** + * Serializes/unserializes PHP values. + * + * Implementations of this interface MUST deal with errors carefully. They MUST + * also deal with forward and backward compatibility at the storage format level. + * + * @author Nicolas Grekas + */ +interface MarshallerInterface +{ + /** + * Serializes a list of values. + * + * When serialization fails for a specific value, no exception should be + * thrown. Instead, its key should be listed in $failed. + */ + public function marshall(array $values, ?array &$failed): array; + + /** + * Unserializes a single value and throws an exception if anything goes wrong. + * + * @throws \Exception Whenever unserialization fails + */ + public function unmarshall(string $value): mixed; +} diff --git a/vendor/symfony/cache/Marshaller/SodiumMarshaller.php b/vendor/symfony/cache/Marshaller/SodiumMarshaller.php new file mode 100644 index 000000000..49eb716a6 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/SodiumMarshaller.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; + +/** + * Encrypt/decrypt values using Libsodium. + * + * @author Ahmed TAILOULOUTE + */ +class SodiumMarshaller implements MarshallerInterface +{ + private MarshallerInterface $marshaller; + private array $decryptionKeys; + + /** + * @param string[] $decryptionKeys The key at index "0" is required and is used to decrypt and encrypt values; + * more rotating keys can be provided to decrypt values; + * each key must be generated using sodium_crypto_box_keypair() + */ + public function __construct(array $decryptionKeys, ?MarshallerInterface $marshaller = null) + { + if (!self::isSupported()) { + throw new CacheException('The "sodium" PHP extension is not loaded.'); + } + + if (!isset($decryptionKeys[0])) { + throw new InvalidArgumentException('At least one decryption key must be provided at index "0".'); + } + + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + $this->decryptionKeys = $decryptionKeys; + } + + public static function isSupported(): bool + { + return \function_exists('sodium_crypto_box_seal'); + } + + public function marshall(array $values, ?array &$failed): array + { + $encryptionKey = sodium_crypto_box_publickey($this->decryptionKeys[0]); + + $encryptedValues = []; + foreach ($this->marshaller->marshall($values, $failed) as $k => $v) { + $encryptedValues[$k] = sodium_crypto_box_seal($v, $encryptionKey); + } + + return $encryptedValues; + } + + public function unmarshall(string $value): mixed + { + foreach ($this->decryptionKeys as $k) { + if (false !== $decryptedValue = @sodium_crypto_box_seal_open($value, $k)) { + $value = $decryptedValue; + break; + } + } + + return $this->marshaller->unmarshall($value); + } +} diff --git a/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php b/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php new file mode 100644 index 000000000..825f32cc0 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +/** + * A marshaller optimized for data structures generated by AbstractTagAwareAdapter. + * + * @author Nicolas Grekas + */ +class TagAwareMarshaller implements MarshallerInterface +{ + private MarshallerInterface $marshaller; + + public function __construct(?MarshallerInterface $marshaller = null) + { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + public function marshall(array $values, ?array &$failed): array + { + $failed = $notSerialized = $serialized = []; + + foreach ($values as $id => $value) { + if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) { + // if the value is an array with keys "tags", "value" and "meta", use a compact serialization format + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall() + + $v = $this->marshaller->marshall($value, $f); + + if ($f) { + $f = []; + $failed[] = $id; + } else { + if ([] === $value['tags']) { + $v['tags'] = ''; + } + + $serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value']; + $serialized[$id][9] = "\x5F"; + } + } else { + // other arbitrary values are serialized using the decorated marshaller below + $notSerialized[$id] = $value; + } + } + + if ($notSerialized) { + $serialized += $this->marshaller->marshall($notSerialized, $f); + $failed = array_merge($failed, $f); + } + + return $serialized; + } + + public function unmarshall(string $value): mixed + { + // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) { + return $this->marshaller->unmarshall($value); + } + + // data consists of value, tags and metadata which we need to unpack + $meta = substr($value, 1, 12); + $meta[8] = "\0"; + $tagLen = unpack('Nlen', $meta, 8)['len']; + $meta = substr($meta, 0, 8); + + return [ + 'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)), + 'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [], + 'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta, + ]; + } +} diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php b/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php new file mode 100644 index 000000000..8fe0f2515 --- /dev/null +++ b/vendor/symfony/cache/Messenger/EarlyExpirationDispatcher.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Messenger; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\DependencyInjection\ReverseContainer; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Stamp\HandledStamp; + +/** + * Sends the computation of cached values to a message bus. + */ +class EarlyExpirationDispatcher +{ + private MessageBusInterface $bus; + private ReverseContainer $reverseContainer; + private ?\Closure $callbackWrapper; + + public function __construct(MessageBusInterface $bus, ReverseContainer $reverseContainer, ?callable $callbackWrapper = null) + { + $this->bus = $bus; + $this->reverseContainer = $reverseContainer; + $this->callbackWrapper = null === $callbackWrapper ? null : $callbackWrapper(...); + } + + /** + * @return mixed + */ + public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null) + { + if (!$item->isHit() || null === $message = EarlyExpirationMessage::create($this->reverseContainer, $callback, $item, $pool)) { + // The item is stale or the callback cannot be reversed: we must compute the value now + $logger?->info('Computing item "{key}" online: '.($item->isHit() ? 'callback cannot be reversed' : 'item is stale'), ['key' => $item->getKey()]); + + return null !== $this->callbackWrapper ? ($this->callbackWrapper)($callback, $item, $save, $pool, $setMetadata, $logger) : $callback($item, $save); + } + + $envelope = $this->bus->dispatch($message); + + if ($logger) { + if ($envelope->last(HandledStamp::class)) { + $logger->info('Item "{key}" was computed online', ['key' => $item->getKey()]); + } else { + $logger->info('Item "{key}" sent for recomputation', ['key' => $item->getKey()]); + } + } + + // The item's value is not stale, no need to write it to the backend + $save = false; + + return $message->getItem()->get() ?? $item->get(); + } +} diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php b/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php new file mode 100644 index 000000000..b7eab8064 --- /dev/null +++ b/vendor/symfony/cache/Messenger/EarlyExpirationHandler.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Messenger; + +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\DependencyInjection\ReverseContainer; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; + +/** + * Computes cached values sent to a message bus. + */ +#[AsMessageHandler] +class EarlyExpirationHandler +{ + private ReverseContainer $reverseContainer; + private array $processedNonces = []; + + public function __construct(ReverseContainer $reverseContainer) + { + $this->reverseContainer = $reverseContainer; + } + + /** + * @return void + */ + public function __invoke(EarlyExpirationMessage $message) + { + $item = $message->getItem(); + $metadata = $item->getMetadata(); + $expiry = $metadata[CacheItem::METADATA_EXPIRY] ?? 0; + $ctime = $metadata[CacheItem::METADATA_CTIME] ?? 0; + + if ($expiry && $ctime) { + // skip duplicate or expired messages + + $processingNonce = [$expiry, $ctime]; + $pool = $message->getPool(); + $key = $item->getKey(); + + if (($this->processedNonces[$pool][$key] ?? null) === $processingNonce) { + return; + } + + if (microtime(true) >= $expiry) { + return; + } + + $this->processedNonces[$pool] = [$key => $processingNonce] + ($this->processedNonces[$pool] ?? []); + + if (\count($this->processedNonces[$pool]) > 100) { + array_pop($this->processedNonces[$pool]); + } + } + + static $setMetadata; + + $setMetadata ??= \Closure::bind( + function (CacheItem $item, float $startTime) { + if ($item->expiry > $endTime = microtime(true)) { + $item->newMetadata[CacheItem::METADATA_EXPIRY] = $item->expiry; + $item->newMetadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime)); + } + }, + null, + CacheItem::class + ); + + $startTime = microtime(true); + $pool = $message->findPool($this->reverseContainer); + $callback = $message->findCallback($this->reverseContainer); + $save = true; + $value = $callback($item, $save); + $setMetadata($item, $startTime); + $pool->save($item->set($value)); + } +} diff --git a/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php b/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php new file mode 100644 index 000000000..6056ebab4 --- /dev/null +++ b/vendor/symfony/cache/Messenger/EarlyExpirationMessage.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Messenger; + +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\DependencyInjection\ReverseContainer; + +/** + * Conveys a cached value that needs to be computed. + */ +final class EarlyExpirationMessage +{ + private CacheItem $item; + private string $pool; + private string|array $callback; + + public static function create(ReverseContainer $reverseContainer, callable $callback, CacheItem $item, AdapterInterface $pool): ?self + { + try { + $item = clone $item; + $item->set(null); + } catch (\Exception) { + return null; + } + + $pool = $reverseContainer->getId($pool); + + if (\is_object($callback)) { + if (null === $id = $reverseContainer->getId($callback)) { + return null; + } + + $callback = '@'.$id; + } elseif (!\is_array($callback)) { + $callback = (string) $callback; + } elseif (!\is_object($callback[0])) { + $callback = [(string) $callback[0], (string) $callback[1]]; + } else { + if (null === $id = $reverseContainer->getId($callback[0])) { + return null; + } + + $callback = ['@'.$id, (string) $callback[1]]; + } + + return new self($item, $pool, $callback); + } + + public function getItem(): CacheItem + { + return $this->item; + } + + public function getPool(): string + { + return $this->pool; + } + + /** + * @return string|string[] + */ + public function getCallback(): string|array + { + return $this->callback; + } + + public function findPool(ReverseContainer $reverseContainer): AdapterInterface + { + return $reverseContainer->getService($this->pool); + } + + public function findCallback(ReverseContainer $reverseContainer): callable + { + if (\is_string($callback = $this->callback)) { + return '@' === $callback[0] ? $reverseContainer->getService(substr($callback, 1)) : $callback; + } + if ('@' === $callback[0][0]) { + $callback[0] = $reverseContainer->getService(substr($callback[0], 1)); + } + + return $callback; + } + + private function __construct(CacheItem $item, string $pool, string|array $callback) + { + $this->item = $item; + $this->pool = $pool; + $this->callback = $callback; + } +} diff --git a/vendor/symfony/cache/PruneableInterface.php b/vendor/symfony/cache/PruneableInterface.php new file mode 100644 index 000000000..3095c80f4 --- /dev/null +++ b/vendor/symfony/cache/PruneableInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +/** + * Interface extends psr-6 and psr-16 caches to allow for pruning (deletion) of all expired cache items. + */ +interface PruneableInterface +{ + public function prune(): bool; +} diff --git a/vendor/symfony/cache/Psr16Cache.php b/vendor/symfony/cache/Psr16Cache.php new file mode 100644 index 000000000..f21384fee --- /dev/null +++ b/vendor/symfony/cache/Psr16Cache.php @@ -0,0 +1,240 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Cache\CacheException as Psr6CacheException; +use Psr\Cache\CacheItemPoolInterface; +use Psr\SimpleCache\CacheException as SimpleCacheException; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\ProxyTrait; + +/** + * Turns a PSR-6 cache into a PSR-16 one. + * + * @author Nicolas Grekas + */ +class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + private ?\Closure $createCacheItem = null; + private ?CacheItem $cacheItemPrototype = null; + private static \Closure $packCacheItem; + + public function __construct(CacheItemPoolInterface $pool) + { + $this->pool = $pool; + + if (!$pool instanceof AdapterInterface) { + return; + } + $cacheItemPrototype = &$this->cacheItemPrototype; + $createCacheItem = \Closure::bind( + static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) { + $item = clone $cacheItemPrototype; + $item->poolHash = $item->innerItem = null; + if ($allowInt && \is_int($key)) { + $item->key = (string) $key; + } else { + \assert('' !== CacheItem::validateKey($key)); + $item->key = $key; + } + $item->value = $value; + $item->isHit = false; + + return $item; + }, + null, + CacheItem::class + ); + $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) { + if (null === $this->cacheItemPrototype) { + $this->get($allowInt && \is_int($key) ? (string) $key : $key); + } + $this->createCacheItem = $createCacheItem; + + return $createCacheItem($key, null, $allowInt)->set($value); + }; + self::$packCacheItem ??= \Closure::bind( + static function (CacheItem $item) { + $item->newMetadata = $item->metadata; + + return $item->pack(); + }, + null, + CacheItem::class + ); + } + + public function get($key, $default = null): mixed + { + try { + $item = $this->pool->getItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null === $this->cacheItemPrototype) { + $this->cacheItemPrototype = clone $item; + $this->cacheItemPrototype->set(null); + } + + return $item->isHit() ? $item->get() : $default; + } + + public function set($key, $value, $ttl = null): bool + { + try { + if (null !== $f = $this->createCacheItem) { + $item = $f($key, $value); + } else { + $item = $this->pool->getItem($key)->set($value); + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + + return $this->pool->save($item); + } + + public function delete($key): bool + { + try { + return $this->pool->deleteItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + public function clear(): bool + { + return $this->pool->clear(); + } + + public function getMultiple($keys, $default = null): iterable + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); + } + + try { + $items = $this->pool->getItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $values = []; + + if (!$this->pool instanceof AdapterInterface) { + foreach ($items as $key => $item) { + $values[$key] = $item->isHit() ? $item->get() : $default; + } + + return $values; + } + + foreach ($items as $key => $item) { + $values[$key] = $item->isHit() ? (self::$packCacheItem)($item) : $default; + } + + return $values; + } + + public function setMultiple($values, $ttl = null): bool + { + $valuesIsArray = \is_array($values); + if (!$valuesIsArray && !$values instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', get_debug_type($values))); + } + $items = []; + + try { + if (null !== $f = $this->createCacheItem) { + $valuesIsArray = false; + foreach ($values as $key => $value) { + $items[$key] = $f($key, $value, true); + } + } elseif ($valuesIsArray) { + $items = []; + foreach ($values as $key => $value) { + $items[] = (string) $key; + } + $items = $this->pool->getItems($items); + } else { + foreach ($values as $key => $value) { + if (\is_int($key)) { + $key = (string) $key; + } + $items[$key] = $this->pool->getItem($key)->set($value); + } + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $ok = true; + + foreach ($items as $key => $item) { + if ($valuesIsArray) { + $item->set($values[$key]); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + $ok = $this->pool->saveDeferred($item) && $ok; + } + + return $this->pool->commit() && $ok; + } + + public function deleteMultiple($keys): bool + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); + } + + try { + return $this->pool->deleteItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + public function has($key): bool + { + try { + return $this->pool->hasItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/vendor/symfony/cache/README.md b/vendor/symfony/cache/README.md new file mode 100644 index 000000000..c466d5788 --- /dev/null +++ b/vendor/symfony/cache/README.md @@ -0,0 +1,19 @@ +Symfony PSR-6 implementation for caching +======================================== + +The Cache component provides extended +[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to +your applications. It is designed to have a low overhead so that caching is +fastest. It ships with adapters for the most widespread caching backends. +It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter, +and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)' +`CacheInterface` and `TagAwareCacheInterface`. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/cache.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/cache/ResettableInterface.php b/vendor/symfony/cache/ResettableInterface.php new file mode 100644 index 000000000..7b0a853f2 --- /dev/null +++ b/vendor/symfony/cache/ResettableInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Symfony\Contracts\Service\ResetInterface; + +/** + * Resets a pool's local state. + */ +interface ResettableInterface extends ResetInterface +{ +} diff --git a/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php new file mode 100644 index 000000000..4ab2537db --- /dev/null +++ b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php @@ -0,0 +1,380 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Psr\Cache\CacheItemInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait AbstractAdapterTrait +{ + use LoggerAwareTrait; + + /** + * needs to be set by class, signature is function(string , mixed , bool ). + */ + private static \Closure $createCacheItem; + + /** + * needs to be set by class, signature is function(array , string , array <&expiredIds>). + */ + private static \Closure $mergeByLifetime; + + private string $namespace = ''; + private int $defaultLifetime; + private string $namespaceVersion = ''; + private bool $versioningIsEnabled = false; + private array $deferred = []; + private array $ids = []; + + /** + * @var int|null The maximum length to enforce for identifiers or null when no limit applies + */ + protected $maxIdLength; + + /** + * Fetches several cache items. + * + * @param array $ids The cache identifiers to fetch + */ + abstract protected function doFetch(array $ids): iterable; + + /** + * Confirms if the cache contains specified cache item. + * + * @param string $id The identifier for which to check existence + */ + abstract protected function doHave(string $id): bool; + + /** + * Deletes all items in the pool. + * + * @param string $namespace The prefix used for all identifiers managed by this pool + */ + abstract protected function doClear(string $namespace): bool; + + /** + * Removes multiple items from the pool. + * + * @param array $ids An array of identifiers that should be removed from the pool + */ + abstract protected function doDelete(array $ids): bool; + + /** + * Persists several cache items immediately. + * + * @param array $values The values to cache, indexed by their cache identifier + * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning + * + * @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not + */ + abstract protected function doSave(array $values, int $lifetime): array|bool; + + public function hasItem(mixed $key): bool + { + $id = $this->getId($key); + + if (isset($this->deferred[$key])) { + $this->commit(); + } + + try { + return $this->doHave($id); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached: '.$e->getMessage(), ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + + return false; + } + } + + public function clear(string $prefix = ''): bool + { + $this->deferred = []; + if ($cleared = $this->versioningIsEnabled) { + if ('' === $namespaceVersionToClear = $this->namespaceVersion) { + foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) { + $namespaceVersionToClear = $v; + } + } + $namespaceToClear = $this->namespace.$namespaceVersionToClear; + $namespaceVersion = self::formatNamespaceVersion(mt_rand()); + try { + $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0); + } catch (\Exception $e) { + } + if (true !== $e && [] !== $e) { + $cleared = false; + $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } else { + $this->namespaceVersion = $namespaceVersion; + $this->ids = []; + } + } else { + $namespaceToClear = $this->namespace.$prefix; + } + + try { + return $this->doClear($namespaceToClear) || $cleared; + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + + return false; + } + } + + public function deleteItem(mixed $key): bool + { + return $this->deleteItems([$key]); + } + + public function deleteItems(array $keys): bool + { + $ids = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + try { + if ($this->doDelete($ids)) { + return true; + } + } catch (\Exception) { + } + + $ok = true; + + // When bulk-delete failed, retry each item individually + foreach ($ids as $key => $id) { + try { + $e = null; + if ($this->doDelete([$id])) { + continue; + } + } catch (\Exception $e) { + } + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + $ok = false; + } + + return $ok; + } + + public function getItem(mixed $key): CacheItem + { + $id = $this->getId($key); + + if (isset($this->deferred[$key])) { + $this->commit(); + } + + $isHit = false; + $value = null; + + try { + foreach ($this->doFetch([$id]) as $value) { + $isHit = true; + } + + return (self::$createCacheItem)($key, $value, $isHit); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + + return (self::$createCacheItem)($key, null, false); + } + + public function getItems(array $keys = []): iterable + { + $ids = []; + $commit = false; + + foreach ($keys as $key) { + $ids[] = $this->getId($key); + $commit = $commit || isset($this->deferred[$key]); + } + + if ($commit) { + $this->commit(); + } + + try { + $items = $this->doFetch($ids); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + $items = []; + } + $ids = array_combine($ids, $keys); + + return $this->generateItems($items, $ids); + } + + public function save(CacheItemInterface $item): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return $this->commit(); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return true; + } + + /** + * Enables/disables versioning of items. + * + * When versioning is enabled, clearing the cache is atomic and doesn't require listing existing keys to proceed, + * but old keys may need garbage collection and extra round-trips to the back-end are required. + * + * Calling this method also clears the memoized namespace version and thus forces a resynchronization of it. + * + * @return bool the previous state of versioning + */ + public function enableVersioning(bool $enable = true): bool + { + $wasEnabled = $this->versioningIsEnabled; + $this->versioningIsEnabled = $enable; + $this->namespaceVersion = ''; + $this->ids = []; + + return $wasEnabled; + } + + public function reset(): void + { + if ($this->deferred) { + $this->commit(); + } + $this->namespaceVersion = ''; + $this->ids = []; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + /** + * @return void + */ + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + if ($this->deferred) { + $this->commit(); + } + } + + private function generateItems(iterable $items, array &$keys): \Generator + { + $f = self::$createCacheItem; + + try { + foreach ($items as $id => $value) { + if (!isset($keys[$id])) { + throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); + } + $key = $keys[$id]; + unset($keys[$id]); + yield $key => $f($key, $value, true); + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + + foreach ($keys as $key) { + yield $key => $f($key, null, false); + } + } + + /** + * @internal + */ + protected function getId(mixed $key): string + { + if ($this->versioningIsEnabled && '' === $this->namespaceVersion) { + $this->ids = []; + $this->namespaceVersion = '1'.static::NS_SEPARATOR; + try { + foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) { + $this->namespaceVersion = $v; + } + $e = true; + if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) { + $this->namespaceVersion = self::formatNamespaceVersion(time()); + $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0); + } + } catch (\Exception $e) { + } + if (true !== $e && [] !== $e) { + $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); + } + } + + if (\is_string($key) && isset($this->ids[$key])) { + return $this->namespace.$this->namespaceVersion.$this->ids[$key]; + } + \assert('' !== CacheItem::validateKey($key)); + $this->ids[$key] = $key; + + if (\count($this->ids) > 1000) { + $this->ids = \array_slice($this->ids, 500, null, true); // stop memory leak if there are many keys + } + + if (null === $this->maxIdLength) { + return $this->namespace.$this->namespaceVersion.$key; + } + if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) { + // Use xxh128 to favor speed over security, which is not an issue here + $this->ids[$key] = $id = substr_replace(base64_encode(hash('xxh128', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 2)); + $id = $this->namespace.$this->namespaceVersion.$id; + } + + return $id; + } + + /** + * @internal + */ + public static function handleUnserializeCallback(string $class): never + { + throw new \DomainException('Class not found: '.$class); + } + + private static function formatNamespaceVersion(int $value): string + { + return strtr(substr_replace(base64_encode(pack('V', $value)), static::NS_SEPARATOR, 5), '/', '_'); + } +} diff --git a/vendor/symfony/cache/Traits/ContractsTrait.php b/vendor/symfony/cache/Traits/ContractsTrait.php new file mode 100644 index 000000000..8d830f0ab --- /dev/null +++ b/vendor/symfony/cache/Traits/ContractsTrait.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\LockRegistry; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\CacheTrait; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait ContractsTrait +{ + use CacheTrait { + doGet as private contractsGet; + } + + private \Closure $callbackWrapper; + private array $computing = []; + + /** + * Wraps the callback passed to ->get() in a callable. + * + * @return callable the previous callback wrapper + */ + public function setCallbackWrapper(?callable $callbackWrapper): callable + { + if (!isset($this->callbackWrapper)) { + $this->callbackWrapper = LockRegistry::compute(...); + + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) { + $this->setCallbackWrapper(null); + } + } + + if (null !== $callbackWrapper && !$callbackWrapper instanceof \Closure) { + $callbackWrapper = $callbackWrapper(...); + } + + $previousWrapper = $this->callbackWrapper; + $this->callbackWrapper = $callbackWrapper ?? static fn (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) => $callback($item, $save); + + return $previousWrapper; + } + + private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null): mixed + { + if (0 > $beta ??= 1.0) { + throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)); + } + + static $setMetadata; + + $setMetadata ??= \Closure::bind( + static function (CacheItem $item, float $startTime, ?array &$metadata) { + if ($item->expiry > $endTime = microtime(true)) { + $item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry; + $item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime)); + } else { + unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME], $metadata[CacheItem::METADATA_TAGS]); + } + }, + null, + CacheItem::class + ); + + $this->callbackWrapper ??= LockRegistry::compute(...); + + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { + // don't wrap nor save recursive calls + if (isset($this->computing[$key])) { + $value = $callback($item, $save); + $save = false; + + return $value; + } + + $this->computing[$key] = $key; + $startTime = microtime(true); + + if (!isset($this->callbackWrapper)) { + $this->setCallbackWrapper($this->setCallbackWrapper(null)); + } + + try { + $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $setMetadata($item, $startTime, $metadata); + }, $this->logger ?? null); + $setMetadata($item, $startTime, $metadata); + + return $value; + } finally { + unset($this->computing[$key]); + } + }, $beta, $metadata, $this->logger ?? null); + } +} diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php new file mode 100644 index 000000000..3b976b66f --- /dev/null +++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php @@ -0,0 +1,197 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\Cache\Exception\InvalidArgumentException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait FilesystemCommonTrait +{ + private string $directory; + private string $tmpSuffix; + + private function init(string $namespace, ?string $directory): void + { + if (!isset($directory[0])) { + $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache'; + } else { + $directory = realpath($directory) ?: $directory; + } + if (isset($namespace[0])) { + if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { + throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); + } + $directory .= \DIRECTORY_SEPARATOR.$namespace; + } else { + $directory .= \DIRECTORY_SEPARATOR.'@'; + } + if (!is_dir($directory)) { + @mkdir($directory, 0777, true); + } + $directory .= \DIRECTORY_SEPARATOR; + // On Windows the whole path is limited to 258 chars + if ('\\' === \DIRECTORY_SEPARATOR && \strlen($directory) > 234) { + throw new InvalidArgumentException(sprintf('Cache directory too long (%s).', $directory)); + } + + $this->directory = $directory; + } + + protected function doClear(string $namespace): bool + { + $ok = true; + + foreach ($this->scanHashDir($this->directory) as $file) { + if ('' !== $namespace && !str_starts_with($this->getFileKey($file), $namespace)) { + continue; + } + + $ok = ($this->doUnlink($file) || !file_exists($file)) && $ok; + } + + return $ok; + } + + protected function doDelete(array $ids): bool + { + $ok = true; + + foreach ($ids as $id) { + $file = $this->getFile($id); + $ok = (!is_file($file) || $this->doUnlink($file) || !file_exists($file)) && $ok; + } + + return $ok; + } + + /** + * @return bool + */ + protected function doUnlink(string $file) + { + return @unlink($file); + } + + private function write(string $file, string $data, ?int $expiresAt = null): bool + { + $unlink = false; + set_error_handler(static fn ($type, $message, $file, $line) => throw new \ErrorException($message, 0, $type, $file, $line)); + try { + $tmp = $this->directory.$this->tmpSuffix ??= str_replace('/', '-', base64_encode(random_bytes(6))); + try { + $h = fopen($tmp, 'x'); + } catch (\ErrorException $e) { + if (!str_contains($e->getMessage(), 'File exists')) { + throw $e; + } + + $tmp = $this->directory.$this->tmpSuffix = str_replace('/', '-', base64_encode(random_bytes(6))); + $h = fopen($tmp, 'x'); + } + fwrite($h, $data); + fclose($h); + $unlink = true; + + if (null !== $expiresAt) { + touch($tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds + } + + if ('\\' === \DIRECTORY_SEPARATOR) { + $success = copy($tmp, $file); + $unlink = true; + } else { + $success = rename($tmp, $file); + $unlink = !$success; + } + + return $success; + } finally { + restore_error_handler(); + + if ($unlink) { + @unlink($tmp); + } + } + } + + private function getFile(string $id, bool $mkdir = false, ?string $directory = null): string + { + // Use xxh128 to favor speed over security, which is not an issue here + $hash = str_replace('/', '-', base64_encode(hash('xxh128', static::class.$id, true))); + $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); + + if ($mkdir && !is_dir($dir)) { + @mkdir($dir, 0777, true); + } + + return $dir.substr($hash, 2, 20); + } + + private function getFileKey(string $file): string + { + return ''; + } + + private function scanHashDir(string $directory): \Generator + { + if (!is_dir($directory)) { + return; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + if (!is_dir($directory.$chars[$i])) { + continue; + } + + for ($j = 0; $j < 38; ++$j) { + if (!is_dir($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + + foreach (@scandir($dir, \SCANDIR_SORT_NONE) ?: [] as $file) { + if ('.' !== $file && '..' !== $file) { + yield $dir.\DIRECTORY_SEPARATOR.$file; + } + } + } + } + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + /** + * @return void + */ + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + if (method_exists(parent::class, '__destruct')) { + parent::__destruct(); + } + if (isset($this->tmpSuffix) && is_file($this->directory.$this->tmpSuffix)) { + unlink($this->directory.$this->tmpSuffix); + } + } +} diff --git a/vendor/symfony/cache/Traits/FilesystemTrait.php b/vendor/symfony/cache/Traits/FilesystemTrait.php new file mode 100644 index 000000000..47e9b838f --- /dev/null +++ b/vendor/symfony/cache/Traits/FilesystemTrait.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Nicolas Grekas + * @author Rob Frawley 2nd + * + * @internal + */ +trait FilesystemTrait +{ + use FilesystemCommonTrait; + + private MarshallerInterface $marshaller; + + public function prune(): bool + { + $time = time(); + $pruned = true; + + foreach ($this->scanHashDir($this->directory) as $file) { + if (!$h = @fopen($file, 'r')) { + continue; + } + + if (($expiresAt = (int) fgets($h)) && $time >= $expiresAt) { + fclose($h); + $pruned = (@unlink($file) || !file_exists($file)) && $pruned; + } else { + fclose($h); + } + } + + return $pruned; + } + + protected function doFetch(array $ids): iterable + { + $values = []; + $now = time(); + + foreach ($ids as $id) { + $file = $this->getFile($id); + if (!is_file($file) || !$h = @fopen($file, 'r')) { + continue; + } + if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) { + fclose($h); + @unlink($file); + } else { + $i = rawurldecode(rtrim(fgets($h))); + $value = stream_get_contents($h); + fclose($h); + if ($i === $id) { + $values[$id] = $this->marshaller->unmarshall($value); + } + } + } + + return $values; + } + + protected function doHave(string $id): bool + { + $file = $this->getFile($id); + + return is_file($file) && (@filemtime($file) > time() || $this->doFetch([$id])); + } + + protected function doSave(array $values, int $lifetime): array|bool + { + $expiresAt = $lifetime ? (time() + $lifetime) : 0; + $values = $this->marshaller->marshall($values, $failed); + + foreach ($values as $id => $value) { + if (!$this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".$value, $expiresAt)) { + $failed[] = $id; + } + } + + if ($failed && !is_writable($this->directory)) { + throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory)); + } + + return $failed; + } + + private function getFileKey(string $file): string + { + if (!$h = @fopen($file, 'r')) { + return ''; + } + + fgets($h); // expiry + $encodedKey = fgets($h); + fclose($h); + + return rawurldecode(rtrim($encodedKey)); + } +} diff --git a/vendor/symfony/cache/Traits/ProxyTrait.php b/vendor/symfony/cache/Traits/ProxyTrait.php new file mode 100644 index 000000000..ba7c11fbe --- /dev/null +++ b/vendor/symfony/cache/Traits/ProxyTrait.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait ProxyTrait +{ + private object $pool; + + public function prune(): bool + { + return $this->pool instanceof PruneableInterface && $this->pool->prune(); + } + + public function reset(): void + { + if ($this->pool instanceof ResetInterface) { + $this->pool->reset(); + } + } +} diff --git a/vendor/symfony/cache/Traits/Redis5Proxy.php b/vendor/symfony/cache/Traits/Redis5Proxy.php new file mode 100644 index 000000000..0b2794ee1 --- /dev/null +++ b/vendor/symfony/cache/Traits/Redis5Proxy.php @@ -0,0 +1,1228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\VarExporter\LazyObjectInterface; +use Symfony\Component\VarExporter\LazyProxyTrait; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + +/** + * @internal + */ +class Redis5Proxy extends \Redis implements ResetInterface, LazyObjectInterface +{ + use LazyProxyTrait { + resetLazyObject as reset; + } + + private const LAZY_OBJECT_PROPERTY_SCOPES = []; + + public function __construct() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->__construct(...\func_get_args()); + } + + public function _prefix($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_prefix(...\func_get_args()); + } + + public function _serialize($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_serialize(...\func_get_args()); + } + + public function _unserialize($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unserialize(...\func_get_args()); + } + + public function _pack($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_pack(...\func_get_args()); + } + + public function _unpack($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unpack(...\func_get_args()); + } + + public function _compress($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_compress(...\func_get_args()); + } + + public function _uncompress($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_uncompress(...\func_get_args()); + } + + public function acl($subcmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->acl(...\func_get_args()); + } + + public function append($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->append(...\func_get_args()); + } + + public function auth(#[\SensitiveParameter] $auth) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->auth(...\func_get_args()); + } + + public function bgSave() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgSave(...\func_get_args()); + } + + public function bgrewriteaof() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgrewriteaof(...\func_get_args()); + } + + public function bitcount($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitcount(...\func_get_args()); + } + + public function bitop($operation, $ret_key, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitop(...\func_get_args()); + } + + public function bitpos($key, $bit, $start = null, $end = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitpos(...\func_get_args()); + } + + public function blPop($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blPop(...\func_get_args()); + } + + public function brPop($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brPop(...\func_get_args()); + } + + public function brpoplpush($src, $dst, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpoplpush(...\func_get_args()); + } + + public function bzPopMax($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzPopMax(...\func_get_args()); + } + + public function bzPopMin($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzPopMin(...\func_get_args()); + } + + public function clearLastError() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearLastError(...\func_get_args()); + } + + public function client($cmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->client(...\func_get_args()); + } + + public function close() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->close(...\func_get_args()); + } + + public function command(...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->command(...\func_get_args()); + } + + public function config($cmd, $key, $value = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->config(...\func_get_args()); + } + + public function connect($host, $port = null, $timeout = null, $retry_interval = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->connect(...\func_get_args()); + } + + public function dbSize() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbSize(...\func_get_args()); + } + + public function debug($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->debug(...\func_get_args()); + } + + public function decr($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decr(...\func_get_args()); + } + + public function decrBy($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrBy(...\func_get_args()); + } + + public function del($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->del(...\func_get_args()); + } + + public function discard() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->discard(...\func_get_args()); + } + + public function dump($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function echo($msg) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->echo(...\func_get_args()); + } + + public function eval($script, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval(...\func_get_args()); + } + + public function evalsha($script_sha, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha(...\func_get_args()); + } + + public function exec() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exec(...\func_get_args()); + } + + public function exists($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exists(...\func_get_args()); + } + + public function expire($key, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expire(...\func_get_args()); + } + + public function expireAt($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expireAt(...\func_get_args()); + } + + public function flushAll($async = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushAll(...\func_get_args()); + } + + public function flushDB($async = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushDB(...\func_get_args()); + } + + public function geoadd($key, $lng, $lat, $member, ...$other_triples) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function geohash($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); + } + + public function geopos($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geopos(...\func_get_args()); + } + + public function georadius($key, $lng, $lan, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius(...\func_get_args()); + } + + public function georadius_ro($key, $lng, $lan, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); + } + + public function georadiusbymember($key, $member, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember(...\func_get_args()); + } + + public function georadiusbymember_ro($key, $member, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember_ro(...\func_get_args()); + } + + public function get($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->get(...\func_get_args()); + } + + public function getAuth() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getAuth(...\func_get_args()); + } + + public function getBit($key, $offset) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getBit(...\func_get_args()); + } + + public function getDBNum() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getDBNum(...\func_get_args()); + } + + public function getHost() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getHost(...\func_get_args()); + } + + public function getLastError() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getLastError(...\func_get_args()); + } + + public function getMode() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getMode(...\func_get_args()); + } + + public function getOption($option) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getOption(...\func_get_args()); + } + + public function getPersistentID() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPersistentID(...\func_get_args()); + } + + public function getPort() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPort(...\func_get_args()); + } + + public function getRange($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getRange(...\func_get_args()); + } + + public function getReadTimeout() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getReadTimeout(...\func_get_args()); + } + + public function getSet($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getSet(...\func_get_args()); + } + + public function getTimeout() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getTimeout(...\func_get_args()); + } + + public function hDel($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hDel(...\func_get_args()); + } + + public function hExists($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hExists(...\func_get_args()); + } + + public function hGet($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hGet(...\func_get_args()); + } + + public function hGetAll($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hGetAll(...\func_get_args()); + } + + public function hIncrBy($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hIncrBy(...\func_get_args()); + } + + public function hIncrByFloat($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hIncrByFloat(...\func_get_args()); + } + + public function hKeys($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hKeys(...\func_get_args()); + } + + public function hLen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hLen(...\func_get_args()); + } + + public function hMget($key, $keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hMget(...\func_get_args()); + } + + public function hMset($key, $pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hMset(...\func_get_args()); + } + + public function hSet($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hSet(...\func_get_args()); + } + + public function hSetNx($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hSetNx(...\func_get_args()); + } + + public function hStrLen($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hStrLen(...\func_get_args()); + } + + public function hVals($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hVals(...\func_get_args()); + } + + public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function incr($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incr(...\func_get_args()); + } + + public function incrBy($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrBy(...\func_get_args()); + } + + public function incrByFloat($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrByFloat(...\func_get_args()); + } + + public function info($option = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->info(...\func_get_args()); + } + + public function isConnected() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->isConnected(...\func_get_args()); + } + + public function keys($pattern) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->keys(...\func_get_args()); + } + + public function lInsert($key, $position, $pivot, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lInsert(...\func_get_args()); + } + + public function lLen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lLen(...\func_get_args()); + } + + public function lPop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPop(...\func_get_args()); + } + + public function lPush($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPush(...\func_get_args()); + } + + public function lPushx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPushx(...\func_get_args()); + } + + public function lSet($key, $index, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lSet(...\func_get_args()); + } + + public function lastSave() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lastSave(...\func_get_args()); + } + + public function lindex($key, $index) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lindex(...\func_get_args()); + } + + public function lrange($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); + } + + public function lrem($key, $value, $count) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrem(...\func_get_args()); + } + + public function ltrim($key, $start, $stop) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ltrim(...\func_get_args()); + } + + public function mget($keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function migrate($host, $port, $key, $db, $timeout, $copy = null, $replace = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->migrate(...\func_get_args()); + } + + public function move($key, $dbindex) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->move(...\func_get_args()); + } + + public function mset($pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mset(...\func_get_args()); + } + + public function msetnx($pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetnx(...\func_get_args()); + } + + public function multi($mode = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->multi(...\func_get_args()); + } + + public function object($field, $key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->object(...\func_get_args()); + } + + public function pconnect($host, $port = null, $timeout = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pconnect(...\func_get_args()); + } + + public function persist($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->persist(...\func_get_args()); + } + + public function pexpire($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpire(...\func_get_args()); + } + + public function pexpireAt($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpireAt(...\func_get_args()); + } + + public function pfadd($key, $elements) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); + } + + public function pfcount($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + + public function pfmerge($dstkey, $keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); + } + + public function ping() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ping(...\func_get_args()); + } + + public function pipeline() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pipeline(...\func_get_args()); + } + + public function psetex($key, $expire, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psetex(...\func_get_args()); + } + + public function psubscribe($patterns, $callback) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psubscribe(...\func_get_args()); + } + + public function pttl($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pttl(...\func_get_args()); + } + + public function publish($channel, $message) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + + public function pubsub($cmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + + public function punsubscribe($pattern, ...$other_patterns) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->punsubscribe(...\func_get_args()); + } + + public function rPop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPop(...\func_get_args()); + } + + public function rPush($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPush(...\func_get_args()); + } + + public function rPushx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPushx(...\func_get_args()); + } + + public function randomKey() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->randomKey(...\func_get_args()); + } + + public function rawcommand($cmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawcommand(...\func_get_args()); + } + + public function rename($key, $newkey) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rename(...\func_get_args()); + } + + public function renameNx($key, $newkey) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renameNx(...\func_get_args()); + } + + public function restore($ttl, $key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args()); + } + + public function role() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->role(...\func_get_args()); + } + + public function rpoplpush($src, $dst) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpoplpush(...\func_get_args()); + } + + public function sAdd($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sAdd(...\func_get_args()); + } + + public function sAddArray($key, $options) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sAddArray(...\func_get_args()); + } + + public function sDiff($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sDiff(...\func_get_args()); + } + + public function sDiffStore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sDiffStore(...\func_get_args()); + } + + public function sInter($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sInter(...\func_get_args()); + } + + public function sInterStore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sInterStore(...\func_get_args()); + } + + public function sMembers($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMembers(...\func_get_args()); + } + + public function sMisMember($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMisMember(...\func_get_args()); + } + + public function sMove($src, $dst, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMove(...\func_get_args()); + } + + public function sPop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sPop(...\func_get_args()); + } + + public function sRandMember($key, $count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sRandMember(...\func_get_args()); + } + + public function sUnion($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sUnion(...\func_get_args()); + } + + public function sUnionStore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sUnionStore(...\func_get_args()); + } + + public function save() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); + } + + public function scan(&$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, ...\array_slice(\func_get_args(), 1)); + } + + public function scard($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scard(...\func_get_args()); + } + + public function script($cmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->script(...\func_get_args()); + } + + public function select($dbindex) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); + } + + public function set($key, $value, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->set(...\func_get_args()); + } + + public function setBit($key, $offset, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setBit(...\func_get_args()); + } + + public function setOption($option, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setOption(...\func_get_args()); + } + + public function setRange($key, $offset, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setRange(...\func_get_args()); + } + + public function setex($key, $expire, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setex(...\func_get_args()); + } + + public function setnx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setnx(...\func_get_args()); + } + + public function sismember($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sismember(...\func_get_args()); + } + + public function slaveof($host = null, $port = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slaveof(...\func_get_args()); + } + + public function slowlog($arg, $option = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slowlog(...\func_get_args()); + } + + public function sort($key, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort(...\func_get_args()); + } + + public function sortAsc($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortAsc(...\func_get_args()); + } + + public function sortAscAlpha($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortAscAlpha(...\func_get_args()); + } + + public function sortDesc($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortDesc(...\func_get_args()); + } + + public function sortDescAlpha($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortDescAlpha(...\func_get_args()); + } + + public function srem($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srem(...\func_get_args()); + } + + public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function strlen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->strlen(...\func_get_args()); + } + + public function subscribe($channels, $callback) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->subscribe(...\func_get_args()); + } + + public function swapdb($srcdb, $dstdb) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->swapdb(...\func_get_args()); + } + + public function time() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->time(...\func_get_args()); + } + + public function ttl($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ttl(...\func_get_args()); + } + + public function type($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); + } + + public function unlink($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unlink(...\func_get_args()); + } + + public function unsubscribe($channel, ...$other_channels) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unsubscribe(...\func_get_args()); + } + + public function unwatch() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); + } + + public function wait($numslaves, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->wait(...\func_get_args()); + } + + public function watch($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + + public function xack($str_key, $str_group, $arr_ids) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); + } + + public function xadd($str_key, $str_id, $arr_fields, $i_maxlen = null, $boo_approximate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function xclaim($str_key, $str_group, $str_consumer, $i_min_idle, $arr_ids, $arr_opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); + } + + public function xdel($str_key, $arr_ids) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdel(...\func_get_args()); + } + + public function xgroup($str_operation, $str_key = null, $str_arg1 = null, $str_arg2 = null, $str_arg3 = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xgroup(...\func_get_args()); + } + + public function xinfo($str_cmd, $str_key = null, $str_group = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xinfo(...\func_get_args()); + } + + public function xlen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xlen(...\func_get_args()); + } + + public function xpending($str_key, $str_group, $str_start = null, $str_end = null, $i_count = null, $str_consumer = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xpending(...\func_get_args()); + } + + public function xrange($str_key, $str_start, $str_end, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrange(...\func_get_args()); + } + + public function xread($arr_streams, $i_count = null, $i_block = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xread(...\func_get_args()); + } + + public function xreadgroup($str_group, $str_consumer, $arr_streams, $i_count = null, $i_block = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xreadgroup(...\func_get_args()); + } + + public function xrevrange($str_key, $str_start, $str_end, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrevrange(...\func_get_args()); + } + + public function xtrim($str_key, $i_maxlen, $boo_approximate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xtrim(...\func_get_args()); + } + + public function zAdd($key, $score, $value, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zAdd(...\func_get_args()); + } + + public function zCard($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zCard(...\func_get_args()); + } + + public function zCount($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zCount(...\func_get_args()); + } + + public function zIncrBy($key, $value, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zIncrBy(...\func_get_args()); + } + + public function zLexCount($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zLexCount(...\func_get_args()); + } + + public function zPopMax($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zPopMax(...\func_get_args()); + } + + public function zPopMin($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zPopMin(...\func_get_args()); + } + + public function zRange($key, $start, $end, $scores = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRange(...\func_get_args()); + } + + public function zRangeByLex($key, $min, $max, $offset = null, $limit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRangeByLex(...\func_get_args()); + } + + public function zRangeByScore($key, $start, $end, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRangeByScore(...\func_get_args()); + } + + public function zRank($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRank(...\func_get_args()); + } + + public function zRem($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRem(...\func_get_args()); + } + + public function zRemRangeByLex($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByLex(...\func_get_args()); + } + + public function zRemRangeByRank($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByRank(...\func_get_args()); + } + + public function zRemRangeByScore($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByScore(...\func_get_args()); + } + + public function zRevRange($key, $start, $end, $scores = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRange(...\func_get_args()); + } + + public function zRevRangeByLex($key, $min, $max, $offset = null, $limit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRangeByLex(...\func_get_args()); + } + + public function zRevRangeByScore($key, $start, $end, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRangeByScore(...\func_get_args()); + } + + public function zRevRank($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRank(...\func_get_args()); + } + + public function zScore($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zScore(...\func_get_args()); + } + + public function zinterstore($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinterstore(...\func_get_args()); + } + + public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function zunionstore($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunionstore(...\func_get_args()); + } + + public function delete($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delete(...\func_get_args()); + } + + public function evaluate($script, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evaluate(...\func_get_args()); + } + + public function evaluateSha($script_sha, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evaluateSha(...\func_get_args()); + } + + public function getKeys($pattern) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getKeys(...\func_get_args()); + } + + public function getMultiple($keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getMultiple(...\func_get_args()); + } + + public function lGet($key, $index) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lGet(...\func_get_args()); + } + + public function lGetRange($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lGetRange(...\func_get_args()); + } + + public function lRemove($key, $value, $count) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lRemove(...\func_get_args()); + } + + public function lSize($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lSize(...\func_get_args()); + } + + public function listTrim($key, $start, $stop) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->listTrim(...\func_get_args()); + } + + public function open($host, $port = null, $timeout = null, $retry_interval = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->open(...\func_get_args()); + } + + public function popen($host, $port = null, $timeout = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->popen(...\func_get_args()); + } + + public function renameKey($key, $newkey) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renameKey(...\func_get_args()); + } + + public function sContains($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sContains(...\func_get_args()); + } + + public function sGetMembers($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sGetMembers(...\func_get_args()); + } + + public function sRemove($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sRemove(...\func_get_args()); + } + + public function sSize($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sSize(...\func_get_args()); + } + + public function sendEcho($msg) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sendEcho(...\func_get_args()); + } + + public function setTimeout($key, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setTimeout(...\func_get_args()); + } + + public function substr($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->substr(...\func_get_args()); + } + + public function zDelete($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zDelete(...\func_get_args()); + } + + public function zDeleteRangeByRank($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zDeleteRangeByRank(...\func_get_args()); + } + + public function zDeleteRangeByScore($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zDeleteRangeByScore(...\func_get_args()); + } + + public function zInter($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zInter(...\func_get_args()); + } + + public function zRemove($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemove(...\func_get_args()); + } + + public function zRemoveRangeByScore($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemoveRangeByScore(...\func_get_args()); + } + + public function zReverseRange($key, $start, $end, $scores = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zReverseRange(...\func_get_args()); + } + + public function zSize($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zSize(...\func_get_args()); + } + + public function zUnion($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zUnion(...\func_get_args()); + } +} diff --git a/vendor/symfony/cache/Traits/Redis6Proxy.php b/vendor/symfony/cache/Traits/Redis6Proxy.php new file mode 100644 index 000000000..c841d4269 --- /dev/null +++ b/vendor/symfony/cache/Traits/Redis6Proxy.php @@ -0,0 +1,1269 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\VarExporter\LazyObjectInterface; +use Symfony\Component\VarExporter\LazyProxyTrait; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + +/** + * @internal + */ +class Redis6Proxy extends \Redis implements ResetInterface, LazyObjectInterface +{ + use Redis6ProxyTrait; + use LazyProxyTrait { + resetLazyObject as reset; + } + + private const LAZY_OBJECT_PROPERTY_SCOPES = []; + + public function __construct($options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->__construct(...\func_get_args()); + } + + public function _compress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_compress(...\func_get_args()); + } + + public function _uncompress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_uncompress(...\func_get_args()); + } + + public function _prefix($key): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_prefix(...\func_get_args()); + } + + public function _serialize($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_serialize(...\func_get_args()); + } + + public function _unserialize($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unserialize(...\func_get_args()); + } + + public function _pack($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_pack(...\func_get_args()); + } + + public function _unpack($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unpack(...\func_get_args()); + } + + public function acl($subcmd, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->acl(...\func_get_args()); + } + + public function append($key, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->append(...\func_get_args()); + } + + public function auth(#[\SensitiveParameter] $credentials): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->auth(...\func_get_args()); + } + + public function bgSave(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgSave(...\func_get_args()); + } + + public function bgrewriteaof(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgrewriteaof(...\func_get_args()); + } + + public function bitcount($key, $start = 0, $end = -1, $bybit = false): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitcount(...\func_get_args()); + } + + public function bitop($operation, $deskey, $srckey, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitop(...\func_get_args()); + } + + public function bitpos($key, $bit, $start = 0, $end = -1, $bybit = false): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitpos(...\func_get_args()); + } + + public function blPop($key_or_keys, $timeout_or_key, ...$extra_args): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blPop(...\func_get_args()); + } + + public function brPop($key_or_keys, $timeout_or_key, ...$extra_args): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brPop(...\func_get_args()); + } + + public function brpoplpush($src, $dst, $timeout): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpoplpush(...\func_get_args()); + } + + public function bzPopMax($key, $timeout_or_key, ...$extra_args): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzPopMax(...\func_get_args()); + } + + public function bzPopMin($key, $timeout_or_key, ...$extra_args): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzPopMin(...\func_get_args()); + } + + public function bzmpop($timeout, $keys, $from, $count = 1): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzmpop(...\func_get_args()); + } + + public function zmpop($keys, $from, $count = 1): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmpop(...\func_get_args()); + } + + public function blmpop($timeout, $keys, $from, $count = 1): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmpop(...\func_get_args()); + } + + public function lmpop($keys, $from, $count = 1): \Redis|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmpop(...\func_get_args()); + } + + public function clearLastError(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearLastError(...\func_get_args()); + } + + public function client($opt, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->client(...\func_get_args()); + } + + public function close(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->close(...\func_get_args()); + } + + public function command($opt = null, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->command(...\func_get_args()); + } + + public function config($operation, $key_or_settings = null, $value = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->config(...\func_get_args()); + } + + public function connect($host, $port = 6379, $timeout = 0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0, $context = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->connect(...\func_get_args()); + } + + public function copy($src, $dst, $options = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + + public function dbSize(): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbSize(...\func_get_args()); + } + + public function debug($key): \Redis|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->debug(...\func_get_args()); + } + + public function decr($key, $by = 1): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decr(...\func_get_args()); + } + + public function decrBy($key, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrBy(...\func_get_args()); + } + + public function del($key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->del(...\func_get_args()); + } + + public function delete($key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delete(...\func_get_args()); + } + + public function discard(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->discard(...\func_get_args()); + } + + public function echo($str): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->echo(...\func_get_args()); + } + + public function eval($script, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval(...\func_get_args()); + } + + public function eval_ro($script_sha, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval_ro(...\func_get_args()); + } + + public function evalsha($sha1, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha(...\func_get_args()); + } + + public function evalsha_ro($sha1, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha_ro(...\func_get_args()); + } + + public function exec(): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exec(...\func_get_args()); + } + + public function exists($key, ...$other_keys): \Redis|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exists(...\func_get_args()); + } + + public function expire($key, $timeout, $mode = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expire(...\func_get_args()); + } + + public function expireAt($key, $timestamp, $mode = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expireAt(...\func_get_args()); + } + + public function failover($to = null, $abort = false, $timeout = 0): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->failover(...\func_get_args()); + } + + public function expiretime($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expiretime(...\func_get_args()); + } + + public function pexpiretime($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpiretime(...\func_get_args()); + } + + public function fcall($fn, $keys = [], $args = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->fcall(...\func_get_args()); + } + + public function fcall_ro($fn, $keys = [], $args = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->fcall_ro(...\func_get_args()); + } + + public function flushAll($sync = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushAll(...\func_get_args()); + } + + public function flushDB($sync = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushDB(...\func_get_args()); + } + + public function function($operation, ...$args): \Redis|array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->function(...\func_get_args()); + } + + public function geoadd($key, $lng, $lat, $member, ...$other_triples_and_options): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null): \Redis|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function geohash($key, $member, ...$other_members): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); + } + + public function geopos($key, $member, ...$other_members): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geopos(...\func_get_args()); + } + + public function georadius($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius(...\func_get_args()); + } + + public function georadius_ro($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); + } + + public function georadiusbymember($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember(...\func_get_args()); + } + + public function georadiusbymember_ro($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember_ro(...\func_get_args()); + } + + public function geosearch($key, $position, $shape, $unit, $options = []): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); + } + + public function geosearchstore($dst, $src, $position, $shape, $unit, $options = []): \Redis|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearchstore(...\func_get_args()); + } + + public function get($key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->get(...\func_get_args()); + } + + public function getAuth(): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getAuth(...\func_get_args()); + } + + public function getBit($key, $idx): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getBit(...\func_get_args()); + } + + public function getEx($key, $options = []): \Redis|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getEx(...\func_get_args()); + } + + public function getDBNum(): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getDBNum(...\func_get_args()); + } + + public function getDel($key): \Redis|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getDel(...\func_get_args()); + } + + public function getHost(): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getHost(...\func_get_args()); + } + + public function getLastError(): ?string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getLastError(...\func_get_args()); + } + + public function getMode(): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getMode(...\func_get_args()); + } + + public function getOption($option): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getOption(...\func_get_args()); + } + + public function getPersistentID(): ?string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPersistentID(...\func_get_args()); + } + + public function getPort(): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPort(...\func_get_args()); + } + + public function getRange($key, $start, $end): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getRange(...\func_get_args()); + } + + public function lcs($key1, $key2, $options = null): \Redis|array|false|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lcs(...\func_get_args()); + } + + public function getReadTimeout(): float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getReadTimeout(...\func_get_args()); + } + + public function getset($key, $value): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getset(...\func_get_args()); + } + + public function getTimeout(): false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getTimeout(...\func_get_args()); + } + + public function getTransferredBytes(): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getTransferredBytes(...\func_get_args()); + } + + public function clearTransferredBytes(): void + { + ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearTransferredBytes(...\func_get_args()); + } + + public function hDel($key, $field, ...$other_fields): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hDel(...\func_get_args()); + } + + public function hExists($key, $field): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hExists(...\func_get_args()); + } + + public function hGet($key, $member): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hGet(...\func_get_args()); + } + + public function hGetAll($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hGetAll(...\func_get_args()); + } + + public function hIncrBy($key, $field, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hIncrBy(...\func_get_args()); + } + + public function hIncrByFloat($key, $field, $value): \Redis|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hIncrByFloat(...\func_get_args()); + } + + public function hKeys($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hKeys(...\func_get_args()); + } + + public function hLen($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hLen(...\func_get_args()); + } + + public function hMget($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hMget(...\func_get_args()); + } + + public function hMset($key, $fieldvals): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hMset(...\func_get_args()); + } + + public function hSetNx($key, $field, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hSetNx(...\func_get_args()); + } + + public function hStrLen($key, $field): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hStrLen(...\func_get_args()); + } + + public function hVals($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hVals(...\func_get_args()); + } + + public function hscan($key, &$iterator, $pattern = null, $count = 0): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function incr($key, $by = 1): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incr(...\func_get_args()); + } + + public function incrBy($key, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrBy(...\func_get_args()); + } + + public function incrByFloat($key, $value): \Redis|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrByFloat(...\func_get_args()); + } + + public function info(...$sections): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->info(...\func_get_args()); + } + + public function isConnected(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->isConnected(...\func_get_args()); + } + + public function keys($pattern) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->keys(...\func_get_args()); + } + + public function lInsert($key, $pos, $pivot, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lInsert(...\func_get_args()); + } + + public function lLen($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lLen(...\func_get_args()); + } + + public function lMove($src, $dst, $wherefrom, $whereto): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lMove(...\func_get_args()); + } + + public function blmove($src, $dst, $wherefrom, $whereto, $timeout): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); + } + + public function lPop($key, $count = 0): \Redis|array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPop(...\func_get_args()); + } + + public function lPos($key, $value, $options = null): \Redis|array|bool|int|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPos(...\func_get_args()); + } + + public function lPush($key, ...$elements): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPush(...\func_get_args()); + } + + public function rPush($key, ...$elements): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPush(...\func_get_args()); + } + + public function lPushx($key, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lPushx(...\func_get_args()); + } + + public function rPushx($key, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPushx(...\func_get_args()); + } + + public function lSet($key, $index, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lSet(...\func_get_args()); + } + + public function lastSave(): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lastSave(...\func_get_args()); + } + + public function lindex($key, $index): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lindex(...\func_get_args()); + } + + public function lrange($key, $start, $end): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); + } + + public function lrem($key, $value, $count = 0): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrem(...\func_get_args()); + } + + public function ltrim($key, $start, $end): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ltrim(...\func_get_args()); + } + + public function migrate($host, $port, $key, $dstdb, $timeout, $copy = false, $replace = false, #[\SensitiveParameter] $credentials = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->migrate(...\func_get_args()); + } + + public function move($key, $index): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->move(...\func_get_args()); + } + + public function mset($key_values): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mset(...\func_get_args()); + } + + public function msetnx($key_values): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetnx(...\func_get_args()); + } + + public function multi($value = \Redis::MULTI): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->multi(...\func_get_args()); + } + + public function object($subcommand, $key): \Redis|false|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->object(...\func_get_args()); + } + + public function open($host, $port = 6379, $timeout = 0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0, $context = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->open(...\func_get_args()); + } + + public function pconnect($host, $port = 6379, $timeout = 0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0, $context = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pconnect(...\func_get_args()); + } + + public function persist($key): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->persist(...\func_get_args()); + } + + public function pexpire($key, $timeout, $mode = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpire(...\func_get_args()); + } + + public function pexpireAt($key, $timestamp, $mode = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpireAt(...\func_get_args()); + } + + public function pfadd($key, $elements): \Redis|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); + } + + public function pfcount($key_or_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + + public function pfmerge($dst, $srckeys): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); + } + + public function ping($message = null): \Redis|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ping(...\func_get_args()); + } + + public function pipeline(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pipeline(...\func_get_args()); + } + + public function popen($host, $port = 6379, $timeout = 0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0, $context = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->popen(...\func_get_args()); + } + + public function psetex($key, $expire, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psetex(...\func_get_args()); + } + + public function psubscribe($patterns, $cb): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psubscribe(...\func_get_args()); + } + + public function pttl($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pttl(...\func_get_args()); + } + + public function publish($channel, $message): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + + public function pubsub($command, $arg = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + + public function punsubscribe($patterns): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->punsubscribe(...\func_get_args()); + } + + public function rPop($key, $count = 0): \Redis|array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rPop(...\func_get_args()); + } + + public function randomKey(): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->randomKey(...\func_get_args()); + } + + public function rawcommand($command, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawcommand(...\func_get_args()); + } + + public function rename($old_name, $new_name): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rename(...\func_get_args()); + } + + public function renameNx($key_src, $key_dst): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renameNx(...\func_get_args()); + } + + public function restore($key, $ttl, $value, $options = null): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args()); + } + + public function role(): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->role(...\func_get_args()); + } + + public function rpoplpush($srckey, $dstkey): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpoplpush(...\func_get_args()); + } + + public function sAdd($key, $value, ...$other_values): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sAdd(...\func_get_args()); + } + + public function sAddArray($key, $values): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sAddArray(...\func_get_args()); + } + + public function sDiff($key, ...$other_keys): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sDiff(...\func_get_args()); + } + + public function sDiffStore($dst, $key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sDiffStore(...\func_get_args()); + } + + public function sInter($key, ...$other_keys): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sInter(...\func_get_args()); + } + + public function sintercard($keys, $limit = -1): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sintercard(...\func_get_args()); + } + + public function sInterStore($key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sInterStore(...\func_get_args()); + } + + public function sMembers($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMembers(...\func_get_args()); + } + + public function sMisMember($key, $member, ...$other_members): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMisMember(...\func_get_args()); + } + + public function sMove($src, $dst, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sMove(...\func_get_args()); + } + + public function sPop($key, $count = 0): \Redis|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sPop(...\func_get_args()); + } + + public function sUnion($key, ...$other_keys): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sUnion(...\func_get_args()); + } + + public function sUnionStore($dst, $key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sUnionStore(...\func_get_args()); + } + + public function save(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); + } + + public function scan(&$iterator, $pattern = null, $count = 0, $type = null): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); + } + + public function scard($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scard(...\func_get_args()); + } + + public function script($command, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->script(...\func_get_args()); + } + + public function select($db): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); + } + + public function set($key, $value, $options = null): \Redis|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->set(...\func_get_args()); + } + + public function setBit($key, $idx, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setBit(...\func_get_args()); + } + + public function setRange($key, $index, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setRange(...\func_get_args()); + } + + public function setOption($option, $value): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setOption(...\func_get_args()); + } + + public function setex($key, $expire, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setex(...\func_get_args()); + } + + public function setnx($key, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setnx(...\func_get_args()); + } + + public function sismember($key, $value): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sismember(...\func_get_args()); + } + + public function slaveof($host = null, $port = 6379): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slaveof(...\func_get_args()); + } + + public function replicaof($host = null, $port = 6379): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->replicaof(...\func_get_args()); + } + + public function touch($key_or_array, ...$more_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->touch(...\func_get_args()); + } + + public function slowlog($operation, $length = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slowlog(...\func_get_args()); + } + + public function sort($key, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort(...\func_get_args()); + } + + public function sort_ro($key, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort_ro(...\func_get_args()); + } + + public function sortAsc($key, $pattern = null, $get = null, $offset = -1, $count = -1, $store = null): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortAsc(...\func_get_args()); + } + + public function sortAscAlpha($key, $pattern = null, $get = null, $offset = -1, $count = -1, $store = null): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortAscAlpha(...\func_get_args()); + } + + public function sortDesc($key, $pattern = null, $get = null, $offset = -1, $count = -1, $store = null): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortDesc(...\func_get_args()); + } + + public function sortDescAlpha($key, $pattern = null, $get = null, $offset = -1, $count = -1, $store = null): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sortDescAlpha(...\func_get_args()); + } + + public function srem($key, $value, ...$other_values): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srem(...\func_get_args()); + } + + public function sscan($key, &$iterator, $pattern = null, $count = 0): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function ssubscribe($channels, $cb): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ssubscribe(...\func_get_args()); + } + + public function strlen($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->strlen(...\func_get_args()); + } + + public function subscribe($channels, $cb): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->subscribe(...\func_get_args()); + } + + public function sunsubscribe($channels): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunsubscribe(...\func_get_args()); + } + + public function swapdb($src, $dst): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->swapdb(...\func_get_args()); + } + + public function time(): \Redis|array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->time(...\func_get_args()); + } + + public function ttl($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ttl(...\func_get_args()); + } + + public function type($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); + } + + public function unlink($key, ...$other_keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unlink(...\func_get_args()); + } + + public function unsubscribe($channels): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unsubscribe(...\func_get_args()); + } + + public function unwatch(): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); + } + + public function watch($key, ...$other_keys): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + + public function wait($numreplicas, $timeout): false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->wait(...\func_get_args()); + } + + public function xack($key, $group, $ids): false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); + } + + public function xadd($key, $id, $values, $maxlen = 0, $approx = false, $nomkstream = false): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function xautoclaim($key, $group, $consumer, $min_idle, $start, $count = -1, $justid = false): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xautoclaim(...\func_get_args()); + } + + public function xclaim($key, $group, $consumer, $min_idle, $ids, $options): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); + } + + public function xdel($key, $ids): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdel(...\func_get_args()); + } + + public function xgroup($operation, $key = null, $group = null, $id_or_consumer = null, $mkstream = false, $entries_read = -2): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xgroup(...\func_get_args()); + } + + public function xinfo($operation, $arg1 = null, $arg2 = null, $count = -1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xinfo(...\func_get_args()); + } + + public function xlen($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xlen(...\func_get_args()); + } + + public function xpending($key, $group, $start = null, $end = null, $count = -1, $consumer = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xpending(...\func_get_args()); + } + + public function xrange($key, $start, $end, $count = -1): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrange(...\func_get_args()); + } + + public function xread($streams, $count = -1, $block = -1): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xread(...\func_get_args()); + } + + public function xreadgroup($group, $consumer, $streams, $count = 1, $block = 1): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xreadgroup(...\func_get_args()); + } + + public function xrevrange($key, $end, $start, $count = -1): \Redis|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrevrange(...\func_get_args()); + } + + public function xtrim($key, $threshold, $approx = false, $minid = false, $limit = -1): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xtrim(...\func_get_args()); + } + + public function zAdd($key, $score_or_options, ...$more_scores_and_mems): \Redis|false|float|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zAdd(...\func_get_args()); + } + + public function zCard($key): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zCard(...\func_get_args()); + } + + public function zCount($key, $start, $end): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zCount(...\func_get_args()); + } + + public function zIncrBy($key, $value, $member): \Redis|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zIncrBy(...\func_get_args()); + } + + public function zLexCount($key, $min, $max): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zLexCount(...\func_get_args()); + } + + public function zMscore($key, $member, ...$other_members): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zMscore(...\func_get_args()); + } + + public function zPopMax($key, $count = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zPopMax(...\func_get_args()); + } + + public function zPopMin($key, $count = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zPopMin(...\func_get_args()); + } + + public function zRange($key, $start, $end, $options = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRange(...\func_get_args()); + } + + public function zRangeByLex($key, $min, $max, $offset = -1, $count = -1): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRangeByLex(...\func_get_args()); + } + + public function zRangeByScore($key, $start, $end, $options = []): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRangeByScore(...\func_get_args()); + } + + public function zrangestore($dstkey, $srckey, $start, $end, $options = null): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangestore(...\func_get_args()); + } + + public function zRandMember($key, $options = null): \Redis|array|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRandMember(...\func_get_args()); + } + + public function zRank($key, $member): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRank(...\func_get_args()); + } + + public function zRem($key, $member, ...$other_members): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRem(...\func_get_args()); + } + + public function zRemRangeByLex($key, $min, $max): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByLex(...\func_get_args()); + } + + public function zRemRangeByRank($key, $start, $end): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByRank(...\func_get_args()); + } + + public function zRemRangeByScore($key, $start, $end): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRemRangeByScore(...\func_get_args()); + } + + public function zRevRange($key, $start, $end, $scores = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRange(...\func_get_args()); + } + + public function zRevRangeByLex($key, $max, $min, $offset = -1, $count = -1): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRangeByLex(...\func_get_args()); + } + + public function zRevRangeByScore($key, $max, $min, $options = []): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRangeByScore(...\func_get_args()); + } + + public function zRevRank($key, $member): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zRevRank(...\func_get_args()); + } + + public function zScore($key, $member): \Redis|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zScore(...\func_get_args()); + } + + public function zdiff($keys, $options = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiff(...\func_get_args()); + } + + public function zdiffstore($dst, $keys): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiffstore(...\func_get_args()); + } + + public function zinter($keys, $weights = null, $options = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinter(...\func_get_args()); + } + + public function zintercard($keys, $limit = -1): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zintercard(...\func_get_args()); + } + + public function zinterstore($dst, $keys, $weights = null, $aggregate = null): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinterstore(...\func_get_args()); + } + + public function zscan($key, &$iterator, $pattern = null, $count = 0): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function zunion($keys, $weights = null, $options = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunion(...\func_get_args()); + } + + public function zunionstore($dst, $keys, $weights = null, $aggregate = null): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunionstore(...\func_get_args()); + } +} diff --git a/vendor/symfony/cache/Traits/Redis6ProxyTrait.php b/vendor/symfony/cache/Traits/Redis6ProxyTrait.php new file mode 100644 index 000000000..34f60cb10 --- /dev/null +++ b/vendor/symfony/cache/Traits/Redis6ProxyTrait.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.1.0-dev', '>=')) { + /** + * @internal + */ + trait Redis6ProxyTrait + { + public function dump($key): \Redis|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function hRandField($key, $options = null): \Redis|array|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hRandField(...\func_get_args()); + } + + public function hSet($key, ...$fields_and_vals): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hSet(...\func_get_args()); + } + + public function mget($keys): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function sRandMember($key, $count = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sRandMember(...\func_get_args()); + } + + public function waitaof($numlocal, $numreplicas, $timeout): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->waitaof(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Redis6ProxyTrait + { + public function dump($key): \Redis|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function hRandField($key, $options = null): \Redis|array|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hRandField(...\func_get_args()); + } + + public function hSet($key, $member, $value): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hSet(...\func_get_args()); + } + + public function mget($keys): \Redis|array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function sRandMember($key, $count = 0): \Redis|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sRandMember(...\func_get_args()); + } + } +} diff --git a/vendor/symfony/cache/Traits/RedisCluster5Proxy.php b/vendor/symfony/cache/Traits/RedisCluster5Proxy.php new file mode 100644 index 000000000..511c53dd7 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisCluster5Proxy.php @@ -0,0 +1,983 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\VarExporter\LazyObjectInterface; +use Symfony\Component\VarExporter\LazyProxyTrait; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + +/** + * @internal + */ +class RedisCluster5Proxy extends \RedisCluster implements ResetInterface, LazyObjectInterface +{ + use LazyProxyTrait { + resetLazyObject as reset; + } + + private const LAZY_OBJECT_PROPERTY_SCOPES = []; + + public function __construct($name, $seeds = null, $timeout = null, $read_timeout = null, $persistent = null, #[\SensitiveParameter] $auth = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->__construct(...\func_get_args()); + } + + public function _masters() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_masters(...\func_get_args()); + } + + public function _prefix($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_prefix(...\func_get_args()); + } + + public function _redir() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_redir(...\func_get_args()); + } + + public function _serialize($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_serialize(...\func_get_args()); + } + + public function _unserialize($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unserialize(...\func_get_args()); + } + + public function _compress($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_compress(...\func_get_args()); + } + + public function _uncompress($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_uncompress(...\func_get_args()); + } + + public function _pack($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_pack(...\func_get_args()); + } + + public function _unpack($value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unpack(...\func_get_args()); + } + + public function acl($key_or_address, $subcmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->acl(...\func_get_args()); + } + + public function append($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->append(...\func_get_args()); + } + + public function bgrewriteaof($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgrewriteaof(...\func_get_args()); + } + + public function bgsave($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); + } + + public function bitcount($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitcount(...\func_get_args()); + } + + public function bitop($operation, $ret_key, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitop(...\func_get_args()); + } + + public function bitpos($key, $bit, $start = null, $end = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitpos(...\func_get_args()); + } + + public function blpop($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blpop(...\func_get_args()); + } + + public function brpop($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpop(...\func_get_args()); + } + + public function brpoplpush($src, $dst, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpoplpush(...\func_get_args()); + } + + public function clearlasterror() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearlasterror(...\func_get_args()); + } + + public function bzpopmax($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmax(...\func_get_args()); + } + + public function bzpopmin($key, $timeout_or_key, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmin(...\func_get_args()); + } + + public function client($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->client(...\func_get_args()); + } + + public function close() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->close(...\func_get_args()); + } + + public function cluster($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cluster(...\func_get_args()); + } + + public function command(...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->command(...\func_get_args()); + } + + public function config($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->config(...\func_get_args()); + } + + public function dbsize($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbsize(...\func_get_args()); + } + + public function decr($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decr(...\func_get_args()); + } + + public function decrby($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrby(...\func_get_args()); + } + + public function del($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->del(...\func_get_args()); + } + + public function discard() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->discard(...\func_get_args()); + } + + public function dump($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function echo($msg) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->echo(...\func_get_args()); + } + + public function eval($script, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval(...\func_get_args()); + } + + public function evalsha($script_sha, $args = null, $num_keys = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha(...\func_get_args()); + } + + public function exec() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exec(...\func_get_args()); + } + + public function exists($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exists(...\func_get_args()); + } + + public function expire($key, $timeout) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expire(...\func_get_args()); + } + + public function expireat($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expireat(...\func_get_args()); + } + + public function flushall($key_or_address, $async = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushall(...\func_get_args()); + } + + public function flushdb($key_or_address, $async = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushdb(...\func_get_args()); + } + + public function geoadd($key, $lng, $lat, $member, ...$other_triples) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function geohash($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); + } + + public function geopos($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geopos(...\func_get_args()); + } + + public function georadius($key, $lng, $lan, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius(...\func_get_args()); + } + + public function georadius_ro($key, $lng, $lan, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); + } + + public function georadiusbymember($key, $member, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember(...\func_get_args()); + } + + public function georadiusbymember_ro($key, $member, $radius, $unit, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember_ro(...\func_get_args()); + } + + public function get($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->get(...\func_get_args()); + } + + public function getbit($key, $offset) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getbit(...\func_get_args()); + } + + public function getlasterror() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getlasterror(...\func_get_args()); + } + + public function getmode() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getmode(...\func_get_args()); + } + + public function getoption($option) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getoption(...\func_get_args()); + } + + public function getrange($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); + } + + public function getset($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getset(...\func_get_args()); + } + + public function hdel($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hdel(...\func_get_args()); + } + + public function hexists($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexists(...\func_get_args()); + } + + public function hget($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hget(...\func_get_args()); + } + + public function hgetall($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetall(...\func_get_args()); + } + + public function hincrby($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrby(...\func_get_args()); + } + + public function hincrbyfloat($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrbyfloat(...\func_get_args()); + } + + public function hkeys($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hkeys(...\func_get_args()); + } + + public function hlen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hlen(...\func_get_args()); + } + + public function hmget($key, $keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmget(...\func_get_args()); + } + + public function hmset($key, $pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmset(...\func_get_args()); + } + + public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function hset($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); + } + + public function hsetnx($key, $member, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetnx(...\func_get_args()); + } + + public function hstrlen($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hstrlen(...\func_get_args()); + } + + public function hvals($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hvals(...\func_get_args()); + } + + public function incr($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incr(...\func_get_args()); + } + + public function incrby($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrby(...\func_get_args()); + } + + public function incrbyfloat($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrbyfloat(...\func_get_args()); + } + + public function info($key_or_address, $option = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->info(...\func_get_args()); + } + + public function keys($pattern) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->keys(...\func_get_args()); + } + + public function lastsave($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lastsave(...\func_get_args()); + } + + public function lget($key, $index) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lget(...\func_get_args()); + } + + public function lindex($key, $index) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lindex(...\func_get_args()); + } + + public function linsert($key, $position, $pivot, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->linsert(...\func_get_args()); + } + + public function llen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->llen(...\func_get_args()); + } + + public function lpop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpop(...\func_get_args()); + } + + public function lpush($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpush(...\func_get_args()); + } + + public function lpushx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpushx(...\func_get_args()); + } + + public function lrange($key, $start, $end) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); + } + + public function lrem($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrem(...\func_get_args()); + } + + public function lset($key, $index, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lset(...\func_get_args()); + } + + public function ltrim($key, $start, $stop) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ltrim(...\func_get_args()); + } + + public function mget($keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function mset($pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mset(...\func_get_args()); + } + + public function msetnx($pairs) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetnx(...\func_get_args()); + } + + public function multi() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->multi(...\func_get_args()); + } + + public function object($field, $key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->object(...\func_get_args()); + } + + public function persist($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->persist(...\func_get_args()); + } + + public function pexpire($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpire(...\func_get_args()); + } + + public function pexpireat($key, $timestamp) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpireat(...\func_get_args()); + } + + public function pfadd($key, $elements) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); + } + + public function pfcount($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + + public function pfmerge($dstkey, $keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); + } + + public function ping($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ping(...\func_get_args()); + } + + public function psetex($key, $expire, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psetex(...\func_get_args()); + } + + public function psubscribe($patterns, $callback) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psubscribe(...\func_get_args()); + } + + public function pttl($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pttl(...\func_get_args()); + } + + public function publish($channel, $message) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + + public function pubsub($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + + public function punsubscribe($pattern, ...$other_patterns) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->punsubscribe(...\func_get_args()); + } + + public function randomkey($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->randomkey(...\func_get_args()); + } + + public function rawcommand($cmd, ...$args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawcommand(...\func_get_args()); + } + + public function rename($key, $newkey) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rename(...\func_get_args()); + } + + public function renamenx($key, $newkey) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renamenx(...\func_get_args()); + } + + public function restore($ttl, $key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args()); + } + + public function role() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->role(...\func_get_args()); + } + + public function rpop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpop(...\func_get_args()); + } + + public function rpoplpush($src, $dst) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpoplpush(...\func_get_args()); + } + + public function rpush($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpush(...\func_get_args()); + } + + public function rpushx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpushx(...\func_get_args()); + } + + public function sadd($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sadd(...\func_get_args()); + } + + public function saddarray($key, $options) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->saddarray(...\func_get_args()); + } + + public function save($key_or_address) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); + } + + public function scan(&$i_iterator, $str_node, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, ...\array_slice(\func_get_args(), 1)); + } + + public function scard($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scard(...\func_get_args()); + } + + public function script($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->script(...\func_get_args()); + } + + public function sdiff($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiff(...\func_get_args()); + } + + public function sdiffstore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiffstore(...\func_get_args()); + } + + public function set($key, $value, $opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->set(...\func_get_args()); + } + + public function setbit($key, $offset, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setbit(...\func_get_args()); + } + + public function setex($key, $expire, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setex(...\func_get_args()); + } + + public function setnx($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setnx(...\func_get_args()); + } + + public function setoption($option, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setoption(...\func_get_args()); + } + + public function setrange($key, $offset, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setrange(...\func_get_args()); + } + + public function sinter($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinter(...\func_get_args()); + } + + public function sinterstore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinterstore(...\func_get_args()); + } + + public function sismember($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sismember(...\func_get_args()); + } + + public function slowlog($key_or_address, $arg = null, ...$other_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slowlog(...\func_get_args()); + } + + public function smembers($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smembers(...\func_get_args()); + } + + public function smove($src, $dst, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smove(...\func_get_args()); + } + + public function sort($key, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort(...\func_get_args()); + } + + public function spop($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->spop(...\func_get_args()); + } + + public function srandmember($key, $count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srandmember(...\func_get_args()); + } + + public function srem($key, $value) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srem(...\func_get_args()); + } + + public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function strlen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->strlen(...\func_get_args()); + } + + public function subscribe($channels, $callback) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->subscribe(...\func_get_args()); + } + + public function sunion($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunion(...\func_get_args()); + } + + public function sunionstore($dst, $key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunionstore(...\func_get_args()); + } + + public function time() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->time(...\func_get_args()); + } + + public function ttl($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ttl(...\func_get_args()); + } + + public function type($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); + } + + public function unsubscribe($channel, ...$other_channels) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unsubscribe(...\func_get_args()); + } + + public function unlink($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unlink(...\func_get_args()); + } + + public function unwatch() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); + } + + public function watch($key, ...$other_keys) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + + public function xack($str_key, $str_group, $arr_ids) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); + } + + public function xadd($str_key, $str_id, $arr_fields, $i_maxlen = null, $boo_approximate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function xclaim($str_key, $str_group, $str_consumer, $i_min_idle, $arr_ids, $arr_opts = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); + } + + public function xdel($str_key, $arr_ids) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdel(...\func_get_args()); + } + + public function xgroup($str_operation, $str_key = null, $str_arg1 = null, $str_arg2 = null, $str_arg3 = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xgroup(...\func_get_args()); + } + + public function xinfo($str_cmd, $str_key = null, $str_group = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xinfo(...\func_get_args()); + } + + public function xlen($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xlen(...\func_get_args()); + } + + public function xpending($str_key, $str_group, $str_start = null, $str_end = null, $i_count = null, $str_consumer = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xpending(...\func_get_args()); + } + + public function xrange($str_key, $str_start, $str_end, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrange(...\func_get_args()); + } + + public function xread($arr_streams, $i_count = null, $i_block = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xread(...\func_get_args()); + } + + public function xreadgroup($str_group, $str_consumer, $arr_streams, $i_count = null, $i_block = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xreadgroup(...\func_get_args()); + } + + public function xrevrange($str_key, $str_start, $str_end, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrevrange(...\func_get_args()); + } + + public function xtrim($str_key, $i_maxlen, $boo_approximate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xtrim(...\func_get_args()); + } + + public function zadd($key, $score, $value, ...$extra_args) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zadd(...\func_get_args()); + } + + public function zcard($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcard(...\func_get_args()); + } + + public function zcount($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcount(...\func_get_args()); + } + + public function zincrby($key, $value, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zincrby(...\func_get_args()); + } + + public function zinterstore($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinterstore(...\func_get_args()); + } + + public function zlexcount($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zlexcount(...\func_get_args()); + } + + public function zpopmax($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmax(...\func_get_args()); + } + + public function zpopmin($key) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmin(...\func_get_args()); + } + + public function zrange($key, $start, $end, $scores = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrange(...\func_get_args()); + } + + public function zrangebylex($key, $min, $max, $offset = null, $limit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebylex(...\func_get_args()); + } + + public function zrangebyscore($key, $start, $end, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebyscore(...\func_get_args()); + } + + public function zrank($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); + } + + public function zrem($key, $member, ...$other_members) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrem(...\func_get_args()); + } + + public function zremrangebylex($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebylex(...\func_get_args()); + } + + public function zremrangebyrank($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyrank(...\func_get_args()); + } + + public function zremrangebyscore($key, $min, $max) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyscore(...\func_get_args()); + } + + public function zrevrange($key, $start, $end, $scores = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrange(...\func_get_args()); + } + + public function zrevrangebylex($key, $min, $max, $offset = null, $limit = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebylex(...\func_get_args()); + } + + public function zrevrangebyscore($key, $start, $end, $options = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebyscore(...\func_get_args()); + } + + public function zrevrank($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); + } + + public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function zscore($key, $member) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); + } + + public function zunionstore($key, $keys, $weights = null, $aggregate = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunionstore(...\func_get_args()); + } +} diff --git a/vendor/symfony/cache/Traits/RedisCluster6Proxy.php b/vendor/symfony/cache/Traits/RedisCluster6Proxy.php new file mode 100644 index 000000000..c19aa1620 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisCluster6Proxy.php @@ -0,0 +1,1139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\VarExporter\LazyObjectInterface; +use Symfony\Component\VarExporter\LazyProxyTrait; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + +/** + * @internal + */ +class RedisCluster6Proxy extends \RedisCluster implements ResetInterface, LazyObjectInterface +{ + use RedisCluster6ProxyTrait; + use LazyProxyTrait { + resetLazyObject as reset; + } + + private const LAZY_OBJECT_PROPERTY_SCOPES = []; + + public function __construct($name, $seeds = null, $timeout = 0, $read_timeout = 0, $persistent = false, #[\SensitiveParameter] $auth = null, $context = null) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->__construct(...\func_get_args()); + } + + public function _compress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_compress(...\func_get_args()); + } + + public function _uncompress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_uncompress(...\func_get_args()); + } + + public function _serialize($value): bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_serialize(...\func_get_args()); + } + + public function _unserialize($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unserialize(...\func_get_args()); + } + + public function _pack($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_pack(...\func_get_args()); + } + + public function _unpack($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unpack(...\func_get_args()); + } + + public function _prefix($key): bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_prefix(...\func_get_args()); + } + + public function _masters(): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_masters(...\func_get_args()); + } + + public function _redir(): ?string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_redir(...\func_get_args()); + } + + public function acl($key_or_address, $subcmd, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->acl(...\func_get_args()); + } + + public function append($key, $value): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->append(...\func_get_args()); + } + + public function bgrewriteaof($key_or_address): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgrewriteaof(...\func_get_args()); + } + + public function bgsave($key_or_address): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); + } + + public function bitcount($key, $start = 0, $end = -1, $bybit = false): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitcount(...\func_get_args()); + } + + public function bitop($operation, $deskey, $srckey, ...$otherkeys): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitop(...\func_get_args()); + } + + public function bitpos($key, $bit, $start = 0, $end = -1, $bybit = false): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitpos(...\func_get_args()); + } + + public function blpop($key, $timeout_or_key, ...$extra_args): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blpop(...\func_get_args()); + } + + public function brpop($key, $timeout_or_key, ...$extra_args): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpop(...\func_get_args()); + } + + public function brpoplpush($srckey, $deskey, $timeout): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpoplpush(...\func_get_args()); + } + + public function lmove($src, $dst, $wherefrom, $whereto): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmove(...\func_get_args()); + } + + public function blmove($src, $dst, $wherefrom, $whereto, $timeout): \Redis|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); + } + + public function bzpopmax($key, $timeout_or_key, ...$extra_args): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmax(...\func_get_args()); + } + + public function bzpopmin($key, $timeout_or_key, ...$extra_args): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmin(...\func_get_args()); + } + + public function bzmpop($timeout, $keys, $from, $count = 1): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzmpop(...\func_get_args()); + } + + public function zmpop($keys, $from, $count = 1): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmpop(...\func_get_args()); + } + + public function blmpop($timeout, $keys, $from, $count = 1): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmpop(...\func_get_args()); + } + + public function lmpop($keys, $from, $count = 1): \RedisCluster|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmpop(...\func_get_args()); + } + + public function clearlasterror(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearlasterror(...\func_get_args()); + } + + public function client($key_or_address, $subcommand, $arg = null): array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->client(...\func_get_args()); + } + + public function close(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->close(...\func_get_args()); + } + + public function cluster($key_or_address, $command, ...$extra_args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cluster(...\func_get_args()); + } + + public function command(...$extra_args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->command(...\func_get_args()); + } + + public function config($key_or_address, $subcommand, ...$extra_args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->config(...\func_get_args()); + } + + public function dbsize($key_or_address): \RedisCluster|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbsize(...\func_get_args()); + } + + public function copy($src, $dst, $options = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + + public function decr($key, $by = 1): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decr(...\func_get_args()); + } + + public function decrby($key, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrby(...\func_get_args()); + } + + public function decrbyfloat($key, $value): float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrbyfloat(...\func_get_args()); + } + + public function del($key, ...$other_keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->del(...\func_get_args()); + } + + public function discard(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->discard(...\func_get_args()); + } + + public function dump($key): \RedisCluster|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function echo($key_or_address, $msg): \RedisCluster|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->echo(...\func_get_args()); + } + + public function eval($script, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval(...\func_get_args()); + } + + public function eval_ro($script, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval_ro(...\func_get_args()); + } + + public function evalsha($script_sha, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha(...\func_get_args()); + } + + public function evalsha_ro($script_sha, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha_ro(...\func_get_args()); + } + + public function exec(): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exec(...\func_get_args()); + } + + public function exists($key, ...$other_keys): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exists(...\func_get_args()); + } + + public function touch($key, ...$other_keys): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->touch(...\func_get_args()); + } + + public function expire($key, $timeout, $mode = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expire(...\func_get_args()); + } + + public function expireat($key, $timestamp, $mode = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expireat(...\func_get_args()); + } + + public function expiretime($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expiretime(...\func_get_args()); + } + + public function pexpiretime($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpiretime(...\func_get_args()); + } + + public function flushall($key_or_address, $async = false): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushall(...\func_get_args()); + } + + public function flushdb($key_or_address, $async = false): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushdb(...\func_get_args()); + } + + public function geoadd($key, $lng, $lat, $member, ...$other_triples_and_options): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); + } + + public function geodist($key, $src, $dest, $unit = null): \RedisCluster|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function geohash($key, $member, ...$other_members): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); + } + + public function geopos($key, $member, ...$other_members): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geopos(...\func_get_args()); + } + + public function georadius($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius(...\func_get_args()); + } + + public function georadius_ro($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); + } + + public function georadiusbymember($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember(...\func_get_args()); + } + + public function georadiusbymember_ro($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember_ro(...\func_get_args()); + } + + public function geosearch($key, $position, $shape, $unit, $options = []): \RedisCluster|array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); + } + + public function geosearchstore($dst, $src, $position, $shape, $unit, $options = []): \RedisCluster|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearchstore(...\func_get_args()); + } + + public function get($key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->get(...\func_get_args()); + } + + public function getbit($key, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getbit(...\func_get_args()); + } + + public function getlasterror(): ?string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getlasterror(...\func_get_args()); + } + + public function getmode(): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getmode(...\func_get_args()); + } + + public function getoption($option): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getoption(...\func_get_args()); + } + + public function getrange($key, $start, $end): \RedisCluster|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); + } + + public function lcs($key1, $key2, $options = null): \RedisCluster|array|false|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lcs(...\func_get_args()); + } + + public function getset($key, $value): \RedisCluster|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getset(...\func_get_args()); + } + + public function gettransferredbytes(): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->gettransferredbytes(...\func_get_args()); + } + + public function cleartransferredbytes(): void + { + ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cleartransferredbytes(...\func_get_args()); + } + + public function hdel($key, $member, ...$other_members): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hdel(...\func_get_args()); + } + + public function hexists($key, $member): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexists(...\func_get_args()); + } + + public function hget($key, $member): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hget(...\func_get_args()); + } + + public function hgetall($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetall(...\func_get_args()); + } + + public function hincrby($key, $member, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrby(...\func_get_args()); + } + + public function hincrbyfloat($key, $member, $value): \RedisCluster|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrbyfloat(...\func_get_args()); + } + + public function hkeys($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hkeys(...\func_get_args()); + } + + public function hlen($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hlen(...\func_get_args()); + } + + public function hmget($key, $keys): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmget(...\func_get_args()); + } + + public function hmset($key, $key_values): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmset(...\func_get_args()); + } + + public function hscan($key, &$iterator, $pattern = null, $count = 0): array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function hrandfield($key, $options = null): \RedisCluster|array|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hrandfield(...\func_get_args()); + } + + public function hset($key, $member, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); + } + + public function hsetnx($key, $member, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetnx(...\func_get_args()); + } + + public function hstrlen($key, $field): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hstrlen(...\func_get_args()); + } + + public function hvals($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hvals(...\func_get_args()); + } + + public function incr($key, $by = 1): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incr(...\func_get_args()); + } + + public function incrby($key, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrby(...\func_get_args()); + } + + public function incrbyfloat($key, $value): \RedisCluster|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrbyfloat(...\func_get_args()); + } + + public function info($key_or_address, ...$sections): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->info(...\func_get_args()); + } + + public function keys($pattern): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->keys(...\func_get_args()); + } + + public function lastsave($key_or_address): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lastsave(...\func_get_args()); + } + + public function lget($key, $index): \RedisCluster|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lget(...\func_get_args()); + } + + public function lindex($key, $index): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lindex(...\func_get_args()); + } + + public function linsert($key, $pos, $pivot, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->linsert(...\func_get_args()); + } + + public function llen($key): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->llen(...\func_get_args()); + } + + public function lpop($key, $count = 0): \RedisCluster|array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpop(...\func_get_args()); + } + + public function lpos($key, $value, $options = null): \Redis|array|bool|int|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpos(...\func_get_args()); + } + + public function lpush($key, $value, ...$other_values): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpush(...\func_get_args()); + } + + public function lpushx($key, $value): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpushx(...\func_get_args()); + } + + public function lrange($key, $start, $end): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); + } + + public function lrem($key, $value, $count = 0): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrem(...\func_get_args()); + } + + public function lset($key, $index, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lset(...\func_get_args()); + } + + public function ltrim($key, $start, $end): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ltrim(...\func_get_args()); + } + + public function mget($keys): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function mset($key_values): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mset(...\func_get_args()); + } + + public function msetnx($key_values): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetnx(...\func_get_args()); + } + + public function multi($value = \Redis::MULTI): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->multi(...\func_get_args()); + } + + public function object($subcommand, $key): \RedisCluster|false|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->object(...\func_get_args()); + } + + public function persist($key): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->persist(...\func_get_args()); + } + + public function pexpire($key, $timeout, $mode = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpire(...\func_get_args()); + } + + public function pexpireat($key, $timestamp, $mode = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpireat(...\func_get_args()); + } + + public function pfadd($key, $elements): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); + } + + public function pfcount($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + + public function pfmerge($key, $keys): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); + } + + public function ping($key_or_address, $message = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ping(...\func_get_args()); + } + + public function psetex($key, $timeout, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psetex(...\func_get_args()); + } + + public function psubscribe($patterns, $callback): void + { + ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psubscribe(...\func_get_args()); + } + + public function pttl($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pttl(...\func_get_args()); + } + + public function pubsub($key_or_address, ...$values): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + + public function punsubscribe($pattern, ...$other_patterns): array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->punsubscribe(...\func_get_args()); + } + + public function randomkey($key_or_address): \RedisCluster|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->randomkey(...\func_get_args()); + } + + public function rawcommand($key_or_address, $command, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawcommand(...\func_get_args()); + } + + public function rename($key_src, $key_dst): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rename(...\func_get_args()); + } + + public function renamenx($key, $newkey): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renamenx(...\func_get_args()); + } + + public function restore($key, $timeout, $value, $options = null): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args()); + } + + public function role($key_or_address): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->role(...\func_get_args()); + } + + public function rpop($key, $count = 0): \RedisCluster|array|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpop(...\func_get_args()); + } + + public function rpoplpush($src, $dst): \RedisCluster|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpoplpush(...\func_get_args()); + } + + public function rpush($key, ...$elements): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpush(...\func_get_args()); + } + + public function rpushx($key, $value): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpushx(...\func_get_args()); + } + + public function sadd($key, $value, ...$other_values): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sadd(...\func_get_args()); + } + + public function saddarray($key, $values): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->saddarray(...\func_get_args()); + } + + public function save($key_or_address): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); + } + + public function scan(&$iterator, $key_or_address, $pattern = null, $count = 0): array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); + } + + public function scard($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scard(...\func_get_args()); + } + + public function script($key_or_address, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->script(...\func_get_args()); + } + + public function sdiff($key, ...$other_keys): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiff(...\func_get_args()); + } + + public function sdiffstore($dst, $key, ...$other_keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiffstore(...\func_get_args()); + } + + public function set($key, $value, $options = null): \RedisCluster|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->set(...\func_get_args()); + } + + public function setbit($key, $offset, $onoff): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setbit(...\func_get_args()); + } + + public function setex($key, $expire, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setex(...\func_get_args()); + } + + public function setnx($key, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setnx(...\func_get_args()); + } + + public function setoption($option, $value): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setoption(...\func_get_args()); + } + + public function setrange($key, $offset, $value): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setrange(...\func_get_args()); + } + + public function sinter($key, ...$other_keys): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinter(...\func_get_args()); + } + + public function sintercard($keys, $limit = -1): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sintercard(...\func_get_args()); + } + + public function sinterstore($key, ...$other_keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinterstore(...\func_get_args()); + } + + public function sismember($key, $value): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sismember(...\func_get_args()); + } + + public function smismember($key, $member, ...$other_members): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smismember(...\func_get_args()); + } + + public function slowlog($key_or_address, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slowlog(...\func_get_args()); + } + + public function smembers($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smembers(...\func_get_args()); + } + + public function smove($src, $dst, $member): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smove(...\func_get_args()); + } + + public function sort($key, $options = null): \RedisCluster|array|bool|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort(...\func_get_args()); + } + + public function sort_ro($key, $options = null): \RedisCluster|array|bool|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort_ro(...\func_get_args()); + } + + public function spop($key, $count = 0): \RedisCluster|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->spop(...\func_get_args()); + } + + public function srandmember($key, $count = 0): \RedisCluster|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srandmember(...\func_get_args()); + } + + public function srem($key, $value, ...$other_values): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srem(...\func_get_args()); + } + + public function sscan($key, &$iterator, $pattern = null, $count = 0): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function strlen($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->strlen(...\func_get_args()); + } + + public function subscribe($channels, $cb): void + { + ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->subscribe(...\func_get_args()); + } + + public function sunion($key, ...$other_keys): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunion(...\func_get_args()); + } + + public function sunionstore($dst, $key, ...$other_keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunionstore(...\func_get_args()); + } + + public function time($key_or_address): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->time(...\func_get_args()); + } + + public function ttl($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ttl(...\func_get_args()); + } + + public function type($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); + } + + public function unsubscribe($channels): array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unsubscribe(...\func_get_args()); + } + + public function unlink($key, ...$other_keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unlink(...\func_get_args()); + } + + public function unwatch(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); + } + + public function watch($key, ...$other_keys): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + + public function xack($key, $group, $ids): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); + } + + public function xadd($key, $id, $values, $maxlen = 0, $approx = false): \RedisCluster|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function xclaim($key, $group, $consumer, $min_iddle, $ids, $options): \RedisCluster|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); + } + + public function xdel($key, $ids): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdel(...\func_get_args()); + } + + public function xgroup($operation, $key = null, $group = null, $id_or_consumer = null, $mkstream = false, $entries_read = -2): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xgroup(...\func_get_args()); + } + + public function xautoclaim($key, $group, $consumer, $min_idle, $start, $count = -1, $justid = false): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xautoclaim(...\func_get_args()); + } + + public function xinfo($operation, $arg1 = null, $arg2 = null, $count = -1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xinfo(...\func_get_args()); + } + + public function xlen($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xlen(...\func_get_args()); + } + + public function xpending($key, $group, $start = null, $end = null, $count = -1, $consumer = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xpending(...\func_get_args()); + } + + public function xrange($key, $start, $end, $count = -1): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrange(...\func_get_args()); + } + + public function xread($streams, $count = -1, $block = -1): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xread(...\func_get_args()); + } + + public function xreadgroup($group, $consumer, $streams, $count = 1, $block = 1): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xreadgroup(...\func_get_args()); + } + + public function xrevrange($key, $start, $end, $count = -1): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrevrange(...\func_get_args()); + } + + public function xtrim($key, $maxlen, $approx = false, $minid = false, $limit = -1): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xtrim(...\func_get_args()); + } + + public function zadd($key, $score_or_options, ...$more_scores_and_mems): \RedisCluster|false|float|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zadd(...\func_get_args()); + } + + public function zcard($key): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcard(...\func_get_args()); + } + + public function zcount($key, $start, $end): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcount(...\func_get_args()); + } + + public function zincrby($key, $value, $member): \RedisCluster|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zincrby(...\func_get_args()); + } + + public function zinterstore($dst, $keys, $weights = null, $aggregate = null): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinterstore(...\func_get_args()); + } + + public function zintercard($keys, $limit = -1): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zintercard(...\func_get_args()); + } + + public function zlexcount($key, $min, $max): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zlexcount(...\func_get_args()); + } + + public function zpopmax($key, $value = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmax(...\func_get_args()); + } + + public function zpopmin($key, $value = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmin(...\func_get_args()); + } + + public function zrange($key, $start, $end, $options = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrange(...\func_get_args()); + } + + public function zrangestore($dstkey, $srckey, $start, $end, $options = null): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangestore(...\func_get_args()); + } + + public function zrandmember($key, $options = null): \RedisCluster|array|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrandmember(...\func_get_args()); + } + + public function zrangebylex($key, $min, $max, $offset = -1, $count = -1): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebylex(...\func_get_args()); + } + + public function zrangebyscore($key, $start, $end, $options = []): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebyscore(...\func_get_args()); + } + + public function zrank($key, $member): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); + } + + public function zrem($key, $value, ...$other_values): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrem(...\func_get_args()); + } + + public function zremrangebylex($key, $min, $max): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebylex(...\func_get_args()); + } + + public function zremrangebyrank($key, $min, $max): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyrank(...\func_get_args()); + } + + public function zremrangebyscore($key, $min, $max): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyscore(...\func_get_args()); + } + + public function zrevrange($key, $min, $max, $options = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrange(...\func_get_args()); + } + + public function zrevrangebylex($key, $min, $max, $options = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebylex(...\func_get_args()); + } + + public function zrevrangebyscore($key, $min, $max, $options = null): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebyscore(...\func_get_args()); + } + + public function zrevrank($key, $member): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); + } + + public function zscan($key, &$iterator, $pattern = null, $count = 0): \RedisCluster|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function zscore($key, $member): \RedisCluster|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); + } + + public function zmscore($key, $member, ...$other_members): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmscore(...\func_get_args()); + } + + public function zunionstore($dst, $keys, $weights = null, $aggregate = null): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunionstore(...\func_get_args()); + } + + public function zinter($keys, $weights = null, $options = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinter(...\func_get_args()); + } + + public function zdiffstore($dst, $keys): \RedisCluster|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiffstore(...\func_get_args()); + } + + public function zunion($keys, $weights = null, $options = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunion(...\func_get_args()); + } + + public function zdiff($keys, $options = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiff(...\func_get_args()); + } +} diff --git a/vendor/symfony/cache/Traits/RedisCluster6ProxyTrait.php b/vendor/symfony/cache/Traits/RedisCluster6ProxyTrait.php new file mode 100644 index 000000000..9c3169e32 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisCluster6ProxyTrait.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.1.0-dev', '>')) { + /** + * @internal + */ + trait RedisCluster6ProxyTrait + { + public function getex($key, $options = []): \RedisCluster|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getex(...\func_get_args()); + } + + public function publish($channel, $message): \RedisCluster|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + + public function waitaof($key_or_address, $numlocal, $numreplicas, $timeout): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->waitaof(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait RedisCluster6ProxyTrait + { + public function publish($channel, $message): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + } +} diff --git a/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php new file mode 100644 index 000000000..f5c0baa3e --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +/** + * This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as + * individual \Redis objects. + * + * Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)' + * according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands + * + * @author Jack Thomas + * + * @internal + */ +class RedisClusterNodeProxy +{ + public function __construct( + private array $host, + private \RedisCluster $redis, + ) { + } + + public function __call(string $method, array $args) + { + return $this->redis->{$method}($this->host, ...$args); + } + + public function scan(&$iIterator, $strPattern = null, $iCount = null) + { + return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount); + } + + public function getOption($name) + { + return $this->redis->getOption($name); + } +} diff --git a/vendor/symfony/cache/Traits/RedisClusterProxy.php b/vendor/symfony/cache/Traits/RedisClusterProxy.php new file mode 100644 index 000000000..c67d5341c --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisClusterProxy.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +class_alias(6.0 <= (float) phpversion('redis') ? RedisCluster6Proxy::class : RedisCluster5Proxy::class, RedisClusterProxy::class); + +if (false) { + /** + * @internal + */ + class RedisClusterProxy extends \RedisCluster + { + } +} diff --git a/vendor/symfony/cache/Traits/RedisProxy.php b/vendor/symfony/cache/Traits/RedisProxy.php new file mode 100644 index 000000000..7f4537b15 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisProxy.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +class_alias(6.0 <= (float) phpversion('redis') ? Redis6Proxy::class : Redis5Proxy::class, RedisProxy::class); + +if (false) { + /** + * @internal + */ + class RedisProxy extends \Redis + { + } +} diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php new file mode 100644 index 000000000..2a1fa3921 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisTrait.php @@ -0,0 +1,676 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Predis\Command\Redis\UNLINK; +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Connection\Aggregate\RedisCluster; +use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Connection\Cluster\ClusterInterface as Predis2ClusterInterface; +use Predis\Connection\Cluster\RedisCluster as Predis2RedisCluster; +use Predis\Response\ErrorInterface; +use Predis\Response\Status; +use Relay\Relay; +use Relay\Sentinel; +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Aurimas Niekis + * @author Nicolas Grekas + * + * @internal + */ +trait RedisTrait +{ + private static array $defaultConnectionOptions = [ + 'class' => null, + 'persistent' => 0, + 'persistent_id' => null, + 'timeout' => 30, + 'read_timeout' => 0, + 'retry_interval' => 0, + 'tcp_keepalive' => 0, + 'lazy' => null, + 'redis_cluster' => false, + 'redis_sentinel' => null, + 'dbindex' => 0, + 'failover' => 'none', + 'ssl' => null, // see https://php.net/context.ssl + ]; + private \Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis; + private MarshallerInterface $marshaller; + + private function init(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller): void + { + parent::__construct($namespace, $defaultLifetime); + + if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { + throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); + } + + if ($redis instanceof \Predis\ClientInterface && $redis->getOptions()->exceptions) { + $options = clone $redis->getOptions(); + \Closure::bind(function () { $this->options['exceptions'] = false; }, $options, $options)(); + $redis = new $redis($redis->getConnection(), $options); + } + + $this->redis = $redis; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + /** + * Creates a Redis connection using a DSN configuration. + * + * Example DSN: + * - redis://localhost + * - redis://example.com:1234 + * - redis://secret@example.com/13 + * - redis:///var/run/redis.sock + * - redis://secret@/var/run/redis.sock/13 + * + * @param array $options See self::$defaultConnectionOptions + * + * @throws InvalidArgumentException when the DSN is invalid + */ + public static function createConnection(#[\SensitiveParameter] string $dsn, array $options = []): \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|Relay + { + if (str_starts_with($dsn, 'redis:')) { + $scheme = 'redis'; + } elseif (str_starts_with($dsn, 'rediss:')) { + $scheme = 'rediss'; + } else { + throw new InvalidArgumentException('Invalid Redis DSN: it does not start with "redis[s]:".'); + } + + if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { + throw new CacheException('Cannot find the "redis" extension nor the "predis/predis" package.'); + } + + $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:(?[^:@]*+):)?(?[^@]*+)@)?#', function ($m) use (&$auth) { + if (isset($m['password'])) { + if (\in_array($m['user'], ['', 'default'], true)) { + $auth = rawurldecode($m['password']); + } else { + $auth = [rawurldecode($m['user']), rawurldecode($m['password'])]; + } + + if ('' === $auth) { + $auth = null; + } + } + + return 'file:'.($m[1] ?? ''); + }, $dsn); + + if (false === $params = parse_url($params)) { + throw new InvalidArgumentException('Invalid Redis DSN.'); + } + + $query = $hosts = []; + + $tls = 'rediss' === $scheme; + $tcpScheme = $tls ? 'tls' : 'tcp'; + + if (isset($params['query'])) { + parse_str($params['query'], $query); + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException('Invalid Redis DSN: query parameter "host" must be an array.'); + } + foreach ($hosts as $host => $parameters) { + if (\is_string($parameters)) { + parse_str($parameters, $parameters); + } + if (false === $i = strrpos($host, ':')) { + $hosts[$host] = ['scheme' => $tcpScheme, 'host' => $host, 'port' => 6379] + $parameters; + } elseif ($port = (int) substr($host, 1 + $i)) { + $hosts[$host] = ['scheme' => $tcpScheme, 'host' => substr($host, 0, $i), 'port' => $port] + $parameters; + } else { + $hosts[$host] = ['scheme' => 'unix', 'path' => substr($host, 0, $i)] + $parameters; + } + } + $hosts = array_values($hosts); + } + } + + if (isset($params['host']) || isset($params['path'])) { + if (!isset($params['dbindex']) && isset($params['path'])) { + if (preg_match('#/(\d+)?$#', $params['path'], $m)) { + $params['dbindex'] = $m[1] ?? $query['dbindex'] ?? '0'; + $params['path'] = substr($params['path'], 0, -\strlen($m[0])); + } elseif (isset($params['host'])) { + throw new InvalidArgumentException('Invalid Redis DSN: parameter "dbindex" must be a number.'); + } + } + + if (isset($params['host'])) { + array_unshift($hosts, ['scheme' => $tcpScheme, 'host' => $params['host'], 'port' => $params['port'] ?? 6379]); + } else { + array_unshift($hosts, ['scheme' => 'unix', 'path' => $params['path']]); + } + } + + if (!$hosts) { + throw new InvalidArgumentException('Invalid Redis DSN: missing host.'); + } + + if (isset($params['dbindex'], $query['dbindex']) && $params['dbindex'] !== $query['dbindex']) { + throw new InvalidArgumentException('Invalid Redis DSN: path and query "dbindex" parameters mismatch.'); + } + + $params += $query + $options + self::$defaultConnectionOptions; + + if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) { + throw new CacheException('Redis Sentinel support requires one of: "predis/predis", "ext-redis >= 5.2", "ext-relay".'); + } + + if (isset($params['lazy'])) { + $params['lazy'] = filter_var($params['lazy'], \FILTER_VALIDATE_BOOLEAN); + } + $params['redis_cluster'] = filter_var($params['redis_cluster'], \FILTER_VALIDATE_BOOLEAN); + + if ($params['redis_cluster'] && isset($params['redis_sentinel'])) { + throw new InvalidArgumentException('Cannot use both "redis_cluster" and "redis_sentinel" at the same time.'); + } + + $class = $params['class'] ?? match (true) { + $params['redis_cluster'] => \extension_loaded('redis') ? \RedisCluster::class : \Predis\Client::class, + isset($params['redis_sentinel']) => match (true) { + \extension_loaded('redis') => \Redis::class, + \extension_loaded('relay') => Relay::class, + default => \Predis\Client::class, + }, + 1 < \count($hosts) && \extension_loaded('redis') => 1 < \count($hosts) ? \RedisArray::class : \Redis::class, + \extension_loaded('redis') => \Redis::class, + \extension_loaded('relay') => Relay::class, + default => \Predis\Client::class, + }; + + if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) { + throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and neither ext-redis >= 5.2 nor ext-relay have been found.', $class)); + } + + $isRedisExt = is_a($class, \Redis::class, true); + $isRelayExt = !$isRedisExt && is_a($class, Relay::class, true); + + if ($isRedisExt || $isRelayExt) { + $connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect'; + + $initializer = static function () use ($class, $isRedisExt, $connect, $params, $auth, $hosts, $tls) { + $sentinelClass = $isRedisExt ? \RedisSentinel::class : Sentinel::class; + $redis = new $class(); + $hostIndex = 0; + do { + $host = $hosts[$hostIndex]['host'] ?? $hosts[$hostIndex]['path']; + $port = $hosts[$hostIndex]['port'] ?? 0; + $passAuth = isset($params['auth']) && (!$isRedisExt || \defined('Redis::OPT_NULL_MULTIBULK_AS_NULL')); + $address = false; + + if (isset($hosts[$hostIndex]['host']) && $tls) { + $host = 'tls://'.$host; + } + + if (!isset($params['redis_sentinel'])) { + break; + } + + try { + if (version_compare(phpversion('redis'), '6.0.0', '>=') && $isRedisExt) { + $options = [ + 'host' => $host, + 'port' => $port, + 'connectTimeout' => (float) $params['timeout'], + 'persistent' => $params['persistent_id'], + 'retryInterval' => (int) $params['retry_interval'], + 'readTimeout' => (float) $params['read_timeout'], + ]; + + if ($passAuth) { + $options['auth'] = $params['auth']; + } + + $sentinel = new \RedisSentinel($options); + } else { + $extra = $passAuth ? [$params['auth']] : []; + + $sentinel = new $sentinelClass($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra); + } + + if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) { + [$host, $port] = $address; + } + } catch (\RedisException|\Relay\Exception $redisException) { + } + } while (++$hostIndex < \count($hosts) && !$address); + + if (isset($params['redis_sentinel']) && !$address) { + throw new InvalidArgumentException(sprintf('Failed to retrieve master information from sentinel "%s".', $params['redis_sentinel']), previous: $redisException ?? null); + } + + try { + $extra = [ + 'stream' => $params['ssl'] ?? null, + ]; + $booleanStreamOptions = [ + 'allow_self_signed', + 'capture_peer_cert', + 'capture_peer_cert_chain', + 'disable_compression', + 'SNI_enabled', + 'verify_peer', + 'verify_peer_name', + ]; + + foreach ($extra['stream'] ?? [] as $streamOption => $value) { + if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) { + $extra['stream'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL); + } + } + + if (isset($params['auth'])) { + $extra['auth'] = $params['auth']; + } + @$redis->{$connect}($host, $port, (float) $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') || !$isRedisExt ? [$extra] : []); + + set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); + try { + $isConnected = $redis->isConnected(); + } finally { + restore_error_handler(); + } + if (!$isConnected) { + $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? sprintf(' (%s)', $error[1]) : ''; + throw new InvalidArgumentException('Redis connection failed: '.$error.'.'); + } + + if ((null !== $auth && !$redis->auth($auth)) + // Due to a bug in phpredis we must always select the dbindex if persistent pooling is enabled + // @see https://github.com/phpredis/phpredis/issues/1920 + // @see https://github.com/symfony/symfony/issues/51578 + || (($params['dbindex'] || ('pconnect' === $connect && '0' !== \ini_get('redis.pconnect.pooling_enabled'))) && !$redis->select($params['dbindex'])) + ) { + $e = preg_replace('/^ERR /', '', $redis->getLastError()); + throw new InvalidArgumentException('Redis connection failed: '.$e.'.'); + } + + if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) { + $redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + } catch (\RedisException|\Relay\Exception $e) { + throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage()); + } + + return $redis; + }; + + if ($params['lazy']) { + $redis = $isRedisExt ? RedisProxy::createLazyProxy($initializer) : RelayProxy::createLazyProxy($initializer); + } else { + $redis = $initializer(); + } + } elseif (is_a($class, \RedisArray::class, true)) { + foreach ($hosts as $i => $host) { + $hosts[$i] = match ($host['scheme']) { + 'tcp' => $host['host'].':'.$host['port'], + 'tls' => 'tls://'.$host['host'].':'.$host['port'], + default => $host['path'], + }; + } + $params['lazy_connect'] = $params['lazy'] ?? true; + $params['connect_timeout'] = $params['timeout']; + + try { + $redis = new $class($hosts, $params); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage()); + } + + if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) { + $redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + } elseif (is_a($class, \RedisCluster::class, true)) { + $initializer = static function () use ($isRedisExt, $class, $params, $hosts) { + foreach ($hosts as $i => $host) { + $hosts[$i] = match ($host['scheme']) { + 'tcp' => $host['host'].':'.$host['port'], + 'tls' => 'tls://'.$host['host'].':'.$host['port'], + default => $host['path'], + }; + } + + try { + $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', ...\defined('Redis::SCAN_PREFIX') ? [$params['ssl'] ?? null] : []); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage()); + } + + if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) { + $redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, match ($params['failover']) { + 'error' => \RedisCluster::FAILOVER_ERROR, + 'distribute' => \RedisCluster::FAILOVER_DISTRIBUTE, + 'slaves' => \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES, + 'none' => \RedisCluster::FAILOVER_NONE, + }); + + return $redis; + }; + + $redis = $params['lazy'] ? RedisClusterProxy::createLazyProxy($initializer) : $initializer(); + } elseif (is_a($class, \Predis\ClientInterface::class, true)) { + if ($params['redis_cluster']) { + $params['cluster'] = 'redis'; + } elseif (isset($params['redis_sentinel'])) { + $params['replication'] = 'sentinel'; + $params['service'] = $params['redis_sentinel']; + } + $params += ['parameters' => []]; + $params['parameters'] += [ + 'persistent' => $params['persistent'], + 'timeout' => $params['timeout'], + 'read_write_timeout' => $params['read_timeout'], + 'tcp_nodelay' => true, + ]; + if ($params['dbindex']) { + $params['parameters']['database'] = $params['dbindex']; + } + if (null !== $auth) { + if (\is_array($auth)) { + // ACL + $params['parameters']['username'] = $auth[0]; + $params['parameters']['password'] = $auth[1]; + } else { + $params['parameters']['password'] = $auth; + } + } + + if (isset($params['ssl'])) { + foreach ($hosts as $i => $host) { + $hosts[$i]['ssl'] ??= $params['ssl']; + } + } + + if (1 === \count($hosts) && !($params['redis_cluster'] || $params['redis_sentinel'])) { + $hosts = $hosts[0]; + } elseif (\in_array($params['failover'], ['slaves', 'distribute'], true) && !isset($params['replication'])) { + $params['replication'] = true; + $hosts[0] += ['alias' => 'master']; + } + $params['exceptions'] = false; + + $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions)); + if (isset($params['redis_sentinel'])) { + $redis->getConnection()->setSentinelTimeout($params['timeout']); + } + } elseif (class_exists($class, false)) { + throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster", "Relay\Relay" nor "Predis\ClientInterface".', $class)); + } else { + throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); + } + + return $redis; + } + + protected function doFetch(array $ids): iterable + { + if (!$ids) { + return []; + } + + $result = []; + + if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) { + $values = $this->pipeline(function () use ($ids) { + foreach ($ids as $id) { + yield 'get' => [$id]; + } + }); + } else { + $values = $this->redis->mget($ids); + + if (!\is_array($values) || \count($values) !== \count($ids)) { + return []; + } + + $values = array_combine($ids, $values); + } + + foreach ($values as $id => $v) { + if ($v) { + $result[$id] = $this->marshaller->unmarshall($v); + } + } + + return $result; + } + + protected function doHave(string $id): bool + { + return (bool) $this->redis->exists($id); + } + + protected function doClear(string $namespace): bool + { + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + $prefixLen = \strlen($prefix ?? ''); + } + + $cleared = true; + $hosts = $this->getHosts(); + $host = reset($hosts); + if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { + // Predis supports info command only on the master in replication environments + $hosts = [$host->getClientFor('master')]; + } + + foreach ($hosts as $host) { + if (!isset($namespace[0])) { + $cleared = $host->flushDb() && $cleared; + continue; + } + + $info = $host->info('Server'); + $info = !$info instanceof ErrorInterface ? $info['Server'] ?? $info : ['redis_version' => '2.0']; + + if ($host instanceof Relay) { + $prefix = Relay::SCAN_PREFIX & $host->getOption(Relay::OPT_SCAN) ? '' : $host->getOption(Relay::OPT_PREFIX); + $prefixLen = \strlen($host->getOption(Relay::OPT_PREFIX) ?? ''); + } elseif (!$host instanceof \Predis\ClientInterface) { + $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX); + $prefixLen = \strlen($host->getOption(\Redis::OPT_PREFIX) ?? ''); + } + $pattern = $prefix.$namespace.'*'; + + if (!version_compare($info['redis_version'], '2.8', '>=')) { + // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS + // can hang your server when it is executed against large databases (millions of items). + // Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above. + $unlink = version_compare($info['redis_version'], '4.0', '>=') ? 'UNLINK' : 'DEL'; + $args = $this->redis instanceof \Predis\ClientInterface ? [0, $pattern] : [[$pattern], 0]; + $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]) for i=1,#keys,5000 do redis.call('$unlink',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $args[0], $args[1]) && $cleared; + continue; + } + + $cursor = null; + do { + $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000); + if (isset($keys[1]) && \is_array($keys[1])) { + $cursor = $keys[0]; + $keys = $keys[1]; + } + if ($keys) { + if ($prefixLen) { + foreach ($keys as $i => $key) { + $keys[$i] = substr($key, $prefixLen); + } + } + $this->doDelete($keys); + } + } while ($cursor); + } + + return $cleared; + } + + protected function doDelete(array $ids): bool + { + if (!$ids) { + return true; + } + + if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) { + static $del; + $del ??= (class_exists(UNLINK::class) ? 'unlink' : 'del'); + + $this->pipeline(function () use ($ids, $del) { + foreach ($ids as $id) { + yield $del => [$id]; + } + })->rewind(); + } else { + static $unlink = true; + + if ($unlink) { + try { + $unlink = false !== $this->redis->unlink($ids); + } catch (\Throwable) { + $unlink = false; + } + } + + if (!$unlink) { + $this->redis->del($ids); + } + } + + return true; + } + + protected function doSave(array $values, int $lifetime): array|bool + { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + $results = $this->pipeline(function () use ($values, $lifetime) { + foreach ($values as $id => $value) { + if (0 >= $lifetime) { + yield 'set' => [$id, $value]; + } else { + yield 'setEx' => [$id, $lifetime, $value]; + } + } + }); + + foreach ($results as $id => $result) { + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { + $failed[] = $id; + } + } + + return $failed; + } + + private function pipeline(\Closure $generator, ?object $redis = null): \Generator + { + $ids = []; + $redis ??= $this->redis; + + if ($redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && ($redis->getConnection() instanceof RedisCluster || $redis->getConnection() instanceof Predis2RedisCluster))) { + // phpredis & predis don't support pipelining with RedisCluster + // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining + // see https://github.com/nrk/predis/issues/267#issuecomment-123781423 + $results = []; + foreach ($generator() as $command => $args) { + $results[] = $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? ($redis instanceof \Predis\ClientInterface ? $args[2] : $args[1][0]) : $args[0]; + } + } elseif ($redis instanceof \Predis\ClientInterface) { + $results = $redis->pipeline(static function ($redis) use ($generator, &$ids) { + foreach ($generator() as $command => $args) { + $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? $args[2] : $args[0]; + } + }); + } elseif ($redis instanceof \RedisArray) { + $connections = $results = $ids = []; + foreach ($generator() as $command => $args) { + $id = 'eval' === $command ? $args[1][0] : $args[0]; + if (!isset($connections[$h = $redis->_target($id)])) { + $connections[$h] = [$redis->_instance($h), -1]; + $connections[$h][0]->multi(\Redis::PIPELINE); + } + $connections[$h][0]->{$command}(...$args); + $results[] = [$h, ++$connections[$h][1]]; + $ids[] = $id; + } + foreach ($connections as $h => $c) { + $connections[$h] = $c[0]->exec(); + } + foreach ($results as $k => [$h, $c]) { + $results[$k] = $connections[$h][$c]; + } + } else { + $redis->multi($redis instanceof Relay ? Relay::PIPELINE : \Redis::PIPELINE); + foreach ($generator() as $command => $args) { + $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? $args[1][0] : $args[0]; + } + $results = $redis->exec(); + } + + if (!$redis instanceof \Predis\ClientInterface && 'eval' === $command && $redis->getLastError()) { + $e = $redis instanceof Relay ? new \Relay\Exception($redis->getLastError()) : new \RedisException($redis->getLastError()); + $results = array_map(fn ($v) => false === $v ? $e : $v, (array) $results); + } + + if (\is_bool($results)) { + return; + } + + foreach ($ids as $k => $id) { + yield $id => $results[$k]; + } + } + + private function getHosts(): array + { + $hosts = [$this->redis]; + if ($this->redis instanceof \Predis\ClientInterface) { + $connection = $this->redis->getConnection(); + if (($connection instanceof ClusterInterface || $connection instanceof Predis2ClusterInterface) && $connection instanceof \Traversable) { + $hosts = []; + foreach ($connection as $c) { + $hosts[] = new \Predis\Client($c); + } + } + } elseif ($this->redis instanceof \RedisArray) { + $hosts = []; + foreach ($this->redis->_hosts() as $host) { + $hosts[] = $this->redis->_instance($host); + } + } elseif ($this->redis instanceof \RedisCluster) { + $hosts = []; + foreach ($this->redis->_masters() as $host) { + $hosts[] = new RedisClusterNodeProxy($host, $this->redis); + } + } + + return $hosts; + } +} diff --git a/vendor/symfony/cache/Traits/RelayProxy.php b/vendor/symfony/cache/Traits/RelayProxy.php new file mode 100644 index 000000000..96d7d19b4 --- /dev/null +++ b/vendor/symfony/cache/Traits/RelayProxy.php @@ -0,0 +1,1319 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Symfony\Component\VarExporter\LazyObjectInterface; +use Symfony\Component\VarExporter\LazyProxyTrait; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); +class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + +/** + * @internal + */ +class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInterface +{ + use LazyProxyTrait { + resetLazyObject as reset; + } + use RelayProxyTrait; + + private const LAZY_OBJECT_PROPERTY_SCOPES = []; + + public function __construct($host = null, $port = 6379, $connect_timeout = 0.0, $command_timeout = 0.0, #[\SensitiveParameter] $context = [], $database = 0) + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->__construct(...\func_get_args()); + } + + public function connect($host, $port = 6379, $timeout = 0.0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0.0, #[\SensitiveParameter] $context = [], $database = 0): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->connect(...\func_get_args()); + } + + public function pconnect($host, $port = 6379, $timeout = 0.0, $persistent_id = null, $retry_interval = 0, $read_timeout = 0.0, #[\SensitiveParameter] $context = [], $database = 0): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pconnect(...\func_get_args()); + } + + public function close(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->close(...\func_get_args()); + } + + public function pclose(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pclose(...\func_get_args()); + } + + public function listen($callback): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->listen(...\func_get_args()); + } + + public function onFlushed($callback): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->onFlushed(...\func_get_args()); + } + + public function onInvalidated($callback, $pattern = null): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->onInvalidated(...\func_get_args()); + } + + public function dispatchEvents(): false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dispatchEvents(...\func_get_args()); + } + + public function getOption($option): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getOption(...\func_get_args()); + } + + public function option($option, $value = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->option(...\func_get_args()); + } + + public function setOption($option, $value): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setOption(...\func_get_args()); + } + + public function addIgnorePatterns(...$pattern): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->addIgnorePatterns(...\func_get_args()); + } + + public function addAllowPatterns(...$pattern): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->addAllowPatterns(...\func_get_args()); + } + + public function getTimeout(): false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getTimeout(...\func_get_args()); + } + + public function timeout(): false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->timeout(...\func_get_args()); + } + + public function getReadTimeout(): false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getReadTimeout(...\func_get_args()); + } + + public function readTimeout(): false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->readTimeout(...\func_get_args()); + } + + public function getBytes(): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getBytes(...\func_get_args()); + } + + public function bytes(): array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bytes(...\func_get_args()); + } + + public function getHost(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getHost(...\func_get_args()); + } + + public function isConnected(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->isConnected(...\func_get_args()); + } + + public function getPort(): false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPort(...\func_get_args()); + } + + public function getAuth(): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getAuth(...\func_get_args()); + } + + public function getDbNum(): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getDbNum(...\func_get_args()); + } + + public function _serialize($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_serialize(...\func_get_args()); + } + + public function _unserialize($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unserialize(...\func_get_args()); + } + + public function _compress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_compress(...\func_get_args()); + } + + public function _uncompress($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_uncompress(...\func_get_args()); + } + + public function _pack($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_pack(...\func_get_args()); + } + + public function _unpack($value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_unpack(...\func_get_args()); + } + + public function _prefix($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_prefix(...\func_get_args()); + } + + public function getLastError(): ?string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getLastError(...\func_get_args()); + } + + public function clearLastError(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearLastError(...\func_get_args()); + } + + public function endpointId(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->endpointId(...\func_get_args()); + } + + public function getPersistentID(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getPersistentID(...\func_get_args()); + } + + public function socketId(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->socketId(...\func_get_args()); + } + + public function rawCommand($cmd, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawCommand(...\func_get_args()); + } + + public function select($db): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); + } + + public function auth(#[\SensitiveParameter] $auth): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->auth(...\func_get_args()); + } + + public function info(...$sections): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->info(...\func_get_args()); + } + + public function flushdb($sync = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushdb(...\func_get_args()); + } + + public function flushall($sync = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->flushall(...\func_get_args()); + } + + public function fcall($name, $keys = [], $argv = [], $handler = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->fcall(...\func_get_args()); + } + + public function fcall_ro($name, $keys = [], $argv = [], $handler = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->fcall_ro(...\func_get_args()); + } + + public function function($op, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->function(...\func_get_args()); + } + + public function dbsize(): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbsize(...\func_get_args()); + } + + public function dump($key): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function replicaof($host = null, $port = 0): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->replicaof(...\func_get_args()); + } + + public function waitaof($numlocal, $numremote, $timeout): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->waitaof(...\func_get_args()); + } + + public function restore($key, $ttl, $value, $options = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->restore(...\func_get_args()); + } + + public function migrate($host, $port, $key, $dstdb, $timeout, $copy = false, $replace = false, #[\SensitiveParameter] $credentials = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->migrate(...\func_get_args()); + } + + public function echo($arg): \Relay\Relay|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->echo(...\func_get_args()); + } + + public function ping($arg = null): \Relay\Relay|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ping(...\func_get_args()); + } + + public function idleTime(): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->idleTime(...\func_get_args()); + } + + public function randomkey(): \Relay\Relay|bool|null|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->randomkey(...\func_get_args()); + } + + public function time(): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->time(...\func_get_args()); + } + + public function bgrewriteaof(): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgrewriteaof(...\func_get_args()); + } + + public function lastsave(): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lastsave(...\func_get_args()); + } + + public function lcs($key1, $key2, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lcs(...\func_get_args()); + } + + public function bgsave($schedule = false): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); + } + + public function save(): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); + } + + public function role(): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->role(...\func_get_args()); + } + + public function ttl($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ttl(...\func_get_args()); + } + + public function pttl($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pttl(...\func_get_args()); + } + + public function exists(...$keys): \Relay\Relay|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exists(...\func_get_args()); + } + + public function eval($script, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval(...\func_get_args()); + } + + public function eval_ro($script, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->eval_ro(...\func_get_args()); + } + + public function evalsha($sha, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha(...\func_get_args()); + } + + public function evalsha_ro($sha, $args = [], $num_keys = 0): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->evalsha_ro(...\func_get_args()); + } + + public function client($operation, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->client(...\func_get_args()); + } + + public function geoadd($key, $lng, $lat, $member, ...$other_triples_and_options): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function geohash($key, $member, ...$other_members): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); + } + + public function georadius($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius(...\func_get_args()); + } + + public function georadiusbymember($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember(...\func_get_args()); + } + + public function georadiusbymember_ro($key, $member, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadiusbymember_ro(...\func_get_args()); + } + + public function georadius_ro($key, $lng, $lat, $radius, $unit, $options = []): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); + } + + public function geosearch($key, $position, $shape, $unit, $options = []): \Relay\Relay|array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); + } + + public function geosearchstore($dst, $src, $position, $shape, $unit, $options = []): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearchstore(...\func_get_args()); + } + + public function get($key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->get(...\func_get_args()); + } + + public function getset($key, $value): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getset(...\func_get_args()); + } + + public function getrange($key, $start, $end): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); + } + + public function setrange($key, $start, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setrange(...\func_get_args()); + } + + public function getbit($key, $pos): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getbit(...\func_get_args()); + } + + public function bitcount($key, $start = 0, $end = -1, $by_bit = false): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitcount(...\func_get_args()); + } + + public function bitfield($key, ...$args): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitfield(...\func_get_args()); + } + + public function config($operation, $key = null, $value = null): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->config(...\func_get_args()); + } + + public function command(...$args): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->command(...\func_get_args()); + } + + public function bitop($operation, $dstkey, $srckey, ...$other_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitop(...\func_get_args()); + } + + public function bitpos($key, $bit, $start = null, $end = null, $bybit = false): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bitpos(...\func_get_args()); + } + + public function setbit($key, $pos, $val): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setbit(...\func_get_args()); + } + + public function acl($cmd, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->acl(...\func_get_args()); + } + + public function append($key, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->append(...\func_get_args()); + } + + public function set($key, $value, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->set(...\func_get_args()); + } + + public function getex($key, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getex(...\func_get_args()); + } + + public function getdel($key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getdel(...\func_get_args()); + } + + public function setex($key, $seconds, $value): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setex(...\func_get_args()); + } + + public function pfadd($key, $elements): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); + } + + public function pfcount($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + + public function pfmerge($dst, $srckeys): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); + } + + public function psetex($key, $milliseconds, $value): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psetex(...\func_get_args()); + } + + public function publish($channel, $message): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); + } + + public function pubsub($operation, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + + public function spublish($channel, $message): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->spublish(...\func_get_args()); + } + + public function setnx($key, $value): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setnx(...\func_get_args()); + } + + public function mget($keys): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mget(...\func_get_args()); + } + + public function move($key, $db): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->move(...\func_get_args()); + } + + public function mset($kvals): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->mset(...\func_get_args()); + } + + public function msetnx($kvals): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetnx(...\func_get_args()); + } + + public function rename($key, $newkey): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rename(...\func_get_args()); + } + + public function renamenx($key, $newkey): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->renamenx(...\func_get_args()); + } + + public function del(...$keys): \Relay\Relay|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->del(...\func_get_args()); + } + + public function unlink(...$keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unlink(...\func_get_args()); + } + + public function expire($key, $seconds, $mode = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expire(...\func_get_args()); + } + + public function pexpire($key, $milliseconds): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpire(...\func_get_args()); + } + + public function expireat($key, $timestamp): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expireat(...\func_get_args()); + } + + public function expiretime($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expiretime(...\func_get_args()); + } + + public function pexpireat($key, $timestamp_ms): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpireat(...\func_get_args()); + } + + public function pexpiretime($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pexpiretime(...\func_get_args()); + } + + public function persist($key): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->persist(...\func_get_args()); + } + + public function type($key): \Relay\Relay|bool|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); + } + + public function lmove($srckey, $dstkey, $srcpos, $dstpos): \Relay\Relay|false|null|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmove(...\func_get_args()); + } + + public function blmove($srckey, $dstkey, $srcpos, $dstpos, $timeout): \Relay\Relay|false|null|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); + } + + public function lrange($key, $start, $stop): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); + } + + public function lpush($key, $mem, ...$mems): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpush(...\func_get_args()); + } + + public function rpush($key, $mem, ...$mems): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpush(...\func_get_args()); + } + + public function lpushx($key, $mem, ...$mems): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpushx(...\func_get_args()); + } + + public function rpushx($key, $mem, ...$mems): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpushx(...\func_get_args()); + } + + public function lset($key, $index, $mem): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lset(...\func_get_args()); + } + + public function lpop($key, $count = 1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpop(...\func_get_args()); + } + + public function lpos($key, $value, $options = null): \Relay\Relay|array|false|int|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lpos(...\func_get_args()); + } + + public function rpop($key, $count = 1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpop(...\func_get_args()); + } + + public function rpoplpush($source, $dest): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rpoplpush(...\func_get_args()); + } + + public function brpoplpush($source, $dest, $timeout): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpoplpush(...\func_get_args()); + } + + public function blpop($key, $timeout_or_key, ...$extra_args): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blpop(...\func_get_args()); + } + + public function blmpop($timeout, $keys, $from, $count = 1): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmpop(...\func_get_args()); + } + + public function bzmpop($timeout, $keys, $from, $count = 1): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzmpop(...\func_get_args()); + } + + public function lmpop($keys, $from, $count = 1): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmpop(...\func_get_args()); + } + + public function zmpop($keys, $from, $count = 1): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmpop(...\func_get_args()); + } + + public function brpop($key, $timeout_or_key, ...$extra_args): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->brpop(...\func_get_args()); + } + + public function bzpopmax($key, $timeout_or_key, ...$extra_args): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmax(...\func_get_args()); + } + + public function bzpopmin($key, $timeout_or_key, ...$extra_args): \Relay\Relay|array|false|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bzpopmin(...\func_get_args()); + } + + public function object($op, $key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->object(...\func_get_args()); + } + + public function geopos($key, ...$members): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geopos(...\func_get_args()); + } + + public function lrem($key, $mem, $count = 0): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrem(...\func_get_args()); + } + + public function lindex($key, $index): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lindex(...\func_get_args()); + } + + public function linsert($key, $op, $pivot, $element): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->linsert(...\func_get_args()); + } + + public function ltrim($key, $start, $end): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ltrim(...\func_get_args()); + } + + public function hget($hash, $member): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hget(...\func_get_args()); + } + + public function hstrlen($hash, $member): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hstrlen(...\func_get_args()); + } + + public function hgetall($hash): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetall(...\func_get_args()); + } + + public function hkeys($hash): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hkeys(...\func_get_args()); + } + + public function hvals($hash): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hvals(...\func_get_args()); + } + + public function hmget($hash, $members): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmget(...\func_get_args()); + } + + public function hrandfield($hash, $options = null): \Relay\Relay|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hrandfield(...\func_get_args()); + } + + public function hmset($hash, $members): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmset(...\func_get_args()); + } + + public function hexists($hash, $member): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexists(...\func_get_args()); + } + + public function hsetnx($hash, $member, $value): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetnx(...\func_get_args()); + } + + public function hset($key, $mem, $val, ...$kvals): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); + } + + public function hdel($key, $mem, ...$mems): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hdel(...\func_get_args()); + } + + public function hincrby($key, $mem, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrby(...\func_get_args()); + } + + public function hincrbyfloat($key, $mem, $value): \Relay\Relay|bool|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hincrbyfloat(...\func_get_args()); + } + + public function incr($key, $by = 1): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incr(...\func_get_args()); + } + + public function decr($key, $by = 1): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decr(...\func_get_args()); + } + + public function incrby($key, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrby(...\func_get_args()); + } + + public function decrby($key, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->decrby(...\func_get_args()); + } + + public function incrbyfloat($key, $value): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->incrbyfloat(...\func_get_args()); + } + + public function sdiff($key, ...$other_keys): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiff(...\func_get_args()); + } + + public function sdiffstore($key, ...$other_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sdiffstore(...\func_get_args()); + } + + public function sinter($key, ...$other_keys): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinter(...\func_get_args()); + } + + public function sintercard($keys, $limit = -1): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sintercard(...\func_get_args()); + } + + public function sinterstore($key, ...$other_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sinterstore(...\func_get_args()); + } + + public function sunion($key, ...$other_keys): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunion(...\func_get_args()); + } + + public function sunionstore($key, ...$other_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunionstore(...\func_get_args()); + } + + public function subscribe($channels, $callback): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->subscribe(...\func_get_args()); + } + + public function unsubscribe($channels = []): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unsubscribe(...\func_get_args()); + } + + public function psubscribe($patterns, $callback): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->psubscribe(...\func_get_args()); + } + + public function punsubscribe($patterns = []): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->punsubscribe(...\func_get_args()); + } + + public function ssubscribe($channels, $callback): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ssubscribe(...\func_get_args()); + } + + public function sunsubscribe($channels = []): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sunsubscribe(...\func_get_args()); + } + + public function touch($key_or_array, ...$more_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->touch(...\func_get_args()); + } + + public function pipeline(): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pipeline(...\func_get_args()); + } + + public function multi($mode = 0): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->multi(...\func_get_args()); + } + + public function exec(): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->exec(...\func_get_args()); + } + + public function wait($replicas, $timeout): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->wait(...\func_get_args()); + } + + public function watch($key, ...$other_keys): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + + public function unwatch(): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); + } + + public function discard(): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->discard(...\func_get_args()); + } + + public function getMode($masked = false): int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getMode(...\func_get_args()); + } + + public function clearBytes(): void + { + ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->clearBytes(...\func_get_args()); + } + + public function scan(&$iterator, $match = null, $count = 0, $type = null): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); + } + + public function hscan($key, &$iterator, $match = null, $count = 0): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function sscan($key, &$iterator, $match = null, $count = 0): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function zscan($key, &$iterator, $match = null, $count = 0): array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); + } + + public function keys($pattern): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->keys(...\func_get_args()); + } + + public function slowlog($operation, ...$extra_args): \Relay\Relay|array|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->slowlog(...\func_get_args()); + } + + public function smembers($set): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smembers(...\func_get_args()); + } + + public function sismember($set, $member): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sismember(...\func_get_args()); + } + + public function smismember($set, ...$members): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smismember(...\func_get_args()); + } + + public function srem($set, $member, ...$members): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srem(...\func_get_args()); + } + + public function sadd($set, $member, ...$members): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sadd(...\func_get_args()); + } + + public function sort($key, $options = []): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort(...\func_get_args()); + } + + public function sort_ro($key, $options = []): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sort_ro(...\func_get_args()); + } + + public function smove($srcset, $dstset, $member): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->smove(...\func_get_args()); + } + + public function spop($set, $count = 1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->spop(...\func_get_args()); + } + + public function srandmember($set, $count = 1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->srandmember(...\func_get_args()); + } + + public function scard($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scard(...\func_get_args()); + } + + public function script($command, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->script(...\func_get_args()); + } + + public function strlen($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->strlen(...\func_get_args()); + } + + public function hlen($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hlen(...\func_get_args()); + } + + public function llen($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->llen(...\func_get_args()); + } + + public function xack($key, $group, $ids): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); + } + + public function xadd($key, $id, $values, $maxlen = 0, $approx = false, $nomkstream = false): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function xclaim($key, $group, $consumer, $min_idle, $ids, $options): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); + } + + public function xautoclaim($key, $group, $consumer, $min_idle, $start, $count = -1, $justid = false): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xautoclaim(...\func_get_args()); + } + + public function xlen($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xlen(...\func_get_args()); + } + + public function xgroup($operation, $key = null, $group = null, $id_or_consumer = null, $mkstream = false, $entries_read = -2): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xgroup(...\func_get_args()); + } + + public function xdel($key, $ids): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdel(...\func_get_args()); + } + + public function xinfo($operation, $arg1 = null, $arg2 = null, $count = -1): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xinfo(...\func_get_args()); + } + + public function xpending($key, $group, $start = null, $end = null, $count = -1, $consumer = null, $idle = 0): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xpending(...\func_get_args()); + } + + public function xrange($key, $start, $end, $count = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrange(...\func_get_args()); + } + + public function xrevrange($key, $end, $start, $count = -1): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xrevrange(...\func_get_args()); + } + + public function xread($streams, $count = -1, $block = -1): \Relay\Relay|array|bool|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xread(...\func_get_args()); + } + + public function xreadgroup($group, $consumer, $streams, $count = 1, $block = 1): \Relay\Relay|array|bool|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xreadgroup(...\func_get_args()); + } + + public function xtrim($key, $threshold, $approx = false, $minid = false, $limit = -1): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xtrim(...\func_get_args()); + } + + public function zadd($key, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zadd(...\func_get_args()); + } + + public function zrandmember($key, $options = null): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrandmember(...\func_get_args()); + } + + public function zrange($key, $start, $end, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrange(...\func_get_args()); + } + + public function zrevrange($key, $start, $end, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrange(...\func_get_args()); + } + + public function zrangebyscore($key, $start, $end, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebyscore(...\func_get_args()); + } + + public function zrevrangebyscore($key, $start, $end, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebyscore(...\func_get_args()); + } + + public function zrangestore($dst, $src, $start, $end, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangestore(...\func_get_args()); + } + + public function zrangebylex($key, $min, $max, $offset = -1, $count = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrangebylex(...\func_get_args()); + } + + public function zrevrangebylex($key, $max, $min, $offset = -1, $count = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebylex(...\func_get_args()); + } + + public function zrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); + } + + public function zrevrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); + } + + public function zrem($key, ...$args): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrem(...\func_get_args()); + } + + public function zremrangebylex($key, $min, $max): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebylex(...\func_get_args()); + } + + public function zremrangebyrank($key, $start, $end): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyrank(...\func_get_args()); + } + + public function zremrangebyscore($key, $min, $max): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zremrangebyscore(...\func_get_args()); + } + + public function zcard($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcard(...\func_get_args()); + } + + public function zcount($key, $min, $max): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zcount(...\func_get_args()); + } + + public function zdiff($keys, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiff(...\func_get_args()); + } + + public function zdiffstore($dst, $keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zdiffstore(...\func_get_args()); + } + + public function zincrby($key, $score, $mem): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zincrby(...\func_get_args()); + } + + public function zlexcount($key, $min, $max): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zlexcount(...\func_get_args()); + } + + public function zmscore($key, ...$mems): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmscore(...\func_get_args()); + } + + public function zscore($key, $member): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); + } + + public function zinter($keys, $weights = null, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinter(...\func_get_args()); + } + + public function zintercard($keys, $limit = -1): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zintercard(...\func_get_args()); + } + + public function zinterstore($dst, $keys, $weights = null, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinterstore(...\func_get_args()); + } + + public function zunion($keys, $weights = null, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunion(...\func_get_args()); + } + + public function zunionstore($dst, $keys, $weights = null, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zunionstore(...\func_get_args()); + } + + public function zpopmin($key, $count = 1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmin(...\func_get_args()); + } + + public function zpopmax($key, $count = 1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zpopmax(...\func_get_args()); + } + + public function _getKeys() + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_getKeys(...\func_get_args()); + } +} diff --git a/vendor/symfony/cache/Traits/RelayProxyTrait.php b/vendor/symfony/cache/Traits/RelayProxyTrait.php new file mode 100644 index 000000000..a1d252b96 --- /dev/null +++ b/vendor/symfony/cache/Traits/RelayProxyTrait.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('relay'), '0.8.1', '>=')) { + /** + * @internal + */ + trait RelayProxyTrait + { + public function copy($src, $dst, $options = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + + public function jsonArrAppend($key, $value_or_array, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrAppend(...\func_get_args()); + } + + public function jsonArrIndex($key, $path, $value, $start = 0, $stop = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrIndex(...\func_get_args()); + } + + public function jsonArrInsert($key, $path, $index, $value, ...$other_values): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrInsert(...\func_get_args()); + } + + public function jsonArrLen($key, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrLen(...\func_get_args()); + } + + public function jsonArrPop($key, $path = null, $index = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrPop(...\func_get_args()); + } + + public function jsonArrTrim($key, $path, $start, $stop): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrTrim(...\func_get_args()); + } + + public function jsonClear($key, $path = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonClear(...\func_get_args()); + } + + public function jsonDebug($command, $key, $path = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonDebug(...\func_get_args()); + } + + public function jsonDel($key, $path = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonDel(...\func_get_args()); + } + + public function jsonForget($key, $path = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonForget(...\func_get_args()); + } + + public function jsonGet($key, $options = [], ...$paths): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonGet(...\func_get_args()); + } + + public function jsonMerge($key, $path, $value): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonMerge(...\func_get_args()); + } + + public function jsonMget($key_or_array, $path): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonMget(...\func_get_args()); + } + + public function jsonMset($key, $path, $value, ...$other_triples): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonMset(...\func_get_args()); + } + + public function jsonNumIncrBy($key, $path, $value): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonNumIncrBy(...\func_get_args()); + } + + public function jsonNumMultBy($key, $path, $value): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonNumMultBy(...\func_get_args()); + } + + public function jsonObjKeys($key, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonObjKeys(...\func_get_args()); + } + + public function jsonObjLen($key, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonObjLen(...\func_get_args()); + } + + public function jsonResp($key, $path = null): \Relay\Relay|array|false|int|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonResp(...\func_get_args()); + } + + public function jsonSet($key, $path, $value, $condition = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonSet(...\func_get_args()); + } + + public function jsonStrAppend($key, $value, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonStrAppend(...\func_get_args()); + } + + public function jsonStrLen($key, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonStrLen(...\func_get_args()); + } + + public function jsonToggle($key, $path): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonToggle(...\func_get_args()); + } + + public function jsonType($key, $path = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonType(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait RelayProxyTrait + { + public function copy($src, $dst, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + } +} diff --git a/vendor/symfony/cache/Traits/ValueWrapper.php b/vendor/symfony/cache/Traits/ValueWrapper.php new file mode 100644 index 000000000..718a23d39 --- /dev/null +++ b/vendor/symfony/cache/Traits/ValueWrapper.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * A short namespace-less class to serialize items with metadata. + * + * @author Nicolas Grekas + * + * @internal + */ +class +{ + private const EXPIRY_OFFSET = 1648206727; + private const INT32_MAX = 2147483647; + + public readonly mixed $value; + public readonly array $metadata; + + public function __construct(mixed $value, array $metadata) + { + $this->value = $value; + $this->metadata = $metadata; + } + + public function __serialize(): array + { + // pack 31-bits ctime into 14bits + $c = $this->metadata['ctime'] ?? 0; + $c = match (true) { + $c > self::INT32_MAX - 2 => self::INT32_MAX, + $c > 0 => 1 + $c, + default => 1, + }; + $e = 0; + while (!(0x40000000 & $c)) { + $c <<= 1; + ++$e; + } + $c = (0x7FE0 & ($c >> 16)) | $e; + + $pack = pack('Vn', (int) (0.1 + ($this->metadata['expiry'] ?: self::INT32_MAX + self::EXPIRY_OFFSET) - self::EXPIRY_OFFSET), $c); + + if (isset($this->metadata['tags'])) { + $pack[4] = $pack[4] | "\x80"; + } + + return [$pack => $this->value] + ($this->metadata['tags'] ?? []); + } + + public function __unserialize(array $data): void + { + $pack = array_key_first($data); + $this->value = $data[$pack]; + + if ($hasTags = "\x80" === ($pack[4] & "\x80")) { + unset($data[$pack]); + $pack[4] = $pack[4] & "\x7F"; + } + + $metadata = unpack('Vexpiry/nctime', $pack); + $metadata['expiry'] += self::EXPIRY_OFFSET; + + if (!$metadata['ctime'] = ((0x4000 | $metadata['ctime']) << 16 >> (0x1F & $metadata['ctime'])) - 1) { + unset($metadata['ctime']); + } + + if ($hasTags) { + $metadata['tags'] = $data; + } + + $this->metadata = $metadata; + } +} diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json new file mode 100644 index 000000000..af743b463 --- /dev/null +++ b/vendor/symfony/cache/composer.json @@ -0,0 +1,59 @@ +{ + "name": "symfony/cache", + "type": "library", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "keywords": ["caching", "psr6"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.3.6|^7.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/var-dumper": "<5.4" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Cache\\": "" }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/vendor/symfony/css-selector/CHANGELOG.md b/vendor/symfony/css-selector/CHANGELOG.md new file mode 100644 index 000000000..c035d6b3d --- /dev/null +++ b/vendor/symfony/css-selector/CHANGELOG.md @@ -0,0 +1,23 @@ +CHANGELOG +========= + +6.3 +----- + + * Add support for `:scope` + +4.4.0 +----- + + * Added support for `*:only-of-type` + +2.8.0 +----- + + * Added the `CssSelectorConverter` class as a non-static API for the component. + * Deprecated the `CssSelector` static API of the component. + +2.1.0 +----- + + * none diff --git a/vendor/symfony/css-selector/CssSelectorConverter.php b/vendor/symfony/css-selector/CssSelectorConverter.php new file mode 100644 index 000000000..7120a2950 --- /dev/null +++ b/vendor/symfony/css-selector/CssSelectorConverter.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector; + +use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser; +use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser; +use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser; +use Symfony\Component\CssSelector\Parser\Shortcut\HashParser; +use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension; +use Symfony\Component\CssSelector\XPath\Translator; + +/** + * CssSelectorConverter is the main entry point of the component and can convert CSS + * selectors to XPath expressions. + * + * @author Christophe Coevoet + */ +class CssSelectorConverter +{ + private Translator $translator; + private array $cache; + + private static array $xmlCache = []; + private static array $htmlCache = []; + + /** + * @param bool $html Whether HTML support should be enabled. Disable it for XML documents + */ + public function __construct(bool $html = true) + { + $this->translator = new Translator(); + + if ($html) { + $this->translator->registerExtension(new HtmlExtension($this->translator)); + $this->cache = &self::$htmlCache; + } else { + $this->cache = &self::$xmlCache; + } + + $this->translator + ->registerParserShortcut(new EmptyStringParser()) + ->registerParserShortcut(new ElementParser()) + ->registerParserShortcut(new ClassParser()) + ->registerParserShortcut(new HashParser()) + ; + } + + /** + * Translates a CSS expression to its XPath equivalent. + * + * Optionally, a prefix can be added to the resulting XPath + * expression with the $prefix parameter. + */ + public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string + { + return $this->cache[$prefix][$cssExpr] ??= $this->translator->cssToXPath($cssExpr, $prefix); + } +} diff --git a/vendor/symfony/css-selector/Exception/ExceptionInterface.php b/vendor/symfony/css-selector/Exception/ExceptionInterface.php new file mode 100644 index 000000000..9e259006b --- /dev/null +++ b/vendor/symfony/css-selector/Exception/ExceptionInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Exception; + +/** + * Interface for exceptions. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/css-selector/Exception/ExpressionErrorException.php b/vendor/symfony/css-selector/Exception/ExpressionErrorException.php new file mode 100644 index 000000000..fd5deeabe --- /dev/null +++ b/vendor/symfony/css-selector/Exception/ExpressionErrorException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Exception; + +/** + * ParseException is thrown when a CSS selector syntax is not valid. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + */ +class ExpressionErrorException extends ParseException +{ +} diff --git a/vendor/symfony/css-selector/Exception/InternalErrorException.php b/vendor/symfony/css-selector/Exception/InternalErrorException.php new file mode 100644 index 000000000..e60e5ed0f --- /dev/null +++ b/vendor/symfony/css-selector/Exception/InternalErrorException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Exception; + +/** + * ParseException is thrown when a CSS selector syntax is not valid. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + */ +class InternalErrorException extends ParseException +{ +} diff --git a/vendor/symfony/css-selector/Exception/ParseException.php b/vendor/symfony/css-selector/Exception/ParseException.php new file mode 100644 index 000000000..3b0b0ee8f --- /dev/null +++ b/vendor/symfony/css-selector/Exception/ParseException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Exception; + +/** + * ParseException is thrown when a CSS selector syntax is not valid. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Fabien Potencier + */ +class ParseException extends \Exception implements ExceptionInterface +{ +} diff --git a/vendor/symfony/css-selector/Exception/SyntaxErrorException.php b/vendor/symfony/css-selector/Exception/SyntaxErrorException.php new file mode 100644 index 000000000..5a9d8078d --- /dev/null +++ b/vendor/symfony/css-selector/Exception/SyntaxErrorException.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Exception; + +use Symfony\Component\CssSelector\Parser\Token; + +/** + * ParseException is thrown when a CSS selector syntax is not valid. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + */ +class SyntaxErrorException extends ParseException +{ + public static function unexpectedToken(string $expectedValue, Token $foundToken): self + { + return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken)); + } + + public static function pseudoElementFound(string $pseudoElement, string $unexpectedLocation): self + { + return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation)); + } + + public static function unclosedString(int $position): self + { + return new self(sprintf('Unclosed/invalid string at %s.', $position)); + } + + public static function nestedNot(): self + { + return new self('Got nested ::not().'); + } + + public static function notAtTheStartOfASelector(string $pseudoElement): self + { + return new self(sprintf('Got immediate child pseudo-element ":%s" not at the start of a selector', $pseudoElement)); + } + + public static function stringAsFunctionArgument(): self + { + return new self('String not allowed as function argument.'); + } +} diff --git a/vendor/symfony/css-selector/LICENSE b/vendor/symfony/css-selector/LICENSE new file mode 100644 index 000000000..0138f8f07 --- /dev/null +++ b/vendor/symfony/css-selector/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +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. diff --git a/vendor/symfony/css-selector/Node/AbstractNode.php b/vendor/symfony/css-selector/Node/AbstractNode.php new file mode 100644 index 000000000..d99e80a87 --- /dev/null +++ b/vendor/symfony/css-selector/Node/AbstractNode.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Abstract base node class. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +abstract class AbstractNode implements NodeInterface +{ + private string $nodeName; + + public function getNodeName(): string + { + return $this->nodeName ??= preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class); + } +} diff --git a/vendor/symfony/css-selector/Node/AttributeNode.php b/vendor/symfony/css-selector/Node/AttributeNode.php new file mode 100644 index 000000000..ba4df3100 --- /dev/null +++ b/vendor/symfony/css-selector/Node/AttributeNode.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a "[| ]" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class AttributeNode extends AbstractNode +{ + private NodeInterface $selector; + private ?string $namespace; + private string $attribute; + private string $operator; + private ?string $value; + + public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value) + { + $this->selector = $selector; + $this->namespace = $namespace; + $this->attribute = $attribute; + $this->operator = $operator; + $this->value = $value; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getNamespace(): ?string + { + return $this->namespace; + } + + public function getAttribute(): string + { + return $this->attribute; + } + + public function getOperator(): string + { + return $this->operator; + } + + public function getValue(): ?string + { + return $this->value; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); + } + + public function __toString(): string + { + $attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute; + + return 'exists' === $this->operator + ? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute) + : sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value); + } +} diff --git a/vendor/symfony/css-selector/Node/ClassNode.php b/vendor/symfony/css-selector/Node/ClassNode.php new file mode 100644 index 000000000..717445870 --- /dev/null +++ b/vendor/symfony/css-selector/Node/ClassNode.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a "." node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class ClassNode extends AbstractNode +{ + private NodeInterface $selector; + private string $name; + + public function __construct(NodeInterface $selector, string $name) + { + $this->selector = $selector; + $this->name = $name; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getName(): string + { + return $this->name; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); + } + + public function __toString(): string + { + return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name); + } +} diff --git a/vendor/symfony/css-selector/Node/CombinedSelectorNode.php b/vendor/symfony/css-selector/Node/CombinedSelectorNode.php new file mode 100644 index 000000000..19fecb700 --- /dev/null +++ b/vendor/symfony/css-selector/Node/CombinedSelectorNode.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a combined node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class CombinedSelectorNode extends AbstractNode +{ + private NodeInterface $selector; + private string $combinator; + private NodeInterface $subSelector; + + public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector) + { + $this->selector = $selector; + $this->combinator = $combinator; + $this->subSelector = $subSelector; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getCombinator(): string + { + return $this->combinator; + } + + public function getSubSelector(): NodeInterface + { + return $this->subSelector; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); + } + + public function __toString(): string + { + $combinator = ' ' === $this->combinator ? '' : $this->combinator; + + return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector); + } +} diff --git a/vendor/symfony/css-selector/Node/ElementNode.php b/vendor/symfony/css-selector/Node/ElementNode.php new file mode 100644 index 000000000..76d2078ea --- /dev/null +++ b/vendor/symfony/css-selector/Node/ElementNode.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a "|" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class ElementNode extends AbstractNode +{ + private ?string $namespace; + private ?string $element; + + public function __construct(?string $namespace = null, ?string $element = null) + { + $this->namespace = $namespace; + $this->element = $element; + } + + public function getNamespace(): ?string + { + return $this->namespace; + } + + public function getElement(): ?string + { + return $this->element; + } + + public function getSpecificity(): Specificity + { + return new Specificity(0, 0, $this->element ? 1 : 0); + } + + public function __toString(): string + { + $element = $this->element ?: '*'; + + return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element); + } +} diff --git a/vendor/symfony/css-selector/Node/FunctionNode.php b/vendor/symfony/css-selector/Node/FunctionNode.php new file mode 100644 index 000000000..938a82b1a --- /dev/null +++ b/vendor/symfony/css-selector/Node/FunctionNode.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +use Symfony\Component\CssSelector\Parser\Token; + +/** + * Represents a ":()" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class FunctionNode extends AbstractNode +{ + private NodeInterface $selector; + private string $name; + private array $arguments; + + /** + * @param Token[] $arguments + */ + public function __construct(NodeInterface $selector, string $name, array $arguments = []) + { + $this->selector = $selector; + $this->name = strtolower($name); + $this->arguments = $arguments; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getName(): string + { + return $this->name; + } + + /** + * @return Token[] + */ + public function getArguments(): array + { + return $this->arguments; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); + } + + public function __toString(): string + { + $arguments = implode(', ', array_map(fn (Token $token) => "'".$token->getValue()."'", $this->arguments)); + + return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : ''); + } +} diff --git a/vendor/symfony/css-selector/Node/HashNode.php b/vendor/symfony/css-selector/Node/HashNode.php new file mode 100644 index 000000000..3af8e8474 --- /dev/null +++ b/vendor/symfony/css-selector/Node/HashNode.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a "#" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class HashNode extends AbstractNode +{ + private NodeInterface $selector; + private string $id; + + public function __construct(NodeInterface $selector, string $id) + { + $this->selector = $selector; + $this->id = $id; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getId(): string + { + return $this->id; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0)); + } + + public function __toString(): string + { + return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id); + } +} diff --git a/vendor/symfony/css-selector/Node/NegationNode.php b/vendor/symfony/css-selector/Node/NegationNode.php new file mode 100644 index 000000000..f80675838 --- /dev/null +++ b/vendor/symfony/css-selector/Node/NegationNode.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a ":not()" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class NegationNode extends AbstractNode +{ + private NodeInterface $selector; + private NodeInterface $subSelector; + + public function __construct(NodeInterface $selector, NodeInterface $subSelector) + { + $this->selector = $selector; + $this->subSelector = $subSelector; + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getSubSelector(): NodeInterface + { + return $this->subSelector; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); + } + + public function __toString(): string + { + return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector); + } +} diff --git a/vendor/symfony/css-selector/Node/NodeInterface.php b/vendor/symfony/css-selector/Node/NodeInterface.php new file mode 100644 index 000000000..7d541f9c8 --- /dev/null +++ b/vendor/symfony/css-selector/Node/NodeInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Interface for nodes. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +interface NodeInterface extends \Stringable +{ + public function getNodeName(): string; + + public function getSpecificity(): Specificity; +} diff --git a/vendor/symfony/css-selector/Node/PseudoNode.php b/vendor/symfony/css-selector/Node/PseudoNode.php new file mode 100644 index 000000000..c21cd6e92 --- /dev/null +++ b/vendor/symfony/css-selector/Node/PseudoNode.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a ":" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class PseudoNode extends AbstractNode +{ + private NodeInterface $selector; + private string $identifier; + + public function __construct(NodeInterface $selector, string $identifier) + { + $this->selector = $selector; + $this->identifier = strtolower($identifier); + } + + public function getSelector(): NodeInterface + { + return $this->selector; + } + + public function getIdentifier(): string + { + return $this->identifier; + } + + public function getSpecificity(): Specificity + { + return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); + } + + public function __toString(): string + { + return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier); + } +} diff --git a/vendor/symfony/css-selector/Node/SelectorNode.php b/vendor/symfony/css-selector/Node/SelectorNode.php new file mode 100644 index 000000000..2318b2bf2 --- /dev/null +++ b/vendor/symfony/css-selector/Node/SelectorNode.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a "(::|:)" node. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class SelectorNode extends AbstractNode +{ + private NodeInterface $tree; + private ?string $pseudoElement; + + public function __construct(NodeInterface $tree, ?string $pseudoElement = null) + { + $this->tree = $tree; + $this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null; + } + + public function getTree(): NodeInterface + { + return $this->tree; + } + + public function getPseudoElement(): ?string + { + return $this->pseudoElement; + } + + public function getSpecificity(): Specificity + { + return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0)); + } + + public function __toString(): string + { + return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : ''); + } +} diff --git a/vendor/symfony/css-selector/Node/Specificity.php b/vendor/symfony/css-selector/Node/Specificity.php new file mode 100644 index 000000000..bb8e5e346 --- /dev/null +++ b/vendor/symfony/css-selector/Node/Specificity.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Node; + +/** + * Represents a node specificity. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @see http://www.w3.org/TR/selectors/#specificity + * + * @author Jean-François Simon + * + * @internal + */ +class Specificity +{ + public const A_FACTOR = 100; + public const B_FACTOR = 10; + public const C_FACTOR = 1; + + private int $a; + private int $b; + private int $c; + + public function __construct(int $a, int $b, int $c) + { + $this->a = $a; + $this->b = $b; + $this->c = $c; + } + + public function plus(self $specificity): self + { + return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c); + } + + public function getValue(): int + { + return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR; + } + + /** + * Returns -1 if the object specificity is lower than the argument, + * 0 if they are equal, and 1 if the argument is lower. + */ + public function compareTo(self $specificity): int + { + if ($this->a !== $specificity->a) { + return $this->a > $specificity->a ? 1 : -1; + } + + if ($this->b !== $specificity->b) { + return $this->b > $specificity->b ? 1 : -1; + } + + if ($this->c !== $specificity->c) { + return $this->c > $specificity->c ? 1 : -1; + } + + return 0; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php b/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php new file mode 100644 index 000000000..cc01d1e6e --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector comment handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class CommentHandler implements HandlerInterface +{ + public function handle(Reader $reader, TokenStream $stream): bool + { + if ('/*' !== $reader->getSubstring(2)) { + return false; + } + + $offset = $reader->getOffset('*/'); + + if (false === $offset) { + $reader->moveToEnd(); + } else { + $reader->moveForward($offset + 2); + } + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php b/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php new file mode 100644 index 000000000..9ec714d54 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector handler interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +interface HandlerInterface +{ + public function handle(Reader $reader, TokenStream $stream): bool; +} diff --git a/vendor/symfony/css-selector/Parser/Handler/HashHandler.php b/vendor/symfony/css-selector/Parser/Handler/HashHandler.php new file mode 100644 index 000000000..b29042f56 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/HashHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector comment handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class HashHandler implements HandlerInterface +{ + private TokenizerPatterns $patterns; + private TokenizerEscaping $escaping; + + public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) + { + $this->patterns = $patterns; + $this->escaping = $escaping; + } + + public function handle(Reader $reader, TokenStream $stream): bool + { + $match = $reader->findPattern($this->patterns->getHashPattern()); + + if (!$match) { + return false; + } + + $value = $this->escaping->escapeUnicode($match[1]); + $stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition())); + $reader->moveForward(\strlen($match[0])); + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php b/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php new file mode 100644 index 000000000..25c0761e9 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector comment handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class IdentifierHandler implements HandlerInterface +{ + private TokenizerPatterns $patterns; + private TokenizerEscaping $escaping; + + public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) + { + $this->patterns = $patterns; + $this->escaping = $escaping; + } + + public function handle(Reader $reader, TokenStream $stream): bool + { + $match = $reader->findPattern($this->patterns->getIdentifierPattern()); + + if (!$match) { + return false; + } + + $value = $this->escaping->escapeUnicode($match[0]); + $stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition())); + $reader->moveForward(\strlen($match[0])); + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php b/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php new file mode 100644 index 000000000..e3eb7afe3 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector comment handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class NumberHandler implements HandlerInterface +{ + private TokenizerPatterns $patterns; + + public function __construct(TokenizerPatterns $patterns) + { + $this->patterns = $patterns; + } + + public function handle(Reader $reader, TokenStream $stream): bool + { + $match = $reader->findPattern($this->patterns->getNumberPattern()); + + if (!$match) { + return false; + } + + $stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition())); + $reader->moveForward(\strlen($match[0])); + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/StringHandler.php b/vendor/symfony/css-selector/Parser/Handler/StringHandler.php new file mode 100644 index 000000000..5fd44df26 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/StringHandler.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Exception\InternalErrorException; +use Symfony\Component\CssSelector\Exception\SyntaxErrorException; +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; +use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector comment handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class StringHandler implements HandlerInterface +{ + private TokenizerPatterns $patterns; + private TokenizerEscaping $escaping; + + public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) + { + $this->patterns = $patterns; + $this->escaping = $escaping; + } + + public function handle(Reader $reader, TokenStream $stream): bool + { + $quote = $reader->getSubstring(1); + + if (!\in_array($quote, ["'", '"'])) { + return false; + } + + $reader->moveForward(1); + $match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote)); + + if (!$match) { + throw new InternalErrorException(sprintf('Should have found at least an empty match at %d.', $reader->getPosition())); + } + + // check unclosed strings + if (\strlen($match[0]) === $reader->getRemainingLength()) { + throw SyntaxErrorException::unclosedString($reader->getPosition() - 1); + } + + // check quotes pairs validity + if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) { + throw SyntaxErrorException::unclosedString($reader->getPosition() - 1); + } + + $string = $this->escaping->escapeUnicodeAndNewLine($match[0]); + $stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition())); + $reader->moveForward(\strlen($match[0]) + 1); + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php b/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php new file mode 100644 index 000000000..eb41c3f7f --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Handler; + +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector whitespace handler. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class WhitespaceHandler implements HandlerInterface +{ + public function handle(Reader $reader, TokenStream $stream): bool + { + $match = $reader->findPattern('~^[ \t\r\n\f]+~'); + + if (false === $match) { + return false; + } + + $stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition())); + $reader->moveForward(\strlen($match[0])); + + return true; + } +} diff --git a/vendor/symfony/css-selector/Parser/Parser.php b/vendor/symfony/css-selector/Parser/Parser.php new file mode 100644 index 000000000..309c9b521 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Parser.php @@ -0,0 +1,359 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser; + +use Symfony\Component\CssSelector\Exception\SyntaxErrorException; +use Symfony\Component\CssSelector\Node; +use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer; + +/** + * CSS selector parser. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/scrapy/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class Parser implements ParserInterface +{ + private Tokenizer $tokenizer; + + public function __construct(?Tokenizer $tokenizer = null) + { + $this->tokenizer = $tokenizer ?? new Tokenizer(); + } + + public function parse(string $source): array + { + $reader = new Reader($source); + $stream = $this->tokenizer->tokenize($reader); + + return $this->parseSelectorList($stream); + } + + /** + * Parses the arguments for ":nth-child()" and friends. + * + * @param Token[] $tokens + * + * @throws SyntaxErrorException + */ + public static function parseSeries(array $tokens): array + { + foreach ($tokens as $token) { + if ($token->isString()) { + throw SyntaxErrorException::stringAsFunctionArgument(); + } + } + + $joined = trim(implode('', array_map(fn (Token $token) => $token->getValue(), $tokens))); + + $int = function ($string) { + if (!is_numeric($string)) { + throw SyntaxErrorException::stringAsFunctionArgument(); + } + + return (int) $string; + }; + + switch (true) { + case 'odd' === $joined: + return [2, 1]; + case 'even' === $joined: + return [2, 0]; + case 'n' === $joined: + return [1, 0]; + case !str_contains($joined, 'n'): + return [0, $int($joined)]; + } + + $split = explode('n', $joined); + $first = $split[0] ?? null; + + return [ + $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1, + isset($split[1]) && $split[1] ? $int($split[1]) : 0, + ]; + } + + private function parseSelectorList(TokenStream $stream): array + { + $stream->skipWhitespace(); + $selectors = []; + + while (true) { + $selectors[] = $this->parserSelectorNode($stream); + + if ($stream->getPeek()->isDelimiter([','])) { + $stream->getNext(); + $stream->skipWhitespace(); + } else { + break; + } + } + + return $selectors; + } + + private function parserSelectorNode(TokenStream $stream): Node\SelectorNode + { + [$result, $pseudoElement] = $this->parseSimpleSelector($stream); + + while (true) { + $stream->skipWhitespace(); + $peek = $stream->getPeek(); + + if ($peek->isFileEnd() || $peek->isDelimiter([','])) { + break; + } + + if (null !== $pseudoElement) { + throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector'); + } + + if ($peek->isDelimiter(['+', '>', '~'])) { + $combinator = $stream->getNext()->getValue(); + $stream->skipWhitespace(); + } else { + $combinator = ' '; + } + + [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream); + $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector); + } + + return new Node\SelectorNode($result, $pseudoElement); + } + + /** + * Parses next simple node (hash, class, pseudo, negation). + * + * @throws SyntaxErrorException + */ + private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array + { + $stream->skipWhitespace(); + + $selectorStart = \count($stream->getUsed()); + $result = $this->parseElementNode($stream); + $pseudoElement = null; + + while (true) { + $peek = $stream->getPeek(); + if ($peek->isWhitespace() + || $peek->isFileEnd() + || $peek->isDelimiter([',', '+', '>', '~']) + || ($insideNegation && $peek->isDelimiter([')'])) + ) { + break; + } + + if (null !== $pseudoElement) { + throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector'); + } + + if ($peek->isHash()) { + $result = new Node\HashNode($result, $stream->getNext()->getValue()); + } elseif ($peek->isDelimiter(['.'])) { + $stream->getNext(); + $result = new Node\ClassNode($result, $stream->getNextIdentifier()); + } elseif ($peek->isDelimiter(['['])) { + $stream->getNext(); + $result = $this->parseAttributeNode($result, $stream); + } elseif ($peek->isDelimiter([':'])) { + $stream->getNext(); + + if ($stream->getPeek()->isDelimiter([':'])) { + $stream->getNext(); + $pseudoElement = $stream->getNextIdentifier(); + + continue; + } + + $identifier = $stream->getNextIdentifier(); + if (\in_array(strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) { + // Special case: CSS 2.1 pseudo-elements can have a single ':'. + // Any new pseudo-element must have two. + $pseudoElement = $identifier; + + continue; + } + + if (!$stream->getPeek()->isDelimiter(['('])) { + $result = new Node\PseudoNode($result, $identifier); + if ('Pseudo[Element[*]:scope]' === $result->__toString()) { + $used = \count($stream->getUsed()); + if (!(2 === $used + || 3 === $used && $stream->getUsed()[0]->isWhiteSpace() + || $used >= 3 && $stream->getUsed()[$used - 3]->isDelimiter([',']) + || $used >= 4 + && $stream->getUsed()[$used - 3]->isWhiteSpace() + && $stream->getUsed()[$used - 4]->isDelimiter([',']) + )) { + throw SyntaxErrorException::notAtTheStartOfASelector('scope'); + } + } + continue; + } + + $stream->getNext(); + $stream->skipWhitespace(); + + if ('not' === strtolower($identifier)) { + if ($insideNegation) { + throw SyntaxErrorException::nestedNot(); + } + + [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true); + $next = $stream->getNext(); + + if (null !== $argumentPseudoElement) { + throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()'); + } + + if (!$next->isDelimiter([')'])) { + throw SyntaxErrorException::unexpectedToken('")"', $next); + } + + $result = new Node\NegationNode($result, $argument); + } else { + $arguments = []; + $next = null; + + while (true) { + $stream->skipWhitespace(); + $next = $stream->getNext(); + + if ($next->isIdentifier() + || $next->isString() + || $next->isNumber() + || $next->isDelimiter(['+', '-']) + ) { + $arguments[] = $next; + } elseif ($next->isDelimiter([')'])) { + break; + } else { + throw SyntaxErrorException::unexpectedToken('an argument', $next); + } + } + + if (!$arguments) { + throw SyntaxErrorException::unexpectedToken('at least one argument', $next); + } + + $result = new Node\FunctionNode($result, $identifier, $arguments); + } + } else { + throw SyntaxErrorException::unexpectedToken('selector', $peek); + } + } + + if (\count($stream->getUsed()) === $selectorStart) { + throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek()); + } + + return [$result, $pseudoElement]; + } + + private function parseElementNode(TokenStream $stream): Node\ElementNode + { + $peek = $stream->getPeek(); + + if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) { + if ($peek->isIdentifier()) { + $namespace = $stream->getNext()->getValue(); + } else { + $stream->getNext(); + $namespace = null; + } + + if ($stream->getPeek()->isDelimiter(['|'])) { + $stream->getNext(); + $element = $stream->getNextIdentifierOrStar(); + } else { + $element = $namespace; + $namespace = null; + } + } else { + $element = $namespace = null; + } + + return new Node\ElementNode($namespace, $element); + } + + private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode + { + $stream->skipWhitespace(); + $attribute = $stream->getNextIdentifierOrStar(); + + if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) { + throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek()); + } + + if ($stream->getPeek()->isDelimiter(['|'])) { + $stream->getNext(); + + if ($stream->getPeek()->isDelimiter(['='])) { + $namespace = null; + $stream->getNext(); + $operator = '|='; + } else { + $namespace = $attribute; + $attribute = $stream->getNextIdentifier(); + $operator = null; + } + } else { + $namespace = $operator = null; + } + + if (null === $operator) { + $stream->skipWhitespace(); + $next = $stream->getNext(); + + if ($next->isDelimiter([']'])) { + return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null); + } elseif ($next->isDelimiter(['='])) { + $operator = '='; + } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!']) + && $stream->getPeek()->isDelimiter(['=']) + ) { + $operator = $next->getValue().'='; + $stream->getNext(); + } else { + throw SyntaxErrorException::unexpectedToken('operator', $next); + } + } + + $stream->skipWhitespace(); + $value = $stream->getNext(); + + if ($value->isNumber()) { + // if the value is a number, it's casted into a string + $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition()); + } + + if (!($value->isIdentifier() || $value->isString())) { + throw SyntaxErrorException::unexpectedToken('string or identifier', $value); + } + + $stream->skipWhitespace(); + $next = $stream->getNext(); + + if (!$next->isDelimiter([']'])) { + throw SyntaxErrorException::unexpectedToken('"]"', $next); + } + + return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue()); + } +} diff --git a/vendor/symfony/css-selector/Parser/ParserInterface.php b/vendor/symfony/css-selector/Parser/ParserInterface.php new file mode 100644 index 000000000..51c3d9350 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/ParserInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser; + +use Symfony\Component\CssSelector\Node\SelectorNode; + +/** + * CSS selector parser interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +interface ParserInterface +{ + /** + * Parses given selector source into an array of tokens. + * + * @return SelectorNode[] + */ + public function parse(string $source): array; +} diff --git a/vendor/symfony/css-selector/Parser/Reader.php b/vendor/symfony/css-selector/Parser/Reader.php new file mode 100644 index 000000000..7f6ae7a60 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Reader.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser; + +/** + * CSS selector reader. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class Reader +{ + private string $source; + private int $length; + private int $position = 0; + + public function __construct(string $source) + { + $this->source = $source; + $this->length = \strlen($source); + } + + public function isEOF(): bool + { + return $this->position >= $this->length; + } + + public function getPosition(): int + { + return $this->position; + } + + public function getRemainingLength(): int + { + return $this->length - $this->position; + } + + public function getSubstring(int $length, int $offset = 0): string + { + return substr($this->source, $this->position + $offset, $length); + } + + /** + * @return int|false + */ + public function getOffset(string $string): int|bool + { + $position = strpos($this->source, $string, $this->position); + + return false === $position ? false : $position - $this->position; + } + + public function findPattern(string $pattern): array|false + { + $source = substr($this->source, $this->position); + + if (preg_match($pattern, $source, $matches)) { + return $matches; + } + + return false; + } + + public function moveForward(int $length): void + { + $this->position += $length; + } + + public function moveToEnd(): void + { + $this->position = $this->length; + } +} diff --git a/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php b/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php new file mode 100644 index 000000000..f0ce61184 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Shortcut; + +use Symfony\Component\CssSelector\Node\ClassNode; +use Symfony\Component\CssSelector\Node\ElementNode; +use Symfony\Component\CssSelector\Node\SelectorNode; +use Symfony\Component\CssSelector\Parser\ParserInterface; + +/** + * CSS selector class parser shortcut. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class ClassParser implements ParserInterface +{ + public function parse(string $source): array + { + // Matches an optional namespace, optional element, and required class + // $source = 'test|input.ab6bd_field'; + // $matches = array (size=4) + // 0 => string 'test|input.ab6bd_field' (length=22) + // 1 => string 'test' (length=4) + // 2 => string 'input' (length=5) + // 3 => string 'ab6bd_field' (length=11) + if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) { + return [ + new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])), + ]; + } + + return []; + } +} diff --git a/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php b/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php new file mode 100644 index 000000000..a448e4a87 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Shortcut; + +use Symfony\Component\CssSelector\Node\ElementNode; +use Symfony\Component\CssSelector\Node\SelectorNode; +use Symfony\Component\CssSelector\Parser\ParserInterface; + +/** + * CSS selector element parser shortcut. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class ElementParser implements ParserInterface +{ + public function parse(string $source): array + { + // Matches an optional namespace, required element or `*` + // $source = 'testns|testel'; + // $matches = array (size=3) + // 0 => string 'testns|testel' (length=13) + // 1 => string 'testns' (length=6) + // 2 => string 'testel' (length=6) + if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) { + return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))]; + } + + return []; + } +} diff --git a/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php b/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php new file mode 100644 index 000000000..a63919120 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Shortcut; + +use Symfony\Component\CssSelector\Node\ElementNode; +use Symfony\Component\CssSelector\Node\SelectorNode; +use Symfony\Component\CssSelector\Parser\ParserInterface; + +/** + * CSS selector class parser shortcut. + * + * This shortcut ensure compatibility with previous version. + * - The parser fails to parse an empty string. + * - In the previous version, an empty string matches each tags. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class EmptyStringParser implements ParserInterface +{ + public function parse(string $source): array + { + // Matches an empty string + if ('' == $source) { + return [new SelectorNode(new ElementNode(null, '*'))]; + } + + return []; + } +} diff --git a/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php b/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php new file mode 100644 index 000000000..6683126a3 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Shortcut; + +use Symfony\Component\CssSelector\Node\ElementNode; +use Symfony\Component\CssSelector\Node\HashNode; +use Symfony\Component\CssSelector\Node\SelectorNode; +use Symfony\Component\CssSelector\Parser\ParserInterface; + +/** + * CSS selector hash parser shortcut. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class HashParser implements ParserInterface +{ + public function parse(string $source): array + { + // Matches an optional namespace, optional element, and required id + // $source = 'test|input#ab6bd_field'; + // $matches = array (size=4) + // 0 => string 'test|input#ab6bd_field' (length=22) + // 1 => string 'test' (length=4) + // 2 => string 'input' (length=5) + // 3 => string 'ab6bd_field' (length=11) + if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) { + return [ + new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])), + ]; + } + + return []; + } +} diff --git a/vendor/symfony/css-selector/Parser/Token.php b/vendor/symfony/css-selector/Parser/Token.php new file mode 100644 index 000000000..b50441a8e --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Token.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser; + +/** + * CSS selector token. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class Token +{ + public const TYPE_FILE_END = 'eof'; + public const TYPE_DELIMITER = 'delimiter'; + public const TYPE_WHITESPACE = 'whitespace'; + public const TYPE_IDENTIFIER = 'identifier'; + public const TYPE_HASH = 'hash'; + public const TYPE_NUMBER = 'number'; + public const TYPE_STRING = 'string'; + + private ?string $type; + private ?string $value; + private ?int $position; + + public function __construct(?string $type, ?string $value, ?int $position) + { + $this->type = $type; + $this->value = $value; + $this->position = $position; + } + + public function getType(): ?int + { + return $this->type; + } + + public function getValue(): ?string + { + return $this->value; + } + + public function getPosition(): ?int + { + return $this->position; + } + + public function isFileEnd(): bool + { + return self::TYPE_FILE_END === $this->type; + } + + public function isDelimiter(array $values = []): bool + { + if (self::TYPE_DELIMITER !== $this->type) { + return false; + } + + if (!$values) { + return true; + } + + return \in_array($this->value, $values); + } + + public function isWhitespace(): bool + { + return self::TYPE_WHITESPACE === $this->type; + } + + public function isIdentifier(): bool + { + return self::TYPE_IDENTIFIER === $this->type; + } + + public function isHash(): bool + { + return self::TYPE_HASH === $this->type; + } + + public function isNumber(): bool + { + return self::TYPE_NUMBER === $this->type; + } + + public function isString(): bool + { + return self::TYPE_STRING === $this->type; + } + + public function __toString(): string + { + if ($this->value) { + return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position); + } + + return sprintf('<%s at %s>', $this->type, $this->position); + } +} diff --git a/vendor/symfony/css-selector/Parser/TokenStream.php b/vendor/symfony/css-selector/Parser/TokenStream.php new file mode 100644 index 000000000..8b72d5dbc --- /dev/null +++ b/vendor/symfony/css-selector/Parser/TokenStream.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser; + +use Symfony\Component\CssSelector\Exception\InternalErrorException; +use Symfony\Component\CssSelector\Exception\SyntaxErrorException; + +/** + * CSS selector token stream. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class TokenStream +{ + /** + * @var Token[] + */ + private array $tokens = []; + + /** + * @var Token[] + */ + private array $used = []; + + private int $cursor = 0; + private ?Token $peeked; + private bool $peeking = false; + + /** + * Pushes a token. + * + * @return $this + */ + public function push(Token $token): static + { + $this->tokens[] = $token; + + return $this; + } + + /** + * Freezes stream. + * + * @return $this + */ + public function freeze(): static + { + return $this; + } + + /** + * Returns next token. + * + * @throws InternalErrorException If there is no more token + */ + public function getNext(): Token + { + if ($this->peeking) { + $this->peeking = false; + $this->used[] = $this->peeked; + + return $this->peeked; + } + + if (!isset($this->tokens[$this->cursor])) { + throw new InternalErrorException('Unexpected token stream end.'); + } + + return $this->tokens[$this->cursor++]; + } + + /** + * Returns peeked token. + */ + public function getPeek(): Token + { + if (!$this->peeking) { + $this->peeked = $this->getNext(); + $this->peeking = true; + } + + return $this->peeked; + } + + /** + * Returns used tokens. + * + * @return Token[] + */ + public function getUsed(): array + { + return $this->used; + } + + /** + * Returns next identifier token. + * + * @throws SyntaxErrorException If next token is not an identifier + */ + public function getNextIdentifier(): string + { + $next = $this->getNext(); + + if (!$next->isIdentifier()) { + throw SyntaxErrorException::unexpectedToken('identifier', $next); + } + + return $next->getValue(); + } + + /** + * Returns next identifier or null if star delimiter token is found. + * + * @throws SyntaxErrorException If next token is not an identifier or a star delimiter + */ + public function getNextIdentifierOrStar(): ?string + { + $next = $this->getNext(); + + if ($next->isIdentifier()) { + return $next->getValue(); + } + + if ($next->isDelimiter(['*'])) { + return null; + } + + throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next); + } + + /** + * Skips next whitespace if any. + */ + public function skipWhitespace(): void + { + $peek = $this->getPeek(); + + if ($peek->isWhitespace()) { + $this->getNext(); + } + } +} diff --git a/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php b/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php new file mode 100644 index 000000000..35c96a484 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Tokenizer; + +use Symfony\Component\CssSelector\Parser\Handler; +use Symfony\Component\CssSelector\Parser\Reader; +use Symfony\Component\CssSelector\Parser\Token; +use Symfony\Component\CssSelector\Parser\TokenStream; + +/** + * CSS selector tokenizer. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class Tokenizer +{ + /** + * @var Handler\HandlerInterface[] + */ + private array $handlers; + + public function __construct() + { + $patterns = new TokenizerPatterns(); + $escaping = new TokenizerEscaping($patterns); + + $this->handlers = [ + new Handler\WhitespaceHandler(), + new Handler\IdentifierHandler($patterns, $escaping), + new Handler\HashHandler($patterns, $escaping), + new Handler\StringHandler($patterns, $escaping), + new Handler\NumberHandler($patterns), + new Handler\CommentHandler(), + ]; + } + + /** + * Tokenize selector source code. + */ + public function tokenize(Reader $reader): TokenStream + { + $stream = new TokenStream(); + + while (!$reader->isEOF()) { + foreach ($this->handlers as $handler) { + if ($handler->handle($reader, $stream)) { + continue 2; + } + } + + $stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition())); + $reader->moveForward(1); + } + + return $stream + ->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition())) + ->freeze(); + } +} diff --git a/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php b/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php new file mode 100644 index 000000000..8c4b9f742 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Tokenizer; + +/** + * CSS selector tokenizer escaping applier. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class TokenizerEscaping +{ + private TokenizerPatterns $patterns; + + public function __construct(TokenizerPatterns $patterns) + { + $this->patterns = $patterns; + } + + public function escapeUnicode(string $value): string + { + $value = $this->replaceUnicodeSequences($value); + + return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value); + } + + public function escapeUnicodeAndNewLine(string $value): string + { + $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value); + + return $this->escapeUnicode($value); + } + + private function replaceUnicodeSequences(string $value): string + { + return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) { + $c = hexdec($match[1]); + + if (0x80 > $c %= 0x200000) { + return \chr($c); + } + if (0x800 > $c) { + return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F); + } + if (0x10000 > $c) { + return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); + } + + return ''; + }, $value); + } +} diff --git a/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php b/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php new file mode 100644 index 000000000..3c77cf091 --- /dev/null +++ b/vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\Parser\Tokenizer; + +/** + * CSS selector tokenizer patterns builder. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class TokenizerPatterns +{ + private string $unicodeEscapePattern; + private string $simpleEscapePattern; + private string $newLineEscapePattern; + private string $escapePattern; + private string $stringEscapePattern; + private string $nonAsciiPattern; + private string $nmCharPattern; + private string $nmStartPattern; + private string $identifierPattern; + private string $hashPattern; + private string $numberPattern; + private string $quotedStringPattern; + + public function __construct() + { + $this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?'; + $this->simpleEscapePattern = '\\\\(.)'; + $this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)'; + $this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]'; + $this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern; + $this->nonAsciiPattern = '[^\x00-\x7F]'; + $this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern; + $this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern; + $this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*'; + $this->hashPattern = '#((?:'.$this->nmCharPattern.')+)'; + $this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)'; + $this->quotedStringPattern = '([^\n\r\f\\\\%s]|'.$this->stringEscapePattern.')*'; + } + + public function getNewLineEscapePattern(): string + { + return '~'.$this->newLineEscapePattern.'~'; + } + + public function getSimpleEscapePattern(): string + { + return '~'.$this->simpleEscapePattern.'~'; + } + + public function getUnicodeEscapePattern(): string + { + return '~'.$this->unicodeEscapePattern.'~i'; + } + + public function getIdentifierPattern(): string + { + return '~^'.$this->identifierPattern.'~i'; + } + + public function getHashPattern(): string + { + return '~^'.$this->hashPattern.'~i'; + } + + public function getNumberPattern(): string + { + return '~^'.$this->numberPattern.'~'; + } + + public function getQuotedStringPattern(string $quote): string + { + return '~^'.sprintf($this->quotedStringPattern, $quote).'~i'; + } +} diff --git a/vendor/symfony/css-selector/README.md b/vendor/symfony/css-selector/README.md new file mode 100644 index 000000000..ede4a3acc --- /dev/null +++ b/vendor/symfony/css-selector/README.md @@ -0,0 +1,20 @@ +CssSelector Component +===================== + +The CssSelector component converts CSS selectors to XPath expressions. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/css_selector.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +Credits +------- + +This component is a port of the Python cssselect library +[v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1), +which is distributed under the BSD license. diff --git a/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php b/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php new file mode 100644 index 000000000..495f88291 --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +/** + * XPath expression translator abstract extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +abstract class AbstractExtension implements ExtensionInterface +{ + public function getNodeTranslators(): array + { + return []; + } + + public function getCombinationTranslators(): array + { + return []; + } + + public function getFunctionTranslators(): array + { + return []; + } + + public function getPseudoClassTranslators(): array + { + return []; + } + + public function getAttributeMatchingTranslators(): array + { + return []; + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php b/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php new file mode 100644 index 000000000..3c785e97a --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\XPath\Translator; +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator attribute extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class AttributeMatchingExtension extends AbstractExtension +{ + public function getAttributeMatchingTranslators(): array + { + return [ + 'exists' => $this->translateExists(...), + '=' => $this->translateEquals(...), + '~=' => $this->translateIncludes(...), + '|=' => $this->translateDashMatch(...), + '^=' => $this->translatePrefixMatch(...), + '$=' => $this->translateSuffixMatch(...), + '*=' => $this->translateSubstringMatch(...), + '!=' => $this->translateDifferent(...), + ]; + } + + public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition($attribute); + } + + public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); + } + + public function translateIncludes(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition($value ? sprintf( + '%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)', + $attribute, + Translator::getXpathLiteral(' '.$value.' ') + ) : '0'); + } + + public function translateDashMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition(sprintf( + '%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))', + $attribute, + Translator::getXpathLiteral($value), + Translator::getXpathLiteral($value.'-') + )); + } + + public function translatePrefixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition($value ? sprintf( + '%1$s and starts-with(%1$s, %2$s)', + $attribute, + Translator::getXpathLiteral($value) + ) : '0'); + } + + public function translateSuffixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition($value ? sprintf( + '%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s', + $attribute, + \strlen($value) - 1, + Translator::getXpathLiteral($value) + ) : '0'); + } + + public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition($value ? sprintf( + '%1$s and contains(%1$s, %2$s)', + $attribute, + Translator::getXpathLiteral($value) + ) : '0'); + } + + public function translateDifferent(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr + { + return $xpath->addCondition(sprintf( + $value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s', + $attribute, + Translator::getXpathLiteral($value) + )); + } + + public function getName(): string + { + return 'attribute-matching'; + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php b/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php new file mode 100644 index 000000000..f78d48883 --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator combination extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class CombinationExtension extends AbstractExtension +{ + public function getCombinationTranslators(): array + { + return [ + ' ' => $this->translateDescendant(...), + '>' => $this->translateChild(...), + '+' => $this->translateDirectAdjacent(...), + '~' => $this->translateIndirectAdjacent(...), + ]; + } + + public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr + { + return $xpath->join('/descendant-or-self::*/', $combinedXpath); + } + + public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr + { + return $xpath->join('/', $combinedXpath); + } + + public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr + { + return $xpath + ->join('/following-sibling::', $combinedXpath) + ->addNameTest() + ->addCondition('position() = 1'); + } + + public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr + { + return $xpath->join('/following-sibling::', $combinedXpath); + } + + public function getName(): string + { + return 'combination'; + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php b/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php new file mode 100644 index 000000000..1a74b90ac --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +/** + * XPath expression translator extension interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +interface ExtensionInterface +{ + /** + * Returns node translators. + * + * These callables will receive the node as first argument and the translator as second argument. + * + * @return callable[] + */ + public function getNodeTranslators(): array; + + /** + * Returns combination translators. + * + * @return callable[] + */ + public function getCombinationTranslators(): array; + + /** + * Returns function translators. + * + * @return callable[] + */ + public function getFunctionTranslators(): array; + + /** + * Returns pseudo-class translators. + * + * @return callable[] + */ + public function getPseudoClassTranslators(): array; + + /** + * Returns attribute operation translators. + * + * @return callable[] + */ + public function getAttributeMatchingTranslators(): array; + + /** + * Returns extension name. + */ + public function getName(): string; +} diff --git a/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php b/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php new file mode 100644 index 000000000..4b9d7bc26 --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\Exception\ExpressionErrorException; +use Symfony\Component\CssSelector\Exception\SyntaxErrorException; +use Symfony\Component\CssSelector\Node\FunctionNode; +use Symfony\Component\CssSelector\Parser\Parser; +use Symfony\Component\CssSelector\XPath\Translator; +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator function extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class FunctionExtension extends AbstractExtension +{ + public function getFunctionTranslators(): array + { + return [ + 'nth-child' => $this->translateNthChild(...), + 'nth-last-child' => $this->translateNthLastChild(...), + 'nth-of-type' => $this->translateNthOfType(...), + 'nth-last-of-type' => $this->translateNthLastOfType(...), + 'contains' => $this->translateContains(...), + 'lang' => $this->translateLang(...), + ]; + } + + /** + * @throws ExpressionErrorException + */ + public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr + { + try { + [$a, $b] = Parser::parseSeries($function->getArguments()); + } catch (SyntaxErrorException $e) { + throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e); + } + + $xpath->addStarPrefix(); + if ($addNameTest) { + $xpath->addNameTest(); + } + + if (0 === $a) { + return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b)); + } + + if ($a < 0) { + if ($b < 1) { + return $xpath->addCondition('false()'); + } + + $sign = '<='; + } else { + $sign = '>='; + } + + $expr = 'position()'; + + if ($last) { + $expr = 'last() - '.$expr; + --$b; + } + + if (0 !== $b) { + $expr .= ' - '.$b; + } + + $conditions = [sprintf('%s %s 0', $expr, $sign)]; + + if (1 !== $a && -1 !== $a) { + $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a); + } + + return $xpath->addCondition(implode(' and ', $conditions)); + + // todo: handle an+b, odd, even + // an+b means every-a, plus b, e.g., 2n+1 means odd + // 0n+b means b + // n+0 means a=1, i.e., all elements + // an means every a elements, i.e., 2n means even + // -n means -1n + // -1n+6 means elements 6 and previous + } + + public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + return $this->translateNthChild($xpath, $function, true); + } + + public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + return $this->translateNthChild($xpath, $function, false, false); + } + + /** + * @throws ExpressionErrorException + */ + public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + if ('*' === $xpath->getElement()) { + throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.'); + } + + return $this->translateNthChild($xpath, $function, true, false); + } + + /** + * @throws ExpressionErrorException + */ + public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + $arguments = $function->getArguments(); + foreach ($arguments as $token) { + if (!($token->isString() || $token->isIdentifier())) { + throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments)); + } + } + + return $xpath->addCondition(sprintf( + 'contains(string(.), %s)', + Translator::getXpathLiteral($arguments[0]->getValue()) + )); + } + + /** + * @throws ExpressionErrorException + */ + public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + $arguments = $function->getArguments(); + foreach ($arguments as $token) { + if (!($token->isString() || $token->isIdentifier())) { + throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments)); + } + } + + return $xpath->addCondition(sprintf( + 'lang(%s)', + Translator::getXpathLiteral($arguments[0]->getValue()) + )); + } + + public function getName(): string + { + return 'function'; + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php b/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php new file mode 100644 index 000000000..4653add5d --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php @@ -0,0 +1,178 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\Exception\ExpressionErrorException; +use Symfony\Component\CssSelector\Node\FunctionNode; +use Symfony\Component\CssSelector\XPath\Translator; +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator HTML extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class HtmlExtension extends AbstractExtension +{ + public function __construct(Translator $translator) + { + $translator + ->getExtension('node') + ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true) + ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true); + } + + public function getPseudoClassTranslators(): array + { + return [ + 'checked' => $this->translateChecked(...), + 'link' => $this->translateLink(...), + 'disabled' => $this->translateDisabled(...), + 'enabled' => $this->translateEnabled(...), + 'selected' => $this->translateSelected(...), + 'invalid' => $this->translateInvalid(...), + 'hover' => $this->translateHover(...), + 'visited' => $this->translateVisited(...), + ]; + } + + public function getFunctionTranslators(): array + { + return [ + 'lang' => $this->translateLang(...), + ]; + } + + public function translateChecked(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition( + '(@checked ' + ."and (name(.) = 'input' or name(.) = 'command')" + ."and (@type = 'checkbox' or @type = 'radio'))" + ); + } + + public function translateLink(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')"); + } + + public function translateDisabled(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition( + '(' + .'@disabled and' + .'(' + ."(name(.) = 'input' and @type != 'hidden')" + ." or name(.) = 'button'" + ." or name(.) = 'select'" + ." or name(.) = 'textarea'" + ." or name(.) = 'command'" + ." or name(.) = 'fieldset'" + ." or name(.) = 'optgroup'" + ." or name(.) = 'option'" + .')' + .') or (' + ."(name(.) = 'input' and @type != 'hidden')" + ." or name(.) = 'button'" + ." or name(.) = 'select'" + ." or name(.) = 'textarea'" + .')' + .' and ancestor::fieldset[@disabled]' + ); + // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any." + } + + public function translateEnabled(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition( + '(' + .'@href and (' + ."name(.) = 'a'" + ." or name(.) = 'link'" + ." or name(.) = 'area'" + .')' + .') or (' + .'(' + ."name(.) = 'command'" + ." or name(.) = 'fieldset'" + ." or name(.) = 'optgroup'" + .')' + .' and not(@disabled)' + .') or (' + .'(' + ."(name(.) = 'input' and @type != 'hidden')" + ." or name(.) = 'button'" + ." or name(.) = 'select'" + ." or name(.) = 'textarea'" + ." or name(.) = 'keygen'" + .')' + .' and not (@disabled or ancestor::fieldset[@disabled])' + .') or (' + ."name(.) = 'option' and not(" + .'@disabled or ancestor::optgroup[@disabled]' + .')' + .')' + ); + } + + /** + * @throws ExpressionErrorException + */ + public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + $arguments = $function->getArguments(); + foreach ($arguments as $token) { + if (!($token->isString() || $token->isIdentifier())) { + throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments)); + } + } + + return $xpath->addCondition(sprintf( + 'ancestor-or-self::*[@lang][1][starts-with(concat(' + ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')" + .', %s)]', + 'lang', + Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-') + )); + } + + public function translateSelected(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition("(@selected and name(.) = 'option')"); + } + + public function translateInvalid(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('0'); + } + + public function translateHover(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('0'); + } + + public function translateVisited(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('0'); + } + + public function getName(): string + { + return 'html'; + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php b/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php new file mode 100644 index 000000000..49e894ade --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\Node; +use Symfony\Component\CssSelector\XPath\Translator; +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator node extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class NodeExtension extends AbstractExtension +{ + public const ELEMENT_NAME_IN_LOWER_CASE = 1; + public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2; + public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4; + + private int $flags; + + public function __construct(int $flags = 0) + { + $this->flags = $flags; + } + + /** + * @return $this + */ + public function setFlag(int $flag, bool $on): static + { + if ($on && !$this->hasFlag($flag)) { + $this->flags += $flag; + } + + if (!$on && $this->hasFlag($flag)) { + $this->flags -= $flag; + } + + return $this; + } + + public function hasFlag(int $flag): bool + { + return (bool) ($this->flags & $flag); + } + + public function getNodeTranslators(): array + { + return [ + 'Selector' => $this->translateSelector(...), + 'CombinedSelector' => $this->translateCombinedSelector(...), + 'Negation' => $this->translateNegation(...), + 'Function' => $this->translateFunction(...), + 'Pseudo' => $this->translatePseudo(...), + 'Attribute' => $this->translateAttribute(...), + 'Class' => $this->translateClass(...), + 'Hash' => $this->translateHash(...), + 'Element' => $this->translateElement(...), + ]; + } + + public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr + { + return $translator->nodeToXPath($node->getTree()); + } + + public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr + { + return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector()); + } + + public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr + { + $xpath = $translator->nodeToXPath($node->getSelector()); + $subXpath = $translator->nodeToXPath($node->getSubSelector()); + $subXpath->addNameTest(); + + if ($subXpath->getCondition()) { + return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition())); + } + + return $xpath->addCondition('0'); + } + + public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr + { + $xpath = $translator->nodeToXPath($node->getSelector()); + + return $translator->addFunction($xpath, $node); + } + + public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr + { + $xpath = $translator->nodeToXPath($node->getSelector()); + + return $translator->addPseudoClass($xpath, $node->getIdentifier()); + } + + public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr + { + $name = $node->getAttribute(); + $safe = $this->isSafeName($name); + + if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) { + $name = strtolower($name); + } + + if ($node->getNamespace()) { + $name = sprintf('%s:%s', $node->getNamespace(), $name); + $safe = $safe && $this->isSafeName($node->getNamespace()); + } + + $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name)); + $value = $node->getValue(); + $xpath = $translator->nodeToXPath($node->getSelector()); + + if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) { + $value = strtolower($value); + } + + return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value); + } + + public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr + { + $xpath = $translator->nodeToXPath($node->getSelector()); + + return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName()); + } + + public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr + { + $xpath = $translator->nodeToXPath($node->getSelector()); + + return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId()); + } + + public function translateElement(Node\ElementNode $node): XPathExpr + { + $element = $node->getElement(); + + if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) { + $element = strtolower($element); + } + + if ($element) { + $safe = $this->isSafeName($element); + } else { + $element = '*'; + $safe = true; + } + + if ($node->getNamespace()) { + $element = sprintf('%s:%s', $node->getNamespace(), $element); + $safe = $safe && $this->isSafeName($node->getNamespace()); + } + + $xpath = new XPathExpr('', $element); + + if (!$safe) { + $xpath->addNameTest(); + } + + return $xpath; + } + + public function getName(): string + { + return 'node'; + } + + private function isSafeName(string $name): bool + { + return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name); + } +} diff --git a/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php b/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php new file mode 100644 index 000000000..aada83291 --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath\Extension; + +use Symfony\Component\CssSelector\Exception\ExpressionErrorException; +use Symfony\Component\CssSelector\XPath\XPathExpr; + +/** + * XPath expression translator pseudo-class extension. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class PseudoClassExtension extends AbstractExtension +{ + public function getPseudoClassTranslators(): array + { + return [ + 'root' => $this->translateRoot(...), + 'scope' => $this->translateScopePseudo(...), + 'first-child' => $this->translateFirstChild(...), + 'last-child' => $this->translateLastChild(...), + 'first-of-type' => $this->translateFirstOfType(...), + 'last-of-type' => $this->translateLastOfType(...), + 'only-child' => $this->translateOnlyChild(...), + 'only-of-type' => $this->translateOnlyOfType(...), + 'empty' => $this->translateEmpty(...), + ]; + } + + public function translateRoot(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('not(parent::*)'); + } + + public function translateScopePseudo(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('1'); + } + + public function translateFirstChild(XPathExpr $xpath): XPathExpr + { + return $xpath + ->addStarPrefix() + ->addNameTest() + ->addCondition('position() = 1'); + } + + public function translateLastChild(XPathExpr $xpath): XPathExpr + { + return $xpath + ->addStarPrefix() + ->addNameTest() + ->addCondition('position() = last()'); + } + + /** + * @throws ExpressionErrorException + */ + public function translateFirstOfType(XPathExpr $xpath): XPathExpr + { + if ('*' === $xpath->getElement()) { + throw new ExpressionErrorException('"*:first-of-type" is not implemented.'); + } + + return $xpath + ->addStarPrefix() + ->addCondition('position() = 1'); + } + + /** + * @throws ExpressionErrorException + */ + public function translateLastOfType(XPathExpr $xpath): XPathExpr + { + if ('*' === $xpath->getElement()) { + throw new ExpressionErrorException('"*:last-of-type" is not implemented.'); + } + + return $xpath + ->addStarPrefix() + ->addCondition('position() = last()'); + } + + public function translateOnlyChild(XPathExpr $xpath): XPathExpr + { + return $xpath + ->addStarPrefix() + ->addNameTest() + ->addCondition('last() = 1'); + } + + public function translateOnlyOfType(XPathExpr $xpath): XPathExpr + { + $element = $xpath->getElement(); + + return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element)); + } + + public function translateEmpty(XPathExpr $xpath): XPathExpr + { + return $xpath->addCondition('not(*) and not(string-length())'); + } + + public function getName(): string + { + return 'pseudo-class'; + } +} diff --git a/vendor/symfony/css-selector/XPath/Translator.php b/vendor/symfony/css-selector/XPath/Translator.php new file mode 100644 index 000000000..9e66ce7dd --- /dev/null +++ b/vendor/symfony/css-selector/XPath/Translator.php @@ -0,0 +1,224 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath; + +use Symfony\Component\CssSelector\Exception\ExpressionErrorException; +use Symfony\Component\CssSelector\Node\FunctionNode; +use Symfony\Component\CssSelector\Node\NodeInterface; +use Symfony\Component\CssSelector\Node\SelectorNode; +use Symfony\Component\CssSelector\Parser\Parser; +use Symfony\Component\CssSelector\Parser\ParserInterface; + +/** + * XPath expression translator interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class Translator implements TranslatorInterface +{ + private ParserInterface $mainParser; + + /** + * @var ParserInterface[] + */ + private array $shortcutParsers = []; + + /** + * @var Extension\ExtensionInterface[] + */ + private array $extensions = []; + + private array $nodeTranslators = []; + private array $combinationTranslators = []; + private array $functionTranslators = []; + private array $pseudoClassTranslators = []; + private array $attributeMatchingTranslators = []; + + public function __construct(?ParserInterface $parser = null) + { + $this->mainParser = $parser ?? new Parser(); + + $this + ->registerExtension(new Extension\NodeExtension()) + ->registerExtension(new Extension\CombinationExtension()) + ->registerExtension(new Extension\FunctionExtension()) + ->registerExtension(new Extension\PseudoClassExtension()) + ->registerExtension(new Extension\AttributeMatchingExtension()) + ; + } + + public static function getXpathLiteral(string $element): string + { + if (!str_contains($element, "'")) { + return "'".$element."'"; + } + + if (!str_contains($element, '"')) { + return '"'.$element.'"'; + } + + $string = $element; + $parts = []; + while (true) { + if (false !== $pos = strpos($string, "'")) { + $parts[] = sprintf("'%s'", substr($string, 0, $pos)); + $parts[] = "\"'\""; + $string = substr($string, $pos + 1); + } else { + $parts[] = "'$string'"; + break; + } + } + + return sprintf('concat(%s)', implode(', ', $parts)); + } + + public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string + { + $selectors = $this->parseSelectors($cssExpr); + + /** @var SelectorNode $selector */ + foreach ($selectors as $index => $selector) { + if (null !== $selector->getPseudoElement()) { + throw new ExpressionErrorException('Pseudo-elements are not supported.'); + } + + $selectors[$index] = $this->selectorToXPath($selector, $prefix); + } + + return implode(' | ', $selectors); + } + + public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string + { + return ($prefix ?: '').$this->nodeToXPath($selector); + } + + /** + * @return $this + */ + public function registerExtension(Extension\ExtensionInterface $extension): static + { + $this->extensions[$extension->getName()] = $extension; + + $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators()); + $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators()); + $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators()); + $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators()); + $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators()); + + return $this; + } + + /** + * @throws ExpressionErrorException + */ + public function getExtension(string $name): Extension\ExtensionInterface + { + if (!isset($this->extensions[$name])) { + throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name)); + } + + return $this->extensions[$name]; + } + + /** + * @return $this + */ + public function registerParserShortcut(ParserInterface $shortcut): static + { + $this->shortcutParsers[] = $shortcut; + + return $this; + } + + /** + * @throws ExpressionErrorException + */ + public function nodeToXPath(NodeInterface $node): XPathExpr + { + if (!isset($this->nodeTranslators[$node->getNodeName()])) { + throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName())); + } + + return $this->nodeTranslators[$node->getNodeName()]($node, $this); + } + + /** + * @throws ExpressionErrorException + */ + public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr + { + if (!isset($this->combinationTranslators[$combiner])) { + throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner)); + } + + return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath)); + } + + /** + * @throws ExpressionErrorException + */ + public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr + { + if (!isset($this->functionTranslators[$function->getName()])) { + throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName())); + } + + return $this->functionTranslators[$function->getName()]($xpath, $function); + } + + /** + * @throws ExpressionErrorException + */ + public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr + { + if (!isset($this->pseudoClassTranslators[$pseudoClass])) { + throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass)); + } + + return $this->pseudoClassTranslators[$pseudoClass]($xpath); + } + + /** + * @throws ExpressionErrorException + */ + public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr + { + if (!isset($this->attributeMatchingTranslators[$operator])) { + throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator)); + } + + return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value); + } + + /** + * @return SelectorNode[] + */ + private function parseSelectors(string $css): array + { + foreach ($this->shortcutParsers as $shortcut) { + $tokens = $shortcut->parse($css); + + if ($tokens) { + return $tokens; + } + } + + return $this->mainParser->parse($css); + } +} diff --git a/vendor/symfony/css-selector/XPath/TranslatorInterface.php b/vendor/symfony/css-selector/XPath/TranslatorInterface.php new file mode 100644 index 000000000..c19eefb9c --- /dev/null +++ b/vendor/symfony/css-selector/XPath/TranslatorInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath; + +use Symfony\Component\CssSelector\Node\SelectorNode; + +/** + * XPath expression translator interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +interface TranslatorInterface +{ + /** + * Translates a CSS selector to an XPath expression. + */ + public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string; + + /** + * Translates a parsed selector node to an XPath expression. + */ + public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string; +} diff --git a/vendor/symfony/css-selector/XPath/XPathExpr.php b/vendor/symfony/css-selector/XPath/XPathExpr.php new file mode 100644 index 000000000..a76e30bec --- /dev/null +++ b/vendor/symfony/css-selector/XPath/XPathExpr.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\CssSelector\XPath; + +/** + * XPath expression translator interface. + * + * This component is a port of the Python cssselect library, + * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. + * + * @author Jean-François Simon + * + * @internal + */ +class XPathExpr +{ + private string $path; + private string $element; + private string $condition; + + public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false) + { + $this->path = $path; + $this->element = $element; + $this->condition = $condition; + + if ($starPrefix) { + $this->addStarPrefix(); + } + } + + public function getElement(): string + { + return $this->element; + } + + /** + * @return $this + */ + public function addCondition(string $condition): static + { + $this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition; + + return $this; + } + + public function getCondition(): string + { + return $this->condition; + } + + /** + * @return $this + */ + public function addNameTest(): static + { + if ('*' !== $this->element) { + $this->addCondition('name() = '.Translator::getXpathLiteral($this->element)); + $this->element = '*'; + } + + return $this; + } + + /** + * @return $this + */ + public function addStarPrefix(): static + { + $this->path .= '*/'; + + return $this; + } + + /** + * Joins another XPathExpr with a combiner. + * + * @return $this + */ + public function join(string $combiner, self $expr): static + { + $path = $this->__toString().$combiner; + + if ('*/' !== $expr->path) { + $path .= $expr->path; + } + + $this->path = $path; + $this->element = $expr->element; + $this->condition = $expr->condition; + + return $this; + } + + public function __toString(): string + { + $path = $this->path.$this->element; + $condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']'; + + return $path.$condition; + } +} diff --git a/vendor/symfony/css-selector/composer.json b/vendor/symfony/css-selector/composer.json new file mode 100644 index 000000000..c08fdc2cd --- /dev/null +++ b/vendor/symfony/css-selector/composer.json @@ -0,0 +1,32 @@ +{ + "name": "symfony/css-selector", + "type": "library", + "description": "Converts CSS selectors to XPath expressions", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\CssSelector\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/vendor/symfony/dom-crawler/AbstractUriElement.php b/vendor/symfony/dom-crawler/AbstractUriElement.php new file mode 100644 index 000000000..e67716f64 --- /dev/null +++ b/vendor/symfony/dom-crawler/AbstractUriElement.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +/** + * Any HTML element that can link to an URI. + * + * @author Fabien Potencier + */ +abstract class AbstractUriElement +{ + /** + * @var \DOMElement + */ + protected $node; + + /** + * @var string|null The method to use for the element + */ + protected $method; + + /** + * @var string The URI of the page where the element is embedded (or the base href) + */ + protected $currentUri; + + /** + * @param \DOMElement $node A \DOMElement instance + * @param string|null $currentUri The URI of the page where the link is embedded (or the base href) + * @param string|null $method The method to use for the link (GET by default) + * + * @throws \InvalidArgumentException if the node is not a link + */ + public function __construct(\DOMElement $node, ?string $currentUri = null, ?string $method = 'GET') + { + $this->setNode($node); + $this->method = $method ? strtoupper($method) : null; + $this->currentUri = $currentUri; + + $elementUriIsRelative = null === parse_url(trim($this->getRawUri()), \PHP_URL_SCHEME); + $baseUriIsAbsolute = null !== $this->currentUri && \in_array(strtolower(substr($this->currentUri, 0, 4)), ['http', 'file']); + if ($elementUriIsRelative && !$baseUriIsAbsolute) { + throw new \InvalidArgumentException(sprintf('The URL of the element is relative, so you must define its base URI passing an absolute URL to the constructor of the "%s" class ("%s" was passed).', __CLASS__, $this->currentUri)); + } + } + + /** + * Gets the node associated with this link. + */ + public function getNode(): \DOMElement + { + return $this->node; + } + + /** + * Gets the method associated with this link. + */ + public function getMethod(): string + { + return $this->method ?? 'GET'; + } + + /** + * Gets the URI associated with this link. + */ + public function getUri(): string + { + return UriResolver::resolve($this->getRawUri(), $this->currentUri); + } + + /** + * Returns raw URI data. + */ + abstract protected function getRawUri(): string; + + /** + * Returns the canonicalized URI path (see RFC 3986, section 5.2.4). + * + * @param string $path URI path + */ + protected function canonicalizePath(string $path): string + { + if ('' === $path || '/' === $path) { + return $path; + } + + if (str_ends_with($path, '.')) { + $path .= '/'; + } + + $output = []; + + foreach (explode('/', $path) as $segment) { + if ('..' === $segment) { + array_pop($output); + } elseif ('.' !== $segment) { + $output[] = $segment; + } + } + + return implode('/', $output); + } + + /** + * Sets current \DOMElement instance. + * + * @param \DOMElement $node A \DOMElement instance + * + * @return void + * + * @throws \LogicException If given node is not an anchor + */ + abstract protected function setNode(\DOMElement $node); +} diff --git a/vendor/symfony/dom-crawler/CHANGELOG.md b/vendor/symfony/dom-crawler/CHANGELOG.md new file mode 100644 index 000000000..9f8f204ed --- /dev/null +++ b/vendor/symfony/dom-crawler/CHANGELOG.md @@ -0,0 +1,124 @@ +CHANGELOG +========= + +6.4 +--- + + * Add `CrawlerAnySelectorTextContains` test constraint + * Add `CrawlerAnySelectorTextSame` test constraint + * Add argument `$default` to `Crawler::attr()` + +6.3 +--- + + * Add `$useHtml5Parser` argument to `Crawler` + * Add `CrawlerSelectorCount` test constraint + * Add argument `$normalizeWhitespace` to `Crawler::innerText()` + * Make `Crawler::innerText()` return the first non-empty text + +6.0 +--- + + * Remove `Crawler::parents()` method, use `ancestors()` instead + +5.4 +--- + + * Add `Crawler::innerText` method. + +5.3 +--- + + * The `parents()` method is deprecated. Use `ancestors()` instead. + * Marked the `containsOption()`, `availableOptionValues()`, and `disableValidation()` methods of the + `ChoiceFormField` class as internal + +5.1.0 +----- + + * Added an internal cache layer on top of the CssSelectorConverter + * Added `UriResolver` to resolve an URI according to a base URI + +5.0.0 +----- + + * Added argument `$selector` to `Crawler::children()` + * Added argument `$default` to `Crawler::text()` and `html()` + +4.4.0 +----- + + * Added `Form::getName()` method. + * Added `Crawler::matches()` method. + * Added `Crawler::closest()` method. + * Added `Crawler::outerHtml()` method. + * Added an argument to the `Crawler::text()` method to opt-in normalizing whitespaces. + +4.3.0 +----- + + * Added PHPUnit constraints: `CrawlerSelectorAttributeValueSame`, `CrawlerSelectorExists`, `CrawlerSelectorTextContains` + and `CrawlerSelectorTextSame` + * Added return of element name (`_name`) in `extract()` method. + * Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. + * When available, the [html5-php library](https://github.com/Masterminds/html5-php) is used to + parse HTML added to a Crawler for better support of HTML5 tags. + +4.2.0 +----- + + * The `$currentUri` constructor argument of the `AbstractUriElement`, `Link` and + `Image` classes is now optional. + * The `Crawler::children()` method will have a new `$selector` argument in version 5.0, + not defining it is deprecated. + +3.1.0 +----- + + * All the URI parsing logic have been abstracted in the `AbstractUriElement` class. + The `Link` class is now a child of `AbstractUriElement`. + * Added an `Image` class to crawl images and parse their `src` attribute, + and `selectImage`, `image`, `images` methods in the `Crawler` (the image version of the equivalent `link` methods). + +2.5.0 +----- + + * [BC BREAK] The default value for checkbox and radio inputs without a value attribute have changed + from '1' to 'on' to match the HTML specification. + * [BC BREAK] The typehints on the `Link`, `Form` and `FormField` classes have been changed from + `\DOMNode` to `DOMElement`. Using any other type of `DOMNode` was triggering fatal errors in previous + versions. Code extending these classes will need to update the typehints when overwriting these methods. + +2.4.0 +----- + + * `Crawler::addXmlContent()` removes the default document namespace again if it's an only namespace. + * added support for automatic discovery and explicit registration of document + namespaces for `Crawler::filterXPath()` and `Crawler::filter()` + * improved content type guessing in `Crawler::addContent()` + * [BC BREAK] `Crawler::addXmlContent()` no longer removes the default document + namespace + +2.3.0 +----- + + * added Crawler::html() + * [BC BREAK] Crawler::each() and Crawler::reduce() now return Crawler instances instead of DomElement instances + * added schema relative URL support to links + * added support for HTML5 'form' attribute + +2.2.0 +----- + + * added a way to set raw path to the file in FileFormField - necessary for + simulating HTTP requests + +2.1.0 +----- + + * added support for the HTTP PATCH method + * refactored the Form class internals to support multi-dimensional fields + (the public API is backward compatible) + * added a way to get parsing errors for Crawler::addHtmlContent() and + Crawler::addXmlContent() via libxml functions + * added support for submitting a form without a submit button diff --git a/vendor/symfony/dom-crawler/Crawler.php b/vendor/symfony/dom-crawler/Crawler.php new file mode 100644 index 000000000..ac5a98338 --- /dev/null +++ b/vendor/symfony/dom-crawler/Crawler.php @@ -0,0 +1,1265 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +use Masterminds\HTML5; +use Symfony\Component\CssSelector\CssSelectorConverter; + +/** + * Crawler eases navigation of a list of \DOMNode objects. + * + * @author Fabien Potencier + * + * @implements \IteratorAggregate + */ +class Crawler implements \Countable, \IteratorAggregate +{ + /** + * @var string|null + */ + protected $uri; + + /** + * The default namespace prefix to be used with XPath and CSS expressions. + */ + private string $defaultNamespacePrefix = 'default'; + + /** + * A map of manually registered namespaces. + * + * @var array + */ + private array $namespaces = []; + + /** + * A map of cached namespaces. + */ + private \ArrayObject $cachedNamespaces; + + private ?string $baseHref; + private ?\DOMDocument $document = null; + + /** + * @var list<\DOMNode> + */ + private array $nodes = []; + + /** + * Whether the Crawler contains HTML or XML content (used when converting CSS to XPath). + */ + private bool $isHtml = true; + + private ?HTML5 $html5Parser = null; + + /** + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A Node to use as the base for the crawling + */ + public function __construct(\DOMNodeList|\DOMNode|array|string|null $node = null, ?string $uri = null, ?string $baseHref = null, bool $useHtml5Parser = true) + { + $this->uri = $uri; + $this->baseHref = $baseHref ?: $uri; + $this->html5Parser = $useHtml5Parser ? new HTML5(['disable_html_ns' => true]) : null; + $this->cachedNamespaces = new \ArrayObject(); + + $this->add($node); + } + + /** + * Returns the current URI. + */ + public function getUri(): ?string + { + return $this->uri; + } + + /** + * Returns base href. + */ + public function getBaseHref(): ?string + { + return $this->baseHref; + } + + /** + * Removes all the nodes. + * + * @return void + */ + public function clear() + { + $this->nodes = []; + $this->document = null; + $this->cachedNamespaces = new \ArrayObject(); + } + + /** + * Adds a node to the current list of nodes. + * + * This method uses the appropriate specialized add*() method based + * on the type of the argument. + * + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A node + * + * @return void + * + * @throws \InvalidArgumentException when node is not the expected type + */ + public function add(\DOMNodeList|\DOMNode|array|string|null $node) + { + if ($node instanceof \DOMNodeList) { + $this->addNodeList($node); + } elseif ($node instanceof \DOMNode) { + $this->addNode($node); + } elseif (\is_array($node)) { + $this->addNodes($node); + } elseif (\is_string($node)) { + $this->addContent($node); + } elseif (null !== $node) { + throw new \InvalidArgumentException(sprintf('Expecting a DOMNodeList or DOMNode instance, an array, a string, or null, but got "%s".', get_debug_type($node))); + } + } + + /** + * Adds HTML/XML content. + * + * If the charset is not set via the content type, it is assumed to be UTF-8, + * or ISO-8859-1 as a fallback, which is the default charset defined by the + * HTTP 1.1 specification. + * + * @return void + */ + public function addContent(string $content, ?string $type = null) + { + if (empty($type)) { + $type = str_starts_with($content, 'convertToHtmlEntities('charset=', $m[2])) { + $charset = $m[2]; + } + + return $m[1].$charset; + }, $content, 1); + + if ('x' === $xmlMatches[1]) { + $this->addXmlContent($content, $charset); + } else { + $this->addHtmlContent($content, $charset); + } + } + + /** + * Adds an HTML content to the list of nodes. + * + * The libxml errors are disabled when the content is parsed. + * + * If you want to get parsing errors, be sure to enable + * internal errors via libxml_use_internal_errors(true) + * and then, get the errors via libxml_get_errors(). Be + * sure to clear errors with libxml_clear_errors() afterward. + * + * @return void + */ + public function addHtmlContent(string $content, string $charset = 'UTF-8') + { + $dom = $this->parseHtmlString($content, $charset); + $this->addDocument($dom); + + $base = $this->filterRelativeXPath('descendant-or-self::base')->extract(['href']); + + $baseHref = current($base); + if (\count($base) && !empty($baseHref)) { + if ($this->baseHref) { + $linkNode = $dom->createElement('a'); + $linkNode->setAttribute('href', $baseHref); + $link = new Link($linkNode, $this->baseHref); + $this->baseHref = $link->getUri(); + } else { + $this->baseHref = $baseHref; + } + } + } + + /** + * Adds an XML content to the list of nodes. + * + * The libxml errors are disabled when the content is parsed. + * + * If you want to get parsing errors, be sure to enable + * internal errors via libxml_use_internal_errors(true) + * and then, get the errors via libxml_get_errors(). Be + * sure to clear errors with libxml_clear_errors() afterward. + * + * @param int $options Bitwise OR of the libxml option constants + * LIBXML_PARSEHUGE is dangerous, see + * http://symfony.com/blog/security-release-symfony-2-0-17-released + * + * @return void + */ + public function addXmlContent(string $content, string $charset = 'UTF-8', int $options = \LIBXML_NONET) + { + // remove the default namespace if it's the only namespace to make XPath expressions simpler + if (!str_contains($content, 'xmlns:')) { + $content = str_replace('xmlns', 'ns', $content); + } + + $internalErrors = libxml_use_internal_errors(true); + + $dom = new \DOMDocument('1.0', $charset); + $dom->validateOnParse = true; + + if ('' !== trim($content)) { + @$dom->loadXML($content, $options); + } + + libxml_use_internal_errors($internalErrors); + + $this->addDocument($dom); + + $this->isHtml = false; + } + + /** + * Adds a \DOMDocument to the list of nodes. + * + * @param \DOMDocument $dom A \DOMDocument instance + * + * @return void + */ + public function addDocument(\DOMDocument $dom) + { + if ($dom->documentElement) { + $this->addNode($dom->documentElement); + } + } + + /** + * Adds a \DOMNodeList to the list of nodes. + * + * @param \DOMNodeList $nodes A \DOMNodeList instance + * + * @return void + */ + public function addNodeList(\DOMNodeList $nodes) + { + foreach ($nodes as $node) { + if ($node instanceof \DOMNode) { + $this->addNode($node); + } + } + } + + /** + * Adds an array of \DOMNode instances to the list of nodes. + * + * @param \DOMNode[] $nodes An array of \DOMNode instances + * + * @return void + */ + public function addNodes(array $nodes) + { + foreach ($nodes as $node) { + $this->add($node); + } + } + + /** + * Adds a \DOMNode instance to the list of nodes. + * + * @param \DOMNode $node A \DOMNode instance + * + * @return void + */ + public function addNode(\DOMNode $node) + { + if ($node instanceof \DOMDocument) { + $node = $node->documentElement; + } + + if (null !== $this->document && $this->document !== $node->ownerDocument) { + throw new \InvalidArgumentException('Attaching DOM nodes from multiple documents in the same crawler is forbidden.'); + } + + $this->document ??= $node->ownerDocument; + + // Don't add duplicate nodes in the Crawler + if (\in_array($node, $this->nodes, true)) { + return; + } + + $this->nodes[] = $node; + } + + /** + * Returns a node given its position in the node list. + */ + public function eq(int $position): static + { + if (isset($this->nodes[$position])) { + return $this->createSubCrawler($this->nodes[$position]); + } + + return $this->createSubCrawler(null); + } + + /** + * Calls an anonymous function on each node of the list. + * + * The anonymous function receives the position and the node wrapped + * in a Crawler instance as arguments. + * + * Example: + * + * $crawler->filter('h1')->each(function ($node, $i) { + * return $node->text(); + * }); + * + * @param \Closure $closure An anonymous function + * + * @return array An array of values returned by the anonymous function + */ + public function each(\Closure $closure): array + { + $data = []; + foreach ($this->nodes as $i => $node) { + $data[] = $closure($this->createSubCrawler($node), $i); + } + + return $data; + } + + /** + * Slices the list of nodes by $offset and $length. + */ + public function slice(int $offset = 0, ?int $length = null): static + { + return $this->createSubCrawler(\array_slice($this->nodes, $offset, $length)); + } + + /** + * Reduces the list of nodes by calling an anonymous function. + * + * To remove a node from the list, the anonymous function must return false. + * + * @param \Closure $closure An anonymous function + */ + public function reduce(\Closure $closure): static + { + $nodes = []; + foreach ($this->nodes as $i => $node) { + if (false !== $closure($this->createSubCrawler($node), $i)) { + $nodes[] = $node; + } + } + + return $this->createSubCrawler($nodes); + } + + /** + * Returns the first node of the current selection. + */ + public function first(): static + { + return $this->eq(0); + } + + /** + * Returns the last node of the current selection. + */ + public function last(): static + { + return $this->eq(\count($this->nodes) - 1); + } + + /** + * Returns the siblings nodes of the current selection. + * + * @throws \InvalidArgumentException When current node is empty + */ + public function siblings(): static + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + return $this->createSubCrawler($this->sibling($this->getNode(0)->parentNode->firstChild)); + } + + public function matches(string $selector): bool + { + if (!$this->nodes) { + return false; + } + + $converter = $this->createCssSelectorConverter(); + $xpath = $converter->toXPath($selector, 'self::'); + + return 0 !== $this->filterRelativeXPath($xpath)->count(); + } + + /** + * Return first parents (heading toward the document root) of the Element that matches the provided selector. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill + * + * @throws \InvalidArgumentException When current node is empty + */ + public function closest(string $selector): ?self + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $domNode = $this->getNode(0); + + while (\XML_ELEMENT_NODE === $domNode->nodeType) { + $node = $this->createSubCrawler($domNode); + if ($node->matches($selector)) { + return $node; + } + + $domNode = $node->getNode(0)->parentNode; + } + + return null; + } + + /** + * Returns the next siblings nodes of the current selection. + * + * @throws \InvalidArgumentException When current node is empty + */ + public function nextAll(): static + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + return $this->createSubCrawler($this->sibling($this->getNode(0))); + } + + /** + * Returns the previous sibling nodes of the current selection. + * + * @throws \InvalidArgumentException + */ + public function previousAll(): static + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + return $this->createSubCrawler($this->sibling($this->getNode(0), 'previousSibling')); + } + + /** + * Returns the ancestors of the current selection. + * + * @throws \InvalidArgumentException When the current node is empty + */ + public function ancestors(): static + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + $nodes = []; + + while ($node = $node->parentNode) { + if (\XML_ELEMENT_NODE === $node->nodeType) { + $nodes[] = $node; + } + } + + return $this->createSubCrawler($nodes); + } + + /** + * Returns the children nodes of the current selection. + * + * @throws \InvalidArgumentException When current node is empty + * @throws \RuntimeException If the CssSelector Component is not available and $selector is provided + */ + public function children(?string $selector = null): static + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + if (null !== $selector) { + $converter = $this->createCssSelectorConverter(); + $xpath = $converter->toXPath($selector, 'child::'); + + return $this->filterRelativeXPath($xpath); + } + + $node = $this->getNode(0)->firstChild; + + return $this->createSubCrawler($node ? $this->sibling($node) : []); + } + + /** + * Returns the attribute value of the first node of the list. + * + * @param string|null $default When not null: the value to return when the node or attribute is empty + * + * @throws \InvalidArgumentException When current node is empty + */ + public function attr(string $attribute/* , string $default = null */): ?string + { + $default = \func_num_args() > 1 ? func_get_arg(1) : null; + if (!$this->nodes) { + if (null !== $default) { + return $default; + } + + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + + return $node->hasAttribute($attribute) ? $node->getAttribute($attribute) : $default; + } + + /** + * Returns the node name of the first node of the list. + * + * @throws \InvalidArgumentException When current node is empty + */ + public function nodeName(): string + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + return $this->getNode(0)->nodeName; + } + + /** + * Returns the text of the first node of the list. + * + * Pass true as the second argument to normalize whitespaces. + * + * @param string|null $default When not null: the value to return when the current node is empty + * @param bool $normalizeWhitespace Whether whitespaces should be trimmed and normalized to single spaces + * + * @throws \InvalidArgumentException When current node is empty + */ + public function text(?string $default = null, bool $normalizeWhitespace = true): string + { + if (!$this->nodes) { + if (null !== $default) { + return $default; + } + + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $text = $this->getNode(0)->nodeValue; + + if ($normalizeWhitespace) { + return $this->normalizeWhitespace($text); + } + + return $text; + } + + /** + * Returns only the inner text that is the direct descendent of the current node, excluding any child nodes. + * + * @param bool $normalizeWhitespace Whether whitespaces should be trimmed and normalized to single spaces + */ + public function innerText(/* bool $normalizeWhitespace = true */): string + { + $normalizeWhitespace = 1 <= \func_num_args() ? func_get_arg(0) : true; + + foreach ($this->getNode(0)->childNodes as $childNode) { + if (\XML_TEXT_NODE !== $childNode->nodeType && \XML_CDATA_SECTION_NODE !== $childNode->nodeType) { + continue; + } + if (!$normalizeWhitespace) { + return $childNode->nodeValue; + } + if ('' !== trim($childNode->nodeValue)) { + return $this->normalizeWhitespace($childNode->nodeValue); + } + } + + return ''; + } + + /** + * Returns the first node of the list as HTML. + * + * @param string|null $default When not null: the value to return when the current node is empty + * + * @throws \InvalidArgumentException When current node is empty + */ + public function html(?string $default = null): string + { + if (!$this->nodes) { + if (null !== $default) { + return $default; + } + + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + $owner = $node->ownerDocument; + + if ($this->html5Parser && '' === $owner->saveXML($owner->childNodes[0])) { + $owner = $this->html5Parser; + } + + $html = ''; + foreach ($node->childNodes as $child) { + $html .= $owner->saveHTML($child); + } + + return $html; + } + + public function outerHtml(): string + { + if (!\count($this)) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + $owner = $node->ownerDocument; + + if ($this->html5Parser && '' === $owner->saveXML($owner->childNodes[0])) { + $owner = $this->html5Parser; + } + + return $owner->saveHTML($node); + } + + /** + * Evaluates an XPath expression. + * + * Since an XPath expression might evaluate to either a simple type or a \DOMNodeList, + * this method will return either an array of simple types or a new Crawler instance. + */ + public function evaluate(string $xpath): array|self + { + if (null === $this->document) { + throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.'); + } + + $data = []; + $domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath)); + + foreach ($this->nodes as $node) { + $data[] = $domxpath->evaluate($xpath, $node); + } + + if (isset($data[0]) && $data[0] instanceof \DOMNodeList) { + return $this->createSubCrawler($data); + } + + return $data; + } + + /** + * Extracts information from the list of nodes. + * + * You can extract attributes or/and the node value (_text). + * + * Example: + * + * $crawler->filter('h1 a')->extract(['_text', 'href']); + */ + public function extract(array $attributes): array + { + $count = \count($attributes); + + $data = []; + foreach ($this->nodes as $node) { + $elements = []; + foreach ($attributes as $attribute) { + if ('_text' === $attribute) { + $elements[] = $node->nodeValue; + } elseif ('_name' === $attribute) { + $elements[] = $node->nodeName; + } else { + $elements[] = $node->getAttribute($attribute); + } + } + + $data[] = 1 === $count ? $elements[0] : $elements; + } + + return $data; + } + + /** + * Filters the list of nodes with an XPath expression. + * + * The XPath expression is evaluated in the context of the crawler, which + * is considered as a fake parent of the elements inside it. + * This means that a child selector "div" or "./div" will match only + * the div elements of the current crawler, not their children. + */ + public function filterXPath(string $xpath): static + { + $xpath = $this->relativize($xpath); + + // If we dropped all expressions in the XPath while preparing it, there would be no match + if ('' === $xpath) { + return $this->createSubCrawler(null); + } + + return $this->filterRelativeXPath($xpath); + } + + /** + * Filters the list of nodes with a CSS selector. + * + * This method only works if you have installed the CssSelector Symfony Component. + * + * @throws \LogicException if the CssSelector Component is not available + */ + public function filter(string $selector): static + { + $converter = $this->createCssSelectorConverter(); + + // The CssSelector already prefixes the selector with descendant-or-self:: + return $this->filterRelativeXPath($converter->toXPath($selector)); + } + + /** + * Selects links by name or alt value for clickable images. + */ + public function selectLink(string $value): static + { + return $this->filterRelativeXPath( + sprintf('descendant-or-self::a[contains(concat(\' \', normalize-space(string(.)), \' \'), %1$s) or ./img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %1$s)]]', static::xpathLiteral(' '.$value.' ')) + ); + } + + /** + * Selects images by alt value. + */ + public function selectImage(string $value): static + { + $xpath = sprintf('descendant-or-self::img[contains(normalize-space(string(@alt)), %s)]', static::xpathLiteral($value)); + + return $this->filterRelativeXPath($xpath); + } + + /** + * Selects a button by name or alt value for images. + */ + public function selectButton(string $value): static + { + return $this->filterRelativeXPath( + sprintf('descendant-or-self::input[((contains(%1$s, "submit") or contains(%1$s, "button")) and contains(concat(\' \', normalize-space(string(@value)), \' \'), %2$s)) or (contains(%1$s, "image") and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %2$s)) or @id=%3$s or @name=%3$s] | descendant-or-self::button[contains(concat(\' \', normalize-space(string(.)), \' \'), %2$s) or @id=%3$s or @name=%3$s]', 'translate(@type, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")', static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value)) + ); + } + + /** + * Returns a Link object for the first node in the list. + * + * @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement + */ + public function link(string $method = 'get'): Link + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + + if (!$node instanceof \DOMElement) { + throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); + } + + return new Link($node, $this->baseHref, $method); + } + + /** + * Returns an array of Link objects for the nodes in the list. + * + * @return Link[] + * + * @throws \InvalidArgumentException If the current node list contains non-DOMElement instances + */ + public function links(): array + { + $links = []; + foreach ($this->nodes as $node) { + if (!$node instanceof \DOMElement) { + throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', get_debug_type($node))); + } + + $links[] = new Link($node, $this->baseHref, 'get'); + } + + return $links; + } + + /** + * Returns an Image object for the first node in the list. + * + * @throws \InvalidArgumentException If the current node list is empty + */ + public function image(): Image + { + if (!\count($this)) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + + if (!$node instanceof \DOMElement) { + throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); + } + + return new Image($node, $this->baseHref); + } + + /** + * Returns an array of Image objects for the nodes in the list. + * + * @return Image[] + */ + public function images(): array + { + $images = []; + foreach ($this as $node) { + if (!$node instanceof \DOMElement) { + throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', get_debug_type($node))); + } + + $images[] = new Image($node, $this->baseHref); + } + + return $images; + } + + /** + * Returns a Form object for the first node in the list. + * + * @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement + */ + public function form(?array $values = null, ?string $method = null): Form + { + if (!$this->nodes) { + throw new \InvalidArgumentException('The current node list is empty.'); + } + + $node = $this->getNode(0); + + if (!$node instanceof \DOMElement) { + throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); + } + + $form = new Form($node, $this->uri, $method, $this->baseHref); + + if (null !== $values) { + $form->setValues($values); + } + + return $form; + } + + /** + * Overloads a default namespace prefix to be used with XPath and CSS expressions. + * + * @return void + */ + public function setDefaultNamespacePrefix(string $prefix) + { + $this->defaultNamespacePrefix = $prefix; + } + + /** + * @return void + */ + public function registerNamespace(string $prefix, string $namespace) + { + $this->namespaces[$prefix] = $namespace; + } + + /** + * Converts string for XPath expressions. + * + * Escaped characters are: quotes (") and apostrophe ('). + * + * Examples: + * + * echo Crawler::xpathLiteral('foo " bar'); + * //prints 'foo " bar' + * + * echo Crawler::xpathLiteral("foo ' bar"); + * //prints "foo ' bar" + * + * echo Crawler::xpathLiteral('a\'b"c'); + * //prints concat('a', "'", 'b"c') + */ + public static function xpathLiteral(string $s): string + { + if (!str_contains($s, "'")) { + return sprintf("'%s'", $s); + } + + if (!str_contains($s, '"')) { + return sprintf('"%s"', $s); + } + + $string = $s; + $parts = []; + while (true) { + if (false !== $pos = strpos($string, "'")) { + $parts[] = sprintf("'%s'", substr($string, 0, $pos)); + $parts[] = "\"'\""; + $string = substr($string, $pos + 1); + } else { + $parts[] = "'$string'"; + break; + } + } + + return sprintf('concat(%s)', implode(', ', $parts)); + } + + /** + * Filters the list of nodes with an XPath expression. + * + * The XPath expression should already be processed to apply it in the context of each node. + */ + private function filterRelativeXPath(string $xpath): static + { + $crawler = $this->createSubCrawler(null); + if (null === $this->document) { + return $crawler; + } + + $domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath)); + + foreach ($this->nodes as $node) { + $crawler->add($domxpath->query($xpath, $node)); + } + + return $crawler; + } + + /** + * Make the XPath relative to the current context. + * + * The returned XPath will match elements matching the XPath inside the current crawler + * when running in the context of a node of the crawler. + */ + private function relativize(string $xpath): string + { + $expressions = []; + + // An expression which will never match to replace expressions which cannot match in the crawler + // We cannot drop + $nonMatchingExpression = 'a[name() = "b"]'; + + $xpathLen = \strlen($xpath); + $openedBrackets = 0; + $startPosition = strspn($xpath, " \t\n\r\0\x0B"); + + for ($i = $startPosition; $i <= $xpathLen; ++$i) { + $i += strcspn($xpath, '"\'[]|', $i); + + if ($i < $xpathLen) { + switch ($xpath[$i]) { + case '"': + case "'": + if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) { + return $xpath; // The XPath expression is invalid + } + continue 2; + case '[': + ++$openedBrackets; + continue 2; + case ']': + --$openedBrackets; + continue 2; + } + } + if ($openedBrackets) { + continue; + } + + if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) { + // If the union is inside some braces, we need to preserve the opening braces and apply + // the change only inside it. + $j = 1 + strspn($xpath, "( \t\n\r\0\x0B", $startPosition + 1); + $parenthesis = substr($xpath, $startPosition, $j); + $startPosition += $j; + } else { + $parenthesis = ''; + } + $expression = rtrim(substr($xpath, $startPosition, $i - $startPosition)); + + if (str_starts_with($expression, 'self::*/')) { + $expression = './'.substr($expression, 8); + } + + // add prefix before absolute element selector + if ('' === $expression) { + $expression = $nonMatchingExpression; + } elseif (str_starts_with($expression, '//')) { + $expression = 'descendant-or-self::'.substr($expression, 2); + } elseif (str_starts_with($expression, './/')) { + $expression = 'descendant-or-self::'.substr($expression, 3); + } elseif (str_starts_with($expression, './')) { + $expression = 'self::'.substr($expression, 2); + } elseif (str_starts_with($expression, 'child::')) { + $expression = 'self::'.substr($expression, 7); + } elseif ('/' === $expression[0] || '.' === $expression[0] || str_starts_with($expression, 'self::')) { + $expression = $nonMatchingExpression; + } elseif (str_starts_with($expression, 'descendant::')) { + $expression = 'descendant-or-self::'.substr($expression, 12); + } elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) { + // the fake root has no parent, preceding or following nodes and also no attributes (even no namespace attributes) + $expression = $nonMatchingExpression; + } elseif (!str_starts_with($expression, 'descendant-or-self::')) { + $expression = 'self::'.$expression; + } + $expressions[] = $parenthesis.$expression; + + if ($i === $xpathLen) { + return implode(' | ', $expressions); + } + + $i += strspn($xpath, " \t\n\r\0\x0B", $i + 1); + $startPosition = $i + 1; + } + + return $xpath; // The XPath expression is invalid + } + + public function getNode(int $position): ?\DOMNode + { + return $this->nodes[$position] ?? null; + } + + public function count(): int + { + return \count($this->nodes); + } + + /** + * @return \ArrayIterator + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->nodes); + } + + protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling'): array + { + $nodes = []; + + $currentNode = $this->getNode(0); + do { + if ($node !== $currentNode && \XML_ELEMENT_NODE === $node->nodeType) { + $nodes[] = $node; + } + } while ($node = $node->$siblingDir); + + return $nodes; + } + + private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument + { + if (!$this->supportsEncoding($charset)) { + $htmlContent = $this->convertToHtmlEntities($htmlContent, $charset); + $charset = 'UTF-8'; + } + + return $this->html5Parser->parse($htmlContent, ['encoding' => $charset]); + } + + private function supportsEncoding(string $encoding): bool + { + try { + return '' === @mb_convert_encoding('', $encoding, 'UTF-8'); + } catch (\Throwable $e) { + return false; + } + } + + private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument + { + if ('UTF-8' === $charset && preg_match('//u', $htmlContent)) { + $htmlContent = ''.$htmlContent; + } else { + $htmlContent = $this->convertToHtmlEntities($htmlContent, $charset); + } + + $internalErrors = libxml_use_internal_errors(true); + + $dom = new \DOMDocument('1.0', $charset); + $dom->validateOnParse = true; + + if ('' !== trim($htmlContent)) { + @$dom->loadHTML($htmlContent); + } + + libxml_use_internal_errors($internalErrors); + + return $dom; + } + + /** + * Converts charset to HTML-entities to ensure valid parsing. + */ + private function convertToHtmlEntities(string $htmlContent, string $charset = 'UTF-8'): string + { + set_error_handler(static fn () => throw new \Exception()); + + try { + return mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], $charset); + } catch (\Exception|\ValueError) { + try { + $htmlContent = iconv($charset, 'UTF-8', $htmlContent); + $htmlContent = mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); + } catch (\Exception|\ValueError) { + } + + return $htmlContent; + } finally { + restore_error_handler(); + } + } + + /** + * @throws \InvalidArgumentException + */ + private function createDOMXPath(\DOMDocument $document, array $prefixes = []): \DOMXPath + { + $domxpath = new \DOMXPath($document); + + foreach ($prefixes as $prefix) { + $namespace = $this->discoverNamespace($domxpath, $prefix); + if (null !== $namespace) { + $domxpath->registerNamespace($prefix, $namespace); + } + } + + return $domxpath; + } + + /** + * @throws \InvalidArgumentException + */ + private function discoverNamespace(\DOMXPath $domxpath, string $prefix): ?string + { + if (\array_key_exists($prefix, $this->namespaces)) { + return $this->namespaces[$prefix]; + } + + if ($this->cachedNamespaces->offsetExists($prefix)) { + return $this->cachedNamespaces[$prefix]; + } + + // ask for one namespace, otherwise we'd get a collection with an item for each node + $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', $this->defaultNamespacePrefix === $prefix ? '' : $prefix)); + + return $this->cachedNamespaces[$prefix] = ($node = $namespaces->item(0)) ? $node->nodeValue : null; + } + + private function findNamespacePrefixes(string $xpath): array + { + if (preg_match_all('/(?P[a-z_][a-z_0-9\-\.]*+):[^"\/:]/i', $xpath, $matches)) { + return array_unique($matches['prefix']); + } + + return []; + } + + /** + * Creates a crawler for some subnodes. + * + * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $nodes + */ + private function createSubCrawler(\DOMNodeList|\DOMNode|array|string|null $nodes): static + { + $crawler = new static($nodes, $this->uri, $this->baseHref); + $crawler->isHtml = $this->isHtml; + $crawler->document = $this->document; + $crawler->namespaces = $this->namespaces; + $crawler->cachedNamespaces = $this->cachedNamespaces; + $crawler->html5Parser = $this->html5Parser; + + return $crawler; + } + + /** + * @throws \LogicException If the CssSelector Component is not available + */ + private function createCssSelectorConverter(): CssSelectorConverter + { + if (!class_exists(CssSelectorConverter::class)) { + throw new \LogicException('To filter with a CSS selector, install the CssSelector component ("composer require symfony/css-selector"). Or use filterXpath instead.'); + } + + return new CssSelectorConverter($this->isHtml); + } + + /** + * Parse string into DOMDocument object using HTML5 parser if the content is HTML5 and the library is available. + * Use libxml parser otherwise. + */ + private function parseHtmlString(string $content, string $charset): \DOMDocument + { + if ($this->canParseHtml5String($content)) { + return $this->parseHtml5($content, $charset); + } + + return $this->parseXhtml($content, $charset); + } + + private function canParseHtml5String(string $content): bool + { + if (!$this->html5Parser) { + return false; + } + + if (false === ($pos = stripos($content, ''))) { + return false; + } + + $header = substr($content, 0, $pos); + + return '' === $header || $this->isValidHtml5Heading($header); + } + + private function isValidHtml5Heading(string $heading): bool + { + return 1 === preg_match('/^\x{FEFF}?\s*(\s*)*$/u', $heading); + } + + private function normalizeWhitespace(string $string): string + { + return trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $string), " \n\r\t\x0C"); + } +} diff --git a/vendor/symfony/dom-crawler/Field/ChoiceFormField.php b/vendor/symfony/dom-crawler/Field/ChoiceFormField.php new file mode 100644 index 000000000..dcae5490a --- /dev/null +++ b/vendor/symfony/dom-crawler/Field/ChoiceFormField.php @@ -0,0 +1,305 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Field; + +/** + * ChoiceFormField represents a choice form field. + * + * It is constructed from an HTML select tag, or an HTML checkbox, or radio inputs. + * + * @author Fabien Potencier + */ +class ChoiceFormField extends FormField +{ + private string $type; + private bool $multiple; + private array $options; + private bool $validationDisabled = false; + + /** + * Returns true if the field should be included in the submitted values. + * + * @return bool true if the field should be included in the submitted values, false otherwise + */ + public function hasValue(): bool + { + // don't send a value for unchecked checkboxes + if (\in_array($this->type, ['checkbox', 'radio']) && null === $this->value) { + return false; + } + + return true; + } + + /** + * Check if the current selected option is disabled. + */ + public function isDisabled(): bool + { + if (parent::isDisabled() && 'select' === $this->type) { + return true; + } + + foreach ($this->options as $option) { + if ($option['value'] == $this->value && $option['disabled']) { + return true; + } + } + + return false; + } + + /** + * Sets the value of the field. + * + * @return void + */ + public function select(string|array|bool $value) + { + $this->setValue($value); + } + + /** + * Ticks a checkbox. + * + * @return void + * + * @throws \LogicException When the type provided is not correct + */ + public function tick() + { + if ('checkbox' !== $this->type) { + throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); + } + + $this->setValue(true); + } + + /** + * Unticks a checkbox. + * + * @return void + * + * @throws \LogicException When the type provided is not correct + */ + public function untick() + { + if ('checkbox' !== $this->type) { + throw new \LogicException(sprintf('You cannot untick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); + } + + $this->setValue(false); + } + + /** + * Sets the value of the field. + * + * @return void + * + * @throws \InvalidArgumentException When value type provided is not correct + */ + public function setValue(string|array|bool|null $value) + { + if ('checkbox' === $this->type && false === $value) { + // uncheck + $this->value = null; + } elseif ('checkbox' === $this->type && true === $value) { + // check + $this->value = $this->options[0]['value']; + } else { + if (\is_array($value)) { + if (!$this->multiple) { + throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name)); + } + + foreach ($value as $v) { + if (!$this->containsOption($v, $this->options)) { + throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $v, implode('", "', $this->availableOptionValues()))); + } + } + } elseif (!$this->containsOption($value, $this->options)) { + throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $value, implode('", "', $this->availableOptionValues()))); + } + + if ($this->multiple) { + $value = (array) $value; + } + + if (\is_array($value)) { + $this->value = $value; + } else { + parent::setValue($value); + } + } + } + + /** + * Adds a choice to the current ones. + * + * @throws \LogicException When choice provided is not multiple nor radio + * + * @internal + */ + public function addChoice(\DOMElement $node): void + { + if (!$this->multiple && 'radio' !== $this->type) { + throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name)); + } + + $option = $this->buildOptionValue($node); + $this->options[] = $option; + + if ($node->hasAttribute('checked')) { + $this->value = $option['value']; + } + } + + /** + * Returns the type of the choice field (radio, select, or checkbox). + */ + public function getType(): string + { + return $this->type; + } + + /** + * Returns true if the field accepts multiple values. + */ + public function isMultiple(): bool + { + return $this->multiple; + } + + /** + * Initializes the form field. + * + * @return void + * + * @throws \LogicException When node type is incorrect + */ + protected function initialize() + { + if ('input' !== $this->node->nodeName && 'select' !== $this->node->nodeName) { + throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName)); + } + + if ('input' === $this->node->nodeName && 'checkbox' !== strtolower($this->node->getAttribute('type')) && 'radio' !== strtolower($this->node->getAttribute('type'))) { + throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is "%s").', $this->node->getAttribute('type'))); + } + + $this->value = null; + $this->options = []; + $this->multiple = false; + + if ('input' == $this->node->nodeName) { + $this->type = strtolower($this->node->getAttribute('type')); + $optionValue = $this->buildOptionValue($this->node); + $this->options[] = $optionValue; + + if ($this->node->hasAttribute('checked')) { + $this->value = $optionValue['value']; + } + } else { + $this->type = 'select'; + if ($this->node->hasAttribute('multiple')) { + $this->multiple = true; + $this->value = []; + $this->name = str_replace('[]', '', $this->name); + } + + $found = false; + foreach ($this->xpath->query('descendant::option', $this->node) as $option) { + $optionValue = $this->buildOptionValue($option); + $this->options[] = $optionValue; + + if ($option->hasAttribute('selected')) { + $found = true; + if ($this->multiple) { + $this->value[] = $optionValue['value']; + } else { + $this->value = $optionValue['value']; + } + } + } + + // if no option is selected and if it is a simple select box, take the first option as the value + if (!$found && !$this->multiple && $this->options) { + $this->value = $this->options[0]['value']; + } + } + } + + /** + * Returns option value with associated disabled flag. + */ + private function buildOptionValue(\DOMElement $node): array + { + $option = []; + + $defaultDefaultValue = 'select' === $this->node->nodeName ? '' : 'on'; + $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : $defaultDefaultValue; + $option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue; + $option['disabled'] = $node->hasAttribute('disabled'); + + return $option; + } + + /** + * Checks whether given value is in the existing options. + * + * @internal + */ + public function containsOption(string $optionValue, array $options): bool + { + if ($this->validationDisabled) { + return true; + } + + foreach ($options as $option) { + if ($option['value'] == $optionValue) { + return true; + } + } + + return false; + } + + /** + * Returns list of available field options. + * + * @internal + */ + public function availableOptionValues(): array + { + $values = []; + + foreach ($this->options as $option) { + $values[] = $option['value']; + } + + return $values; + } + + /** + * Disables the internal validation of the field. + * + * @internal + * + * @return $this + */ + public function disableValidation(): static + { + $this->validationDisabled = true; + + return $this; + } +} diff --git a/vendor/symfony/dom-crawler/Field/FileFormField.php b/vendor/symfony/dom-crawler/Field/FileFormField.php new file mode 100644 index 000000000..4ebe766f0 --- /dev/null +++ b/vendor/symfony/dom-crawler/Field/FileFormField.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Field; + +/** + * FileFormField represents a file form field (an HTML file input tag). + * + * @author Fabien Potencier + */ +class FileFormField extends FormField +{ + /** + * Sets the PHP error code associated with the field. + * + * @param int $error The error code (one of UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, UPLOAD_ERR_PARTIAL, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_NO_TMP_DIR, UPLOAD_ERR_CANT_WRITE, or UPLOAD_ERR_EXTENSION) + * + * @return void + * + * @throws \InvalidArgumentException When error code doesn't exist + */ + public function setErrorCode(int $error) + { + $codes = [\UPLOAD_ERR_INI_SIZE, \UPLOAD_ERR_FORM_SIZE, \UPLOAD_ERR_PARTIAL, \UPLOAD_ERR_NO_FILE, \UPLOAD_ERR_NO_TMP_DIR, \UPLOAD_ERR_CANT_WRITE, \UPLOAD_ERR_EXTENSION]; + if (!\in_array($error, $codes)) { + throw new \InvalidArgumentException(sprintf('The error code "%s" is not valid.', $error)); + } + + $this->value = ['name' => '', 'type' => '', 'tmp_name' => '', 'error' => $error, 'size' => 0]; + } + + /** + * Sets the value of the field. + * + * @return void + */ + public function upload(?string $value) + { + $this->setValue($value); + } + + /** + * Sets the value of the field. + * + * @return void + */ + public function setValue(?string $value) + { + if (null !== $value && is_readable($value)) { + $error = \UPLOAD_ERR_OK; + $size = filesize($value); + $info = pathinfo($value); + $name = $info['basename']; + + // copy to a tmp location + $tmp = sys_get_temp_dir().'/'.strtr(substr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), 0, 7), '/', '_'); + if (\array_key_exists('extension', $info)) { + $tmp .= '.'.$info['extension']; + } + if (is_file($tmp)) { + unlink($tmp); + } + copy($value, $tmp); + $value = $tmp; + } else { + $error = \UPLOAD_ERR_NO_FILE; + $size = 0; + $name = ''; + $value = ''; + } + + $this->value = ['name' => $name, 'type' => '', 'tmp_name' => $value, 'error' => $error, 'size' => $size]; + } + + /** + * Sets path to the file as string for simulating HTTP request. + * + * @return void + */ + public function setFilePath(string $path) + { + parent::setValue($path); + } + + /** + * Initializes the form field. + * + * @return void + * + * @throws \LogicException When node type is incorrect + */ + protected function initialize() + { + if ('input' !== $this->node->nodeName) { + throw new \LogicException(sprintf('A FileFormField can only be created from an input tag (%s given).', $this->node->nodeName)); + } + + if ('file' !== strtolower($this->node->getAttribute('type'))) { + throw new \LogicException(sprintf('A FileFormField can only be created from an input tag with a type of file (given type is "%s").', $this->node->getAttribute('type'))); + } + + $this->setValue(null); + } +} diff --git a/vendor/symfony/dom-crawler/Field/FormField.php b/vendor/symfony/dom-crawler/Field/FormField.php new file mode 100644 index 000000000..b97d54dda --- /dev/null +++ b/vendor/symfony/dom-crawler/Field/FormField.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Field; + +/** + * FormField is the abstract class for all form fields. + * + * @author Fabien Potencier + */ +abstract class FormField +{ + /** + * @var \DOMElement + */ + protected $node; + /** + * @var string + */ + protected $name; + /** + * @var string + */ + protected $value; + /** + * @var \DOMDocument + */ + protected $document; + /** + * @var \DOMXPath + */ + protected $xpath; + /** + * @var bool + */ + protected $disabled; + + /** + * @param \DOMElement $node The node associated with this field + */ + public function __construct(\DOMElement $node) + { + $this->node = $node; + $this->name = $node->getAttribute('name'); + $this->xpath = new \DOMXPath($node->ownerDocument); + + $this->initialize(); + } + + /** + * Returns the label tag associated to the field or null if none. + */ + public function getLabel(): ?\DOMElement + { + $xpath = new \DOMXPath($this->node->ownerDocument); + + if ($this->node->hasAttribute('id')) { + $labels = $xpath->query(sprintf('descendant::label[@for="%s"]', $this->node->getAttribute('id'))); + if ($labels->length > 0) { + return $labels->item(0); + } + } + + $labels = $xpath->query('ancestor::label[1]', $this->node); + + return $labels->length > 0 ? $labels->item(0) : null; + } + + /** + * Returns the name of the field. + */ + public function getName(): string + { + return $this->name; + } + + /** + * Gets the value of the field. + */ + public function getValue(): string|array|null + { + return $this->value; + } + + /** + * Sets the value of the field. + * + * @return void + */ + public function setValue(?string $value) + { + $this->value = $value ?? ''; + } + + /** + * Returns true if the field should be included in the submitted values. + */ + public function hasValue(): bool + { + return true; + } + + /** + * Check if the current field is disabled. + */ + public function isDisabled(): bool + { + return $this->node->hasAttribute('disabled'); + } + + /** + * Initializes the form field. + * + * @return void + */ + abstract protected function initialize(); +} diff --git a/vendor/symfony/dom-crawler/Field/InputFormField.php b/vendor/symfony/dom-crawler/Field/InputFormField.php new file mode 100644 index 000000000..19d77352f --- /dev/null +++ b/vendor/symfony/dom-crawler/Field/InputFormField.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Field; + +/** + * InputFormField represents an input form field (an HTML input tag). + * + * For inputs with type of file, checkbox, or radio, there are other more + * specialized classes (cf. FileFormField and ChoiceFormField). + * + * @author Fabien Potencier + */ +class InputFormField extends FormField +{ + /** + * Initializes the form field. + * + * @return void + * + * @throws \LogicException When node type is incorrect + */ + protected function initialize() + { + if ('input' !== $this->node->nodeName && 'button' !== $this->node->nodeName) { + throw new \LogicException(sprintf('An InputFormField can only be created from an input or button tag (%s given).', $this->node->nodeName)); + } + + $type = strtolower($this->node->getAttribute('type')); + if ('checkbox' === $type) { + throw new \LogicException('Checkboxes should be instances of ChoiceFormField.'); + } + + if ('file' === $type) { + throw new \LogicException('File inputs should be instances of FileFormField.'); + } + + $this->value = $this->node->getAttribute('value'); + } +} diff --git a/vendor/symfony/dom-crawler/Field/TextareaFormField.php b/vendor/symfony/dom-crawler/Field/TextareaFormField.php new file mode 100644 index 000000000..5168c5225 --- /dev/null +++ b/vendor/symfony/dom-crawler/Field/TextareaFormField.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Field; + +/** + * TextareaFormField represents a textarea form field (an HTML textarea tag). + * + * @author Fabien Potencier + */ +class TextareaFormField extends FormField +{ + /** + * Initializes the form field. + * + * @return void + * + * @throws \LogicException When node type is incorrect + */ + protected function initialize() + { + if ('textarea' !== $this->node->nodeName) { + throw new \LogicException(sprintf('A TextareaFormField can only be created from a textarea tag (%s given).', $this->node->nodeName)); + } + + $this->value = ''; + foreach ($this->node->childNodes as $node) { + $this->value .= $node->wholeText; + } + } +} diff --git a/vendor/symfony/dom-crawler/Form.php b/vendor/symfony/dom-crawler/Form.php new file mode 100644 index 000000000..fd55546fe --- /dev/null +++ b/vendor/symfony/dom-crawler/Form.php @@ -0,0 +1,470 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +use Symfony\Component\DomCrawler\Field\ChoiceFormField; +use Symfony\Component\DomCrawler\Field\FormField; + +/** + * Form represents an HTML form. + * + * @author Fabien Potencier + */ +class Form extends Link implements \ArrayAccess +{ + private \DOMElement $button; + private FormFieldRegistry $fields; + private ?string $baseHref; + + /** + * @param \DOMElement $node A \DOMElement instance + * @param string|null $currentUri The URI of the page where the form is embedded + * @param string|null $method The method to use for the link (if null, it defaults to the method defined by the form) + * @param string|null $baseHref The URI of the used for relative links, but not for empty action + * + * @throws \LogicException if the node is not a button inside a form tag + */ + public function __construct(\DOMElement $node, ?string $currentUri = null, ?string $method = null, ?string $baseHref = null) + { + parent::__construct($node, $currentUri, $method); + $this->baseHref = $baseHref; + + $this->initialize(); + } + + /** + * Gets the form node associated with this form. + */ + public function getFormNode(): \DOMElement + { + return $this->node; + } + + /** + * Sets the value of the fields. + * + * @param array $values An array of field values + * + * @return $this + */ + public function setValues(array $values): static + { + foreach ($values as $name => $value) { + $this->fields->set($name, $value); + } + + return $this; + } + + /** + * Gets the field values. + * + * The returned array does not include file fields (@see getFiles). + */ + public function getValues(): array + { + $values = []; + foreach ($this->fields->all() as $name => $field) { + if ($field->isDisabled()) { + continue; + } + + if (!$field instanceof Field\FileFormField && $field->hasValue()) { + $values[$name] = $field->getValue(); + } + } + + return $values; + } + + /** + * Gets the file field values. + */ + public function getFiles(): array + { + if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) { + return []; + } + + $files = []; + + foreach ($this->fields->all() as $name => $field) { + if ($field->isDisabled()) { + continue; + } + + if ($field instanceof Field\FileFormField) { + $files[$name] = $field->getValue(); + } + } + + return $files; + } + + /** + * Gets the field values as PHP. + * + * This method converts fields with the array notation + * (like foo[bar] to arrays) like PHP does. + */ + public function getPhpValues(): array + { + $values = []; + foreach ($this->getValues() as $name => $value) { + $qs = http_build_query([$name => $value], '', '&'); + if (!empty($qs)) { + parse_str($qs, $expandedValue); + $varName = substr($name, 0, \strlen(key($expandedValue))); + $values[] = [$varName => current($expandedValue)]; + } + } + + return array_replace_recursive([], ...$values); + } + + /** + * Gets the file field values as PHP. + * + * This method converts fields with the array notation + * (like foo[bar] to arrays) like PHP does. + * The returned array is consistent with the array for field values + * (@see getPhpValues), rather than uploaded files found in $_FILES. + * For a compound file field foo[bar] it will create foo[bar][name], + * instead of foo[name][bar] which would be found in $_FILES. + */ + public function getPhpFiles(): array + { + $values = []; + foreach ($this->getFiles() as $name => $value) { + $qs = http_build_query([$name => $value], '', '&'); + if (!empty($qs)) { + parse_str($qs, $expandedValue); + $varName = substr($name, 0, \strlen(key($expandedValue))); + + array_walk_recursive( + $expandedValue, + function (&$value, $key) { + if (ctype_digit($value) && ('size' === $key || 'error' === $key)) { + $value = (int) $value; + } + } + ); + + reset($expandedValue); + + $values[] = [$varName => current($expandedValue)]; + } + } + + return array_replace_recursive([], ...$values); + } + + /** + * Gets the URI of the form. + * + * The returned URI is not the same as the form "action" attribute. + * This method merges the value if the method is GET to mimics + * browser behavior. + */ + public function getUri(): string + { + $uri = parent::getUri(); + + if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) { + $query = parse_url($uri, \PHP_URL_QUERY); + $currentParameters = []; + if ($query) { + parse_str($query, $currentParameters); + } + + $queryString = http_build_query(array_merge($currentParameters, $this->getValues()), '', '&'); + + $pos = strpos($uri, '?'); + $base = false === $pos ? $uri : substr($uri, 0, $pos); + $uri = rtrim($base.'?'.$queryString, '?'); + } + + return $uri; + } + + protected function getRawUri(): string + { + // If the form was created from a button rather than the form node, check for HTML5 action overrides + if ($this->button !== $this->node && $this->button->getAttribute('formaction')) { + return $this->button->getAttribute('formaction'); + } + + return $this->node->getAttribute('action'); + } + + /** + * Gets the form method. + * + * If no method is defined in the form, GET is returned. + */ + public function getMethod(): string + { + if (null !== $this->method) { + return $this->method; + } + + // If the form was created from a button rather than the form node, check for HTML5 method override + if ($this->button !== $this->node && $this->button->getAttribute('formmethod')) { + return strtoupper($this->button->getAttribute('formmethod')); + } + + return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET'; + } + + /** + * Gets the form name. + * + * If no name is defined on the form, an empty string is returned. + */ + public function getName(): string + { + return $this->node->getAttribute('name'); + } + + /** + * Returns true if the named field exists. + */ + public function has(string $name): bool + { + return $this->fields->has($name); + } + + /** + * Removes a field from the form. + * + * @return void + */ + public function remove(string $name) + { + $this->fields->remove($name); + } + + /** + * Gets a named field. + * + * @return FormField|FormField[]|FormField[][] + * + * @throws \InvalidArgumentException When field is not present in this form + */ + public function get(string $name): FormField|array + { + return $this->fields->get($name); + } + + /** + * Sets a named field. + * + * @return void + */ + public function set(FormField $field) + { + $this->fields->add($field); + } + + /** + * Gets all fields. + * + * @return FormField[] + */ + public function all(): array + { + return $this->fields->all(); + } + + /** + * Returns true if the named field exists. + * + * @param string $name The field name + */ + public function offsetExists(mixed $name): bool + { + return $this->has($name); + } + + /** + * Gets the value of a field. + * + * @param string $name The field name + * + * @return FormField|FormField[]|FormField[][] + * + * @throws \InvalidArgumentException if the field does not exist + */ + public function offsetGet(mixed $name): FormField|array + { + return $this->fields->get($name); + } + + /** + * Sets the value of a field. + * + * @param string $name The field name + * @param string|array $value The value of the field + * + * @throws \InvalidArgumentException if the field does not exist + */ + public function offsetSet(mixed $name, mixed $value): void + { + $this->fields->set($name, $value); + } + + /** + * Removes a field from the form. + * + * @param string $name The field name + */ + public function offsetUnset(mixed $name): void + { + $this->fields->remove($name); + } + + /** + * Disables validation. + * + * @return $this + */ + public function disableValidation(): static + { + foreach ($this->fields->all() as $field) { + if ($field instanceof Field\ChoiceFormField) { + $field->disableValidation(); + } + } + + return $this; + } + + /** + * Sets the node for the form. + * + * Expects a 'submit' button \DOMElement and finds the corresponding form element, or the form element itself. + * + * @return void + * + * @throws \LogicException If given node is not a button or input or does not have a form ancestor + */ + protected function setNode(\DOMElement $node) + { + $this->button = $node; + if ('button' === $node->nodeName || ('input' === $node->nodeName && \in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image']))) { + if ($node->hasAttribute('form')) { + // if the node has the HTML5-compliant 'form' attribute, use it + $formId = $node->getAttribute('form'); + $form = $node->ownerDocument->getElementById($formId); + if (null === $form) { + throw new \LogicException(sprintf('The selected node has an invalid form attribute (%s).', $formId)); + } + $this->node = $form; + + return; + } + // we loop until we find a form ancestor + do { + if (null === $node = $node->parentNode) { + throw new \LogicException('The selected node does not have a form ancestor.'); + } + } while ('form' !== $node->nodeName); + } elseif ('form' !== $node->nodeName) { + throw new \LogicException(sprintf('Unable to submit on a "%s" tag.', $node->nodeName)); + } + + $this->node = $node; + } + + /** + * Adds form elements related to this form. + * + * Creates an internal copy of the submitted 'button' element and + * the form node or the entire document depending on whether we need + * to find non-descendant elements through HTML5 'form' attribute. + */ + private function initialize(): void + { + $this->fields = new FormFieldRegistry(); + + $xpath = new \DOMXPath($this->node->ownerDocument); + + // add submitted button if it has a valid name + if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) { + if ('input' == $this->button->nodeName && 'image' == strtolower($this->button->getAttribute('type'))) { + $name = $this->button->getAttribute('name'); + $this->button->setAttribute('value', '0'); + + // temporarily change the name of the input node for the x coordinate + $this->button->setAttribute('name', $name.'.x'); + $this->set(new Field\InputFormField($this->button)); + + // temporarily change the name of the input node for the y coordinate + $this->button->setAttribute('name', $name.'.y'); + $this->set(new Field\InputFormField($this->button)); + + // restore the original name of the input node + $this->button->setAttribute('name', $name); + } else { + $this->set(new Field\InputFormField($this->button)); + } + } + + // find form elements corresponding to the current form + if ($this->node->hasAttribute('id')) { + // corresponding elements are either descendants or have a matching HTML5 form attribute + $formId = Crawler::xpathLiteral($this->node->getAttribute('id')); + + $fieldNodes = $xpath->query(sprintf('( descendant::input[@form=%s] | descendant::button[@form=%1$s] | descendant::textarea[@form=%1$s] | descendant::select[@form=%1$s] | //form[@id=%1$s]//input[not(@form)] | //form[@id=%1$s]//button[not(@form)] | //form[@id=%1$s]//textarea[not(@form)] | //form[@id=%1$s]//select[not(@form)] )[( not(ancestor::template) or ancestor::turbo-stream )]', $formId)); + foreach ($fieldNodes as $node) { + $this->addField($node); + } + } else { + // do the xpath query with $this->node as the context node, to only find descendant elements + // however, descendant elements with form attribute are not part of this form + $fieldNodes = $xpath->query('( descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] )[( not(ancestor::template) or ancestor::turbo-stream )]', $this->node); + foreach ($fieldNodes as $node) { + $this->addField($node); + } + } + + if ($this->baseHref && '' !== $this->node->getAttribute('action')) { + $this->currentUri = $this->baseHref; + } + } + + private function addField(\DOMElement $node): void + { + if (!$node->hasAttribute('name') || !$node->getAttribute('name')) { + return; + } + + $nodeName = $node->nodeName; + if ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == strtolower($node->getAttribute('type'))) { + $this->set(new Field\ChoiceFormField($node)); + } elseif ('input' == $nodeName && 'radio' == strtolower($node->getAttribute('type'))) { + // there may be other fields with the same name that are no choice + // fields already registered (see https://github.com/symfony/symfony/issues/11689) + if ($this->has($node->getAttribute('name')) && $this->get($node->getAttribute('name')) instanceof ChoiceFormField) { + $this->get($node->getAttribute('name'))->addChoice($node); + } else { + $this->set(new Field\ChoiceFormField($node)); + } + } elseif ('input' == $nodeName && 'file' == strtolower($node->getAttribute('type'))) { + $this->set(new Field\FileFormField($node)); + } elseif ('input' == $nodeName && !\in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image'])) { + $this->set(new Field\InputFormField($node)); + } elseif ('textarea' == $nodeName) { + $this->set(new Field\TextareaFormField($node)); + } + } +} diff --git a/vendor/symfony/dom-crawler/FormFieldRegistry.php b/vendor/symfony/dom-crawler/FormFieldRegistry.php new file mode 100644 index 000000000..9e1571656 --- /dev/null +++ b/vendor/symfony/dom-crawler/FormFieldRegistry.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +use Symfony\Component\DomCrawler\Field\FormField; + +/** + * This is an internal class that must not be used directly. + * + * @internal + */ +class FormFieldRegistry +{ + private array $fields = []; + private string $base = ''; + + /** + * Adds a field to the registry. + */ + public function add(FormField $field): void + { + $segments = $this->getSegments($field->getName()); + + $target = &$this->fields; + while ($segments) { + if (!\is_array($target)) { + $target = []; + } + $path = array_shift($segments); + if ('' === $path) { + $target = &$target[]; + } else { + $target = &$target[$path]; + } + } + $target = $field; + } + + /** + * Removes a field based on the fully qualified name and its children from the registry. + */ + public function remove(string $name): void + { + $segments = $this->getSegments($name); + $target = &$this->fields; + while (\count($segments) > 1) { + $path = array_shift($segments); + if (!\is_array($target) || !\array_key_exists($path, $target)) { + return; + } + $target = &$target[$path]; + } + unset($target[array_shift($segments)]); + } + + /** + * Returns the value of the field based on the fully qualified name and its children. + * + * @return FormField|FormField[]|FormField[][] + * + * @throws \InvalidArgumentException if the field does not exist + */ + public function &get(string $name): FormField|array + { + $segments = $this->getSegments($name); + $target = &$this->fields; + while ($segments) { + $path = array_shift($segments); + if (!\is_array($target) || !\array_key_exists($path, $target)) { + throw new \InvalidArgumentException(sprintf('Unreachable field "%s".', $path)); + } + $target = &$target[$path]; + } + + return $target; + } + + /** + * Tests whether the form has the given field based on the fully qualified name. + */ + public function has(string $name): bool + { + try { + $this->get($name); + + return true; + } catch (\InvalidArgumentException) { + return false; + } + } + + /** + * Set the value of a field based on the fully qualified name and its children. + * + * @throws \InvalidArgumentException if the field does not exist + */ + public function set(string $name, mixed $value): void + { + $target = &$this->get($name); + if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) { + $target->setValue($value); + } elseif (\is_array($value)) { + $registry = new static(); + $registry->base = $name; + $registry->fields = $value; + foreach ($registry->all() as $k => $v) { + $this->set($k, $v); + } + } else { + throw new \InvalidArgumentException(sprintf('Cannot set value on a compound field "%s".', $name)); + } + } + + /** + * Returns the list of field with their value. + * + * @return FormField[] The list of fields as [string] Fully qualified name => (mixed) value) + */ + public function all(): array + { + return $this->walk($this->fields, $this->base); + } + + /** + * Transforms a PHP array in a list of fully qualified name / value. + */ + private function walk(array $array, ?string $base = '', array &$output = []): array + { + foreach ($array as $k => $v) { + $path = empty($base) ? $k : sprintf('%s[%s]', $base, $k); + if (\is_array($v)) { + $this->walk($v, $path, $output); + } else { + $output[$path] = $v; + } + } + + return $output; + } + + /** + * Splits a field name into segments as a web browser would do. + * + * getSegments('base[foo][3][]') = ['base', 'foo, '3', '']; + * + * @return string[] + */ + private function getSegments(string $name): array + { + if (preg_match('/^(?P[^[]+)(?P(\[.*)|$)/', $name, $m)) { + $segments = [$m['base']]; + while (!empty($m['extra'])) { + $extra = $m['extra']; + if (preg_match('/^\[(?P.*?)\](?P.*)$/', $extra, $m)) { + $segments[] = $m['segment']; + } else { + $segments[] = $extra; + } + } + + return $segments; + } + + return [$name]; + } +} diff --git a/vendor/symfony/dom-crawler/Image.php b/vendor/symfony/dom-crawler/Image.php new file mode 100644 index 000000000..34c8fda6c --- /dev/null +++ b/vendor/symfony/dom-crawler/Image.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +/** + * Image represents an HTML image (an HTML img tag). + */ +class Image extends AbstractUriElement +{ + public function __construct(\DOMElement $node, ?string $currentUri = null) + { + parent::__construct($node, $currentUri, 'GET'); + } + + protected function getRawUri(): string + { + return $this->node->getAttribute('src'); + } + + /** + * @return void + */ + protected function setNode(\DOMElement $node) + { + if ('img' !== $node->nodeName) { + throw new \LogicException(sprintf('Unable to visualize a "%s" tag.', $node->nodeName)); + } + + $this->node = $node; + } +} diff --git a/vendor/symfony/dom-crawler/LICENSE b/vendor/symfony/dom-crawler/LICENSE new file mode 100644 index 000000000..0138f8f07 --- /dev/null +++ b/vendor/symfony/dom-crawler/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +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. diff --git a/vendor/symfony/dom-crawler/Link.php b/vendor/symfony/dom-crawler/Link.php new file mode 100644 index 000000000..681a2f7a2 --- /dev/null +++ b/vendor/symfony/dom-crawler/Link.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +/** + * Link represents an HTML link (an HTML a, area or link tag). + * + * @author Fabien Potencier + */ +class Link extends AbstractUriElement +{ + protected function getRawUri(): string + { + return $this->node->getAttribute('href'); + } + + /** + * @return void + */ + protected function setNode(\DOMElement $node) + { + if ('a' !== $node->nodeName && 'area' !== $node->nodeName && 'link' !== $node->nodeName) { + throw new \LogicException(sprintf('Unable to navigate from a "%s" tag.', $node->nodeName)); + } + + $this->node = $node; + } +} diff --git a/vendor/symfony/dom-crawler/README.md b/vendor/symfony/dom-crawler/README.md new file mode 100644 index 000000000..c77a5e39c --- /dev/null +++ b/vendor/symfony/dom-crawler/README.md @@ -0,0 +1,13 @@ +DomCrawler Component +==================== + +The DomCrawler component eases DOM navigation for HTML and XML documents. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/dom_crawler.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php new file mode 100644 index 000000000..f20949931 --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextContains.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerAnySelectorTextContains extends Constraint +{ + private string $selector; + private string $expectedText; + private bool $hasNode = false; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + public function toString(): string + { + if ($this->hasNode) { + return sprintf('the text of any node matching selector "%s" contains "%s"', $this->selector, $this->expectedText); + } + + return sprintf('the Crawler has a node matching selector "%s"', $this->selector); + } + + protected function matches($other): bool + { + if (!$other instanceof Crawler) { + throw new \InvalidArgumentException(sprintf('"%s" constraint expected an argument of type "%s", got "%s".', self::class, Crawler::class, get_debug_type($other))); + } + + $other = $other->filter($this->selector); + if (!\count($other)) { + $this->hasNode = false; + + return false; + } + + $this->hasNode = true; + + $nodes = $other->each(fn (Crawler $node) => $node->text(null, true)); + $matches = array_filter($nodes, function (string $node): bool { + return str_contains($node, $this->expectedText); + }); + + return 0 < \count($matches); + } + + protected function failureDescription($other): string + { + if (!$other instanceof Crawler) { + throw new \InvalidArgumentException(sprintf('"%s" constraint expected an argument of type "%s", got "%s".', self::class, Crawler::class, get_debug_type($other))); + } + + return $this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php new file mode 100644 index 000000000..f4c8320b2 --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerAnySelectorTextSame.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerAnySelectorTextSame extends Constraint +{ + private string $selector; + private string $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + public function toString(): string + { + return sprintf('has at least a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText); + } + + protected function matches($other): bool + { + if (!$other instanceof Crawler) { + throw new \InvalidArgumentException(sprintf('"%s" constraint expected an argument of type "%s", got "%s".', self::class, Crawler::class, get_debug_type($other))); + } + + $other = $other->filter($this->selector); + if (!\count($other)) { + return false; + } + + $nodes = $other->each(fn (Crawler $node) => trim($node->text(null, true))); + + return \in_array($this->expectedText, $nodes, true); + } + + protected function failureDescription($other): string + { + if (!$other instanceof Crawler) { + throw new \InvalidArgumentException(sprintf('"%s" constraint expected an argument of type "%s", got "%s".', self::class, Crawler::class, get_debug_type($other))); + } + + return 'the Crawler '.$this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php new file mode 100644 index 000000000..f8df35b69 --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorAttributeValueSame extends Constraint +{ + private string $selector; + private string $attribute; + private string $expectedText; + + public function __construct(string $selector, string $attribute, string $expectedText) + { + $this->selector = $selector; + $this->attribute = $attribute; + $this->expectedText = $expectedText; + } + + public function toString(): string + { + return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText); + } + + /** + * @param Crawler $crawler + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->attr($this->attribute) ?? ''); + } + + /** + * @param Crawler $crawler + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php new file mode 100644 index 000000000..22ee1db07 --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorCount extends Constraint +{ + public function __construct( + private readonly int $count, + private readonly string $selector, + ) { + } + + public function toString(): string + { + return sprintf('selector "%s" count is "%d"', $this->selector, $this->count); + } + + /** + * @param Crawler $crawler + */ + protected function matches($crawler): bool + { + return $this->count === \count($crawler->filter($this->selector)); + } + + /** + * @param Crawler $crawler + */ + protected function failureDescription($crawler): string + { + return sprintf('the Crawler selector "%s" was expected to be found %d time(s) but was found %d time(s)', $this->selector, $this->count, \count($crawler->filter($this->selector))); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php new file mode 100644 index 000000000..5d0c100ae --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorExists extends Constraint +{ + private string $selector; + + public function __construct(string $selector) + { + $this->selector = $selector; + } + + public function toString(): string + { + return sprintf('matches selector "%s"', $this->selector); + } + + /** + * @param Crawler $crawler + */ + protected function matches($crawler): bool + { + return 0 < \count($crawler->filter($this->selector)); + } + + /** + * @param Crawler $crawler + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php new file mode 100644 index 000000000..c70fff1d0 --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextContains extends Constraint +{ + private string $selector; + private string $expectedText; + private bool $hasNode = false; + private string $nodeText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + public function toString(): string + { + if ($this->hasNode) { + return sprintf('the text "%s" of the node matching selector "%s" contains "%s"', $this->nodeText, $this->selector, $this->expectedText); + } + + return sprintf('the Crawler has a node matching selector "%s"', $this->selector); + } + + /** + * @param Crawler $crawler + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + $this->hasNode = false; + + return false; + } + + $this->hasNode = true; + $this->nodeText = $crawler->text(null, true); + + return str_contains($this->nodeText, $this->expectedText); + } + + /** + * @param Crawler $crawler + */ + protected function failureDescription($crawler): string + { + return $this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php new file mode 100644 index 000000000..269e23fce --- /dev/null +++ b/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextSame extends Constraint +{ + private string $selector; + private string $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + public function toString(): string + { + return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText); + } + + /** + * @param Crawler $crawler + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->text(null, true)); + } + + /** + * @param Crawler $crawler + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/vendor/symfony/dom-crawler/UriResolver.php b/vendor/symfony/dom-crawler/UriResolver.php new file mode 100644 index 000000000..d42c2eb55 --- /dev/null +++ b/vendor/symfony/dom-crawler/UriResolver.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DomCrawler; + +/** + * The UriResolver class takes an URI (relative, absolute, fragment, etc.) + * and turns it into an absolute URI against another given base URI. + * + * @author Fabien Potencier + * @author Grégoire Pineau + */ +class UriResolver +{ + /** + * Resolves a URI according to a base URI. + * + * For example if $uri=/foo/bar and $baseUri=https://symfony.com it will + * return https://symfony.com/foo/bar + * + * If the $uri is not absolute you must pass an absolute $baseUri + */ + public static function resolve(string $uri, ?string $baseUri): string + { + $uri = trim($uri); + + if (false === ($scheme = parse_url($uri, \PHP_URL_SCHEME)) && '/' === ($uri[0] ?? '')) { + $scheme = parse_url($uri.'#', \PHP_URL_SCHEME); + } + + // absolute URL? + if (null !== $scheme) { + return $uri; + } + + if (null === $baseUri) { + throw new \InvalidArgumentException('The URI is relative, so you must define its base URI passing an absolute URL.'); + } + + // empty URI + if (!$uri) { + return $baseUri; + } + + // an anchor + if ('#' === $uri[0]) { + return self::cleanupAnchor($baseUri).$uri; + } + + $baseUriCleaned = self::cleanupUri($baseUri); + + if ('?' === $uri[0]) { + return $baseUriCleaned.$uri; + } + + // absolute URL with relative schema + if (str_starts_with($uri, '//')) { + return preg_replace('#^([^/]*)//.*$#', '$1', $baseUriCleaned).$uri; + } + + $baseUriCleaned = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUriCleaned); + + // absolute path + if ('/' === $uri[0]) { + return $baseUriCleaned.$uri; + } + + // relative path + $path = parse_url(substr($baseUri, \strlen($baseUriCleaned)), \PHP_URL_PATH) ?? ''; + $path = self::canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri); + + return $baseUriCleaned.('' === $path || '/' !== $path[0] ? '/' : '').$path; + } + + /** + * Returns the canonicalized URI path (see RFC 3986, section 5.2.4). + */ + private static function canonicalizePath(string $path): string + { + if ('' === $path || '/' === $path) { + return $path; + } + + if (str_ends_with($path, '.')) { + $path .= '/'; + } + + $output = []; + + foreach (explode('/', $path) as $segment) { + if ('..' === $segment) { + array_pop($output); + } elseif ('.' !== $segment) { + $output[] = $segment; + } + } + + return implode('/', $output); + } + + /** + * Removes the query string and the anchor from the given uri. + */ + private static function cleanupUri(string $uri): string + { + return self::cleanupQuery(self::cleanupAnchor($uri)); + } + + /** + * Removes the query string from the uri. + */ + private static function cleanupQuery(string $uri): string + { + if (false !== $pos = strpos($uri, '?')) { + return substr($uri, 0, $pos); + } + + return $uri; + } + + /** + * Removes the anchor from the uri. + */ + private static function cleanupAnchor(string $uri): string + { + if (false !== $pos = strpos($uri, '#')) { + return substr($uri, 0, $pos); + } + + return $uri; + } +} diff --git a/vendor/symfony/dom-crawler/composer.json b/vendor/symfony/dom-crawler/composer.json new file mode 100644 index 000000000..d703acbe8 --- /dev/null +++ b/vendor/symfony/dom-crawler/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/dom-crawler", + "type": "library", + "description": "Eases DOM navigation for HTML and XML documents", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "masterminds/html5": "^2.6" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\DomCrawler\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/vendor/symfony/var-exporter/CHANGELOG.md b/vendor/symfony/var-exporter/CHANGELOG.md new file mode 100644 index 000000000..fdca002cb --- /dev/null +++ b/vendor/symfony/var-exporter/CHANGELOG.md @@ -0,0 +1,25 @@ +CHANGELOG +========= + +6.4 +--- + + * Deprecate per-property lazy-initializers + +6.2 +--- + + * Add support for lazy ghost objects and virtual proxies + * Add `Hydrator::hydrate()` + * Preserve PHP references also when using `Hydrator::hydrate()` or `Instantiator::instantiate()` + * Add support for hydrating from native (array) casts + +5.1.0 +----- + + * added argument `array &$foundClasses` to `VarExporter::export()` to ease with preloading exported values + +4.2.0 +----- + + * added the component diff --git a/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php new file mode 100644 index 000000000..379a76517 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +class ClassNotFoundException extends \Exception implements ExceptionInterface +{ + public function __construct(string $class, ?\Throwable $previous = null) + { + parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous); + } +} diff --git a/vendor/symfony/var-exporter/Exception/ExceptionInterface.php b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php new file mode 100644 index 000000000..adfaed47c --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/var-exporter/Exception/LogicException.php b/vendor/symfony/var-exporter/Exception/LogicException.php new file mode 100644 index 000000000..619d0559a --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/LogicException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php new file mode 100644 index 000000000..b9ba225d8 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +class NotInstantiableTypeException extends \Exception implements ExceptionInterface +{ + public function __construct(string $type, ?\Throwable $previous = null) + { + parent::__construct(sprintf('Type "%s" is not instantiable.', $type), 0, $previous); + } +} diff --git a/vendor/symfony/var-exporter/Hydrator.php b/vendor/symfony/var-exporter/Hydrator.php new file mode 100644 index 000000000..5f456fb3c --- /dev/null +++ b/vendor/symfony/var-exporter/Hydrator.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Internal\Hydrator as InternalHydrator; + +/** + * Utility class to hydrate the properties of an object. + * + * @author Nicolas Grekas + */ +final class Hydrator +{ + /** + * Sets the properties of an object, including private and protected ones. + * + * For example: + * + * // Sets the public or protected $object->propertyName property + * Hydrator::hydrate($object, ['propertyName' => $propertyValue]); + * + * // Sets a private property defined on its parent Bar class: + * Hydrator::hydrate($object, ["\0Bar\0privateBarProperty" => $propertyValue]); + * + * // Alternative way to set the private $object->privateBarProperty property + * Hydrator::hydrate($object, [], [ + * Bar::class => ['privateBarProperty' => $propertyValue], + * ]); + * + * Instances of ArrayObject, ArrayIterator and SplObjectStorage can be hydrated + * by using the special "\0" property name to define their internal value: + * + * // Hydrates an SplObjectStorage where $info1 is attached to $obj1, etc. + * Hydrator::hydrate($object, ["\0" => [$obj1, $info1, $obj2, $info2...]]); + * + * // Hydrates an ArrayObject populated with $inputArray + * Hydrator::hydrate($object, ["\0" => [$inputArray]]); + * + * @template T of object + * + * @param T $instance The object to hydrate + * @param array $properties The properties to set on the instance + * @param array> $scopedProperties The properties to set on the instance, + * keyed by their declaring class + * + * @return T + */ + public static function hydrate(object $instance, array $properties = [], array $scopedProperties = []): object + { + if ($properties) { + $class = $instance::class; + $propertyScopes = InternalHydrator::$propertyScopes[$class] ??= InternalHydrator::getPropertyScopes($class); + + foreach ($properties as $name => &$value) { + [$scope, $name, $readonlyScope] = $propertyScopes[$name] ?? [$class, $name, $class]; + $scopedProperties[$readonlyScope ?? $scope][$name] = &$value; + } + unset($value); + } + + foreach ($scopedProperties as $scope => $properties) { + if ($properties) { + (InternalHydrator::$simpleHydrators[$scope] ??= InternalHydrator::getSimpleHydrator($scope))($properties, $instance); + } + } + + return $instance; + } +} diff --git a/vendor/symfony/var-exporter/Instantiator.php b/vendor/symfony/var-exporter/Instantiator.php new file mode 100644 index 000000000..10200c00b --- /dev/null +++ b/vendor/symfony/var-exporter/Instantiator.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; +use Symfony\Component\VarExporter\Internal\Registry; + +/** + * A utility class to create objects without calling their constructor. + * + * @author Nicolas Grekas + */ +final class Instantiator +{ + /** + * Creates an object and sets its properties without calling its constructor nor any other methods. + * + * @see Hydrator::hydrate() for examples + * + * @template T of object + * + * @param class-string $class The class of the instance to create + * @param array $properties The properties to set on the instance + * @param array> $scopedProperties The properties to set on the instance, + * keyed by their declaring class + * + * @return T + * + * @throws ExceptionInterface When the instance cannot be created + */ + public static function instantiate(string $class, array $properties = [], array $scopedProperties = []): object + { + $reflector = Registry::$reflectors[$class] ??= Registry::getClassReflector($class); + + if (Registry::$cloneable[$class]) { + $instance = clone Registry::$prototypes[$class]; + } elseif (Registry::$instantiableWithoutConstructor[$class]) { + $instance = $reflector->newInstanceWithoutConstructor(); + } elseif (null === Registry::$prototypes[$class]) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize')) { + $instance = unserialize('C:'.\strlen($class).':"'.$class.'":0:{}'); + } else { + $instance = unserialize('O:'.\strlen($class).':"'.$class.'":0:{}'); + } + + return $properties || $scopedProperties ? Hydrator::hydrate($instance, $properties, $scopedProperties) : $instance; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Exporter.php b/vendor/symfony/var-exporter/Internal/Exporter.php new file mode 100644 index 000000000..ec711e1ed --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Exporter.php @@ -0,0 +1,419 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Exporter +{ + /** + * Prepares an array of values for VarExporter. + * + * For performance this method is public and has no type-hints. + * + * @param array &$values + * @param \SplObjectStorage $objectsPool + * @param array &$refsPool + * @param int &$objectsCount + * @param bool &$valuesAreStatic + * + * @return array + * + * @throws NotInstantiableTypeException When a value cannot be serialized + */ + public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic) + { + $refs = $values; + foreach ($values as $k => $value) { + if (\is_resource($value)) { + throw new NotInstantiableTypeException(get_resource_type($value).' resource'); + } + $refs[$k] = $objectsPool; + + if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) { + $values[$k] = &$value; // Break hard references to make $values completely + unset($value); // independent from the original structure + $refs[$k] = $value = $values[$k]; + if ($value instanceof Reference && 0 > $value->id) { + $valuesAreStatic = false; + ++$value->count; + continue; + } + $refsPool[] = [&$refs[$k], $value, &$value]; + $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value); + } + + if (\is_array($value)) { + if ($value) { + $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + } + goto handle_value; + } elseif (!\is_object($value) || $value instanceof \UnitEnum) { + goto handle_value; + } + + $valueIsStatic = false; + if (isset($objectsPool[$value])) { + ++$objectsCount; + $value = new Reference($objectsPool[$value][0]); + goto handle_value; + } + + $class = $value::class; + $reflector = Registry::$reflectors[$class] ??= Registry::getClassReflector($class); + $properties = []; + + if ($reflector->hasMethod('__serialize')) { + if (!$reflector->getMethod('__serialize')->isPublic()) { + throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class)); + } + + if (!\is_array($serializeProperties = $value->__serialize())) { + throw new \TypeError($class.'::__serialize() must return an array'); + } + + if ($reflector->hasMethod('__unserialize')) { + $properties = $serializeProperties; + } else { + foreach ($serializeProperties as $n => $v) { + $c = $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass'; + $properties[$c][$n] = $v; + } + } + + goto prepare_value; + } + + $sleep = null; + $proto = Registry::$prototypes[$class]; + + if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) { + // ArrayIterator and ArrayObject need special care because their "flags" + // option changes the behavior of the (array) casting operator. + [$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto); + + // populates Registry::$prototypes[$class] with a new instance + Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); + } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) { + // By implementing Serializable, SplObjectStorage breaks + // internal references; let's deal with it on our own. + foreach (clone $value as $v) { + $properties[] = $v; + $properties[] = $value[$v]; + } + $properties = ['SplObjectStorage' => ["\0" => $properties]]; + $arrayValue = (array) $value; + } elseif ($value instanceof \Serializable + || $value instanceof \__PHP_Incomplete_Class + || \PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod + ) { + ++$objectsCount; + $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0]; + $value = new Reference($id); + goto handle_value; + } else { + if (method_exists($class, '__sleep')) { + if (!\is_array($sleep = $value->__sleep())) { + trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE); + $value = null; + goto handle_value; + } + $sleep = array_flip($sleep); + } + + $arrayValue = (array) $value; + } + + $proto = (array) $proto; + + foreach ($arrayValue as $name => $v) { + $i = 0; + $n = (string) $name; + if ('' === $n || "\0" !== $n[0]) { + $c = $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass'; + } elseif ('*' === $n[1]) { + $n = substr($n, 3); + $c = $reflector->getProperty($n)->class; + if ('Error' === $c) { + $c = 'TypeError'; + } elseif ('Exception' === $c) { + $c = 'ErrorException'; + } + } else { + $i = strpos($n, "\0", 2); + $c = substr($n, 1, $i - 1); + $n = substr($n, 1 + $i); + } + if (null !== $sleep) { + if (!isset($sleep[$name]) && (!isset($sleep[$n]) || ($i && $c !== $class))) { + unset($arrayValue[$name]); + continue; + } + unset($sleep[$name], $sleep[$n]); + } + if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) { + $properties[$c][$n] = $v; + } + } + if ($sleep) { + foreach ($sleep as $n => $v) { + trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE); + } + } + if (method_exists($class, '__unserialize')) { + $properties = $arrayValue; + } + + prepare_value: + $objectsPool[$value] = [$id = \count($objectsPool)]; + $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + ++$objectsCount; + $objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)]; + + $value = new Reference($id); + + handle_value: + if ($isRef) { + unset($value); // Break the hard reference created above + } elseif (!$valueIsStatic) { + $values[$k] = $value; + } + $valuesAreStatic = $valueIsStatic && $valuesAreStatic; + } + + return $values; + } + + public static function export($value, $indent = '') + { + switch (true) { + case \is_int($value) || \is_float($value): return var_export($value, true); + case [] === $value: return '[]'; + case false === $value: return 'false'; + case true === $value: return 'true'; + case null === $value: return 'null'; + case '' === $value: return "''"; + case $value instanceof \UnitEnum: return '\\'.ltrim(var_export($value, true), '\\'); + } + + if ($value instanceof Reference) { + if (0 <= $value->id) { + return '$o['.$value->id.']'; + } + if (!$value->count) { + return self::export($value->value, $indent); + } + $value = -$value->id; + + return '&$r['.$value.']'; + } + $subIndent = $indent.' '; + + if (\is_string($value)) { + $code = sprintf("'%s'", addcslashes($value, "'\\")); + + $code = preg_replace_callback("/((?:[\\0\\r\\n]|\u{202A}|\u{202B}|\u{202D}|\u{202E}|\u{2066}|\u{2067}|\u{2068}|\u{202C}|\u{2069})++)(.)/", function ($m) use ($subIndent) { + $m[1] = sprintf('\'."%s".\'', str_replace( + ["\0", "\r", "\n", "\u{202A}", "\u{202B}", "\u{202D}", "\u{202E}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{202C}", "\u{2069}", '\n\\'], + ['\0', '\r', '\n', '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', '\u{2069}', '\n"'."\n".$subIndent.'."\\'], + $m[1] + )); + + if ("'" === $m[2]) { + return substr($m[1], 0, -2); + } + + if (str_ends_with($m[1], 'n".\'')) { + return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2); + } + + return $m[1].$m[2]; + }, $code, -1, $count); + + if ($count && str_starts_with($code, "''.")) { + $code = substr($code, 3); + } + + return $code; + } + + if (\is_array($value)) { + $j = -1; + $code = ''; + foreach ($value as $k => $v) { + $code .= $subIndent; + if (!\is_int($k) || 1 !== $k - $j) { + $code .= self::export($k, $subIndent).' => '; + } + if (\is_int($k) && $k > $j) { + $j = $k; + } + $code .= self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Values) { + $code = $subIndent."\$r = [],\n"; + foreach ($value->values as $k => $v) { + $code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Registry) { + return self::exportRegistry($value, $indent, $subIndent); + } + + if ($value instanceof Hydrator) { + return self::exportHydrator($value, $indent, $subIndent); + } + + throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', get_debug_type($value))); + } + + private static function exportRegistry(Registry $value, string $indent, string $subIndent): string + { + $code = ''; + $serializables = []; + $seen = []; + $prototypesAccess = 0; + $factoriesAccess = 0; + $r = '\\'.Registry::class; + $j = -1; + + foreach ($value->classes as $k => $class) { + if (':' === ($class[1] ?? null)) { + $serializables[$k] = $class; + continue; + } + if (!Registry::$instantiableWithoutConstructor[$class]) { + if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) { + $serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}'; + } else { + $serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}'; + } + if (is_subclass_of($class, 'Throwable')) { + $eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0"; + $serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4); + } + continue; + } + $code .= $subIndent.(1 !== $k - $j ? $k.' => ' : ''); + $j = $k; + $eol = ",\n"; + $c = '['.self::export($class).']'; + + if ($seen[$class] ?? false) { + if (Registry::$cloneable[$class]) { + ++$prototypesAccess; + $code .= 'clone $p'.$c; + } else { + ++$factoriesAccess; + $code .= '$f'.$c.'()'; + } + } else { + $seen[$class] = true; + if (Registry::$cloneable[$class]) { + $code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p'; + } else { + $code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f'; + $eol = '()'.$eol; + } + $code .= '('.substr($c, 1, -1).'))'; + } + $code .= $eol; + } + + if (1 === $prototypesAccess) { + $code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code); + } + if (1 === $factoriesAccess) { + $code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code); + } + if ('' !== $code) { + $code = "\n".$code.$indent; + } + + if ($serializables) { + $code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')'; + } else { + $code = '['.$code.']'; + } + + return '$o = '.$code; + } + + private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string + { + $code = ''; + foreach ($value->properties as $class => $properties) { + $code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n"; + } + + $code = [ + self::export($value->registry, $subIndent), + self::export($value->values, $subIndent), + '' !== $code ? "[\n".$code.$subIndent.']' : '[]', + self::export($value->value, $subIndent), + self::export($value->wakeups, $subIndent), + ]; + + return '\\'.$value::class."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')'; + } + + /** + * @param \ArrayIterator|\ArrayObject $value + * @param \ArrayIterator|\ArrayObject $proto + */ + private static function getArrayObjectProperties($value, $proto): array + { + $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'; + $reflector = Registry::$reflectors[$reflector] ??= Registry::getClassReflector($reflector); + + $properties = [ + $arrayValue = (array) $value, + $reflector->getMethod('getFlags')->invoke($value), + $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator', + ]; + + $reflector = $reflector->getMethod('setFlags'); + $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST); + + if ($properties[1] & \ArrayObject::STD_PROP_LIST) { + $reflector->invoke($value, 0); + $properties[0] = (array) $value; + } else { + $reflector->invoke($value, \ArrayObject::STD_PROP_LIST); + $arrayValue = (array) $value; + } + $reflector->invoke($value, $properties[1]); + + if ([[], 0, 'ArrayIterator'] === $properties) { + $properties = []; + } else { + if ('ArrayIterator' === $properties[2]) { + unset($properties[2]); + } + $properties = [$reflector->class => ["\0" => $properties]]; + } + + return [$arrayValue, $properties]; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Hydrator.php b/vendor/symfony/var-exporter/Internal/Hydrator.php new file mode 100644 index 000000000..49d636fb8 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Hydrator.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Hydrator +{ + public static array $hydrators = []; + public static array $simpleHydrators = []; + public static array $propertyScopes = []; + + public $registry; + public $values; + public $properties; + public $value; + public $wakeups; + + public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups) + { + $this->registry = $registry; + $this->values = $values; + $this->properties = $properties; + $this->value = $value; + $this->wakeups = $wakeups; + } + + public static function hydrate($objects, $values, $properties, $value, $wakeups) + { + foreach ($properties as $class => $vars) { + (self::$hydrators[$class] ??= self::getHydrator($class))($vars, $objects); + } + foreach ($wakeups as $k => $v) { + if (\is_array($v)) { + $objects[-$k]->__unserialize($v); + } else { + $objects[$v]->__wakeup(); + } + } + + return $value; + } + + public static function getHydrator($class) + { + $baseHydrator = self::$hydrators['stdClass'] ??= static function ($properties, $objects) { + foreach ($properties as $name => $values) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + + switch ($class) { + case 'stdClass': + return $baseHydrator; + + case 'ErrorException': + return $baseHydrator->bindTo(null, new class() extends \ErrorException { + }); + + case 'TypeError': + return $baseHydrator->bindTo(null, new class() extends \Error { + }); + + case 'SplObjectStorage': + return static function ($properties, $objects) { + foreach ($properties as $name => $values) { + if ("\0" === $name) { + foreach ($values as $i => $v) { + for ($j = 0; $j < \count($v); ++$j) { + $objects[$i]->attach($v[$j], $v[++$j]); + } + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } + + if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $classReflector = new \ReflectionClass($class); + + switch ($class) { + case 'ArrayIterator': + case 'ArrayObject': + $constructor = $classReflector->getConstructor()->invokeArgs(...); + + return static function ($properties, $objects) use ($constructor) { + foreach ($properties as $name => $values) { + if ("\0" !== $name) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + } + foreach ($properties["\0"] ?? [] as $i => $v) { + $constructor($objects[$i], $v); + } + }; + } + + if (!$classReflector->isInternal()) { + return $baseHydrator->bindTo(null, $class); + } + + if ($classReflector->name !== $class) { + return self::$hydrators[$classReflector->name] ??= self::getHydrator($classReflector->name); + } + + $propertySetters = []; + foreach ($classReflector->getProperties() as $propertyReflector) { + if (!$propertyReflector->isStatic()) { + $propertySetters[$propertyReflector->name] = $propertyReflector->setValue(...); + } + } + + if (!$propertySetters) { + return $baseHydrator; + } + + return static function ($properties, $objects) use ($propertySetters) { + foreach ($properties as $name => $values) { + if ($setValue = $propertySetters[$name] ?? null) { + foreach ($values as $i => $v) { + $setValue($objects[$i], $v); + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } + + public static function getSimpleHydrator($class) + { + $baseHydrator = self::$simpleHydrators['stdClass'] ??= (function ($properties, $object) { + $readonly = (array) $this; + + foreach ($properties as $name => &$value) { + $object->$name = $value; + + if (!($readonly[$name] ?? false)) { + $object->$name = &$value; + } + } + })->bindTo(new \stdClass()); + + switch ($class) { + case 'stdClass': + return $baseHydrator; + + case 'ErrorException': + return $baseHydrator->bindTo(new \stdClass(), new class() extends \ErrorException { + }); + + case 'TypeError': + return $baseHydrator->bindTo(new \stdClass(), new class() extends \Error { + }); + + case 'SplObjectStorage': + return static function ($properties, $object) { + foreach ($properties as $name => &$value) { + if ("\0" !== $name) { + $object->$name = $value; + $object->$name = &$value; + continue; + } + for ($i = 0; $i < \count($value); ++$i) { + $object->attach($value[$i], $value[++$i]); + } + } + }; + } + + if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $classReflector = new \ReflectionClass($class); + + switch ($class) { + case 'ArrayIterator': + case 'ArrayObject': + $constructor = $classReflector->getConstructor()->invokeArgs(...); + + return static function ($properties, $object) use ($constructor) { + foreach ($properties as $name => &$value) { + if ("\0" === $name) { + $constructor($object, $value); + } else { + $object->$name = $value; + $object->$name = &$value; + } + } + }; + } + + if (!$classReflector->isInternal()) { + $readonly = new \stdClass(); + foreach ($classReflector->getProperties(\ReflectionProperty::IS_READONLY) as $propertyReflector) { + if ($class === $propertyReflector->class) { + $readonly->{$propertyReflector->name} = true; + } + } + + return $baseHydrator->bindTo($readonly, $class); + } + + if ($classReflector->name !== $class) { + return self::$simpleHydrators[$classReflector->name] ??= self::getSimpleHydrator($classReflector->name); + } + + $propertySetters = []; + foreach ($classReflector->getProperties() as $propertyReflector) { + if (!$propertyReflector->isStatic()) { + $propertySetters[$propertyReflector->name] = $propertyReflector->setValue(...); + } + } + + if (!$propertySetters) { + return $baseHydrator; + } + + return static function ($properties, $object) use ($propertySetters) { + foreach ($properties as $name => &$value) { + if ($setValue = $propertySetters[$name] ?? null) { + $setValue($object, $value); + } else { + $object->$name = $value; + $object->$name = &$value; + } + } + }; + } + + /** + * @return array + */ + public static function getPropertyScopes($class) + { + $propertyScopes = []; + $r = new \ReflectionClass($class); + + foreach ($r->getProperties() as $property) { + $flags = $property->getModifiers(); + + if (\ReflectionProperty::IS_STATIC & $flags) { + continue; + } + $name = $property->name; + + if (\ReflectionProperty::IS_PRIVATE & $flags) { + $readonlyScope = null; + if ($flags & \ReflectionProperty::IS_READONLY) { + $readonlyScope = $class; + } + $propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $readonlyScope, $property]; + + continue; + } + $readonlyScope = null; + if ($flags & \ReflectionProperty::IS_READONLY) { + $readonlyScope = $property->class; + } + $propertyScopes[$name] = [$class, $name, $readonlyScope, $property]; + + if (\ReflectionProperty::IS_PROTECTED & $flags) { + $propertyScopes["\0*\0$name"] = $propertyScopes[$name]; + } + } + + while ($r = $r->getParentClass()) { + $class = $r->name; + + foreach ($r->getProperties(\ReflectionProperty::IS_PRIVATE) as $property) { + if (!$property->isStatic()) { + $name = $property->name; + $readonlyScope = $property->isReadOnly() ? $class : null; + $propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope, $property]; + $propertyScopes[$name] ??= [$class, $name, $readonlyScope, $property]; + } + } + } + + return $propertyScopes; + } +} diff --git a/vendor/symfony/var-exporter/Internal/LazyObjectRegistry.php b/vendor/symfony/var-exporter/Internal/LazyObjectRegistry.php new file mode 100644 index 000000000..fddc6fb3b --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/LazyObjectRegistry.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +/** + * Stores the state of lazy objects and caches related reflection information. + * + * As a micro-optimization, this class uses no type declarations. + * + * @internal + */ +class LazyObjectRegistry +{ + /** + * @var array + */ + public static array $classReflectors = []; + + /** + * @var array> + */ + public static array $defaultProperties = []; + + /** + * @var array> + */ + public static array $classResetters = []; + + /** + * @var array + */ + public static array $classAccessors = []; + + /** + * @var array + */ + public static array $parentMethods = []; + + public static ?\Closure $noInitializerState = null; + + public static function getClassResetters($class) + { + $classProperties = []; + + if ((self::$classReflectors[$class] ??= new \ReflectionClass($class))->isInternal()) { + $propertyScopes = []; + } else { + $propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class); + } + + foreach ($propertyScopes as $key => [$scope, $name, $readonlyScope]) { + $propertyScopes[$k = "\0$scope\0$name"] ?? $propertyScopes[$k = "\0*\0$name"] ?? $k = $name; + + if ($k === $key && "\0$class\0lazyObjectState" !== $k) { + $classProperties[$readonlyScope ?? $scope][$name] = $key; + } + } + + $resetters = []; + foreach ($classProperties as $scope => $properties) { + $resetters[] = \Closure::bind(static function ($instance, $skippedProperties, $onlyProperties = null) use ($properties) { + foreach ($properties as $name => $key) { + if (!\array_key_exists($key, $skippedProperties) && (null === $onlyProperties || \array_key_exists($key, $onlyProperties))) { + unset($instance->$name); + } + } + }, null, $scope); + } + + $resetters[] = static function ($instance, $skippedProperties, $onlyProperties = null) { + foreach ((array) $instance as $name => $value) { + if ("\0" !== ($name[0] ?? '') && !\array_key_exists($name, $skippedProperties) && (null === $onlyProperties || \array_key_exists($name, $onlyProperties))) { + unset($instance->$name); + } + } + }; + + return $resetters; + } + + public static function getClassAccessors($class) + { + return \Closure::bind(static fn () => [ + 'get' => static function &($instance, $name, $readonly) { + if (!$readonly) { + return $instance->$name; + } + $value = $instance->$name; + + return $value; + }, + 'set' => static function ($instance, $name, $value) { + $instance->$name = $value; + }, + 'isset' => static fn ($instance, $name) => isset($instance->$name), + 'unset' => static function ($instance, $name) { + unset($instance->$name); + }, + ], null, \Closure::class === $class ? null : $class)(); + } + + public static function getParentMethods($class) + { + $parent = get_parent_class($class); + $methods = []; + + foreach (['set', 'isset', 'unset', 'clone', 'serialize', 'unserialize', 'sleep', 'wakeup', 'destruct', 'get'] as $method) { + if (!$parent || !method_exists($parent, '__'.$method)) { + $methods[$method] = false; + } else { + $m = new \ReflectionMethod($parent, '__'.$method); + $methods[$method] = !$m->isAbstract() && !$m->isPrivate(); + } + } + + $methods['get'] = $methods['get'] ? ($m->returnsReference() ? 2 : 1) : 0; + + return $methods; + } + + public static function getScope($propertyScopes, $class, $property, $readonlyScope = null) + { + if (null === $readonlyScope && !isset($propertyScopes[$k = "\0$class\0$property"]) && !isset($propertyScopes[$k = "\0*\0$property"])) { + return null; + } + $frame = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]; + + if (\ReflectionProperty::class === $scope = $frame['class'] ?? \Closure::class) { + $scope = $frame['object']->class; + } + if (null === $readonlyScope && '*' === $k[1] && ($class === $scope || (is_subclass_of($class, $scope) && !isset($propertyScopes["\0$scope\0$property"])))) { + return null; + } + + return $scope; + } +} diff --git a/vendor/symfony/var-exporter/Internal/LazyObjectState.php b/vendor/symfony/var-exporter/Internal/LazyObjectState.php new file mode 100644 index 000000000..f47dea4d8 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/LazyObjectState.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Hydrator as PublicHydrator; + +/** + * Keeps the state of lazy objects. + * + * As a micro-optimization, this class uses no type declarations. + * + * @internal + */ +class LazyObjectState +{ + public const STATUS_UNINITIALIZED_FULL = 1; + public const STATUS_UNINITIALIZED_PARTIAL = 2; + public const STATUS_INITIALIZED_FULL = 3; + public const STATUS_INITIALIZED_PARTIAL = 4; + + /** + * @var array + */ + public readonly array $skippedProperties; + + /** + * @var self::STATUS_* + */ + public int $status = 0; + + public object $realInstance; + + public function __construct(public readonly \Closure|array $initializer, $skippedProperties = []) + { + $this->skippedProperties = $skippedProperties; + $this->status = \is_array($initializer) ? self::STATUS_UNINITIALIZED_PARTIAL : self::STATUS_UNINITIALIZED_FULL; + } + + public function initialize($instance, $propertyName, $propertyScope) + { + if (self::STATUS_INITIALIZED_FULL === $this->status) { + return self::STATUS_INITIALIZED_FULL; + } + + if (\is_array($this->initializer)) { + $class = $instance::class; + $propertyScope ??= $class; + $propertyScopes = Hydrator::$propertyScopes[$class]; + $propertyScopes[$k = "\0$propertyScope\0$propertyName"] ?? $propertyScopes[$k = "\0*\0$propertyName"] ?? $k = $propertyName; + + if ($initializer = $this->initializer[$k] ?? null) { + $value = $initializer(...[$instance, $propertyName, $propertyScope, LazyObjectRegistry::$defaultProperties[$class][$k] ?? null]); + $accessor = LazyObjectRegistry::$classAccessors[$propertyScope] ??= LazyObjectRegistry::getClassAccessors($propertyScope); + $accessor['set']($instance, $propertyName, $value); + + return $this->status = self::STATUS_INITIALIZED_PARTIAL; + } + + if ($initializer = $this->initializer["\0"] ?? null) { + if (!\is_array($values = $initializer($instance, LazyObjectRegistry::$defaultProperties[$class]))) { + throw new \TypeError(sprintf('The lazy-initializer defined for instance of "%s" must return an array, got "%s".', $class, get_debug_type($values))); + } + $properties = (array) $instance; + foreach ($values as $key => $value) { + if (!\array_key_exists($key, $properties) && [$scope, $name, $readonlyScope] = $propertyScopes[$key] ?? null) { + $scope = $readonlyScope ?? ('*' !== $scope ? $scope : $class); + $accessor = LazyObjectRegistry::$classAccessors[$scope] ??= LazyObjectRegistry::getClassAccessors($scope); + $accessor['set']($instance, $name, $value); + + if ($k === $key) { + $this->status = self::STATUS_INITIALIZED_PARTIAL; + } + } + } + } + + return $this->status; + } + + if (self::STATUS_INITIALIZED_PARTIAL === $this->status) { + return self::STATUS_INITIALIZED_PARTIAL; + } + + $this->status = self::STATUS_INITIALIZED_PARTIAL; + + try { + if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) { + PublicHydrator::hydrate($instance, $defaultProperties); + } + + ($this->initializer)($instance); + } catch (\Throwable $e) { + $this->status = self::STATUS_UNINITIALIZED_FULL; + $this->reset($instance); + + throw $e; + } + + return $this->status = self::STATUS_INITIALIZED_FULL; + } + + public function reset($instance): void + { + $class = $instance::class; + $propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class); + $skippedProperties = $this->skippedProperties; + $properties = (array) $instance; + $onlyProperties = \is_array($this->initializer) ? $this->initializer : null; + + foreach ($propertyScopes as $key => [$scope, $name, $readonlyScope]) { + $propertyScopes[$k = "\0$scope\0$name"] ?? $propertyScopes[$k = "\0*\0$name"] ?? $k = $name; + + if ($k === $key && (null !== $readonlyScope || !\array_key_exists($k, $properties))) { + $skippedProperties[$k] = true; + } + } + + foreach (LazyObjectRegistry::$classResetters[$class] as $reset) { + $reset($instance, $skippedProperties, $onlyProperties); + } + + $this->status = self::STATUS_INITIALIZED_FULL === $this->status ? self::STATUS_UNINITIALIZED_FULL : self::STATUS_UNINITIALIZED_PARTIAL; + } +} diff --git a/vendor/symfony/var-exporter/Internal/LazyObjectTrait.php b/vendor/symfony/var-exporter/Internal/LazyObjectTrait.php new file mode 100644 index 000000000..4a6f232af --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/LazyObjectTrait.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\Serializer\Attribute\Ignore; + +if (\PHP_VERSION_ID >= 80300) { + /** + * @internal + */ + trait LazyObjectTrait + { + #[Ignore] + private readonly LazyObjectState $lazyObjectState; + } +} else { + /** + * @internal + */ + trait LazyObjectTrait + { + #[Ignore] + private LazyObjectState $lazyObjectState; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Reference.php b/vendor/symfony/var-exporter/Internal/Reference.php new file mode 100644 index 000000000..2c7bd7b82 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Reference.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Reference +{ + public int $count = 0; + + public function __construct( + public readonly int $id, + public readonly mixed $value = null, + ) { + } +} diff --git a/vendor/symfony/var-exporter/Internal/Registry.php b/vendor/symfony/var-exporter/Internal/Registry.php new file mode 100644 index 000000000..db05bbb85 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Registry.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Registry +{ + public static array $reflectors = []; + public static array $prototypes = []; + public static array $factories = []; + public static array $cloneable = []; + public static array $instantiableWithoutConstructor = []; + + public $classes = []; + + public function __construct(array $classes) + { + $this->classes = $classes; + } + + public static function unserialize($objects, $serializables) + { + $unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector'); + + try { + foreach ($serializables as $k => $v) { + $objects[$k] = unserialize($v); + } + } finally { + ini_set('unserialize_callback_func', $unserializeCallback); + } + + return $objects; + } + + public static function p($class) + { + self::getClassReflector($class, true, true); + + return self::$prototypes[$class]; + } + + public static function f($class) + { + $reflector = self::$reflectors[$class] ??= self::getClassReflector($class, true, false); + + return self::$factories[$class] = [$reflector, 'newInstanceWithoutConstructor'](...); + } + + public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null) + { + if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $reflector = new \ReflectionClass($class); + + if ($instantiableWithoutConstructor) { + $proto = $reflector->newInstanceWithoutConstructor(); + } elseif (!$isClass || $reflector->isAbstract()) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->name !== $class) { + $reflector = self::$reflectors[$name = $reflector->name] ??= self::getClassReflector($name, false, $cloneable); + self::$cloneable[$class] = self::$cloneable[$name]; + self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name]; + self::$prototypes[$class] = self::$prototypes[$name]; + + return $reflector; + } else { + try { + $proto = $reflector->newInstanceWithoutConstructor(); + $instantiableWithoutConstructor = true; + } catch (\ReflectionException) { + $proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:'; + if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) { + $proto = null; + } else { + try { + $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}'); + } catch (\Exception $e) { + if (__FILE__ !== $e->getFile()) { + throw $e; + } + throw new NotInstantiableTypeException($class, $e); + } + if (false === $proto) { + throw new NotInstantiableTypeException($class); + } + } + } + if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && !method_exists($class, '__serialize')) { + try { + serialize($proto); + } catch (\Exception $e) { + throw new NotInstantiableTypeException($class, $e); + } + } + } + + if (null === $cloneable) { + if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && !method_exists($class, '__unserialize'))) { + throw new NotInstantiableTypeException($class); + } + + $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone'); + } + + self::$cloneable[$class] = $cloneable; + self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor; + self::$prototypes[$class] = $proto; + + if ($proto instanceof \Throwable) { + static $setTrace; + + if (null === $setTrace) { + $setTrace = [ + new \ReflectionProperty(\Error::class, 'trace'), + new \ReflectionProperty(\Exception::class, 'trace'), + ]; + $setTrace[0] = $setTrace[0]->setValue(...); + $setTrace[1] = $setTrace[1]->setValue(...); + } + + $setTrace[$proto instanceof \Exception]($proto, []); + } + + return $reflector; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Values.php b/vendor/symfony/var-exporter/Internal/Values.php new file mode 100644 index 000000000..21ae04e68 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Values.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Values +{ + public $values; + + public function __construct(array $values) + { + $this->values = $values; + } +} diff --git a/vendor/symfony/var-exporter/LICENSE b/vendor/symfony/var-exporter/LICENSE new file mode 100644 index 000000000..7536caeae --- /dev/null +++ b/vendor/symfony/var-exporter/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +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. diff --git a/vendor/symfony/var-exporter/LazyGhostTrait.php b/vendor/symfony/var-exporter/LazyGhostTrait.php new file mode 100644 index 000000000..5191b59e7 --- /dev/null +++ b/vendor/symfony/var-exporter/LazyGhostTrait.php @@ -0,0 +1,403 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\Serializer\Attribute\Ignore; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\LazyObjectRegistry as Registry; +use Symfony\Component\VarExporter\Internal\LazyObjectState; +use Symfony\Component\VarExporter\Internal\LazyObjectTrait; + +trait LazyGhostTrait +{ + use LazyObjectTrait; + + /** + * Creates a lazy-loading ghost instance. + * + * Skipped properties should be indexed by their array-cast identifier, see + * https://php.net/manual/language.types.array#language.types.array.casting + * + * @param (\Closure(static):void $initializer The closure should initialize the object it receives as argument + * @param array|null $skippedProperties An array indexed by the properties to skip, a.k.a. the ones + * that the initializer doesn't initialize, if any + * @param static|null $instance + */ + public static function createLazyGhost(\Closure|array $initializer, ?array $skippedProperties = null, ?object $instance = null): static + { + if (\is_array($initializer)) { + trigger_deprecation('symfony/var-exporter', '6.4', 'Per-property lazy-initializers are deprecated and won\'t be supported anymore in 7.0, use an object initializer instead.'); + } + + $onlyProperties = null === $skippedProperties && \is_array($initializer) ? $initializer : null; + + if (self::class !== $class = $instance ? $instance::class : static::class) { + $skippedProperties["\0".self::class."\0lazyObjectState"] = true; + } elseif (\defined($class.'::LAZY_OBJECT_PROPERTY_SCOPES')) { + Hydrator::$propertyScopes[$class] ??= $class::LAZY_OBJECT_PROPERTY_SCOPES; + } + + $instance ??= (Registry::$classReflectors[$class] ??= new \ReflectionClass($class))->newInstanceWithoutConstructor(); + Registry::$defaultProperties[$class] ??= (array) $instance; + $instance->lazyObjectState = new LazyObjectState($initializer, $skippedProperties ??= []); + + foreach (Registry::$classResetters[$class] ??= Registry::getClassResetters($class) as $reset) { + $reset($instance, $skippedProperties, $onlyProperties); + } + + return $instance; + } + + /** + * Returns whether the object is initialized. + * + * @param $partial Whether partially initialized objects should be considered as initialized + */ + #[Ignore] + public function isLazyObjectInitialized(bool $partial = false): bool + { + if (!$state = $this->lazyObjectState ?? null) { + return true; + } + + if (!\is_array($state->initializer)) { + return LazyObjectState::STATUS_INITIALIZED_FULL === $state->status; + } + + $class = $this::class; + $properties = (array) $this; + + if ($partial) { + return (bool) array_intersect_key($state->initializer, $properties); + } + + $propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class); + foreach ($state->initializer as $key => $initializer) { + if (!\array_key_exists($key, $properties) && isset($propertyScopes[$key])) { + return false; + } + } + + return true; + } + + /** + * Forces initialization of a lazy object and returns it. + */ + public function initializeLazyObject(): static + { + if (!$state = $this->lazyObjectState ?? null) { + return $this; + } + + if (!\is_array($state->initializer)) { + if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) { + $state->initialize($this, '', null); + } + + return $this; + } + + $values = isset($state->initializer["\0"]) ? null : []; + + $class = $this::class; + $properties = (array) $this; + $propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class); + foreach ($state->initializer as $key => $initializer) { + if (\array_key_exists($key, $properties) || ![$scope, $name, $readonlyScope] = $propertyScopes[$key] ?? null) { + continue; + } + $scope = $readonlyScope ?? ('*' !== $scope ? $scope : $class); + + if (null === $values) { + if (!\is_array($values = ($state->initializer["\0"])($this, Registry::$defaultProperties[$class]))) { + throw new \TypeError(sprintf('The lazy-initializer defined for instance of "%s" must return an array, got "%s".', $class, get_debug_type($values))); + } + + if (\array_key_exists($key, $properties = (array) $this)) { + continue; + } + } + + if (\array_key_exists($key, $values)) { + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + $accessor['set']($this, $name, $properties[$key] = $values[$key]); + } else { + $state->initialize($this, $name, $scope); + $properties = (array) $this; + } + } + + return $this; + } + + /** + * @return bool Returns false when the object cannot be reset, ie when it's not a lazy object + */ + public function resetLazyObject(): bool + { + if (!$state = $this->lazyObjectState ?? null) { + return false; + } + + if (LazyObjectState::STATUS_UNINITIALIZED_FULL !== $state->status) { + $state->reset($this); + } + + return true; + } + + public function &__get($name): mixed + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name); + $state = $this->lazyObjectState ?? null; + + if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))) { + if (LazyObjectState::STATUS_INITIALIZED_FULL === $state->status) { + // Work around php/php-src#12695 + $property = null === $scope ? $name : "\0$scope\0$name"; + $property = $propertyScopes[$property][3] + ?? Hydrator::$propertyScopes[$this::class][$property][3] = new \ReflectionProperty($scope ?? $class, $name); + } else { + $property = null; + } + + if ($property?->isInitialized($this) ?? LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope)) { + goto get_in_scope; + } + } + } + + if ($parent = (Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['get']) { + if (2 === $parent) { + return parent::__get($name); + } + $value = parent::__get($name); + + return $value; + } + + if (null === $class) { + $frame = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; + trigger_error(sprintf('Undefined property: %s::$%s in %s on line %s', $this::class, $name, $frame['file'], $frame['line']), \E_USER_NOTICE); + } + + get_in_scope: + + try { + if (null === $scope) { + if (null === $readonlyScope) { + return $this->$name; + } + $value = $this->$name; + + return $value; + } + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + + return $accessor['get']($this, $name, null !== $readonlyScope); + } catch (\Error $e) { + if (\Error::class !== $e::class || !str_starts_with($e->getMessage(), 'Cannot access uninitialized non-nullable property')) { + throw $e; + } + + try { + if (null === $scope) { + $this->$name = []; + + return $this->$name; + } + + $accessor['set']($this, $name, []); + + return $accessor['get']($this, $name, null !== $readonlyScope); + } catch (\Error) { + if (preg_match('/^Cannot access uninitialized non-nullable property ([^ ]++) by reference$/', $e->getMessage(), $matches)) { + throw new \Error('Typed property '.$matches[1].' must not be accessed before initialization', $e->getCode(), $e->getPrevious()); + } + + throw $e; + } + } + } + + public function __set($name, $value): void + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); + $state = $this->lazyObjectState ?? null; + + if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status + ) { + if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) { + $state->initialize($this, $name, $readonlyScope ?? $scope); + } + goto set_in_scope; + } + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['set']) { + parent::__set($name, $value); + + return; + } + + set_in_scope: + + if (null === $scope) { + $this->$name = $value; + } else { + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + $accessor['set']($this, $name, $value); + } + } + + public function __isset($name): bool + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name); + $state = $this->lazyObjectState ?? null; + + if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status + && LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope) + ) { + goto isset_in_scope; + } + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['isset']) { + return parent::__isset($name); + } + + isset_in_scope: + + if (null === $scope) { + return isset($this->$name); + } + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + + return $accessor['isset']($this, $name); + } + + public function __unset($name): void + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); + $state = $this->lazyObjectState ?? null; + + if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status + ) { + if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) { + $state->initialize($this, $name, $readonlyScope ?? $scope); + } + goto unset_in_scope; + } + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['unset']) { + parent::__unset($name); + + return; + } + + unset_in_scope: + + if (null === $scope) { + unset($this->$name); + } else { + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + $accessor['unset']($this, $name); + } + } + + public function __clone(): void + { + if ($state = $this->lazyObjectState ?? null) { + $this->lazyObjectState = clone $state; + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['clone']) { + parent::__clone(); + } + } + + public function __serialize(): array + { + $class = self::class; + + if ((Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['serialize']) { + $properties = parent::__serialize(); + } else { + $this->initializeLazyObject(); + $properties = (array) $this; + } + unset($properties["\0$class\0lazyObjectState"]); + + if (Registry::$parentMethods[$class]['serialize'] || !Registry::$parentMethods[$class]['sleep']) { + return $properties; + } + + $scope = get_parent_class($class); + $data = []; + + foreach (parent::__sleep() as $name) { + $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; + + if (null === $k) { + trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE); + } else { + $data[$k] = $value; + } + } + + return $data; + } + + public function __destruct() + { + $state = $this->lazyObjectState ?? null; + + if ($state && \in_array($state->status, [LazyObjectState::STATUS_UNINITIALIZED_FULL, LazyObjectState::STATUS_UNINITIALIZED_PARTIAL], true)) { + return; + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['destruct']) { + parent::__destruct(); + } + } + + #[Ignore] + private function setLazyObjectAsInitialized(bool $initialized): void + { + $state = $this->lazyObjectState ?? null; + + if ($state && !\is_array($state->initializer)) { + $state->status = $initialized ? LazyObjectState::STATUS_INITIALIZED_FULL : LazyObjectState::STATUS_UNINITIALIZED_FULL; + } + } +} diff --git a/vendor/symfony/var-exporter/LazyObjectInterface.php b/vendor/symfony/var-exporter/LazyObjectInterface.php new file mode 100644 index 000000000..367088459 --- /dev/null +++ b/vendor/symfony/var-exporter/LazyObjectInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +interface LazyObjectInterface +{ + /** + * Returns whether the object is initialized. + * + * @param $partial Whether partially initialized objects should be considered as initialized + */ + public function isLazyObjectInitialized(bool $partial = false): bool; + + /** + * Forces initialization of a lazy object and returns it. + */ + public function initializeLazyObject(): object; + + /** + * @return bool Returns false when the object cannot be reset, ie when it's not a lazy object + */ + public function resetLazyObject(): bool; +} diff --git a/vendor/symfony/var-exporter/LazyProxyTrait.php b/vendor/symfony/var-exporter/LazyProxyTrait.php new file mode 100644 index 000000000..203367052 --- /dev/null +++ b/vendor/symfony/var-exporter/LazyProxyTrait.php @@ -0,0 +1,349 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\Serializer\Attribute\Ignore; +use Symfony\Component\VarExporter\Hydrator as PublicHydrator; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\LazyObjectRegistry as Registry; +use Symfony\Component\VarExporter\Internal\LazyObjectState; +use Symfony\Component\VarExporter\Internal\LazyObjectTrait; + +trait LazyProxyTrait +{ + use LazyObjectTrait; + + /** + * Creates a lazy-loading virtual proxy. + * + * @param \Closure():object $initializer Returns the proxied object + * @param static|null $instance + */ + public static function createLazyProxy(\Closure $initializer, ?object $instance = null): static + { + if (self::class !== $class = $instance ? $instance::class : static::class) { + $skippedProperties = ["\0".self::class."\0lazyObjectState" => true]; + } elseif (\defined($class.'::LAZY_OBJECT_PROPERTY_SCOPES')) { + Hydrator::$propertyScopes[$class] ??= $class::LAZY_OBJECT_PROPERTY_SCOPES; + } + + $instance ??= (Registry::$classReflectors[$class] ??= new \ReflectionClass($class))->newInstanceWithoutConstructor(); + $instance->lazyObjectState = new LazyObjectState($initializer); + + foreach (Registry::$classResetters[$class] ??= Registry::getClassResetters($class) as $reset) { + $reset($instance, $skippedProperties ??= []); + } + + return $instance; + } + + /** + * Returns whether the object is initialized. + * + * @param $partial Whether partially initialized objects should be considered as initialized + */ + #[Ignore] + public function isLazyObjectInitialized(bool $partial = false): bool + { + return !isset($this->lazyObjectState) || isset($this->lazyObjectState->realInstance) || Registry::$noInitializerState === $this->lazyObjectState->initializer; + } + + /** + * Forces initialization of a lazy object and returns it. + */ + public function initializeLazyObject(): parent + { + if ($state = $this->lazyObjectState ?? null) { + return $state->realInstance ??= ($state->initializer)(); + } + + return $this; + } + + /** + * @return bool Returns false when the object cannot be reset, ie when it's not a lazy object + */ + public function resetLazyObject(): bool + { + if (!isset($this->lazyObjectState) || Registry::$noInitializerState === $this->lazyObjectState->initializer) { + return false; + } + + unset($this->lazyObjectState->realInstance); + + return true; + } + + public function &__get($name): mixed + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + $instance = $this; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name); + + if (null === $scope || isset($propertyScopes["\0$scope\0$name"])) { + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } + $parent = 2; + goto get_in_scope; + } + } + $parent = (Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['get']; + + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } else { + if (2 === $parent) { + return parent::__get($name); + } + $value = parent::__get($name); + + return $value; + } + + if (!$parent && null === $class && !\array_key_exists($name, (array) $instance)) { + $frame = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; + trigger_error(sprintf('Undefined property: %s::$%s in %s on line %s', $instance::class, $name, $frame['file'], $frame['line']), \E_USER_NOTICE); + } + + get_in_scope: + + try { + if (null === $scope) { + if (null === $readonlyScope && 1 !== $parent) { + return $instance->$name; + } + $value = $instance->$name; + + return $value; + } + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + + return $accessor['get']($instance, $name, null !== $readonlyScope || 1 === $parent); + } catch (\Error $e) { + if (\Error::class !== $e::class || !str_starts_with($e->getMessage(), 'Cannot access uninitialized non-nullable property')) { + throw $e; + } + + try { + if (null === $scope) { + $instance->$name = []; + + return $instance->$name; + } + + $accessor['set']($instance, $name, []); + + return $accessor['get']($instance, $name, null !== $readonlyScope || 1 === $parent); + } catch (\Error) { + throw $e; + } + } + } + + public function __set($name, $value): void + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + $instance = $this; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); + + if ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) { + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } + goto set_in_scope; + } + } + + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['set']) { + parent::__set($name, $value); + + return; + } + + set_in_scope: + + if (null === $scope) { + $instance->$name = $value; + } else { + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + $accessor['set']($instance, $name, $value); + } + } + + public function __isset($name): bool + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + $instance = $this; + + if ([$class] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name); + + if (null === $scope || isset($propertyScopes["\0$scope\0$name"])) { + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } + goto isset_in_scope; + } + } + + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['isset']) { + return parent::__isset($name); + } + + isset_in_scope: + + if (null === $scope) { + return isset($instance->$name); + } + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + + return $accessor['isset']($instance, $name); + } + + public function __unset($name): void + { + $propertyScopes = Hydrator::$propertyScopes[$this::class] ??= Hydrator::getPropertyScopes($this::class); + $scope = null; + $instance = $this; + + if ([$class, , $readonlyScope] = $propertyScopes[$name] ?? null) { + $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); + + if ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) { + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } + goto unset_in_scope; + } + } + + if ($state = $this->lazyObjectState ?? null) { + $instance = $state->realInstance ??= ($state->initializer)(); + } elseif ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['unset']) { + parent::__unset($name); + + return; + } + + unset_in_scope: + + if (null === $scope) { + unset($instance->$name); + } else { + $accessor = Registry::$classAccessors[$scope] ??= Registry::getClassAccessors($scope); + $accessor['unset']($instance, $name); + } + } + + public function __clone(): void + { + if (!isset($this->lazyObjectState)) { + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['clone']) { + parent::__clone(); + } + + return; + } + + $this->lazyObjectState = clone $this->lazyObjectState; + + if (isset($this->lazyObjectState->realInstance)) { + $this->lazyObjectState->realInstance = clone $this->lazyObjectState->realInstance; + } + } + + public function __serialize(): array + { + $class = self::class; + $state = $this->lazyObjectState ?? null; + + if (!$state && (Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['serialize']) { + $properties = parent::__serialize(); + } else { + $properties = (array) $this; + + if ($state) { + unset($properties["\0$class\0lazyObjectState"]); + $properties["\0$class\0lazyObjectReal"] = $state->realInstance ??= ($state->initializer)(); + } + } + + if ($state || Registry::$parentMethods[$class]['serialize'] || !Registry::$parentMethods[$class]['sleep']) { + return $properties; + } + + $scope = get_parent_class($class); + $data = []; + + foreach (parent::__sleep() as $name) { + $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; + + if (null === $k) { + trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE); + } else { + $data[$k] = $value; + } + } + + return $data; + } + + public function __unserialize(array $data): void + { + $class = self::class; + + if ($instance = $data["\0$class\0lazyObjectReal"] ?? null) { + unset($data["\0$class\0lazyObjectReal"]); + + foreach (Registry::$classResetters[$class] ??= Registry::getClassResetters($class) as $reset) { + $reset($this, $data); + } + + if ($data) { + PublicHydrator::hydrate($this, $data); + } + $this->lazyObjectState = new LazyObjectState(Registry::$noInitializerState ??= static fn () => throw new \LogicException('Lazy proxy has no initializer.')); + $this->lazyObjectState->realInstance = $instance; + } elseif ((Registry::$parentMethods[$class] ??= Registry::getParentMethods($class))['unserialize']) { + parent::__unserialize($data); + } else { + PublicHydrator::hydrate($this, $data); + + if (Registry::$parentMethods[$class]['wakeup']) { + parent::__wakeup(); + } + } + } + + public function __destruct() + { + if (isset($this->lazyObjectState)) { + return; + } + + if ((Registry::$parentMethods[self::class] ??= Registry::getParentMethods(self::class))['destruct']) { + parent::__destruct(); + } + } +} diff --git a/vendor/symfony/var-exporter/ProxyHelper.php b/vendor/symfony/var-exporter/ProxyHelper.php new file mode 100644 index 000000000..d5a8d7418 --- /dev/null +++ b/vendor/symfony/var-exporter/ProxyHelper.php @@ -0,0 +1,413 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Exception\LogicException; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\LazyObjectRegistry; + +/** + * @author Nicolas Grekas + */ +final class ProxyHelper +{ + /** + * Helps generate lazy-loading ghost objects. + * + * @throws LogicException When the class is incompatible with ghost objects + */ + public static function generateLazyGhost(\ReflectionClass $class): string + { + if (\PHP_VERSION_ID >= 80200 && \PHP_VERSION_ID < 80300 && $class->isReadOnly()) { + throw new LogicException(sprintf('Cannot generate lazy ghost with PHP < 8.3: class "%s" is readonly.', $class->name)); + } + if ($class->isFinal()) { + throw new LogicException(sprintf('Cannot generate lazy ghost: class "%s" is final.', $class->name)); + } + if ($class->isInterface() || $class->isAbstract()) { + throw new LogicException(sprintf('Cannot generate lazy ghost: "%s" is not a concrete class.', $class->name)); + } + if (\stdClass::class !== $class->name && $class->isInternal()) { + throw new LogicException(sprintf('Cannot generate lazy ghost: class "%s" is internal.', $class->name)); + } + if ($class->hasMethod('__get') && 'mixed' !== (self::exportType($class->getMethod('__get')) ?? 'mixed')) { + throw new LogicException(sprintf('Cannot generate lazy ghost: return type of method "%s::__get()" should be "mixed".', $class->name)); + } + + static $traitMethods; + $traitMethods ??= (new \ReflectionClass(LazyGhostTrait::class))->getMethods(); + + foreach ($traitMethods as $method) { + if ($class->hasMethod($method->name) && $class->getMethod($method->name)->isFinal()) { + throw new LogicException(sprintf('Cannot generate lazy ghost: method "%s::%s()" is final.', $class->name, $method->name)); + } + } + + $parent = $class; + while ($parent = $parent->getParentClass()) { + if (\stdClass::class !== $parent->name && $parent->isInternal()) { + throw new LogicException(sprintf('Cannot generate lazy ghost: class "%s" extends "%s" which is internal.', $class->name, $parent->name)); + } + } + $propertyScopes = self::exportPropertyScopes($class->name); + + return <<name} implements \Symfony\Component\VarExporter\LazyObjectInterface + { + use \Symfony\Component\VarExporter\LazyGhostTrait; + + private const LAZY_OBJECT_PROPERTY_SCOPES = {$propertyScopes}; + } + + // Help opcache.preload discover always-needed symbols + class_exists(\Symfony\Component\VarExporter\Internal\Hydrator::class); + class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectRegistry::class); + class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); + + EOPHP; + } + + /** + * Helps generate lazy-loading virtual proxies. + * + * @param \ReflectionClass[] $interfaces + * + * @throws LogicException When the class is incompatible with virtual proxies + */ + public static function generateLazyProxy(?\ReflectionClass $class, array $interfaces = []): string + { + if (!class_exists($class?->name ?? \stdClass::class, false)) { + throw new LogicException(sprintf('Cannot generate lazy proxy: "%s" is not a class.', $class->name)); + } + if ($class?->isFinal()) { + throw new LogicException(sprintf('Cannot generate lazy proxy: class "%s" is final.', $class->name)); + } + if (\PHP_VERSION_ID >= 80200 && \PHP_VERSION_ID < 80300 && $class?->isReadOnly()) { + throw new LogicException(sprintf('Cannot generate lazy proxy with PHP < 8.3: class "%s" is readonly.', $class->name)); + } + + $methodReflectors = [$class?->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) ?? []]; + foreach ($interfaces as $interface) { + if (!$interface->isInterface()) { + throw new LogicException(sprintf('Cannot generate lazy proxy: "%s" is not an interface.', $interface->name)); + } + $methodReflectors[] = $interface->getMethods(); + } + $methodReflectors = array_merge(...$methodReflectors); + + $extendsInternalClass = false; + if ($parent = $class) { + do { + $extendsInternalClass = \stdClass::class !== $parent->name && $parent->isInternal(); + } while (!$extendsInternalClass && $parent = $parent->getParentClass()); + } + $methodsHaveToBeProxied = $extendsInternalClass; + $methods = []; + + foreach ($methodReflectors as $method) { + if ('__get' !== strtolower($method->name) || 'mixed' === ($type = self::exportType($method) ?? 'mixed')) { + continue; + } + $methodsHaveToBeProxied = true; + $trait = new \ReflectionMethod(LazyProxyTrait::class, '__get'); + $body = \array_slice(file($trait->getFileName()), $trait->getStartLine() - 1, $trait->getEndLine() - $trait->getStartLine()); + $body[0] = str_replace('): mixed', '): '.$type, $body[0]); + $methods['__get'] = strtr(implode('', $body).' }', [ + 'Hydrator' => '\\'.Hydrator::class, + 'Registry' => '\\'.LazyObjectRegistry::class, + ]); + break; + } + + foreach ($methodReflectors as $method) { + if (($method->isStatic() && !$method->isAbstract()) || isset($methods[$lcName = strtolower($method->name)])) { + continue; + } + if ($method->isFinal()) { + if ($extendsInternalClass || $methodsHaveToBeProxied || method_exists(LazyProxyTrait::class, $method->name)) { + throw new LogicException(sprintf('Cannot generate lazy proxy: method "%s::%s()" is final.', $class->name, $method->name)); + } + continue; + } + if (method_exists(LazyProxyTrait::class, $method->name) || ($method->isProtected() && !$method->isAbstract())) { + continue; + } + + $signature = self::exportSignature($method, true, $args); + $parentCall = $method->isAbstract() ? "throw new \BadMethodCallException('Cannot forward abstract method \"{$method->class}::{$method->name}()\".')" : "parent::{$method->name}({$args})"; + + if ($method->isStatic()) { + $body = " $parentCall;"; + } elseif (str_ends_with($signature, '): never') || str_ends_with($signature, '): void')) { + $body = <<lazyObjectState)) { + (\$this->lazyObjectState->realInstance ??= (\$this->lazyObjectState->initializer)())->{$method->name}({$args}); + } else { + {$parentCall}; + } + EOPHP; + } else { + if (!$methodsHaveToBeProxied && !$method->isAbstract()) { + // Skip proxying methods that might return $this + foreach (preg_split('/[()|&]++/', self::exportType($method) ?? 'static') as $type) { + if (\in_array($type = ltrim($type, '?'), ['static', 'object'], true)) { + continue 2; + } + foreach ([$class, ...$interfaces] as $r) { + if ($r && is_a($r->name, $type, true)) { + continue 3; + } + } + } + } + + $body = <<lazyObjectState)) { + return (\$this->lazyObjectState->realInstance ??= (\$this->lazyObjectState->initializer)())->{$method->name}({$args}); + } + + return {$parentCall}; + EOPHP; + } + $methods[$lcName] = " {$signature}\n {\n{$body}\n }"; + } + + $types = $interfaces = array_unique(array_column($interfaces, 'name')); + $interfaces[] = LazyObjectInterface::class; + $interfaces = implode(', \\', $interfaces); + $parent = $class ? ' extends \\'.$class->name : ''; + array_unshift($types, $class ? 'parent' : ''); + $type = ltrim(implode('&\\', $types), '&'); + + if (!$class) { + $trait = new \ReflectionMethod(LazyProxyTrait::class, 'initializeLazyObject'); + $body = \array_slice(file($trait->getFileName()), $trait->getStartLine() - 1, $trait->getEndLine() - $trait->getStartLine()); + $body[0] = str_replace('): parent', '): '.$type, $body[0]); + $methods = ['initializeLazyObject' => implode('', $body).' }'] + $methods; + } + $body = $methods ? "\n".implode("\n\n", $methods)."\n" : ''; + $propertyScopes = $class ? self::exportPropertyScopes($class->name) : '[]'; + + if ( + $class?->hasMethod('__unserialize') + && !$class->getMethod('__unserialize')->getParameters()[0]->getType() + ) { + // fix contravariance type problem when $class declares a `__unserialize()` method without typehint. + $lazyProxyTraitStatement = <<__doUnserialize(\$data); + } + + EOPHP; + } else { + $lazyProxyTraitStatement = <<class : $function->getNamespaceName().'\\'; + $namespace = substr($namespace, 0, strrpos($namespace, '\\') ?: 0); + foreach ($function->getParameters() as $param) { + $parameters[] = ($param->getAttributes(\SensitiveParameter::class) ? '#[\SensitiveParameter] ' : '') + .($withParameterTypes && $param->hasType() ? self::exportType($param).' ' : '') + .($param->isPassedByReference() ? '&' : '') + .($param->isVariadic() ? '...' : '').'$'.$param->name + .($param->isOptional() && !$param->isVariadic() ? ' = '.self::exportDefault($param, $namespace) : ''); + if ($param->isPassedByReference()) { + $byRefIndex = 1 + $param->getPosition(); + } + $args .= ($param->isVariadic() ? '...$' : '$').$param->name.', '; + } + + if (!$param || !$byRefIndex) { + $args = '...\func_get_args()'; + } elseif ($param->isVariadic()) { + $args = substr($args, 0, -2); + } else { + $args = explode(', ', $args, 1 + $byRefIndex); + $args[$byRefIndex] = sprintf('...\array_slice(\func_get_args(), %d)', $byRefIndex); + $args = implode(', ', $args); + } + + $signature = 'function '.($function->returnsReference() ? '&' : '') + .($function->isClosure() ? '' : $function->name).'('.implode(', ', $parameters).')'; + + if ($function instanceof \ReflectionMethod) { + $signature = ($function->isPublic() ? 'public ' : ($function->isProtected() ? 'protected ' : 'private ')) + .($function->isStatic() ? 'static ' : '').$signature; + } + if ($function->hasReturnType()) { + $signature .= ': '.self::exportType($function); + } + + static $getPrototype; + $getPrototype ??= (new \ReflectionMethod(\ReflectionMethod::class, 'getPrototype'))->invoke(...); + + while ($function) { + if ($function->hasTentativeReturnType()) { + return '#[\ReturnTypeWillChange] '.$signature; + } + + try { + $function = $function instanceof \ReflectionMethod && $function->isAbstract() ? false : $getPrototype($function); + } catch (\ReflectionException) { + break; + } + } + + return $signature; + } + + public static function exportType(\ReflectionFunctionAbstract|\ReflectionProperty|\ReflectionParameter $owner, bool $noBuiltin = false, ?\ReflectionType $type = null): ?string + { + if (!$type ??= $owner instanceof \ReflectionFunctionAbstract ? $owner->getReturnType() : $owner->getType()) { + return null; + } + $class = null; + $types = []; + if ($type instanceof \ReflectionUnionType) { + $reflectionTypes = $type->getTypes(); + $glue = '|'; + } elseif ($type instanceof \ReflectionIntersectionType) { + $reflectionTypes = $type->getTypes(); + $glue = '&'; + } else { + $reflectionTypes = [$type]; + $glue = null; + } + + foreach ($reflectionTypes as $type) { + if ($type instanceof \ReflectionIntersectionType) { + if ('' !== $name = '('.self::exportType($owner, $noBuiltin, $type).')') { + $types[] = $name; + } + continue; + } + $name = $type->getName(); + + if ($noBuiltin && $type->isBuiltin()) { + continue; + } + if (\in_array($name, ['parent', 'self'], true) && $class ??= $owner->getDeclaringClass()) { + $name = 'parent' === $name ? ($class->getParentClass() ?: null)?->name ?? 'parent' : $class->name; + } + + $types[] = ($noBuiltin || $type->isBuiltin() || 'static' === $name ? '' : '\\').$name; + } + + if (!$types) { + return ''; + } + if (null === $glue) { + return (!$noBuiltin && $type->allowsNull() && !\in_array($name, ['mixed', 'null'], true) ? '?' : '').$types[0]; + } + sort($types); + + return implode($glue, $types); + } + + private static function exportPropertyScopes(string $parent): string + { + $propertyScopes = Hydrator::$propertyScopes[$parent] ??= Hydrator::getPropertyScopes($parent); + uksort($propertyScopes, 'strnatcmp'); + foreach ($propertyScopes as $k => $v) { + unset($propertyScopes[$k][3]); + } + $propertyScopes = VarExporter::export($propertyScopes); + $propertyScopes = str_replace(VarExporter::export($parent), 'parent::class', $propertyScopes); + $propertyScopes = preg_replace("/(?|(,)\n( ) |\n |,\n (\]))/", '$1$2', $propertyScopes); + $propertyScopes = str_replace("\n", "\n ", $propertyScopes); + + return $propertyScopes; + } + + private static function exportDefault(\ReflectionParameter $param, $namespace): string + { + $default = rtrim(substr(explode('$'.$param->name.' = ', (string) $param, 2)[1] ?? '', 0, -2)); + + if (\in_array($default, ['', 'NULL'], true)) { + return 'null'; + } + if (str_ends_with($default, "...'") && preg_match("/^'(?:[^'\\\\]*+(?:\\\\.)*+)*+'$/", $default)) { + return VarExporter::export($param->getDefaultValue()); + } + + $regexp = "/(\"(?:[^\"\\\\]*+(?:\\\\.)*+)*+\"|'(?:[^'\\\\]*+(?:\\\\.)*+)*+')/"; + $parts = preg_split($regexp, $default, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + + $regexp = '/([\[\( ]|^)([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z0-9_\x7f-\xff]++)*+)(\(?)(?!: )/'; + $callback = (false !== strpbrk($default, "\\:('") && $class = $param->getDeclaringClass()) + ? fn ($m) => $m[1].match ($m[2]) { + 'new', 'false', 'true', 'null' => $m[2], + 'NULL' => 'null', + 'self' => '\\'.$class->name, + 'namespace\\parent', + 'parent' => ($parent = $class->getParentClass()) ? '\\'.$parent->name : 'parent', + default => self::exportSymbol($m[2], '(' !== $m[3], $namespace), + }.$m[3] + : fn ($m) => $m[1].match ($m[2]) { + 'new', 'false', 'true', 'null', 'self', 'parent' => $m[2], + 'NULL' => 'null', + default => self::exportSymbol($m[2], '(' !== $m[3], $namespace), + }.$m[3]; + + return implode('', array_map(fn ($part) => match ($part[0]) { + '"' => $part, // for internal classes only + "'" => false !== strpbrk($part, "\\\0\r\n") ? '"'.substr(str_replace(['$', "\0", "\r", "\n"], ['\$', '\0', '\r', '\n'], $part), 1, -1).'"' : $part, + default => preg_replace_callback($regexp, $callback, $part), + }, $parts)); + } + + private static function exportSymbol(string $symbol, bool $mightBeRootConst, string $namespace): string + { + if (!$mightBeRootConst + || false === ($ns = strrpos($symbol, '\\')) + || substr($symbol, 0, $ns) !== $namespace + || \defined($symbol) + || !\defined(substr($symbol, $ns + 1)) + ) { + return '\\'.$symbol; + } + + return '\\'.substr($symbol, $ns + 1); + } +} diff --git a/vendor/symfony/var-exporter/README.md b/vendor/symfony/var-exporter/README.md new file mode 100644 index 000000000..719527052 --- /dev/null +++ b/vendor/symfony/var-exporter/README.md @@ -0,0 +1,137 @@ +VarExporter Component +===================== + +The VarExporter component provides various tools to deal with the internal state +of objects: + +- `VarExporter::export()` allows exporting any serializable PHP data structure to + plain PHP code. While doing so, it preserves all the semantics associated with + the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`, + `__serialize`, `__unserialize`); +- `Instantiator::instantiate()` creates an object and sets its properties without + calling its constructor nor any other methods; +- `Hydrator::hydrate()` can set the properties of an existing object; +- `Lazy*Trait` can make a class behave as a lazy-loading ghost or virtual proxy. + +VarExporter::export() +--------------------- + +The reason to use `VarExporter::export()` *vs* `serialize()` or +[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to +OPcache, the resulting code is significantly faster and more memory efficient +than using `unserialize()` or `igbinary_unserialize()`. + +Unlike `var_export()`, this works on any serializable PHP value. + +It also provides a few improvements over `var_export()`/`serialize()`: + + * the output is PSR-2 compatible; + * the output can be re-indented without messing up with `\r` or `\n` in the data; + * missing classes throw a `ClassNotFoundException` instead of being unserialized + to `PHP_Incomplete_Class` objects; + * references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator` + instances are preserved; + * `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes + throw an exception when being serialized (their unserialized version is broken + anyway, see https://bugs.php.net/76737). + +Instantiator and Hydrator +------------------------- + +`Instantiator::instantiate($class)` creates an object of the given class without +calling its constructor nor any other methods. + +`Hydrator::hydrate()` sets the properties of an existing object, including +private and protected ones. For example: + +```php +// Sets the public or protected $object->propertyName property +Hydrator::hydrate($object, ['propertyName' => $propertyValue]); + +// Sets a private property defined on its parent Bar class: +Hydrator::hydrate($object, ["\0Bar\0privateBarProperty" => $propertyValue]); + +// Alternative way to set the private $object->privateBarProperty property +Hydrator::hydrate($object, [], [ + Bar::class => ['privateBarProperty' => $propertyValue], +]); +``` + +`Lazy*Trait` +------------ + +The component provides two lazy-loading patterns: ghost objects and virtual +proxies (see https://martinfowler.com/eaaCatalog/lazyLoad.html for reference). + +Ghost objects work only with concrete and non-internal classes. In the generic +case, they are not compatible with using factories in their initializer. + +Virtual proxies work with concrete, abstract or internal classes. They provide an +API that looks like the actual objects and forward calls to them. They can cause +identity problems because proxies might not be seen as equivalents to the actual +objects they proxy. + +Because of this identity problem, ghost objects should be preferred when +possible. Exceptions thrown by the `ProxyHelper` class can help decide when it +can be used or not. + +Ghost objects and virtual proxies both provide implementations for the +`LazyObjectInterface` which allows resetting them to their initial state or to +forcibly initialize them when needed. Note that resetting a ghost object skips +its read-only properties. You should use a virtual proxy to reset read-only +properties. + +### `LazyGhostTrait` + +By using `LazyGhostTrait` either directly in your classes or by using +`ProxyHelper::generateLazyGhost()`, you can make their instances lazy-loadable. +This works by creating these instances empty and by computing their state only +when accessing a property. + +```php +class FooLazyGhost extends Foo +{ + use LazyGhostTrait; +} + +$foo = FooLazyGhost::createLazyGhost(initializer: function (Foo $instance): void { + // [...] Use whatever heavy logic you need here + // to compute the $dependencies of the $instance + $instance->__construct(...$dependencies); + // [...] Call setters, etc. if needed +}); + +// $foo is now a lazy-loading ghost object. The initializer will +// be called only when and if a *property* is accessed. +``` + +### `LazyProxyTrait` + +Alternatively, `LazyProxyTrait` can be used to create virtual proxies: + +```php +$proxyCode = ProxyHelper::generateLazyProxy(new ReflectionClass(Foo::class)); +// $proxyCode contains the reference to LazyProxyTrait +// and should be dumped into a file in production envs +eval('class FooLazyProxy'.$proxyCode); + +$foo = FooLazyProxy::createLazyProxy(initializer: function (): Foo { + // [...] Use whatever heavy logic you need here + // to compute the $dependencies of the $instance + $instance = new Foo(...$dependencies); + // [...] Call setters, etc. if needed + + return $instance; +}); +// $foo is now a lazy-loading virtual proxy object. The initializer will +// be called only when and if a *method* is called. +``` + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/var_exporter.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/var-exporter/VarExporter.php b/vendor/symfony/var-exporter/VarExporter.php new file mode 100644 index 000000000..22e9b5152 --- /dev/null +++ b/vendor/symfony/var-exporter/VarExporter.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Internal\Exporter; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\Registry; +use Symfony\Component\VarExporter\Internal\Values; + +/** + * Exports serializable PHP values to PHP code. + * + * VarExporter allows serializing PHP data structures to plain PHP code (like var_export()) + * while preserving all the semantics associated with serialize() (unlike var_export()). + * + * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize(). + * + * @author Nicolas Grekas + */ +final class VarExporter +{ + /** + * Exports a serializable PHP value to PHP code. + * + * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise + * @param array &$foundClasses Classes found in the value are added to this list as both keys and values + * + * @throws ExceptionInterface When the provided value cannot be serialized + */ + public static function export(mixed $value, ?bool &$isStaticValue = null, array &$foundClasses = []): string + { + $isStaticValue = true; + + if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) { + return Exporter::export($value); + } + + $objectsPool = new \SplObjectStorage(); + $refsPool = []; + $objectsCount = 0; + + try { + $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0]; + } finally { + $references = []; + foreach ($refsPool as $i => $v) { + if ($v[0]->count) { + $references[1 + $i] = $v[2]; + } + $v[0] = $v[1]; + } + } + + if ($isStaticValue) { + return Exporter::export($value); + } + + $classes = []; + $values = []; + $states = []; + foreach ($objectsPool as $i => $v) { + [, $class, $values[], $wakeup] = $objectsPool[$v]; + $foundClasses[$class] = $classes[] = $class; + + if (0 < $wakeup) { + $states[$wakeup] = $i; + } elseif (0 > $wakeup) { + $states[-$wakeup] = [$i, array_pop($values)]; + $values[] = []; + } + } + ksort($states); + + $wakeups = [null]; + foreach ($states as $v) { + if (\is_array($v)) { + $wakeups[-$v[0]] = $v[1]; + } else { + $wakeups[] = $v; + } + } + + if (null === $wakeups[0]) { + unset($wakeups[0]); + } + + $properties = []; + foreach ($values as $i => $vars) { + foreach ($vars as $class => $values) { + foreach ($values as $name => $v) { + $properties[$class][$name][$i] = $v; + } + } + } + + if ($classes || $references) { + $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups); + } else { + $isStaticValue = true; + } + + return Exporter::export($value); + } +} diff --git a/vendor/symfony/var-exporter/composer.json b/vendor/symfony/var-exporter/composer.json new file mode 100644 index 000000000..e7b0fb039 --- /dev/null +++ b/vendor/symfony/var-exporter/composer.json @@ -0,0 +1,34 @@ +{ + "name": "symfony/var-exporter", + "type": "library", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone", "lazy-loading", "proxy"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\VarExporter\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +}