diff --git a/app/composer.json b/app/composer.json index 29cb6562f..b47f40050 100644 --- a/app/composer.json +++ b/app/composer.json @@ -6,7 +6,7 @@ "license": "MIT", "require": { "php": ">=8.0", - "cakephp/cakephp": "4.4.*", + "cakephp/cakephp": "4.5.*", "cakephp/migrations": "^3.2", "cakephp/plugin-installer": "^1.3", "doctrine/dbal": "^3.3", diff --git a/app/vendor/bin/sql-formatter b/app/vendor/bin/sql-formatter new file mode 100755 index 000000000..de69b8ade --- /dev/null +++ b/app/vendor/bin/sql-formatter @@ -0,0 +1,120 @@ +#!/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')) + ) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/doctrine/sql-formatter/bin/sql-formatter'); + exit(0); + } +} + +include __DIR__ . '/..'.'/doctrine/sql-formatter/bin/sql-formatter'; diff --git a/app/vendor/bin/validate-json b/app/vendor/bin/validate-json index 5910c8159..d077db58b 100755 --- a/app/vendor/bin/validate-json +++ b/app/vendor/bin/validate-json @@ -108,7 +108,10 @@ if (PHP_VERSION_ID < 80000) { } } - if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { include("phpvfscomposer://" . __DIR__ . '/..'.'/justinrainbow/json-schema/bin/validate-json'); exit(0); } diff --git a/app/vendor/cakephp-plugins.php b/app/vendor/cakephp-plugins.php index e0831e061..f862280d8 100644 --- a/app/vendor/cakephp-plugins.php +++ b/app/vendor/cakephp-plugins.php @@ -6,6 +6,7 @@ 'Bake' => $baseDir . '/vendor/cakephp/bake/', 'Cake/TwigView' => $baseDir . '/vendor/cakephp/twig-view/', 'CoreAssigner' => $baseDir . '/plugins/CoreAssigner/', + 'CoreEnroller' => $baseDir . '/plugins/CoreEnroller/', 'CoreServer' => $baseDir . '/plugins/CoreServer/', 'DebugKit' => $baseDir . '/vendor/cakephp/debug_kit/', 'Migrations' => $baseDir . '/vendor/cakephp/migrations/', diff --git a/app/vendor/cakephp/cakephp/VERSION.txt b/app/vendor/cakephp/cakephp/VERSION.txt index d0e169172..4a9ed9ac7 100644 --- a/app/vendor/cakephp/cakephp/VERSION.txt +++ b/app/vendor/cakephp/cakephp/VERSION.txt @@ -16,4 +16,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -4.4.16 +4.5.4 diff --git a/app/vendor/cakephp/cakephp/composer.json b/app/vendor/cakephp/cakephp/composer.json index 278f11070..0060696c6 100644 --- a/app/vendor/cakephp/cakephp/composer.json +++ b/app/vendor/cakephp/cakephp/composer.json @@ -22,11 +22,11 @@ } ], "require": { - "php": ">=7.4.0", + "php": ">=7.4.0,<9", "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "cakephp/chronos": "^2.2", + "cakephp/chronos": "^2.4.0-RC2", "composer/ca-bundle": "^1.2", "laminas/laminas-diactoros": "^2.2.2", "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", @@ -58,7 +58,7 @@ "require-dev": { "cakephp/cakephp-codesniffer": "^4.5", "mikey179/vfsstream": "^1.6.10", - "paragonie/csp-builder": "^2.3", + "paragonie/csp-builder": "^2.3 || ^3.0", "phpunit/phpunit": "^8.5 || ^9.3" }, "suggest": { @@ -88,6 +88,7 @@ }, "files": [ "src/Core/functions.php", + "src/Error/functions.php", "src/Collection/functions.php", "src/I18n/functions.php", "src/Routing/functions.php", diff --git a/app/vendor/cakephp/cakephp/src/Cache/Cache.php b/app/vendor/cakephp/cakephp/src/Cache/Cache.php index 0c8d8d37f..b91032291 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Cache.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Cache.php @@ -17,8 +17,11 @@ namespace Cake\Cache; use Cake\Cache\Engine\NullEngine; +use Cake\Cache\Exception\CacheWriteException; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\StaticConfigTrait; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Cache provides a consistent interface to Caching in your application. It allows you @@ -136,7 +139,7 @@ public static function setRegistry(CacheRegistry $registry): void * Finds and builds the instance of the required engine class. * * @param string $name Name of the config array that needs an engine instance built - * @throws \Cake\Cache\InvalidArgumentException When a cache engine cannot be created. + * @throws \Cake\Cache\Exception\InvalidArgumentException When a cache engine cannot be created. * @throws \RuntimeException If loading of the engine failed. * @return void */ @@ -265,15 +268,12 @@ public static function write(string $key, $value, string $config = 'default'): b $backend = static::pool($config); $success = $backend->set($key, $value); if ($success === false && $value !== '') { - trigger_error( - sprintf( - "%s cache was unable to write '%s' to %s cache", - $config, - $key, - get_class($backend) - ), - E_USER_WARNING - ); + throw new CacheWriteException(sprintf( + "%s cache was unable to write '%s' to %s cache", + $config, + $key, + get_class($backend) + )); } return $success; @@ -299,7 +299,7 @@ public static function write(string $key, $value, string $config = 'default'): b * @param iterable $data An array or Traversable of data to be stored in the cache * @param string $config Optional string configuration name to write to. Defaults to 'default' * @return bool True on success, false on failure - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function writeMany(iterable $data, string $config = 'default'): bool { @@ -354,7 +354,7 @@ public static function read(string $key, string $config = 'default') * @param string $config optional name of the configuration to use. Defaults to 'default' * @return iterable An array containing, for each of the given $keys, * the cached data or false if cached data could not be retrieved. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function readMany(iterable $keys, string $config = 'default'): iterable { @@ -369,7 +369,7 @@ public static function readMany(iterable $keys, string $config = 'default'): ite * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it. - * @throws \Cake\Cache\InvalidArgumentException When offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException When offset < 0 */ public static function increment(string $key, int $offset = 1, string $config = 'default') { @@ -388,7 +388,7 @@ public static function increment(string $key, int $offset = 1, string $config = * @param string $config Optional string configuration name. Defaults to 'default' * @return int|false New value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it - * @throws \Cake\Cache\InvalidArgumentException when offset < 0 + * @throws \Cake\Cache\Exception\InvalidArgumentException when offset < 0 */ public static function decrement(string $key, int $offset = 1, string $config = 'default') { @@ -445,7 +445,7 @@ public static function delete(string $key, string $config = 'default'): bool * @param iterable $keys Array or Traversable of cache keys to be deleted * @param string $config name of the configuration to use. Defaults to 'default' * @return bool True on success, false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function deleteMany(iterable $keys, string $config = 'default'): bool { @@ -505,7 +505,7 @@ public static function clearGroup(string $group, string $config = 'default'): bo * * @param string|null $group Group name or null to retrieve all group mappings * @return array Map of group and all configuration that has the same group - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ public static function groupConfigs(?string $group = null): array { diff --git a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php index da5bcc719..b37fc672f 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php @@ -16,10 +16,12 @@ */ namespace Cake\Cache; +use Cake\Cache\Exception\InvalidArgumentException; use Cake\Core\InstanceConfigTrait; use DateInterval; use DateTime; use Psr\SimpleCache\CacheInterface; +use function Cake\Core\triggerWarning; /** * Storage engine for CakePHP caching @@ -96,7 +98,7 @@ public function init(array $config = []): bool * * @param string $key Key to check. * @return void - * @throws \Cake\Cache\InvalidArgumentException When the key is not valid. + * @throws \Cake\Cache\Exception\InvalidArgumentException When the key is not valid. */ protected function ensureValidKey($key): void { @@ -111,7 +113,7 @@ protected function ensureValidKey($key): void * @param iterable $iterable The iterable to check. * @param string $check Whether to check keys or values. * @return void - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException */ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE): void { @@ -137,7 +139,7 @@ protected function ensureValidType($iterable, string $check = self::CHECK_VALUE) * @param iterable $keys A list of keys that can obtained in a single operation. * @param mixed $default Default value to return for keys that do not exist. * @return iterable A list of key value pairs. Cache keys that do not exist or are stale will have $default as value. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function getMultiple($keys, $default = null): iterable @@ -160,7 +162,7 @@ public function getMultiple($keys, $default = null): iterable * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException If $values is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $values is neither an array nor a Traversable, * or if any of the $values are not a legal value. */ public function setMultiple($values, $ttl = null): bool @@ -196,7 +198,7 @@ public function setMultiple($values, $ttl = null): bool * * @param iterable $keys A list of string-based keys to be deleted. * @return bool True if the items were successfully removed. False if there was an error. - * @throws \Cake\Cache\InvalidArgumentException If $keys is neither an array nor a Traversable, + * @throws \Cake\Cache\Exception\InvalidArgumentException If $keys is neither an array nor a Traversable, * or if any of the $keys are not a legal value. */ public function deleteMultiple($keys): bool @@ -223,7 +225,7 @@ public function deleteMultiple($keys): bool * * @param string $key The cache item key. * @return bool - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ public function has($key): bool { @@ -236,7 +238,7 @@ public function has($key): bool * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * @return mixed The value of the item from the cache, or $default in case of cache miss. - * @throws \Cake\Cache\InvalidArgumentException If the $key string is not a legal value. + * @throws \Cake\Cache\Exception\InvalidArgumentException If the $key string is not a legal value. */ abstract public function get($key, $default = null); @@ -249,7 +251,7 @@ abstract public function get($key, $default = null); * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * @return bool True on success and false on failure. - * @throws \Cake\Cache\InvalidArgumentException + * @throws \Cake\Cache\Exception\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ abstract public function set($key, $value, $ttl = null): bool; @@ -337,7 +339,7 @@ public function groups(): array * * @param string $key the key passed over * @return string Prefixed key with potentially unsafe characters replaced. - * @throws \Cake\Cache\InvalidArgumentException If key's value is invalid. + * @throws \Cake\Cache\Exception\InvalidArgumentException If key's value is invalid. */ protected function _key($key): string { diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php index 35252b98e..9e786787a 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php @@ -50,6 +50,7 @@ class FileEngine extends CacheEngine * handy for deleting a complete group from cache. * - `lock` Used by FileCache. Should files be locked before writing to them? * - `mask` The mask used for created files + * - `dirMask` The mask used for created folders * - `path` Path to where cachefiles should be saved. Defaults to system's temp dir. * - `prefix` Prepended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. @@ -63,6 +64,7 @@ class FileEngine extends CacheEngine 'groups' => [], 'lock' => true, 'mask' => 0664, + 'dirMask' => 0770, 'path' => null, 'prefix' => 'cake_', 'serialize' => true, @@ -371,7 +373,7 @@ protected function _setKey(string $key, bool $createKey = false): bool $dir = $this->_config['path'] . $groups; if (!is_dir($dir)) { - mkdir($dir, 0775, true); + mkdir($dir, $this->_config['dirMask'], true); } $path = new SplFileInfo($dir . $key); @@ -418,7 +420,7 @@ protected function _active(): bool $success = true; if (!is_dir($path)) { // phpcs:disable - $success = @mkdir($path, 0775, true); + $success = @mkdir($path, $this->_config['dirMask'], true); // phpcs:enable } diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php index b714f5056..f490b363e 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php @@ -17,7 +17,7 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use InvalidArgumentException; +use Cake\Cache\Exception\InvalidArgumentException; use Memcached; use RuntimeException; @@ -98,7 +98,7 @@ class MemcachedEngine extends CacheEngine * * @param array $config array of setting for the engine * @return bool True if the engine has been successfully initialized, false if not - * @throws \InvalidArgumentException When you try use authentication without + * @throws \Cake\Cache\Exception\InvalidArgumentException When you try use authentication without * Memcached compiled with SASL support */ public function init(array $config = []): bool @@ -199,7 +199,7 @@ public function init(array $config = []): bool * Settings the memcached instance * * @return void - * @throws \InvalidArgumentException When the Memcached extension is not built + * @throws \Cake\Cache\Exception\InvalidArgumentException When the Memcached extension is not built * with the desired serializer engine. */ protected function _setOptions(): void diff --git a/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php b/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php new file mode 100644 index 000000000..241ef6539 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Cache/Exception/CacheWriteException.php @@ -0,0 +1,27 @@ +> */ class Collection extends IteratorIterator implements CollectionInterface, Serializable { diff --git a/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php b/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php index 7e50cfced..1fcd3a1ab 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php +++ b/app/vendor/cakephp/cakephp/src/Collection/CollectionInterface.php @@ -24,6 +24,8 @@ * Describes the methods a Collection should implement. A collection is an immutable * list of elements exposing a number of traversing and extracting method for * generating other collections. + * + * @template-extends \Iterator */ interface CollectionInterface extends Iterator, JsonSerializable { diff --git a/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php b/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php index 010b06a63..7cee96969 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php +++ b/app/vendor/cakephp/cakephp/src/Collection/CollectionTrait.php @@ -591,14 +591,37 @@ public function combine($keyPath, $valuePath, $groupPath = null): CollectionInte $rowVal = $options['valuePath']; if (!$options['groupPath']) { - $mapReduce->emit($rowVal($value, $key), $rowKey($value, $key)); + $mapKey = $rowKey($value, $key); + if ($mapKey === null) { + throw new InvalidArgumentException( + 'Cannot index by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + + $mapReduce->emit($rowVal($value, $key), $mapKey); return null; } $key = $options['groupPath']($value, $key); + if ($key === null) { + throw new InvalidArgumentException( + 'Cannot group by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + + $mapKey = $rowKey($value, $key); + if ($mapKey === null) { + throw new InvalidArgumentException( + 'Cannot index by path that does not exist or contains a null value. ' . + 'Use a callback to return a default value for that path.' + ); + } + $mapReduce->emitIntermediate( - [$rowKey($value, $key) => $rowVal($value, $key)], + [$mapKey => $rowVal($value, $key)], $key ); }; diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php index 6e3048c7d..0ea3368fe 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/MapReduce.php @@ -25,6 +25,8 @@ * like an iterator for the original passed data after each result has been * processed, thus offering a transparent wrapper for results coming from any * source. + * + * @template-implements \IteratorAggregate */ class MapReduce implements IteratorAggregate { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php index c60c39b2f..831bc46fa 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NestIterator.php @@ -23,6 +23,8 @@ /** * A type of collection that is aware of nested items and exposes methods to * check or retrieve them + * + * @template-implements \RecursiveIterator */ class NestIterator extends Collection implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php index ed940c1c4..53f5ceb79 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/NoChildrenIterator.php @@ -23,6 +23,8 @@ * An iterator that can be used as an argument for other iterators that require * a RecursiveIterator but do not want children. This iterator will * always behave as having no nested items. + * + * @template-implements \RecursiveIterator */ class NoChildrenIterator extends Collection implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php index 49a28fe01..e8072db31 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreeIterator.php @@ -24,6 +24,8 @@ /** * A Recursive iterator used to flatten nested structures and also exposes * all Collection methods + * + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> */ class TreeIterator extends RecursiveIteratorIterator implements CollectionInterface { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php index d509d471a..0942b0f18 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/TreePrinter.php @@ -24,6 +24,8 @@ /** * Iterator for flattening elements in a tree structure while adding some * visual markers for their relative position in the tree + * + * @template-extends \RecursiveIteratorIterator<\RecursiveIterator> */ class TreePrinter extends RecursiveIteratorIterator implements CollectionInterface { diff --git a/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php b/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php index 017373ebc..db284c1aa 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Iterator/UnfoldIterator.php @@ -26,6 +26,8 @@ * * @internal * @see \Cake\Collection\Collection::unfold() + * @template-implements \RecursiveIterator + * @template-extends \IteratorIterator> */ class UnfoldIterator extends IteratorIterator implements RecursiveIterator { diff --git a/app/vendor/cakephp/cakephp/src/Collection/functions.php b/app/vendor/cakephp/cakephp/src/Collection/functions.php index 0440f10ff..b3bbfb9eb 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/functions.php +++ b/app/vendor/cakephp/cakephp/src/Collection/functions.php @@ -1,4 +1,5 @@ setDescription('Clear all data in a single cache group.'); + $parser->addArgument('group', [ + 'help' => 'The cache group to clear. For example, `cake cache clear_group mygroup` will clear ' . + 'all cache items belonging to group "mygroup".', + 'required' => true, + ]); + $parser->addArgument('config', [ + 'help' => 'Name of the configuration to use. Defaults to no value which clears all cache configurations.', + ]); + + return $parser; + } + + /** + * Clears the cache group + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return int|null The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): ?int + { + $group = (string)$args->getArgument('group'); + try { + $groupConfigs = Cache::groupConfigs($group); + } catch (InvalidArgumentException $e) { + $io->error(sprintf('Cache group "%s" not found', $group)); + + return static::CODE_ERROR; + } + + $config = $args->getArgument('config'); + if ($config !== null && Cache::getConfig($config) === null) { + $io->error(sprintf('Cache config "%s" not found', $config)); + + return static::CODE_ERROR; + } + + foreach ($groupConfigs[$group] as $groupConfig) { + if ($config !== null && $config !== $groupConfig) { + continue; + } + + if (!Cache::clearGroup($group, $groupConfig)) { + $io->error(sprintf( + 'Error encountered clearing group "%s". Was unable to clear entries for "%s".', + $group, + $groupConfig + )); + $this->abort(); + } else { + $io->success(sprintf('Group "%s" was cleared.', $group)); + } + } + + return static::CODE_SUCCESS; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php index 724783bcf..1b6a04252 100644 --- a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php @@ -133,7 +133,7 @@ protected function _getPaths(ConsoleIo $io): void /** @psalm-suppress UndefinedConstant */ $defaultPaths = array_merge( [APP], - App::path('templates'), + array_values(App::path('templates')), ['D'] // This is required to break the loop below ); $defaultPathIndex = 0; @@ -217,7 +217,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int . 'locales' . DIRECTORY_SEPARATOR; } else { $message = "What is the path you would like to output?\n[Q]uit"; - $localePaths = App::path('locales'); + $localePaths = array_values(App::path('locales')); if (!$localePaths) { $localePaths[] = ROOT . 'resources' . DIRECTORY_SEPARATOR . 'locales'; } diff --git a/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php b/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php index ff2806888..39bbf5b83 100644 --- a/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/I18nInitCommand.php @@ -56,7 +56,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int return static::CODE_ERROR; } - $paths = App::path('locales'); + $paths = array_values(App::path('locales')); if ($args->hasOption('plugin')) { $plugin = Inflector::camelize((string)$args->getOption('plugin')); $paths = [Plugin::path($plugin) . 'resources' . DIRECTORY_SEPARATOR . 'locales' . DIRECTORY_SEPARATOR]; @@ -66,7 +66,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $sourceFolder = rtrim($response, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $targetFolder = $sourceFolder . $language . DIRECTORY_SEPARATOR; if (!is_dir($targetFolder)) { - mkdir($targetFolder, 0775, true); + mkdir($targetFolder, 0770, true); } $count = 0; diff --git a/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php b/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php index 69f1203a0..8019638f9 100644 --- a/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/ServerCommand.php @@ -21,6 +21,7 @@ use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; +use function Cake\Core\env; /** * built-in Server command diff --git a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php index c927ccf80..b9b13e47a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php +++ b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php @@ -21,6 +21,7 @@ use Cake\Utility\Inflector; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\getTypeName; /** * Base class for console commands. @@ -238,7 +239,7 @@ protected function setOutputLevel(Arguments $args, ConsoleIo $io): void abstract public function execute(Arguments $args, ConsoleIo $io); /** - * Halt the the current process with a StopException. + * Halt the current process with a StopException. * * @param int $code The exit code to use. * @throws \Cake\Console\Exception\StopException diff --git a/app/vendor/cakephp/cakephp/src/Console/Command.php b/app/vendor/cakephp/cakephp/src/Console/Command.php index 9494b024a..5062c8ddc 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Command.php +++ b/app/vendor/cakephp/cakephp/src/Console/Command.php @@ -1,7 +1,9 @@ > */ class CommandCollection implements IteratorAggregate, Countable { @@ -127,7 +129,7 @@ public function has(string $name): bool * Get the target for a command. * * @param string $name The named shell. - * @return \Cake\Console\CommandInterface|\Cake\Console\Shell|string Either the command class or an instance. + * @return \Cake\Console\CommandInterface|\Cake\Console\Shell|class-string<\Cake\Console\CommandInterface> Either the command class or an instance. * @throws \InvalidArgumentException when unknown commands are fetched. * @psalm-return \Cake\Console\CommandInterface|\Cake\Console\Shell|class-string */ @@ -144,7 +146,7 @@ public function get(string $name) * Implementation of IteratorAggregate. * * @return \Traversable - * @psalm-return \Traversable + * @psalm-return \Traversable)> */ public function getIterator(): Traversable { diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php index cac0d22f5..27fcf22f8 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php @@ -1,7 +1,10 @@ tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -225,7 +225,7 @@ public function info($message, int $newlines = 1, int $level = self::NORMAL): ?i } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -243,7 +243,7 @@ public function comment($message, int $newlines = 1, int $level = self::NORMAL): } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -259,7 +259,7 @@ public function warning($message, int $newlines = 1): int } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -275,7 +275,7 @@ public function error($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php index b20775a1d..846f94fd1 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php @@ -691,10 +691,23 @@ public function parse(array $argv, ?ConsoleIo $io = null): array /** @psalm-suppress PossiblyNullReference */ return $this->_subcommands[$command]->parser()->parse($argv, $io); } + $params = $args = []; $this->_tokens = $argv; + + $afterDoubleDash = false; while (($token = array_shift($this->_tokens)) !== null) { $token = (string)$token; + if ($token === '--') { + $afterDoubleDash = true; + continue; + } + if ($afterDoubleDash) { + // only positional arguments after -- + $args = $this->_parseArg($token, $args); + continue; + } + if (isset($this->_subcommands[$token])) { continue; } diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php index c11101875..4c7ea902a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleOutput.php @@ -16,7 +16,9 @@ */ namespace Cake\Console; +use Cake\Console\Exception\ConsoleException; use InvalidArgumentException; +use function Cake\Core\env; /** * Object wrapper for outputting information from a shell application. @@ -160,11 +162,20 @@ class ConsoleOutput * Checks for a pretty console environment. Ansicon and ConEmu allows * pretty consoles on Windows, and is supported. * - * @param string $stream The identifier of the stream to write output to. + * @param string|resource $stream The identifier of the stream to write output to. + * @throws \Cake\Console\Exception\ConsoleException If the given stream is not a valid resource. */ - public function __construct(string $stream = 'php://stdout') + public function __construct($stream = 'php://stdout') { - $this->_output = fopen($stream, 'wb'); + if (is_string($stream)) { + $stream = fopen($stream, 'wb'); + } + + if (!is_resource($stream)) { + throw new ConsoleException('Invalid stream in constructor. It is not a valid resource.'); + } + + $this->_output = $stream; if ( ( diff --git a/app/vendor/cakephp/cakephp/src/Console/Shell.php b/app/vendor/cakephp/cakephp/src/Console/Shell.php index 636216766..46bdda200 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Shell.php +++ b/app/vendor/cakephp/cakephp/src/Console/Shell.php @@ -31,6 +31,7 @@ use ReflectionException; use ReflectionMethod; use RuntimeException; +use function Cake\Core\namespaceSplit; /** * Base class for command-line utilities for automating programmer chores. @@ -719,7 +720,7 @@ public function err($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -733,7 +734,7 @@ public function info($message, int $newlines = 1, int $level = Shell::NORMAL): ? } /** - * Convenience method for err() that wraps message between tag + * Convenience method for err() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append @@ -746,7 +747,7 @@ public function warn($message, int $newlines = 1): int } /** - * Convenience method for out() that wraps message between tag + * Convenience method for out() that wraps message between tag * * @param array|string $message A string or an array of strings to output * @param int $newlines Number of newlines to append diff --git a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php index 2075784b0..a8615a168 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php @@ -24,6 +24,7 @@ use Cake\Log\Log; use Cake\Shell\Task\CommandTask; use Cake\Utility\Inflector; +use function Cake\Core\pluginSplit; /** * Shell dispatcher handles dispatching CLI commands. diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php index f5f756fc7..b10d2cd98 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/ConsoleIntegrationTestTrait.php @@ -343,3 +343,10 @@ protected function commandStringToArgs(string $command): array return $argv; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\ConsoleIntegrationTestTrait', + 'Cake\TestSuite\ConsoleIntegrationTestTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php index 8ea9d2619..f9f87322d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsBase.php @@ -46,3 +46,10 @@ public function __construct(array $contents, string $output) $this->output = $output; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsBase', + 'Cake\TestSuite\Constraint\Console\ContentsBase' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php index 5dc3942e4..82747a782 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContain.php @@ -43,3 +43,10 @@ public function toString(): string return sprintf('is in %s,' . PHP_EOL . 'actual result:' . PHP_EOL, $this->output) . $this->contents; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsContain', + 'Cake\TestSuite\Constraint\Console\ContentsContain' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php index a1b9edd08..583abbfb5 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsContainRow.php @@ -59,3 +59,10 @@ public function failureDescription($other): string return '`' . $this->exporter()->shortenedExport($other) . '` ' . $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsContainRow', + 'Cake\TestSuite\Constraint\Console\ContentsContainRow' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php index 015d68bbc..6cae114e3 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsEmpty.php @@ -54,3 +54,10 @@ protected function failureDescription($other): string return $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsEmpty', + 'Cake\TestSuite\Constraint\Console\ContentsEmpty' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php index 47855c520..c8a666c13 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsNotContain.php @@ -43,3 +43,10 @@ public function toString(): string return sprintf('is not in %s', $this->output); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsNotContain', + 'Cake\TestSuite\Constraint\Console\ContentsNotContain' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php index e3a3fb6c7..a715b95d6 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ContentsRegExp.php @@ -52,3 +52,10 @@ public function failureDescription($other): string return '`' . $other . '` ' . $this->toString(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ContentsRegExp', + 'Cake\TestSuite\Constraint\Console\ContentsRegExp' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php index 4e7f01edb..da3f46a5d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/Constraint/ExitCode.php @@ -60,3 +60,10 @@ public function toString(): string return sprintf('matches exit code %s', $this->exitCode ?? 'null'); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\Constraint\ExitCode', + 'Cake\TestSuite\Constraint\Console\ExitCode' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php index 8cbb5542a..d1ec2c74d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyCommandRunner.php @@ -37,3 +37,10 @@ public function run(array $argv, ?ConsoleIo $io = null): int return $dispatcher->dispatch(); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\LegacyCommandRunner', + 'Cake\TestSuite\LegacyCommandRunner' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php index 59caba325..cc9fde4da 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/LegacyShellDispatcher.php @@ -18,6 +18,7 @@ use Cake\Console\ConsoleIo; use Cake\Console\Shell; use Cake\Console\ShellDispatcher; +use function Cake\Core\pluginSplit; /** * Allows injecting mock IO into shells @@ -62,3 +63,10 @@ protected function _createShell(string $className, string $shortName): Shell return $instance; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\LegacyShellDispatcher', + 'Cake\TestSuite\LegacyShellDispatcher' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php index a76d36f63..9b58c4659 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/MissingConsoleInputException.php @@ -35,5 +35,8 @@ public function setQuestion($question) } // phpcs:disable -class_alias(MissingConsoleInputException::class, 'Cake\TestSuite\Stub\MissingConsoleInputException'); +class_alias( + 'Cake\Console\TestSuite\MissingConsoleInputException', + 'Cake\TestSuite\Stub\MissingConsoleInputException' +); // phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php index 96a83198f..cd968194a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleInput.php @@ -86,3 +86,10 @@ public function dataAvailable($timeout = 0): bool return true; } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\StubConsoleInput', + 'Cake\TestSuite\Stub\ConsoleInput' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php index 280ea3e7d..46b234237 100644 --- a/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php +++ b/app/vendor/cakephp/cakephp/src/Console/TestSuite/StubConsoleOutput.php @@ -82,3 +82,10 @@ public function output(): string return implode("\n", $this->_out); } } + +// phpcs:disable +class_alias( + 'Cake\Console\TestSuite\StubConsoleOutput', + 'Cake\TestSuite\Stub\ConsoleOutput' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component.php b/app/vendor/cakephp/cakephp/src/Controller/Component.php index 1ebafbd59..9cdc87ad1 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component.php @@ -19,6 +19,7 @@ use Cake\Core\InstanceConfigTrait; use Cake\Event\EventListenerInterface; use Cake\Log\LogTrait; +use function Cake\Core\deprecationWarning; /** * Base class for an individual Component. Components provide reusable bits of diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php index d9b0a59e5..851117c75 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php @@ -31,6 +31,7 @@ use Cake\Http\ServerRequest; use Cake\Routing\Router; use Cake\Utility\Hash; +use function Cake\I18n\__d; /** * Authentication control component class. diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php index 947403dca..54a2fd99a 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/FormProtectionComponent.php @@ -67,6 +67,20 @@ class FormProtectionComponent extends Component 'validationFailureCallback' => null, ]; + /** + * Get Session id for FormProtector + * Must be the same as in FormHelper + * + * @return string + */ + protected function _getSessionId(): string + { + $session = $this->getController()->getRequest()->getSession(); + $session->start(); + + return $session->id(); + } + /** * Component startup. * @@ -86,12 +100,11 @@ public function startup(EventInterface $event): ?Response && $hasData && $this->_config['validate'] ) { - $session = $request->getSession(); - $session->start(); + $sessionId = $this->_getSessionId(); $url = Router::url($request->getRequestTarget()); $formProtector = new FormProtector($this->_config); - $isValid = $formProtector->validate($data, $url, $session->id()); + $isValid = $formProtector->validate($data, $url, $sessionId); if (!$isValid) { return $this->validationFailure($formProtector); diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php index 85e27729a..07dc6352e 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php @@ -24,6 +24,7 @@ use Cake\Http\Exception\NotFoundException; use InvalidArgumentException; use UnexpectedValueException; +use function Cake\Core\deprecationWarning; /** * This component is used to handle automatic model data pagination. The primary way to use this diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php index 1b84ba258..6938d0cb4 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/SecurityComponent.php @@ -209,7 +209,7 @@ protected function _secureRequired(Controller $controller): void ($requireSecure[0] === '*' || in_array($this->_action, $requireSecure, true) ) && - !$controller->getRequest()->is('ssl') + !$controller->getRequest()->is('https') ) { throw new SecurityException( 'Request is not SSL and the action is required to be secure' diff --git a/app/vendor/cakephp/cakephp/src/Controller/Controller.php b/app/vendor/cakephp/cakephp/src/Controller/Controller.php index 623214fd6..5d2831ff5 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Controller.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Controller.php @@ -44,6 +44,11 @@ use ReflectionMethod; use RuntimeException; use UnexpectedValueException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\namespaceSplit; +use function Cake\Core\pluginSplit; +use function Cake\Core\triggerWarning; /** * Application controller class for organization of business logic. @@ -91,6 +96,7 @@ * @property \Cake\Controller\Component\RequestHandlerComponent $RequestHandler * @property \Cake\Controller\Component\SecurityComponent $Security * @property \Cake\Controller\Component\AuthComponent $Auth + * @property \Cake\Controller\Component\CheckHttpCacheComponent $CheckHttpCache * @link https://book.cakephp.org/4/en/controllers.html */ #[\AllowDynamicProperties] @@ -170,6 +176,13 @@ class Controller implements EventListenerInterface, EventDispatcherInterface */ protected $middlewares = []; + /** + * View classes for content negotiation. + * + * @var array + */ + protected $viewClasses = []; + /** * Constructor. * @@ -320,7 +333,7 @@ public function __get(string $name) } if ($class === $name) { - return $this->loadModel(); + return $this->fetchModel(); } } @@ -684,10 +697,14 @@ public function redirect($url, int $status = 302): ?Response { $this->autoRender = false; - if ($status) { - $this->response = $this->response->withStatus($status); + if ($status < 300 || $status > 399) { + throw new InvalidArgumentException( + sprintf('Invalid status code `%s`. It should be within the range ' . + '`300` - `399` for redirect responses.', $status) + ); } + $this->response = $this->response->withStatus($status); $event = $this->dispatchEvent('Controller.beforeRedirect', [$url, $this->response]); if ($event->getResult() instanceof Response) { return $this->response = $event->getResult(); @@ -787,7 +804,25 @@ public function render(?string $template = null, ?string $layout = null): Respon */ public function viewClasses(): array { - return []; + return $this->viewClasses; + } + + /** + * Add View classes this controller can perform content negotiation with. + * + * Each view class must implement the `getContentType()` hook method + * to participate in negotiation. + * + * @param array $viewClasses View classes list. + * @return $this + * @see Cake\Http\ContentTypeNegotiation + * @since 4.5.0 + */ + public function addViewClasses(array $viewClasses) + { + $this->viewClasses = array_merge($this->viewClasses, $viewClasses); + + return $this; } /** diff --git a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php index 34b8c18a7..88e776c4b 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php +++ b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php @@ -32,6 +32,7 @@ use ReflectionClass; use ReflectionFunction; use ReflectionNamedType; +use function Cake\Core\deprecationWarning; /** * Factory method for building controllers for request. @@ -105,7 +106,7 @@ public function invoke($controller): ResponseInterface $middlewares = $controller->getMiddleware(); if ($middlewares) { - $middlewareQueue = new MiddlewareQueue($middlewares); + $middlewareQueue = new MiddlewareQueue($middlewares, $this->container); $runner = new Runner(); return $runner->run($middlewareQueue, $controller->getRequest(), $this); @@ -159,17 +160,6 @@ protected function getActionArgs(Closure $action, array $passedParams): array $function = new ReflectionFunction($action); foreach ($function->getParameters() as $parameter) { $type = $parameter->getType(); - if ($type && !$type instanceof ReflectionNamedType) { - // Only single types are supported - throw new InvalidParameterException([ - 'template' => 'unsupported_type', - 'parameter' => $parameter->getName(), - 'controller' => $this->controller->getName(), - 'action' => $this->controller->getRequest()->getParam('action'), - 'prefix' => $this->controller->getRequest()->getParam('prefix'), - 'plugin' => $this->controller->getRequest()->getParam('plugin'), - ]); - } // Check for dependency injection for classes if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) { @@ -354,3 +344,10 @@ protected function missingController(ServerRequest $request) ]); } } + +// phpcs:disable +class_alias( + 'Cake\Controller\ControllerFactory', + 'Cake\Http\ControllerFactory' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/BasePlugin.php b/app/vendor/cakephp/cakephp/src/Core/BasePlugin.php index 08e5905d8..a748be37c 100644 --- a/app/vendor/cakephp/cakephp/src/Core/BasePlugin.php +++ b/app/vendor/cakephp/cakephp/src/Core/BasePlugin.php @@ -210,7 +210,7 @@ public function getTemplatePath(): string public function enable(string $hook) { $this->checkHook($hook); - $this->{"{$hook}Enabled}"} = true; + $this->{"{$hook}Enabled"} = true; return $this; } diff --git a/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php b/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php index 34931c895..79bcdea49 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php +++ b/app/vendor/cakephp/cakephp/src/Core/Configure/FileConfigTrait.php @@ -18,6 +18,7 @@ use Cake\Core\Exception\CakeException; use Cake\Core\Plugin; +use function Cake\Core\pluginSplit; /** * Trait providing utility methods for file based config engines. diff --git a/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php b/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php index 82ef43738..43f885a81 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php +++ b/app/vendor/cakephp/cakephp/src/Core/Exception/CakeException.php @@ -16,6 +16,7 @@ use RuntimeException; use Throwable; +use function Cake\Core\deprecationWarning; /** * Base class that all CakePHP Exceptions extend. @@ -115,5 +116,8 @@ public function responseHeader($header = null, $value = null): ?array } // phpcs:disable -class_exists('Cake\Core\Exception\Exception'); +class_alias( + 'Cake\Core\Exception\CakeException', + 'Cake\Core\Exception\Exception' +); // phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php b/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php index fb5d49fb2..bd93c509e 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php +++ b/app/vendor/cakephp/cakephp/src/Core/Exception/Exception.php @@ -1,6 +1,8 @@ */ abstract class ObjectRegistry implements Countable, IteratorAggregate { @@ -336,7 +337,6 @@ public function reset() * @param object $object instance to store in the registry * @return $this * @psalm-param TObject $object - * @psalm-suppress MoreSpecificReturnType */ public function set(string $name, object $object) { @@ -351,7 +351,6 @@ public function set(string $name, object $object) } $this->_loaded[$objName] = $object; - /** @psalm-suppress LessSpecificReturnStatement */ return $this; } @@ -362,7 +361,6 @@ public function set(string $name, object $object) * * @param string $name The name of the object to remove from the registry. * @return $this - * @psalm-suppress MoreSpecificReturnType */ public function unload(string $name) { @@ -377,7 +375,6 @@ public function unload(string $name) } unset($this->_loaded[$name]); - /** @psalm-suppress LessSpecificReturnStatement */ return $this; } diff --git a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php index 1862d6e43..a9fc4a191 100644 --- a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php +++ b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php @@ -15,6 +15,7 @@ */ namespace Cake\Core; +use Cake\Core\Exception\CakeException; use Cake\Core\Exception\MissingPluginException; use Countable; use Generator; @@ -34,6 +35,8 @@ * * While its implementation supported nested iteration it does not * support using `continue` or `break` inside loops. + * + * @template-implements \Iterator */ class PluginCollection implements Iterator, Countable { @@ -232,6 +235,10 @@ public function get(string $name): PluginInterface */ public function create(string $name, array $config = []): PluginInterface { + if ($name === '') { + throw new CakeException('Cannot create a plugin with empty name'); + } + if (strpos($name, '\\') !== false) { /** @var \Cake\Core\PluginInterface */ return new $name($config); diff --git a/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php b/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php index 909ade79f..9c6ae1e05 100644 --- a/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php +++ b/app/vendor/cakephp/cakephp/src/Core/TestSuite/ContainerStubTrait.php @@ -172,3 +172,10 @@ public function cleanupContainer(): void $this->containerServices = []; } } + +// phpcs:disable +class_alias( + 'Cake\Core\TestSuite\ContainerStubTrait', + 'Cake\TestSuite\ContainerStubTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Core/functions.php b/app/vendor/cakephp/cakephp/src/Core/functions.php index f938d8817..af2d2b6c3 100644 --- a/app/vendor/cakephp/cakephp/src/Core/functions.php +++ b/app/vendor/cakephp/cakephp/src/Core/functions.php @@ -11,20 +11,13 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @link https://cakephp.org CakePHP(tm) Project - * @since 3.0.0 + * @since 4.5.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +// phpcs:disable PSR1.Files.SideEffects +namespace Cake\Core; -use Cake\Core\Configure; - -if (!defined('DS')) { - /** - * Defines DS as short form of DIRECTORY_SEPARATOR. - */ - define('DS', DIRECTORY_SEPARATOR); -} - -if (!function_exists('h')) { +if (!function_exists('Cake\Core\h')) { /** * Convenience method for htmlspecialchars. * @@ -66,10 +59,9 @@ function h($text, bool $double = true, ?string $charset = null) return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset ?: $defaultCharset, $double); } - } -if (!function_exists('pluginSplit')) { +if (!function_exists('Cake\Core\pluginSplit')) { /** * Splits a dot syntax plugin name into its plugin and class name. * If $name does not have a dot, then index 0 will be null. @@ -94,16 +86,15 @@ function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = nu $parts[0] .= '.'; } - /** @psalm-var array{string, string}*/ + /** @psalm-var array{string, string} */ return $parts; } return [$plugin, $name]; } - } -if (!function_exists('namespaceSplit')) { +if (!function_exists('Cake\Core\namespaceSplit')) { /** * Split the namespace from the classname. * @@ -121,10 +112,9 @@ function namespaceSplit(string $class): array return [substr($class, 0, $pos), substr($class, $pos + 1)]; } - } -if (!function_exists('pr')) { +if (!function_exists('Cake\Core\pr')) { /** * print_r() convenience function. * @@ -149,10 +139,9 @@ function pr($var) return $var; } - } -if (!function_exists('pj')) { +if (!function_exists('Cake\Core\pj')) { /** * JSON pretty print convenience function. * @@ -177,10 +166,9 @@ function pj($var) return $var; } - } -if (!function_exists('env')) { +if (!function_exists('Cake\Core\env')) { /** * Gets an environment variable from available sources, and provides emulation * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on @@ -242,10 +230,9 @@ function env(string $key, $default = null) return $default; } - } -if (!function_exists('triggerWarning')) { +if (!function_exists('Cake\Core\triggerWarning')) { /** * Triggers an E_USER_WARNING. * @@ -269,7 +256,7 @@ function triggerWarning(string $message): void } } -if (!function_exists('deprecationWarning')) { +if (!function_exists('Cake\Core\deprecationWarning')) { /** * Helper method for outputting deprecation warnings * @@ -294,7 +281,11 @@ function deprecationWarning(string $message, int $stackFrame = 1): void if (defined('ROOT')) { $root = ROOT; } - $relative = str_replace(DIRECTORY_SEPARATOR, '/', substr($frame['file'], strlen($root) + 1)); + $relative = str_replace( + DIRECTORY_SEPARATOR, + '/', + substr($frame['file'], strlen($root) + 1) + ); $patterns = (array)Configure::read('Error.ignoredDeprecationPaths'); foreach ($patterns as $pattern) { $pattern = str_replace(DIRECTORY_SEPARATOR, '/', $pattern); @@ -304,8 +295,7 @@ function deprecationWarning(string $message, int $stackFrame = 1): void } $message = sprintf( - "%s\n%s, line: %s\n" . - 'You can disable all deprecation warnings by setting `Error.errorLevel` to ' . + "%s\n%s, line: %s\n" . 'You can disable all deprecation warnings by setting `Error.errorLevel` to ' . '`E_ALL & ~E_USER_DEPRECATED`. Adding `%s` to `Error.ignoredDeprecationPaths` ' . 'in your `config/app.php` config will mute deprecations from that file only.', $message, @@ -329,7 +319,7 @@ function deprecationWarning(string $message, int $stackFrame = 1): void } } -if (!function_exists('getTypeName')) { +if (!function_exists('Cake\Core\getTypeName')) { /** * Returns the objects class or var type of it's not an object * @@ -341,3 +331,10 @@ function getTypeName($var): string return is_object($var) ? get_class($var) : gettype($var); } } + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; +} diff --git a/app/vendor/cakephp/cakephp/src/Core/functions_global.php b/app/vendor/cakephp/cakephp/src/Core/functions_global.php new file mode 100644 index 000000000..bb2a71478 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Core/functions_global.php @@ -0,0 +1,190 @@ + plugin name, 1 => class name. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pluginSplit + * @psalm-return array{string|null, string} + */ + function pluginSplit(string $name, bool $dotAppend = false, ?string $plugin = null): array + { + return cakePluginSplit($name, $dotAppend, $plugin); + } +} + +if (!function_exists('namespaceSplit')) { + /** + * Split the namespace from the classname. + * + * Commonly used like `list($namespace, $className) = namespaceSplit($class);`. + * + * @param string $class The full class name, ie `Cake\Core\App`. + * @return array Array with 2 indexes. 0 => namespace, 1 => classname. + */ + function namespaceSplit(string $class): array + { + return cakeNamespaceSplit($class); + } +} + +if (!function_exists('pr')) { + /** + * print_r() convenience function. + * + * In terminals this will act similar to using print_r() directly, when not run on CLI + * print_r() will also wrap `
` tags around the output of given variable. Similar to debug().
+     *
+     * This function returns the same variable that was passed.
+     *
+     * @param mixed $var Variable to print out.
+     * @return mixed the same $var that was passed to this function
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pr
+     * @see debug()
+     */
+    function pr($var)
+    {
+        return cakePr($var);
+    }
+}
+
+if (!function_exists('pj')) {
+    /**
+     * JSON pretty print convenience function.
+     *
+     * In terminals this will act similar to using json_encode() with JSON_PRETTY_PRINT directly, when not run on CLI
+     * will also wrap `
` tags around the output of given variable. Similar to pr().
+     *
+     * This function returns the same variable that was passed.
+     *
+     * @param mixed $var Variable to print out.
+     * @return mixed the same $var that was passed to this function
+     * @see pr()
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#pj
+     */
+    function pj($var)
+    {
+        return cakePj($var);
+    }
+}
+
+if (!function_exists('env')) {
+    /**
+     * Gets an environment variable from available sources, and provides emulation
+     * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on
+     * IIS, or SCRIPT_NAME in CGI mode). Also exposes some additional custom
+     * environment information.
+     *
+     * @param string $key Environment variable name.
+     * @param string|bool|null $default Specify a default value in case the environment variable is not defined.
+     * @return string|bool|null Environment variable setting.
+     * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#env
+     */
+    function env(string $key, $default = null)
+    {
+        return cakeEnv($key, $default);
+    }
+}
+
+if (!function_exists('triggerWarning')) {
+    /**
+     * Triggers an E_USER_WARNING.
+     *
+     * @param string $message The warning message.
+     * @return void
+     */
+    function triggerWarning(string $message): void
+    {
+        cakeTriggerWarning($message);
+    }
+}
+
+if (!function_exists('deprecationWarning')) {
+    /**
+     * Helper method for outputting deprecation warnings
+     *
+     * @param string $message The message to output as a deprecation warning.
+     * @param int $stackFrame The stack frame to include in the error. Defaults to 1
+     *   as that should point to application/plugin code.
+     * @return void
+     */
+    function deprecationWarning(string $message, int $stackFrame = 1): void
+    {
+        cakeDeprecationWarning($message, $stackFrame + 1);
+    }
+}
+
+if (!function_exists('getTypeName')) {
+    /**
+     * Returns the objects class or var type of it's not an object
+     *
+     * @param mixed $var Variable to check
+     * @return string Returns the class name or variable type
+     */
+    function getTypeName($var): string
+    {
+        return cakeGetTypeName($var);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Connection.php b/app/vendor/cakephp/cakephp/src/Database/Connection.php
index 92a54ae8d..83777d723 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Connection.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Connection.php
@@ -26,6 +26,10 @@
 use Cake\Database\Log\LoggedQuery;
 use Cake\Database\Log\LoggingStatement;
 use Cake\Database\Log\QueryLogger;
+use Cake\Database\Query\DeleteQuery;
+use Cake\Database\Query\InsertQuery;
+use Cake\Database\Query\SelectQuery;
+use Cake\Database\Query\UpdateQuery;
 use Cake\Database\Retry\ReconnectStrategy;
 use Cake\Database\Schema\CachedCollection;
 use Cake\Database\Schema\Collection as SchemaCollection;
@@ -37,6 +41,7 @@
 use Psr\SimpleCache\CacheInterface;
 use RuntimeException;
 use Throwable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Represents a connection with a database server.
@@ -53,12 +58,14 @@ class Connection implements ConnectionInterface
     protected $_config;
 
     /**
-     * Driver object, responsible for creating the real connection
-     * and provide specific SQL dialect.
-     *
      * @var \Cake\Database\DriverInterface
      */
-    protected $_driver;
+    protected DriverInterface $readDriver;
+
+    /**
+     * @var \Cake\Database\DriverInterface
+     */
+    protected DriverInterface $writeDriver;
 
     /**
      * Contains how many nested transactions have been started.
@@ -135,19 +142,61 @@ class Connection implements ConnectionInterface
     public function __construct(array $config)
     {
         $this->_config = $config;
+        [self::ROLE_READ => $this->readDriver, self::ROLE_WRITE => $this->writeDriver] = $this->createDrivers($config);
+
+        if (!empty($config['log'])) {
+            $this->enableQueryLogging((bool)$config['log']);
+        }
+    }
 
-        $driverConfig = array_diff_key($config, array_flip([
+    /**
+     * Creates read and write drivers.
+     *
+     * @param array $config Connection config
+     * @return array
+     * @psalm-return array{read: \Cake\Database\DriverInterface, write: \Cake\Database\DriverInterface}
+     */
+    protected function createDrivers(array $config): array
+    {
+        $driver = $config['driver'] ?? '';
+        if (!is_string($driver)) {
+            /** @var \Cake\Database\DriverInterface $driver */
+            if (!$driver->enabled()) {
+                throw new MissingExtensionException(['driver' => get_class($driver), 'name' => $this->configName()]);
+            }
+
+            // Legacy support for setting instance instead of driver class
+            return [self::ROLE_READ => $driver, self::ROLE_WRITE => $driver];
+        }
+
+        /** @var class-string<\Cake\Database\DriverInterface>|null $driverClass */
+        $driverClass = App::className($driver, 'Database/Driver');
+        if ($driverClass === null) {
+            throw new MissingDriverException(['driver' => $driver, 'connection' => $this->configName()]);
+        }
+
+        $sharedConfig = array_diff_key($config, array_flip([
             'name',
             'driver',
             'log',
             'cacheMetaData',
             'cacheKeyPrefix',
         ]));
-        $this->_driver = $this->createDriver($config['driver'] ?? '', $driverConfig);
 
-        if (!empty($config['log'])) {
-            $this->enableQueryLogging((bool)$config['log']);
+        $writeConfig = $config['write'] ?? [] + $sharedConfig;
+        $readConfig = $config['read'] ?? [] + $sharedConfig;
+        if ($readConfig == $writeConfig) {
+            $readDriver = $writeDriver = new $driverClass(['_role' => self::ROLE_WRITE] + $writeConfig);
+        } else {
+            $readDriver = new $driverClass(['_role' => self::ROLE_READ] + $readConfig);
+            $writeDriver = new $driverClass(['_role' => self::ROLE_WRITE] + $writeConfig);
         }
+
+        if (!$writeDriver->enabled()) {
+            throw new MissingExtensionException(['driver' => get_class($writeDriver), 'name' => $this->configName()]);
+        }
+
+        return [self::ROLE_READ => $readDriver, self::ROLE_WRITE => $writeDriver];
     }
 
     /**
@@ -178,6 +227,16 @@ public function configName(): string
         return $this->_config['name'] ?? '';
     }
 
+    /**
+     * Returns the connection role: read or write.
+     *
+     * @return string
+     */
+    public function role(): string
+    {
+        return preg_match('/:read$/', $this->configName()) === 1 ? static::ROLE_READ : static::ROLE_WRITE;
+    }
+
     /**
      * Sets the driver instance. If a string is passed it will be treated
      * as a class name and will be instantiated.
@@ -193,7 +252,8 @@ public function setDriver($driver, $config = [])
     {
         deprecationWarning('Setting the driver is deprecated. Use the connection config instead.');
 
-        $this->_driver = $this->createDriver($driver, $config);
+        $driver = $this->createDriver($driver, $config);
+        $this->readDriver = $this->writeDriver = $driver;
 
         return $this;
     }
@@ -216,7 +276,7 @@ protected function createDriver($name, array $config): DriverInterface
             if ($className === null) {
                 throw new MissingDriverException(['driver' => $driver, 'connection' => $this->configName()]);
             }
-            $driver = new $className($config);
+            $driver = new $className(['_role' => self::ROLE_WRITE] + $config);
         }
 
         if (!$driver->enabled()) {
@@ -240,11 +300,14 @@ public function getDisconnectRetry(): CommandRetry
     /**
      * Gets the driver instance.
      *
+     * @param string $role Connection role ('read' or 'write')
      * @return \Cake\Database\DriverInterface
      */
-    public function getDriver(): DriverInterface
+    public function getDriver(string $role = self::ROLE_WRITE): DriverInterface
     {
-        return $this->_driver;
+        assert($role === self::ROLE_READ || $role === self::ROLE_WRITE);
+
+        return $role === self::ROLE_READ ? $this->readDriver : $this->writeDriver;
     }
 
     /**
@@ -252,43 +315,62 @@ public function getDriver(): DriverInterface
      *
      * @throws \Cake\Database\Exception\MissingConnectionException If database connection could not be established.
      * @return bool true, if the connection was already established or the attempt was successful.
+     * @deprecated 4.5.0 Use getDriver()->connect() instead.
      */
     public function connect(): bool
     {
-        try {
-            return $this->_driver->connect();
-        } catch (MissingConnectionException $e) {
-            throw $e;
-        } catch (Throwable $e) {
-            throw new MissingConnectionException(
-                [
-                    'driver' => App::shortName(get_class($this->_driver), 'Database/Driver'),
-                    'reason' => $e->getMessage(),
-                ],
-                null,
-                $e
-            );
+        deprecationWarning(
+            'If you cannot use automatic connection management, use $connection->getDriver()->connect() instead.'
+        );
+
+        $connected = true;
+        foreach ([self::ROLE_READ, self::ROLE_WRITE] as $role) {
+            try {
+                $connected = $connected && $this->getDriver($role)->connect();
+            } catch (MissingConnectionException $e) {
+                throw $e;
+            } catch (Throwable $e) {
+                throw new MissingConnectionException(
+                    [
+                        'driver' => App::shortName(get_class($this->getDriver($role)), 'Database/Driver'),
+                        'reason' => $e->getMessage(),
+                    ],
+                    null,
+                    $e
+                );
+            }
         }
+
+        return $connected;
     }
 
     /**
      * Disconnects from database server.
      *
      * @return void
+     * @deprecated 4.5.0 Use getDriver()->disconnect() instead.
      */
     public function disconnect(): void
     {
-        $this->_driver->disconnect();
+        deprecationWarning(
+            'If you cannot use automatic connection management, use $connection->getDriver()->disconnect() instead.'
+        );
+
+        $this->getDriver(self::ROLE_READ)->disconnect();
+        $this->getDriver(self::ROLE_WRITE)->disconnect();
     }
 
     /**
      * Returns whether connection to database server was already established.
      *
      * @return bool
+     * @deprecated 4.5.0 Use getDriver()->isConnected() instead.
      */
     public function isConnected(): bool
     {
-        return $this->_driver->isConnected();
+        deprecationWarning('Use $connection->getDriver()->isConnected() instead.');
+
+        return $this->getDriver(self::ROLE_READ)->isConnected() && $this->getDriver(self::ROLE_WRITE)->isConnected();
     }
 
     /**
@@ -296,11 +378,14 @@ public function isConnected(): bool
      *
      * @param \Cake\Database\Query|string $query The SQL to convert into a prepared statement.
      * @return \Cake\Database\StatementInterface
+     * @deprecated 4.5.0 Use getDriver()->prepare() instead.
      */
     public function prepare($query): StatementInterface
     {
-        return $this->getDisconnectRetry()->run(function () use ($query) {
-            $statement = $this->_driver->prepare($query);
+        $role = $query instanceof Query ? $query->getConnectionRole() : self::ROLE_WRITE;
+
+        return $this->getDisconnectRetry()->run(function () use ($query, $role) {
+            $statement = $this->getDriver($role)->prepare($query);
 
             if ($this->_logQueries) {
                 $statement = $this->_newLogger($statement);
@@ -339,10 +424,13 @@ public function execute(string $sql, array $params = [], array $types = []): Sta
      * @param \Cake\Database\Query $query The query to be compiled
      * @param \Cake\Database\ValueBinder $binder Value binder
      * @return string
+     * @deprecated 4.5.0 Use getDriver()->compileQuery() instead.
      */
     public function compileQuery(Query $query, ValueBinder $binder): string
     {
-        return $this->getDriver()->compileQuery($query, $binder)[1];
+        deprecationWarning('Use getDriver()->compileQuery() instead.');
+
+        return $this->getDriver($query->getConnectionRole())->compileQuery($query, $binder)[1];
     }
 
     /**
@@ -363,14 +451,42 @@ public function run(Query $query): StatementInterface
         });
     }
 
+    /**
+     * Create a new SelectQuery instance for this connection.
+     *
+     * @param \Cake\Database\ExpressionInterface|callable|array|string $fields fields to be added to the list.
+     * @param array|string $table The table or list of tables to query.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\SelectQuery
+     */
+    public function selectQuery(
+        $fields = [],
+        $table = [],
+        array $types = []
+    ): SelectQuery {
+        $query = new SelectQuery($this);
+        if ($table) {
+            $query->from($table);
+        }
+        if ($fields) {
+            $query->select($fields, false);
+        }
+        $query->setDefaultTypes($types);
+
+        return $query;
+    }
+
     /**
      * Executes a SQL statement and returns the Statement object as result.
      *
      * @param string $sql The SQL query to execute.
      * @return \Cake\Database\StatementInterface
+     * @deprecated 4.5.0 Use either `selectQuery`, `insertQuery`, `deleteQuery`, `updateQuery` instead.
      */
     public function query(string $sql): StatementInterface
     {
+        deprecationWarning('Use either `selectQuery`, `insertQuery`, `deleteQuery`, `updateQuery` instead.');
+
         return $this->getDisconnectRetry()->run(function () use ($sql) {
             $statement = $this->prepare($sql);
             $statement->execute();
@@ -383,9 +499,17 @@ public function query(string $sql): StatementInterface
      * Create a new Query instance for this connection.
      *
      * @return \Cake\Database\Query
+     * @deprecated 4.5.0 Use `insertQuery()`, `deleteQuery()`, `selectQuery()` or `updateQuery()` instead.
      */
     public function newQuery(): Query
     {
+        deprecationWarning(
+            'As of 4.5.0, using newQuery() is deprecated. Instead, use `insertQuery()`, ' .
+            '`deleteQuery()`, `selectQuery()` or `updateQuery()`. The query objects ' .
+            'returned by these methods will emit deprecations that will become fatal errors in 5.0.' .
+            'See https://book.cakephp.org/4/en/appendices/4-5-migration-guide.html for more information.'
+        );
+
         return new Query($this);
     }
 
@@ -435,13 +559,31 @@ public function getSchemaCollection(): SchemaCollectionInterface
     public function insert(string $table, array $values, array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $values, $types) {
+            return $this->insertQuery($table, $values, $types)->execute();
+        });
+    }
+
+    /**
+     * Create a new InsertQuery instance for this connection.
+     *
+     * @param string|null $table The table to insert rows into.
+     * @param array $values Associative array of column => value to be inserted.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\InsertQuery
+     */
+    public function insertQuery(?string $table = null, array $values = [], array $types = []): InsertQuery
+    {
+        $query = new InsertQuery($this);
+        if ($table) {
+            $query->into($table);
+        }
+        if ($values) {
             $columns = array_keys($values);
+            $query->insert($columns, $types)
+                ->values($values);
+        }
 
-            return $this->newQuery()->insert($columns, $types)
-                ->into($table)
-                ->values($values)
-                ->execute();
-        });
+        return $query;
     }
 
     /**
@@ -456,13 +598,39 @@ public function insert(string $table, array $values, array $types = []): Stateme
     public function update(string $table, array $values, array $conditions = [], array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $values, $conditions, $types) {
-            return $this->newQuery()->update($table)
-                ->set($values, $types)
-                ->where($conditions, $types)
-                ->execute();
+            return $this->updateQuery($table, $values, $conditions, $types)->execute();
         });
     }
 
+    /**
+     * Create a new UpdateQuery instance for this connection.
+     *
+     * @param \Cake\Database\ExpressionInterface|string|null $table The table to update rows of.
+     * @param array $values Values to be updated.
+     * @param array $conditions Conditions to be set for the update statement.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\UpdateQuery
+     */
+    public function updateQuery(
+        $table = null,
+        array $values = [],
+        array $conditions = [],
+        array $types = []
+    ): UpdateQuery {
+        $query = new UpdateQuery($this);
+        if ($table) {
+            $query->update($table);
+        }
+        if ($values) {
+            $query->set($values, $types);
+        }
+        if ($conditions) {
+            $query->where($conditions, $types);
+        }
+
+        return $query;
+    }
+
     /**
      * Executes a DELETE statement on the specified table.
      *
@@ -474,12 +642,31 @@ public function update(string $table, array $values, array $conditions = [], arr
     public function delete(string $table, array $conditions = [], array $types = []): StatementInterface
     {
         return $this->getDisconnectRetry()->run(function () use ($table, $conditions, $types) {
-            return $this->newQuery()->delete($table)
-                ->where($conditions, $types)
-                ->execute();
+            return $this->deleteQuery($table, $conditions, $types)->execute();
         });
     }
 
+    /**
+     * Create a new DeleteQuery instance for this connection.
+     *
+     * @param string|null $table The table to delete rows from.
+     * @param array $conditions Conditions to be set for the delete statement.
+     * @param array $types Associative array containing the types to be used for casting.
+     * @return \Cake\Database\Query\DeleteQuery
+     */
+    public function deleteQuery(?string $table = null, array $conditions = [], array $types = []): DeleteQuery
+    {
+        $query = new DeleteQuery($this);
+        if ($table) {
+            $query->from($table);
+        }
+        if ($conditions) {
+            $query->where($conditions, $types);
+        }
+
+        return $query;
+    }
+
     /**
      * Starts a new transaction.
      *
@@ -493,7 +680,7 @@ public function begin(): void
             }
 
             $this->getDisconnectRetry()->run(function (): void {
-                $this->_driver->beginTransaction();
+                $this->getDriver()->beginTransaction();
             });
 
             $this->_transactionLevel = 0;
@@ -534,7 +721,7 @@ public function commit(): bool
                 $this->log('COMMIT');
             }
 
-            return $this->_driver->commitTransaction();
+            return $this->getDriver()->commitTransaction();
         }
         if ($this->isSavePointsEnabled()) {
             $this->releaseSavePoint((string)$this->_transactionLevel);
@@ -569,7 +756,7 @@ public function rollback(?bool $toBeginning = null): bool
             if ($this->_logQueries) {
                 $this->log('ROLLBACK');
             }
-            $this->_driver->rollbackTransaction();
+            $this->getDriver()->rollbackTransaction();
 
             return true;
         }
@@ -598,7 +785,7 @@ public function enableSavePoints(bool $enable = true)
         if ($enable === false) {
             $this->_useSavePoints = false;
         } else {
-            $this->_useSavePoints = $this->_driver->supports(DriverInterface::FEATURE_SAVEPOINT);
+            $this->_useSavePoints = $this->getDriver()->supports(DriverInterface::FEATURE_SAVEPOINT);
         }
 
         return $this;
@@ -634,7 +821,7 @@ public function isSavePointsEnabled(): bool
      */
     public function createSavePoint($name): void
     {
-        $this->execute($this->_driver->savePointSQL($name))->closeCursor();
+        $this->execute($this->getDriver()->savePointSQL($name))->closeCursor();
     }
 
     /**
@@ -645,7 +832,7 @@ public function createSavePoint($name): void
      */
     public function releaseSavePoint($name): void
     {
-        $sql = $this->_driver->releaseSavePointSQL($name);
+        $sql = $this->getDriver()->releaseSavePointSQL($name);
         if ($sql) {
             $this->execute($sql)->closeCursor();
         }
@@ -659,7 +846,7 @@ public function releaseSavePoint($name): void
      */
     public function rollbackSavepoint($name): void
     {
-        $this->execute($this->_driver->rollbackSavePointSQL($name))->closeCursor();
+        $this->execute($this->getDriver()->rollbackSavePointSQL($name))->closeCursor();
     }
 
     /**
@@ -670,7 +857,7 @@ public function rollbackSavepoint($name): void
     public function disableForeignKeys(): void
     {
         $this->getDisconnectRetry()->run(function (): void {
-            $this->execute($this->_driver->disableForeignKeySQL())->closeCursor();
+            $this->execute($this->getDriver()->disableForeignKeySQL())->closeCursor();
         });
     }
 
@@ -682,7 +869,7 @@ public function disableForeignKeys(): void
     public function enableForeignKeys(): void
     {
         $this->getDisconnectRetry()->run(function (): void {
-            $this->execute($this->_driver->enableForeignKeySQL())->closeCursor();
+            $this->execute($this->getDriver()->enableForeignKeySQL())->closeCursor();
         });
     }
 
@@ -695,7 +882,7 @@ public function enableForeignKeys(): void
      */
     public function supportsDynamicConstraints(): bool
     {
-        return $this->_driver->supportsDynamicConstraints();
+        return $this->getDriver()->supportsDynamicConstraints();
     }
 
     /**
@@ -774,12 +961,14 @@ public function inTransaction(): bool
      * @param mixed $value The value to quote.
      * @param \Cake\Database\TypeInterface|string|int $type Type to be used for determining kind of quoting to perform
      * @return string Quoted value
+     * @deprecated 4.5.0 Use getDriver()->quote() instead.
      */
     public function quote($value, $type = 'string'): string
     {
+        deprecationWarning('Use getDriver()->quote() instead.');
         [$value, $type] = $this->cast($value, $type);
 
-        return $this->_driver->quote($value, $type);
+        return $this->getDriver()->quote($value, $type);
     }
 
     /**
@@ -788,10 +977,13 @@ public function quote($value, $type = 'string'): string
      * This is not required to use `quoteIdentifier()`.
      *
      * @return bool
+     * @deprecated 4.5.0 Use getDriver()->supportsQuoting() instead.
      */
     public function supportsQuoting(): bool
     {
-        return $this->_driver->supports(DriverInterface::FEATURE_QUOTE);
+        deprecationWarning('Use getDriver()->supportsQuoting() instead.');
+
+        return $this->getDriver()->supports(DriverInterface::FEATURE_QUOTE);
     }
 
     /**
@@ -802,10 +994,13 @@ public function supportsQuoting(): bool
      *
      * @param string $identifier The identifier to quote.
      * @return string
+     * @deprecated 4.5.0 Use getDriver()->quoteIdentifier() instead.
      */
     public function quoteIdentifier(string $identifier): string
     {
-        return $this->_driver->quoteIdentifier($identifier);
+        deprecationWarning('Use getDriver()->quoteIdentifier() instead.');
+
+        return $this->getDriver()->quoteIdentifier($identifier);
     }
 
     /**
@@ -865,6 +1060,7 @@ public function getCacher(): CacheInterface
      *
      * @param bool $enable Enable/disable query logging
      * @return $this
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function enableQueryLogging(bool $enable = true)
     {
@@ -877,6 +1073,7 @@ public function enableQueryLogging(bool $enable = true)
      * Disable query logging
      *
      * @return $this
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function disableQueryLogging()
     {
@@ -889,6 +1086,7 @@ public function disableQueryLogging()
      * Check if query logging is enabled.
      *
      * @return bool
+     * @deprecated 4.5.0 Connection logging is moving to the driver in 5.x
      */
     public function isQueryLoggingEnabled(): bool
     {
@@ -952,7 +1150,7 @@ public function log(string $sql): void
      */
     protected function _newLogger(StatementInterface $statement): LoggingStatement
     {
-        $log = new LoggingStatement($statement, $this->_driver);
+        $log = new LoggingStatement($statement, $this->getDriver());
         $log->setLogger($this->getLogger());
 
         return $log;
@@ -976,9 +1174,19 @@ public function __debugInfo(): array
         $replace = array_intersect_key($secrets, $this->_config);
         $config = $replace + $this->_config;
 
+        if (isset($config['read'])) {
+            /** @psalm-suppress PossiblyInvalidArgument */
+            $config['read'] = array_intersect_key($secrets, $config['read']) + $config['read'];
+        }
+        if (isset($config['write'])) {
+            /** @psalm-suppress PossiblyInvalidArgument */
+            $config['write'] = array_intersect_key($secrets, $config['write']) + $config['write'];
+        }
+
         return [
             'config' => $config,
-            'driver' => $this->_driver,
+            'readDriver' => $this->readDriver,
+            'writeDriver' => $this->writeDriver,
             'transactionLevel' => $this->_transactionLevel,
             'transactionStarted' => $this->_transactionStarted,
             'useSavePoints' => $this->_useSavePoints,
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver.php b/app/vendor/cakephp/cakephp/src/Database/Driver.php
index 249868c47..5d43f1acc 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver.php
@@ -27,6 +27,7 @@
 use InvalidArgumentException;
 use PDO;
 use PDOException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Represents a database driver containing all specificities for
@@ -108,6 +109,16 @@ public function __construct(array $config = [])
         }
     }
 
+    /**
+     * Get the configuration data used to create the driver.
+     *
+     * @return array
+     */
+    public function config(): array
+    {
+        return $this->_config;
+    }
+
     /**
      * Establishes a connection to the database server
      *
@@ -513,6 +524,16 @@ public function getConnectRetries(): int
         return $this->connectRetries;
     }
 
+    /**
+     * Returns the connection role this driver performs.
+     *
+     * @return string
+     */
+    public function getRole(): string
+    {
+        return $this->_config['_role'] ?? Connection::ROLE_WRITE;
+    }
+
     /**
      * Destructor
      */
@@ -532,6 +553,7 @@ public function __debugInfo(): array
     {
         return [
             'connected' => $this->_connection !== null,
+            'role' => $this->getRole(),
         ];
     }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
index 68f46ff74..b7d30b69f 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Mysql.php
@@ -23,6 +23,7 @@
 use Cake\Database\Statement\MysqlStatement;
 use Cake\Database\StatementInterface;
 use PDO;
+use function Cake\Core\deprecationWarning;
 
 /**
  * MySQL Driver
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php b/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
index 7bcabda6b..94a5e88b9 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/SqlDialectTrait.php
@@ -306,3 +306,10 @@ public function rollbackSavePointSQL($name): string
         return 'ROLLBACK TO SAVEPOINT LEVEL' . $name;
     }
 }
+
+// phpcs:disable
+class_alias(
+    'Cake\Database\Driver\SqlDialectTrait',
+    'Cake\Database\SqlDialectTrait'
+);
+// phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
index 6ca955856..65c3e7a1d 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php
@@ -30,6 +30,7 @@
 use InvalidArgumentException;
 use PDO;
 use RuntimeException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Class Sqlite
diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php b/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
index e94b268b5..e21a79d08 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Driver/TupleComparisonTranslatorTrait.php
@@ -90,8 +90,7 @@ protected function _transformTupleComparison(TupleComparison $expression, Query
         }
 
         $surrogate = $query->getConnection()
-            ->newQuery()
-            ->select($true);
+            ->selectQuery($true);
 
         if (!is_array(current($value))) {
             $value = [$value];
diff --git a/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php b/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
index e2ccc4d31..914d6b755 100644
--- a/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Database/DriverInterface.php
@@ -27,6 +27,8 @@
  * @method int getConnectRetries() Returns the number of connection retry attempts made.
  * @method bool supports(string $feature) Checks whether a feature is supported by the driver.
  * @method bool inTransaction() Returns whether a transaction is active.
+ * @method array config() Get the configuration data used to create the driver.
+ * @method string getRole() Returns the connection role this driver prforms.
  */
 interface DriverInterface
 {
diff --git a/app/vendor/cakephp/cakephp/src/Database/Exception.php b/app/vendor/cakephp/cakephp/src/Database/Exception.php
index d47914df0..b8f495836 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Exception.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Exception.php
@@ -1,16 +1,10 @@
 _conditions[] = $conditions;
-
-            return $this;
-        }
-
-        if ($conditions instanceof ExpressionInterface) {
+        if (is_string($conditions) || $conditions instanceof ExpressionInterface) {
             $this->_conditions[] = $conditions;
 
             return $this;
diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
index bf51eaf19..bbc415414 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php
@@ -24,6 +24,7 @@
 use Closure;
 use InvalidArgumentException;
 use LogicException;
+use function Cake\Core\getTypeName;
 
 /**
  * Represents a SQL when/then clause with a fluid API
diff --git a/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php b/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
index 1251fcad4..9e50ad63c 100644
--- a/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
+++ b/app/vendor/cakephp/cakephp/src/Database/FunctionsBuilder.php
@@ -19,6 +19,7 @@
 use Cake\Database\Expression\AggregateExpression;
 use Cake\Database\Expression\FunctionExpression;
 use InvalidArgumentException;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Contains methods related to generating FunctionExpression objects
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php b/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
index 6560a367f..f029bc935 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/LoggedQuery.php
@@ -130,6 +130,7 @@ public function getContext(): array
         return [
             'numRows' => $this->numRows,
             'took' => $this->took,
+            'role' => $this->driver ? $this->driver->getRole() : '',
         ];
     }
 
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php b/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
index ada3d381d..e83f6f60e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/LoggingStatement.php
@@ -21,6 +21,7 @@
 use Cake\Database\Statement\StatementDecorator;
 use Exception;
 use Psr\Log\LoggerInterface;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Statement decorator used to
diff --git a/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php b/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
index a7f27b489..e2faadce2 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Log/QueryLogger.php
@@ -50,7 +50,7 @@ public function log($level, $message, array $context = [])
 
         if ($context['query'] instanceof LoggedQuery) {
             $context = $context['query']->getContext() + $context;
-            $message = 'connection={connection} duration={took} rows={numRows} ' . $message;
+            $message = 'connection={connection} role={role} duration={took} rows={numRows} ' . $message;
         }
         Log::write('debug', (string)$message, $context);
     }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query.php b/app/vendor/cakephp/cakephp/src/Database/Query.php
index 503c3a443..594b8a70f 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Query.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Query.php
@@ -30,6 +30,7 @@
 use IteratorAggregate;
 use RuntimeException;
 use Throwable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * This class represents a Relational database SQL Query. A query can be of
@@ -63,6 +64,13 @@ class Query implements ExpressionInterface, IteratorAggregate
      */
     protected $_connection;
 
+    /**
+     * Connection role ('read' or 'write')
+     *
+     * @var string
+     */
+    protected $connectionRole = Connection::ROLE_WRITE;
+
     /**
      * Type of this query (select, insert, update, delete).
      *
@@ -178,6 +186,7 @@ class Query implements ExpressionInterface, IteratorAggregate
      * are enabled.
      *
      * @var bool
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     protected $_useBufferedResults = true;
 
@@ -230,6 +239,16 @@ public function getConnection(): Connection
         return $this->_connection;
     }
 
+    /**
+     * Returns the connection role ('read' or 'write')
+     *
+     * @return string
+     */
+    public function getConnectionRole(): string
+    {
+        return $this->connectionRole;
+    }
+
     /**
      * Compiles the SQL representation of this query and executes it using the
      * configured connection object. Returns the resulting statement object.
@@ -311,8 +330,9 @@ public function sql(?ValueBinder $binder = null): string
             $binder = $this->getValueBinder();
             $binder->resetCount();
         }
+        $connection = $this->getConnection();
 
-        return $this->getConnection()->compileQuery($this, $binder);
+        return $connection->getDriver($this->getConnectionRole())->compileQuery($this, $binder)[1];
     }
 
     /**
@@ -428,7 +448,7 @@ public function with($cte, bool $overwrite = false)
         }
 
         if ($cte instanceof Closure) {
-            $query = $this->getConnection()->newQuery();
+            $query = $this->getConnection()->selectQuery();
             $cte = $cte(new CommonTableExpression(), $query);
             if (!($cte instanceof CommonTableExpression)) {
                 throw new RuntimeException(
@@ -864,7 +884,6 @@ public function innerJoin($table, $conditions = [], $types = [])
      * to use for joining.
      * @param string $type the join type to use
      * @return array
-     * @psalm-suppress InvalidReturnType
      */
     protected function _makeJoin($table, $conditions, $type): array
     {
@@ -877,7 +896,6 @@ protected function _makeJoin($table, $conditions, $type): array
 
         /**
          * @psalm-suppress InvalidArrayOffset
-         * @psalm-suppress InvalidReturnStatement
          */
         return [
             $alias => [
@@ -2197,9 +2215,15 @@ public function setValueBinder(?ValueBinder $binder)
      *
      * @param bool $enable Whether to enable buffering
      * @return $this
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function enableBufferedResults(bool $enable = true)
     {
+        if (!$enable) {
+            deprecationWarning(
+                '4.5.0 enableBufferedResults() is deprecated. Results will always be buffered in 5.0.'
+            );
+        }
         $this->_dirty();
         $this->_useBufferedResults = $enable;
 
@@ -2213,6 +2237,7 @@ public function enableBufferedResults(bool $enable = true)
      * remembered for future iterations.
      *
      * @return $this
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function disableBufferedResults()
     {
@@ -2233,6 +2258,7 @@ public function disableBufferedResults()
      * remembered for future iterations.
      *
      * @return bool
+     * @deprecated 4.5.0 Results will always be buffered in 5.0.
      */
     public function isBufferedResultsEnabled(): bool
     {
@@ -2327,7 +2353,7 @@ public function isResultsCastingEnabled(): bool
     protected function _decorateStatement(StatementInterface $statement)
     {
         $typeMap = $this->getSelectTypeMap();
-        $driver = $this->getConnection()->getDriver();
+        $driver = $this->getConnection()->getDriver($this->connectionRole);
 
         if ($this->typeCastEnabled && $typeMap->toArray()) {
             $statement = new CallbackStatement($statement, $driver, new FieldTypeConverter($typeMap, $driver));
@@ -2418,7 +2444,6 @@ public function __clone()
                             }
                         }
                     } elseif ($piece instanceof ExpressionInterface) {
-                        /** @psalm-suppress PossiblyUndefinedMethod */
                         $this->_parts[$name][$i] = clone $piece;
                     }
                 }
@@ -2473,4 +2498,19 @@ function ($errno, $errstr) {
             'executed' => $this->_iterator ? true : false,
         ];
     }
+
+    /**
+     * Helper for Query deprecation methods.
+     *
+     * @param string $method The method that is invalid.
+     * @param string $message An additional message.
+     * @return void
+     * @internal
+     */
+    protected function _deprecatedMethod($method, $message = '')
+    {
+        $class = static::class;
+        $text = "As of 4.5.0 calling {$method}() on {$class} is deprecated. " . $message;
+        deprecationWarning($text);
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php
new file mode 100644
index 000000000..5c11ae9d7
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/DeleteQuery.php
@@ -0,0 +1,222 @@
+_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distint()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function order($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('order()');
+
+        return parent::order($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderAsc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderAsc()');
+
+        return parent::orderAsc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderDesc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderDesc()');
+
+        return parent::orderDesc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function limit($limit)
+    {
+        $this->_deprecatedMethod('limit()');
+
+        return parent::limit($limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('unionAll()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php
new file mode 100644
index 000000000..7d326239b
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/InsertQuery.php
@@ -0,0 +1,322 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function select($fields = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distinct()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function join($tables, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('join()');
+
+        return parent::join($tables, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function removeJoin(string $name)
+    {
+        $this->_deprecatedMethod('removeJoin()');
+
+        return parent::removeJoin($name);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function leftJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('leftJoin()');
+
+        return parent::leftJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function rightJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('rightJoin()');
+
+        return parent::rightJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function innerJoin($table, $conditions = [], $types = [])
+    {
+        $this->_deprecatedMethod('innerJoin()');
+
+        return parent::innerJoin($table, $conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function from($tables = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('from()', 'Use into() instead.');
+
+        return parent::from($tables, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function where($conditions = null, array $types = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('where()');
+
+        return parent::where($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotNull($fields)
+    {
+        $this->_deprecatedMethod('whereNotNull()');
+
+        return parent::whereNotNull($fields);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNull($fields)
+    {
+        $this->_deprecatedMethod('whereNull()');
+
+        return parent::whereNull($fields);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereInList(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereInList()');
+
+        return parent::whereInList($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotInList(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereNotInList()');
+
+        return parent::whereNotInList($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function whereNotInListOrNull(string $field, array $values, array $options = [])
+    {
+        $this->_deprecatedMethod('whereNotInListOrNull()');
+
+        return parent::whereNotInListOrNull($field, $values, $options);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andWhere($conditions, array $types = [])
+    {
+        $this->_deprecatedMethod('andWhere()');
+
+        return parent::andWhere($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function order($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('order()');
+
+        return parent::order($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderAsc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderAsc()');
+
+        return parent::orderAsc($field, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function orderDesc($field, $overwrite = false)
+    {
+        $this->_deprecatedMethod('orderDesc()');
+
+        return parent::orderDesc($field, $overwrite);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php
new file mode 100644
index 000000000..7d2986aba
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/SelectQuery.php
@@ -0,0 +1,127 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()', 'Use from() instead.');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function update($table)
+    {
+        $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.');
+
+        return parent::update($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function set($key, $value = null, $types = [])
+    {
+        $this->_deprecatedMethod('set()');
+
+        return parent::set($key, $value, $types);
+    }
+
+    /**
+     * Sets the connection role.
+     *
+     * @param string $role Connection role ('read' or 'write')
+     * @return $this
+     */
+    public function setConnectionRole(string $role)
+    {
+        assert($role === Connection::ROLE_READ || $role === Connection::ROLE_WRITE);
+        $this->connectionRole = $role;
+
+        return $this;
+    }
+
+    /**
+     * Sets the connection role to read.
+     *
+     * @return $this
+     */
+    public function useReadRole()
+    {
+        return $this->setConnectionRole(Connection::ROLE_READ);
+    }
+
+    /**
+     * Sets the connection role to write.
+     *
+     * @return $this
+     */
+    public function useWriteRole()
+    {
+        return $this->setConnectionRole(Connection::ROLE_WRITE);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php b/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php
new file mode 100644
index 000000000..0f84cce6c
--- /dev/null
+++ b/app/vendor/cakephp/cakephp/src/Database/Query/UpdateQuery.php
@@ -0,0 +1,182 @@
+_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.');
+
+        return parent::delete($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function select($fields = [], bool $overwrite = false)
+    {
+        $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.');
+
+        return parent::select($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function distinct($on = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('distinct()');
+
+        return parent::distinct($on, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function modifier($modifiers, $overwrite = false)
+    {
+        $this->_deprecatedMethod('modifier()');
+
+        return parent::modifier($modifiers, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function group($fields, $overwrite = false)
+    {
+        $this->_deprecatedMethod('group()');
+
+        return parent::group($fields, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function having($conditions = null, $types = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('having()');
+
+        return parent::having($conditions, $types, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function andHaving($conditions, $types = [])
+    {
+        $this->_deprecatedMethod('andHaving()');
+
+        return parent::andHaving($conditions, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function page(int $num, ?int $limit = null)
+    {
+        $this->_deprecatedMethod('page()');
+
+        return parent::page($num, $limit);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offset($offset)
+    {
+        $this->_deprecatedMethod('offset()');
+
+        return parent::offset($offset);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function union($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::union($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unionAll($query, $overwrite = false)
+    {
+        $this->_deprecatedMethod('union()');
+
+        return parent::unionAll($query, $overwrite);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function insert(array $columns, array $types = [])
+    {
+        $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.');
+
+        return parent::insert($columns, $types);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function into(string $table)
+    {
+        $this->_deprecatedMethod('into()', 'Use update() instead.');
+
+        return parent::into($table);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function values($data)
+    {
+        $this->_deprecatedMethod('values()');
+
+        return parent::values($data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function from($tables = [], $overwrite = false)
+    {
+        $this->_deprecatedMethod('from()', 'Use update() instead.');
+
+        return parent::from($tables, $overwrite);
+    }
+}
diff --git a/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php b/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
index 236d5eb72..9ed44223e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
+++ b/app/vendor/cakephp/cakephp/src/Database/QueryCompiler.php
@@ -201,7 +201,7 @@ protected function _buildSelectPart(array $parts, Query $query, ValueBinder $bin
         $distinct = $query->clause('distinct');
         $modifiers = $this->_buildModifierPart($query->clause('modifier'), $query, $binder);
 
-        $driver = $query->getConnection()->getDriver();
+        $driver = $query->getConnection()->getDriver($query->getConnectionRole());
         $quoteIdentifiers = $driver->isAutoQuotingEnabled() || $this->_quotedSelectAliases;
         $normalized = [];
         $parts = $this->_stringifyExpressions($parts, $binder);
diff --git a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
index 7d76cc01e..ac847810f 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php
@@ -104,7 +104,7 @@ protected function reconnect(): bool
 
         try {
             // Make sure we free any resources associated with the old connection
-            $this->connection->disconnect();
+            $this->connection->getDriver()->disconnect();
         } catch (Exception $e) {
         }
 
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
index 46513170d..8d32d3448 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/BaseSchema.php
@@ -1,5 +1,10 @@
 _dialect->listTablesWithoutViewsSql($this->_connection->config());
+        [$sql, $params] = $this->_dialect->listTablesWithoutViewsSql($this->_connection->getDriver()->config());
         $result = [];
         $statement = $this->_connection->execute($sql, $params);
         while ($row = $statement->fetch()) {
@@ -78,7 +78,7 @@ public function listTablesWithoutViews(): array
      */
     public function listTables(): array
     {
-        [$sql, $params] = $this->_dialect->listTablesSql($this->_connection->config());
+        [$sql, $params] = $this->_dialect->listTablesSql($this->_connection->getDriver()->config());
         $result = [];
         $statement = $this->_connection->execute($sql, $params);
         while ($row = $statement->fetch()) {
@@ -109,7 +109,7 @@ public function listTables(): array
      */
     public function describe(string $name, array $options = []): TableSchemaInterface
     {
-        $config = $this->_connection->config();
+        $config = $this->_connection->getDriver()->config();
         if (strpos($name, '.')) {
             [$config['schema'], $name] = explode('.', $name);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
index 237d6362b..30b20db6e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchema.php
@@ -1,5 +1,10 @@
  TableSchema::TYPE_BOOLEAN, 'length' => null];
         }
 
-        if ($col === 'char' && $length === 36) {
+        if (($col === 'char' && $length === 36) || $col === 'uuid') {
             return ['type' => TableSchema::TYPE_UUID, 'length' => null];
         }
         if ($col === 'char') {
@@ -642,6 +642,8 @@ public function hasSequences(): bool
 }
 
 // phpcs:disable
-// Add backwards compatible alias.
-class_alias('Cake\Database\Schema\SqliteSchemaDialect', 'Cake\Database\Schema\SqliteSchema');
+class_alias(
+    'Cake\Database\Schema\SqliteSchemaDialect',
+    'Cake\Database\Schema\SqliteSchema'
+);
 // phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
index dbe584efd..62e3f6981 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlserverSchema.php
@@ -1,5 +1,10 @@
 _schema->describe($table, ['forceRefresh' => true]);
         }
 
@@ -86,7 +85,6 @@ public function clear(?string $name = null): array
         $cacher = $this->_schema->getCacher();
 
         foreach ($tables as $table) {
-            /** @psalm-suppress PossiblyNullArgument */
             $key = $this->_schema->cacheKey($table);
             $cacher->delete($key);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php b/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
index 38ef7bc08..763f8fd70 100644
--- a/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/SqlDialectTrait.php
@@ -1,5 +1,10 @@
 
  */
 class BufferedStatement implements Iterator, StatementInterface
 {
@@ -85,6 +87,16 @@ public function __construct(StatementInterface $statement, DriverInterface $driv
         $this->_driver = $driver;
     }
 
+    /**
+     * Returns the connection driver.
+     *
+     * @return \Cake\Database\DriverInterface
+     */
+    protected function getDriver(): DriverInterface
+    {
+        return $this->_driver;
+    }
+
     /**
      * Magic getter to return $queryString as read-only.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php b/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
index 5e7309ad1..6cbc82720 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/PDOStatement.php
@@ -20,6 +20,7 @@
 use Cake\Database\DriverInterface;
 use PDO;
 use PDOStatement as Statement;
+use function Cake\Core\getTypeName;
 
 /**
  * Decorator for \PDOStatement class mainly used for converting human readable
@@ -55,7 +56,6 @@ public function __construct(Statement $statement, DriverInterface $driver)
     public function __get(string $property)
     {
         if ($property === 'queryString' && isset($this->_statement->queryString)) {
-            /** @psalm-suppress NoInterfaceProperties */
             return $this->_statement->queryString;
         }
 
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php b/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
index efd3b6a2c..39f3be8c3 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/SqlserverStatement.php
@@ -45,7 +45,6 @@ public function bindValue($column, $value, $type = 'string'): void
             [$value, $type] = $this->cast($value, $type);
         }
         if ($type === PDO::PARAM_LOB) {
-            /** @psalm-suppress UndefinedConstant */
             $this->_statement->bindParam($column, $value, $type, 0, PDO::SQLSRV_ENCODING_BINARY);
         } else {
             $this->_statement->bindValue($column, $value, $type);
diff --git a/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php b/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
index 4a1d33e95..2c2f46bfa 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Statement/StatementDecorator.php
@@ -32,6 +32,7 @@
  * PDOStatement.
  *
  * @property-read string $queryString
+ * @template-implements \IteratorAggregate
  */
 class StatementDecorator implements StatementInterface, Countable, IteratorAggregate
 {
@@ -72,6 +73,16 @@ public function __construct(StatementInterface $statement, DriverInterface $driv
         $this->_driver = $driver;
     }
 
+    /**
+     * Returns the connection driver.
+     *
+     * @return \Cake\Database\DriverInterface
+     */
+    protected function getDriver(): DriverInterface
+    {
+        return $this->_driver;
+    }
+
     /**
      * Magic getter to return $queryString as read-only.
      *
@@ -326,7 +337,6 @@ public function bind(array $params, array $types): void
                 /** @psalm-suppress InvalidOperand */
                 $index += $offset;
             }
-            /** @psalm-suppress InvalidScalarArgument */
             $this->bindValue($index, $value, $type);
         }
     }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type.php b/app/vendor/cakephp/cakephp/src/Database/Type.php
index 466b8d597..164419c87 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type.php
@@ -1,5 +1,9 @@
 setTimezone($this->defaultTimezone);
         }
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php b/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
index 19d5453fe..0cd63cd6c 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/DateType.php
@@ -22,6 +22,8 @@
 use DateTime;
 use DateTimeImmutable;
 use DateTimeInterface;
+use Exception;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Class DateType
@@ -102,14 +104,61 @@ public function useMutable()
      */
     public function marshal($value): ?DateTimeInterface
     {
-        $date = parent::marshal($value);
-        /** @psalm-var \DateTime|\DateTimeImmutable|null $date */
-        if ($date && !$date instanceof I18nDateTimeInterface) {
-            // Clear time manually when I18n types aren't available and raw DateTime used
-            $date = $date->setTime(0, 0, 0);
+        if ($value instanceof DateTimeInterface) {
+            return new FrozenDate($value);
         }
 
-        return $date;
+        /** @var class-string<\Cake\Chronos\ChronosDate> $class */
+        $class = $this->_className;
+        try {
+            if ($value === '' || $value === null || is_bool($value)) {
+                return null;
+            }
+
+            if (is_int($value) || (is_string($value) && ctype_digit($value))) {
+                /** @var \Cake\I18n\FrozenDate|\DateTimeImmutable $dateTime */
+                $dateTime = new $class('@' . $value);
+
+                return $dateTime;
+            }
+
+            if (is_string($value)) {
+                if ($this->_useLocaleMarshal) {
+                    $dateTime = $this->_parseLocaleValue($value);
+                } else {
+                    $dateTime = $this->_parseValue($value);
+                }
+
+                return $dateTime;
+            }
+        } catch (Exception $e) {
+            return null;
+        }
+
+        if (is_array($value) && implode('', $value) === '') {
+            return null;
+        }
+        $format = '';
+        if (
+            isset($value['year'], $value['month'], $value['day']) &&
+            (
+                is_numeric($value['year']) &&
+                is_numeric($value['month']) &&
+                is_numeric($value['day'])
+            )
+        ) {
+            $format .= sprintf('%d-%02d-%02d', $value['year'], $value['month'], $value['day']);
+        }
+
+        if (empty($format)) {
+            // Invalid array format.
+            return null;
+        }
+
+        /** @var \Cake\I18n\FrozenDate|\DateTimeImmutable $dateTime */
+        $dateTime = new $class($format);
+
+        return $dateTime;
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php b/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
index cb332fd37..f06f6d795 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/DecimalType.php
@@ -21,6 +21,7 @@
 use InvalidArgumentException;
 use PDO;
 use RuntimeException;
+use function Cake\Core\getTypeName;
 
 /**
  * Decimal type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php b/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
index 4a84c59e3..973d7ca55 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/IntegerType.php
@@ -19,6 +19,7 @@
 use Cake\Database\DriverInterface;
 use InvalidArgumentException;
 use PDO;
+use function Cake\Core\getTypeName;
 
 /**
  * Integer type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php b/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
index 4dd38bc86..4c98e3369 100644
--- a/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
+++ b/app/vendor/cakephp/cakephp/src/Database/Type/StringType.php
@@ -19,6 +19,7 @@
 use Cake\Database\DriverInterface;
 use InvalidArgumentException;
 use PDO;
+use function Cake\Core\getTypeName;
 
 /**
  * String type converter.
diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php b/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
index f92c85027..2f04b814e 100644
--- a/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Database/TypeConverterTrait.php
@@ -36,8 +36,8 @@ public function cast($value, $type = 'string'): array
             $type = TypeFactory::build($type);
         }
         if ($type instanceof TypeInterface) {
-            $value = $type->toDatabase($value, $this->_driver);
-            $type = $type->toStatement($value, $this->_driver);
+            $value = $type->toDatabase($value, $this->getDriver());
+            $type = $type->toStatement($value, $this->getDriver());
         }
 
         return [$value, $type];
diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php b/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
index 2f5006697..617bad6d9 100644
--- a/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
+++ b/app/vendor/cakephp/cakephp/src/Database/TypeFactory.php
@@ -162,3 +162,10 @@ public static function clear(): void
         static::$_builtTypes = [];
     }
 }
+
+// phpcs:disable
+class_alias(
+    'Cake\Database\TypeFactory',
+    'Cake\Database\Type'
+);
+// phpcs:enable
diff --git a/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php b/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
index 1a63a57d9..0e5dd3d08 100644
--- a/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
+++ b/app/vendor/cakephp/cakephp/src/Database/ValueBinder.php
@@ -148,4 +148,16 @@ public function attachTo(StatementInterface $statement): void
             $statement->bindValue($b['placeholder'], $b['value'], $b['type']);
         }
     }
+
+    /**
+     * Get verbose debugging data.
+     *
+     * @return array
+     */
+    public function __debugInfo(): array
+    {
+        return [
+            'bindings' => $this->bindings(),
+        ];
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
index 01a7d5330..7efef433d 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php
@@ -30,8 +30,6 @@
  *   already created tables. {@see \Cake\Database\Connnection::supportsDynamicConstraints()}
  * @method \Cake\Database\Schema\Collection getSchemaCollection() Gets a Schema\Collection object for this connection.
  *    {@see \Cake\Database\Connnection::getSchemaCollection()}
- * @method \Cake\Database\Query newQuery() Create a new Query instance for this connection.
- *    {@see \Cake\Database\Connnection::newQuery()}
  * @method \Cake\Database\StatementInterface prepare($sql) Prepares a SQL statement to be executed.
  *    {@see \Cake\Database\Connnection::prepare()}
  * @method \Cake\Database\StatementInterface execute($query, $params = [], array $types = []) Executes a query using
@@ -42,6 +40,16 @@
  */
 interface ConnectionInterface extends LoggerAwareInterface
 {
+    /**
+     * @var string
+     */
+    public const ROLE_WRITE = 'write';
+
+    /**
+     * @var string
+     */
+    public const ROLE_READ = 'read';
+
     /**
      * Gets the current logger object.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
index 54adf540f..8f244ea16 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionManager.php
@@ -43,7 +43,7 @@ class ConnectionManager
     /**
      * A map of connection aliases.
      *
-     * @var array
+     * @var array
      */
     protected static $_aliasMap = [];
 
@@ -63,7 +63,7 @@ class ConnectionManager
     /**
      * The ConnectionRegistry used by the manager.
      *
-     * @var \Cake\Datasource\ConnectionRegistry
+     * @var \Cake\Datasource\ConnectionRegistry|null
      */
     protected static $_registry;
 
@@ -173,6 +173,16 @@ public static function dropAlias(string $alias): void
         unset(static::$_aliasMap[$alias]);
     }
 
+    /**
+     * Returns the current connection aliases and what they alias.
+     *
+     * @return array
+     */
+    public static function aliases(): array
+    {
+        return static::$_aliasMap;
+    }
+
     /**
      * Get a connection.
      *
@@ -182,8 +192,8 @@ public static function dropAlias(string $alias): void
      * as second parameter.
      *
      * @param string $name The connection name.
-     * @param bool $useAliases Set to false to not use aliased connections.
-     * @return \Cake\Datasource\ConnectionInterface A connection object.
+     * @param bool $useAliases Whether connection aliases are used
+     * @return \Cake\Datasource\ConnectionInterface
      * @throws \Cake\Datasource\Exception\MissingDatasourceConfigException When config
      * data is missing.
      */
@@ -192,15 +202,15 @@ public static function get(string $name, bool $useAliases = true)
         if ($useAliases && isset(static::$_aliasMap[$name])) {
             $name = static::$_aliasMap[$name];
         }
-        if (empty(static::$_config[$name])) {
+
+        if (!isset(static::$_config[$name])) {
             throw new MissingDatasourceConfigException(['name' => $name]);
         }
-        /** @psalm-suppress RedundantPropertyInitializationCheck */
+
         if (!isset(static::$_registry)) {
             static::$_registry = new ConnectionRegistry();
         }
 
-        return static::$_registry->{$name}
-            ?? static::$_registry->load($name, static::$_config[$name]);
+        return static::$_registry->{$name} ?? static::$_registry->load($name, static::$_config[$name]);
     }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
index c0991064b..58876709b 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php
@@ -25,6 +25,7 @@
  *
  * @property mixed $id Alias for commonly used primary key.
  * @method bool[] getAccessible() Accessible configuration for this entity.
+ * @template-extends \ArrayAccess
  */
 interface EntityInterface extends ArrayAccess, JsonSerializable
 {
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
index b8ef4a9dd..3cd54bb1a 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php
@@ -22,6 +22,7 @@
 use Cake\Utility\Inflector;
 use InvalidArgumentException;
 use Traversable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * An entity represents a single result row from a repository. It exposes the
@@ -118,6 +119,23 @@ trait EntityTrait
      */
     protected $_registryAlias = '';
 
+    /**
+     * Storing the current visitation status while recursing through entities getting errors.
+     *
+     * @var bool
+     */
+    protected $_hasBeenVisited = false;
+
+    /**
+     * Set to true in your entity's class definition or
+     * via application logic. When true. has() and related
+     * methods will use `array_key_exists` instead of `isset`
+     * to decide if fields are 'defined' in an entity.
+     *
+     * @var bool
+     */
+    protected $_hasAllowsNull = false;
+
     /**
      * Magic getter to access fields that have been set in this entity
      *
@@ -361,7 +379,11 @@ public function getOriginalValues(): array
     public function has($field): bool
     {
         foreach ((array)$field as $prop) {
-            if ($this->get($prop) === null) {
+            if ($this->_hasAllowsNull) {
+                if (!array_key_exists($prop, $this->_fields) && !static::_accessor($prop, 'get')) {
+                    return false;
+                }
+            } elseif ($this->get($prop) === null) {
                 return false;
             }
         }
@@ -845,6 +867,11 @@ public function isNew(): bool
      */
     public function hasErrors(bool $includeNested = true): bool
     {
+        if ($this->_hasBeenVisited) {
+            // While recursing through entities, each entity should only be visited once. See https://github.com/cakephp/cakephp/issues/17318
+            return false;
+        }
+
         if (Hash::filter($this->_errors)) {
             return true;
         }
@@ -853,10 +880,15 @@ public function hasErrors(bool $includeNested = true): bool
             return false;
         }
 
-        foreach ($this->_fields as $field) {
-            if ($this->_readHasErrors($field)) {
-                return true;
+        $this->_hasBeenVisited = true;
+        try {
+            foreach ($this->_fields as $field) {
+                if ($this->_readHasErrors($field)) {
+                    return true;
+                }
             }
+        } finally {
+            $this->_hasBeenVisited = false;
         }
 
         return false;
@@ -869,17 +901,29 @@ public function hasErrors(bool $includeNested = true): bool
      */
     public function getErrors(): array
     {
+        if ($this->_hasBeenVisited) {
+            // While recursing through entities, each entity should only be visited once. See https://github.com/cakephp/cakephp/issues/17318
+            return [];
+        }
+
         $diff = array_diff_key($this->_fields, $this->_errors);
 
-        return $this->_errors + (new Collection($diff))
-            ->filter(function ($value) {
-                return is_array($value) || $value instanceof EntityInterface;
-            })
-            ->map(function ($value) {
-                return $this->_readError($value);
-            })
-            ->filter()
-            ->toArray();
+        $this->_hasBeenVisited = true;
+        try {
+            $errors = $this->_errors + (new Collection($diff))
+                ->filter(function ($value) {
+                    return is_array($value) || $value instanceof EntityInterface;
+                })
+                ->map(function ($value) {
+                    return $this->_readError($value);
+                })
+                ->filter()
+                ->toArray();
+        } finally {
+            $this->_hasBeenVisited = false;
+        }
+
+        return $errors;
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
index be75b2d76..a841303dd 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php
@@ -1,7 +1,10 @@
 {$alias})) {
             return $this->{$alias};
@@ -135,6 +142,60 @@ public function loadModel(?string $modelClass = null, ?string $modelType = null)
         return $this->{$alias};
     }
 
+    /**
+     * Fetch or construct a model instance from a locator.
+     *
+     * Uses a modelFactory based on `$modelType` to fetch and construct a `RepositoryInterface`
+     * and return it. The default `modelType` can be defined with `setModelType()`.
+     *
+     * Unlike `loadModel()` this method will *not* set an object property.
+     *
+     * If a repository provider does not return an object a MissingModelException will
+     * be thrown.
+     *
+     * @param string|null $modelClass Name of model class to load. Defaults to $this->modelClass.
+     *  The name can be an alias like `'Post'` or FQCN like `App\Model\Table\PostsTable::class`.
+     * @param string|null $modelType The type of repository to load. Defaults to the getModelType() value.
+     * @return \Cake\Datasource\RepositoryInterface The model instance created.
+     * @throws \Cake\Datasource\Exception\MissingModelException If the model class cannot be found.
+     * @throws \UnexpectedValueException If $modelClass argument is not provided
+     *   and ModelAwareTrait::$modelClass property value is empty.
+     */
+    public function fetchModel(?string $modelClass = null, ?string $modelType = null): RepositoryInterface
+    {
+        $modelClass = $modelClass ?? $this->modelClass;
+        if (empty($modelClass)) {
+            throw new UnexpectedValueException('Default modelClass is empty');
+        }
+        $modelType = $modelType ?? $this->getModelType();
+
+        $options = [];
+        if (strpos($modelClass, '\\') === false) {
+            [, $alias] = pluginSplit($modelClass, true);
+        } else {
+            $options['className'] = $modelClass;
+            /** @psalm-suppress PossiblyFalseOperand */
+            $alias = substr(
+                $modelClass,
+                strrpos($modelClass, '\\') + 1,
+                -strlen($modelType)
+            );
+            $modelClass = $alias;
+        }
+
+        $factory = $this->_modelFactories[$modelType] ?? FactoryLocator::get($modelType);
+        if ($factory instanceof LocatorInterface) {
+            $instance = $factory->get($modelClass, $options);
+        } else {
+            $instance = $factory($modelClass, $options);
+        }
+        if ($instance) {
+            return $instance;
+        }
+
+        throw new MissingModelException([$modelClass, $modelType]);
+    }
+
     /**
      * Override a existing callable to generate repositories of a given type.
      *
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
index a87c8ea62..926b2318f 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php
@@ -1,7 +1,10 @@
  20,
         'maxLimit' => 100,
         'allowedParameters' => ['limit', 'sort', 'page', 'direction'],
+        'sortableFields' => null,
+        'finder' => 'all',
     ];
 
     /**
@@ -214,10 +217,17 @@ public function paginate(object $object, array $params = [], array $settings = [
      */
     protected function getQuery(RepositoryInterface $object, ?QueryInterface $query, array $data): QueryInterface
     {
+        $options = $data['options'];
+        unset(
+            $options['scope'],
+            $options['sort'],
+            $options['direction'],
+        );
+
         if ($query === null) {
-            $query = $object->find($data['finder'], $data['options']);
+            $query = $object->find($data['finder'], $options);
         } else {
-            $query->applyOptions($data['options']);
+            $query->applyOptions($options);
         }
 
         return $query;
@@ -247,6 +257,20 @@ protected function extractData(RepositoryInterface $object, array $params, array
     {
         $alias = $object->getAlias();
         $defaults = $this->getDefaults($alias, $settings);
+
+        $validSettings = array_merge(
+            array_keys($this->_defaultConfig),
+            ['whitelist', 'sortWhitelist', 'order', 'scope']
+        );
+        $extraSettings = array_diff_key($defaults, array_flip($validSettings));
+        if ($extraSettings) {
+            deprecationWarning(
+                'Passing query options as paginator settings is deprecated.'
+                . ' Use a custom finder through `finder` config instead.'
+                . ' Extra keys found are: ' . implode(',', array_keys($extraSettings))
+            );
+        }
+
         $options = $this->mergeOptions($params, $defaults);
         $options = $this->validateSort($object, $options);
         $options = $this->checkLimit($options);
@@ -396,7 +420,14 @@ protected function addSortingParams(array $params, array $data): array
     protected function _extractFinder(array $options): array
     {
         $type = !empty($options['finder']) ? $options['finder'] : 'all';
-        unset($options['finder'], $options['maxLimit']);
+        unset(
+            $options['finder'],
+            $options['maxLimit'],
+            $options['allowedParameters'],
+            $options['whitelist'],
+            $options['sortableFields'],
+            $options['sortWhitelist'],
+        );
 
         if (is_array($type)) {
             $options = (array)current($type) + $options;
@@ -611,6 +642,13 @@ protected function _removeAliases(array $fields, string $model): array
     {
         $result = [];
         foreach ($fields as $field => $sort) {
+            if (is_int($field)) {
+                throw new CakeException(sprintf(
+                    'The `order` config must be an associative array. Found invalid value with numeric key: `%s`',
+                    $sort
+                ));
+            }
+
             if (strpos($field, '.') === false) {
                 $result[$field] = $sort;
                 continue;
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
index 3c34bdf8d..fc7023a55 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/QueryInterface.php
@@ -24,6 +24,7 @@
  *   provided list using the AND operator. {@see \Cake\Database\Query::andWhere()}
  * @method \Cake\Datasource\EntityInterface|array firstOrFail() Get the first result from the executing query or raise an exception.
  *   {@see \Cake\Database\Query::firstOrFail()}
+ * @method $this setRepository(\Cake\Datasource\RepositoryInterface $repository) Set the default repository object that will be used by this query.
  */
 interface QueryInterface
 {
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
index 6d70a77b5..15525612e 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
@@ -17,10 +17,12 @@
 namespace Cake\Datasource;
 
 use BadMethodCallException;
+use Cake\Collection\CollectionInterface;
 use Cake\Collection\Iterator\MapReduce;
 use Cake\Datasource\Exception\RecordNotFoundException;
 use InvalidArgumentException;
 use Traversable;
+use function Cake\Core\deprecationWarning;
 
 /**
  * Contains the characteristics for an object that is attached to a repository and
@@ -89,8 +91,23 @@ trait QueryTrait
      *
      * @param \Cake\Datasource\RepositoryInterface|\Cake\ORM\Table $repository The default table object to use
      * @return $this
+     * @deprecated 4.5.0 Use `setRepository()` instead.
      */
     public function repository(RepositoryInterface $repository)
+    {
+        deprecationWarning('`repository() method is deprecated. Use `setRepository()` instead.');
+
+        return $this->setRepository($repository);
+    }
+
+    /**
+     * Set the default Table object that will be used by this query
+     * and form the `FROM` clause.
+     *
+     * @param \Cake\Datasource\RepositoryInterface|\Cake\ORM\Table $repository The default table object to use
+     * @return $this
+     */
+    public function setRepository(RepositoryInterface $repository)
     {
         $this->_repository = $repository;
 
@@ -564,6 +581,833 @@ public function __call(string $method, array $arguments)
         );
     }
 
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::each()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function each(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling each() on a Query is deprecated. ' .
+            'Instead call `$query->all()->each(...)` instead.'
+        );
+
+        return $this->all()->each($callback);
+    }
+
+    /**
+     * @param ?callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::filter()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function filter(?callable $callback = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling filter() on a Query is deprecated. ' .
+            'Instead call `$query->all()->filter(...)` instead.'
+        );
+
+        return $this->all()->filter($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::reject()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function reject(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling reject() on a Query is deprecated. ' .
+            'Instead call `$query->all()->reject(...)` instead.'
+        );
+
+        return $this->all()->reject($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::every()
+     * @return bool
+     * @deprecated
+     */
+    public function every(callable $callback): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling every() on a Query is deprecated. ' .
+            'Instead call `$query->all()->every(...)` instead.'
+        );
+
+        return $this->all()->every($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::some()
+     * @return bool
+     * @deprecated
+     */
+    public function some(callable $callback): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling some() on a Query is deprecated. ' .
+            'Instead call `$query->all()->some(...)` instead.'
+        );
+
+        return $this->all()->some($callback);
+    }
+
+    /**
+     * @param mixed $value The value to check.
+     * @see \Cake\Collection\CollectionInterface::contains()
+     * @return bool
+     * @deprecated
+     */
+    public function contains($value): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling contains() on a Query is deprecated. ' .
+            'Instead call `$query->all()->contains(...)` instead.'
+        );
+
+        return $this->all()->contains($value);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @see \Cake\Collection\CollectionInterface::map()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function map(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling map() on a Query is deprecated. ' .
+            'Instead call `$query->all()->map(...)` instead.'
+        );
+
+        return $this->all()->map($callback);
+    }
+
+    /**
+     * @param callable $callback The callback to apply
+     * @param mixed $initial The initial value
+     * @see \Cake\Collection\CollectionInterface::reduce()
+     * @return mixed
+     * @deprecated
+     */
+    public function reduce(callable $callback, $initial = null)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling reduce() on a Query is deprecated. ' .
+            'Instead call `$query->all()->reduce(...)` instead.'
+        );
+
+        return $this->all()->reduce($callback, $initial);
+    }
+
+    /**
+     * @param callable|string $path The path to extract
+     * @see \Cake\Collection\CollectionInterface::extract()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function extract($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling extract() on a Query is deprecated. ' .
+            'Instead call `$query->all()->extract(...)` instead.'
+        );
+
+        return $this->all()->extract($path);
+    }
+
+    /**
+     * @param callable|string $path The path to max
+     * @param int $sort The SORT_ constant to order by.
+     * @see \Cake\Collection\CollectionInterface::max()
+     * @return mixed
+     * @deprecated
+     */
+    public function max($path, int $sort = \SORT_NUMERIC)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling max() on a Query is deprecated. ' .
+            'Instead call `$query->all()->max(...)` instead.'
+        );
+
+        return $this->all()->max($path, $sort);
+    }
+
+    /**
+     * @param callable|string $path The path to max
+     * @param int $sort The SORT_ constant to order by.
+     * @see \Cake\Collection\CollectionInterface::min()
+     * @return mixed
+     * @deprecated
+     */
+    public function min($path, int $sort = \SORT_NUMERIC)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling min() on a Query is deprecated. ' .
+            'Instead call `$query->all()->min(...)` instead.'
+        );
+
+        return $this->all()->min($path, $sort);
+    }
+
+    /**
+     * @param callable|string|null $path the path to average
+     * @see \Cake\Collection\CollectionInterface::avg()
+     * @return float|int|null
+     * @deprecated
+     */
+    public function avg($path = null)
+    {
+        deprecationwarning(
+            '4.3.0 - calling avg() on a query is deprecated. ' .
+            'instead call `$query->all()->avg(...)` instead.'
+        );
+
+        return $this->all()->avg($path);
+    }
+
+    /**
+     * @param callable|string|null $path the path to average
+     * @see \Cake\Collection\CollectionInterface::median()
+     * @return float|int|null
+     * @deprecated
+     */
+    public function median($path = null)
+    {
+        deprecationwarning(
+            '4.3.0 - calling median() on a query is deprecated. ' .
+            'instead call `$query->all()->median(...)` instead.'
+        );
+
+        return $this->all()->median($path);
+    }
+
+    /**
+     * @param callable|string $path the path to average
+     * @param int $order The \SORT_ constant for the direction you want results in.
+     * @param int $sort The \SORT_ method to use.
+     * @see \Cake\Collection\CollectionInterface::sortBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function sortBy($path, int $order = SORT_DESC, int $sort = \SORT_NUMERIC): CollectionInterface
+    {
+        deprecationwarning(
+            '4.3.0 - calling sortBy() on a query is deprecated. ' .
+            'instead call `$query->all()->sortBy(...)` instead.'
+        );
+
+        return $this->all()->sortBy($path, $order, $sort);
+    }
+
+    /**
+     * @param callable|string $path The path to group by
+     * @see \Cake\Collection\CollectionInterface::groupBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function groupBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling groupBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->groupBy(...)` instead.'
+        );
+
+        return $this->all()->groupBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to extract
+     * @see \Cake\Collection\CollectionInterface::indexBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function indexBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling indexBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->indexBy(...)` instead.'
+        );
+
+        return $this->all()->indexBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to count by
+     * @see \Cake\Collection\CollectionInterface::countBy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function countBy($path): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling countBy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->countBy(...)` instead.'
+        );
+
+        return $this->all()->countBy($path);
+    }
+
+    /**
+     * @param string|callable $path The path to sum
+     * @see \Cake\Collection\CollectionInterface::sumOf()
+     * @return int|float
+     * @deprecated
+     */
+    public function sumOf($path = null)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling sumOf() on a Query is deprecated. ' .
+                'Instead call `$query->all()->sumOf(...)` instead.'
+        );
+
+        return $this->all()->sumOf($path);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::shuffle()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function shuffle(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling shuffle() on a Query is deprecated. ' .
+            'Instead call `$query->all()->shuffle(...)` instead.'
+        );
+
+        return $this->all()->shuffle();
+    }
+
+    /**
+     * @param int $length The number of samples to select
+     * @see \Cake\Collection\CollectionInterface::sample()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function sample(int $length = 10): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling sample() on a Query is deprecated. ' .
+            'Instead call `$query->all()->sample(...)` instead.'
+        );
+
+        return $this->all()->sample($length);
+    }
+
+    /**
+     * @param int $length The number of elements to take
+     * @param int $offset The offset of the first element to take.
+     * @see \Cake\Collection\CollectionInterface::take()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function take(int $length = 1, int $offset = 0): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling take() on a Query is deprecated. ' .
+            'Instead call `$query->all()->take(...)` instead.'
+        );
+
+        return $this->all()->take($length, $offset);
+    }
+
+    /**
+     * @param int $length The number of items to take.
+     * @see \Cake\Collection\CollectionInterface::takeLast()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function takeLast(int $length): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling takeLast() on a Query is deprecated. ' .
+            'Instead call `$query->all()->takeLast(...)` instead.'
+        );
+
+        return $this->all()->takeLast($length);
+    }
+
+    /**
+     * @param int $length The number of items to skip
+     * @see \Cake\Collection\CollectionInterface::skip()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function skip(int $length): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling skip() on a Query is deprecated. ' .
+            'Instead call `$query->all()->skip(...)` instead.'
+        );
+
+        return $this->all()->skip($length);
+    }
+
+    /**
+     * @param array $conditions The conditions to use.
+     * @see \Cake\Collection\CollectionInterface::match()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function match(array $conditions): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling match() on a Query is deprecated. ' .
+            'Instead call `$query->all()->match(...)` instead.'
+        );
+
+        return $this->all()->match($conditions);
+    }
+
+    /**
+     * @param array $conditions The conditions to apply
+     * @see \Cake\Collection\CollectionInterface::firstMatch()
+     * @return mixed
+     * @deprecated
+     */
+    public function firstMatch(array $conditions)
+    {
+        deprecationWarning(
+            '4.3.0 - Calling firstMatch() on a Query is deprecated. ' .
+            'Instead call `$query->all()->firstMatch(...)` instead.'
+        );
+
+        return $this->all()->firstMatch($conditions);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::last()
+     * @deprecated
+     * @return mixed
+     */
+    public function last()
+    {
+        deprecationWarning(
+            '4.3.0 - Calling last() on a Query is deprecated. ' .
+            'Instead call `$query->all()->last(...)` instead.'
+        );
+
+        return $this->all()->last();
+    }
+
+    /**
+     * @param mixed $items The items to append
+     * @see \Cake\Collection\CollectionInterface::append()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function append($items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling append() on a Query is deprecated. ' .
+            'Instead call `$query->all()->append(...)` instead.'
+        );
+
+        return $this->all()->append($items);
+    }
+
+    /**
+     * @param mixed $item The item to apply
+     * @param mixed $key The key to append with
+     * @see \Cake\Collection\CollectionInterface::appendItem()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function appendItem($item, $key = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling appendItem() on a Query is deprecated. ' .
+            'Instead call `$query->all()->appendItem(...)` instead.'
+        );
+
+        return $this->all()->appendItem($item, $key);
+    }
+
+    /**
+     * @param mixed $items The items to prepend.
+     * @see \Cake\Collection\CollectionInterface::prepend()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function prepend($items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling prepend() on a Query is deprecated. ' .
+            'Instead call `$query->all()->prepend(...)` instead.'
+        );
+
+        return $this->all()->prepend($items);
+    }
+
+    /**
+     * @param mixed $item The item to prepend
+     * @param mixed $key The key to use.
+     * @see \Cake\Collection\CollectionInterface::prependItem()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function prependItem($item, $key = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling prependItem() on a Query is deprecated. ' .
+            'Instead call `$query->all()->prependItem(...)` instead.'
+        );
+
+        return $this->all()->prependItem($item, $key);
+    }
+
+    /**
+     * @param callable|string $keyPath The path for keys
+     * @param callable|string $valuePath The path for values
+     * @param callable|string|null $groupPath The path for grouping
+     * @see \Cake\Collection\CollectionInterface::combine()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function combine($keyPath, $valuePath, $groupPath = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling combine() on a Query is deprecated. ' .
+            'Instead call `$query->all()->combine(...)` instead.'
+        );
+
+        return $this->all()->combine($keyPath, $valuePath, $groupPath);
+    }
+
+    /**
+     * @param callable|string $idPath The path to ids
+     * @param callable|string $parentPath The path to parents
+     * @param string $nestingKey Key used for nesting children.
+     * @see \Cake\Collection\CollectionInterface::nest()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function nest($idPath, $parentPath, string $nestingKey = 'children'): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling nest() on a Query is deprecated. ' .
+            'Instead call `$query->all()->nest(...)` instead.'
+        );
+
+        return $this->all()->nest($idPath, $parentPath, $nestingKey);
+    }
+
+    /**
+     * @param string $path The path to insert on
+     * @param mixed $values The values to insert.
+     * @see \Cake\Collection\CollectionInterface::insert()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function insert(string $path, $values): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling insert() on a Query is deprecated. ' .
+            'Instead call `$query->all()->insert(...)` instead.'
+        );
+
+        return $this->all()->insert($path, $values);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::toList()
+     * @return array
+     * @deprecated
+     */
+    public function toList(): array
+    {
+        deprecationWarning(
+            '4.3.0 - Calling toList() on a Query is deprecated. ' .
+            'Instead call `$query->all()->toList(...)` instead.'
+        );
+
+        return $this->all()->toList();
+    }
+
+    /**
+     * @param bool $keepKeys Whether or not keys should be kept
+     * @see \Cake\Collection\CollectionInterface::compile()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function compile(bool $keepKeys = true): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling compile() on a Query is deprecated. ' .
+            'Instead call `$query->all()->compile(...)` instead.'
+        );
+
+        return $this->all()->compile($keepKeys);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::lazy()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function lazy(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling lazy() on a Query is deprecated. ' .
+            'Instead call `$query->all()->lazy(...)` instead.'
+        );
+
+        return $this->all()->lazy();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::buffered()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function buffered(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling buffered() on a Query is deprecated. ' .
+            'Instead call `$query->all()->buffered(...)` instead.'
+        );
+
+        return $this->all()->buffered();
+    }
+
+    /**
+     * @param string|int $order The order in which to return the elements
+     * @param callable|string $nestingKey The key name under which children are nested
+     * @see \Cake\Collection\CollectionInterface::listNested()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function listNested($order = 'desc', $nestingKey = 'children'): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling listNested() on a Query is deprecated. ' .
+            'Instead call `$query->all()->listNested(...)` instead.'
+        );
+
+        return $this->all()->listNested($order, $nestingKey);
+    }
+
+    /**
+     * @param callable|array $condition the method that will receive each of the elements and
+     *   returns true when the iteration should be stopped.
+     * @see \Cake\Collection\CollectionInterface::stopWhen()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function stopWhen($condition): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling stopWhen() on a Query is deprecated. ' .
+            'Instead call `$query->all()->stopWhen(...)` instead.'
+        );
+
+        return $this->all()->stopWhen($condition);
+    }
+
+    /**
+     * @param callable|null $callback A callable function that will receive each of
+     *  items in the collection.
+     * @see \Cake\Collection\CollectionInterface::unfold()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function unfold(?callable $callback = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling unfold() on a Query is deprecated. ' .
+            'Instead call `$query->all()->unfold(...)` instead.'
+        );
+
+        return $this->all()->unfold($callback);
+    }
+
+    /**
+     * @param callable $callback A callable function that will receive each of
+     *  items in the collection.
+     * @see \Cake\Collection\CollectionInterface::through()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function through(callable $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling through() on a Query is deprecated. ' .
+            'Instead call `$query->all()->through(...)` instead.'
+        );
+
+        return $this->all()->through($callback);
+    }
+
+    /**
+     * @param iterable ...$items The collections to zip.
+     * @see \Cake\Collection\CollectionInterface::zip()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function zip(iterable $items): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling zip() on a Query is deprecated. ' .
+            'Instead call `$query->all()->zip(...)` instead.'
+        );
+
+        return $this->all()->zip($items);
+    }
+
+    /**
+     * @param iterable ...$items The collections to zip.
+     * @param callable $callback The function to use for zipping the elements together.
+     * @see \Cake\Collection\CollectionInterface::zipWith()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function zipWith(iterable $items, $callback): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling zipWith() on a Query is deprecated. ' .
+            'Instead call `$query->all()->zipWith(...)` instead.'
+        );
+
+        return $this->all()->zipWith($items, $callback);
+    }
+
+    /**
+     * @param int $chunkSize The maximum size for each chunk
+     * @see \Cake\Collection\CollectionInterface::chunk()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function chunk(int $chunkSize): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling chunk() on a Query is deprecated. ' .
+            'Instead call `$query->all()->chunk(...)` instead.'
+        );
+
+        return $this->all()->chunk($chunkSize);
+    }
+
+    /**
+     * @param int $chunkSize The maximum size for each chunk
+     * @param bool $keepKeys If the keys of the array should be kept
+     * @see \Cake\Collection\CollectionInterface::chunkWithKeys()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function chunkWithKeys(int $chunkSize, bool $keepKeys = true): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling chunkWithKeys() on a Query is deprecated. ' .
+            'Instead call `$query->all()->chunkWithKeys(...)` instead.'
+        );
+
+        return $this->all()->chunkWithKeys($chunkSize, $keepKeys);
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::isEmpty()
+     * @return bool
+     * @deprecated
+     */
+    public function isEmpty(): bool
+    {
+        deprecationWarning(
+            '4.3.0 - Calling isEmpty() on a Query is deprecated. ' .
+            'Instead call `$query->all()->isEmpty(...)` instead.'
+        );
+
+        return $this->all()->isEmpty();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::unwrap()
+     * @return \Traversable
+     * @deprecated
+     */
+    public function unwrap(): Traversable
+    {
+        deprecationWarning(
+            '4.3.0 - Calling unwrap() on a Query is deprecated. ' .
+            'Instead call `$query->all()->unwrap(...)` instead.'
+        );
+
+        return $this->all()->unwrap();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::transpose()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function transpose(): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling transpose() on a Query is deprecated. ' .
+            'Instead call `$query->all()->transpose(...)` instead.'
+        );
+
+        return $this->all()->transpose();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::count()
+     * @return int
+     * @deprecated
+     */
+    public function count(): int
+    {
+        deprecationWarning(
+            '4.3.0 - Calling count() on a Query is deprecated. ' .
+            'Instead call `$query->all()->count(...)` instead.'
+        );
+
+        return $this->all()->count();
+    }
+
+    /**
+     * @see \Cake\Collection\CollectionInterface::countKeys()
+     * @return int
+     * @deprecated
+     */
+    public function countKeys(): int
+    {
+        deprecationWarning(
+            '4.3.0 - Calling countKeys() on a Query is deprecated. ' .
+            'Instead call `$query->all()->countKeys(...)` instead.'
+        );
+
+        return $this->all()->countKeys();
+    }
+
+    /**
+     * @param callable|null $operation A callable that allows you to customize the product result.
+     * @param callable|null $filter A filtering callback that must return true for a result to be part
+     *   of the final results.
+     * @see \Cake\Collection\CollectionInterface::cartesianProduct()
+     * @return \Cake\Collection\CollectionInterface
+     * @deprecated
+     */
+    public function cartesianProduct(?callable $operation = null, ?callable $filter = null): CollectionInterface
+    {
+        deprecationWarning(
+            '4.3.0 - Calling cartesianProduct() on a Query is deprecated. ' .
+            'Instead call `$query->all()->cartesianProduct(...)` instead.'
+        );
+
+        return $this->all()->cartesianProduct($operation, $filter);
+    }
+
     /**
      * Populates or adds parts to current query clauses using an array.
      * This is handy for passing all query clauses at once.
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
index e59e63e54..85d98b618 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetDecorator.php
@@ -17,11 +17,15 @@
 namespace Cake\Datasource;
 
 use Cake\Collection\Collection;
+use Cake\Core\Configure;
 use Countable;
 
 /**
  * Generic ResultSet decorator. This will make any traversable object appear to
  * be a database result
+ *
+ * @template T of \Cake\Datasource\EntityInterface|array
+ * @implements \Cake\Datasource\ResultSetInterface
  */
 class ResultSetDecorator extends Collection implements ResultSetInterface
 {
@@ -43,4 +47,15 @@ public function count(): int
 
         return count($this->toArray());
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function __debugInfo(): array
+    {
+        $parentInfo = parent::__debugInfo();
+        $limit = Configure::read('App.ResultSetDebugLimit', 10);
+
+        return array_merge($parentInfo, ['items' => $this->take($limit)->toArray()]);
+    }
 }
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
index a62ee77f3..c193fac81 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/ResultSetInterface.php
@@ -22,6 +22,8 @@
 
 /**
  * Describes how a collection of datasource results should look like
+ *
+ * @template T
  */
 interface ResultSetInterface extends CollectionInterface, Countable, Serializable
 {
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php b/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
index 1bf5c9c37..c523eba5a 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/RulesChecker.php
@@ -112,7 +112,7 @@ class RulesChecker
     public function __construct(array $options = [])
     {
         $this->_options = $options;
-        $this->_useI18n = function_exists('__d');
+        $this->_useI18n = function_exists('\Cake\I18n\__d');
     }
 
     /**
diff --git a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
index 95499fb6d..134b0bd64 100644
--- a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
+++ b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php
@@ -1,7 +1,10 @@
 getTrace();
+        }
+        $parentFrames = $parent->getTrace();
+        $frames = $exception->getTrace();
+
+        $parentCount = count($parentFrames) - 1;
+        $frameCount = count($frames) - 1;
+
+        // Reverse loop through both traces removing frames that
+        // are the same.
+        for ($i = $frameCount, $p = $parentCount; $i >= 0 && $p >= 0; $p--) {
+            $parentTail = $parentFrames[$p];
+            $tail = $frames[$i];
+
+            // Frames without file/line are never equal to another frame.
+            $isEqual = (
+                (
+                    isset($tail['file']) &&
+                    isset($tail['line']) &&
+                    isset($parentTail['file']) &&
+                    isset($parentTail['line'])
+                ) &&
+                ($tail['file'] === $parentTail['file']) &&
+                ($tail['line'] === $parentTail['line'])
+            );
+            if ($isEqual) {
+                unset($frames[$i]);
+                $i--;
+            }
+        }
+
+        return $frames;
+    }
+
     /**
      * Outputs a stack trace based on the supplied options.
      *
@@ -390,7 +438,11 @@ public static function log($var, $level = 'debug', int $maxDepth = 3): void
      */
     public static function trace(array $options = [])
     {
-        return Debugger::formatTrace(debug_backtrace(), $options);
+        // Remove the frame for Debugger::trace()
+        $backtrace = debug_backtrace();
+        array_shift($backtrace);
+
+        return Debugger::formatTrace($backtrace, $options);
     }
 
     /**
@@ -426,60 +478,50 @@ public static function formatTrace($backtrace, array $options = [])
         ];
         $options = Hash::merge($defaults, $options);
 
-        $count = count($backtrace);
+        $count = count($backtrace) + 1;
         $back = [];
 
-        $_trace = [
-            'line' => '??',
-            'file' => '[internal]',
-            'class' => null,
-            'function' => '[main]',
-        ];
-
         for ($i = $options['start']; $i < $count && $i < $options['depth']; $i++) {
-            $trace = $backtrace[$i] + ['file' => '[internal]', 'line' => '??'];
-            $signature = $reference = '[main]';
-
-            if (isset($backtrace[$i + 1])) {
-                $next = $backtrace[$i + 1] + $_trace;
-                $signature = $reference = $next['function'];
-
-                if (!empty($next['class'])) {
-                    $signature = $next['class'] . '::' . $next['function'];
-                    $reference = $signature . '(';
-                    if ($options['args'] && isset($next['args'])) {
-                        $args = [];
-                        foreach ($next['args'] as $arg) {
-                            $args[] = Debugger::exportVar($arg);
-                        }
-                        $reference .= implode(', ', $args);
+            $frame = ['file' => '[main]', 'line' => ''];
+            if (isset($backtrace[$i])) {
+                $frame = $backtrace[$i] + ['file' => '[internal]', 'line' => '??'];
+            }
+
+            $signature = $reference = $frame['file'];
+            if (!empty($frame['class'])) {
+                $signature = $frame['class'] . $frame['type'] . $frame['function'];
+                $reference = $signature . '(';
+                if ($options['args'] && isset($frame['args'])) {
+                    $args = [];
+                    foreach ($frame['args'] as $arg) {
+                        $args[] = Debugger::exportVar($arg);
                     }
-                    $reference .= ')';
+                    $reference .= implode(', ', $args);
                 }
+                $reference .= ')';
             }
             if (in_array($signature, $options['exclude'], true)) {
                 continue;
             }
             if ($options['format'] === 'points') {
-                $back[] = ['file' => $trace['file'], 'line' => $trace['line'], 'reference' => $reference];
+                $back[] = ['file' => $frame['file'], 'line' => $frame['line'], 'reference' => $reference];
             } elseif ($options['format'] === 'array') {
                 if (!$options['args']) {
-                    unset($trace['args']);
+                    unset($frame['args']);
                 }
-                $back[] = $trace;
+                $back[] = $frame;
             } else {
-                if (isset($self->_templates[$options['format']]['traceLine'])) {
-                    $tpl = $self->_templates[$options['format']]['traceLine'];
+                $tpl = $self->_templates[$options['format']]['traceLine'] ?? $self->_templates['base']['traceLine'];
+                if ($frame['file'] == '[main]') {
+                    $back[] = '[main]';
                 } else {
-                    $tpl = $self->_templates['base']['traceLine'];
+                    $frame['path'] = static::trimPath($frame['file']);
+                    $frame['reference'] = $reference;
+                    unset($frame['object'], $frame['args']);
+                    $back[] = Text::insert($tpl, $frame, ['before' => '{:', 'after' => '}']);
                 }
-                $trace['path'] = static::trimPath($trace['file']);
-                $trace['reference'] = $reference;
-                unset($trace['object'], $trace['args']);
-                $back[] = Text::insert($tpl, $trace, ['before' => '{:', 'after' => '}']);
             }
         }
-
         if ($options['format'] === 'array' || $options['format'] === 'points') {
             return $back;
         }
@@ -575,9 +617,6 @@ public static function excerpt(string $file, int $line, int $context = 2): array
      */
     protected static function _highlight(string $str): string
     {
-        if (function_exists('hphp_log') || function_exists('hphp_gettid')) {
-            return htmlentities($str);
-        }
         $added = false;
         if (strpos($str, '', '<?php 
'], + ['<?php 
', '<?php 
', '<?php '], '', $highlight ); @@ -1119,7 +1158,7 @@ public static function printVar($var, array $location = [], ?bool $showHtml = nu * * - HTML escape the message. * - Convert `bool` into `bool` - * - Convert newlines into `
` + * - Convert newlines into `
` * * @param string $message The string message to format. * @return string Formatted message. diff --git a/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php b/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php index 76fdf1a81..ab2f54d04 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php +++ b/app/vendor/cakephp/cakephp/src/Error/ErrorTrap.php @@ -10,6 +10,7 @@ use Cake\Event\EventDispatcherTrait; use Cake\Routing\Router; use Exception; +use function Cake\Core\deprecationWarning; /** * Entry point to CakePHP's error handling. @@ -122,6 +123,17 @@ public function handleError( $trace = Debugger::trace(['start' => 1, 'format' => 'points']); $error = new PhpError($code, $description, $file, $line, $trace); + $ignoredPaths = (array)Configure::read('Error.ignoredDeprecationPaths'); + if ($code === E_USER_DEPRECATED && $ignoredPaths) { + $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', substr((string)$file, strlen(ROOT) + 1)); + foreach ($ignoredPaths as $pattern) { + $pattern = str_replace(DIRECTORY_SEPARATOR, '/', $pattern); + if (fnmatch($pattern, $relativePath)) { + return true; + } + } + } + $debug = Configure::read('debug'); $renderer = $this->renderer(); @@ -132,7 +144,7 @@ public function handleError( if ($event->isStopped()) { return true; } - $renderer->write($renderer->render($error, $debug)); + $renderer->write($event->getResult() ?: $renderer->render($error, $debug)); } catch (Exception $e) { // Fatal errors always log. $this->logger()->logMessage('error', 'Could not render error. Got: ' . $e->getMessage()); diff --git a/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php b/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php index f86155762..249cca920 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php +++ b/app/vendor/cakephp/cakephp/src/Error/ExceptionTrap.php @@ -10,6 +10,8 @@ use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; use Throwable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; /** * Entry point to CakePHP's exception handling. @@ -237,8 +239,15 @@ public function handleException(Throwable $exception): void $this->logException($exception, $request); try { - $renderer = $this->renderer($exception); - $renderer->write($renderer->render()); + $event = $this->dispatchEvent('Exception.beforeRender', ['exception' => $exception, 'request' => $request]); + if ($event->isStopped()) { + return; + } + $exception = $event->getData('exception'); + assert($exception instanceof Throwable); + + $renderer = $this->renderer($exception, $request); + $renderer->write($event->getResult() ?: $renderer->render()); } catch (Throwable $exception) { $this->logInternalError($exception); } @@ -365,7 +374,6 @@ public function logException(Throwable $exception, ?ServerRequestInterface $requ $this->logger()->log($exception, $request); } } - $this->dispatchEvent('Exception.beforeRender', ['exception' => $exception]); } /** diff --git a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php index d1e7efae7..b39ecc3f9 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php @@ -19,11 +19,15 @@ use Cake\Core\App; use Cake\Core\Configure; use Cake\Core\InstanceConfigTrait; +use Cake\Core\PluginApplicationInterface; use Cake\Error\ErrorHandler; use Cake\Error\ExceptionTrap; use Cake\Error\Renderer\WebExceptionRenderer; +use Cake\Event\EventDispatcherTrait; use Cake\Http\Exception\RedirectException; use Cake\Http\Response; +use Cake\Routing\Router; +use Cake\Routing\RoutingApplicationInterface; use InvalidArgumentException; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; @@ -31,6 +35,9 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Throwable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\triggerWarning; /** * Error handling middleware. @@ -41,6 +48,7 @@ class ErrorHandlerMiddleware implements MiddlewareInterface { use InstanceConfigTrait; + use EventDispatcherTrait; /** * Default configuration values. @@ -72,22 +80,32 @@ class ErrorHandlerMiddleware implements MiddlewareInterface */ protected $exceptionTrap = null; + /** + * @var \Cake\Routing\RoutingApplicationInterface|null + */ + protected $app = null; + /** * Constructor * * @param \Cake\Error\ErrorHandler|\Cake\Error\ExceptionTrap|array $errorHandler The error handler instance * or config array. + * @param \Cake\Routing\RoutingApplicationInterface|null $app Application instance. * @throws \InvalidArgumentException */ - public function __construct($errorHandler = []) + public function __construct($errorHandler = [], $app = null) { if (func_num_args() > 1) { - deprecationWarning( - 'The signature of ErrorHandlerMiddleware::__construct() has changed. ' - . 'Pass the config array as 1st argument instead.' - ); + if (is_array($app)) { + deprecationWarning( + 'The signature of ErrorHandlerMiddleware::__construct() has changed. ' + . 'Pass the config array as 1st argument instead.' + ); - $errorHandler = func_get_arg(1); + $errorHandler = func_get_arg(1); + } else { + $this->app = $app; + } } if (PHP_VERSION_ID >= 70400 && Configure::read('debug')) { @@ -145,11 +163,24 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface */ public function handleException(Throwable $exception, ServerRequestInterface $request): ResponseInterface { + $this->loadRoutes(); + + $response = null; if ($this->errorHandler === null) { $handler = $this->getExceptionTrap(); $handler->logException($exception, $request); + $event = $this->dispatchEvent( + 'Exception.beforeRender', + ['exception' => $exception, 'request' => $request], + $handler + ); + + $exception = $event->getData('exception'); + assert($exception instanceof Throwable); $renderer = $handler->renderer($exception, $request); + + $response = $event->getResult(); } else { $handler = $this->getErrorHandler(); $handler->logException($exception, $request); @@ -158,13 +189,13 @@ public function handleException(Throwable $exception, ServerRequestInterface $re } try { - /** @var \Psr\Http\Message\ResponseInterface|string $response */ - $response = $renderer->render(); - if (is_string($response)) { - return new Response(['body' => $response, 'status' => 500]); + if ($response === null) { + $response = $renderer->render(); } - return $response; + return $response instanceof ResponseInterface + ? $response + : new Response(['body' => $response, 'status' => 500]); } catch (Throwable $internalException) { $handler->logException($internalException, $request); @@ -231,4 +262,34 @@ protected function getExceptionTrap(): ExceptionTrap return $this->exceptionTrap; } + + /** + * Ensure that the application's routes are loaded. + * + * @return void + */ + protected function loadRoutes(): void + { + if ( + !($this->app instanceof RoutingApplicationInterface) + || Router::routes() + ) { + return; + } + + try { + $builder = Router::createRouteBuilder('/'); + + $this->app->routes($builder); + if ($this->app instanceof PluginApplicationInterface) { + $this->app->pluginRoutes($builder); + } + } catch (Throwable $e) { + triggerWarning(sprintf( + "Exception loading routes when rendering an error page: \n %s - %s", + get_class($e), + $e->getMessage() + )); + } + } } diff --git a/app/vendor/cakephp/cakephp/src/Error/PhpError.php b/app/vendor/cakephp/cakephp/src/Error/PhpError.php index a0a5396fe..0b9944edb 100644 --- a/app/vendor/cakephp/cakephp/src/Error/PhpError.php +++ b/app/vendor/cakephp/cakephp/src/Error/PhpError.php @@ -183,7 +183,11 @@ public function getTraceAsString(): string { $out = []; foreach ($this->trace as $frame) { - $out[] = "{$frame['reference']} {$frame['file']}, line {$frame['line']}"; + if (!empty($frame['line'])) { + $out[] = "{$frame['reference']} {$frame['file']}, line {$frame['line']}"; + } else { + $out[] = $frame['reference']; + } } return implode("\n", $out); diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php index 988dcfa44..cba448219 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/ConsoleExceptionRenderer.php @@ -19,6 +19,7 @@ use Cake\Console\ConsoleOutput; use Cake\Core\Configure; use Cake\Core\Exception\CakeException; +use Cake\Error\Debugger; use Psr\Http\Message\ServerRequestInterface; use Throwable; @@ -76,7 +77,8 @@ public function render() } $out = []; foreach ($exceptions as $i => $error) { - $out = array_merge($out, $this->renderException($error, $i)); + $parent = $exceptions[$i - 1] ?? null; + $out = array_merge($out, $this->renderException($error, $parent)); } return join("\n", $out); @@ -86,15 +88,15 @@ public function render() * Render an individual exception * * @param \Throwable $exception The exception to render. - * @param int $index Exception index in the chain + * @param ?\Throwable $parent The Exception index in the chain * @return array */ - protected function renderException(Throwable $exception, int $index): array + protected function renderException(Throwable $exception, ?Throwable $parent): array { $out = [ sprintf( '%s[%s] %s in %s on line %s', - $index > 0 ? 'Caused by ' : '', + $parent ? 'Caused by ' : '', get_class($exception), $exception->getMessage(), $exception->getFile(), @@ -114,10 +116,11 @@ protected function renderException(Throwable $exception, int $index): array } if ($this->trace) { + $stacktrace = Debugger::getUniqueFrames($exception, $parent); $out[] = ''; $out[] = 'Stack Trace:'; $out[] = ''; - $out[] = $exception->getTraceAsString(); + $out[] = Debugger::formatTrace($stacktrace, ['format' => 'txt']); $out[] = ''; } diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php index 569445e0b..7e49178f5 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/HtmlErrorRenderer.php @@ -19,6 +19,7 @@ use Cake\Error\Debugger; use Cake\Error\ErrorRendererInterface; use Cake\Error\PhpError; +use function Cake\Core\h; /** * Interactive HTML error rendering with a stack trace. diff --git a/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php index 5c7143c1b..b249f7409 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php @@ -44,6 +44,9 @@ use PDOException; use Psr\Http\Message\ResponseInterface; use Throwable; +use function Cake\Core\h; +use function Cake\Core\namespaceSplit; +use function Cake\I18n\__d; /** * Web Exception Renderer. @@ -167,9 +170,17 @@ protected function _getController(): Controller $params['controller'] = 'Error'; $factory = new ControllerFactory(new Container()); + // Check including plugin + prefix $class = $factory->getControllerClass($request->withAttribute('params', $params)); + if (!$class && !empty($params['prefix']) && !empty($params['plugin'])) { + unset($params['prefix']); + // Fallback to only plugin + $class = $factory->getControllerClass($request->withAttribute('params', $params)); + } + if (!$class) { + // Fallback to app/core provided controller. /** @var string $class */ $class = App::className('Error', 'Controller', 'Controller'); } diff --git a/app/vendor/cakephp/cakephp/src/Error/functions.php b/app/vendor/cakephp/cakephp/src/Error/functions.php new file mode 100644 index 000000000..6a33370a1 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Error/functions.php @@ -0,0 +1,117 @@ + 0, 'depth' => 1, 'format' => 'array']); + if (isset($trace[0]['line']) && isset($trace[0]['file'])) { + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + } + } + + Debugger::printVar($var, $location, $showHtml); + + return $var; +} + +/** + * Outputs a stack trace based on the supplied options. + * + * ### Options + * + * - `depth` - The number of stack frames to return. Defaults to 999 + * - `args` - Should arguments for functions be shown? If true, the arguments for each method call + * will be displayed. + * - `start` - The stack frame to start generating a trace from. Defaults to 1 + * + * @param array $options Format for outputting stack trace + * @return void + */ +function stackTrace(array $options = []): void +{ + if (!Configure::read('debug')) { + return; + } + + $options += ['start' => 0]; + $options['start']++; + + /** @var string $trace */ + $trace = Debugger::trace($options); + echo $trace; +} + +/** + * Prints out debug information about given variable and dies. + * + * Only runs if debug mode is enabled. + * It will otherwise just continue code execution and ignore this function. + * + * @param mixed $var Variable to show debug information for. + * @param bool|null $showHtml If set to true, the method prints the debug data in a browser-friendly way. + * @return void + * @link https://book.cakephp.org/4/en/development/debugging.html#basic-debugging + */ +function dd($var, $showHtml = null): void +{ + if (!Configure::read('debug')) { + return; + } + + $trace = Debugger::trace(['start' => 0, 'depth' => 2, 'format' => 'array']); + /** @psalm-suppress PossiblyInvalidArrayOffset */ + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + + Debugger::printVar($var, $location, $showHtml); + die(1); +} + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; +} diff --git a/app/vendor/cakephp/cakephp/src/Error/functions_global.php b/app/vendor/cakephp/cakephp/src/Error/functions_global.php new file mode 100644 index 000000000..1f5ae23d8 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Error/functions_global.php @@ -0,0 +1,141 @@ + 0, 'depth' => 1, 'format' => 'array']); + if (isset($trace[0]['line']) && isset($trace[0]['file'])) { + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + } + } + + Debugger::printVar($var, $location, $showHtml); + + return $var; + } +} + +if (!function_exists('stackTrace')) { + /** + * Outputs a stack trace based on the supplied options. + * + * ### Options + * + * - `depth` - The number of stack frames to return. Defaults to 999 + * - `args` - Should arguments for functions be shown? If true, the arguments for each method call + * will be displayed. + * - `start` - The stack frame to start generating a trace from. Defaults to 1 + * + * @param array $options Format for outputting stack trace + * @return void + */ + function stackTrace(array $options = []): void + { + if (!Configure::read('debug')) { + return; + } + + $options += ['start' => 0]; + $options['start']++; + + /** @var string $trace */ + $trace = Debugger::trace($options); + echo $trace; + } +} + +if (!function_exists('dd')) { + /** + * Prints out debug information about given variable and dies. + * + * Only runs if debug mode is enabled. + * It will otherwise just continue code execution and ignore this function. + * + * @param mixed $var Variable to show debug information for. + * @param bool|null $showHtml If set to true, the method prints the debug data in a browser-friendly way. + * @return void + * @link https://book.cakephp.org/4/en/development/debugging.html#basic-debugging + */ + function dd($var, $showHtml = null): void + { + if (!Configure::read('debug')) { + return; + } + + $trace = Debugger::trace(['start' => 0, 'depth' => 2, 'format' => 'array']); + /** @psalm-suppress PossiblyInvalidArrayOffset */ + $location = [ + 'line' => $trace[0]['line'], + 'file' => $trace[0]['file'], + ]; + + Debugger::printVar($var, $location, $showHtml); + die(1); + } +} + +if (!function_exists('breakpoint')) { + /** + * Command to return the eval-able code to startup PsySH in interactive debugger + * Works the same way as eval(\Psy\sh()); + * psy/psysh must be loaded in your project + * + * ``` + * eval(breakpoint()); + * ``` + * + * @return string|null + * @link https://psysh.org/ + */ + function breakpoint(): ?string + { + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && class_exists(PsyShell::class)) { + return 'extract(\Psy\Shell::debug(get_defined_vars(), isset($this) ? $this : null));'; + } + trigger_error( + 'psy/psysh must be installed and you must be in a CLI environment to use the breakpoint function', + E_USER_WARNING + ); + + return null; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Event/EventList.php b/app/vendor/cakephp/cakephp/src/Event/EventList.php index e8cc40c93..00be78cd2 100644 --- a/app/vendor/cakephp/cakephp/src/Event/EventList.php +++ b/app/vendor/cakephp/cakephp/src/Event/EventList.php @@ -21,6 +21,8 @@ /** * The Event List + * + * @template-implements \ArrayAccess */ class EventList implements ArrayAccess, Countable { @@ -69,7 +71,7 @@ public function offsetExists($offset): bool * * @link https://secure.php.net/manual/en/arrayaccess.offsetget.php * @param mixed $offset The offset to retrieve. - * @return mixed Can return all value types. + * @return \Cake\Event\EventInterface|null */ #[\ReturnTypeWillChange] public function offsetGet($offset) diff --git a/app/vendor/cakephp/cakephp/src/Form/Form.php b/app/vendor/cakephp/cakephp/src/Form/Form.php index 9e8122359..29f8b198b 100644 --- a/app/vendor/cakephp/cakephp/src/Form/Form.php +++ b/app/vendor/cakephp/cakephp/src/Form/Form.php @@ -23,6 +23,7 @@ use Cake\Utility\Hash; use Cake\Validation\ValidatorAwareInterface; use Cake\Validation\ValidatorAwareTrait; +use function Cake\Core\deprecationWarning; /** * Form abstraction used to create forms not tied to ORM backed models, @@ -234,6 +235,17 @@ public function getErrors(): array return $this->_errors; } + /** + * Returns validation errors for the given field + * + * @param string $field Field name to get the errors from. + * @return array The validation errors for the given field. + */ + public function getError(string $field): array + { + return $this->_errors[$field] ?? []; + } + /** * Set the errors in the form. * diff --git a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php index a8c381db3..3f2dbaf84 100644 --- a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php +++ b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php @@ -18,6 +18,7 @@ namespace Cake\Http; use Cake\Console\CommandCollection; +use Cake\Controller\ComponentRegistry; use Cake\Controller\ControllerFactory; use Cake\Core\ConsoleApplicationInterface; use Cake\Core\Container; @@ -306,6 +307,7 @@ public function handle( ): ResponseInterface { $container = $this->getContainer(); $container->add(ServerRequest::class, $request); + $container->add(ContainerInterface::class, $container); if ($this->controllerFactory === null) { $this->controllerFactory = new ControllerFactory($container); @@ -317,6 +319,9 @@ public function handle( $controller = $this->controllerFactory->create($request); + // This is needed for auto-wiring. Should be removed in 5.x + $container->add(ComponentRegistry::class, $controller->components()); + return $this->controllerFactory->invoke($controller); } } diff --git a/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php b/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php index 4ceed68e4..8289c19df 100644 --- a/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php +++ b/app/vendor/cakephp/cakephp/src/Http/CallbackStream.php @@ -40,7 +40,6 @@ public function getContents(): string { $callback = $this->detach(); $result = ''; - /** @psalm-suppress TypeDoesNotContainType */ if ($callback !== null) { $result = $callback(); } diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php index 15ee3bf21..4ec86236d 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Mock.php @@ -21,6 +21,7 @@ use Closure; use InvalidArgumentException; use Psr\Http\Message\RequestInterface; +use function Cake\Core\getTypeName; /** * Implements sending requests to an array of stubbed responses diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php index d77fb0a6d..fcddd89d0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php @@ -314,7 +314,6 @@ protected function _open(string $url, RequestInterface $request): void return true; }); try { - /** @psalm-suppress PossiblyNullArgument */ $this->_stream = fopen($url, 'rb', false, $this->_context); } finally { restore_error_handler(); diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php b/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php index 577b1b78f..41e8903c3 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Auth/Digest.php @@ -17,6 +17,8 @@ use Cake\Http\Client; use Cake\Http\Client\Request; +use Cake\Http\HeaderUtility; +use Cake\Utility\Hash; /** * Digest authentication adapter for Cake\Http\Client @@ -26,6 +28,33 @@ */ class Digest { + /** + * Algorithms + */ + public const ALGO_MD5 = 'MD5'; + public const ALGO_SHA_256 = 'SHA-256'; + public const ALGO_SHA_512_256 = 'SHA-512-256'; + public const ALGO_MD5_SESS = 'MD5-sess'; + public const ALGO_SHA_256_SESS = 'SHA-256-sess'; + public const ALGO_SHA_512_256_SESS = 'SHA-512-256-sess'; + + /** + * QOP + */ + public const QOP_AUTH = 'auth'; + public const QOP_AUTH_INT = 'auth-int'; + + /** + * Algorithms <-> Hash type + */ + public const HASH_ALGORITHMS = [ + self::ALGO_MD5 => 'md5', + self::ALGO_SHA_256 => 'sha256', + self::ALGO_SHA_512_256 => 'sha512/256', + self::ALGO_MD5_SESS => 'md5', + self::ALGO_SHA_256_SESS => 'sha256', + self::ALGO_SHA_512_256_SESS => 'sha512/256', + ]; /** * Instance of Cake\Http\Client * @@ -33,6 +62,27 @@ class Digest */ protected $_client; + /** + * Algorithm + * + * @var string + */ + protected $algorithm; + + /** + * Hash type + * + * @var string + */ + protected $hashType; + + /** + * Is Sess algorithm + * + * @var bool + */ + protected $isSessAlgorithm; + /** * Constructor * @@ -44,6 +94,24 @@ public function __construct(Client $client, ?array $options = null) $this->_client = $client; } + /** + * Set algorithm based on credentials + * + * @param array $credentials authentication params + * @return void + */ + protected function setAlgorithm(array $credentials): void + { + $algorithm = $credentials['algorithm'] ?? self::ALGO_MD5; + if (!isset(self::HASH_ALGORITHMS[$algorithm])) { + throw new \InvalidArgumentException('Invalid Algorithm. Valid ones are: ' . + implode(',', array_keys(self::HASH_ALGORITHMS))); + } + $this->algorithm = $algorithm; + $this->isSessAlgorithm = strpos($this->algorithm, '-sess') !== false; + $this->hashType = Hash::get(self::HASH_ALGORITHMS, $this->algorithm); + } + /** * Add Authorization header to the request. * @@ -63,6 +131,8 @@ public function authentication(Request $request, array $credentials): Request if (!isset($credentials['realm'])) { return $request; } + + $this->setAlgorithm($credentials); $value = $this->_generateHeader($request, $credentials); return $request->withHeader('Authorization', $value); @@ -87,25 +157,28 @@ protected function _getServerInfo(Request $request, array $credentials): array ['auth' => ['type' => null]] ); - if (!$response->getHeader('WWW-Authenticate')) { + $header = $response->getHeader('WWW-Authenticate'); + if (!$header) { return []; } - preg_match_all( - '@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', - $response->getHeaderLine('WWW-Authenticate'), - $matches, - PREG_SET_ORDER - ); - foreach ($matches as $match) { - $credentials[$match[1]] = $match[2]; - } - if (!empty($credentials['qop']) && empty($credentials['nc'])) { + $matches = HeaderUtility::parseWwwAuthenticate($header[0]); + $credentials = array_merge($credentials, $matches); + + if (($this->isSessAlgorithm || !empty($credentials['qop'])) && empty($credentials['nc'])) { $credentials['nc'] = 1; } return $credentials; } + /** + * @return string + */ + protected function generateCnonce(): string + { + return uniqid(); + } + /** * Generate the header Authorization * @@ -115,18 +188,39 @@ protected function _getServerInfo(Request $request, array $credentials): array */ protected function _generateHeader(Request $request, array $credentials): string { - $path = $request->getUri()->getPath(); - $a1 = md5($credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']); - $a2 = md5($request->getMethod() . ':' . $path); - $nc = ''; + $path = $request->getRequestTarget(); + + if ($this->isSessAlgorithm) { + $credentials['cnonce'] = $this->generateCnonce(); + $a1 = hash($this->hashType, $credentials['username'] . ':' . + $credentials['realm'] . ':' . $credentials['password']) . ':' . + $credentials['nonce'] . ':' . $credentials['cnonce']; + } else { + $a1 = $credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']; + } + $ha1 = hash($this->hashType, $a1); + $a2 = $request->getMethod() . ':' . $path; + $nc = sprintf('%08x', $credentials['nc'] ?? 1); if (empty($credentials['qop'])) { - $response = md5($a1 . ':' . $credentials['nonce'] . ':' . $a2); + $ha2 = hash($this->hashType, $a2); + $response = hash($this->hashType, $ha1 . ':' . $credentials['nonce'] . ':' . $ha2); } else { - $credentials['cnonce'] = uniqid(); - $nc = sprintf('%08x', $credentials['nc']++); - $response = md5( - $a1 . ':' . $credentials['nonce'] . ':' . $nc . ':' . $credentials['cnonce'] . ':auth:' . $a2 + if (!in_array($credentials['qop'], [self::QOP_AUTH, self::QOP_AUTH_INT])) { + throw new \InvalidArgumentException('Invalid QOP parameter. Valid types are: ' . + implode(',', [self::QOP_AUTH, self::QOP_AUTH_INT])); + } + if ($credentials['qop'] === self::QOP_AUTH_INT) { + $a2 = $request->getMethod() . ':' . $path . ':' . hash($this->hashType, (string)$request->getBody()); + } + if (empty($credentials['cnonce'])) { + $credentials['cnonce'] = $this->generateCnonce(); + } + $ha2 = hash($this->hashType, $a2); + $response = hash( + $this->hashType, + $ha1 . ':' . $credentials['nonce'] . ':' . $nc . ':' . + $credentials['cnonce'] . ':' . $credentials['qop'] . ':' . $ha2 ); } @@ -135,13 +229,19 @@ protected function _generateHeader(Request $request, array $credentials): string $authHeader .= 'realm="' . $credentials['realm'] . '", '; $authHeader .= 'nonce="' . $credentials['nonce'] . '", '; $authHeader .= 'uri="' . $path . '", '; - $authHeader .= 'response="' . $response . '"'; + $authHeader .= 'algorithm="' . $this->algorithm . '"'; + + if (!empty($credentials['qop'])) { + $authHeader .= ', qop=' . $credentials['qop']; + } + if ($this->isSessAlgorithm || !empty($credentials['qop'])) { + $authHeader .= ', nc=' . $nc . ', cnonce="' . $credentials['cnonce'] . '"'; + } + $authHeader .= ', response="' . $response . '"'; + if (!empty($credentials['opaque'])) { $authHeader .= ', opaque="' . $credentials['opaque'] . '"'; } - if (!empty($credentials['qop'])) { - $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $credentials['cnonce'] . '"'; - } return $authHeader; } diff --git a/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php b/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php index e02e78b0d..9db0c5530 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php +++ b/app/vendor/cakephp/cakephp/src/Http/ContentTypeNegotiation.php @@ -51,37 +51,7 @@ public function parseAcceptLanguage(RequestInterface $request): array */ protected function parseQualifiers(string $header): array { - $accept = []; - if (!$header) { - return $accept; - } - $headers = explode(',', $header); - foreach (array_filter($headers) as $value) { - $prefValue = '1.0'; - $value = trim($value); - - $semiPos = strpos($value, ';'); - if ($semiPos !== false) { - $params = explode(';', $value); - $value = trim($params[0]); - foreach ($params as $param) { - $qPos = strpos($param, 'q='); - if ($qPos !== false) { - $prefValue = substr($param, $qPos + 2); - } - } - } - - if (!isset($accept[$prefValue])) { - $accept[$prefValue] = []; - } - if ($prefValue) { - $accept[$prefValue][] = $value; - } - } - krsort($accept); - - return $accept; + return HeaderUtility::parseAccept($header); } /** diff --git a/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php b/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php index 4e01026b8..d5af2a37e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php +++ b/app/vendor/cakephp/cakephp/src/Http/ControllerFactory.php @@ -1,10 +1,10 @@ urldecode($name), 'value' => urldecode($value), diff --git a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php index a028433f3..966b57e9e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php +++ b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php @@ -27,12 +27,16 @@ use Psr\Http\Message\ServerRequestInterface; use Traversable; use TypeError; +use function Cake\Core\getTypeName; +use function Cake\Core\triggerWarning; /** * Cookie Collection * * Provides an immutable collection of cookies objects. Adding or removing * to a collection returns a *new* collection that you must retain. + * + * @template-implements \IteratorAggregate */ class CookieCollection implements IteratorAggregate, Countable { diff --git a/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php b/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php index 5d6b1065f..ee74d3d59 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php +++ b/app/vendor/cakephp/cakephp/src/Http/Exception/RedirectException.php @@ -16,6 +16,8 @@ */ namespace Cake\Http\Exception; +use function Cake\Core\deprecationWarning; + /** * An exception subclass used by routing and application code to * trigger a redirect. diff --git a/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php b/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php index 2df3b396e..529f602e0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php +++ b/app/vendor/cakephp/cakephp/src/Http/FlashMessage.php @@ -18,6 +18,7 @@ use Cake\Core\InstanceConfigTrait; use Throwable; +use function Cake\Core\pluginSplit; /** * The FlashMessage class provides a way for you to write a flash variable diff --git a/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php b/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php new file mode 100644 index 000000000..3242179c1 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Http/HeaderUtility.php @@ -0,0 +1,125 @@ + + */ + protected static function parseLinkItem(string $value): array + { + preg_match('/<(.*)>[; ]?[; ]?(.*)?/i', $value, $matches); + + $url = $matches[1]; + $parsedParams = ['link' => $url]; + + $params = $matches[2]; + if ($params) { + $explodedParams = explode(';', $params); + foreach ($explodedParams as $param) { + $explodedParam = explode('=', $param); + $trimedKey = trim($explodedParam[0]); + $trimedValue = trim($explodedParam[1], '"'); + if ($trimedKey === 'title*') { + // See https://www.rfc-editor.org/rfc/rfc8187#section-3.2.3 + preg_match('/(.*)\'(.*)\'(.*)/i', $trimedValue, $matches); + $trimedValue = [ + 'language' => $matches[2], + 'encoding' => $matches[1], + 'value' => urldecode($matches[3]), + ]; + } + $parsedParams[$trimedKey] = $trimedValue; + } + } + + return $parsedParams; + } + + /** + * Parse the Accept header value into weight => value mapping. + * + * @param string $header The header value to parse + * @return array> + */ + public static function parseAccept(string $header): array + { + $accept = []; + if (!$header) { + return $accept; + } + + $headers = explode(',', $header); + foreach (array_filter($headers) as $value) { + $prefValue = '1.0'; + $value = trim($value); + + $semiPos = strpos($value, ';'); + if ($semiPos !== false) { + $params = explode(';', $value); + $value = trim($params[0]); + foreach ($params as $param) { + $qPos = strpos($param, 'q='); + if ($qPos !== false) { + $prefValue = substr($param, $qPos + 2); + } + } + } + + if (!isset($accept[$prefValue])) { + $accept[$prefValue] = []; + } + if ($prefValue) { + $accept[$prefValue][] = $value; + } + } + krsort($accept); + + return $accept; + } + + /** + * @param string $value The WWW-Authenticate header + * @return array + */ + public static function parseWwwAuthenticate(string $value): array + { + preg_match_all( + '@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', + $value, + $matches, + PREG_SET_ORDER + ); + + $return = []; + foreach ($matches as $match) { + $return[$match[1]] = $match[3] ?? $match[2]; + } + + return $return; + } +} diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php index a350b24f4..a10d7b53e 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php @@ -29,6 +29,8 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Provides CSRF protection & validation. diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php index 7bf83d67b..96eec01cb 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/DoublePassDecoratorMiddleware.php @@ -21,6 +21,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use function Cake\Core\deprecationWarning; /** * Decorate double-pass middleware as PSR-15 middleware. diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php index 709cc6f10..81458e858 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php @@ -18,6 +18,7 @@ use Cake\Core\Configure; use Cake\Http\Exception\BadRequestException; +use Cake\Http\ServerRequest; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -39,6 +40,7 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface * - `statusCode` - Status code to use in case of redirect, defaults to 301 - Permanent redirect. * - `headers` - Array of response headers in case of redirect. * - `disableOnDebug` - Whether HTTPS check should be disabled when debug is on. Default `true`. + * - `trustedProxies` - Array of trusted proxies that will be passed to the request. Defaults to `null`. * - 'hsts' - Strict-Transport-Security header for HTTPS response configuration. Defaults to `null`. * If enabled, an array of config options: * @@ -53,6 +55,7 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface 'statusCode' => 301, 'headers' => [], 'disableOnDebug' => true, + 'trustedProxies' => null, 'hsts' => null, ]; @@ -80,6 +83,10 @@ public function __construct(array $config = []) */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { + if ($request instanceof ServerRequest && is_array($this->config['trustedProxies'])) { + $request->setTrustedProxies($this->config['trustedProxies']); + } + if ( $request->getUri()->getScheme() === 'https' || ($this->config['disableOnDebug'] diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php index abba6cd1a..82b2279e7 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php @@ -18,6 +18,7 @@ use ArrayAccess; use Cake\Http\Exception\InvalidCsrfTokenException; +use Cake\Http\ServerRequest; use Cake\Http\Session; use Cake\Utility\Hash; use Cake\Utility\Security; @@ -26,6 +27,7 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; +use function Cake\I18n\__d; /** * Provides CSRF protection via session based tokens. @@ -267,4 +269,24 @@ protected function validateToken(ServerRequestInterface $request, Session $sessi 'CSRF token from either the request body or request headers did not match or is missing.' )); } + + /** + * Replace the token in the provided request. + * + * Replace the token in the session and request attribute. Replacing + * tokens is a good idea during privilege escalation or privilege reduction. + * + * @param \Cake\Http\ServerRequest $request The request to update + * @param string $key The session key/attribute to set. + * @return \Cake\Http\ServerRequest An updated request. + */ + public static function replaceToken(ServerRequest $request, string $key = 'csrfToken'): ServerRequest + { + $middleware = new SessionCsrfProtectionMiddleware(['key' => $key]); + + $token = $middleware->createToken(); + $request->getSession()->write($key, $token); + + return $request->withAttribute($key, $middleware->saltToken($token)); + } } diff --git a/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php b/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php index 1069117c0..6079d8cda 100644 --- a/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php +++ b/app/vendor/cakephp/cakephp/src/Http/MiddlewareQueue.php @@ -17,6 +17,7 @@ namespace Cake\Http; use Cake\Core\App; +use Cake\Core\ContainerInterface; use Cake\Http\Middleware\ClosureDecoratorMiddleware; use Cake\Http\Middleware\DoublePassDecoratorMiddleware; use Closure; @@ -50,13 +51,20 @@ class MiddlewareQueue implements Countable, SeekableIterator */ protected $queue = []; + /** + * @var \Cake\Core\ContainerInterface|null + */ + protected $container; + /** * Constructor * * @param array $middleware The list of middleware to append. + * @param \Cake\Core\ContainerInterface $container Container instance. */ - public function __construct(array $middleware = []) + public function __construct(array $middleware = [], ?ContainerInterface $container = null) { + $this->container = $container; $this->queue = $middleware; } @@ -70,14 +78,20 @@ public function __construct(array $middleware = []) protected function resolve($middleware): MiddlewareInterface { if (is_string($middleware)) { - $className = App::className($middleware, 'Middleware', 'Middleware'); - if ($className === null) { - throw new RuntimeException(sprintf( - 'Middleware "%s" was not found.', - $middleware - )); + if ($this->container && $this->container->has($middleware)) { + $middleware = $this->container->get($middleware); + } else { + $className = App::className($middleware, 'Middleware', 'Middleware'); + if ($className === null) { + throw new RuntimeException( + sprintf( + 'Middleware "%s" was not found.', + $middleware + ) + ); + } + $middleware = new $className(); } - $middleware = new $className(); } if ($middleware instanceof MiddlewareInterface) { diff --git a/app/vendor/cakephp/cakephp/src/Http/Response.php b/app/vendor/cakephp/cakephp/src/Http/Response.php index 3feb4b4b1..d8833deaa 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Response.php +++ b/app/vendor/cakephp/cakephp/src/Http/Response.php @@ -29,6 +29,9 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use SplFileInfo; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; +use function Cake\I18n\__d; /** * Responses contain the response text, status and headers of a HTTP response. @@ -1387,9 +1390,9 @@ public function withCookieCollection(CookieCollection $cookieCollection) public function cors(ServerRequest $request): CorsBuilder { $origin = $request->getHeaderLine('Origin'); - $ssl = $request->is('ssl'); + $https = $request->is('https'); - return new CorsBuilder($this, $origin, $ssl); + return new CorsBuilder($this, $origin, $https); } /** diff --git a/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php b/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php index 2dac3d4ca..0cbb23c6f 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php +++ b/app/vendor/cakephp/cakephp/src/Http/ResponseEmitter.php @@ -232,7 +232,6 @@ protected function setCookie($cookie): bool } if (PHP_VERSION_ID >= 70300) { - /** @psalm-suppress InvalidArgument */ return setcookie($cookie->getName(), $cookie->getScalarValue(), $cookie->getOptions()); } diff --git a/app/vendor/cakephp/cakephp/src/Http/Server.php b/app/vendor/cakephp/cakephp/src/Http/Server.php index fe90d51f0..ea9cf5973 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Server.php +++ b/app/vendor/cakephp/cakephp/src/Http/Server.php @@ -16,6 +16,7 @@ */ namespace Cake\Http; +use Cake\Core\ContainerApplicationInterface; use Cake\Core\HttpApplicationInterface; use Cake\Core\PluginApplicationInterface; use Cake\Event\EventDispatcherInterface; @@ -80,7 +81,15 @@ public function run( $request = $request ?: ServerRequestFactory::fromGlobals(); - $middleware = $this->app->middleware($middlewareQueue ?? new MiddlewareQueue()); + if ($middlewareQueue === null) { + if ($this->app instanceof ContainerApplicationInterface) { + $middlewareQueue = new MiddlewareQueue([], $this->app->getContainer()); + } else { + $middlewareQueue = new MiddlewareQueue(); + } + } + + $middleware = $this->app->middleware($middlewareQueue); if ($this->app instanceof PluginApplicationInterface) { $middleware = $this->app->pluginMiddleware($middleware); } diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php index eaf661177..cd63b5375 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php @@ -30,6 +30,8 @@ use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UriInterface; +use function Cake\Core\deprecationWarning; +use function Cake\Core\env; /** * A class that helps wrap Request information and particulars about a single request. @@ -127,6 +129,7 @@ class ServerRequest implements ServerRequestInterface 'head' => ['env' => 'REQUEST_METHOD', 'value' => 'HEAD'], 'options' => ['env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'], 'ssl' => ['env' => 'HTTPS', 'options' => [1, 'on']], + 'https' => ['env' => 'HTTPS', 'options' => [1, 'on']], 'ajax' => ['env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'], 'json' => ['accept' => ['application/json'], 'param' => '_ext', 'value' => 'json'], 'xml' => [ @@ -485,6 +488,7 @@ public function __call(string $name, array $params) * this method will return true if the request matches any type. * @param mixed ...$args List of arguments * @return bool Whether the request is the type you are checking. + * @throws \InvalidArgumentException If no detector has been set for the provided type. */ public function is($type, ...$args): bool { @@ -500,7 +504,7 @@ public function is($type, ...$args): bool $type = strtolower($type); if (!isset(static::$_detectors[$type])) { - return false; + throw new InvalidArgumentException("No detector set for type `{$type}`"); } if ($args) { return $this->_is($type, $args); @@ -528,6 +532,9 @@ public function clearDetectorCache(): void */ protected function _is(string $type, array $args): bool { + if ($type === 'ssl') { + deprecationWarning('The `ssl` detector is deprecated. Use `https` instead.'); + } $detect = static::$_detectors[$type]; if (is_callable($detect)) { array_unshift($args, $this); @@ -1792,7 +1799,6 @@ public function withUri(UriInterface $uri, $preserveHost = false) * request-target forms allowed in request messages) * @param string $requestTarget The request target. * @return static - * @psalm-suppress MoreSpecificImplementedParamType */ public function withRequestTarget($requestTarget) { diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php index fe6e4f9f4..a4e48d07d 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php @@ -71,7 +71,6 @@ public static function fromGlobals( $uri->getUri(); } - /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', 'cookiePath' => $webroot, diff --git a/app/vendor/cakephp/cakephp/src/Http/Session.php b/app/vendor/cakephp/cakephp/src/Http/Session.php index d9a88e35e..c3cf9ae07 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Session.php +++ b/app/vendor/cakephp/cakephp/src/Http/Session.php @@ -23,6 +23,7 @@ use InvalidArgumentException; use RuntimeException; use SessionHandlerInterface; +use function Cake\Core\env; /** * This class is a wrapper for the native PHP session functions. It provides @@ -526,7 +527,6 @@ public function write($name, $value = null): void $data = Hash::insert($data, $key, $val); } - /** @psalm-suppress PossiblyNullArgument */ $this->_overwrite($_SESSION, $data); } diff --git a/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php b/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php index 0c5f75b15..d4281d2d0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php +++ b/app/vendor/cakephp/cakephp/src/Http/TestSuite/HttpClientTrait.php @@ -115,3 +115,10 @@ public function mockClientDelete(string $url, Response $response, array $options Client::addMockResponse('DELETE', $url, $response, $options); } } + +// phpcs:disable +class_alias( + 'Cake\Http\TestSuite\HttpClientTrait', + 'Cake\TestSuite\HttpClientTrait' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/I18n/Date.php b/app/vendor/cakephp/cakephp/src/I18n/Date.php index 3dcc47eb2..9678bfdeb 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Date.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Date.php @@ -18,6 +18,7 @@ use Cake\Chronos\MutableDate; use IntlDateFormatter; +use function Cake\Core\deprecationWarning; /** * Extends the Date class provided by Chronos. diff --git a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php index bd23d8cb5..942ce1a30 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php +++ b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php @@ -190,7 +190,7 @@ public function i18nFormat($format = null, $timezone = null, $locale = null) if ($timezone) { // Handle the immutable and mutable object cases. $time = clone $this; - $time = $time->timezone($timezone); + $time = $time->setTimezone($timezone); } $format = $format ?? static::$_toStringFormat; diff --git a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php index 4596bb0ea..84d11f1cd 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php +++ b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php @@ -16,7 +16,7 @@ */ namespace Cake\I18n; -use Cake\Chronos\Date as ChronosDate; +use Cake\Chronos\ChronosDate; use IntlDateFormatter; /** diff --git a/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php b/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php index e3993d9f5..2d02ab18c 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php +++ b/app/vendor/cakephp/cakephp/src/I18n/MessagesFileLoader.php @@ -21,6 +21,7 @@ use Cake\Utility\Inflector; use Locale; use RuntimeException; +use function Cake\Core\pluginSplit; /** * A generic translations package factory that will load translations files @@ -37,6 +38,13 @@ class MessagesFileLoader */ protected $_name; + /** + * The package (domain) plugin + * + * @var string|null + */ + protected $_plugin; + /** * The locale to load for the given package. * @@ -93,6 +101,13 @@ class MessagesFileLoader public function __construct(string $name, string $locale, string $extension = 'po') { $this->_name = $name; + // If space is not added after slash, the character after it remains lowercased + $pluginName = Inflector::camelize(str_replace('/', '/ ', $this->_name)); + if (strpos($this->_name, '.')) { + [$this->_plugin, $this->_name] = pluginSplit($pluginName); + } elseif (Plugin::isLoaded($pluginName)) { + $this->_plugin = $pluginName; + } $this->_locale = $locale; $this->_extension = $extension; } @@ -169,10 +184,8 @@ public function translationsFolders(): array } } - // If space is not added after slash, the character after it remains lowercased - $pluginName = Inflector::camelize(str_replace('/', '/ ', $this->_name)); - if (Plugin::isLoaded($pluginName)) { - $basePath = App::path('locales', $pluginName)[0]; + if ($this->_plugin && Plugin::isLoaded($this->_plugin)) { + $basePath = App::path('locales', $this->_plugin)[0]; foreach ($folders as $folder) { $searchPaths[] = $basePath . $folder . DIRECTORY_SEPARATOR; } diff --git a/app/vendor/cakephp/cakephp/src/I18n/Number.php b/app/vendor/cakephp/cakephp/src/I18n/Number.php index accd550b0..ccc224f33 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Number.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Number.php @@ -17,6 +17,7 @@ namespace Cake\I18n; use NumberFormatter; +use function Cake\Core\deprecationWarning; /** * Number helper library. @@ -85,7 +86,7 @@ class Number * * - `locale`: The locale name to use for formatting the number, e.g. fr_FR * - * @param string|float $value A floating point number. + * @param string|float|int $value A floating point number. * @param int $precision The precision of the returned number. * @param array $options Additional options * @return string Formatted float. @@ -101,7 +102,7 @@ public static function precision($value, int $precision = 3, array $options = [] /** * Returns a formatted-for-humans file size. * - * @param string|int $size Size in bytes + * @param string|float|int $size Size in bytes * @return string Human readable size * @link https://book.cakephp.org/4/en/core-libraries/number.html#interacting-with-human-readable-values */ @@ -131,7 +132,7 @@ public static function toReadableSize($size): string * - `multiply`: Multiply the input value by 100 for decimal percentages. * - `locale`: The locale name to use for formatting the number, e.g. fr_FR * - * @param string|float $value A floating point number + * @param string|float|int $value A floating point number * @param int $precision The precision of the returned number * @param array $options Options * @return string Percentage string diff --git a/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php b/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php index a3b195923..e4aa46270 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Parser/PoFileParser.php @@ -94,7 +94,6 @@ public function parse(string $resource): array } elseif (substr($line, 0, 7) === 'msgid "') { // We start a new msg so save previous $this->_addMessage($messages, $item); - /** @psalm-suppress InvalidArrayOffset */ $item['ids']['singular'] = substr($line, 7, -1); $stage = ['ids', 'singular']; } elseif (substr($line, 0, 8) === 'msgstr "') { @@ -124,7 +123,6 @@ public function parse(string $resource): array break; } } elseif (substr($line, 0, 14) === 'msgid_plural "') { - /** @psalm-suppress InvalidArrayOffset */ $item['ids']['plural'] = substr($line, 14, -1); $stage = ['ids', 'plural']; } elseif (substr($line, 0, 7) === 'msgstr[') { diff --git a/app/vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php b/app/vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php index ffc18a5b0..7615507f5 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php +++ b/app/vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php @@ -101,7 +101,7 @@ public function timeAgoInWords(I18nDateTimeInterface $time, array $options = []) { $options = $this->_options($options, FrozenTime::class); if ($options['timezone']) { - $time = $time->timezone($options['timezone']); + $time = $time->setTimezone($options['timezone']); } $now = $options['from']->format('U'); @@ -323,7 +323,7 @@ public function dateAgoInWords(I18nDateTimeInterface $date, array $options = []) { $options = $this->_options($options, FrozenDate::class); if ($options['timezone']) { - $date = $date->timezone($options['timezone']); + $date = $date->setTimezone($options['timezone']); } $now = $options['from']->format('U'); diff --git a/app/vendor/cakephp/cakephp/src/I18n/Time.php b/app/vendor/cakephp/cakephp/src/I18n/Time.php index 9528e9de3..9209418cc 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Time.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Time.php @@ -20,6 +20,7 @@ use DateTimeInterface; use DateTimeZone; use IntlDateFormatter; +use function Cake\Core\deprecationWarning; /** * Extends the built-in DateTime class to provide handy methods and locale-aware diff --git a/app/vendor/cakephp/cakephp/src/I18n/functions.php b/app/vendor/cakephp/cakephp/src/I18n/functions.php index 45f17250f..3295049ad 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/functions.php +++ b/app/vendor/cakephp/cakephp/src/I18n/functions.php @@ -14,240 +14,221 @@ * @since 3.0.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +namespace Cake\I18n; -use Cake\I18n\I18n; - +// phpcs:disable PSR1.Files.SideEffects // Backwards compatibility alias for custom translation messages loaders which return a Package instance. -// phpcs:disable if (!class_exists('Aura\Intl\Package')) { class_alias('Cake\I18n\Package', 'Aura\Intl\Package'); } -// phpcs:enable - -if (!function_exists('__')) { - /** - * Returns a translated string if one is found; Otherwise, the submitted message. - * - * @param string $singular Text to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string The translated text. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__ - */ - function __(string $singular, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate($singular, $args); + +/** + * Returns a translated string if one is found; Otherwise, the submitted message. + * + * @param string $singular Text to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string The translated text. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__ + */ +function __(string $singular, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate($singular, $args); } -if (!function_exists('__n')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Some languages have more than one form for plural messages dependent on the count. - * - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__n - */ - function __n(string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate( - $plural, - ['_count' => $count, '_singular' => $singular] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Some languages have more than one form for plural messages dependent on the count. + * + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__n + */ +function __n(string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate( + $plural, + ['_count' => $count, '_singular' => $singular] + $args + ); } -if (!function_exists('__d')) { - /** - * Allows you to override the current domain for a single message lookup. - * - * @param string $domain Domain. - * @param string $msg String to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__d - */ - function __d(string $domain, string $msg, ...$args): string - { - if (!$msg) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate($msg, $args); +/** + * Allows you to override the current domain for a single message lookup. + * + * @param string $domain Domain. + * @param string $msg String to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__d + */ +function __d(string $domain, string $msg, ...$args): string +{ + if (!$msg) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate($msg, $args); } -if (!function_exists('__dn')) { - /** - * Allows you to override the current domain for a single plural message lookup. - * Returns correct plural form of message identified by $singular and $plural for count $count - * from domain $domain. - * - * @param string $domain Domain. - * @param string $singular Singular string to translate. - * @param string $plural Plural. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dn - */ - function __dn(string $domain, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $plural, - ['_count' => $count, '_singular' => $singular] + $args - ); +/** + * Allows you to override the current domain for a single plural message lookup. + * Returns correct plural form of message identified by $singular and $plural for count $count + * from domain $domain. + * + * @param string $domain Domain. + * @param string $singular Singular string to translate. + * @param string $plural Plural. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dn + */ +function __dn(string $domain, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $plural, + ['_count' => $count, '_singular' => $singular] + $args + ); } -if (!function_exists('__x')) { - /** - * Returns a translated string if one is found; Otherwise, the submitted message. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $context Context of the text. - * @param string $singular Text to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__x - */ - function __x(string $context, string $singular, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate($singular, ['_context' => $context] + $args); +/** + * Returns a translated string if one is found; Otherwise, the submitted message. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $context Context of the text. + * @param string $singular Text to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__x + */ +function __x(string $context, string $singular, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate($singular, ['_context' => $context] + $args); } -if (!function_exists('__xn')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Some languages have more than one form for plural messages dependent on the count. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $context Context of the text. - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__xn - */ - function __xn(string $context, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator()->translate( - $plural, - ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Some languages have more than one form for plural messages dependent on the count. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $context Context of the text. + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__xn + */ +function __xn(string $context, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator()->translate( + $plural, + ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args + ); } -if (!function_exists('__dx')) { - /** - * Allows you to override the current domain for a single message lookup. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $domain Domain. - * @param string $context Context of the text. - * @param string $msg String to translate. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dx - */ - function __dx(string $domain, string $context, string $msg, ...$args): string - { - if (!$msg) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $msg, - ['_context' => $context] + $args - ); +/** + * Allows you to override the current domain for a single message lookup. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $domain Domain. + * @param string $context Context of the text. + * @param string $msg String to translate. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dx + */ +function __dx(string $domain, string $context, string $msg, ...$args): string +{ + if (!$msg) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $msg, + ['_context' => $context] + $args + ); } -if (!function_exists('__dxn')) { - /** - * Returns correct plural form of message identified by $singular and $plural for count $count. - * Allows you to override the current domain for a single message lookup. - * The context is a unique identifier for the translations string that makes it unique - * within the same domain. - * - * @param string $domain Domain. - * @param string $context Context of the text. - * @param string $singular Singular text to translate. - * @param string $plural Plural text. - * @param int $count Count. - * @param mixed ...$args Array with arguments or multiple arguments in function. - * @return string Plural form of translated string. - * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dxn - */ - function __dxn(string $domain, string $context, string $singular, string $plural, int $count, ...$args): string - { - if (!$singular) { - return ''; - } - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - - return I18n::getTranslator($domain)->translate( - $plural, - ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args - ); +/** + * Returns correct plural form of message identified by $singular and $plural for count $count. + * Allows you to override the current domain for a single message lookup. + * The context is a unique identifier for the translations string that makes it unique + * within the same domain. + * + * @param string $domain Domain. + * @param string $context Context of the text. + * @param string $singular Singular text to translate. + * @param string $plural Plural text. + * @param int $count Count. + * @param mixed ...$args Array with arguments or multiple arguments in function. + * @return string Plural form of translated string. + * @link https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#__dxn + */ +function __dxn(string $domain, string $context, string $singular, string $plural, int $count, ...$args): string +{ + if (!$singular) { + return ''; + } + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; } + return I18n::getTranslator($domain)->translate( + $plural, + ['_count' => $count, '_singular' => $singular, '_context' => $context] + $args + ); +} + +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; } diff --git a/app/vendor/cakephp/cakephp/src/I18n/functions_global.php b/app/vendor/cakephp/cakephp/src/I18n/functions_global.php new file mode 100644 index 000000000..94e48d381 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/I18n/functions_global.php @@ -0,0 +1,174 @@ + @@ -54,6 +55,7 @@ class FileLog extends BaseLog 'rotate' => 10, 'size' => 10485760, // 10MB 'mask' => null, + 'dirMask' => 0770, 'formatter' => [ 'className' => DefaultFormatter::class, ], @@ -90,8 +92,8 @@ public function __construct(array $config = []) parent::__construct($config); $this->_path = $this->getConfig('path', sys_get_temp_dir() . DIRECTORY_SEPARATOR); - if (Configure::read('debug') && !is_dir($this->_path)) { - mkdir($this->_path, 0775, true); + if (!is_dir($this->_path)) { + mkdir($this->_path, $this->_config['dirMask'], true); } if (!empty($this->_config['file'])) { diff --git a/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php b/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php index 1e48d0d52..5f8c6d342 100644 --- a/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php +++ b/app/vendor/cakephp/cakephp/src/Log/Engine/SyslogLog.php @@ -18,6 +18,7 @@ use Cake\Log\Formatter\DefaultFormatter; use Cake\Log\Formatter\LegacySyslogFormatter; +use function Cake\Core\deprecationWarning; /** * Syslog stream for Logging. Writes logs to the system logger diff --git a/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php b/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php index 113f67002..535ade03f 100644 --- a/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php +++ b/app/vendor/cakephp/cakephp/src/Log/LogEngineRegistry.php @@ -20,6 +20,7 @@ use Cake\Core\ObjectRegistry; use Psr\Log\LoggerInterface; use RuntimeException; +use function Cake\Core\getTypeName; /** * Registry of loaded log engines @@ -79,7 +80,6 @@ protected function _create($class, string $alias, array $config): LoggerInterfac } if (!isset($instance)) { - /** @psalm-suppress UndefinedClass */ $instance = new $class($config); } diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php index ce1b87fab..1cd89c23f 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php @@ -24,6 +24,7 @@ use Cake\ORM\Locator\LocatorAwareTrait; use Cake\View\ViewBuilder; use InvalidArgumentException; +use function Cake\Core\deprecationWarning; /** * Mailer base class. diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Message.php b/app/vendor/cakephp/cakephp/src/Mailer/Message.php index 9b51be0e1..78ae98a62 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Message.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Message.php @@ -28,6 +28,7 @@ use Psr\Http\Message\UploadedFileInterface; use Serializable; use SimpleXMLElement; +use function Cake\Core\env; /** * Email message class. @@ -301,6 +302,18 @@ class Message implements JsonSerializable, Serializable */ protected $emailPattern = self::EMAIL_PATTERN; + /** + * Properties that could be serialized + * + * @var array + */ + protected $serializableProperties = [ + 'to', 'from', 'sender', 'replyTo', 'cc', 'bcc', 'subject', + 'returnPath', 'readReceipt', 'emailFormat', 'emailPattern', 'domain', + 'attachments', 'messageId', 'headers', 'appCharset', 'charset', 'headerCharset', + 'textMessage', 'htmlMessage', + ]; + /** * Constructor * @@ -999,8 +1012,8 @@ protected function formatAddress(array $address): array $return[] = $email; } else { $encoded = $this->encodeForHeader($alias); - if ($encoded === $alias && preg_match('/[^a-z0-9 ]/i', $encoded)) { - $encoded = '"' . str_replace('"', '\"', $encoded) . '"'; + if (preg_match('/[^a-z0-9+\-\\=? ]/i', $encoded)) { + $encoded = '"' . addcslashes($encoded, '"\\') . '"'; } $return[] = sprintf('%s <%s>', $encoded, $email); } @@ -1151,7 +1164,7 @@ public function getDomain(): string * ``` * * The `contentId` key allows you to specify an inline attachment. In your email text, you - * can use `` to display the image inline. + * can use `` to display the image inline. * * The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve * attachment compatibility with outlook email clients. @@ -1849,15 +1862,8 @@ public function getContentTypeCharset(): string */ public function jsonSerialize(): array { - $properties = [ - 'to', 'from', 'sender', 'replyTo', 'cc', 'bcc', 'subject', - 'returnPath', 'readReceipt', 'emailFormat', 'emailPattern', 'domain', - 'attachments', 'messageId', 'headers', 'appCharset', 'charset', 'headerCharset', - 'textMessage', 'htmlMessage', - ]; - $array = []; - foreach ($properties as $property) { + foreach ($this->serializableProperties as $property) { $array[$property] = $this->{$property}; } diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php b/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php index 2c394309f..32cef1f86 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Renderer.php @@ -18,6 +18,7 @@ use Cake\View\View; use Cake\View\ViewVarsTrait; +use function Cake\Core\pluginSplit; /** * Class for rendering email message. diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php index 0e6409eed..428316b47 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php @@ -23,6 +23,7 @@ use Cake\Network\Socket; use Exception; use RuntimeException; +use function Cake\Core\env; /** * Send mail using SMTP protocol diff --git a/app/vendor/cakephp/cakephp/src/Network/Socket.php b/app/vendor/cakephp/cakephp/src/Network/Socket.php index e94d8eab9..bfcdbc14f 100644 --- a/app/vendor/cakephp/cakephp/src/Network/Socket.php +++ b/app/vendor/cakephp/cakephp/src/Network/Socket.php @@ -23,6 +23,7 @@ use Composer\CaBundle\CaBundle; use Exception; use InvalidArgumentException; +use function Cake\Core\deprecationWarning; /** * CakePHP network socket connection class. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association.php b/app/vendor/cakephp/cakephp/src/ORM/Association.php index 9621dd2c4..8601283b7 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association.php @@ -29,6 +29,8 @@ use Closure; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\pluginSplit; /** * An Association is a relationship established between two tables and is used diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php index 1950b2568..ad2294482 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsTo.php @@ -24,6 +24,7 @@ use Cake\Utility\Inflector; use Closure; use RuntimeException; +use function Cake\Core\pluginSplit; /** * Represents an 1 - N relationship where the source side of the relation is diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php index f43402258..8c95cbc75 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php @@ -1206,7 +1206,7 @@ function () use ($sourceEntity, $targetEntities, $primaryValue, $options) { // Create a subquery join to ensure we get // the correct entity passed to callbacks. - $existing = $junction->query() + $existing = $junction->selectQuery() ->from([$junctionQueryAlias => $matches]) ->innerJoin( [$junction->getAlias() => $junction->getTable()], diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php b/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php index b48ea7213..746caddfc 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/HasOne.php @@ -22,6 +22,7 @@ use Cake\ORM\Table; use Cake\Utility\Inflector; use Closure; +use function Cake\Core\pluginSplit; /** * Represents an 1 - 1 relationship where the source side of the relation is diff --git a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php index 9e9e9c0d1..9f213145a 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php +++ b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php @@ -23,12 +23,16 @@ use InvalidArgumentException; use IteratorAggregate; use Traversable; +use function Cake\Core\namespaceSplit; +use function Cake\Core\pluginSplit; /** * A container/collection for association classes. * * Contains methods for managing associations, and * ordering operations around saving and deleting. + * + * @template-implements \IteratorAggregate */ class AssociationCollection implements IteratorAggregate { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior.php index 31ab1f295..485770880 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior.php @@ -21,6 +21,7 @@ use Cake\Event\EventListenerInterface; use ReflectionClass; use ReflectionMethod; +use function Cake\Core\deprecationWarning; /** * Base class for behaviors. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php index 3284c3dc1..2408090b1 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php @@ -27,6 +27,7 @@ use Cake\ORM\Query; use Cake\ORM\Table; use Cake\Utility\Hash; +use function Cake\Core\pluginSplit; /** * This class provides a way to translate dynamic data by keeping translations @@ -266,7 +267,6 @@ function ($c, &$field) use ($fields, $alias, $mainTableAlias, $mainTableFields, return $c; } - /** @psalm-suppress ParadoxicalCondition */ if (in_array($field, $fields, true)) { $joinRequired = true; $field = "$alias.$field"; @@ -323,7 +323,6 @@ function ($expression) use ($fields, $alias, $mainTableAlias, $mainTableFields, return; } - /** @psalm-suppress ParadoxicalCondition */ if (in_array($field, $mainTableFields, true)) { $expression->setField("$mainTableAlias.$field"); } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php index dc0df6671..576ea8909 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TranslateBehavior.php @@ -25,6 +25,7 @@ use Cake\ORM\Query; use Cake\ORM\Table; use Cake\Utility\Inflector; +use function Cake\Core\namespaceSplit; /** * This behavior provides a way to translate dynamic data by keeping translations diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php index b009d0d52..493bea37d 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php @@ -18,6 +18,7 @@ use Cake\Collection\CollectionInterface; use Cake\Database\Expression\IdentifierExpression; +use Cake\Database\Expression\QueryExpression; use Cake\Datasource\EntityInterface; use Cake\Datasource\Exception\RecordNotFoundException; use Cake\Event\EventInterface; @@ -227,20 +228,24 @@ public function beforeDelete(EventInterface $event, EntityInterface $entity) $diff = $right - $left + 1; if ($diff > 2) { - $query = $this->_scope($this->_table->query()) - ->where(function ($exp) use ($config, $left, $right) { - /** @var \Cake\Database\Expression\QueryExpression $exp */ - return $exp - ->gte($config['leftField'], $left + 1) - ->lte($config['leftField'], $right - 1); - }); if ($this->getConfig('cascadeCallbacks')) { + $query = $this->_scope($this->_table->selectQuery()) + ->where(function (QueryExpression $exp) use ($config, $left, $right) { + return $exp + ->gte($config['leftField'], $left + 1) + ->lte($config['leftField'], $right - 1); + }); $entities = $query->toArray(); foreach ($entities as $entityToDelete) { $this->_table->delete($entityToDelete, ['atomic' => false]); } } else { - $query->delete(); + $query = $this->_scope($this->_table->deleteQuery()) + ->where(function (QueryExpression $exp) use ($config, $left, $right) { + return $exp + ->gte($config['leftField'], $left + 1) + ->lte($config['leftField'], $right - 1); + }); $statement = $query->execute(); $statement->closeCursor(); } @@ -848,7 +853,7 @@ protected function _recoverTree(int $lftRght = 1, $parentId = null, $level = 0): $primaryKey = $this->_getPrimaryKey(); $order = $config['recoverOrder'] ?: $primaryKey; - $nodes = $this->_scope($this->_table->query()) + $nodes = $this->_scope($this->_table->selectQuery()) ->select($primaryKey) ->where([$parent . ' IS' => $parentId]) ->order($order) @@ -911,7 +916,7 @@ protected function _sync(int $shift, string $dir, string $conditions, bool $mark $config = $this->_config; foreach ([$config['leftField'], $config['rightField']] as $field) { - $query = $this->_scope($this->_table->query()); + $query = $this->_scope($this->_table->updateQuery()); $exp = $query->newExpr(); $movement = clone $exp; @@ -925,10 +930,7 @@ protected function _sync(int $shift, string $dir, string $conditions, bool $mark $where = clone $exp; $where->add($field)->add($conditions)->setConjunction(''); - $query->update() - ->set($exp->eq($field, $movement)) - ->where($where); - + $query->set($exp->eq($field, $movement))->where($where); $query->execute()->closeCursor(); } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php index 1778c32de..d4fa10a25 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php @@ -630,7 +630,7 @@ public function loadExternal(Query $query, StatementInterface $statement): State return $statement; } - $driver = $query->getConnection()->getDriver(); + $driver = $query->getConnection()->getDriver($query->getConnectionRole()); [$collected, $statement] = $this->_collectKeys($external, $query, $statement); // No records found, skip trying to attach associations. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php index 67a875201..3fefe3f40 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php @@ -25,6 +25,7 @@ use Cake\ORM\Table; use Cake\Utility\Inflector; use RuntimeException; +use function Cake\Core\pluginSplit; /** * Provides a default registry/factory for Table objects. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php index 7511aafa4..2caa7e573 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php @@ -26,6 +26,8 @@ use Cake\Utility\Hash; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; /** * Contains logic to convert array data into entities. @@ -659,7 +661,6 @@ public function merge(EntityInterface $entity, array $data, array $options = []) * @param array $options List of options. * @return array<\Cake\Datasource\EntityInterface> * @see \Cake\ORM\Entity::$_accessible - * @psalm-suppress NullArrayOffset */ public function mergeMany(iterable $entities, array $data, array $options = []): array { @@ -755,7 +756,6 @@ protected function _mergeAssociation($original, Association $assoc, $value, arra $types = [Association::ONE_TO_ONE, Association::MANY_TO_ONE]; $type = $assoc->type(); if (in_array($type, $types, true)) { - /** @psalm-suppress PossiblyInvalidArgument, ArgumentTypeCoercion */ return $marshaller->merge($original, $value, $options); } if ($type === Association::MANY_TO_MANY) { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query.php b/app/vendor/cakephp/cakephp/src/ORM/Query.php index 7ba368007..3f40d5b6f 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Query.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Query.php @@ -31,6 +31,7 @@ use JsonSerializable; use RuntimeException; use Traversable; +use function Cake\Core\deprecationWarning; /** * Extends the base Query class to provide new methods related to association @@ -51,28 +52,28 @@ * @method \Cake\Collection\CollectionInterface map(callable $c) Modifies each of the results using the callable * @method mixed reduce(callable $c, $zero = null) Folds all the results into a single value using the callable. * @method \Cake\Collection\CollectionInterface extract($field) Extracts a single column from each row - * @method mixed max($field) Returns the maximum value for a single column in all the results. - * @method mixed min($field) Returns the minimum value for a single column in all the results. + * @method mixed max($field, $sort = \SORT_NUMERIC) Returns the maximum value for a single column in all the results. + * @method mixed min($field, $sort = \SORT_NUMERIC) Returns the minimum value for a single column in all the results. * @method \Cake\Collection\CollectionInterface groupBy(callable|string $field) In-memory group all results by the value of a column. * @method \Cake\Collection\CollectionInterface indexBy(callable|string $callback) Returns the results indexed by the value of a column. * @method \Cake\Collection\CollectionInterface countBy(callable|string $field) Returns the number of unique values for a column - * @method float sumOf(callable|string $field) Returns the sum of all values for a single column + * @method int|float sumOf($field = null) Returns the sum of all values for a single column * @method \Cake\Collection\CollectionInterface shuffle() In-memory randomize the order the results are returned * @method \Cake\Collection\CollectionInterface sample(int $size = 10) In-memory shuffle the results and return a subset of them. * @method \Cake\Collection\CollectionInterface take(int $size = 1, int $from = 0) In-memory limit and offset for the query results. * @method \Cake\Collection\CollectionInterface skip(int $howMany) Skips some rows from the start of the query result. * @method mixed last() Return the last row of the query result - * @method \Cake\Collection\CollectionInterface append(array|\Traversable $items) Appends more rows to the result of the query. + * @method \Cake\Collection\CollectionInterface append(mixed $items) Appends more rows to the result of the query. * @method \Cake\Collection\CollectionInterface combine($k, $v, $g = null) Returns the values of the column $v index by column $k, * and grouped by $g. * @method \Cake\Collection\CollectionInterface nest($k, $p, $n = 'children') Creates a tree structure by nesting the values of column $p into that * with the same value for $k using $n as the nesting key. * @method array toArray() Returns a key-value array with the results of this query. * @method array toList() Returns a numerically indexed array with the results of this query. - * @method \Cake\Collection\CollectionInterface stopWhen(callable $c) Returns each row until the callable returns true. - * @method \Cake\Collection\CollectionInterface zip(array|\Traversable $c) Returns the first result of both the query and $c in an array, + * @method \Cake\Collection\CollectionInterface stopWhen(callable|array $c) Returns each row until the callable returns true. + * @method \Cake\Collection\CollectionInterface zip(iterable $c) Returns the first result of both the query and $c in an array, * then the second results and so on. - * @method \Cake\Collection\CollectionInterface zipWith($collections, callable $callable) Returns each of the results out of calling $c + * @method \Cake\Collection\CollectionInterface zipWith(iterable $collections, callable $callable) Returns each of the results out of calling $c * with the first rows of the query and each of the items, then the second rows and so on. * @method \Cake\Collection\CollectionInterface chunk(int $size) Groups the results in arrays of $size rows each. * @method bool isEmpty() Returns true if this query found no results. @@ -178,7 +179,7 @@ class Query extends DatabaseQuery implements JsonSerializable, QueryInterface public function __construct(Connection $connection, Table $table) { parent::__construct($connection); - $this->repository($table); + $this->setRepository($table); if ($this->_repository !== null) { $this->addDefaultTypes($this->_repository); @@ -242,6 +243,24 @@ public function select($fields = [], bool $overwrite = false) return parent::select($fields, $overwrite); } + /** + * Behaves the exact same as `select()` except adds the field to the list of fields selected and + * does not disable auto-selecting fields for Associations. + * + * Use this instead of calling `select()` then `enableAutoFields()` to re-enable auto-fields. + * + * @param \Cake\Database\ExpressionInterface|\Cake\ORM\Table|\Cake\ORM\Association|callable|array|string $fields Fields + * to be added to the list. + * @return $this + */ + public function selectAlso($fields) + { + $this->select($fields); + $this->_autoFields = true; + + return $this; + } + /** * All the fields associated with the passed table except the excluded * fields will be added to the select clause of the query. Passed excluded fields should not be aliased. @@ -977,8 +996,8 @@ protected function _performCount(): int ->disableAutoFields() ->execute(); } else { - $statement = $this->getConnection()->newQuery() - ->select($count) + $statement = $this->getConnection() + ->selectQuery($count) ->from(['count_source' => $query]) ->execute(); } @@ -1440,4 +1459,19 @@ protected function _decorateResults(Traversable $result): ResultSetInterface return $result; } + + /** + * Helper for ORM\Query exceptions + * + * @param string $method The method that is invalid. + * @param string $message An additional message. + * @return void + * @internal + */ + protected function _deprecatedMethod($method, $message = '') + { + $class = static::class; + $text = "As of 4.5.0 calling {$method}() on {$class} is deprecated. " . $message; + deprecationWarning($text); + } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php new file mode 100644 index 000000000..40470210e --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/DeleteQuery.php @@ -0,0 +1,337 @@ +_type === 'delete' && empty($this->_parts['from'])) { + $repository = $this->getRepository(); + $this->from([$repository->getAlias() => $repository->getTable()]); + } + + return parent::sql($binder); + } + + /** + * @inheritDoc + */ + public function delete(?string $table = null) + { + $this->_deprecatedMethod('delete()', 'Remove this method call.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function join($tables, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('join()'); + + return parent::join($tables, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function removeJoin(string $name) + { + $this->_deprecatedMethod('removeJoin()'); + + return parent::removeJoin($name); + } + + /** + * @inheritDoc + */ + public function leftJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('leftJoin()'); + + return parent::leftJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function rightJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('rightJoin()'); + + return parent::rightJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function leftJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('leftJoinWith()'); + + return parent::leftJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function innerJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('innerJoin()'); + + return parent::innerJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function innerJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('innerJoinWith()'); + + return parent::innerJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use from() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php new file mode 100644 index 000000000..6c3462f97 --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/InsertQuery.php @@ -0,0 +1,413 @@ +_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function join($tables, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('join()'); + + return parent::join($tables, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function removeJoin(string $name) + { + $this->_deprecatedMethod('removeJoin()'); + + return parent::removeJoin($name); + } + + /** + * @inheritDoc + */ + public function leftJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('leftJoin()'); + + return parent::leftJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function rightJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('rightJoin()'); + + return parent::rightJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function leftJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('leftJoinWith()'); + + return parent::leftJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function innerJoin($table, $conditions = [], $types = []) + { + $this->_deprecatedMethod('innerJoin()'); + + return parent::innerJoin($table, $conditions, $types); + } + + /** + * @inheritDoc + */ + public function innerJoinWith(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('innerJoinWith()'); + + return parent::innerJoinWith($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function offset($offset) + { + $this->_deprecatedMethod('offset()'); + + return parent::offset($offset); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function from($tables = [], $overwrite = false) + { + $this->_deprecatedMethod('from()', 'Use into() instead.'); + + return parent::from($tables, $overwrite); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } + + /** + * @inheritDoc + */ + public function where($conditions = null, array $types = [], bool $overwrite = false) + { + $this->_deprecatedMethod('where()'); + + return parent::where($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function whereNotNull($fields) + { + $this->_deprecatedMethod('whereNotNull()'); + + return parent::whereNotNull($fields); + } + + /** + * @inheritDoc + */ + public function whereNull($fields) + { + $this->_deprecatedMethod('whereNull()'); + + return parent::whereNull($fields); + } + + /** + * @inheritDoc + */ + public function whereInList(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereInList()'); + + return parent::whereInList($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function whereNotInList(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereNotInList()'); + + return parent::whereNotInList($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function whereNotInListOrNull(string $field, array $values, array $options = []) + { + $this->_deprecatedMethod('whereNotInListOrNull()'); + + return parent::whereNotInListOrNull($field, $values, $options); + } + + /** + * @inheritDoc + */ + public function andWhere($conditions, array $types = []) + { + $this->_deprecatedMethod('andWhere()'); + + return parent::andWhere($conditions, $types); + } + + /** + * @inheritDoc + */ + public function order($fields, $overwrite = false) + { + $this->_deprecatedMethod('order()'); + + return parent::order($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function orderAsc($field, $overwrite = false) + { + $this->_deprecatedMethod('orderAsc()'); + + return parent::orderAsc($field, $overwrite); + } + + /** + * @inheritDoc + */ + public function orderDesc($field, $overwrite = false) + { + $this->_deprecatedMethod('orderDesc()'); + + return parent::orderDesc($field, $overwrite); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php new file mode 100644 index 000000000..06942fabb --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/SelectQuery.php @@ -0,0 +1,92 @@ +_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use from() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function update($table = null) + { + $this->_deprecatedMethod('update()', 'Create your query with updateQuery() instead.'); + + return parent::update($table); + } + + /** + * @inheritDoc + */ + public function set($key, $value = null, $types = []) + { + $this->_deprecatedMethod('set()'); + + return parent::set($key, $value, $types); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php b/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php new file mode 100644 index 000000000..ff25a89da --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/ORM/Query/UpdateQuery.php @@ -0,0 +1,267 @@ +_type === 'update' && empty($this->_parts['update'])) { + $repository = $this->getRepository(); + $this->update($repository->getTable()); + } + + return parent::sql($binder); + } + + /** + * @inheritDoc + */ + public function delete(?string $table = null) + { + $this->_deprecatedMethod('delete()', 'Create your query with deleteQuery() instead.'); + + return parent::delete($table); + } + + /** + * @inheritDoc + */ + public function cache($key, $config = 'default') + { + $this->_deprecatedMethod('cache()', 'Use execute() instead.'); + + return parent::cache($key, $config); + } + + /** + * @inheritDoc + */ + public function all(): ResultSetInterface + { + $this->_deprecatedMethod('all()', 'Use execute() instead.'); + + return parent::all(); + } + + /** + * @inheritDoc + */ + public function select($fields = [], bool $overwrite = false) + { + $this->_deprecatedMethod('select()', 'Create your query with selectQuery() instead.'); + + return parent::select($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function distinct($on = [], $overwrite = false) + { + $this->_deprecatedMethod('distinct()'); + + return parent::distinct($on, $overwrite); + } + + /** + * @inheritDoc + */ + public function modifier($modifiers, $overwrite = false) + { + $this->_deprecatedMethod('modifier()'); + + return parent::modifier($modifiers, $overwrite); + } + + /** + * @inheritDoc + */ + public function group($fields, $overwrite = false) + { + $this->_deprecatedMethod('group()'); + + return parent::group($fields, $overwrite); + } + + /** + * @inheritDoc + */ + public function having($conditions = null, $types = [], $overwrite = false) + { + $this->_deprecatedMethod('having()'); + + return parent::having($conditions, $types, $overwrite); + } + + /** + * @inheritDoc + */ + public function andHaving($conditions, $types = []) + { + $this->_deprecatedMethod('andHaving()'); + + return parent::andHaving($conditions, $types); + } + + /** + * @inheritDoc + */ + public function page(int $num, ?int $limit = null) + { + $this->_deprecatedMethod('page()'); + + return parent::page($num, $limit); + } + + /** + * @inheritDoc + */ + public function offset($offset) + { + $this->_deprecatedMethod('offset()'); + + return parent::offset($offset); + } + + /** + * @inheritDoc + */ + public function union($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::union($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function unionAll($query, $overwrite = false) + { + $this->_deprecatedMethod('union()'); + + return parent::unionAll($query, $overwrite); + } + + /** + * @inheritDoc + */ + public function insert(array $columns, array $types = []) + { + $this->_deprecatedMethod('insert()', 'Create your query with insertQuery() instead.'); + + return parent::insert($columns, $types); + } + + /** + * @inheritDoc + */ + public function into(string $table) + { + $this->_deprecatedMethod('into()', 'Use update() instead.'); + + return parent::into($table); + } + + /** + * @inheritDoc + */ + public function values($data) + { + $this->_deprecatedMethod('values()'); + + return parent::values($data); + } + + /** + * @inheritDoc + */ + public function from($tables = [], $overwrite = false) + { + $this->_deprecatedMethod('from()', 'Use update() instead.'); + + return parent::from($tables, $overwrite); + } + + /** + * @inheritDoc + */ + public function matching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('matching()'); + + return parent::matching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function notMatching(string $assoc, ?callable $builder = null) + { + $this->_deprecatedMethod('notMatching()'); + + return parent::notMatching($assoc, $builder); + } + + /** + * @inheritDoc + */ + public function contain($associations, $override = false) + { + $this->_deprecatedMethod('contain()'); + + return parent::contain($associations, $override); + } + + /** + * @inheritDoc + */ + public function getContain(): array + { + $this->_deprecatedMethod('getContain()'); + + return parent::getContain(); + } + + /** + * @inheritDoc + */ + public function find(string $finder, array $options = []) + { + $this->_deprecatedMethod('find()'); + + return parent::find($finder, $options); + } +} diff --git a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php index 1fe3cf69d..012c40025 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php +++ b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php @@ -29,6 +29,9 @@ * This object is responsible for correctly nesting result keys reported from * the query, casting each field to the correct type and executing the extra * queries required for eager loading external associations. + * + * @template T of \Cake\Datasource\EntityInterface|array + * @implements \Cake\Datasource\ResultSetInterface */ class ResultSet implements ResultSetInterface { @@ -51,7 +54,8 @@ class ResultSet implements ResultSetInterface /** * Last record fetched from the statement * - * @var object|array + * @var \Cake\Datasource\EntityInterface|array + * @psalm-var T */ protected $_current; @@ -161,7 +165,7 @@ public function __construct(Query $query, StatementInterface $statement) { $repository = $query->getRepository(); $this->_statement = $statement; - $this->_driver = $query->getConnection()->getDriver(); + $this->_driver = $query->getConnection()->getDriver($query->getConnectionRole()); $this->_defaultTable = $repository; $this->_calculateAssociationMap($query); $this->_hydrate = $query->isHydrationEnabled(); @@ -182,7 +186,8 @@ public function __construct(Query $query, StatementInterface $statement) * * Part of Iterator interface. * - * @return object|array + * @return \Cake\Datasource\EntityInterface|array + * @psalm-return T */ #[\ReturnTypeWillChange] public function current() @@ -276,7 +281,8 @@ public function valid(): bool * * This method will also close the underlying statement cursor. * - * @return object|array|null + * @return \Cake\Datasource\EntityInterface|array|null + * @psalm-return T|null */ public function first() { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php b/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php index 37fbdf7d0..fe2b1cc76 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Rule/LinkConstraint.php @@ -19,6 +19,7 @@ use Cake\Datasource\EntityInterface; use Cake\ORM\Association; use Cake\ORM\Table; +use function Cake\Core\getTypeName; /** * Checks whether links to a given association exist / do not exist. diff --git a/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php b/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php index 8136b6d82..dd6a8ee4e 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php +++ b/app/vendor/cakephp/cakephp/src/ORM/RulesChecker.php @@ -23,6 +23,8 @@ use Cake\ORM\Rule\LinkConstraint; use Cake\ORM\Rule\ValidCount; use Cake\Utility\Inflector; +use function Cake\Core\getTypeName; +use function Cake\I18n\__d; /** * ORM flavoured rules checker. diff --git a/app/vendor/cakephp/cakephp/src/ORM/Table.php b/app/vendor/cakephp/cakephp/src/ORM/Table.php index 1a37af224..b101dcddf 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Table.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Table.php @@ -40,13 +40,21 @@ use Cake\ORM\Exception\MissingEntityException; use Cake\ORM\Exception\PersistenceFailedException; use Cake\ORM\Exception\RolledbackTransactionException; +use Cake\ORM\Query\DeleteQuery; +use Cake\ORM\Query\InsertQuery; +use Cake\ORM\Query\SelectQuery; +use Cake\ORM\Query\UpdateQuery; use Cake\ORM\Rule\IsUnique; use Cake\Utility\Inflector; use Cake\Validation\ValidatorAwareInterface; use Cake\Validation\ValidatorAwareTrait; use Exception; use InvalidArgumentException; +use ReflectionMethod; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\Core\namespaceSplit; /** * Represents a single database table. @@ -515,11 +523,17 @@ public function getConnection(): Connection public function getSchema(): TableSchemaInterface { if ($this->_schema === null) { - $this->_schema = $this->_initializeSchema( - $this->getConnection() - ->getSchemaCollection() - ->describe($this->getTable()) - ); + $this->_schema = $this->getConnection() + ->getSchemaCollection() + ->describe($this->getTable()); + + $method = new ReflectionMethod($this, '_initializeSchema'); + if ($method->getDeclaringClass()->getName() != Table::class) { + deprecationWarning( + 'Table::_initializeSchema() is deprecated. Override `getSchema()` with a parent call instead.' + ); + $this->_schema = $this->_initializeSchema($this->_schema); + } if (Configure::read('debug')) { $this->checkAliasLengths(); } @@ -682,22 +696,34 @@ public function setDisplayField($field) /** * Returns the display field. * - * @return array|string|null + * @return array|string */ public function getDisplayField() { - if ($this->_displayField === null) { - $schema = $this->getSchema(); - $this->_displayField = $this->getPrimaryKey(); - foreach (['title', 'name', 'label'] as $field) { - if ($schema->hasColumn($field)) { - $this->_displayField = $field; - break; - } + if ($this->_displayField !== null) { + return $this->_displayField; + } + + $schema = $this->getSchema(); + foreach (['title', 'name', 'label'] as $field) { + if ($schema->hasColumn($field)) { + return $this->_displayField = $field; } } - return $this->_displayField; + foreach ($schema->columns() as $column) { + $columnSchema = $schema->getColumn($column); + if ( + $columnSchema && + $columnSchema['null'] !== true && + $columnSchema['type'] === 'string' && + !preg_match('/pass|token|secret/i', $column) + ) { + return $this->_displayField = $column; + } + } + + return $this->_displayField = $this->getPrimaryKey(); } /** @@ -1252,7 +1278,7 @@ public function belongsToMany(string $associated, array $options = []): BelongsT */ public function find(string $type = 'all', array $options = []): Query { - return $this->callFinder($type, $this->query()->select(), $options); + return $this->callFinder($type, $this->selectQuery()->select(), $options); } /** @@ -1697,9 +1723,56 @@ protected function _getFindOrCreateQuery($search): Query */ public function query(): Query { + deprecationWarning( + 'As of 4.5.0 using query() is deprecated. Instead use `insertQuery()`, ' . + '`deleteQuery()`, `selectQuery()` or `updateQuery()`. The query objects ' . + 'returned by these methods will emit deprecations that will become fatal errors in 5.0.' . + 'See https://book.cakephp.org/4/en/appendices/4-5-migration-guide.html for more information.' + ); + return new Query($this->getConnection(), $this); } + /** + * Creates a new DeleteQuery instance for a table. + * + * @return \Cake\ORM\Query\DeleteQuery + */ + public function deleteQuery(): DeleteQuery + { + return new DeleteQuery($this->getConnection(), $this); + } + + /** + * Creates a new InsertQuery instance for a table. + * + * @return \Cake\ORM\Query\InsertQuery + */ + public function insertQuery(): InsertQuery + { + return new InsertQuery($this->getConnection(), $this); + } + + /** + * Creates a new SelectQuery instance for a table. + * + * @return \Cake\ORM\Query\SelectQuery + */ + public function selectQuery(): SelectQuery + { + return new SelectQuery($this->getConnection(), $this); + } + + /** + * Creates a new UpdateQuery instance for a table. + * + * @return \Cake\ORM\Query\UpdateQuery + */ + public function updateQuery(): UpdateQuery + { + return new UpdateQuery($this->getConnection(), $this); + } + /** * Creates a new Query::subquery() instance for a table. * @@ -1716,8 +1789,7 @@ public function subquery(): Query */ public function updateAll($fields, $conditions): int { - $statement = $this->query() - ->update() + $statement = $this->updateQuery() ->set($fields) ->where($conditions) ->execute(); @@ -1731,8 +1803,7 @@ public function updateAll($fields, $conditions): int */ public function deleteAll($conditions): int { - $statement = $this->query() - ->delete() + $statement = $this->deleteQuery() ->where($conditions) ->execute(); $statement->closeCursor(); @@ -2072,7 +2143,8 @@ protected function _insert(EntityInterface $entity, array $data) return false; } - $statement = $this->query()->insert(array_keys($data)) + $statement = $this->insertQuery() + ->insert(array_keys($data)) ->values($data) ->execute(); @@ -2153,8 +2225,7 @@ protected function _update(EntityInterface $entity, array $data) throw new InvalidArgumentException($message); } - $statement = $this->query() - ->update() + $statement = $this->updateQuery() ->set($data) ->where($primaryKey) ->execute(); @@ -2494,8 +2565,7 @@ protected function _processDelete(EntityInterface $entity, ArrayObject $options) return $success; } - $statement = $this->query() - ->delete() + $statement = $this->deleteQuery() ->where($entity->extract($primaryKey)) ->execute(); diff --git a/app/vendor/cakephp/cakephp/src/Routing/Asset.php b/app/vendor/cakephp/cakephp/src/Routing/Asset.php index 88dee894c..ae8bd3bbe 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Asset.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Asset.php @@ -19,6 +19,7 @@ use Cake\Core\Configure; use Cake\Core\Plugin; use Cake\Utility\Inflector; +use function Cake\Core\pluginSplit; /** * Class for generating asset URLs. diff --git a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php index 7ea24dde5..448490aaa 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php @@ -1,8 +1,10 @@ getMessage(), - $e->getCode() + $e->getCode(), + $e->getHeaders() ); } catch (DeprecatedRedirectException $e) { return new RedirectResponse( @@ -186,7 +189,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $handler->handle($request); } - $middleware = new MiddlewareQueue($matching); + $container = $this->app instanceof ContainerApplicationInterface + ? $this->app->getContainer() + : null; + $middleware = new MiddlewareQueue($matching, $container); $runner = new Runner(); return $runner->run($middleware, $request, $handler); diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php index 2444e4029..7122b8aea 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/DashedRoute.php @@ -31,9 +31,9 @@ class DashedRoute extends Route * Default values need to be inflected so that they match the inflections that * match() will create. * - * @var bool + * @var array|null */ - protected $_inflectedDefaults = false; + protected $_inflectedDefaults; /** * Camelizes the previously dashed plugin route taking into account plugin vendors @@ -97,12 +97,18 @@ public function parse(string $url, string $method = ''): ?array public function match(array $url, array $context = []): ?string { $url = $this->_dasherize($url); - if (!$this->_inflectedDefaults) { - $this->_inflectedDefaults = true; - $this->defaults = $this->_dasherize($this->defaults); + if ($this->_inflectedDefaults === null) { + $this->compile(); + $this->_inflectedDefaults = $this->_dasherize($this->defaults); } + $restore = $this->defaults; + try { + $this->defaults = $this->_inflectedDefaults; - return parent::match($url, $context); + return parent::match($url, $context); + } finally { + $this->defaults = $restore; + } } /** diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php index 6adaedc65..4a721724b 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/EntityRoute.php @@ -18,6 +18,7 @@ use ArrayAccess; use RuntimeException; +use function Cake\Core\getTypeName; /** * Matches entities to routes diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php b/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php index fdc552b60..2c819d078 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/InflectedRoute.php @@ -30,9 +30,9 @@ class InflectedRoute extends Route * Default values need to be inflected so that they match the inflections that match() * will create. * - * @var bool + * @var array|null */ - protected $_inflectedDefaults = false; + protected $_inflectedDefaults; /** * Parses a string URL into an array. If it matches, it will convert the prefix, controller and @@ -76,12 +76,18 @@ public function parse(string $url, string $method = ''): ?array public function match(array $url, array $context = []): ?string { $url = $this->_underscore($url); - if (!$this->_inflectedDefaults) { - $this->_inflectedDefaults = true; - $this->defaults = $this->_underscore($this->defaults); + if ($this->_inflectedDefaults === null) { + $this->compile(); + $this->_inflectedDefaults = $this->_underscore($this->defaults); } + $restore = $this->defaults; + try { + $this->defaults = $this->_inflectedDefaults; - return parent::match($url, $context); + return parent::match($url, $context); + } finally { + $this->defaults = $restore; + } } /** diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php index 2315a07f2..15e6c07cb 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php @@ -19,6 +19,7 @@ use Cake\Http\Exception\BadRequestException; use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; +use function Cake\Core\deprecationWarning; /** * A single Route used by the Router to connect requests to diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php index 25dcfd5eb..4f04e9773 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php @@ -25,6 +25,7 @@ use Cake\Utility\Inflector; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\getTypeName; /** * Provides features for building routes inside scopes. diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php index 8f96a5a99..73a34178e 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php @@ -21,6 +21,7 @@ use Cake\Routing\Route\Route; use Psr\Http\Message\ServerRequestInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Contains a collection of routes. @@ -46,6 +47,13 @@ class RouteCollection */ protected $_named = []; + /** + * Routes indexed by static path. + * + * @var array> + */ + protected $staticPaths = []; + /** * Routes indexed by path prefix. * @@ -104,12 +112,17 @@ public function add(Route $route, array $options = []): void // Index path prefixes (for parsing) $path = $route->staticPath(); - $this->_paths[$path][] = $route; $extensions = $route->getExtensions(); if (count($extensions) > 0) { $this->setExtensions($extensions); } + + if ($path === $route->template) { + $this->staticPaths[$path][] = $route; + } + + $this->_paths[$path][] = $route; } /** @@ -119,17 +132,37 @@ public function add(Route $route, array $options = []): void * @param string $method The HTTP method to use. * @return array An array of request parameters parsed from the URL. * @throws \Cake\Routing\Exception\MissingRouteException When a URL has no matching route. + * @deprecated 4.5.0 Use parseRequest() instead. */ public function parse(string $url, string $method = ''): array { - $decoded = urldecode($url); - + deprecationWarning('4.5.0 - Use parseRequest() instead.'); $queryParameters = []; if (strpos($url, '?') !== false) { [$url, $qs] = explode('?', $url, 2); parse_str($qs, $queryParameters); } + $decoded = urldecode($url); + if ($decoded !== '/') { + $decoded = rtrim($decoded, '/'); + } + + if (isset($this->staticPaths[$decoded])) { + foreach ($this->staticPaths[$decoded] as $route) { + $r = $route->parse($url, $method); + if ($r === null) { + continue; + } + + if ($queryParameters) { + $r['?'] = $queryParameters; + } + + return $r; + } + } + // Sort path segments matching longest paths first. krsort($this->_paths); @@ -172,6 +205,24 @@ public function parseRequest(ServerRequestInterface $request): array { $uri = $request->getUri(); $urlPath = urldecode($uri->getPath()); + if ($urlPath !== '/') { + $urlPath = rtrim($urlPath, '/'); + } + + if (isset($this->staticPaths[$urlPath])) { + foreach ($this->staticPaths[$urlPath] as $route) { + $r = $route->parseRequest($request); + if ($r === null) { + continue; + } + if ($uri->getQuery()) { + parse_str($uri->getQuery(), $queryParameters); + $r['?'] = $queryParameters; + } + + return $r; + } + } // Sort path segments matching longest paths first. krsort($this->_paths); @@ -329,6 +380,8 @@ public function match(array $url, array $context): string /** * Get all the connected routes as a flat list. * + * Routes will not be returned in the order they were added. + * * @return array<\Cake\Routing\Route\Route> */ public function routes(): array diff --git a/app/vendor/cakephp/cakephp/src/Routing/Router.php b/app/vendor/cakephp/cakephp/src/Routing/Router.php index 9b4235cc3..d11b2788c 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Router.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Router.php @@ -25,6 +25,7 @@ use ReflectionMethod; use RuntimeException; use Throwable; +use function Cake\Core\deprecationWarning; /** * Parses the request URL into controller, action, and parameters. Uses the connected routes @@ -283,6 +284,7 @@ public static function reload(): void } } static::$_collection = new RouteCollection(); + static::$_routePaths = []; } /** @@ -401,7 +403,7 @@ protected static function _applyUrlFilters(array $url): array * - `_port` - Set the port if you need to create links on non-standard ports. * - `_full` - If true output of `Router::fullBaseUrl()` will be prepended to generated URLs. * - `#` - Allows you to set URL hash fragments. - * - `_ssl` - Set to true to convert the generated URL to https, or false to force http. + * - `_https` - Set to true to convert the generated URL to https, or false to force http. * - `_name` - Name of route. If you have setup named routes you can use this key * to specify it. * @@ -449,7 +451,13 @@ public static function url($url = null, bool $full = false): string } if (isset($url['_ssl'])) { - $url['_scheme'] = $url['_ssl'] === true ? 'https' : 'http'; + deprecationWarning('`_ssl` option is deprecated. Use `_https` instead.'); + $url['_https'] = $url['_ssl']; + unset($url['_ssl']); + } + + if (isset($url['_https'])) { + $url['_scheme'] = $url['_https'] === true ? 'https' : 'http'; } if (isset($url['_full']) && $url['_full'] === true) { @@ -458,7 +466,7 @@ public static function url($url = null, bool $full = false): string if (isset($url['#'])) { $frag = '#' . $url['#']; } - unset($url['_ssl'], $url['_full'], $url['#']); + unset($url['_https'], $url['_full'], $url['#']); $url = static::_applyUrlFilters($url); @@ -930,7 +938,9 @@ public static function plugin(string $name, $options = [], $callback = null): vo } /** - * Get the route scopes and their connected routes. + * Get the all of the routes currently connected. + * + * Routes will not always be returned in the order they were defined. * * @return array<\Cake\Routing\Route\Route> */ @@ -995,7 +1005,7 @@ protected static function unwrapShortString(array $url) * - Vendor/Cms.Management/Admin/Articles::view * * @param string $url Route path in [Plugin.][Prefix/]Controller::action format - * @return array + * @return array */ public static function parseRoutePath(string $url): array { @@ -1009,24 +1019,52 @@ public static function parseRoutePath(string $url): array (?[a-z0-9]+) :: (?[a-z0-9_]+) + (?(?:/(?:[a-z][a-z0-9-_]*=)? + (?:([a-z0-9-_=]+)|(["\'][^\'"]+[\'"])) + )+/?)? $#ix'; if (!preg_match($regex, $url, $matches)) { throw new InvalidArgumentException("Could not parse a string route path `{$url}`."); } - $defaults = []; - + $defaults = [ + 'controller' => $matches['controller'], + 'action' => $matches['action'], + ]; if ($matches['plugin'] !== '') { $defaults['plugin'] = $matches['plugin']; } if ($matches['prefix'] !== '') { $defaults['prefix'] = $matches['prefix']; } - $defaults['controller'] = $matches['controller']; - $defaults['action'] = $matches['action']; - static::$_routePaths[$url] = $defaults; + if (isset($matches['params']) && $matches['params'] !== '') { + $paramsArray = explode('/', trim($matches['params'], '/')); + foreach ($paramsArray as $param) { + if (strpos($param, '=') !== false) { + if (!preg_match('/(?.+?)=(?.*)/', $param, $paramMatches)) { + throw new InvalidArgumentException( + "Could not parse a key=value from `{$param}` in route path `{$url}`." + ); + } + $paramKey = $paramMatches['key']; + if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $paramKey)) { + throw new InvalidArgumentException( + "Param key `{$paramKey}` is not valid in route path `{$url}`." + ); + } + $defaults[$paramKey] = trim($paramMatches['value'], '\'"'); + } else { + $defaults[] = $param; + } + } + } + // Only cache 200 routes per request. Beyond that we could + // be soaking up too much memory. + if (count(static::$_routePaths) < 200) { + static::$_routePaths[$url] = $defaults; + } return $defaults; } diff --git a/app/vendor/cakephp/cakephp/src/Routing/functions.php b/app/vendor/cakephp/cakephp/src/Routing/functions.php index d43f6b788..310ce6990 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/functions.php +++ b/app/vendor/cakephp/cakephp/src/Routing/functions.php @@ -11,30 +11,54 @@ * * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @link https://cakephp.org CakePHP(tm) Project - * @since 4.1.0 + * @since 4.5.0 * @license https://opensource.org/licenses/mit-license.php MIT License */ +// phpcs:disable PSR1.Files.SideEffects +namespace Cake\Routing; -use Cake\Routing\Router; +/** + * Convenience wrapper for Router::url(). + * + * @param \Psr\Http\Message\UriInterface|array|string|null $url An array specifying any of the following: + * 'controller', 'action', 'plugin' additionally, you can provide routed + * elements or query string parameters. If string it can be name any valid url + * string or it can be an UriInterface instance. + * @param bool $full If true, the full base URL will be prepended to the result. + * Default is false. + * @return string Full translated URL with base path. + * @throws \Cake\Core\Exception\CakeException When the route name is not found + * @see \Cake\Routing\Router::url() + * @since 4.5.0 + */ +function url($url = null, bool $full = false): string +{ + return Router::url($url, $full); +} -if (!function_exists('urlArray')) { - /** - * Returns an array URL from a route path string. - * - * @param string $path Route path. - * @param array $params An array specifying any additional parameters. - * Can be also any special parameters supported by `Router::url()`. - * @return array URL - * @see \Cake\Routing\Router::pathUrl() - */ - function urlArray(string $path, array $params = []): array - { - $url = Router::parseRoutePath($path); - $url += [ - 'plugin' => false, - 'prefix' => false, - ]; +/** + * Returns an array URL from a route path string. + * + * @param string $path Route path. + * @param array $params An array specifying any additional parameters. + * Can be also any special parameters supported by `Router::url()`. + * @return array URL + * @see \Cake\Routing\Router::pathUrl() + */ +function urlArray(string $path, array $params = []): array +{ + $url = Router::parseRoutePath($path); + $url += [ + 'plugin' => false, + 'prefix' => false, + ]; + + return $url + $params; +} - return $url + $params; - } +/** + * Include global functions. + */ +if (!getenv('CAKE_DISABLE_GLOBAL_FUNCS')) { + include 'functions_global.php'; } diff --git a/app/vendor/cakephp/cakephp/src/Routing/functions_global.php b/app/vendor/cakephp/cakephp/src/Routing/functions_global.php new file mode 100644 index 000000000..e13958b0c --- /dev/null +++ b/app/vendor/cakephp/cakephp/src/Routing/functions_global.php @@ -0,0 +1,56 @@ +groupBy(function (EventInterface $event): string { return $event->getName(); }) @@ -111,6 +112,6 @@ public function matches($other): bool */ public function toString(): string { - return 'was fired with ' . $this->_dataKey . ' matching ' . (string)$this->_dataValue; + return "was fired with `{$this->_dataKey}` matching `" . json_encode($this->_dataValue) . '`'; } } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php index 0522f86cd..2edbec970 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php @@ -55,7 +55,7 @@ public function __construct(?Response $response, string $cookieName) */ public function matches($other): bool { - $cookie = $this->response->getCookie($this->cookieName); + $cookie = $this->readCookie($this->cookieName); return $cookie !== null && $cookie['value'] === $other; } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php index 370c40c6d..bd31234f4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php @@ -35,7 +35,7 @@ class CookieSet extends ResponseBase */ public function matches($other): bool { - $cookie = $this->response->getCookie($other); + $cookie = $this->readCookie($other); return $cookie !== null && $cookie['value'] !== ''; } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php index c17f9956d..5b43b0124 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php @@ -15,6 +15,7 @@ */ namespace Cake\TestSuite\Constraint\Response; +use Cake\Http\Cookie\CookieCollection; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Constraint\Constraint; use Psr\Http\Message\ResponseInterface; @@ -54,4 +55,24 @@ protected function _getBodyAsString(): string { return (string)$this->response->getBody(); } + + /** + * Read a cookie from either the response cookie collection, + * or headers + * + * @param string $name The name of the cookie you want to read. + * @return array|null Null if the cookie does not exist, array with `value` as the only key. + */ + protected function readCookie(string $name): ?array + { + if (method_exists($this->response, 'getCookie')) { + return $this->response->getCookie($name); + } + $cookies = CookieCollection::createFromHeader($this->response->getHeader('Set-Cookie')); + if (!$cookies->has($name)) { + return null; + } + + return $cookies->get($name)->toArray(); + } } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php index 7e564fc3d..8cd3f99bf 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php @@ -1,6 +1,10 @@ */ $className = $fixture; - /** @psalm-suppress PossiblyFalseArgument */ $name = preg_replace('/Fixture\z/', '', substr(strrchr($fixture, '\\'), 1)); } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php index 3a97b1bd6..5e200f207 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/SchemaLoader.php @@ -92,12 +92,58 @@ public function loadSqlFiles( } /** - * Load and apply CakePHP-specific schema file. + * Load and apply CakePHP schema file. + * + * This method will process the array returned by `$file` and treat + * the contents as a list of table schema. + * + * An example table is: + * + * ``` + * return [ + * 'articles' => [ + * 'columns' => [ + * 'id' => [ + * 'type' => 'integer', + * ], + * 'author_id' => [ + * 'type' => 'integer', + * 'null' => true, + * ], + * 'title' => [ + * 'type' => 'string', + * 'null' => true, + * ], + * 'body' => 'text', + * 'published' => [ + * 'type' => 'string', + * 'length' => 1, + * 'default' => 'N', + * ], + * ], + * 'constraints' => [ + * 'primary' => [ + * 'type' => 'primary', + * 'columns' => [ + * 'id', + * ], + * ], + * ], + * ], + * ]; + * ``` + * + * This schema format can be useful for plugins that want to include + * tables to test against but don't need to include production + * ready schema via migrations. Applications should favour using migrations + * or SQL dump files over this format for ease of maintenance. + * + * A more complete example can be found in `tests/schema.php`. * * @param string $file Schema file * @param string $connectionName Connection name + * @throws \InvalidArgumentException For missing table name(s). * @return void - * @internal */ public function loadInternalFile(string $file, string $connectionName = 'test'): void { @@ -112,8 +158,15 @@ public function loadInternalFile(string $file, string $connectionName = 'test'): $connection = ConnectionManager::get($connectionName); $connection->disableConstraints(function ($connection) use ($tables) { - foreach ($tables as $table) { - $schema = new TableSchema($table['table'], $table['columns']); + foreach ($tables as $tableName => $table) { + $name = $table['table'] ?? $tableName; + if (!is_string($name)) { + throw new InvalidArgumentException( + sprintf('`%s` is not a valid table name. Either use a string key for the table definition' + . '(`\'articles\' => [...]`) or define the `table` key in the table definition.', $name) + ); + } + $schema = new TableSchema($name, $table['columns']); if (isset($table['indexes'])) { foreach ($table['indexes'] as $key => $index) { $schema->addIndex($key, $index); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php index a4f0fde86..7eefb8ac4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php @@ -26,6 +26,7 @@ use Cake\ORM\Locator\LocatorAwareTrait; use Cake\Utility\Inflector; use Exception; +use function Cake\Core\namespaceSplit; /** * Cake TestFixture is responsible for building and destroying tables to be used @@ -335,7 +336,8 @@ public function insert(ConnectionInterface $connection) { if (!empty($this->records)) { [$fields, $values, $types] = $this->_getRecords(); - $query = $connection->newQuery() + /** @var \Cake\Database\Connection $connection */ + $query = $connection->insertQuery() ->insert($fields, $types) ->into($this->sourceName()); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php index c20b154db..0bafe7e65 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php @@ -1,6 +1,10 @@ $query, 'REQUEST_URI' => $url, ]; - if (!empty($hostInfo['ssl'])) { + if (!empty($hostInfo['https'])) { $env['HTTPS'] = 'on'; } if (isset($hostInfo['host'])) { @@ -728,7 +728,7 @@ protected function _url(string $url): array $hostData['host'] = $uri->getHost(); } if ($uri->getScheme()) { - $hostData['ssl'] = $uri->getScheme() === 'https'; + $hostData['https'] = $uri->getScheme() === 'https'; } return [$path, $query, $hostData]; @@ -1248,6 +1248,22 @@ public function assertCookie($expected, string $name, string $message = ''): voi $this->assertThat($expected, new CookieEquals($this->_response, $name), $verboseMessage); } + /** + * Asserts that a cookie is set. + * + * Useful when you're working with cookies that have obfuscated values + * but the cookie being set is important. + * + * @param string $name The cookie name. + * @param string $message The failure message that will be appended to the generated message. + * @return void + */ + public function assertCookieIsSet(string $name, string $message = ''): void + { + $verboseMessage = $this->extractVerboseMessage($message); + $this->assertThat($name, new CookieSet($this->_response), $verboseMessage); + } + /** * Asserts a cookie has not been set in the response * diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php index e598b17f4..d386817d2 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php @@ -1,6 +1,10 @@ _capturedError = null; + set_error_handler( + function (int $code, string $description, string $file, int $line) { + $trace = Debugger::trace(['start' => 1, 'format' => 'points']); + $this->_capturedError = new PhpError($code, $description, $file, $line, $trace); + + return true; + }, + $errorLevel + ); + + try { + $callable(); + } finally { + restore_error_handler(); + error_reporting($default); + } + if ($this->_capturedError === null) { + $this->fail('No error was captured'); + } + /** @var \Cake\Error\PhpError $this->_capturedError */ + return $this->_capturedError; + } + /** * Helper method for check deprecation methods * @@ -208,9 +256,6 @@ public function deprecated(callable $callable): void /** @var bool $deprecation */ $deprecation = false; - /** - * @psalm-suppress InvalidArgument - */ $previousHandler = set_error_handler( function ($code, $message, $file, $line, $context = null) use (&$previousHandler, &$deprecation): bool { if ($code == E_USER_DEPRECATED) { @@ -763,7 +808,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa continue; } foreach ($tags as $tag => $attributes) { - /** @psalm-suppress PossiblyFalseArgument */ $regex[] = [ sprintf('Open %s tag', $tag), sprintf('[\s]*<%s', preg_quote($tag, '/')), @@ -810,7 +854,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa 'attrs' => $attrs, ]; } - /** @psalm-suppress PossiblyFalseArgument */ $regex[] = [ sprintf('End %s tag', $tag), '[\s]*\/?[\s]*>[\n\r]*', @@ -833,7 +876,6 @@ public function assertHtml(array $expected, string $string, bool $fullDebug = fa } // If 'attrs' is not present then the array is just a regular int-offset one - /** @psalm-suppress PossiblyUndefinedArrayOffset */ [$description, $expressions, $itemNum] = $assertion; $expression = ''; foreach ((array)$expressions as $expression) { diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php index 440530d7d..f51e74590 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/TestListenerTrait.php @@ -22,6 +22,9 @@ use PHPUnit\Framework\Warning; use Throwable; +// phpcs:disable +deprecationWarning('4.5.0 - TestListenerTrait is deprecated, as PHPUnit is removing support for listeners.'); + /** * Implements empty default methods for PHPUnit\Framework\TestListener. */ diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php b/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php index e5a18c215..eb96dffe9 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/TestSuite.php @@ -21,6 +21,7 @@ use Cake\Filesystem\Filesystem; use PHPUnit\Framework\TestSuite as BaseTestSuite; use SplFileInfo; +use function Cake\Core\deprecationWarning; /** * A class to contain test cases and run them with shared fixtures @@ -35,6 +36,7 @@ class TestSuite extends BaseTestSuite */ public function addTestDirectory(string $directory = '.'): void { + deprecationWarning('4.5.0 - TestSuite is deprecated as PHPunit is removing support for testsuites.'); $fs = new Filesystem(); $files = $fs->find($directory, '/\.php$/'); foreach ($files as $file => $fileInfo) { @@ -50,6 +52,7 @@ public function addTestDirectory(string $directory = '.'): void */ public function addTestDirectoryRecursive(string $directory = '.'): void { + deprecationWarning('4.5.0 - TestSuite is deprecated as PHPunit is removing support for testsuites.'); $fs = new Filesystem(); $files = $fs->findRecursive($directory, function (SplFileInfo $current) { $file = $current->getFilename(); diff --git a/app/vendor/cakephp/cakephp/src/Utility/Hash.php b/app/vendor/cakephp/cakephp/src/Utility/Hash.php index 782f2c5ca..32781929f 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Hash.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Hash.php @@ -336,7 +336,10 @@ public static function insert(array $data, string $path, $values = null): array foreach ($data as $k => $v) { if (static::_matchToken($k, $token)) { - if (!$conditions || static::_matches($v, $conditions)) { + if ( + !$conditions || + ((is_array($v) || $v instanceof ArrayAccess) && static::_matches($v, $conditions)) + ) { $data[$k] = $nextPath ? static::insert($v, $nextPath, $values) : array_merge($v, (array)$values); @@ -1154,10 +1157,11 @@ public static function mergeDiff(array $data, array $compare): array * * @param array $data List to normalize * @param bool $assoc If true, $data will be converted to an associative array. + * @param mixed $default The default value to use when a top level numeric key is converted to associative form. * @return array * @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::normalize */ - public static function normalize(array $data, bool $assoc = true): array + public static function normalize(array $data, bool $assoc = true, $default = null): array { $keys = array_keys($data); $count = count($keys); @@ -1175,7 +1179,7 @@ public static function normalize(array $data, bool $assoc = true): array $newList = []; for ($i = 0; $i < $count; $i++) { if (is_int($keys[$i])) { - $newList[$data[$keys[$i]]] = null; + $newList[$data[$keys[$i]]] = $default; } else { $newList[$keys[$i]] = $data[$keys[$i]]; } diff --git a/app/vendor/cakephp/cakephp/src/Utility/Text.php b/app/vendor/cakephp/cakephp/src/Utility/Text.php index 95cf22c9e..7116b0dec 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Text.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Text.php @@ -19,6 +19,8 @@ use Cake\Core\Exception\CakeException; use InvalidArgumentException; use Transliterator; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Text handling methods. diff --git a/app/vendor/cakephp/cakephp/src/Utility/Xml.php b/app/vendor/cakephp/cakephp/src/Utility/Xml.php index 069177af4..53ddfbda7 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Xml.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Xml.php @@ -475,7 +475,6 @@ protected static function _toArray(SimpleXMLElement $xml, array &$parentData, st } foreach ($xml->children($namespace, true) as $child) { - /** @psalm-suppress PossiblyNullArgument */ static::_toArray($child, $data, $namespace, $namespaces); } } diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validation.php b/app/vendor/cakephp/cakephp/src/Validation/Validation.php index 6ca684f3a..043347bfa 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validation.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validation.php @@ -25,6 +25,7 @@ use NumberFormatter; use Psr\Http\Message\UploadedFileInterface; use RuntimeException; +use function Cake\Core\deprecationWarning; /** * Validation Class. Used for validation of model data diff --git a/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php b/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php index a16ab6b6a..69808d138 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php +++ b/app/vendor/cakephp/cakephp/src/Validation/ValidationSet.php @@ -25,6 +25,9 @@ /** * ValidationSet object. Holds all validation rules for a field and exposes * methods to dynamically add or remove validation rules + * + * @template-implements \ArrayAccess + * @template-implements \IteratorAggregate */ class ValidationSet implements ArrayAccess, IteratorAggregate, Countable { diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validator.php b/app/vendor/cakephp/cakephp/src/Validation/Validator.php index e968a4c96..51764b486 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validator.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validator.php @@ -23,6 +23,9 @@ use IteratorAggregate; use Psr\Http\Message\UploadedFileInterface; use Traversable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\getTypeName; +use function Cake\I18n\__d; /** * Validator object encapsulates all methods related to data validations for a model @@ -31,6 +34,8 @@ * Implements ArrayAccess to easily modify rules in the set * * @link https://book.cakephp.org/4/en/core-libraries/validation.html + * @template-implements \ArrayAccess + * @template-implements \IteratorAggregate */ class Validator implements ArrayAccess, IteratorAggregate, Countable { @@ -193,7 +198,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable */ public function __construct() { - $this->_useI18n = function_exists('__d'); + $this->_useI18n = function_exists('\Cake\I18n\__d'); $this->_providers = self::$_defaultProviders; } @@ -2349,8 +2354,30 @@ public function integer(string $field, ?string $message = null, $when = null) * @see \Cake\Validation\Validation::isArray() * @return $this */ + public function array(string $field, ?string $message = null, $when = null) + { + $extra = array_filter(['on' => $when, 'message' => $message]); + + return $this->add($field, 'array', $extra + [ + 'rule' => 'isArray', + ]); + } + + /** + * Add a validation rule to ensure that a field contains an array. + * + * @param string $field The field you want to apply the rule to. + * @param string|null $message The error message when the rule fails. + * @param callable|string|null $when Either 'create' or 'update' or a callable that returns + * true when the validation rule should be applied. + * @see \Cake\Validation\Validation::isArray() + * @return $this + * @deprecated 4.5.0 Use Validator::array() instead. + */ public function isArray(string $field, ?string $message = null, $when = null) { + deprecationWarning('`Validator::isArray()` is deprecated, use `Validator::array()` instead'); + $extra = array_filter(['on' => $when, 'message' => $message]); return $this->add($field, 'isArray', $extra + [ diff --git a/app/vendor/cakephp/cakephp/src/View/Cell.php b/app/vendor/cakephp/cakephp/src/View/Cell.php index 49cf528b5..9908a74f2 100644 --- a/app/vendor/cakephp/cakephp/src/View/Cell.php +++ b/app/vendor/cakephp/cakephp/src/View/Cell.php @@ -245,7 +245,6 @@ protected function _cacheConfig(string $action, ?string $template = null): array return $default; } - /** @psalm-suppress PossiblyFalseOperand */ return $this->_cache + $default; } diff --git a/app/vendor/cakephp/cakephp/src/View/CellTrait.php b/app/vendor/cakephp/cakephp/src/View/CellTrait.php index 5252c98c9..78d75aacc 100644 --- a/app/vendor/cakephp/cakephp/src/View/CellTrait.php +++ b/app/vendor/cakephp/cakephp/src/View/CellTrait.php @@ -19,6 +19,7 @@ use Cake\Core\App; use Cake\Utility\Inflector; use Cake\View\Exception\MissingCellException; +use function Cake\Core\pluginSplit; /** * Provides cell() method for usage in Controller and View classes. diff --git a/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php b/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php index 9a9a54373..b276c0f80 100644 --- a/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php +++ b/app/vendor/cakephp/cakephp/src/View/Exception/MissingCellTemplateException.php @@ -56,7 +56,7 @@ public function __construct( * Get the passed in attributes * * @return array - * @psalm-return array{name: string, file: string, paths: array} + * @psalm-return array{name: string, file: string, paths: array} */ public function getAttributes(): array { diff --git a/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php b/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php index 2cd422e04..cf50c7a22 100644 --- a/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php +++ b/app/vendor/cakephp/cakephp/src/View/Exception/MissingTemplateException.php @@ -87,7 +87,7 @@ public function formatMessage(): string * Get the passed in attributes * * @return array - * @psalm-return array{file: string, paths: array} + * @psalm-return array{file: string, paths: array} */ public function getAttributes(): array { diff --git a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php index 8271c92b9..1e197569e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php @@ -17,6 +17,8 @@ namespace Cake\View\Form; use Cake\Utility\Hash; +use function Cake\Core\deprecationWarning; +use function Cake\I18n\__d; /** * Provides a basic array based context provider for FormHelper. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php b/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php index d24fa3de9..482fa85d2 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/ContextFactory.php @@ -21,6 +21,7 @@ use Cake\Form\Form; use Cake\Http\ServerRequest; use RuntimeException; +use function Cake\Core\getTypeName; /** * Factory for getting form context instance based on provided data. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php index 87e2ce4e1..728ade06e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php @@ -27,6 +27,8 @@ use Cake\Validation\Validator; use RuntimeException; use Traversable; +use function Cake\Core\deprecationWarning; +use function Cake\Core\namespaceSplit; /** * Provides a form context around a single entity and its relations. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php index 007e2dcb1..731cc045e 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php @@ -19,6 +19,7 @@ use Cake\Core\Exception\CakeException; use Cake\Form\Form; use Cake\Utility\Hash; +use function Cake\Core\deprecationWarning; /** * Provides a context provider for {@link \Cake\Form\Form} instances. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php b/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php index 5adf5639e..8defaa128 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/NullContext.php @@ -16,6 +16,8 @@ */ namespace Cake\View\Form; +use function Cake\Core\deprecationWarning; + /** * Provides a context provider that does nothing. * diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php index 2b298118d..f67ee04ec 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php @@ -30,6 +30,10 @@ use Cake\View\Widget\WidgetLocator; use InvalidArgumentException; use RuntimeException; +use function Cake\Core\deprecationWarning; +use function Cake\Core\h; +use function Cake\I18n\__; +use function Cake\I18n\__d; /** * Form helper library. @@ -113,9 +117,9 @@ class FormHelper extends Helper // Wrapper content used to hide other content. 'hiddenBlock' => '
{{content}}
', // Generic input element. - 'input' => '', + 'input' => '', // Submit input element. - 'inputSubmit' => '', + 'inputSubmit' => '', // Container element used by control(). 'inputContainer' => '
{{content}}
', // Container element used by control() when a field has an error. @@ -150,6 +154,8 @@ class FormHelper extends Helper 'confirmJs' => '{{confirm}}', // selected class 'selectedClass' => 'selected', + // required class + 'requiredClass' => 'required', ], // set HTML5 validation message to custom required/empty messages 'autoSetCustomValidity' => true, @@ -616,7 +622,7 @@ public function secure(array $fields = [], array $secureAttributes = []): string $tokenData = $this->formProtector->buildTokenData( $this->_lastAction, - $this->_View->getRequest()->getSession()->id() + $this->_getFormProtectorSessionId() ); $tokenFields = array_merge($secureAttributes, [ 'value' => $tokenData['fields'], @@ -636,6 +642,17 @@ public function secure(array $fields = [], array $secureAttributes = []): string return $this->formatTemplate('hiddenBlock', ['content' => $out]); } + /** + * Get Session id for FormProtector + * Must be the same as in FormProtectionComponent + * + * @return string + */ + protected function _getFormProtectorSessionId(): string + { + return $this->_View->getRequest()->getSession()->id(); + } + /** * Add to the list of fields that are currently unlocked. * @@ -1133,6 +1150,7 @@ public function control(string $fieldName, array $options = []): string 'content' => $result, 'error' => $error, 'errorSuffix' => $errorSuffix, + 'label' => $label, 'options' => $options, ]); @@ -1180,7 +1198,8 @@ protected function _inputContainerTemplate(array $options): string return $this->formatTemplate($inputContainerTemplate, [ 'content' => $options['content'], 'error' => $options['error'], - 'required' => $options['options']['required'] ? ' required' : '', + 'label' => $options['label'] ?? '', + 'required' => $options['options']['required'] ? ' ' . $this->templater()->get('requiredClass') : '', 'type' => $options['options']['type'], 'templateVars' => $options['options']['templateVars'] ?? [], ]); @@ -1581,8 +1600,8 @@ public function radio(string $fieldName, iterable $options = [], array $attribut /** * Missing method handler - implements various simple input types. Is used to create inputs - * of various types. e.g. `$this->Form->text();` will create `` while - * `$this->Form->range();` will create `` + * of various types. e.g. `$this->Form->text();` will create `` while + * `$this->Form->range();` will create `` * * ### Usage * @@ -1592,7 +1611,7 @@ public function radio(string $fieldName, iterable $options = [], array $attribut * * Will make an input like: * - * `` + * `` * * The first argument to an input type should always be the fieldname, in `Model.field` format. * The second argument should always be an array of attributes for the input. @@ -1796,7 +1815,7 @@ public function postButton(string $title, $url, array $options = []): string * @param array|string|null $url Cake-relative URL or array of URL parameters, or * external URL (starts with http://) * @param array $options Array of HTML attributes. - * @return string An `` element. + * @return string An `` element. * @link https://book.cakephp.org/4/en/views/helpers/form.html#creating-standalone-buttons-and-post-links */ public function postLink(string $title, $url = null, array $options = []): string @@ -1892,7 +1911,7 @@ public function postLink(string $title, $url = null, array $options = []): strin } /** - * Creates a submit button element. This method will generate `` elements that + * Creates a submit button element. This method will generate `` elements that * can be used to submit, and reset forms by using $options. image submits can be created by supplying an * image path for $caption. * diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php index aa2d5ed02..7b62136b4 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php @@ -19,6 +19,7 @@ use Cake\Core\Configure; use Cake\View\Helper; use Cake\View\StringTemplateTrait; +use function Cake\Core\h; /** * Html Helper class for easy use of HTML widgets. @@ -46,11 +47,11 @@ class HtmlHelper extends Helper */ protected $_defaultConfig = [ 'templates' => [ - 'meta' => '', - 'metalink' => '', + 'meta' => '', + 'metalink' => '', 'link' => '{{content}}', 'mailto' => '{{content}}', - 'image' => '', + 'image' => '', 'tableheader' => '{{content}}', 'tableheaderrow' => '{{content}}', 'tablecell' => '{{content}}', @@ -64,9 +65,9 @@ class HtmlHelper extends Helper 'tagselfclosing' => '<{{tag}}{{attrs}}/>', 'para' => '{{content}}

', 'parastart' => '', - 'css' => '', + 'css' => '', 'style' => '{{content}}', - 'charset' => '', + 'charset' => '', 'ul' => '{{content}}', 'ol' => '{{content}}', 'li' => '{{content}}', @@ -129,7 +130,7 @@ class HtmlHelper extends Helper * @param array|string|null $content The address of the external resource or string for content attribute * @param array $options Other attributes for the generated tag. If the type attribute is html, * rss, atom, or icon, the mime-type is returned. - * @return string|null A completed `` element, or null if the element was sent to a block. + * @return string|null A completed `` element, or null if the element was sent to a block. * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-meta-tags */ public function meta($type, $content = null, array $options = []): ?string @@ -247,7 +248,7 @@ public function charset(?string $charset = null): string * @param array|string|null $url Cake-relative URL or array of URL parameters, or * external URL (starts with http://) * @param array $options Array of options and HTML attributes. - * @return string An `` element. + * @return string An `` element. * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-links */ public function link($title, $url = null, array $options = []): string @@ -314,7 +315,7 @@ public function link($title, $url = null, array $options = []): string * @param array $params An array specifying any additional parameters. * Can be also any special parameters supported by `Router::url()`. * @param array $options Array of options and HTML attributes. - * @return string An `` element. + * @return string An `` element. * @see \Cake\Routing\Router::pathUrl() * @link https://book.cakephp.org/4/en/views/helpers/html.html#creating-links */ @@ -371,7 +372,7 @@ public function linkFromPath(string $title, string $path, array $params = [], ar * CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot * of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css. * @param array $options Array of options and HTML arguments. - * @return string|null CSS `` or ` @@ -282,29 +345,26 @@
-
- element('exception_stack_trace_nav') ?> -
-
- fetch('subheading')): ?> -

- fetch('subheading') ?> -

- + fetch('subheading')): ?> +

+ fetch('subheading') ?> +

+ - element('exception_stack_trace'); ?> + fetch('file')): ?> +
+ fetch('file') ?> +
+ -
- fetch('file') ?> -
+ element('dev_error_stacktrace'); ?> - fetch('templateName')): ?> -

- If you want to customize this error message, create - fetch('templateName') ?> -

- -
+ fetch('templateName')): ?> +

+ If you want to customize this error message, create + fetch('templateName') ?> +

+
+ + + + hello + + + + + + + + + + + + + + + + + + + + + +section as $section) { + ?> + + + + + + section as $section) { + ?> +
+ + + + + + + + +?> + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +<?php echo $title; ?> + + + + + hello + + + + + + + + + + + + + + + + + + + +section as $section) { + ?> +
+ + + + + section as $section) { + ?> +
+ + + + + + + + + + + + +?> + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc new file mode 100644 index 000000000..d8f051277 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.15.inc @@ -0,0 +1,9 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc new file mode 100644 index 000000000..754c241b8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.16.inc @@ -0,0 +1,8 @@ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc new file mode 100644 index 000000000..71de17bfb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.17.inc @@ -0,0 +1,8 @@ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc new file mode 100644 index 000000000..3d61d4859 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed new file mode 100644 index 000000000..8c906d40c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.18.inc.fixed @@ -0,0 +1,13 @@ + + +
+ +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc new file mode 100644 index 000000000..34db64d60 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc @@ -0,0 +1,17 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed new file mode 100644 index 000000000..b1738db57 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.19.inc.fixed @@ -0,0 +1,15 @@ + + +
+ +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc new file mode 100644 index 000000000..755fd355b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed new file mode 100644 index 000000000..e9073da91 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.2.inc.fixed @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc new file mode 100644 index 000000000..28cdbdaf7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed new file mode 100644 index 000000000..fcc24a278 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.20.inc.fixed @@ -0,0 +1,16 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc new file mode 100644 index 000000000..1da67a2ea --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc @@ -0,0 +1,15 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed new file mode 100644 index 000000000..d7487b507 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.21.inc.fixed @@ -0,0 +1,16 @@ + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc new file mode 100644 index 000000000..5196a3b45 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.22.inc @@ -0,0 +1,30 @@ +
Inline HTML with indent to demonstrate the bug in the indent calculation.
+ + + + + + + + +Inline HTML with indent to demonstrate the bug in the indent calculation.
+ + + + + + + + + + + +
+ + +
+

Some more content after the last PHP tag block.

diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.3.inc new file mode 100644 index 000000000..2d608490a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.3.inc @@ -0,0 +1,123 @@ + + + +<?= $title ?> + + + + + hello + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +// Safeguard fixing when there is no whitespace between the close tag and the contents. + + + + + + + + + +<?= $title; ?> + + + + + hello + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Safeguard fixing when there is no whitespace between the close tag and the contents. + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed new file mode 100644 index 000000000..b7985cc50 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.4.inc.fixed @@ -0,0 +1,7 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc new file mode 100644 index 000000000..f4d8d8a0c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.5.inc @@ -0,0 +1,48 @@ + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + - - -<?php echo $title ?> - - - - - hello - - - - - - - - - - - - - - - - - - - - - -section as $section) { - ?> -
- - - - - section as $section) { - ?> -
- - - - - - - - -?> - - - - - - - - - - - - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed deleted file mode 100644 index 5b43d8493..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.inc.fixed +++ /dev/null @@ -1,119 +0,0 @@ - - - -<?php echo $title; ?> - - - - - hello - - - - - - - - - - - - - - - - - - - -section as $section) { - ?> -
- - - - - section as $section) { - ?> -
- - - - - - - - - - - - -?> - - - - - - - - - - - - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php index f8cf4cc79..29111c873 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EmbeddedPhpUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the EmbeddedPhp sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\EmbeddedPhpSniff + */ +final class EmbeddedPhpUnitTest extends AbstractSniffUnitTest { @@ -21,41 +26,173 @@ class EmbeddedPhpUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 7 => 1, - 12 => 1, - 18 => 1, - 19 => 2, - 20 => 1, - 21 => 1, - 22 => 3, - 24 => 1, - 26 => 1, - 29 => 1, - 30 => 1, - 31 => 1, - 34 => 1, - 36 => 1, - 40 => 1, - 41 => 1, - 44 => 1, - 45 => 1, - 49 => 1, - 59 => 1, - 63 => 1, - 93 => 1, - 94 => 2, - 100 => 1, - 102 => 1, - 112 => 1, - 113 => 1, - 116 => 1, - 117 => 1, - ]; + switch ($testFile) { + case 'EmbeddedPhpUnitTest.1.inc': + return [ + 7 => 1, + 12 => 1, + 18 => 1, + 19 => 2, + 20 => 1, + 21 => 1, + 22 => 3, + 24 => 1, + 26 => 1, + 29 => 1, + 30 => 1, + 31 => 1, + 34 => 1, + 36 => 1, + 40 => 1, + 41 => 1, + 44 => 1, + 45 => 1, + 49 => 1, + 59 => 1, + 63 => 1, + 93 => 1, + 94 => 2, + 100 => 1, + 102 => 1, + 112 => 1, + 113 => 1, + 116 => 1, + 117 => 1, + 120 => 1, + 121 => 1, + 128 => 1, + 129 => 1, + 132 => 1, + 134 => 1, + 136 => 1, + 138 => 1, + 142 => 1, + 145 => 1, + 151 => 1, + 158 => 1, + 165 => 1, + 169 => 1, + 175 => 1, + 176 => 2, + 178 => 1, + 179 => 1, + 180 => 2, + 181 => 1, + 189 => 1, + 212 => 1, + 214 => 2, + 219 => 1, + 223 => 1, + 225 => 1, + 226 => 1, + 227 => 2, + 228 => 1, + 235 => 1, + 241 => 1, + 248 => 1, + 253 => 1, + 258 => 1, + 263 => 1, + 264 => 1, + ]; + + case 'EmbeddedPhpUnitTest.2.inc': + case 'EmbeddedPhpUnitTest.4.inc': + return [ + 5 => 2, + 6 => 2, + 7 => 2, + ]; + + case 'EmbeddedPhpUnitTest.3.inc': + return [ + 10 => 1, + 15 => 1, + 21 => 1, + 22 => 2, + 23 => 1, + 24 => 1, + 25 => 3, + 28 => 1, + 29 => 1, + 30 => 1, + 33 => 1, + 35 => 1, + 39 => 1, + 40 => 1, + 43 => 1, + 44 => 1, + 48 => 1, + 53 => 1, + 55 => 1, + 61 => 1, + 62 => 1, + 65 => 2, + 66 => 2, + 69 => 1, + 70 => 1, + 75 => 1, + 82 => 1, + 89 => 1, + 93 => 1, + 98 => 2, + 99 => 1, + 103 => 2, + 105 => 1, + 111 => 1, + 112 => 2, + 114 => 1, + 115 => 1, + 116 => 2, + 117 => 1, + ]; + + case 'EmbeddedPhpUnitTest.5.inc': + return [ + 16 => 1, + 18 => 1, + 25 => 1, + 26 => 1, + 29 => 1, + 31 => 1, + 33 => 1, + 35 => 1, + 39 => 1, + 42 => 1, + ]; + + case 'EmbeddedPhpUnitTest.12.inc': + case 'EmbeddedPhpUnitTest.13.inc': + return [ + 10 => 1, + 12 => 1, + ]; + + case 'EmbeddedPhpUnitTest.18.inc': + return [11 => 1]; + + case 'EmbeddedPhpUnitTest.19.inc': + return [13 => 1]; + + case 'EmbeddedPhpUnitTest.20.inc': + case 'EmbeddedPhpUnitTest.21.inc': + return [12 => 2]; + + case 'EmbeddedPhpUnitTest.22.inc': + return [ + 14 => 1, + 22 => 2, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php index adee78826..db0af7f04 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EvalUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EvalUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the Eval sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\EvalSniff + */ +final class EvalUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php index 52f6a00a5..c0c79baa6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/GlobalKeywordUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class GlobalKeywordUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the GlobalKeyword sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\GlobalKeywordSniff + */ +final class GlobalKeywordUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc new file mode 100644 index 000000000..d1863c076 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.1.inc @@ -0,0 +1,12 @@ +foo. +Now, I am printing some {$foo->bar[1]}. +This should not print a capital 'A': \x41 +EOT; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc similarity index 58% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc index 56f4393ae..eb0062f08 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.2.inc @@ -1,16 +1,6 @@ foo. -Now, I am printing some {$foo->bar[1]}. -This should not print a capital 'A': \x41 -EOT; +// Intentional parse error. // The following function has a simulated git conflict for testing. // This is not a merge conflict - it is a valid test case. // Please do not remove. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php index 2f06f0b08..5d78d8938 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/HeredocUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class HeredocUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the Heredoc sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\HeredocSniff + */ +final class HeredocUnitTest extends AbstractSniffUnitTest { @@ -21,14 +26,22 @@ class HeredocUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 2 => 1, - 8 => 1, - ]; + switch ($testFile) { + case 'HeredocUnitTest.1.inc': + return [ + 2 => 1, + 8 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc index dd851461b..d16c7f2eb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.inc @@ -48,3 +48,40 @@ new class { } } }; + +$outerClosure = function () +{ + // Functions inside closures are not allowed. + function innerFunction() { + } +}; + +// Allow methods in classes/traits/interfaces defined inside functions +function foo() { + if (class_exists('MyClass') === false) { + class MyClass { + function foo() {} + } + } + + if (trait_exists('MyTrait') === false) { + trait MyTrait { + function foo() {} + } + } + + if (interface_exists('MyInterface') === false) { + interface MyInterface { + function foo(); + } + } + + // But disallow functions nested inside those methods + if (class_exists('NestedFunctionInMethod') === false) { + class NestedFunctionInMethod { + function foo() { + function innerFunction() {} + } + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php index 3c9ad07bd..fff8871e6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/InnerFunctionsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class InnerFunctionsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the InnerFunctions sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\InnerFunctionsSniff + */ +final class InnerFunctionsUnitTest extends AbstractSniffUnitTest { @@ -28,6 +33,8 @@ public function getErrorList() return [ 5 => 1, 46 => 1, + 55 => 1, + 83 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc index c67381ad8..702b13de0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc @@ -41,3 +41,10 @@ $callToNamespacedFunction = namespace\STR_REPEAT($a, 2); // Could potentially be $filePath = new \File($path); $count = $object?->Count(); + +class AttributesShouldBeIgnored +{ + #[Putenv('FOO', 'foo')] + public function foo(): void + {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed index 40507c040..281425c59 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.inc.fixed @@ -41,3 +41,10 @@ $callToNamespacedFunction = namespace\STR_REPEAT($a, 2); // Could potentially be $filePath = new \File($path); $count = $object?->Count(); + +class AttributesShouldBeIgnored +{ + #[Putenv('FOO', 'foo')] + public function foo(): void + {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php index 708d01ef0..5feb363f6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/LowercasePHPFunctionsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LowercasePHPFunctionsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LowercasePHPFunctions sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\LowercasePHPFunctionsSniff + */ +final class LowercasePHPFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc index ed7f01151..4b1d1ca65 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.1.inc @@ -297,5 +297,124 @@ class TestAlternativeControlStructures { $var_after_class_in_global_space = 1; do_something_else(); -// Intentional syntax error. -return array_map( +// These are parse errors, but that's not the concern of the sniff. +function parseError1() { + defined('FOO') or return 'foo'; + echo 'unreachable'; +} + +function parseError2() { + defined('FOO') || continue; + echo 'unreachable'; +} + +// All logical operators are allowed with inline expressions (but this was not correctly handled by the sniff). +function exitExpressionsWithLogicalOperators() { + $condition = false; + $condition || exit(); + $condition or die(); + + $condition = true; + $condition && die(); + $condition and exit; + + $condition xor die(); + + echo 'still executable as exit, in all of the above cases, is used as part of an expression'; +} + +// Inline expressions are allowed in ternaries. +function exitExpressionsInTernary() { + $value = $myValue ? $myValue : exit(); + $value = $myValue ?: exit(); + $value = $var == 'foo' ? 'bar' : die( 'world' ); + + $value = (!$myValue ) ? exit() : $myValue; + $value = $var != 'foo' ? die( 'world' ) : 'bar'; + + echo 'still executable'; +} + +// Inline expressions are allowed with null coalesce and null coalesce equals. +function exitExpressionsWithNullCoalesce() { + $value = $nullableValue ?? exit(); + $value ??= die(); + echo 'still executable'; +} + +// Inline expressions are allowed in arrow functions. +function exitExpressionsInArrowFunction() { + $callable = fn() => die(); + echo 'still executable'; +} + +// PHP 8.0+: throw expressions which don't stop execution. +function nonStoppingThrowExpressions() { + $callable = fn() => throw new Exception(); + + $value = $myValue ? 'something' : throw new Exception(); + $value = $myValue ?: throw new Exception(); + $value = $myValue ? throw new Exception() : 'something'; + + $value = $nullableValue ?? throw new Exception(); + $value ??= throw new Exception(); + + $condition && throw new Exception(); + $condition || throw new Exception(); + $condition and throw new Exception(); + $condition or throw new Exception(); + + echo 'still executable as throw, in all of the above cases, is used as part of an expression'; + + throw new Exception(); + echo 'non-executable'; +} + +// PHP 8.0+: throw expressions which do stop execution. +function executionStoppingThrowExpressionsA() { + $condition xor throw new Exception(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsB() { + throw $userIsAuthorized ? new ForbiddenException() : new UnauthorizedException(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsC() { + throw $condition1 && $condition2 ? new Exception1() : new Exception2(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsD() { + throw $exception ??= new Exception(); + echo 'non-executable'; +} + +function executionStoppingThrowExpressionsE() { + throw $maybeNullException ?? new Exception(); + echo 'non-executable'; +} + +function returnNotRequiredIgnoreCommentsA() +{ + if ($something === TRUE) { + return /*comment*/; + } + + echo 'foo'; + return /*comment*/; +} + +function returnNotRequiredIgnoreCommentsB() +{ + echo 'foo'; + return; + /*comment*/ +} + +$closure = function () +{ + echo 'foo'; + return; // This return should be flagged as not required. +}; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc index c9bf052f3..9b7a22bcc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.2.inc @@ -58,4 +58,16 @@ $a = new class { } }; +// Multiple statements are still one line of unreachable code, so should get +// only one complaint from this sniff. (Well, technically two here since there +// are two 'exit()' statements above, so one complaint from each of those. So, +// two here, but not six.) +echo 'one'; echo 'two'; echo 'three'; + +// A single statement split across multiple lines. Here we get complaints for +// each line, even though they're all part of one statement. +echo 'one' . 'two' + . 'three' . 'four' + . 'five' . 'six'; + interface MyInterface { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc new file mode 100644 index 000000000..6fe5c16c6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.3.inc @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
non-executable
+ + + + + + + + +
non-executable
+ + + + + + + + +
non-executable
+ + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc new file mode 100644 index 000000000..189466b4d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/NonExecutableCodeUnitTest.4.inc @@ -0,0 +1,6 @@ + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\PHP; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class NonExecutableCodeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the NonExecutableCode sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\PHP\NonExecutableCodeSniff + */ +final class NonExecutableCodeUnitTest extends AbstractSniffUnitTest { @@ -74,8 +79,19 @@ public function getWarningList($testFile='') 252 => 1, 253 => 1, 254 => 2, + 303 => 1, + 308 => 1, + 370 => 1, + 376 => 1, + 381 => 1, + 386 => 1, + 391 => 1, + 396 => 1, + 406 => 1, + 412 => 1, + 419 => 1, ]; - break; + case 'NonExecutableCodeUnitTest.2.inc': return [ 7 => 1, @@ -84,11 +100,22 @@ public function getWarningList($testFile='') 10 => 2, 14 => 1, 54 => 2, + 65 => 2, + 69 => 2, + 70 => 2, + 71 => 2, + ]; + + case 'NonExecutableCodeUnitTest.3.inc': + return [ + 27 => 1, + 36 => 1, + 45 => 1, + 54 => 1, + 62 => 1, ]; - break; default: return []; - break; }//end switch }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php index 59e49910d..e17f9ae7b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MemberVarScopeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MemberVarScope sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MemberVarScopeSniff + */ +final class MemberVarScopeUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php index 4dc717795..d57ce9d9b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MethodScopeUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MethodScopeUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MethodScope sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MethodScopeSniff + */ +final class MethodScopeUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php index b1a5dd6af..543b56973 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/StaticThisUsageUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Scope; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class StaticThisUsageUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the StaticThisUsage sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\StaticThisUsageSniff + */ +final class StaticThisUsageUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php index 862af7d20..e59da3c6e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/ConcatenationSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ConcatenationSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ConcatenationSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\ConcatenationSpacingSniff + */ +final class ConcatenationSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php index a95d1888b..df50beee1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/DoubleQuoteUsageUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class DoubleQuoteUsageUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the DoubleQuoteUsage sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\DoubleQuoteUsageSniff + */ +final class DoubleQuoteUsageUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php index 0d9af1e93..dd8ead06a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Strings/EchoedStringsUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Strings; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class EchoedStringsUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the EchoedStrings sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\Strings\EchoedStringsSniff + */ +final class EchoedStringsUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php index 48bc841fd..38dba6d42 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/CastSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class CastSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the CastSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\CastSpacingSniff + */ +final class CastSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php index ac3f5d6ff..c5567cb72 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ControlStructureSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ControlStructureSpacingSniff + */ +final class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'ControlStructureSpacingUnitTest.inc': @@ -61,7 +66,7 @@ public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') 261 => 1, 262 => 1, ]; - break; + case 'ControlStructureSpacingUnitTest.js': return [ 3 => 1, @@ -76,10 +81,9 @@ public function getErrorList($testFile='ControlStructureSpacingUnitTest.inc') 74 => 2, 75 => 2, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php index 2e18f875b..cb5cf061d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionClosingBraceSpace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionClosingBraceSpaceSniff + */ +final class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class FunctionClosingBraceSpaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'FunctionClosingBraceSpaceUnitTest.inc': @@ -37,7 +42,7 @@ public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') 31 => 1, 39 => 1, ]; - break; + case 'FunctionClosingBraceSpaceUnitTest.js': return [ 13 => 1, @@ -49,10 +54,9 @@ public function getErrorList($testFile='FunctionClosingBraceSpaceUnitTest.inc') 84 => 1, 128 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php index 438263ebe..dcfb3dd17 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionOpeningBraceSpaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionOpeningBraceSpace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionOpeningBraceSpaceSniff + */ +final class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class FunctionOpeningBraceSpaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='FunctionOpeningBraceSpaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'FunctionOpeningBraceSpaceUnitTest.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc index 36a287f07..b03a0ed82 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc @@ -574,3 +574,11 @@ class ClassWithAttributes { // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacing 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +// Issue #3904. +echo 'this line belongs with the #3904 test'; +class Person {public function __construct($name){}} +echo 'this line belongs with the #3904 test'; + +function Foo() {} function bar($name){} +echo 'this line belongs with the #3904 test'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed index ac2df1cb7..443824ca1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed @@ -656,3 +656,18 @@ class ClassWithAttributes { // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacing 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 // phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +// Issue #3904. +echo 'this line belongs with the #3904 test'; + + +class Person {public function __construct($name){}} + + +echo 'this line belongs with the #3904 test'; + + +function Foo() {} function bar($name){} + + +echo 'this line belongs with the #3904 test'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php index fabb6adb9..cc6d96d25 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class FunctionSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the FunctionSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\FunctionSpacingSniff + */ +final class FunctionSpacingUnitTest extends AbstractSniffUnitTest { @@ -95,6 +100,8 @@ public function getErrorList($testFile='') 553 => 1, 560 => 1, 566 => 1, + 580 => 2, + 583 => 3, ]; case 'FunctionSpacingUnitTest.2.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php index 46b0d858f..f5d6c61f7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LanguageConstructSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LanguageConstructSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\LanguageConstructSpacingSniff + */ +final class LanguageConstructSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php index 62b74e369..31158fd27 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/LogicalOperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the LogicalOperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\LogicalOperatorSpacingSniff + */ +final class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest { @@ -21,11 +26,9 @@ class LogicalOperatorSpacingUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * - * @param string $testFile The name of the file being tested. - * * @return array */ - public function getErrorList($testFile='LogicalOperatorSpacingUnitTest.inc') + public function getErrorList() { return [ 4 => 2, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php index 9b4066811..548ee3baa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class MemberVarSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the MemberVarSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\MemberVarSpacingSniff + */ +final class MemberVarSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php index 82a4056f7..c1ef24a42 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ObjectOperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ObjectOperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ObjectOperatorSpacingSniff + */ +final class ObjectOperatorSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc index 06462acc3..765e7ab71 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc @@ -269,7 +269,7 @@ fn&($x) => $x; // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false $a = 3; - +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true yield -1; echo -1; $a = -1; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed index 8b92a4875..ada77fa85 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed @@ -263,7 +263,7 @@ fn&($x) => $x; // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false $a = 3; - +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true yield -1; echo -1; $a = -1; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js index 16eb130f5..f37df9d86 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js @@ -101,3 +101,4 @@ var foo = bar.map(baz=> baz.length); // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed index 877db4678..47c89302b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed @@ -95,3 +95,4 @@ var foo = bar.map(baz => baz.length); // phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments false a = 3; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreSpacingBeforeAssignments true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php index 8e8ad98d0..e9a50c7e7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class OperatorSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the OperatorSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\OperatorSpacingSniff + */ +final class OperatorSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class OperatorSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='OperatorSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'OperatorSpacingUnitTest.inc': @@ -100,7 +105,7 @@ public function getErrorList($testFile='OperatorSpacingUnitTest.inc') 266 => 2, 271 => 2, ]; - break; + case 'OperatorSpacingUnitTest.js': return [ 4 => 1, @@ -143,10 +148,9 @@ public function getErrorList($testFile='OperatorSpacingUnitTest.inc') 100 => 1, 103 => 2, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php index e80f93670..5c20b0010 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/PropertyLabelSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class PropertyLabelSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the PropertyLabel sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\PropertyLabelSpacingSniff + */ +final class PropertyLabelSpacingUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php index d659d6473..0729624c9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeClosingBraceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ScopeClosingBraceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ScopeClosingBrace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeClosingBraceSniff + */ +final class ScopeClosingBraceUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc similarity index 88% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc index 12685dc97..49eaa2b63 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc @@ -95,9 +95,9 @@ public static function fCreate($attributes = []): ?static } // Also account for static used within union types. -public function fCreate($attributes = []): object|static -{ -} +public function staticLast($attributes = []): object|static {} +public function staticMiddle(): string|static|object {} +public function staticFirst(): static|object {} // Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. $callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; @@ -139,3 +139,11 @@ class ReadonlyTest { public function __construct(readonly protected float|int $x, public readonly?string &$y = 'test') {} } + +// PHP 8.2 readonly classes. +readonly class ReadonlyClassTest {} +readonly class ReadonlyClassTest {} + +// PHP 8.3 readonly anonymous classes. +$anon = new readonly class {}; +$anon = new readonly class {}; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed similarity index 88% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed index d3b682ed7..4c116c76a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed @@ -90,9 +90,9 @@ public static function fCreate($attributes = []): ?static } // Also account for static used within union types. -public function fCreate($attributes = []): object|static -{ -} +public function staticLast($attributes = []): object|static {} +public function staticMiddle(): string|static|object {} +public function staticFirst(): static|object {} // Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. $callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; @@ -133,3 +133,11 @@ class ReadonlyTest { public function __construct(readonly protected float|int $x, public readonly ?string &$y = 'test') {} } + +// PHP 8.2 readonly classes. +readonly class ReadonlyClassTest {} +readonly class ReadonlyClassTest {} + +// PHP 8.3 readonly anonymous classes. +$anon = new readonly class {}; +$anon = new readonly class {}; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc new file mode 100644 index 000000000..45cfb5343 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.2.inc @@ -0,0 +1,6 @@ + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ScopeKeywordSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeKeywordSpacingSniff + */ +final class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest { @@ -21,33 +26,46 @@ class ScopeKeywordSpacingUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 7 => 2, - 8 => 1, - 13 => 1, - 14 => 1, - 15 => 1, - 17 => 2, - 26 => 1, - 28 => 1, - 29 => 1, - 64 => 1, - 67 => 1, - 71 => 1, - 103 => 1, - 106 => 1, - 111 => 1, - 119 => 1, - 121 => 1, - 127 => 2, - 134 => 2, - 138 => 2, - 140 => 3, - ]; + switch ($testFile) { + case 'ScopeKeywordSpacingUnitTest.1.inc': + return [ + 7 => 2, + 8 => 1, + 13 => 1, + 14 => 1, + 15 => 1, + 17 => 2, + 26 => 1, + 28 => 1, + 29 => 1, + 64 => 1, + 67 => 1, + 71 => 1, + 103 => 1, + 106 => 1, + 111 => 1, + 119 => 1, + 121 => 1, + 127 => 2, + 134 => 2, + 138 => 2, + 140 => 3, + 145 => 1, + 149 => 1, + ]; + + case 'ScopeKeywordSpacingUnitTest.3.inc': + return [6 => 1]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php index 72196f8e7..218666dc0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class SemicolonSpacingUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the SemicolonSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SemicolonSpacingSniff + */ +final class SemicolonSpacingUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class SemicolonSpacingUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'SemicolonSpacingUnitTest.inc': @@ -43,7 +48,7 @@ public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') 30 => 2, 36 => 1, ]; - break; + case 'SemicolonSpacingUnitTest.js': return [ 3 => 1, @@ -56,10 +61,9 @@ public function getErrorList($testFile='SemicolonSpacingUnitTest.inc') 22 => 1, 25 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css index 1dd1b6e6b..e3f3f0291 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css @@ -23,3 +23,10 @@ } /* phpcs:set Squiz.WhiteSpace.SuperfluousWhitespace ignoreBlankLines false */ +// /** +// * This text is in two types of comment: each line is commented out +// * individually, and the whole block is in what looks like a +// * docblock-comment. This sniff should ignore all this text as there +// * is no superfluous white-space here. +// */ + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed index 59ddddb08..11be21d5c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.1.css.fixed @@ -21,3 +21,10 @@ float: left; } /* phpcs:set Squiz.WhiteSpace.SuperfluousWhitespace ignoreBlankLines false */ + +// /** +// * This text is in two types of comment: each line is commented out +// * individually, and the whole block is in what looks like a +// * docblock-comment. This sniff should ignore all this text as there +// * is no superfluous white-space here. +// */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php index b9ff96fbc..4f7c7cdbc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SuperfluousWhitespaceUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Squiz\Tests\WhiteSpace; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the SuperfluousWhitespace sniff. + * + * @covers \PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff + */ +final class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest { @@ -25,7 +30,7 @@ class SuperfluousWhitespaceUnitTest extends AbstractSniffUnitTest * * @return array */ - public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') + public function getErrorList($testFile='') { switch ($testFile) { case 'SuperfluousWhitespaceUnitTest.1.inc': @@ -44,26 +49,26 @@ public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') 65 => 1, 73 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.2.inc': return [ 2 => 1, 8 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.3.inc': return [ 6 => 1, 10 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.4.inc': case 'SuperfluousWhitespaceUnitTest.5.inc': return [ 1 => 1, 4 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.1.js': return [ 1 => 1, @@ -77,19 +82,18 @@ public function getErrorList($testFile='SuperfluousWhitespaceUnitTest.inc') 38 => 1, 56 => 1, ]; - break; + case 'SuperfluousWhitespaceUnitTest.1.css': return [ 1 => 1, 8 => 1, 9 => 1, 11 => 1, - 25 => 1, + 32 => 1, ]; - break; + default: return []; - break; }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php index 5df4b0fc2..7bf1f0ad0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php @@ -5,7 +5,9 @@ * @author Holger Kral * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * + * @deprecated 3.9.0 */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Debug; @@ -23,7 +25,7 @@ class CodeAnalyzerSniff implements Sniff /** * Returns the token types that this sniff is interested in. * - * @return int[] + * @return array */ public function register() { @@ -46,7 +48,7 @@ public function process(File $phpcsFile, $stackPtr) { $analyzerPath = Config::getExecutablePath('zend_ca'); if ($analyzerPath === null) { - return; + return ($phpcsFile->numTokens + 1); } $fileName = $phpcsFile->getFilename(); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php index 0ed34d13c..5ae72362d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Files; @@ -20,7 +20,7 @@ class ClosingTagSniff implements Sniff /** * Returns an array of tokens this test wants to listen for. * - * @return array + * @return array */ public function register() { @@ -36,7 +36,7 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return int */ public function process(File $phpcsFile, $stackPtr) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php index 267cd0ad6..2dfeb39aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php index efd3b900e..82781a7d6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Debug/CodeAnalyzerUnitTest.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\Debug; @@ -12,14 +12,19 @@ use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; use PHP_CodeSniffer\Config; -class CodeAnalyzerUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the CodeAnalyzer sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\Debug\CodeAnalyzerSniff + */ +final class CodeAnalyzerUnitTest extends AbstractSniffUnitTest { /** * Should this test be skipped for some reason. * - * @return void + * @return bool */ protected function shouldSkipTest() { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php index 4a42cde09..0a031486b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/Files/ClosingTagUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\Files; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ClosingTagUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ClosingTag sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\Files\ClosingTagSniff + */ +final class ClosingTagUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php index e57c73564..94316dad1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Standards\Zend\Tests\NamingConventions; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; -class ValidVariableNameUnitTest extends AbstractSniffUnitTest +/** + * Unit test class for the ValidVariableName sniff. + * + * @covers \PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff + */ +final class ValidVariableNameUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php index b7c2018bc..d3f71b379 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -196,7 +196,11 @@ public function tokenize($string) // The first and last tokens are the open/close tags. array_shift($commentTokens); - array_pop($commentTokens); + $closeTag = array_pop($commentTokens); + + while ($closeTag['content'] !== '?'.'>') { + $closeTag = array_pop($commentTokens); + } if ($leadingZero === true) { $commentTokens[0]['content'] = substr($commentTokens[0]['content'], 1); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php index beba53c2b..9ca2ddf26 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php index ee2f84294..cb7bd3c19 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -905,10 +905,10 @@ public function tokenize($string) * * If a regular expression is not found, NULL is returned. * - * @param string $char The index of the possible regex start character. + * @param int $char The index of the possible regex start character. * @param string $string The complete content of the string being tokenized. - * @param string $chars An array of characters being tokenized. - * @param string $tokens The current array of tokens found in the string. + * @param array $chars An array of characters being tokenized. + * @param array $tokens The current array of tokens found in the string. * * @return array|null */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php index 3fc67b0c8..4be5400a0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -306,7 +306,7 @@ class PHP extends Tokenizer /** * Known lengths of tokens. * - * @var array + * @var array */ public $knownLengths = [ T_ABSTRACT => 8, @@ -526,8 +526,9 @@ protected function tokenize($string) $numTokens = count($tokens); $lastNotEmptyToken = 0; - $insideInlineIf = []; - $insideUseGroup = false; + $insideInlineIf = []; + $insideUseGroup = false; + $insideConstDeclaration = false; $commentTokenizer = new Comment(); @@ -608,7 +609,8 @@ protected function tokenize($string) if ($tokenIsArray === true && isset(Util\Tokens::$contextSensitiveKeywords[$token[0]]) === true && (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true - || $finalTokens[$lastNotEmptyToken]['content'] === '&') + || $finalTokens[$lastNotEmptyToken]['content'] === '&' + || $insideConstDeclaration === true) ) { if (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true) { $preserveKeyword = false; @@ -621,6 +623,23 @@ protected function tokenize($string) $preserveKeyword = true; } + // `new readonly class` should be preserved. + if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW + && strtolower($token[1]) === 'readonly' + ) { + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === false + || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + ) { + break; + } + } + + if (is_array($tokens[$i]) === true && $tokens[$i][0] === T_CLASS) { + $preserveKeyword = true; + } + } + // `new class extends` `new class implements` should be preserved if (($token[0] === T_EXTENDS || $token[0] === T_IMPLEMENTS) && $finalTokens[$lastNotEmptyToken]['code'] === T_CLASS @@ -648,6 +667,30 @@ protected function tokenize($string) } }//end if + // Types in typed constants should not be touched, but the constant name should be. + if ((isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] === T_CONST) + || $insideConstDeclaration === true + ) { + $preserveKeyword = true; + + // Find the next non-empty token. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + break; + } + + if ($tokens[$i] === '=' || $tokens[$i] === ';') { + $preserveKeyword = false; + $insideConstDeclaration = false; + } + }//end if + if ($finalTokens[$lastNotEmptyToken]['content'] === '&') { $preserveKeyword = true; @@ -681,6 +724,56 @@ protected function tokenize($string) } }//end if + /* + Mark the start of a constant declaration to allow for handling keyword to T_STRING + convertion for constant names using reserved keywords. + */ + + if ($tokenIsArray === true && $token[0] === T_CONST) { + $insideConstDeclaration = true; + } + + /* + Close an open "inside constant declaration" marker when no keyword convertion was needed. + */ + + if ($insideConstDeclaration === true + && $tokenIsArray === false + && ($token[0] === '=' || $token[0] === ';') + ) { + $insideConstDeclaration = false; + } + + /* + Special case for `static` used as a function name, i.e. `static()`. + */ + + if ($tokenIsArray === true + && $token[0] === T_STATIC + && $finalTokens[$lastNotEmptyToken]['code'] !== T_NEW + ) { + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + if ($tokens[$i][0] === '(') { + $finalTokens[$newStackPtr] = [ + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => $token[1], + ]; + + $newStackPtr++; + continue 2; + } + + break; + } + }//end if + /* Parse doc blocks into something that can be easily iterated over. */ @@ -750,6 +843,7 @@ protected function tokenize($string) && (isset($tokens[($stackPtr + 1)]) === true && is_array($tokens[($stackPtr + 1)]) === true && $tokens[($stackPtr + 1)][0] === T_STRING + && isset($tokens[($stackPtr + 1)][1][0], $tokens[($stackPtr + 1)][1][1]) === true && strtolower($tokens[($stackPtr + 1)][1][0]) === 'o' && $tokens[($stackPtr + 1)][1][1] !== '_') && preg_match('`^(o[0-7]+(?:_[0-7]+)?)([0-9_]*)$`i', $tokens[($stackPtr + 1)][1], $matches) === 1 @@ -1282,23 +1376,90 @@ protected function tokenize($string) "readonly" keyword for PHP < 8.1 */ - if (PHP_VERSION_ID < 80100 - && $tokenIsArray === true + if ($tokenIsArray === true && strtolower($token[1]) === 'readonly' - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + && (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + || $finalTokens[$lastNotEmptyToken]['code'] === T_NEW) ) { // Get the next non-whitespace token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || $tokens[$i][0] !== T_WHITESPACE + || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } } + $isReadonlyKeyword = false; + if (isset($tokens[$i]) === false || $tokens[$i] !== '(' ) { + $isReadonlyKeyword = true; + } else if ($tokens[$i] === '(') { + /* + * Skip over tokens which can be used in type declarations. + * At this point, the only token types which need to be taken into consideration + * as potential type declarations are identifier names, T_ARRAY, T_CALLABLE and T_NS_SEPARATOR + * and the union/intersection/dnf parentheses. + */ + + $foundDNFParens = 1; + $foundDNFPipe = 0; + + for (++$i; $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true) { + $tokenType = $tokens[$i][0]; + } else { + $tokenType = $tokens[$i]; + } + + if (isset(Util\Tokens::$emptyTokens[$tokenType]) === true) { + continue; + } + + if ($tokenType === '|') { + ++$foundDNFPipe; + continue; + } + + if ($tokenType === ')') { + ++$foundDNFParens; + continue; + } + + if ($tokenType === '(') { + ++$foundDNFParens; + continue; + } + + if ($tokenType === T_STRING + || $tokenType === T_NAME_FULLY_QUALIFIED + || $tokenType === T_NAME_RELATIVE + || $tokenType === T_NAME_QUALIFIED + || $tokenType === T_ARRAY + || $tokenType === T_NAMESPACE + || $tokenType === T_NS_SEPARATOR + || $tokenType === T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG // PHP 8.0+. + || $tokenType === '&' // PHP < 8.0. + ) { + continue; + } + + // Reached the next token after. + if (($foundDNFParens % 2) === 0 + && $foundDNFPipe >= 1 + && ($tokenType === T_VARIABLE + || $tokenType === T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG) + ) { + $isReadonlyKeyword = true; + } + + break; + }//end for + }//end if + + if ($isReadonlyKeyword === true) { $finalTokens[$newStackPtr] = [ 'code' => T_READONLY, 'type' => 'T_READONLY', @@ -1306,8 +1467,23 @@ protected function tokenize($string) ]; $newStackPtr++; - continue; - } + if (PHP_CODESNIFFER_VERBOSITY > 1 && $type !== T_READONLY) { + echo "\t\t* token $stackPtr changed from $type to T_READONLY".PHP_EOL; + } + } else { + $finalTokens[$newStackPtr] = [ + 'code' => T_STRING, + 'type' => 'T_STRING', + 'content' => $token[1], + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1 && $type !== T_STRING) { + echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL; + } + }//end if + + continue; }//end if /* @@ -1597,7 +1773,7 @@ protected function tokenize($string) || (stripos($newContent, '0b') === 0 && bindec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (stripos($newContent, '0o') === 0 && octdec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (stripos($newContent, '0x') !== 0 - && stripos($newContent, 'e') !== false || strpos($newContent, '.') !== false) + && (stripos($newContent, 'e') !== false || strpos($newContent, '.') !== false)) || (strpos($newContent, '0') === 0 && stripos($newContent, '0x') !== 0 && stripos($newContent, '0b') !== 0 && octdec(str_replace('_', '', $newContent)) > PHP_INT_MAX) || (strpos($newContent, '0') !== 0 && str_replace('_', '', $newContent) > PHP_INT_MAX)) @@ -1739,6 +1915,20 @@ protected function tokenize($string) $newToken = []; $newToken['content'] = '?'; + // For typed constants, we only need to check the token before the ? to be sure. + if ($finalTokens[$lastNotEmptyToken]['code'] === T_CONST) { + $newToken['code'] = T_NULLABLE; + $newToken['type'] = 'T_NULLABLE'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr changed from ? to T_NULLABLE".PHP_EOL; + } + + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + continue; + } + /* * Check if the next non-empty token is one of the tokens which can be used * in type declarations. If not, it's definitely a ternary. @@ -2103,38 +2293,83 @@ function return types. We want to keep the parenthesis map clean, } } else { // Some T_STRING tokens should remain that way due to their context. - if ($tokenIsArray === true - && $token[0] === T_STRING - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true - ) { - // Special case for syntax like: return new self/new parent - // where self/parent should not be a string. - $tokenContentLower = strtolower($token[1]); - if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW - && ($tokenContentLower === 'self' || $tokenContentLower === 'parent') + if ($tokenIsArray === true && $token[0] === T_STRING) { + $preserveTstring = false; + + // True/false/parent/self/static in typed constants should be fixed to their own token, + // but the constant name should not be. + if ((isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] === T_CONST) + || $insideConstDeclaration === true ) { - $finalTokens[$newStackPtr] = [ - 'content' => $token[1], - ]; - if ($tokenContentLower === 'self') { - $finalTokens[$newStackPtr]['code'] = T_SELF; - $finalTokens[$newStackPtr]['type'] = 'T_SELF'; + // Find the next non-empty token. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + break; } - if ($tokenContentLower === 'parent') { - $finalTokens[$newStackPtr]['code'] = T_PARENT; - $finalTokens[$newStackPtr]['type'] = 'T_PARENT'; + if ($tokens[$i] === '=') { + $preserveTstring = true; + $insideConstDeclaration = false; + } + } else if (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true + && $finalTokens[$lastNotEmptyToken]['code'] !== T_CONST + ) { + $preserveTstring = true; + + // Special case for syntax like: return new self/new parent + // where self/parent should not be a string. + $tokenContentLower = strtolower($token[1]); + if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW + && ($tokenContentLower === 'self' || $tokenContentLower === 'parent') + ) { + $preserveTstring = false; + } + } else if ($finalTokens[$lastNotEmptyToken]['content'] === '&') { + // Function names for functions declared to return by reference. + for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) { + if (isset(Util\Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { + continue; + } + + if ($finalTokens[$i]['code'] === T_FUNCTION) { + $preserveTstring = true; + } + + break; } } else { + // Keywords with special PHPCS token when used as a function call. + for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { + if (is_array($tokens[$i]) === true + && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + ) { + continue; + } + + if ($tokens[$i][0] === '(') { + $preserveTstring = true; + } + + break; + } + }//end if + + if ($preserveTstring === true) { $finalTokens[$newStackPtr] = [ - 'content' => $token[1], 'code' => T_STRING, 'type' => 'T_STRING', + 'content' => $token[1], ]; - } - $newStackPtr++; - continue; + $newStackPtr++; + continue; + } }//end if $newToken = null; @@ -2249,11 +2484,12 @@ function return types. We want to keep the parenthesis map clean, if (is_array($tokens[$i]) === false && ($tokens[$i] === ';' - || $tokens[$i] === '{') + || $tokens[$i] === '{' + || $tokens[$i] === '}') ) { break; } - } + }//end for }//end if if ($isInlineIf === true) { @@ -2803,6 +3039,7 @@ protected function processAdditional() T_PARENT => T_PARENT, T_STATIC => T_STATIC, T_FALSE => T_FALSE, + T_TRUE => T_TRUE, T_NULL => T_NULL, T_NAMESPACE => T_NAMESPACE, T_NS_SEPARATOR => T_NS_SEPARATOR, @@ -2854,6 +3091,12 @@ protected function processAdditional() $suspectedType = 'return'; } + if ($this->tokens[$x]['code'] === T_EQUAL) { + // Possible constant declaration, the `T_STRING` name will have been skipped over already. + $suspectedType = 'constant'; + break; + } + break; }//end for @@ -2862,6 +3105,10 @@ protected function processAdditional() continue; } + if ($suspectedType === 'property or parameter') { + unset($allowed[T_STATIC]); + } + $typeTokenCount = 0; $typeOperators = [$i]; $confirmed = false; @@ -2891,9 +3138,15 @@ protected function processAdditional() break; } + if ($suspectedType === 'constant' && $this->tokens[$x]['code'] === T_CONST) { + $confirmed = true; + break; + } + if ($suspectedType === 'property or parameter' && (isset(Util\Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_VAR + || $this->tokens[$x]['code'] === T_STATIC || $this->tokens[$x]['code'] === T_READONLY) ) { // This will also confirm constructor property promotion parameters, but that's fine. @@ -2995,14 +3248,16 @@ protected function processAdditional() || $this->tokens[$i]['code'] === T_FALSE || $this->tokens[$i]['code'] === T_NULL ) { - for ($x = ($i + 1); $i < $numTokens; $x++) { + for ($x = ($i + 1); $x < $numTokens; $x++) { if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Non-whitespace content. break; } } - if (isset($this->tstringContexts[$this->tokens[$x]['code']]) === true) { + if ($x !== $numTokens + && isset($this->tstringContexts[$this->tokens[$x]['code']]) === true + ) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $line = $this->tokens[$i]['line']; $type = $this->tokens[$i]['type']; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php index 0e00bf7f2..bfe8c7a14 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tokenizers; @@ -27,7 +27,7 @@ abstract class Tokenizer * * @var string */ - protected $eolChar = []; + protected $eolChar = ''; /** * A token-based representation of the content. @@ -60,7 +60,7 @@ abstract class Tokenizer /** * Known lengths of tokens. * - * @var array + * @var array */ public $knownLengths = []; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php index 68abef59c..932952e4b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; @@ -19,7 +19,7 @@ class Cache /** * The filesystem location of the cache file. * - * @var void + * @var string */ private static $path = ''; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php index ce7967cc3..afed49e70 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; @@ -35,7 +35,7 @@ class Common * * @param string $path The path to use. * - * @return mixed + * @return bool */ public static function isPharFile($path) { @@ -83,7 +83,7 @@ public static function isReadable($path) * * @param string $path The path to use. * - * @return mixed + * @return string|false */ public static function realpath($path) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php index 65e5d6cb3..ca1060bc9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php index 95ee85216..57470c77a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; @@ -40,6 +40,51 @@ public static function startTiming() }//end startTiming() + /** + * Get the duration of the run up to "now". + * + * @return float Duration in microseconds. + */ + public static function getDuration() + { + if (self::$startTime === null) { + // Timing was never started. + return 0; + } + + return ((microtime(true) - self::$startTime) * 1000); + + }//end getDuration() + + + /** + * Convert a duration in microseconds to a human readable duration string. + * + * @param float $duration Duration in microseconds. + * + * @return string + */ + public static function getHumanReadableDuration($duration) + { + $timeString = ''; + if ($duration > 60000) { + $mins = floor($duration / 60000); + $secs = round((fmod($duration, 60000) / 1000), 2); + $timeString = $mins.' mins'; + if ($secs !== 0) { + $timeString .= ", $secs secs"; + } + } else if ($duration > 1000) { + $timeString = round(($duration / 1000), 2).' secs'; + } else { + $timeString = round($duration).'ms'; + } + + return $timeString; + + }//end getHumanReadableDuration() + + /** * Print information about the run. * @@ -60,23 +105,11 @@ public static function printRunTime($force=false) return; } - $time = ((microtime(true) - self::$startTime) * 1000); - - if ($time > 60000) { - $mins = floor($time / 60000); - $secs = round((fmod($time, 60000) / 1000), 2); - $time = $mins.' mins'; - if ($secs !== 0) { - $time .= ", $secs secs"; - } - } else if ($time > 1000) { - $time = round(($time / 1000), 2).' secs'; - } else { - $time = round($time).'ms'; - } + $duration = self::getDuration(); + $duration = self::getHumanReadableDuration($duration); $mem = round((memory_get_peak_usage(true) / (1024 * 1024)), 2).'MB'; - echo "Time: $time; Memory: $mem".PHP_EOL.PHP_EOL; + echo "Time: $duration; Memory: $mem".PHP_EOL.PHP_EOL; self::$printed = true; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php index bb1fb2ca9..ab70e7832 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Util; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php b/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php index 9d099c1e3..4fa41d9d9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/AllTests.php @@ -4,19 +4,13 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; -if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === false) { - include_once 'Core/AllTests.php'; - include_once 'Standards/AllSniffs.php'; -} else { - include_once 'CodeSniffer/Core/AllTests.php'; - include_once 'CodeSniffer/Standards/AllSniffs.php'; - include_once 'FileList.php'; -} +require_once 'Core/AllTests.php'; +require_once 'Standards/AllSniffs.php'; // PHPUnit 7 made the TestSuite run() method incompatible with // older PHPUnit versions due to return type hints, so maintain @@ -24,7 +18,7 @@ $phpunit7 = false; if (class_exists('\PHPUnit\Runner\Version') === true) { $version = \PHPUnit\Runner\Version::id(); - if ($version[0] === '7') { + if (version_compare($version, '7.0', '>=') === true) { $phpunit7 = true; } } diff --git a/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php new file mode 100644 index 000000000..190f75ece --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php @@ -0,0 +1,196 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests; + +use PHP_CodeSniffer\Config; +use ReflectionProperty; + +final class ConfigDouble extends Config +{ + + /** + * Whether or not the setting of a standard should be skipped. + * + * @var boolean + */ + private $skipSettingStandard = false; + + + /** + * Creates a clean Config object and populates it with command line values. + * + * @param array $cliArgs An array of values gathered from CLI args. + * @param bool $skipSettingStandard Whether to skip setting a standard to prevent + * the Config class trying to auto-discover a ruleset file. + * Should only be set to `true` for tests which actually test + * the ruleset auto-discovery. + * Note: there is no need to set this to `true` when a standard + * is being passed via the `$cliArgs`. Those settings will always + * respected. + * Defaults to `false`. Will result in the standard being set + * to "PSR1" if not provided via `$cliArgs`. + * @param bool $skipSettingReportWidth Whether to skip setting a report-width to prevent + * the Config class trying to auto-discover the screen width. + * Should only be set to `true` for tests which actually test + * the screen width auto-discovery. + * Note: there is no need to set this to `true` when a report-width + * is being passed via the `$cliArgs`. Those settings will always + * respected. + * Defaults to `false`. Will result in the reportWidth being set + * to "80" if not provided via `$cliArgs`. + * + * @return void + */ + public function __construct(array $cliArgs=[], $skipSettingStandard=false, $skipSettingReportWidth=false) + { + $this->skipSettingStandard = $skipSettingStandard; + + $this->resetSelectProperties(); + $this->preventReadingCodeSnifferConfFile(); + + parent::__construct($cliArgs); + + if ($skipSettingReportWidth !== true) { + $this->preventAutoDiscoveryScreenWidth(); + } + + }//end __construct() + + + /** + * Sets the command line values and optionally prevents a file system search for a custom ruleset. + * + * @param array $args An array of command line arguments to set. + * + * @return void + */ + public function setCommandLineValues($args) + { + parent::setCommandLineValues($args); + + if ($this->skipSettingStandard !== true) { + $this->preventSearchingForRuleset(); + } + + }//end setCommandLineValues() + + + /** + * Reset a few properties on the Config class to their default values. + * + * @return void + */ + private function resetSelectProperties() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + + }//end resetSelectProperties() + + + /** + * Prevent the values in a potentially available user-specific `CodeSniffer.conf` file + * from influencing the tests. + * + * This also prevents some file system calls which can influence the test runtime. + * + * @return void + */ + private function preventReadingCodeSnifferConfFile() + { + $this->setStaticConfigProperty('configData', []); + $this->setStaticConfigProperty('configDataFile', ''); + + }//end preventReadingCodeSnifferConfFile() + + + /** + * Prevent searching for a custom ruleset by setting a standard, but only if the test + * being run doesn't set a standard itself. + * + * This also prevents some file system calls which can influence the test runtime. + * + * The standard being set is the smallest one available so the ruleset initialization + * will be the fastest possible. + * + * @return void + */ + private function preventSearchingForRuleset() + { + $overriddenDefaults = $this->getStaticConfigProperty('overriddenDefaults'); + if (isset($overriddenDefaults['standards']) === false) { + $this->standards = ['PSR1']; + $overriddenDefaults['standards'] = true; + } + + self::setStaticConfigProperty('overriddenDefaults', $overriddenDefaults); + + }//end preventSearchingForRuleset() + + + /** + * Prevent a call to stty to figure out the screen width, but only if the test being run + * doesn't set a report width itself. + * + * @return void + */ + private function preventAutoDiscoveryScreenWidth() + { + $settings = $this->getSettings(); + if ($settings['reportWidth'] === 'auto') { + $this->reportWidth = self::DEFAULT_REPORT_WIDTH; + } + + }//end preventAutoDiscoveryScreenWidth() + + + /** + * Helper function to retrieve the value of a private static property on the Config class. + * + * @param string $name The name of the property to retrieve. + * + * @return mixed + */ + private function getStaticConfigProperty($name) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + return $property->getValue(); + + }//end getStaticConfigProperty() + + + /** + * Helper function to set the value of a private static property on the Config class. + * + * @param string $name The name of the property to set. + * @param mixed $value The value to set the property to. + * + * @return void + */ + private function setStaticConfigProperty($name, $value) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticConfigProperty() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php index 4d4f54699..b8522bf4b 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php @@ -4,14 +4,15 @@ * * @author Juliette Reinders Folmer * @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; abstract class AbstractMethodUnitTest extends TestCase @@ -27,6 +28,15 @@ abstract class AbstractMethodUnitTest extends TestCase */ protected static $fileExtension = 'inc'; + /** + * The tab width setting to use when tokenizing the file. + * + * This allows for test case files to use a different tab width than the default. + * + * @var integer + */ + protected static $tabWidth = 4; + /** * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. * @@ -41,12 +51,15 @@ abstract class AbstractMethodUnitTest extends TestCase * The test case file for a unit test class has to be in the same directory * directory and use the same file name as the test class, using the .inc extension. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeFile() { - $config = new Config(); - $config->standards = ['PSR1']; + $config = new ConfigDouble(); + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = static::$tabWidth; $ruleset = new Ruleset($config); @@ -62,19 +75,26 @@ public static function setUpBeforeClass() self::$phpcsFile = new DummyFile($contents, $ruleset, $config); self::$phpcsFile->process(); - }//end setUpBeforeClass() + }//end initializeFile() /** - * Clean up after finished test. + * Get the token pointer for a target token based on a specific comment found on the line before. * - * @return void + * Note: the test delimiter comment MUST start with "/* test" to allow this function to + * distinguish between comments used *in* a test and test delimiters. + * + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. + * + * @return int */ - public static function tearDownAfterClass() + public function getTargetToken($commentString, $tokenType, $tokenContent=null) { - self::$phpcsFile = null; + return self::getTargetTokenFromFile(self::$phpcsFile, $commentString, $tokenType, $tokenContent); - }//end tearDownAfterClass() + }//end getTargetToken() /** @@ -83,16 +103,17 @@ public static function tearDownAfterClass() * Note: the test delimiter comment MUST start with "/* test" to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to find the token in. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. * * @return int */ - public function getTargetToken($commentString, $tokenType, $tokenContent=null) + public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $tokenType, $tokenContent=null) { - $start = (self::$phpcsFile->numTokens - 1); - $comment = self::$phpcsFile->findPrevious( + $start = ($phpcsFile->numTokens - 1); + $comment = $phpcsFile->findPrevious( T_COMMENT, $start, null, @@ -100,7 +121,7 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) $commentString ); - $tokens = self::$phpcsFile->getTokens(); + $tokens = $phpcsFile->getTokens(); $end = ($start + 1); // Limit the token finding to between this and the next delimiter comment. @@ -115,7 +136,7 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) } } - $target = self::$phpcsFile->findNext( + $target = $phpcsFile->findNext( $tokenType, ($comment + 1), $end, @@ -129,12 +150,36 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) $msg .= ' With token content: '.$tokenContent; } - $this->assertFalse(true, $msg); + self::assertFalse(true, $msg); } return $target; - }//end getTargetToken() + }//end getTargetTokenFromFile() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException in a PHPUnit cross-version + * compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + public function expectRunTimeException($message) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + }//end expectRunTimeException() }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php index 304690eff..60547bb36 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php @@ -5,7 +5,7 @@ * @author Greg Sherwood * @author Juliette Reinders Folmer * @copyright 2006-2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php index c0f38fa6f..ea40a5402 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Autoloader; @@ -12,20 +12,27 @@ use PHP_CodeSniffer\Autoload; use PHPUnit\Framework\TestCase; -class DetermineLoadedClassTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Autoload::determineLoadedClass method. + * + * @covers \PHP_CodeSniffer\Autoload::determineLoadedClass + */ +final class DetermineLoadedClassTest extends TestCase { /** * Load the test files. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function includeFixture() { include __DIR__.'/TestFiles/Sub/C.inc'; - }//end setUpBeforeClass() + }//end includeFixture() /** diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php new file mode 100644 index 000000000..2e67fa269 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php @@ -0,0 +1,332 @@ + + * @copyright 2006-2023 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Config; + +use PHP_CodeSniffer\Config; +use PHPUnit\Framework\TestCase; +use ReflectionProperty; + +/** + * Tests for the \PHP_CodeSniffer\Config reportWidth value. + * + * @covers \PHP_CodeSniffer\Config::__get + */ +final class ReportWidthTest extends TestCase +{ + + + /** + * Set static properties in the Config class to prevent tests influencing each other. + * + * @before + * + * @return void + */ + public static function cleanConfig() + { + // Set to the property's default value to clear out potentially set values from other tests. + self::setStaticProperty('executablePaths', []); + + // Set to a usable value to circumvent Config trying to find a phpcs.xml config file. + self::setStaticProperty('overriddenDefaults', ['standards' => ['PSR1']]); + + // Set to values which prevent the test-runner user's `CodeSniffer.conf` file + // from being read and influencing the tests. + self::setStaticProperty('configData', []); + self::setStaticProperty('configDataFile', ''); + + }//end cleanConfig() + + + /** + * Clean up after each finished test. + * + * @after + * + * @return void + */ + public function resetConfig() + { + $_SERVER['argv'] = []; + + }//end resetConfig() + + + /** + * Reset the static properties in the Config class to their true defaults to prevent this class + * from influencing other tests. + * + * @afterClass + * + * @return void + */ + public static function resetConfigToDefaults() + { + self::setStaticProperty('overriddenDefaults', []); + self::setStaticProperty('executablePaths', []); + self::setStaticProperty('configData', null); + self::setStaticProperty('configDataFile', null); + $_SERVER['argv'] = []; + + }//end resetConfigToDefaults() + + + /** + * Test that report width without overrules will always be set to a non-0 positive integer. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthDefault() + { + $config = new Config(); + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthDefault() + + + /** + * Test that the report width will be set to a non-0 positive integer when not found in the CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'show_warnings' => '0', + ]; + + $this->setStaticProperty('configData', $phpCodeSnifferConfig); + + $config = new Config(); + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile() + + + /** + * Test that the report width will be set correctly when found in the CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::getConfigData + * @covers \PHP_CodeSniffer\Config::restoreDefaults + * + * @return void + */ + public function testReportWidthCanBeSetFromConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'report_width' => '120', + ]; + + $this->setStaticProperty('configData', $phpCodeSnifferConfig); + + $config = new Config(); + $this->assertSame(120, $config->reportWidth); + + }//end testReportWidthCanBeSetFromConfFile() + + + /** + * Test that the report width will be set correctly when passed as a CLI argument. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * + * @return void + */ + public function testReportWidthCanBeSetFromCLI() + { + $_SERVER['argv'] = [ + 'phpcs', + '--report-width=100', + ]; + + $config = new Config(); + $this->assertSame(100, $config->reportWidth); + + }//end testReportWidthCanBeSetFromCLI() + + + /** + * Test that the report width will be set correctly when multiple report widths are passed on the CLI. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * + * @return void + */ + public function testReportWidthWhenSetFromCLIFirstValuePrevails() + { + $_SERVER['argv'] = [ + 'phpcs', + '--report-width=100', + '--report-width=200', + ]; + + $config = new Config(); + $this->assertSame(100, $config->reportWidth); + + }//end testReportWidthWhenSetFromCLIFirstValuePrevails() + + + /** + * Test that a report width passed as a CLI argument will overrule a report width set in a CodeSniffer.conf file. + * + * @covers \PHP_CodeSniffer\Config::__set + * @covers \PHP_CodeSniffer\Config::processLongArgument + * @covers \PHP_CodeSniffer\Config::getConfigData + * + * @return void + */ + public function testReportWidthSetFromCLIOverrulesConfFile() + { + $phpCodeSnifferConfig = [ + 'default_standard' => 'PSR2', + 'report_format' => 'summary', + 'show_warnings' => '0', + 'show_progress' => '1', + 'report_width' => '120', + ]; + + $this->setStaticProperty('configData', $phpCodeSnifferConfig); + + $cliArgs = [ + 'phpcs', + '--report-width=180', + ]; + + $config = new Config($cliArgs); + $this->assertSame(180, $config->reportWidth); + + }//end testReportWidthSetFromCLIOverrulesConfFile() + + + /** + * Test that the report width will be set to a non-0 positive integer when set to "auto". + * + * @covers \PHP_CodeSniffer\Config::__set + * + * @return void + */ + public function testReportWidthInputHandlingForAuto() + { + $config = new Config(); + $config->reportWidth = 'auto'; + + // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. + $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); + $this->assertGreaterThan(0, $config->reportWidth, 'Report width is not greater than 0'); + + }//end testReportWidthInputHandlingForAuto() + + + /** + * Test that the report width will be set correctly for various types of input. + * + * @param mixed $input Input value received. + * @param int $expected Expected report width. + * + * @dataProvider dataReportWidthInputHandling + * @covers \PHP_CodeSniffer\Config::__set + * + * @return void + */ + public function testReportWidthInputHandling($input, $expected) + { + $config = new Config(); + $config->reportWidth = $input; + + $this->assertSame($expected, $config->reportWidth); + + }//end testReportWidthInputHandling() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataReportWidthInputHandling() + { + return [ + 'No value (empty string)' => [ + 'value' => '', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type null' => [ + 'value' => null, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type false' => [ + 'value' => false, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid input type float' => [ + 'value' => 100.50, + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid string value "invalid"' => [ + 'value' => 'invalid', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: invalid string value, non-integer string "50.25"' => [ + 'value' => '50.25', + 'expected' => Config::DEFAULT_REPORT_WIDTH, + ], + 'Value: valid numeric string value' => [ + 'value' => '250', + 'expected' => 250, + ], + 'Value: valid int value' => [ + 'value' => 220, + 'expected' => 220, + ], + 'Value: negative int value becomes positive int' => [ + 'value' => -180, + 'expected' => 180, + ], + ]; + + }//end dataReportWidthInputHandling() + + + /** + * Helper function to set a static property on the Config class. + * + * @param string $name The name of the property to set. + * @param mixed $value The value to set the property to. + * + * @return void + */ + public static function setStaticProperty($name, $value) + { + $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); + $property->setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticProperty() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php index 7181613c6..4ae1e33ba 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php @@ -4,17 +4,23 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class ErrorSuppressionTest extends TestCase +/** + * Tests for PHP_CodeSniffer error suppression tags. + * + * @covers PHP_CodeSniffer\Files\File::addMessage + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class ErrorSuppressionTest extends TestCase { @@ -27,7 +33,6 @@ class ErrorSuppressionTest extends TestCase * Defaults to 0. * * @dataProvider dataSuppressError - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -36,7 +41,7 @@ public function testSuppressError($before, $after, $expectedErrors=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -58,9 +63,9 @@ public function testSuppressError($before, $after, $expectedErrors=0) * * @see testSuppressError() * - * @return array + * @return array> */ - public function dataSuppressError() + public static function dataSuppressError() { return [ 'no suppression' => [ @@ -160,7 +165,6 @@ public function dataSuppressError() * Defaults to 1. * * @dataProvider dataSuppressSomeErrors - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -169,7 +173,7 @@ public function testSuppressSomeErrors($before, $between, $expectedErrors=1) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -197,9 +201,9 @@ public function testSuppressSomeErrors($before, $between, $expectedErrors=1) * * @see testSuppressSomeErrors() * - * @return array + * @return array> */ - public function dataSuppressSomeErrors() + public static function dataSuppressSomeErrors() { return [ 'no suppression' => [ @@ -253,7 +257,6 @@ public function dataSuppressSomeErrors() * Defaults to 0. * * @dataProvider dataSuppressWarning - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -262,7 +265,7 @@ public function testSuppressWarning($before, $after, $expectedWarnings=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Commenting.Todo']; @@ -289,9 +292,9 @@ public function testSuppressWarning($before, $after, $expectedWarnings=0) * * @see testSuppressWarning() * - * @return array + * @return array> */ - public function dataSuppressWarning() + public static function dataSuppressWarning() { return [ 'no suppression' => [ @@ -338,7 +341,6 @@ public function dataSuppressWarning() * Defaults to 1. * * @dataProvider dataSuppressLine - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -347,7 +349,7 @@ public function testSuppressLine($before, $after='', $expectedErrors=1) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -374,9 +376,9 @@ public function testSuppressLine($before, $after='', $expectedErrors=1) * * @see testSuppressLine() * - * @return array + * @return array> */ - public function dataSuppressLine() + public static function dataSuppressLine() { return [ 'no suppression' => [ @@ -386,12 +388,24 @@ public function dataSuppressLine() ], // With suppression on line before. - 'ignore: line before, slash comment' => ['before' => '// phpcs:ignore'], - 'ignore: line before, slash comment, with @' => ['before' => '// @phpcs:ignore'], - 'ignore: line before, hash comment' => ['before' => '# phpcs:ignore'], - 'ignore: line before, hash comment, with @' => ['before' => '# @phpcs:ignore'], - 'ignore: line before, star comment' => ['before' => '/* phpcs:ignore */'], - 'ignore: line before, star comment, with @' => ['before' => '/* @phpcs:ignore */'], + 'ignore: line before, slash comment' => [ + 'before' => '// phpcs:ignore', + ], + 'ignore: line before, slash comment, with @' => [ + 'before' => '// @phpcs:ignore', + ], + 'ignore: line before, hash comment' => [ + 'before' => '# phpcs:ignore', + ], + 'ignore: line before, hash comment, with @' => [ + 'before' => '# @phpcs:ignore', + ], + 'ignore: line before, star comment' => [ + 'before' => '/* phpcs:ignore */', + ], + 'ignore: line before, star comment, with @' => [ + 'before' => '/* @phpcs:ignore */', + ], // With suppression as trailing comment on code line. 'ignore: end of line, slash comment' => [ @@ -412,7 +426,9 @@ public function dataSuppressLine() ], // Deprecated syntax. - 'old style: line before, slash comment' => ['before' => '// @codingStandardsIgnoreLine'], + 'old style: line before, slash comment' => [ + 'before' => '// @codingStandardsIgnoreLine', + ], 'old style: end of line, slash comment' => [ 'before' => '', 'after' => ' // @codingStandardsIgnoreLine', @@ -425,13 +441,11 @@ public function dataSuppressLine() /** * Test suppressing a single error using a single line ignore in the middle of a line. * - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap - * * @return void */ public function testSuppressLineMidLine() { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -450,13 +464,11 @@ public function testSuppressLineMidLine() /** * Test suppressing a single error using a single line ignore within a docblock. * - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap - * * @return void */ public function testSuppressLineWithinDocblock() { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Files.LineLength']; @@ -488,7 +500,6 @@ public function testSuppressLineWithinDocblock() * @param string $after Annotation to place after the code. * * @dataProvider dataNestedSuppressLine - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -497,7 +508,7 @@ public function testNestedSuppressLine($before, $after) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.PHP.LowerCaseConstant']; @@ -525,9 +536,9 @@ public function testNestedSuppressLine($before, $after) * * @see testNestedSuppressLine() * - * @return array + * @return array> */ - public function dataNestedSuppressLine() + public static function dataNestedSuppressLine() { return [ // Process with disable/enable suppression and no single line suppression. @@ -579,7 +590,6 @@ public function dataNestedSuppressLine() * Defaults to 0. * * @dataProvider dataSuppressScope - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -588,7 +598,7 @@ public function testSuppressScope($before, $after, $expectedErrors=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['PEAR']; $config->sniffs = ['PEAR.Functions.FunctionDeclaration']; @@ -620,9 +630,9 @@ function myFunction() { * * @see testSuppressScope() * - * @return array + * @return array> */ - public function dataSuppressScope() + public static function dataSuppressScope() { return [ 'no suppression' => [ @@ -677,7 +687,6 @@ public function dataSuppressScope() * Defaults to 0. * * @dataProvider dataSuppressFile - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -686,7 +695,7 @@ public function testSuppressFile($before, $after='', $expectedWarnings=0) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = ['Generic.Commenting.Todo']; @@ -715,9 +724,9 @@ class MyClass {} * * @see testSuppressFile() * - * @return array + * @return array> */ - public function dataSuppressFile() + public static function dataSuppressFile() { return [ 'no suppression' => [ @@ -727,16 +736,30 @@ public function dataSuppressFile() ], // Process with suppression. - 'ignoreFile: start of file, slash comment' => ['before' => '// phpcs:ignoreFile'], - 'ignoreFile: start of file, slash comment, with @' => ['before' => '// @phpcs:ignoreFile'], - 'ignoreFile: start of file, slash comment, mixed case' => ['before' => '// PHPCS:Ignorefile'], - 'ignoreFile: start of file, hash comment' => ['before' => '# phpcs:ignoreFile'], - 'ignoreFile: start of file, hash comment, with @' => ['before' => '# @phpcs:ignoreFile'], - 'ignoreFile: start of file, single-line star comment' => ['before' => '/* phpcs:ignoreFile */'], + 'ignoreFile: start of file, slash comment' => [ + 'before' => '// phpcs:ignoreFile', + ], + 'ignoreFile: start of file, slash comment, with @' => [ + 'before' => '// @phpcs:ignoreFile', + ], + 'ignoreFile: start of file, slash comment, mixed case' => [ + 'before' => '// PHPCS:Ignorefile', + ], + 'ignoreFile: start of file, hash comment' => [ + 'before' => '# phpcs:ignoreFile', + ], + 'ignoreFile: start of file, hash comment, with @' => [ + 'before' => '# @phpcs:ignoreFile', + ], + 'ignoreFile: start of file, single-line star comment' => [ + 'before' => '/* phpcs:ignoreFile */', + ], 'ignoreFile: start of file, multi-line star comment' => [ 'before' => '/*'.PHP_EOL.' phpcs:ignoreFile'.PHP_EOL.' */', ], - 'ignoreFile: start of file, single-line docblock comment' => ['before' => '/** phpcs:ignoreFile */'], + 'ignoreFile: start of file, single-line docblock comment' => [ + 'before' => '/** phpcs:ignoreFile */', + ], // Process late comment. 'ignoreFile: late comment, slash comment' => [ @@ -745,12 +768,18 @@ public function dataSuppressFile() ], // Deprecated syntax. - 'old style: start of file, slash comment' => ['before' => '// @codingStandardsIgnoreFile'], - 'old style: start of file, single-line star comment' => ['before' => '/* @codingStandardsIgnoreFile */'], + 'old style: start of file, slash comment' => [ + 'before' => '// @codingStandardsIgnoreFile', + ], + 'old style: start of file, single-line star comment' => [ + 'before' => '/* @codingStandardsIgnoreFile */', + ], 'old style: start of file, multi-line star comment' => [ 'before' => '/*'.PHP_EOL.' @codingStandardsIgnoreFile'.PHP_EOL.' */', ], - 'old style: start of file, single-line docblock comment' => ['before' => '/** @codingStandardsIgnoreFile */'], + 'old style: start of file, single-line docblock comment' => [ + 'before' => '/** @codingStandardsIgnoreFile */', + ], // Deprecated syntax, late comment. 'old style: late comment, slash comment' => [ @@ -772,7 +801,6 @@ public function dataSuppressFile() * Defaults to 0. * * @dataProvider dataDisableSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -781,7 +809,7 @@ public function testDisableSelected($before, $expectedErrors=0, $expectedWarning static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -814,9 +842,9 @@ public function testDisableSelected($before, $expectedErrors=0, $expectedWarning * * @see testDisableSelected() * - * @return array + * @return array> */ - public function dataDisableSelected() + public static function dataDisableSelected() { return [ // Single sniff. @@ -838,7 +866,9 @@ public function dataDisableSelected() ], // Multiple sniffs. - 'disable: multiple sniffs in one comment' => ['before' => '// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant'], + 'disable: multiple sniffs in one comment' => [ + 'before' => '// phpcs:disable Generic.Commenting.Todo,Generic.PHP.LowerCaseConstant', + ], 'disable: multiple sniff in multiple comments' => [ 'before' => '// phpcs:disable Generic.Commenting.Todo'.PHP_EOL.'// phpcs:disable Generic.PHP.LowerCaseConstant', ], @@ -848,12 +878,16 @@ public function dataDisableSelected() 'before' => '// phpcs:disable Generic.Commenting', 'expectedErrors' => 1, ], - 'disable: whole standard' => ['before' => '// phpcs:disable Generic'], + 'disable: whole standard' => [ + 'before' => '// phpcs:disable Generic', + ], 'disable: single errorcode' => [ 'before' => '# @phpcs:disable Generic.Commenting.Todo.TaskFound', 'expectedErrors' => 1, ], - 'disable: single errorcode and a category' => ['before' => '// phpcs:disable Generic.PHP.LowerCaseConstant.Found,Generic.Commenting'], + 'disable: single errorcode and a category' => [ + 'before' => '// phpcs:disable Generic.PHP.LowerCaseConstant.Found,Generic.Commenting', + ], // Wrong category/sniff/code. 'disable: wrong error code and category' => [ @@ -884,7 +918,6 @@ public function dataDisableSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataEnableSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -893,7 +926,7 @@ public function testEnableSelected($code, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -921,9 +954,9 @@ public function testEnableSelected($code, $expectedErrors, $expectedWarnings) * * @see testEnableSelected() * - * @return array + * @return array> */ - public function dataEnableSelected() + public static function dataEnableSelected() { return [ 'disable/enable: a single sniff' => [ @@ -1059,7 +1092,6 @@ public function dataEnableSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataIgnoreSelected - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -1068,7 +1100,7 @@ public function testIgnoreSelected($before, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -1101,9 +1133,9 @@ public function testIgnoreSelected($before, $expectedErrors, $expectedWarnings) * * @see testIgnoreSelected() * - * @return array + * @return array> */ - public function dataIgnoreSelected() + public static function dataIgnoreSelected() { return [ 'no suppression' => [ @@ -1151,7 +1183,6 @@ public function dataIgnoreSelected() * @param int $expectedWarnings Number of warnings expected. * * @dataProvider dataCommenting - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ @@ -1160,7 +1191,7 @@ public function testCommenting($code, $expectedErrors, $expectedWarnings) static $config, $ruleset; if (isset($config, $ruleset) === false) { - $config = new Config(); + $config = new ConfigDouble(); $config->standards = ['Generic']; $config->sniffs = [ 'Generic.PHP.LowerCaseConstant', @@ -1188,9 +1219,9 @@ public function testCommenting($code, $expectedErrors, $expectedWarnings) * * @see testCommenting() * - * @return array + * @return array> */ - public function dataCommenting() + public static function dataCommenting() { return [ 'ignore: single sniff' => [ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php index 7bff26b56..ba04cd591 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php @@ -1,17 +1,22 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindEndOfStatementTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findEndOfStatement + */ +final class FindEndOfStatementTest extends AbstractMethodUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc index aead06cd9..dae2cd969 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc @@ -1,27 +1,32 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindExtendedClassNameTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findExtendedClassName method. + * + * @covers \PHP_CodeSniffer\Files\File::findExtendedClassName + */ +final class FindExtendedClassNameTest extends AbstractMethodUnitTest { + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findExtendedClassName(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findExtendedClassName($token); + $this->assertFalse($result); + + }//end testNotAClass() + + /** * Test retrieving the name of the class being extended by another class * (or interface). * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param string|false $expected Expected function output. * * @dataProvider dataExtendedClass * @@ -40,50 +72,70 @@ public function testFindExtendedClassName($identifier, $expected) * * @see testFindExtendedClassName() * - * @return array + * @return array> */ - public function dataExtendedClass() + public static function dataExtendedClass() { return [ - [ - '/* testExtendedClass */', - 'testFECNClass', + 'class does not extend' => [ + 'identifier' => '/* testNonExtendedClass */', + 'expected' => false, + ], + 'class extends unqualified class' => [ + 'identifier' => '/* testExtendsUnqualifiedClass */', + 'expected' => 'testFECNClass', + ], + 'class extends fully qualified class' => [ + 'identifier' => '/* testExtendsFullyQualifiedClass */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNClass', + ], + 'class extends partially qualified class' => [ + 'identifier' => '/* testExtendsPartiallyQualifiedClass */', + 'expected' => 'Core\File\RelativeClass', + ], + 'interface does not extend' => [ + 'identifier' => '/* testNonExtendedInterface */', + 'expected' => false, + ], + 'interface extends unqualified interface' => [ + 'identifier' => '/* testInterfaceExtendsUnqualifiedInterface */', + 'expected' => 'testFECNInterface', ], - [ - '/* testNamespacedClass */', - '\PHP_CodeSniffer\Tests\Core\File\testFECNClass', + 'interface extends fully qualified interface' => [ + 'identifier' => '/* testInterfaceExtendsFullyQualifiedInterface */', + 'expected' => '\PHP_CodeSniffer\Tests\Core\File\testFECNInterface', ], - [ - '/* testNonExtendedClass */', - false, + 'anon class extends unqualified class' => [ + 'identifier' => '/* testExtendedAnonClass */', + 'expected' => 'testFECNExtendedAnonClass', ], - [ - '/* testInterface */', - false, + 'class does not extend but contains anon class which extends' => [ + 'identifier' => '/* testNestedExtendedClass */', + 'expected' => false, ], - [ - '/* testInterfaceThatExtendsInterface */', - 'testFECNInterface', + 'anon class extends, nested in non-extended class' => [ + 'identifier' => '/* testNestedExtendedAnonClass */', + 'expected' => 'testFECNAnonClass', ], - [ - '/* testInterfaceThatExtendsFQCNInterface */', - '\PHP_CodeSniffer\Tests\Core\File\testFECNInterface', + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => 'testFECNClass', ], - [ - '/* testNestedExtendedClass */', - false, + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => 'testFECNClass', ], - [ - '/* testNestedExtendedAnonClass */', - 'testFECNAnonClass', + 'interface extends multiple interfaces (not supported)' => [ + 'identifier' => '/* testInterfaceMultiExtends */', + 'expected' => '\Package\FooInterface', ], - [ - '/* testClassThatExtendsAndImplements */', - 'testFECNClass', + 'parse error - extends keyword, but no class name' => [ + 'identifier' => '/* testMissingExtendsName */', + 'expected' => false, ], - [ - '/* testClassThatImplementsAndExtends */', - 'testFECNClass', + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc index 44c0f6432..3246efa2c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc @@ -1,23 +1,25 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames method. + * + * @covers \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames + */ +final class FindImplementedInterfaceNamesTest extends AbstractMethodUnitTest { + /** + * Test getting a `false` result when a non-existent token is passed. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->findImplementedInterfaceNames(100000); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test getting a `false` result when a token other than one of the supported tokens is passed. + * + * @return void + */ + public function testNotAClass() + { + $token = $this->getTargetToken('/* testNotAClass */', [T_FUNCTION]); + $result = self::$phpcsFile->findImplementedInterfaceNames($token); + $this->assertFalse($result); + + }//end testNotAClass() + + /** * Test retrieving the name(s) of the interfaces being implemented by a class. * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param array|false $expected Expected function output. * * @dataProvider dataImplementedInterface * @@ -39,63 +71,89 @@ public function testFindImplementedInterfaceNames($identifier, $expected) * * @see testFindImplementedInterfaceNames() * - * @return array + * @return array>> */ - public function dataImplementedInterface() + public static function dataImplementedInterface() { return [ - [ - '/* testImplementedClass */', - ['testFIINInterface'], + 'interface declaration, no implements' => [ + 'identifier' => '/* testPlainInterface */', + 'expected' => false, ], - [ - '/* testMultiImplementedClass */', - [ + 'class does not implement' => [ + 'identifier' => '/* testNonImplementedClass */', + 'expected' => false, + ], + 'class implements single interface, unqualified' => [ + 'identifier' => '/* testClassImplementsSingle */', + 'expected' => [ 'testFIINInterface', - 'testFIINInterface2', ], ], - [ - '/* testNamespacedClass */', - ['\PHP_CodeSniffer\Tests\Core\File\testFIINInterface'], + 'class implements multiple interfaces' => [ + 'identifier' => '/* testClassImplementsMultiple */', + 'expected' => [ + 'testFIINInterface', + 'testFIINInterface2', + ], ], - [ - '/* testNonImplementedClass */', - false, + 'class implements single interface, fully qualified' => [ + 'identifier' => '/* testImplementsFullyQualified */', + 'expected' => [ + '\PHP_CodeSniffer\Tests\Core\File\testFIINInterface', + ], ], - [ - '/* testInterface */', - false, + 'class implements single interface, partially qualified' => [ + 'identifier' => '/* testImplementsPartiallyQualified */', + 'expected' => [ + 'Core\File\RelativeInterface', + ], ], - [ - '/* testClassThatExtendsAndImplements */', - [ + 'class extends and implements' => [ + 'identifier' => '/* testClassThatExtendsAndImplements */', + 'expected' => [ 'InterfaceA', '\NameSpaced\Cat\InterfaceB', ], ], - [ - '/* testClassThatImplementsAndExtends */', - [ + 'class implements and extends' => [ + 'identifier' => '/* testClassThatImplementsAndExtends */', + 'expected' => [ '\InterfaceA', 'InterfaceB', ], ], - [ - '/* testBackedEnumWithoutImplements */', - false, + 'enum does not implement' => [ + 'identifier' => '/* testBackedEnumWithoutImplements */', + 'expected' => false, ], - [ - '/* testEnumImplements */', - ['Colorful'], + 'enum implements single interface, unqualified' => [ + 'identifier' => '/* testEnumImplementsSingle */', + 'expected' => [ + 'Colorful', + ], ], - [ - '/* testBackedEnumImplements */', - [ + 'enum implements multiple interfaces, unqualified + fully qualified' => [ + 'identifier' => '/* testBackedEnumImplementsMulti */', + 'expected' => [ 'Colorful', '\Deck', ], ], + 'anon class implements single interface, unqualified' => [ + 'identifier' => '/* testAnonClassImplementsSingle */', + 'expected' => [ + 'testFIINInterface', + ], + ], + 'parse error - implements keyword, but no interface name' => [ + 'identifier' => '/* testMissingImplementsName */', + 'expected' => false, + ], + 'parse error - live coding - no curly braces' => [ + 'identifier' => '/* testParseError */', + 'expected' => false, + ], ]; }//end dataImplementedInterface() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc index ce9dfad3f..148d8103a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc @@ -121,3 +121,44 @@ return 0; ?>

Test

', foo(), ''; + +$value = [ + /* testPrecededByArrowFunctionInArray - Expected */ + Url::make('View Song', fn($song) => $song->url()) + /* testPrecededByArrowFunctionInArray */ + ->onlyOnDetail(), + + new Panel('Information', [ + Text::make('Title') + ]), +]; + +switch ($foo) { + /* testCaseStatement */ + case 1: + /* testInsideCaseStatement */ + $var = doSomething(); + /* testInsideCaseBreakStatement */ + break 2; + + case 2: + /* testInsideCaseContinueStatement */ + continue 2; + + case 3: + /* testInsideCaseReturnStatement */ + return false; + + case 4: + /* testInsideCaseExitStatement */ + exit(1); + + case 5: + /* testInsideCaseThrowStatement */ + throw new Exception(); + + /* testDefaultStatement */ + default: + /* testInsideDefaultContinueStatement */ + continue $var; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php index ff859eca1..c674a602d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php @@ -3,15 +3,22 @@ * Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method. * * @author Greg Sherwood + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class FindStartOfStatementTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method. + * + * @covers \PHP_CodeSniffer\Files\File::findStartOfStatement + */ +final class FindStartOfStatementTest extends AbstractMethodUnitTest { @@ -500,4 +507,134 @@ public function testOpenTagWithEcho() }//end testOpenTagWithEcho() + /** + * Test object call on result of static function call with arrow function as parameter and wrapped within an array. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2849 + * @link https://github.com/squizlabs/PHP_CodeSniffer/commit/fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9 + * + * @return void + */ + public function testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + { + $expected = $this->getTargetToken('/* testPrecededByArrowFunctionInArray - Expected */', T_STRING, 'Url'); + + $start = $this->getTargetToken('/* testPrecededByArrowFunctionInArray */', T_STRING, 'onlyOnDetail'); + $found = self::$phpcsFile->findStartOfStatement($start); + + $this->assertSame($expected, $found); + + }//end testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInArray() + + + /** + * Test finding the start of a statement inside a switch control structure case/default statement. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targets The token to search for after the test marker. + * @param string|int $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/squizlabs/php_codesniffer/issues/3192 + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3186/commits/18a0e54735bb9b3850fec266e5f4c50dacf618ea + * + * @dataProvider dataFindStartInsideSwitchCaseDefaultStatements + * + * @return void + */ + public function testFindStartInsideSwitchCaseDefaultStatements($testMarker, $targets, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $targets); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideSwitchCaseDefaultStatements() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideSwitchCaseDefaultStatements() + { + return [ + 'Case keyword should be start of case statement - case itself' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_CASE, + 'expectedTarget' => T_CASE, + ], + 'Case keyword should be start of case statement - number (what\'s being compared)' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CASE, + ], + 'Variable should be start of arbitrary assignment statement - variable itself' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - equal sign' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_EQUAL, + 'expectedTarget' => T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - function call' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_VARIABLE, + ], + 'Break should be start for contents of the break statement - contents' => [ + 'testMarker' => '/* testInsideCaseBreakStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_BREAK, + ], + 'Continue should be start for contents of the continue statement - contents' => [ + 'testMarker' => '/* testInsideCaseContinueStatement */', + 'targets' => T_LNUMBER, + 'expectedTarget' => T_CONTINUE, + ], + 'Return should be start for contents of the return statement - contents' => [ + 'testMarker' => '/* testInsideCaseReturnStatement */', + 'targets' => T_FALSE, + 'expectedTarget' => T_RETURN, + ], + 'Exit should be start for contents of the exit statement - close parenthesis' => [ + // Note: not sure if this is actually correct - should this be the open parenthesis ? + 'testMarker' => '/* testInsideCaseExitStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_EXIT, + ], + 'Throw should be start for contents of the throw statement - new keyword' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_NEW, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - exception name' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_THROW, + ], + 'Throw should be start for contents of the throw statement - close parenthesis' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => T_CLOSE_PARENTHESIS, + 'expectedTarget' => T_THROW, + ], + 'Default keyword should be start of default statement - default itself' => [ + 'testMarker' => '/* testDefaultStatement */', + 'targets' => T_DEFAULT, + 'expectedTarget' => T_DEFAULT, + ], + 'Return should be start for contents of the return statement (inside default) - variable' => [ + 'testMarker' => '/* testInsideDefaultContinueStatement */', + 'targets' => T_VARIABLE, + 'expectedTarget' => T_CONTINUE, + ], + ]; + + }//end dataFindStartInsideSwitchCaseDefaultStatements() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc new file mode 100644 index 000000000..2490a0965 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc @@ -0,0 +1,58 @@ + + * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getClassProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getClassProperties + */ +final class GetClassPropertiesTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non class token is passed. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $tokenType The type of token to look for after the marker. + * + * @dataProvider dataNotAClassException + * + * @return void + */ + public function testNotAClassException($testMarker, $tokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_CLASS'); + + $target = $this->getTargetToken($testMarker, $tokenType); + self::$phpcsFile->getClassProperties($target); + + }//end testNotAClassException() + + + /** + * Data provider. + * + * @see testNotAClassException() For the array format. + * + * @return array> + */ + public static function dataNotAClassException() + { + return [ + 'interface' => [ + 'testMarker' => '/* testNotAClass */', + 'tokenType' => T_INTERFACE, + ], + 'anon-class' => [ + 'testMarker' => '/* testAnonClass */', + 'tokenType' => T_ANON_CLASS, + ], + 'enum' => [ + 'testMarker' => '/* testEnum */', + 'tokenType' => T_ENUM, + ], + ]; + + }//end dataNotAClassException() + + + /** + * Test retrieving the properties for a class declaration. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected Expected function output. + * + * @dataProvider dataGetClassProperties + * + * @return void + */ + public function testGetClassProperties($testMarker, $expected) + { + $class = $this->getTargetToken($testMarker, T_CLASS); + $result = self::$phpcsFile->getClassProperties($class); + $this->assertSame($expected, $result); + + }//end testGetClassProperties() + + + /** + * Data provider. + * + * @see testGetClassProperties() For the array format. + * + * @return array>> + */ + public static function dataGetClassProperties() + { + return [ + 'no-properties' => [ + 'testMarker' => '/* testClassWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract' => [ + 'testMarker' => '/* testAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'final' => [ + 'testMarker' => '/* testFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'final-readonly' => [ + 'testMarker' => '/* testFinalReadonlyClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'readonly-final' => [ + 'testMarker' => '/* testReadonlyFinalClass */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'abstract-readonly' => [ + 'testMarker' => '/* testAbstractReadonlyClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'readonly-abstract' => [ + 'testMarker' => '/* testReadonlyAbstractClass */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'comments-and-new-lines' => [ + 'testMarker' => '/* testWithCommentsAndNewLines */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'no-properties-with-docblock' => [ + 'testMarker' => '/* testWithDocblockWithoutProperties */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => false, + ], + ], + 'abstract-final-parse-error' => [ + 'testMarker' => '/* testParseErrorAbstractFinal */', + 'expected' => [ + 'is_abstract' => true, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + ]; + + }//end dataGetClassProperties() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc new file mode 100644 index 000000000..e7684daa9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc @@ -0,0 +1,91 @@ + $v) { + + /* condition 11-2: try */ + try { + --$k; + + /* condition 11-3: catch */ + } catch (Exception $e) { + /* testInException */ + echo 'oh darn'; + /* condition 11-4: finally */ + } finally { + return true; + } + } + + $a++; + } + break; + + /* condition 8b: default */ + default: + /* testInDefault */ + $return = 'nada'; + return $return; + } + } + } + } + } + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php new file mode 100644 index 000000000..5df0f5a27 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php @@ -0,0 +1,494 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getCondition and \PHP_CodeSniffer\Files\File:hasCondition methods. + * + * @covers \PHP_CodeSniffer\Files\File::getCondition + * @covers \PHP_CodeSniffer\Files\File::hasCondition + */ +final class GetConditionTest extends AbstractMethodUnitTest +{ + + /** + * List of all the test markers with their target token in the test case file. + * + * - The startPoint token is left out as it is tested separately. + * - The key is the type of token to look for after the test marker. + * + * @var array + */ + protected static $testTargets = [ + T_VARIABLE => '/* testSeriouslyNestedMethod */', + T_RETURN => '/* testDeepestNested */', + T_ECHO => '/* testInException */', + T_CONSTANT_ENCAPSED_STRING => '/* testInDefault */', + ]; + + /** + * List of all the condition markers in the test case file. + * + * @var array + */ + protected $conditionMarkers = [ + '/* condition 0: namespace */', + '/* condition 1: if */', + '/* condition 2: function */', + '/* condition 3-1: if */', + '/* condition 3-2: else */', + '/* condition 4: if */', + '/* condition 5: nested class */', + '/* condition 6: class method */', + '/* condition 7: switch */', + '/* condition 8a: case */', + '/* condition 9: while */', + '/* condition 10-1: if */', + '/* condition 11-1: nested anonymous class */', + '/* condition 12: nested anonymous class method */', + '/* condition 13: closure */', + '/* condition 10-2: elseif */', + '/* condition 10-3: foreach */', + '/* condition 11-2: try */', + '/* condition 11-3: catch */', + '/* condition 11-4: finally */', + '/* condition 8b: default */', + ]; + + /** + * Base array with all the scope opening tokens. + * + * This array is merged with expected result arrays for various unit tests + * to make sure all possible conditions are tested. + * + * This array should be kept in sync with the Tokens::$scopeOpeners array. + * This array isn't auto-generated based on the array in Tokens as for these + * tests we want to have access to the token constant names, not just their values. + * + * @var array + */ + protected $conditionDefaults = [ + 'T_CLASS' => false, + 'T_ANON_CLASS' => false, + 'T_INTERFACE' => false, + 'T_TRAIT' => false, + 'T_NAMESPACE' => false, + 'T_FUNCTION' => false, + 'T_CLOSURE' => false, + 'T_IF' => false, + 'T_SWITCH' => false, + 'T_CASE' => false, + 'T_DECLARE' => false, + 'T_DEFAULT' => false, + 'T_WHILE' => false, + 'T_ELSE' => false, + 'T_ELSEIF' => false, + 'T_FOR' => false, + 'T_FOREACH' => false, + 'T_DO' => false, + 'T_TRY' => false, + 'T_CATCH' => false, + 'T_FINALLY' => false, + 'T_PROPERTY' => false, + 'T_OBJECT' => false, + 'T_USE' => false, + ]; + + /** + * Cache for the test token stack pointers. + * + * @var array + */ + protected static $testTokens = []; + + /** + * Cache for the marker token stack pointers. + * + * @var array + */ + protected static $markerTokens = []; + + + /** + * Set up the token position caches for the tests. + * + * Retrieves the test tokens and marker token stack pointer positions + * only once and caches them as they won't change between the tests anyway. + * + * @before + * + * @return void + */ + protected function setUpCaches() + { + if (empty(self::$testTokens) === true) { + foreach (self::$testTargets as $targetToken => $marker) { + self::$testTokens[$marker] = $this->getTargetToken($marker, $targetToken); + } + } + + if (empty(self::$markerTokens) === true) { + foreach ($this->conditionMarkers as $marker) { + self::$markerTokens[$marker] = $this->getTargetToken($marker, Tokens::$scopeOpeners); + } + } + + }//end setUpCaches() + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $result = self::$phpcsFile->getCondition(100000, Tokens::$ooScopeTokens); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition(100000, T_IF); + $this->assertFalse($result); + + }//end testNonExistentToken() + + + /** + * Test passing a non conditional token. + * + * @return void + */ + public function testNonConditionalToken() + { + $targetType = T_STRING; + $stackPtr = $this->getTargetToken('/* testStartPoint */', $targetType); + + $result = self::$phpcsFile->getCondition($stackPtr, T_IF); + $this->assertFalse($result); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertFalse($result); + + }//end testNonConditionalToken() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetCondition + * + * @return void + */ + public function testGetCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testGetCondition() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetCondition() For the array format. + * + * @return array>> + */ + public static function dataGetCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_ANON_CLASS' => '/* condition 11-1: nested anonymous class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_CLOSURE' => '/* condition 13: closure */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_CASE' => '/* condition 8a: case */', + 'T_WHILE' => '/* condition 9: while */', + 'T_ELSE' => '/* condition 3-2: else */', + 'T_FOREACH' => '/* condition 10-3: foreach */', + 'T_CATCH' => '/* condition 11-3: catch */', + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => '/* condition 5: nested class */', + 'T_NAMESPACE' => '/* condition 0: namespace */', + 'T_FUNCTION' => '/* condition 2: function */', + 'T_IF' => '/* condition 1: if */', + 'T_SWITCH' => '/* condition 7: switch */', + 'T_DEFAULT' => '/* condition 8b: default */', + 'T_ELSE' => '/* condition 3-2: else */', + ], + ], + ]; + + }//end dataGetCondition() + + + /** + * Test retrieving a specific condition from a tokens "conditions" array. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the marker for the expected stack pointer result as a value. + * + * @dataProvider dataGetConditionReversed + * + * @return void + */ + public function testGetConditionReversed($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + if (is_string($expected) === true) { + $expected = self::$markerTokens[$expected]; + } + + $result = self::$phpcsFile->getCondition($stackPtr, constant($conditionType), false); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType} (reversed)" + ); + } + + }//end testGetConditionReversed() + + + /** + * Data provider. + * + * Only the conditions which are expected to be *found* need to be listed here. + * All other potential conditions will automatically also be tested and will expect + * `false` as a result. + * + * @see testGetConditionReversed() For the array format. + * + * @return array>> + */ + public static function dataGetConditionReversed() + { + $data = self::dataGetCondition(); + + // Set up the data for the reversed results. + $data['testSeriouslyNestedMethod']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testDeepestNested']['expectedResults']['T_FUNCTION'] = '/* condition 12: nested anonymous class method */'; + $data['testDeepestNested']['expectedResults']['T_IF'] = '/* condition 10-1: if */'; + + $data['testInException']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInException']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + $data['testInDefault']['expectedResults']['T_FUNCTION'] = '/* condition 6: class method */'; + $data['testInDefault']['expectedResults']['T_IF'] = '/* condition 4: if */'; + + return $data; + + }//end dataGetConditionReversed() + + + /** + * Test whether a token has a condition of a certain type. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedResults Array with the condition token type to search for as key + * and the expected result as a value. + * + * @dataProvider dataHasCondition + * + * @return void + */ + public function testHasCondition($testMarker, $expectedResults) + { + $stackPtr = self::$testTokens[$testMarker]; + + // Add expected results for all test markers not listed in the data provider. + $expectedResults += $this->conditionDefaults; + + foreach ($expectedResults as $conditionType => $expected) { + $result = self::$phpcsFile->hasCondition($stackPtr, constant($conditionType)); + $this->assertSame( + $expected, + $result, + "Assertion failed for test marker '{$testMarker}' with condition {$conditionType}" + ); + } + + }//end testHasCondition() + + + /** + * Data Provider. + * + * Only list the "true" conditions in the $results array. + * All other potential conditions will automatically also be tested + * and will expect "false" as a result. + * + * @see testHasCondition() For the array format. + * + * @return array>> + */ + public static function dataHasCondition() + { + return [ + 'testSeriouslyNestedMethod' => [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_ELSE' => true, + ], + ], + 'testDeepestNested' => [ + 'testMarker' => '/* testDeepestNested */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_ANON_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_CLOSURE' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + ], + ], + 'testInException' => [ + 'testMarker' => '/* testInException */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_CASE' => true, + 'T_WHILE' => true, + 'T_ELSE' => true, + 'T_FOREACH' => true, + 'T_CATCH' => true, + ], + ], + 'testInDefault' => [ + 'testMarker' => '/* testInDefault */', + 'expectedResults' => [ + 'T_CLASS' => true, + 'T_NAMESPACE' => true, + 'T_FUNCTION' => true, + 'T_IF' => true, + 'T_SWITCH' => true, + 'T_DEFAULT' => true, + 'T_ELSE' => true, + ], + ], + ]; + + }//end dataHasCondition() + + + /** + * Test whether a token has a condition of a certain type, with multiple allowed possibilities. + * + * @return void + */ + public function testHasConditionMultipleTypes() + { + $stackPtr = self::$testTokens['/* testInException */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_FINALLY]); + $this->assertFalse( + $result, + 'Failed asserting that "testInException" does not have a "try" nor a "finally" condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_TRY, T_CATCH, T_FINALLY]); + $this->assertTrue( + $result, + 'Failed asserting that "testInException" has a "try", "catch" or "finally" condition' + ); + + $stackPtr = self::$testTokens['/* testSeriouslyNestedMethod */']; + + $result = self::$phpcsFile->hasCondition($stackPtr, [T_ANON_CLASS, T_CLOSURE]); + $this->assertFalse( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" does not have an anonymous class nor a closure condition' + ); + + $result = self::$phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens); + $this->assertTrue( + $result, + 'Failed asserting that "testSeriouslyNestedMethod" has an OO Scope token condition' + ); + + }//end testHasConditionMultipleTypes() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js new file mode 100644 index 000000000..ee0a76a44 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js @@ -0,0 +1,23 @@ +/* testInvalidTokenPassed */ +print something; + +var object = +{ + /* testClosure */ + propertyName: function () {} +} + +/* testFunction */ +function functionName() {} + +/* testClass */ +class ClassName +{ + /* testMethod */ + methodName() { + return false; + } +} + +/* testFunctionUnicode */ +function π() {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php new file mode 100644 index 000000000..af3fe56d2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php @@ -0,0 +1,158 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameJSTest extends AbstractMethodUnitTest +{ + + /** + * The file extension of the test case file (without leading dot). + * + * @var string + */ + protected static $fileExtension = 'js'; + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationNameNull() + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param array|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see GetDeclarationNameTest::testGetDeclarationName() + * + * @return array>> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + 'targetType' => [ + T_CLASS, + T_STRING, + ], + ], + 'function-unicode-name' => [ + 'testMarker' => '/* testFunctionUnicode */', + 'expected' => 'π', + ], + ]; + + }//end dataGetDeclarationName() + + + /** + * Test retrieving the name of JS ES6 class method. + * + * @return void + */ + public function testGetDeclarationNameES6Method() + { + $target = $this->getTargetToken('/* testMethod */', [T_CLASS, T_INTERFACE, T_TRAIT, T_FUNCTION]); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame('methodName', $result); + + }//end testGetDeclarationNameES6Method() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc new file mode 100644 index 000000000..14902245b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc @@ -0,0 +1,102 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameTest extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an expected exception when a non-supported token is passed. + * + * @return void + */ + public function testInvalidTokenPassed() + { + $this->expectRunTimeException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); + + $target = $this->getTargetToken('/* testInvalidTokenPassed */', T_STRING); + self::$phpcsFile->getDeclarationName($target); + + }//end testInvalidTokenPassed() + + + /** + * Test receiving "null" when passed an anonymous construct or in case of a parse error. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationNameNull + * + * @return void + */ + public function testGetDeclarationNameNull($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + + /** + * Data provider. + * + * @see testGetDeclarationNameNull() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationNameNull() + { + return [ + 'closure' => [ + 'testMarker' => '/* testClosure */', + 'targetType' => T_CLOSURE, + ], + 'anon-class-with-parentheses' => [ + 'testMarker' => '/* testAnonClassWithParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-with-parentheses-2' => [ + 'testMarker' => '/* testAnonClassWithParens2 */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-without-parentheses' => [ + 'testMarker' => '/* testAnonClassWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + 'anon-class-extends-without-parentheses' => [ + 'testMarker' => '/* testAnonClassExtendsWithoutParens */', + 'targetType' => T_ANON_CLASS, + ], + 'live-coding' => [ + 'testMarker' => '/* testLiveCoding */', + 'targetType' => T_FUNCTION, + ], + ]; + + }//end dataGetDeclarationNameNull() + + + /** + * Test retrieving the name of a function or OO structure. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected Expected function output. + * @param int|string|null $targetType Token type of the token to get as stackPtr. + * + * @dataProvider dataGetDeclarationName + * + * @return void + */ + public function testGetDeclarationName($testMarker, $expected, $targetType=null) + { + if (isset($targetType) === false) { + $targetType = [ + T_CLASS, + T_INTERFACE, + T_TRAIT, + T_ENUM, + T_FUNCTION, + ]; + } + + $target = $this->getTargetToken($testMarker, $targetType); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertSame($expected, $result); + + }//end testGetDeclarationName() + + + /** + * Data provider. + * + * @see testGetDeclarationName() For the array format. + * + * @return array> + */ + public static function dataGetDeclarationName() + { + return [ + 'function' => [ + 'testMarker' => '/* testFunction */', + 'expected' => 'functionName', + ], + 'function-return-by-reference' => [ + 'testMarker' => '/* testFunctionReturnByRef */', + 'expected' => 'functionNameByRef', + ], + 'class' => [ + 'testMarker' => '/* testClass */', + 'expected' => 'ClassName', + ], + 'method' => [ + 'testMarker' => '/* testMethod */', + 'expected' => 'methodName', + ], + 'abstract-method' => [ + 'testMarker' => '/* testAbstractMethod */', + 'expected' => 'abstractMethodName', + ], + 'method-return-by-reference' => [ + 'testMarker' => '/* testMethodReturnByRef */', + 'expected' => 'MethodNameByRef', + ], + 'extended-class' => [ + 'testMarker' => '/* testExtendedClass */', + 'expected' => 'ExtendedClass', + ], + 'interface' => [ + 'testMarker' => '/* testInterface */', + 'expected' => 'InterfaceName', + ], + 'trait' => [ + 'testMarker' => '/* testTrait */', + 'expected' => 'TraitName', + ], + 'function-name-ends-with-number' => [ + 'testMarker' => '/* testFunctionEndingWithNumber */', + 'expected' => 'ValidNameEndingWithNumber5', + ], + 'class-with-numbers-in-name' => [ + 'testMarker' => '/* testClassWithNumber */', + 'expected' => 'ClassWith1Number', + ], + 'interface-with-numbers-in-name' => [ + 'testMarker' => '/* testInterfaceWithNumbers */', + 'expected' => 'InterfaceWith12345Numbers', + ], + 'class-with-comments-and-new-lines' => [ + 'testMarker' => '/* testClassWithCommentsAndNewLines */', + 'expected' => 'ClassWithCommentsAndNewLines', + ], + 'function-named-fn' => [ + 'testMarker' => '/* testFunctionFn */', + 'expected' => 'fn', + ], + 'enum-pure' => [ + 'testMarker' => '/* testPureEnum */', + 'expected' => 'Foo', + ], + 'enum-backed-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumSpaceBetweenNameAndColon */', + 'expected' => 'Hoo', + ], + 'enum-backed-no-space-between-name-and-colon' => [ + 'testMarker' => '/* testBackedEnumNoSpaceBetweenNameAndColon */', + 'expected' => 'Suit', + ], + 'function-return-by-reference-with-reserved-keyword-each' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordEach */', + 'expected' => 'each', + ], + 'function-return-by-reference-with-reserved-keyword-parent' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordParent */', + 'expected' => 'parent', + ], + 'function-return-by-reference-with-reserved-keyword-self' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordSelf */', + 'expected' => 'self', + ], + 'function-return-by-reference-with-reserved-keyword-static' => [ + 'testMarker' => '/* testFunctionReturnByRefWithReservedKeywordStatic */', + 'expected' => 'static', + ], + ]; + + }//end dataGetDeclarationName() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc index f40b6021f..f69a685ec 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc @@ -39,7 +39,10 @@ class TestMemberProperties var static $varG = true; /* testPublicStatic */ - public static $varH = true; + public // comment + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + static + $varH = true; /* testProtectedStatic */ static protected $varI = true; @@ -210,18 +213,19 @@ $anon = class() { /* testPHP8UnionTypesIllegalTypes */ // Intentional fatal error - types which are not allowed for properties, but that's not the concern of the method. - public callable|static|void $unionTypesIllegalTypes; + // Note: static is also not allowed as a type, but using static for a property type is not supported by the tokenizer. + public callable|void $unionTypesIllegalTypes; /* testPHP8UnionTypesNullable */ // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. public ?int|float $unionTypesNullable; /* testPHP8PseudoTypeNull */ - // Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. + // PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. public null $pseudoTypeNull; /* testPHP8PseudoTypeFalse */ - // Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. + // PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. public false $pseudoTypeFalse; /* testPHP8PseudoTypeFalseAndBool */ @@ -244,7 +248,7 @@ $anon = class() { public readonly int $readonly; /* testPHP81ReadonlyWithNullableType */ - public readonly ?array $array; + public readonly ?array $readonlyWithNullableType; /* testPHP81ReadonlyWithUnionType */ public readonly string|int $readonlyWithUnionType; @@ -254,6 +258,16 @@ $anon = class() { /* testPHP81OnlyReadonlyWithUnionType */ readonly string|int $onlyReadonly; + + /* testPHP81OnlyReadonlyWithUnionTypeMultiple */ + readonly \InterfaceA|\Sub\InterfaceB|false + $onlyReadonly; + + /* testPHP81ReadonlyAndStatic */ + readonly private static ?string $readonlyAndStatic; + + /* testPHP81ReadonlyMixedCase */ + public ReadONLY static $readonlyMixedCase; }; $anon = class { @@ -298,7 +312,30 @@ $anon = class() { // Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method. public int&string $illegalIntersectionType; - /* testPHP81NulltableIntersectionType */ + /* testPHP81NullableIntersectionType */ // Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method. public ?Foo&Bar $nullableIntersectionType; }; + +$anon = class() { + /* testPHP82PseudoTypeTrue */ + public true $pseudoTypeTrue; + + /* testPHP82NullablePseudoTypeTrue */ + static protected ?true $pseudoTypeNullableTrue; + + /* testPHP82PseudoTypeTrueInUnion */ + private int|string|true $pseudoTypeTrueInUnion; + + /* testPHP82PseudoTypeFalseAndTrue */ + // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. + readonly true|FALSE $pseudoTypeFalseAndTrue; +}; + +class WhitespaceAndCommentsInTypes { + /* testUnionTypeWithWhitespaceAndComment */ + public int | /*comment*/ string $hasWhitespaceAndComment; + + /* testIntersectionTypeWithWhitespaceAndComment */ + public \Foo /*comment*/ & Bar $hasWhitespaceAndComment; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php index 934d8e289..5f2c4cdf9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php @@ -4,22 +4,27 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMemberPropertiesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMemberProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMemberProperties + */ +final class GetMemberPropertiesTest extends AbstractMethodUnitTest { /** * Test the getMemberProperties() method. * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @param string $identifier Comment which precedes the test case. + * @param array $expected Expected function output. * * @dataProvider dataGetMemberProperties * @@ -30,7 +35,16 @@ public function testGetMemberProperties($identifier, $expected) $variable = $this->getTargetToken($identifier, T_VARIABLE); $result = self::$phpcsFile->getMemberProperties($variable); - $this->assertArraySubset($expected, $result, true); + // Convert offsets to absolute positions in the token stream. + if (isset($expected['type_token']) === true && is_int($expected['type_token']) === true) { + $expected['type_token'] += $variable; + } + + if (isset($expected['type_end_token']) === true && is_int($expected['type_end_token']) === true) { + $expected['type_end_token'] += $variable; + } + + $this->assertSame($expected, $result); }//end testGetMemberProperties() @@ -38,766 +52,1029 @@ public function testGetMemberProperties($identifier, $expected) /** * Data provider for the GetMemberProperties test. * + * Note: the `expected - type_token` and `expected - type_end_token` indexes should + * contain either `false` (no type) or the _offset_ of the type start/end token in + * relation to the `T_VARIABLE` token which is passed to the getMemberProperties() method. + * * @see testGetMemberProperties() * - * @return array + * @return array>> */ - public function dataGetMemberProperties() + public static function dataGetMemberProperties() { return [ - [ - '/* testVar */', - [ + 'var-modifier' => [ + 'identifier' => '/* testVar */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testVarType */', - [ + 'var-modifier-and-type' => [ + 'identifier' => '/* testVarType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, 'type' => '?int', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPublic */', - [ + 'public-modifier' => [ + 'identifier' => '/* testPublic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicType */', - [ + 'public-modifier-and-type' => [ + 'identifier' => '/* testPublicType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testProtected */', - [ + 'protected-modifier' => [ + 'identifier' => '/* testProtected */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedType */', - [ + 'protected-modifier-and-type' => [ + 'identifier' => '/* testProtectedType */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'bool', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPrivate */', - [ + 'private-modifier' => [ + 'identifier' => '/* testPrivate */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateType */', - [ + 'private-modifier-and-type' => [ + 'identifier' => '/* testPrivateType */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testStatic */', - [ + 'static-modifier' => [ + 'identifier' => '/* testStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testStaticType */', - [ + 'static-modifier-and-type' => [ + 'identifier' => '/* testStaticType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testStaticVar */', - [ + 'static-and-var-modifier' => [ + 'identifier' => '/* testStaticVar */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testVarStatic */', - [ + 'var-and-static-modifier' => [ + 'identifier' => '/* testVarStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicStatic */', - [ + 'public-static-modifiers' => [ + 'identifier' => '/* testPublicStatic */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedStatic */', - [ + 'protected-static-modifiers' => [ + 'identifier' => '/* testProtectedStatic */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateStatic */', - [ + 'private-static-modifiers' => [ + 'identifier' => '/* testPrivateStatic */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testNoPrefix */', - [ + 'no-modifier' => [ + 'identifier' => '/* testNoPrefix */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPublicStaticWithDocblock */', - [ + 'public-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPublicStaticWithDocblock */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testProtectedStaticWithDocblock */', - [ + 'protected-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testProtectedStaticWithDocblock */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPrivateStaticWithDocblock */', - [ + 'private-and-static-modifier-with-docblock' => [ + 'identifier' => '/* testPrivateStaticWithDocblock */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupType 1 */', - [ + 'property-group-simple-type-prop-1' => [ + 'identifier' => '/* testGroupType 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'float', + 'type_token' => -6, + 'type_end_token' => -6, 'nullable_type' => false, ], ], - [ - '/* testGroupType 2 */', - [ + 'property-group-simple-type-prop-2' => [ + 'identifier' => '/* testGroupType 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'float', + 'type_token' => -13, + 'type_end_token' => -13, 'nullable_type' => false, ], ], - [ - '/* testGroupNullableType 1 */', - [ + 'property-group-nullable-type-prop-1' => [ + 'identifier' => '/* testGroupNullableType 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '?string', + 'type_token' => -6, + 'type_end_token' => -6, 'nullable_type' => true, ], ], - [ - '/* testGroupNullableType 2 */', - [ + 'property-group-nullable-type-prop-2' => [ + 'identifier' => '/* testGroupNullableType 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '?string', + 'type_token' => -17, + 'type_end_token' => -17, 'nullable_type' => true, ], ], - [ - '/* testGroupProtectedStatic 1 */', - [ + 'property-group-protected-static-prop-1' => [ + 'identifier' => '/* testGroupProtectedStatic 1 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupProtectedStatic 2 */', - [ + 'property-group-protected-static-prop-2' => [ + 'identifier' => '/* testGroupProtectedStatic 2 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupProtectedStatic 3 */', - [ + 'property-group-protected-static-prop-3' => [ + 'identifier' => '/* testGroupProtectedStatic 3 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 1 */', - [ + 'property-group-private-prop-1' => [ + 'identifier' => '/* testGroupPrivate 1 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 2 */', - [ + 'property-group-private-prop-2' => [ + 'identifier' => '/* testGroupPrivate 2 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 3 */', - [ + 'property-group-private-prop-3' => [ + 'identifier' => '/* testGroupPrivate 3 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 4 */', - [ + 'property-group-private-prop-4' => [ + 'identifier' => '/* testGroupPrivate 4 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 5 */', - [ + 'property-group-private-prop-5' => [ + 'identifier' => '/* testGroupPrivate 5 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 6 */', - [ + 'property-group-private-prop-6' => [ + 'identifier' => '/* testGroupPrivate 6 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testGroupPrivate 7 */', - [ + 'property-group-private-prop-7' => [ + 'identifier' => '/* testGroupPrivate 7 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testMessyNullableType */', - [ + 'messy-nullable-type' => [ + 'identifier' => '/* testMessyNullableType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNamespaceType */', - [ + 'fqn-type' => [ + 'identifier' => '/* testNamespaceType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '\MyNamespace\MyClass', + 'type_token' => -5, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testNullableNamespaceType 1 */', - [ + 'nullable-classname-type' => [ + 'identifier' => '/* testNullableNamespaceType 1 */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?ClassName', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNullableNamespaceType 2 */', - [ + 'nullable-namespace-relative-class-type' => [ + 'identifier' => '/* testNullableNamespaceType 2 */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?Folder\ClassName', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testMultilineNamespaceType */', - [ + 'multiline-namespaced-type' => [ + 'identifier' => '/* testMultilineNamespaceType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '\MyNamespace\MyClass\Foo', + 'type_token' => -18, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPropertyAfterMethod */', - [ + 'property-after-method' => [ + 'identifier' => '/* testPropertyAfterMethod */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testInterfaceProperty */', - [], + 'invalid-property-in-interface' => [ + 'identifier' => '/* testInterfaceProperty */', + 'expected' => [], ], - [ - '/* testNestedProperty 1 */', - [ + 'property-in-nested-class-1' => [ + 'identifier' => '/* testNestedProperty 1 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testNestedProperty 2 */', - [ + 'property-in-nested-class-2' => [ + 'identifier' => '/* testNestedProperty 2 */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPHP8MixedTypeHint */', - [ + 'php8-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHint */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, 'is_readonly' => false, 'type' => 'miXed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8MixedTypeHintNullable */', - [ + 'php8-nullable-mixed-type' => [ + 'identifier' => '/* testPHP8MixedTypeHintNullable */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?mixed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testNamespaceOperatorTypeHint */', - [ + 'namespace-operator-type-declaration' => [ + 'identifier' => '/* testNamespaceOperatorTypeHint */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?namespace\Name', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8UnionTypesSimple */', - [ + 'php8-union-types-simple' => [ + 'identifier' => '/* testPHP8UnionTypesSimple */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesTwoClasses */', - [ + 'php8-union-types-two-classes' => [ + 'identifier' => '/* testPHP8UnionTypesTwoClasses */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'MyClassA|\Package\MyClassB', + 'type_token' => -7, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesAllBaseTypes */', - [ + 'php8-union-types-all-base-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllBaseTypes */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'array|bool|int|float|NULL|object|string', + 'type_token' => -14, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesAllPseudoTypes */', - [ + 'php8-union-types-all-pseudo-types' => [ + 'identifier' => '/* testPHP8UnionTypesAllPseudoTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => false, 'type' => 'false|mixed|self|parent|iterable|Resource', + 'type_token' => -12, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesIllegalTypes */', - [ + 'php8-union-types-illegal-types' => [ + 'identifier' => '/* testPHP8UnionTypesIllegalTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, // Missing static, but that's OK as not an allowed syntax. - 'type' => 'callable||void', + 'type' => 'callable|void', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8UnionTypesNullable */', - [ + 'php8-union-types-nullable' => [ + 'identifier' => '/* testPHP8UnionTypesNullable */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8PseudoTypeNull */', - [ + 'php8-union-types-pseudo-type-null' => [ + 'identifier' => '/* testPHP8PseudoTypeNull */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'null', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeFalse */', - [ + 'php8-union-types-pseudo-type-false' => [ + 'identifier' => '/* testPHP8PseudoTypeFalse */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'false', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeFalseAndBool */', - [ + 'php8-union-types-pseudo-type-false-and-bool' => [ + 'identifier' => '/* testPHP8PseudoTypeFalseAndBool */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'bool|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8ObjectAndClass */', - [ + 'php8-union-types-object-and-class' => [ + 'identifier' => '/* testPHP8ObjectAndClass */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'object|ClassName', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PseudoTypeIterableAndArray */', - [ + 'php8-union-types-pseudo-type-iterable-and-array' => [ + 'identifier' => '/* testPHP8PseudoTypeIterableAndArray */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'iterable|array|Traversable', + 'type_token' => -6, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', - [ + 'php8-union-types-duplicate-type-with-whitespace-and-comments' => [ + 'identifier' => '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'int|string|INT', + 'type_token' => -10, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81Readonly */', - [ + 'php8.1-readonly-property' => [ + 'identifier' => '/* testPHP81Readonly */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, 'type' => 'int', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81ReadonlyWithNullableType */', - [ + 'php8.1-readonly-property-with-nullable-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithNullableType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, 'type' => '?array', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP81ReadonlyWithUnionType */', - [ + 'php8.1-readonly-property-with-union-type' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81ReadonlyWithUnionTypeWithNull */', - [ + 'php8.1-readonly-property-with-union-type-with-null' => [ + 'identifier' => '/* testPHP81ReadonlyWithUnionTypeWithNull */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => true, 'type' => 'string|null', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81OnlyReadonlyWithUnionType */', - [ + 'php8.1-readonly-property-with-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, 'is_readonly' => true, 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-multi-union-type-no-visibility' => [ + 'identifier' => '/* testPHP81OnlyReadonlyWithUnionTypeMultiple */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'type' => '\InterfaceA|\Sub\InterfaceB|false', + 'type_token' => -11, + 'type_end_token' => -3, + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-and-static-property' => [ + 'identifier' => '/* testPHP81ReadonlyAndStatic */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-mixed-case-keyword' => [ + 'identifier' => '/* testPHP81ReadonlyMixedCase */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, 'nullable_type' => false, ], ], - [ - '/* testPHP8PropertySingleAttribute */', - [ + 'php8-property-with-single-attribute' => [ + 'identifier' => '/* testPHP8PropertySingleAttribute */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP8PropertyMultipleAttributes */', - [ + 'php8-property-with-multiple-attributes' => [ + 'identifier' => '/* testPHP8PropertyMultipleAttributes */', + 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => '?int|float', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], - [ - '/* testPHP8PropertyMultilineAttribute */', - [ + 'php8-property-with-multiline-attribute' => [ + 'identifier' => '/* testPHP8PropertyMultilineAttribute */', + 'expected' => [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, 'is_readonly' => false, 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testEnumProperty */', - [], + 'invalid-property-in-enum' => [ + 'identifier' => '/* testEnumProperty */', + 'expected' => [], ], - [ - '/* testPHP81IntersectionTypes */', - [ + 'php8.1-single-intersection-type' => [ + 'identifier' => '/* testPHP81IntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81MoreIntersectionTypes */', - [ + 'php8.1-multi-intersection-type' => [ + 'identifier' => '/* testPHP81MoreIntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'Foo&Bar&Baz', + 'type_token' => -6, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81IllegalIntersectionTypes */', - [ + 'php8.1-illegal-intersection-type' => [ + 'identifier' => '/* testPHP81IllegalIntersectionTypes */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'int&string', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => false, ], ], - [ - '/* testPHP81NulltableIntersectionType */', - [ + 'php8.1-nullable-intersection-type' => [ + 'identifier' => '/* testPHP81NullableIntersectionType */', + 'expected' => [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?Foo&Bar', + 'type_token' => -4, + 'type_end_token' => -2, 'nullable_type' => true, ], ], + + 'php8.0-union-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testUnionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int|string', + 'type_token' => -8, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.1-intersection-type-with-whitespace-and-comment' => [ + 'identifier' => '/* testIntersectionTypeWithWhitespaceAndComment */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '\Foo&Bar', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true' => [ + 'identifier' => '/* testPHP82PseudoTypeTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'true', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true-nullable' => [ + 'identifier' => '/* testPHP82NullablePseudoTypeTrue */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'type' => '?true', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.2-pseudo-type-true-in-union' => [ + 'identifier' => '/* testPHP82PseudoTypeTrueInUnion */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int|string|true', + 'type_token' => -6, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-invalid-true-false-union' => [ + 'identifier' => '/* testPHP82PseudoTypeFalseAndTrue */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'true|FALSE', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + ]; }//end dataGetMemberProperties() @@ -808,15 +1085,14 @@ public function dataGetMemberProperties() * * @param string $identifier Comment which precedes the test case. * - * @expectedException PHP_CodeSniffer\Exceptions\RuntimeException - * @expectedExceptionMessage $stackPtr is not a class member var - * * @dataProvider dataNotClassProperty * * @return void */ public function testNotClassPropertyException($identifier) { + $this->expectRunTimeException('$stackPtr is not a class member var'); + $variable = $this->getTargetToken($identifier, T_VARIABLE); $result = self::$phpcsFile->getMemberProperties($variable); @@ -828,18 +1104,18 @@ public function testNotClassPropertyException($identifier) * * @see testNotClassPropertyException() * - * @return array + * @return array> */ - public function dataNotClassProperty() + public static function dataNotClassProperty() { return [ - ['/* testMethodParam */'], - ['/* testImportedGlobal */'], - ['/* testLocalVariable */'], - ['/* testGlobalVariable */'], - ['/* testNestedMethodParam 1 */'], - ['/* testNestedMethodParam 2 */'], - ['/* testEnumMethodParamNotProperty */'], + 'method parameter' => ['/* testMethodParam */'], + 'variable import using global keyword' => ['/* testImportedGlobal */'], + 'function local variable' => ['/* testLocalVariable */'], + 'global variable' => ['/* testGlobalVariable */'], + 'method parameter in anon class nested in ternary' => ['/* testNestedMethodParam 1 */'], + 'method parameter in anon class nested in function call' => ['/* testNestedMethodParam 2 */'], + 'method parameter in enum' => ['/* testEnumMethodParamNotProperty */'], ]; }//end dataNotClassProperty() @@ -848,13 +1124,12 @@ public function dataNotClassProperty() /** * Test receiving an expected exception when a non variable is passed. * - * @expectedException PHP_CodeSniffer\Exceptions\RuntimeException - * @expectedExceptionMessage $stackPtr must be of type T_VARIABLE - * * @return void */ public function testNotAVariableException() { + $this->expectRunTimeException('$stackPtr must be of type T_VARIABLE'); + $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); $result = self::$phpcsFile->getMemberProperties($next); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc new file mode 100644 index 000000000..465679eb3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc new file mode 100644 index 000000000..667cb5ed2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving an empty array when encountering a specific parse error. + * + * @return void + */ + public function testParseError() + { + $target = $this->getTargetToken('/* testParseError */', [T_FUNCTION, T_CLOSURE, T_FN]); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testParseError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc index dc4654914..f6f3cd9eb 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc @@ -1,5 +1,29 @@ $b; +/* testArrowFunctionReturnByRef */ +fn&(?string $a) => $b; + +/* testArrayDefaultValues */ +function arrayDefaultValues($var1 = [], $var2 = array(1, 2, 3) ) {} + +/* testConstantDefaultValueSecondParam */ +function constantDefaultValueSecondParam($var1, $var2 = M_PI) {} + +/* testScalarTernaryExpressionInDefault */ +function ternayInDefault( $a = FOO ? 'bar' : 10, ? bool $b ) {} + +/* testVariadicFunction */ +function variadicFunction( int ... $a ) {} + +/* testVariadicByRefFunction */ +function variadicByRefFunction( &...$a ) {} + +/* testVariadicFunctionClassType */ +function variableLengthArgument($unit, DateInterval ...$intervals) {} + +/* testNameSpacedTypeDeclaration */ +function namespacedClassType( \Package\Sub\ClassName $a, ?Sub\AnotherClass $b ) {} + +/* testWithAllTypes */ +class testAllTypes { + function allTypes( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k + ) {} +} + +/* testArrowFunctionWithAllTypes */ +$fn = fn( + ?ClassName $a, + self $b, + parent $c, + object $d, + ?int $e, + string &$f, + iterable $g, + bool $h = true, + callable $i = 'is_null', + float $j = 1.1, + array ...$k +) => $something; + +/* testMessyDeclaration */ +function messyDeclaration( + // comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a, + $b /* test */ = /* test */ 'default' /* test*/, + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c +) {} + /* testPHP8MixedTypeHint */ function mixedTypeHint(mixed &...$var1) {} @@ -46,7 +139,7 @@ function namespaceOperatorTypeHint(?namespace\Name $var1) {} function unionTypeSimple(int|float $number, self|parent &...$obj) {} /* testPHP8UnionTypesWithSpreadOperatorAndReference */ -function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB) {} +function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB ) {} /* testPHP8UnionTypesSimpleWithBitwiseOrInDefault */ $fn = fn(int|float $var = CONSTANT_A | CONSTANT_B) => $var; @@ -66,11 +159,11 @@ function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var $closure = function (?int|float $number) {}; /* testPHP8PseudoTypeNull */ -// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeNull(null $var = null) {} /* testPHP8PseudoTypeFalse */ -// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeFalse(false $var = false) {} /* testPHP8PseudoTypeFalseAndBool */ @@ -110,7 +203,18 @@ class ConstructorPropertyPromotionAndNormalParams { class ConstructorPropertyPromotionWithReadOnly { /* testPHP81ConstructorPropertyPromotionWithReadOnly */ - public function __construct(public readonly ?int $promotedProp, readonly private string|bool &$promotedToo) {} + public function __construct(public readonly ?int $promotedProp, ReadOnly private string|bool &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration { + /* testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration */ + // Intentional fatal error. Readonly properties MUST be typed. + public function __construct(public readonly $promotedProp, ReadOnly private &$promotedToo) {} +} + +class ConstructorPropertyPromotionWithOnlyReadOnly { + /* testPHP81ConstructorPropertyPromotionWithOnlyReadOnly */ + public function __construct(readonly Foo&Bar $promotedProp, readonly ?bool $promotedToo,) {} } /* testPHP8ConstructorPropertyPromotionGlobalFunction */ @@ -162,3 +266,56 @@ $closure = function (string&int $numeric_string) {}; /* testPHP81NullableIntersectionTypes */ // Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. $closure = function (?Foo&Bar $object) {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(?true $var = true) {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(true|false $var = true) {} + +/* testPHP81NewInInitializers */ +function newInInitializers( + TypeA $new = new TypeA(self::CONST_VALUE), + \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), +) {} + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testClosureNoParams */ +function() {}; + +/* testClosure */ +function( $a = 'test' ) {}; + +/* testClosureUseNoParams */ +function() use() {}; + +/* testClosureUse */ +function() use( $foo, $bar ) {}; + +/* testFunctionParamListWithTrailingComma */ +function trailingComma( + ?string $foo /*comment*/ , + $bar = 0, +) {} + +/* testClosureParamListWithTrailingComma */ +function( + $foo, + $bar, +) {}; + +/* testArrowFunctionParamListWithTrailingComma */ +$fn = fn( ?int $a , ...$b, ) => $b; + +/* testClosureUseWithTrailingComma */ +function() use( + $foo /*comment*/ , + $bar, +) {}; + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php index ba4d75448..83419ddea 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php @@ -1,20 +1,163 @@ + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @copyright 2019-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMethodParametersTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodParameters method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodParameters + */ +final class GetMethodParametersTest extends AbstractMethodUnitTest { + /** + * Test receiving an expected exception when a non function/use token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataUnexpectedTokenException + * + * @return void + */ + public function testUnexpectedTokenException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); + + $target = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodParameters($target); + + }//end testUnexpectedTokenException() + + + /** + * Data Provider. + * + * @see testUnexpectedTokenException() For the array format. + * + * @return array>> + */ + public static function dataUnexpectedTokenException() + { + return [ + 'interface' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_INTERFACE, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataUnexpectedTokenException() + + + /** + * Test receiving an expected exception when a non-closure use token is passed. + * + * @param string $identifier The comment which preceeds the test. + * + * @dataProvider dataInvalidUse + * + * @return void + */ + public function testInvalidUse($identifier) + { + $this->expectRunTimeException('$stackPtr was not a valid T_USE'); + + $use = $this->getTargetToken($identifier, [T_USE]); + self::$phpcsFile->getMethodParameters($use); + + }//end testInvalidUse() + + + /** + * Data Provider. + * + * @see testInvalidUse() For the array format. + * + * @return array> + */ + public static function dataInvalidUse() + { + return [ + 'ImportUse' => ['/* testImportUse */'], + 'ImportGroupUse' => ['/* testImportGroupUse */'], + 'TraitUse' => ['/* testTraitUse */'], + ]; + + }//end dataInvalidUse() + + + /** + * Test receiving an empty array when there are no parameters. + * + * @param string $commentString The comment which preceeds the test. + * @param int|string|array $targetTokenType Optional. The token type to search for after $commentString. + * Defaults to the function/closure/arrow tokens. + * + * @dataProvider dataNoParams + * + * @return void + */ + public function testNoParams($commentString, $targetTokenType=[T_FUNCTION, T_CLOSURE, T_FN]) + { + $target = $this->getTargetToken($commentString, $targetTokenType); + $result = self::$phpcsFile->getMethodParameters($target); + + $this->assertSame([], $result); + + }//end testNoParams() + + + /** + * Data Provider. + * + * @see testNoParams() For the array format. + * + * @return array>> + */ + public static function dataNoParams() + { + return [ + 'FunctionNoParams' => [ + 'commentString' => '/* testFunctionNoParams */', + ], + 'ClosureNoParams' => [ + 'commentString' => '/* testClosureNoParams */', + ], + 'ClosureUseNoParams' => [ + 'commentString' => '/* testClosureUseNoParams */', + 'targetTokenType' => T_USE, + ], + ]; + + }//end dataNoParams() + + /** * Verify pass-by-reference parsing. * @@ -22,15 +165,22 @@ class GetMethodParametersTest extends AbstractMethodUnitTest */ public function testPassByReference() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => '&$var', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 5, + 'name' => '$var', + 'content' => '&$var', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 4, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -45,15 +195,22 @@ public function testPassByReference() */ public function testArrayHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'array $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'array', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var', + 'content' => 'array $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -68,15 +225,22 @@ public function testArrayHint() */ public function testVariable() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => '$var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var', + 'content' => '$var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -91,16 +255,25 @@ public function testVariable() */ public function testSingleDefaultValue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '$var1=self::CONSTANT', - 'has_attributes' => false, - 'default' => 'self::CONSTANT', - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=self::CONSTANT', + 'default' => 'self::CONSTANT', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -115,26 +288,43 @@ public function testSingleDefaultValue() */ public function testDefaultValues() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '$var1=1', - 'has_attributes' => false, - 'default' => '1', - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1=1', + 'default' => '1', + 'default_token' => 6, + 'default_equal_token' => 5, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 7, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => "\$var2='value'", - 'has_attributes' => false, - 'default' => "'value'", - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 9, + 'name' => '$var2', + 'content' => "\$var2='value'", + 'default' => "'value'", + 'default_token' => 11, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -149,25 +339,38 @@ public function testDefaultValues() */ public function testTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => 'foo $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'foo', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var1', + 'content' => 'foo $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'foo', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => 7, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => 'bar $var2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'bar', - 'nullable_type' => false, + 'token' => 11, + 'name' => '$var2', + 'content' => 'bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bar', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -182,15 +385,22 @@ public function testTypeHint() */ public function testSelfTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'self $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'self', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$var', + 'content' => 'self $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -205,25 +415,38 @@ public function testSelfTypeHint() */ public function testNullableTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '?int $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, + 'token' => 7, + 'name' => '$var1', + 'content' => '?int $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, ]; $expected[1] = [ - 'name' => '$var2', - 'content' => '?\bar $var2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?\bar', - 'nullable_type' => true, + 'token' => 14, + 'name' => '$var2', + 'content' => '?\bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -238,16 +461,25 @@ public function testNullableTypeHint() */ public function testBitwiseAndConstantExpressionDefaultValue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$a', - 'content' => '$a = 10 & 20', - 'default' => '10 & 20', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$a', + 'content' => '$a = 10 & 20', + 'default' => '10 & 20', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -262,25 +494,38 @@ public function testBitwiseAndConstantExpressionDefaultValue() */ public function testArrowFunction() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$a', - 'content' => 'int $a', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$a', + 'content' => 'int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 2, + 'type_hint_end_token' => 2, + 'nullable_type' => false, + 'comma_token' => 5, ]; $expected[1] = [ - 'name' => '$b', - 'content' => '...$b', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => '', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -289,855 +534,2492 @@ public function testArrowFunction() /** - * Verify recognition of PHP8 mixed type declaration. + * Verify that arrow functions are supported. * * @return void */ - public function testPHP8MixedTypeHint() + public function testArrowFunctionReturnByRef() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => 'mixed &...$var1', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => 'mixed', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$a', + 'content' => '?string $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8MixedTypeHint() + }//end testArrowFunctionReturnByRef() /** - * Verify recognition of PHP8 mixed type declaration with nullability. + * Verify default value parsing with array values. * * @return void */ - public function testPHP8MixedTypeHintNullable() + public function testArrayDefaultValues() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var1', - 'content' => '?Mixed $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?Mixed', - 'nullable_type' => true, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1 = []', + 'default' => '[]', + 'default_token' => 8, + 'default_equal_token' => 6, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 10, ]; - - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - - }//end testPHP8MixedTypeHintNullable() - - - /** - * Verify recognition of type declarations using the namespace operator. - * - * @return void - */ - public function testNamespaceOperatorTypeHint() - { - $expected = []; - $expected[0] = [ - 'name' => '$var1', - 'content' => '?namespace\Name $var1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?namespace\Name', - 'nullable_type' => true, + $expected[1] = [ + 'token' => 12, + 'name' => '$var2', + 'content' => '$var2 = array(1, 2, 3)', + 'default' => 'array(1, 2, 3)', + 'default_token' => 16, + 'default_equal_token' => 14, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testNamespaceOperatorTypeHint() + }//end testArrayDefaultValues() /** - * Verify recognition of PHP8 union type declaration. + * Verify having a T_STRING constant as a default value for the second parameter. * * @return void */ - public function testPHP8UnionTypesSimple() + public function testConstantDefaultValueSecondParam() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$number', - 'content' => 'int|float $number', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|float', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$var1', + 'content' => '$var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, ]; $expected[1] = [ - 'name' => '$obj', - 'content' => 'self|parent &...$obj', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => 'self|parent', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$var2', + 'content' => '$var2 = M_PI', + 'default' => 'M_PI', + 'default_token' => 11, + 'default_equal_token' => 9, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesSimple() + }//end testConstantDefaultValueSecondParam() /** - * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * Verify distinquishing between a nullable type and a ternary within a default expression. * * @return void */ - public function testPHP8UnionTypesWithSpreadOperatorAndReference() + public function testScalarTernaryExpressionInDefault() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$paramA', - 'content' => 'float|null &$paramA', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'float|null', - 'nullable_type' => false, + 'token' => 5, + 'name' => '$a', + 'content' => '$a = FOO ? \'bar\' : 10', + 'default' => 'FOO ? \'bar\' : 10', + 'default_token' => 9, + 'default_equal_token' => 7, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 18, ]; $expected[1] = [ - 'name' => '$paramB', - 'content' => 'string|int ...$paramB', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => 'string|int', - 'nullable_type' => false, + 'token' => 24, + 'name' => '$b', + 'content' => '? bool $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 22, + 'type_hint_end_token' => 22, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesWithSpreadOperatorAndReference() + }//end testScalarTernaryExpressionInDefault() /** - * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * Verify a variadic parameter being recognized correctly. * * @return void */ - public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + public function testVariadicFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', - 'default' => 'CONSTANT_A | CONSTANT_B', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|float', - 'nullable_type' => false, + 'token' => 9, + 'name' => '$a', + 'content' => 'int ... $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'int', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + }//end testVariadicFunction() /** - * Verify recognition of PHP8 union type declaration with two classes. + * Verify a variadic parameter passed by reference being recognized correctly. * * @return void */ - public function testPHP8UnionTypesTwoClasses() + public function testVariadicByRefFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'MyClassA|\Package\MyClassB $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'MyClassA|\Package\MyClassB', - 'nullable_type' => false, + 'token' => 7, + 'name' => '$a', + 'content' => '&...$a', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 5, + 'variable_length' => true, + 'variadic_token' => 6, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesTwoClasses() + }//end testVariadicByRefFunction() /** - * Verify recognition of PHP8 union type declaration with all base types. + * Verify handling of a variadic parameter with a class based type declaration. * * @return void */ - public function testPHP8UnionTypesAllBaseTypes() + public function testVariadicFunctionClassType() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'array|bool|callable|int|float|null|object|string $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'array|bool|callable|int|float|null|object|string', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$unit', + 'content' => '$unit', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, ]; - - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - - }//end testPHP8UnionTypesAllBaseTypes() - - - /** - * Verify recognition of PHP8 union type declaration with all pseudo types. - * - * @return void - */ - public function testPHP8UnionTypesAllPseudoTypes() - { - $expected = []; - $expected[0] = [ - 'name' => '$var', - 'content' => 'false|mixed|self|parent|iterable|Resource $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'false|mixed|self|parent|iterable|Resource', - 'nullable_type' => false, + $expected[1] = [ + 'token' => 10, + 'name' => '$intervals', + 'content' => 'DateInterval ...$intervals', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 9, + 'type_hint' => 'DateInterval', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesAllPseudoTypes() + }//end testVariadicFunctionClassType() /** - * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * Verify distinquishing between a nullable type and a ternary within a default expression. * * @return void */ - public function testPHP8UnionTypesNullable() + public function testNameSpacedTypeDeclaration() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$number', - 'content' => '?int|float $number', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int|float', - 'nullable_type' => true, + 'token' => 12, + 'name' => '$a', + 'content' => '\Package\Sub\ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\Sub\ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 20, + 'name' => '$b', + 'content' => '?Sub\AnotherClass $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Sub\AnotherClass', + 'type_hint_token' => 16, + 'type_hint_end_token' => 18, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8UnionTypesNullable() + }//end testNameSpacedTypeDeclaration() /** - * Verify recognition of PHP8 type declaration with (illegal) single type null. + * Verify correctly recognizing all type declarations supported by PHP. * * @return void */ - public function testPHP8PseudoTypeNull() + public function testWithAllTypes() { - $expected = []; - $expected[0] = [ - 'name' => '$var', - 'content' => 'null $var = null', - 'default' => 'null', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'null', - 'nullable_type' => false, + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 15, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 13, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => 16, + ]; + $expected[2] = [ + 'token' => 21, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 19, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[3] = [ + 'token' => 27, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 25, + 'type_hint_end_token' => 25, + 'nullable_type' => false, + 'comma_token' => 28, + ]; + $expected[4] = [ + 'token' => 34, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 32, + 'type_hint_end_token' => 32, + 'nullable_type' => true, + 'comma_token' => 35, + ]; + $expected[5] = [ + 'token' => 41, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 40, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 38, + 'type_hint_end_token' => 38, + 'nullable_type' => false, + 'comma_token' => 42, + ]; + $expected[6] = [ + 'token' => 47, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 45, + 'type_hint_end_token' => 45, + 'nullable_type' => false, + 'comma_token' => 48, + ]; + $expected[7] = [ + 'token' => 53, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 57, + 'default_equal_token' => 55, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 51, + 'type_hint_end_token' => 51, + 'nullable_type' => false, + 'comma_token' => 58, + ]; + $expected[8] = [ + 'token' => 63, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 67, + 'default_equal_token' => 65, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 61, + 'type_hint_end_token' => 61, + 'nullable_type' => false, + 'comma_token' => 68, + ]; + $expected[9] = [ + 'token' => 73, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 77, + 'default_equal_token' => 75, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 71, + 'type_hint_end_token' => 71, + 'nullable_type' => false, + 'comma_token' => 78, + ]; + $expected[10] = [ + 'token' => 84, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 83, + 'type_hint' => 'array', + 'type_hint_token' => 81, + 'type_hint_end_token' => 81, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testWithAllTypes() + + + /** + * Verify correctly recognizing all type declarations supported by PHP when used with an arrow function. + * + * @return void + */ + public function testArrowFunctionWithAllTypes() + { + // Offsets are relative to the T_FN token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$a', + 'content' => '?ClassName $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?ClassName', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 13, + 'name' => '$b', + 'content' => 'self $b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 11, + 'type_hint_end_token' => 11, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[2] = [ + 'token' => 19, + 'name' => '$c', + 'content' => 'parent $c', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'parent', + 'type_hint_token' => 17, + 'type_hint_end_token' => 17, + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[3] = [ + 'token' => 25, + 'name' => '$d', + 'content' => 'object $d', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object', + 'type_hint_token' => 23, + 'type_hint_end_token' => 23, + 'nullable_type' => false, + 'comma_token' => 26, + ]; + $expected[4] = [ + 'token' => 32, + 'name' => '$e', + 'content' => '?int $e', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 30, + 'type_hint_end_token' => 30, + 'nullable_type' => true, + 'comma_token' => 33, + ]; + $expected[5] = [ + 'token' => 39, + 'name' => '$f', + 'content' => 'string &$f', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 38, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 36, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[6] = [ + 'token' => 45, + 'name' => '$g', + 'content' => 'iterable $g', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable', + 'type_hint_token' => 43, + 'type_hint_end_token' => 43, + 'nullable_type' => false, + 'comma_token' => 46, + ]; + $expected[7] = [ + 'token' => 51, + 'name' => '$h', + 'content' => 'bool $h = true', + 'default' => 'true', + 'default_token' => 55, + 'default_equal_token' => 53, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool', + 'type_hint_token' => 49, + 'type_hint_end_token' => 49, + 'nullable_type' => false, + 'comma_token' => 56, + ]; + $expected[8] = [ + 'token' => 61, + 'name' => '$i', + 'content' => 'callable $i = \'is_null\'', + 'default' => "'is_null'", + 'default_token' => 65, + 'default_equal_token' => 63, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 59, + 'type_hint_end_token' => 59, + 'nullable_type' => false, + 'comma_token' => 66, + ]; + $expected[9] = [ + 'token' => 71, + 'name' => '$j', + 'content' => 'float $j = 1.1', + 'default' => '1.1', + 'default_token' => 75, + 'default_equal_token' => 73, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float', + 'type_hint_token' => 69, + 'type_hint_end_token' => 69, + 'nullable_type' => false, + 'comma_token' => 76, + ]; + $expected[10] = [ + 'token' => 82, + 'name' => '$k', + 'content' => 'array ...$k', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 81, + 'type_hint' => 'array', + 'type_hint_token' => 79, + 'type_hint_end_token' => 79, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionWithAllTypes() + + + /** + * Verify handling of a declaration interlaced with whitespace and comments. + * + * @return void + */ + public function testMessyDeclaration() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 25, + 'name' => '$a', + 'content' => '// comment + ?\MyNS /* comment */ + \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. + \ MyClass $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?\MyNS\SubCat\MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 23, + 'nullable_type' => true, + 'comma_token' => 26, + ]; + $expected[1] = [ + 'token' => 29, + 'name' => '$b', + 'content' => "\$b /* test */ = /* test */ 'default' /* test*/", + 'default' => "'default' /* test*/", + 'default_token' => 37, + 'default_equal_token' => 33, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 62, + 'name' => '$c', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- For reasons. + ? /*comment*/ + bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. + & /*test*/ ... /* phpcs:ignore */ $c', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 54, + 'variable_length' => true, + 'variadic_token' => 58, + 'type_hint' => '?bool', + 'type_hint_token' => 50, + 'type_hint_end_token' => 50, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testMessyDeclaration() + + + /** + * Verify recognition of PHP8 mixed type declaration. + * + * @return void + */ + public function testPHP8MixedTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var1', + 'content' => 'mixed &...$var1', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 6, + 'variable_length' => true, + 'variadic_token' => 7, + 'type_hint' => 'mixed', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHint() + + + /** + * Verify recognition of PHP8 mixed type declaration with nullability. + * + * @return void + */ + public function testPHP8MixedTypeHintNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 7, + 'name' => '$var1', + 'content' => '?Mixed $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Mixed', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8MixedTypeHintNullable() + + + /** + * Verify recognition of type declarations using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$var1', + 'content' => '?namespace\Name $var1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?namespace\Name', + 'type_hint_token' => 5, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testNamespaceOperatorTypeHint() + + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => 'int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$obj', + 'content' => 'self|parent &...$obj', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'self|parent', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimple() + + + /** + * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * + * @return void + */ + public function testPHP8UnionTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 9, + 'name' => '$paramA', + 'content' => 'float|null &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, + 'name' => '$paramB', + 'content' => 'string|int ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'string|int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * + * @return void + */ + public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', + 'default' => 'CONSTANT_A | CONSTANT_B', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 2, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 11, + 'name' => '$var', + 'content' => 'MyClassA|\Package\MyClassB $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA|\Package\MyClassB', + 'type_hint_token' => 4, + 'type_hint_end_token' => 9, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesTwoClasses() + + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 20, + 'name' => '$var', + 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array|bool|callable|int|float|null|object|string', + 'type_hint_token' => 4, + 'type_hint_end_token' => 18, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllBaseTypes() + + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 16, + 'name' => '$var', + 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|mixed|self|parent|iterable|Resource', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesAllPseudoTypes() + + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$number', + 'content' => '?int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int|float', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8UnionTypesNullable() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'null $var = null', + 'default' => 'null', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'null', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeNull() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 6, + 'name' => '$var', + 'content' => 'false $var = false', + 'default' => 'false', + 'default_token' => 10, + 'default_equal_token' => 8, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalse() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'bool|false $var = false', + 'default' => 'false', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeFalseAndBool() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'object|ClassName $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object|ClassName', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ObjectAndClass() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$var', + 'content' => 'iterable|array|Traversable $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable|array|Traversable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8PseudoTypeIterableAndArray() + + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 17, + 'name' => '$var', + 'content' => 'int | string /*comment*/ | INT $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|string|INT', + 'type_hint_token' => 5, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + + + /** + * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionNoTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$x', + 'content' => 'public $x = 0.0', + 'default' => '0.0', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 6, + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$y', + 'content' => 'protected $y = \'\'', + 'default' => "''", + 'default_token' => 22, + 'default_equal_token' => 20, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 16, + 'property_readonly' => false, + 'comma_token' => 23, + ]; + $expected[2] = [ + 'token' => 28, + 'name' => '$z', + 'content' => 'private $z = null', + 'default' => 'null', + 'default_token' => 32, + 'default_equal_token' => 30, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => 33, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionNoTypes() + + + /** + * Verify recognition of PHP8 constructor property promotion with type declarations. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionWithTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$x', + 'content' => 'protected float|int $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 19, + 'name' => '$y', + 'content' => 'public ?string &$y = \'test\'', + 'default' => "'test'", + 'default_token' => 23, + 'default_equal_token' => 21, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 18, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 30, + 'name' => '$z', + 'content' => 'private mixed $z', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'mixed', + 'type_hint_token' => 28, + 'type_hint_end_token' => 28, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, + 'property_readonly' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeNull() + }//end testPHP8ConstructorPropertyPromotionWithTypes() /** - * Verify recognition of PHP8 type declaration with (illegal) single type false. + * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. * * @return void */ - public function testPHP8PseudoTypeFalse() + public function testPHP8ConstructorPropertyPromotionAndNormalParam() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'false $var = false', - 'default' => 'false', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'false', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$normalArg', + 'content' => '?int $normalArg', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 12, + 'type_hint_end_token' => 12, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeFalse() + }//end testPHP8ConstructorPropertyPromotionAndNormalParam() /** - * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. * * @return void */ - public function testPHP8PseudoTypeFalseAndBool() + public function testPHP81ConstructorPropertyPromotionWithReadOnly() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'bool|false $var = false', - 'default' => 'false', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'bool|false', - 'nullable_type' => false, + 'token' => 11, + 'name' => '$promotedProp', + 'content' => 'public readonly ?int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 12, + ]; + $expected[1] = [ + 'token' => 23, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private string|bool &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 22, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|bool', + 'type_hint_token' => 18, + 'type_hint_end_token' => 20, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 16, + 'property_readonly' => true, + 'readonly_token' => 14, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeFalseAndBool() + }//end testPHP81ConstructorPropertyPromotionWithReadOnly() /** - * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword + * without a property type. * * @return void */ - public function testPHP8ObjectAndClass() + public function testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'object|ClassName $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'object|ClassName', - 'nullable_type' => false, + 'token' => 8, + 'name' => '$promotedProp', + 'content' => 'public readonly $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => true, + 'readonly_token' => 6, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 16, + 'name' => '$promotedToo', + 'content' => 'ReadOnly private &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => true, + 'readonly_token' => 11, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ObjectAndClass() + }//end testPHP81ConstructorPropertyPromotionWithReadOnlyNoTypeDeclaration() /** - * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly + * keyword without explicit visibility. * * @return void */ - public function testPHP8PseudoTypeIterableAndArray() + public function testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 10, + 'name' => '$promotedProp', + 'content' => 'readonly Foo&Bar $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 6, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 4, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 18, + 'name' => '$promotedToo', + 'content' => 'readonly ?bool $promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?bool', + 'type_hint_token' => 16, + 'type_hint_end_token' => 16, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'property_readonly' => true, + 'readonly_token' => 13, + 'comma_token' => 19, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() + + + /** + * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionGlobalFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'iterable|array|Traversable $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'iterable|array|Traversable', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$x', + 'content' => 'private $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8PseudoTypeIterableAndArray() + }//end testPHP8ConstructorPropertyPromotionGlobalFunction() /** - * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. * * @return void */ - public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + public function testPHP8ConstructorPropertyPromotionAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$y', + 'content' => 'public callable $y', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, + 'name' => '$x', + 'content' => 'private ...$x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 13, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 11, + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP8ConstructorPropertyPromotionAbstractMethod() + + + /** + * Verify and document behaviour when there are comments within a parameter declaration. + * + * @return void + */ + public function testCommentsInParameter() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 19, + 'name' => '$param', + 'content' => '// Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default' => '\'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default_token' => 27, + 'default_equal_token' => 23, + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 13, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => '?MyClass', + 'type_hint_token' => 9, + 'type_hint_end_token' => 9, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testCommentsInParameter() + + + /** + * Verify behaviour when parameters have attributes attached. + * + * @return void + */ + public function testParameterAttributesInFunctionDeclaration() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'int | string /*comment*/ | INT $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'int|string|INT', - 'nullable_type' => false, + 'token' => 17, + 'name' => '$constructorPropPromTypedParamSingleAttribute', + 'content' => '#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => 15, + 'type_hint_end_token' => 15, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 13, + 'property_readonly' => false, + 'comma_token' => 18, + ]; + $expected[1] = [ + 'token' => 39, + 'name' => '$typedParamSingleAttribute', + 'content' => '#[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Type|false', + 'type_hint_token' => 34, + 'type_hint_end_token' => 36, + 'nullable_type' => false, + 'comma_token' => 40, + ]; + $expected[2] = [ + 'token' => 59, + 'name' => '$nullableTypedParamMultiAttribute', + 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 57, + 'type_hint_end_token' => 57, + 'nullable_type' => true, + 'comma_token' => 60, + ]; + $expected[3] = [ + 'token' => 74, + 'name' => '$nonTypedParamTwoAttributes', + 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 75, + ]; + $expected[4] = [ + 'token' => 95, + 'name' => '$otherParam', + 'content' => '#[MyAttribute(array("key" => "value"))] + &...$otherParam', + 'has_attributes' => true, + 'pass_by_reference' => true, + 'reference_token' => 93, + 'variable_length' => true, + 'variadic_token' => 94, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 96, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8DuplicateTypeInUnionWhitespaceAndComment() + }//end testParameterAttributesInFunctionDeclaration() /** - * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * Verify recognition of PHP8.1 intersection type declaration. * * @return void */ - public function testPHP8ConstructorPropertyPromotionNoTypes() + public function testPHP8IntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'public $x = 0.0', - 'default' => '0.0', + 'token' => 8, + 'name' => '$obj1', + 'content' => 'Foo&Bar $obj1', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '', + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, 'nullable_type' => false, - 'property_visibility' => 'public', - 'property_readonly' => false, + 'comma_token' => 9, ]; $expected[1] = [ - 'name' => '$y', - 'content' => 'protected $y = \'\'', - 'default' => "''", + 'token' => 15, + 'name' => '$obj2', + 'content' => 'Boo&Bar $obj2', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, - 'property_visibility' => 'protected', - 'property_readonly' => false, - ]; - $expected[2] = [ - 'name' => '$z', - 'content' => 'private $z = null', - 'default' => 'null', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 11, + 'type_hint_end_token' => 13, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionNoTypes() + }//end testPHP8IntersectionTypes() /** - * Verify recognition of PHP8 constructor property promotion with type declarations. + * Verify recognition of PHP8 intersection type declaration when the variable + * has either a spread operator or a reference. * * @return void */ - public function testPHP8ConstructorPropertyPromotionWithTypes() + public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'protected float|int $x', + 'token' => 9, + 'name' => '$paramA', + 'content' => 'Boo&Bar &$paramA', 'has_attributes' => false, - 'pass_by_reference' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, 'variable_length' => false, - 'type_hint' => 'float|int', + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, 'nullable_type' => false, - 'property_visibility' => 'protected', - 'property_readonly' => false, + 'comma_token' => 10, ]; $expected[1] = [ - 'name' => '$y', - 'content' => 'public ?string &$y = \'test\'', - 'default' => "'test'", - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => '?string', - 'nullable_type' => true, - 'property_visibility' => 'public', - 'property_readonly' => false, - ]; - $expected[2] = [ - 'name' => '$z', - 'content' => 'private mixed $z', + 'token' => 17, + 'name' => '$paramB', + 'content' => 'Foo&Bar ...$paramB', 'has_attributes' => false, 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'mixed', + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 12, + 'type_hint_end_token' => 14, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionWithTypes() + }//end testPHP81IntersectionTypesWithSpreadOperatorAndReference() /** - * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. + * Verify recognition of PHP8.1 intersection type declaration with more types. * * @return void */ - public function testPHP8ConstructorPropertyPromotionAndNormalParam() + public function testPHP81MoreIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$promotedProp', - 'content' => 'public int $promotedProp', + 'token' => 16, + 'name' => '$var', + 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'int', + 'variadic_token' => false, + 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'type_hint_token' => 4, + 'type_hint_end_token' => 14, 'nullable_type' => false, - 'property_visibility' => 'public', - 'property_readonly' => false, - ]; - $expected[1] = [ - 'name' => '$normalArg', - 'content' => '?int $normalArg', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionAndNormalParam() + }//end testPHP81MoreIntersectionTypes() /** - * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. * * @return void */ - public function testPHP81ConstructorPropertyPromotionWithReadOnly() + public function testPHP81IllegalIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$promotedProp', - 'content' => 'public readonly ?int $promotedProp', + 'token' => 7, + 'name' => '$numeric_string', + 'content' => 'string&int $numeric_string', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, - 'property_visibility' => 'public', - 'property_readonly' => true, - ]; - $expected[1] = [ - 'name' => '$promotedToo', - 'content' => 'readonly private string|bool &$promotedToo', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'string|bool', + 'variadic_token' => false, + 'type_hint' => 'string&int', + 'type_hint_token' => 3, + 'type_hint_end_token' => 5, 'nullable_type' => false, - 'property_visibility' => 'private', - 'property_readonly' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81ConstructorPropertyPromotionWithReadOnly() + }//end testPHP81IllegalIntersectionTypes() /** - * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. * * @return void */ - public function testPHP8ConstructorPropertyPromotionGlobalFunction() + public function testPHP81NullableIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$x', - 'content' => 'private $x', + 'token' => 8, + 'name' => '$object', + 'content' => '?Foo&Bar $object', 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, - 'property_visibility' => 'private', + 'variadic_token' => false, + 'type_hint' => '?Foo&Bar', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, + 'nullable_type' => true, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionGlobalFunction() + }//end testPHP81NullableIntersectionTypes() /** - * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. + * Verify recognition of PHP 8.2 stand-alone `true` type. * * @return void */ - public function testPHP8ConstructorPropertyPromotionAbstractMethod() + public function testPHP82PseudoTypeTrue() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$y', - 'content' => 'public callable $y', + 'token' => 7, + 'name' => '$var', + 'content' => '?true $var = true', + 'default' => 'true', + 'default_token' => 11, + 'default_equal_token' => 9, 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'callable', - 'nullable_type' => false, - 'property_visibility' => 'public', + 'variadic_token' => false, + 'type_hint' => '?true', + 'type_hint_token' => 5, + 'type_hint_end_token' => 5, + 'nullable_type' => true, + 'comma_token' => false, ]; - $expected[1] = [ - 'name' => '$x', - 'content' => 'private ...$x', + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeTrue() + + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 8, + 'name' => '$var', + 'content' => 'true|false $var = true', + 'default' => 'true', + 'default_token' => 12, + 'default_equal_token' => 10, 'has_attributes' => false, 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => '', + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'true|false', + 'type_hint_token' => 4, + 'type_hint_end_token' => 6, 'nullable_type' => false, - 'property_visibility' => 'private', + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP8ConstructorPropertyPromotionAbstractMethod() + }//end testPHP82PseudoTypeFalseAndTrue() /** - * Verify and document behaviour when there are comments within a parameter declaration. + * Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1. * * @return void */ - public function testCommentsInParameter() + public function testPHP81NewInInitializers() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$param', - 'content' => '// Leading comment. - ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => '?MyClass', - 'nullable_type' => true, + 'token' => 8, + 'name' => '$new', + 'content' => 'TypeA $new = new TypeA(self::CONST_VALUE)', + 'default' => 'new TypeA(self::CONST_VALUE)', + 'default_token' => 12, + 'default_equal_token' => 10, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'TypeA', + 'type_hint_token' => 6, + 'type_hint_end_token' => 6, + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[1] = [ + 'token' => 28, + 'name' => '$newToo', + 'content' => '\Package\TypeB $newToo = new \Package\TypeB(10, \'string\')', + 'default' => "new \Package\TypeB(10, 'string')", + 'default_token' => 32, + 'default_equal_token' => 30, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\TypeB', + 'type_hint_token' => 23, + 'type_hint_end_token' => 26, + 'nullable_type' => false, + 'comma_token' => 44, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testCommentsInParameter() + }//end testPHP81NewInInitializers() /** - * Verify behaviour when parameters have attributes attached. + * Verify handling of a closure. * * @return void */ - public function testParameterAttributesInFunctionDeclaration() + public function testClosure() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$constructorPropPromTypedParamSingleAttribute', - 'content' => '#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute', - 'has_attributes' => true, + 'token' => 3, + 'name' => '$a', + 'content' => '$a = \'test\'', + 'default' => "'test'", + 'default_token' => 7, + 'default_equal_token' => 5, + 'has_attributes' => false, 'pass_by_reference' => false, + 'reference_token' => false, 'variable_length' => false, - 'type_hint' => 'string', + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, - 'property_visibility' => 'private', - ]; - $expected[1] = [ - 'name' => '$typedParamSingleAttribute', - 'content' => '#[MyAttr([1, 2])] - Type|false - $typedParamSingleAttribute', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Type|false', - 'nullable_type' => false, - ]; - $expected[2] = [ - 'name' => '$nullableTypedParamMultiAttribute', - 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?int', - 'nullable_type' => true, - ]; - $expected[3] = [ - 'name' => '$nonTypedParamTwoAttributes', - 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', - 'has_attributes' => true, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '', - 'nullable_type' => false, - ]; - $expected[4] = [ - 'name' => '$otherParam', - 'content' => '#[MyAttribute(array("key" => "value"))] - &...$otherParam', - 'has_attributes' => true, - 'pass_by_reference' => true, - 'variable_length' => true, - 'type_hint' => '', - 'nullable_type' => false, + 'comma_token' => false, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testParameterAttributesInFunctionDeclaration() + }//end testClosure() /** - * Verify recognition of PHP8.1 intersection type declaration. + * Verify handling of a closure T_USE token correctly. * * @return void */ - public function testPHP8IntersectionTypes() + public function testClosureUse() { + // Offsets are relative to the T_USE token. $expected = []; $expected[0] = [ - 'name' => '$obj1', - 'content' => 'Foo&Bar $obj1', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Foo&Bar', - 'nullable_type' => false, + 'token' => 3, + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 4, ]; $expected[1] = [ - 'name' => '$obj2', - 'content' => 'Boo&Bar $obj2', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'Boo&Bar', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, ]; - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); - }//end testPHP8IntersectionTypes() + }//end testClosureUse() /** - * Verify recognition of PHP8 intersection type declaration when the variable has either a spread operator or a reference. + * Verify function declarations with trailing commas are handled correctly. * * @return void */ - public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + public function testFunctionParamListWithTrailingComma() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$paramA', - 'content' => 'Boo&Bar &$paramA', - 'has_attributes' => false, - 'pass_by_reference' => true, - 'variable_length' => false, - 'type_hint' => 'Boo&Bar', - 'nullable_type' => false, + 'token' => 9, + 'name' => '$foo', + 'content' => '?string $foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 7, + 'type_hint_end_token' => 7, + 'nullable_type' => true, + 'comma_token' => 13, ]; $expected[1] = [ - 'name' => '$paramB', - 'content' => 'Foo&Bar ...$paramB', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => true, - 'type_hint' => 'Foo&Bar', - 'nullable_type' => false, + 'token' => 16, + 'name' => '$bar', + 'content' => '$bar = 0', + 'default' => '0', + 'default_token' => 20, + 'default_equal_token' => 18, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 21, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81IntersectionTypesWithSpreadOperatorAndReference() + }//end testFunctionParamListWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration with more types. + * Verify closure declarations with trailing commas are handled correctly. * * @return void */ - public function testPHP81MoreIntersectionTypes() + public function testClosureParamListWithTrailingComma() { + // Offsets are relative to the T_FUNCTION token. $expected = []; $expected[0] = [ - 'name' => '$var', - 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', - 'nullable_type' => false, + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 8, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 9, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81MoreIntersectionTypes() + }//end testClosureParamListWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * Verify arrow function declarations with trailing commas are handled correctly. * * @return void */ - public function testPHP81IllegalIntersectionTypes() + public function testArrowFunctionParamListWithTrailingComma() { + // Offsets are relative to the T_FN token. $expected = []; $expected[0] = [ - 'name' => '$numeric_string', - 'content' => 'string&int $numeric_string', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => 'string&int', - 'nullable_type' => false, + 'token' => 6, + 'name' => '$a', + 'content' => '?int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 4, + 'type_hint_end_token' => 4, + 'nullable_type' => true, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 11, + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 10, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, ]; $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); - }//end testPHP81IllegalIntersectionTypes() + }//end testArrowFunctionParamListWithTrailingComma() /** - * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * Verify closure T_USE statements with trailing commas are handled correctly. * * @return void */ - public function testPHP81NullableIntersectionTypes() + public function testClosureUseWithTrailingComma() { + // Offsets are relative to the T_USE token. $expected = []; $expected[0] = [ - 'name' => '$object', - 'content' => '?Foo&Bar $object', - 'has_attributes' => false, - 'pass_by_reference' => false, - 'variable_length' => false, - 'type_hint' => '?Foo&Bar', - 'nullable_type' => true, + 'token' => 4, + 'name' => '$foo', + 'content' => '$foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 8, + ]; + $expected[1] = [ + 'token' => 11, + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, ]; - $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); - }//end testPHP81NullableIntersectionTypes() + }//end testClosureUseWithTrailingComma() /** * Test helper. * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. + * @param string $commentString The comment which preceeds the test. + * @param array> $expected The expected function output. + * @param int|string|array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. * * @return void */ - private function getMethodParametersTestHelper($commentString, $expected) + private function getMethodParametersTestHelper($commentString, $expected, $targetType=[T_FUNCTION, T_CLOSURE, T_FN]) { - $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); - $found = self::$phpcsFile->getMethodParameters($function); + $target = $this->getTargetToken($commentString, $targetType); + $found = self::$phpcsFile->getMethodParameters($target); + + // Convert offsets to absolute positions in the token stream. + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $target; + + if (is_int($param['reference_token']) === true) { + $expected[$key]['reference_token'] += $target; + } + + if (is_int($param['variadic_token']) === true) { + $expected[$key]['variadic_token'] += $target; + } + + if (is_int($param['type_hint_token']) === true) { + $expected[$key]['type_hint_token'] += $target; + } + + if (is_int($param['type_hint_end_token']) === true) { + $expected[$key]['type_hint_end_token'] += $target; + } + + if (is_int($param['comma_token']) === true) { + $expected[$key]['comma_token'] += $target; + } + + if (isset($param['default_token']) === true) { + $expected[$key]['default_token'] += $target; + } + + if (isset($param['default_equal_token']) === true) { + $expected[$key]['default_equal_token'] += $target; + } + + if (isset($param['visibility_token']) === true && is_int($param['visibility_token']) === true) { + $expected[$key]['visibility_token'] += $target; + } + + if (isset($param['readonly_token']) === true) { + $expected[$key]['readonly_token'] += $target; + } + }//end foreach - $this->assertArraySubset($expected, $found, true); + $this->assertSame($expected, $found); }//end getMethodParametersTestHelper() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc index 0c592369a..24d8cc692 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc @@ -34,16 +34,23 @@ class MyClass { /* testMessyNullableReturnMethod */ public function myFunction() /* comment */ : - /* comment */ ? //comment + /* comment */ ? // phpcs:ignore Stnd.Cat.Sniff -- For reasons. array {} /* testReturnNamespace */ function myFunction(): \MyNamespace\MyClass {} /* testReturnMultilineNamespace */ + // Parse error in PHP 8.0. function myFunction(): \MyNamespace /** comment *\/ comment */ \MyClass /* comment */ \Foo {} + + /* testReturnUnqualifiedName */ + private function myFunction(): ?MyClass {} + + /* testReturnPartiallyQualifiedName */ + function myFunction(): Sub\Level\MyClass {} } abstract class MyClass @@ -72,6 +79,11 @@ class ReturnMe { private function myFunction(): static { return $this; } + + /* testReturnTypeNullableStatic */ + function myNullableFunction(): ?static { + return $this; + } } /* testPHP8MixedTypeHint */ @@ -102,11 +114,11 @@ function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterabl $closure = function () use($a) :?int|float {}; /* testPHP8PseudoTypeNull */ -// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeNull(): null {} /* testPHP8PseudoTypeFalse */ -// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. function pseudoTypeFalse(): false {} /* testPHP8PseudoTypeFalseAndBool */ @@ -150,3 +162,34 @@ $closure = function (): string&int {}; /* testPHP81NullableIntersectionTypes */ // Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. $closure = function (): ?Foo&Bar {}; + +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(): ?true {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(): true|false {} + +/* testNotAFunction */ +return true; + +/* testPhpcsIssue1264 */ +function foo() : array { + echo $foo; +} + +/* testArrowFunctionArrayReturnValue */ +$fn = fn(): array => [a($a, $b)]; + +/* testArrowFunctionReturnByRef */ +fn&(?string $a) : ?string => $b; + +/* testFunctionCallFnPHPCS353-354 */ +$value = $obj->fn(true); + +/* testFunctionDeclarationNestedInTernaryPHPCS2975 */ +return (!$a ? [ new class { public function b(): c {} } ] : []); + +/* testArrowFunctionLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +$fn = fn diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php index 66f4eea3e..85a36bb2b 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php @@ -1,20 +1,78 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class GetMethodPropertiesTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::getMethodProperties method. + * + * @covers \PHP_CodeSniffer\Files\File::getMethodProperties + */ +final class GetMethodPropertiesTest extends AbstractMethodUnitTest { + /** + * Test receiving an expected exception when a non function token is passed. + * + * @param string $commentString The comment which preceeds the test. + * @param string|int|array $targetTokenType The token type to search for after $commentString. + * + * @dataProvider dataNotAFunctionException + * + * @return void + */ + public function testNotAFunctionException($commentString, $targetTokenType) + { + $this->expectRunTimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); + + $next = $this->getTargetToken($commentString, $targetTokenType); + self::$phpcsFile->getMethodProperties($next); + + }//end testNotAFunctionException() + + + /** + * Data Provider. + * + * @see testNotAFunctionException() For the array format. + * + * @return array>> + */ + public static function dataNotAFunctionException() + { + return [ + 'return' => [ + 'commentString' => '/* testNotAFunction */', + 'targetTokenType' => T_RETURN, + ], + 'function-call-fn-phpcs-3.5.3-3.5.4' => [ + 'commentString' => '/* testFunctionCallFnPHPCS353-354 */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + 'fn-live-coding' => [ + 'commentString' => '/* testArrowFunctionLiveCoding */', + 'targetTokenType' => [ + T_FN, + T_STRING, + ], + ], + ]; + + }//end dataNotAFunctionException() + + /** * Test a basic function. * @@ -23,14 +81,16 @@ class GetMethodPropertiesTest extends AbstractMethodUnitTest public function testBasicFunction() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -45,15 +105,18 @@ public function testBasicFunction() */ public function testReturnFunction() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 11, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -68,15 +131,18 @@ public function testReturnFunction() */ public function testNestedClosure() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -92,14 +158,16 @@ public function testNestedClosure() public function testBasicMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -115,14 +183,16 @@ public function testBasicMethod() public function testPrivateStaticMethod() { $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -138,14 +208,16 @@ public function testPrivateStaticMethod() public function testFinalMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => true, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => true, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -160,15 +232,18 @@ public function testFinalMethod() */ public function testProtectedReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'int', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -183,15 +258,18 @@ public function testProtectedReturnMethod() */ public function testPublicReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => 'array', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'array', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -206,15 +284,18 @@ public function testPublicReturnMethod() */ public function testNullableReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -229,15 +310,18 @@ public function testNullableReturnMethod() */ public function testMessyNullableReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 18, + 'return_type_end_token' => 18, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -252,15 +336,18 @@ public function testMessyNullableReturnMethod() */ public function testReturnNamespace() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 10, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -275,15 +362,18 @@ public function testReturnNamespace() */ public function testReturnMultilineNamespace() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass\Foo', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass\Foo', + 'return_type_token' => 7, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -291,6 +381,58 @@ public function testReturnMultilineNamespace() }//end testReturnMultilineNamespace() + /** + * Test a method with an unqualified named return type. + * + * @return void + */ + public function testReturnUnqualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '?MyClass', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnUnqualifiedName() + + + /** + * Test a method with a partially qualified namespaced return type. + * + * @return void + */ + public function testReturnPartiallyQualifiedName() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Sub\Level\MyClass', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnPartiallyQualifiedName() + + /** * Test a basic abstract method. * @@ -299,14 +441,16 @@ public function testReturnMultilineNamespace() public function testAbstractMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -321,15 +465,18 @@ public function testAbstractMethod() */ public function testAbstractReturnMethod() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'bool', - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'bool', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -345,14 +492,16 @@ public function testAbstractReturnMethod() public function testInterfaceMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -367,15 +516,18 @@ public function testInterfaceMethod() */ public function testArrowFunction() { + // Offsets are relative to the T_FN token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 9, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -390,15 +542,18 @@ public function testArrowFunction() */ public function testReturnTypeStatic() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => 'static', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => 'static', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -406,6 +561,32 @@ public function testReturnTypeStatic() }//end testReturnTypeStatic() + /** + * Test a function with return type "?static". + * + * @return void + */ + public function testReturnTypeNullableStatic() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?static', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testReturnTypeNullableStatic() + + /** * Test a function with return type "mixed". * @@ -413,15 +594,18 @@ public function testReturnTypeStatic() */ public function testPHP8MixedTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'mixed', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'mixed', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -436,15 +620,18 @@ public function testPHP8MixedTypeHint() */ public function testPHP8MixedTypeHintNullable() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?mixed', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?mixed', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -459,15 +646,18 @@ public function testPHP8MixedTypeHintNullable() */ public function testNamespaceOperatorTypeHint() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?namespace\Name', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?namespace\Name', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -482,15 +672,18 @@ public function testNamespaceOperatorTypeHint() */ public function testPHP8UnionTypesSimple() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int|float', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|float', + 'return_type_token' => 9, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -505,15 +698,18 @@ public function testPHP8UnionTypesSimple() */ public function testPHP8UnionTypesTwoClasses() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA|\Package\MyClassB', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA|\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -528,15 +724,18 @@ public function testPHP8UnionTypesTwoClasses() */ public function testPHP8UnionTypesAllBaseTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array|bool|callable|int|float|null|Object|string', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array|bool|callable|int|float|null|Object|string', + 'return_type_token' => 8, + 'return_type_end_token' => 22, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -547,19 +746,24 @@ public function testPHP8UnionTypesAllBaseTypes() /** * Verify recognition of PHP8 union type declaration with all pseudo types. * + * Note: "Resource" is not a type, but seen as a class name. + * * @return void */ public function testPHP8UnionTypesAllPseudoTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', + 'return_type_token' => 9, + 'return_type_end_token' => 23, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -574,15 +778,18 @@ public function testPHP8UnionTypesAllPseudoTypes() */ public function testPHP8UnionTypesNullable() { + // Offsets are relative to the T_CLOSURE token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?int|float', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?int|float', + 'return_type_token' => 12, + 'return_type_end_token' => 14, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -597,15 +804,18 @@ public function testPHP8UnionTypesNullable() */ public function testPHP8PseudoTypeNull() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'null', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -620,15 +830,18 @@ public function testPHP8PseudoTypeNull() */ public function testPHP8PseudoTypeFalse() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'false', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -643,15 +856,18 @@ public function testPHP8PseudoTypeFalse() */ public function testPHP8PseudoTypeFalseAndBool() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'bool|false', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -666,15 +882,18 @@ public function testPHP8PseudoTypeFalseAndBool() */ public function testPHP8ObjectAndClass() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'object|ClassName', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|ClassName', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -689,15 +908,18 @@ public function testPHP8ObjectAndClass() */ public function testPHP8PseudoTypeIterableAndArray() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => 'iterable|array|Traversable', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'iterable|array|Traversable', + 'return_type_token' => 7, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -712,15 +934,18 @@ public function testPHP8PseudoTypeIterableAndArray() */ public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int|string|INT', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|string|INT', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -735,15 +960,18 @@ public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() */ public function testPHP81NeverType() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'never', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'never', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -758,15 +986,18 @@ public function testPHP81NeverType() */ public function testPHP81NullableNeverType() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?never', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?never', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -781,15 +1012,18 @@ public function testPHP81NullableNeverType() */ public function testPHP8IntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'Foo&Bar', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -804,15 +1038,18 @@ public function testPHP8IntersectionTypes() */ public function testPHP81MoreIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'return_type_token' => 7, + 'return_type_end_token' => 17, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -827,15 +1064,18 @@ public function testPHP81MoreIntersectionTypes() */ public function testPHP81IntersectionArrowFunction() { + // Offsets are relative to the T_FN token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'MyClassA&\Package\MyClassB', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB', + 'return_type_token' => 6, + 'return_type_end_token' => 11, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -850,15 +1090,18 @@ public function testPHP81IntersectionArrowFunction() */ public function testPHP81IllegalIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'string&int', - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'string&int', + 'return_type_token' => 6, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -873,15 +1116,18 @@ public function testPHP81IllegalIntersectionTypes() */ public function testPHP81NullableIntersectionTypes() { + // Offsets are relative to the T_FUNCTION token. $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?Foo&Bar', - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?Foo&Bar', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); @@ -889,11 +1135,173 @@ public function testPHP81NullableIntersectionTypes() }//end testPHP81NullableIntersectionTypes() + /** + * Verify recognition of PHP 8.2 stand-alone `true` type. + * + * @return void + */ + public function testPHP82PseudoTypeTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?true', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeTrue() + + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'true|false', + 'return_type_token' => 7, + 'return_type_end_token' => 9, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82PseudoTypeFalseAndTrue() + + + /** + * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/1264 + * + * @return void + */ + public function testPhpcsIssue1264() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 8, + 'return_type_end_token' => 8, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPhpcsIssue1264() + + + /** + * Test handling of incorrect tokenization of array return type declarations for arrow functions + * in a very specific code sample in PHPCS < 3.5.4. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2773 + * + * @return void + */ + public function testArrowFunctionArrayReturnValue() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 5, + 'return_type_end_token' => 5, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionArrayReturnValue() + + + /** + * Test handling of an arrow function returning by reference. + * + * @return void + */ + public function testArrowFunctionReturnByRef() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?string', + 'return_type_token' => 12, + 'return_type_end_token' => 12, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testArrowFunctionReturnByRef() + + + /** + * Test handling of function declaration nested in a ternary, where the colon for the + * return type was incorrectly tokenized as T_INLINE_ELSE prior to PHPCS 3.5.7. + * + * @return void + */ + public function testFunctionDeclarationNestedInTernaryPHPCS2975() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'c', + 'return_type_token' => 7, + 'return_type_end_token' => 7, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testFunctionDeclarationNestedInTernaryPHPCS2975() + + /** * Test helper. * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. + * @param string $commentString The comment which preceeds the test. + * @param array $expected The expected function output. * * @return void */ @@ -902,7 +1310,16 @@ private function getMethodPropertiesTestHelper($commentString, $expected) $function = $this->getTargetToken($commentString, [T_FUNCTION, T_CLOSURE, T_FN]); $found = self::$phpcsFile->getMethodProperties($function); - $this->assertArraySubset($expected, $found, true); + // Convert offsets to absolute positions in the token stream. + if (is_int($expected['return_type_token']) === true) { + $expected['return_type_token'] += $function; + } + + if (is_int($expected['return_type_end_token']) === true) { + $expected['return_type_end_token'] += $function; + } + + $this->assertSame($expected, $found); }//end getMethodPropertiesTestHelper() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc new file mode 100644 index 000000000..ace5a9bd4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc @@ -0,0 +1,25 @@ + 20; +} + +/* testEchoWithTabs */ +echo 'foo', + 'bar' , + 'baz'; + +/* testEndOfFile */ +echo $foo; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php new file mode 100644 index 000000000..7db977aaf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php @@ -0,0 +1,334 @@ + + * @copyright 2022-2024 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getTokensAsString method. + * + * @covers \PHP_CodeSniffer\Files\File::getTokensAsString + */ +final class GetTokensAsStringTest extends AbstractMethodUnitTest +{ + + + /** + * Test passing a non-existent token pointer. + * + * @return void + */ + public function testNonExistentToken() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(100000, 10); + + }//end testNonExistentToken() + + + /** + * Test passing a non integer `$start`, like the result of a failed $phpcsFile->findNext(). + * + * @return void + */ + public function testNonIntegerStart() + { + $this->expectRunTimeException('The $start position for getTokensAsString() must exist in the token stack'); + + self::$phpcsFile->getTokensAsString(false, 10); + + }//end testNonIntegerStart() + + + /** + * Test passing a non integer `$length`. + * + * @return void + */ + public function testNonIntegerLength() + { + $result = self::$phpcsFile->getTokensAsString(10, false); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 1.5); + $this->assertSame('', $result); + + }//end testNonIntegerLength() + + + /** + * Test passing a zero or negative `$length`. + * + * @return void + */ + public function testLengthEqualToOrLessThanZero() + { + $result = self::$phpcsFile->getTokensAsString(10, -10); + $this->assertSame('', $result); + + $result = self::$phpcsFile->getTokensAsString(10, 0); + $this->assertSame('', $result); + + }//end testLengthEqualToOrLessThanZero() + + + /** + * Test passing a `$length` beyond the end of the file. + * + * @return void + */ + public function testLengthBeyondEndOfFile() + { + $semicolon = $this->getTargetToken('/* testEndOfFile */', T_SEMICOLON); + $result = self::$phpcsFile->getTokensAsString($semicolon, 20); + $this->assertSame( + '; +', + $result + ); + + }//end testLengthBeyondEndOfFile() + + + /** + * Test getting a token set as a string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetTokensAsString() + * + * @return void + */ + public function testGetTokensAsString($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length); + $this->assertSame($expected, $result); + + }//end testGetTokensAsString() + + + /** + * Data provider. + * + * @see testGetTokensAsString() For the array format. + * + * @return array> + */ + public static function dataGetTokensAsString() + { + return [ + 'length-0' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 0, + 'expected' => '', + ], + 'length-1' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 1, + 'expected' => '1', + ], + 'length-2' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 2, + 'expected' => '1 ', + ], + 'length-3' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 3, + 'expected' => '1 +', + ], + 'length-4' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 4, + 'expected' => '1 + ', + ], + 'length-5' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 5, + 'expected' => '1 + 2', + ], + 'length-6' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 6, + 'expected' => '1 + 2 ', + ], + 'length-7' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 7, + 'expected' => '1 + 2 +', + ], + 'length-8' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 8, + 'expected' => '1 + 2 + +', + ], + 'length-9' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 9, + 'expected' => '1 + 2 + + ', + ], + 'length-10' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 10, + 'expected' => '1 + 2 + + // Comment. +', + ], + 'length-11' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 11, + 'expected' => '1 + 2 + + // Comment. + ', + ], + 'length-12' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 12, + 'expected' => '1 + 2 + + // Comment. + 3', + ], + 'length-13' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 13, + 'expected' => '1 + 2 + + // Comment. + 3 ', + ], + 'length-14' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 14, + 'expected' => '1 + 2 + + // Comment. + 3 +', + ], + 'length-34' => [ + 'testMarker' => '/* testCalculation */', + 'startTokenType' => T_LNUMBER, + 'length' => 34, + 'expected' => '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + ], + 'namespace' => [ + 'testMarker' => '/* testNamespace */', + 'startTokenType' => T_NAMESPACE, + 'length' => 8, + 'expected' => 'namespace Foo\Bar\Baz;', + ], + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetTokensAsString() + + + /** + * Test getting a token set as a string with the original, non tab-replaced content. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $startTokenType The type of token(s) to look for for the start of the string. + * @param int $length Token length to get. + * @param string $expected The expected function return value. + * + * @dataProvider dataGetOrigContent() + * + * @return void + */ + public function testGetOrigContent($testMarker, $startTokenType, $length, $expected) + { + $start = $this->getTargetToken($testMarker, $startTokenType); + $result = self::$phpcsFile->getTokensAsString($start, $length, true); + $this->assertSame($expected, $result); + + }//end testGetOrigContent() + + + /** + * Data provider. + * + * @see testGetOrigContent() For the array format. + * + * @return array> + */ + public static function dataGetOrigContent() + { + return [ + 'use-with-comments' => [ + 'testMarker' => '/* testUseWithComments */', + 'startTokenType' => T_USE, + 'length' => 17, + 'expected' => 'use Foo /*comment*/ \ Bar + // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + \ Bah;', + ], + 'echo-with-tabs' => [ + 'testMarker' => '/* testEchoWithTabs */', + 'startTokenType' => T_ECHO, + 'length' => 13, + 'expected' => 'echo \'foo\', + \'bar\' , + \'baz\';', + ], + 'end-of-file' => [ + 'testMarker' => '/* testEndOfFile */', + 'startTokenType' => T_ECHO, + 'length' => 4, + 'expected' => 'echo $foo;', + ], + ]; + + }//end dataGetOrigContent() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc index f71e2639d..93c7acc67 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc @@ -1,6 +1,8 @@ getValue(); /* testAssignByReferenceE */ $collection = &collector(); +/* testAssignByReferenceF */ +$collection ??= &collector(); + +/* testShortListAssignByReferenceNoKeyA */ +[ + &$a, + /* testShortListAssignByReferenceNoKeyB */ + &$b, + /* testNestedShortListAssignByReferenceNoKey */ + [$c, &$d] +] = $array; + +/* testLongListAssignByReferenceNoKeyA */ +list($a, &$b, list(/* testLongListAssignByReferenceNoKeyB */ &$c, /* testLongListAssignByReferenceNoKeyC */ &$d)) = $array; + +[ + /* testNestedShortListAssignByReferenceWithKeyA */ + 'a' => [&$a, $b], + /* testNestedShortListAssignByReferenceWithKeyB */ + 'b' => [$c, &$d] +] = $array; + + +/* testLongListAssignByReferenceWithKeyA */ +list(get_key()[1] => &$e) = [1, 2, 3]; + /* testPassByReferenceA */ functionCall(&$something, $somethingElse); @@ -128,6 +156,9 @@ functionCall($something, &\SomeNS\SomeClass::$somethingElse); /* testPassByReferenceJ */ functionCall($something, &namespace\SomeClass::$somethingElse); +/* testPassByReferencePartiallyQualifiedName */ +functionCall($something, &Sub\Level\SomeClass::$somethingElse); + /* testNewByReferenceA */ $foobar2 = &new Foobar(); @@ -137,9 +168,27 @@ functionCall( $something , &new Foobar() ); /* testUseByReference */ $closure = function() use (&$var){}; +/* testUseByReferenceWithCommentFirstParam */ +$closure = function() use /*comment*/ (&$this->value){}; + +/* testUseByReferenceWithCommentSecondParam */ +$closure = function() use /*comment*/ ($varA, &$varB){}; + /* testArrowFunctionReturnByReference */ fn&($x) => $x; +$closure = function ( + /* testBitwiseAndExactParameterA */ + $a = MY_CONSTANT & parent::OTHER_CONSTANT, + /* testPassByReferenceExactParameterB */ + &$b, + /* testPassByReferenceExactParameterC */ + &...$c, + /* testBitwiseAndExactParameterD */ + $d = E_NOTICE & E_STRICT, +) {}; + +// Issue PHPCS#3049. /* testArrowFunctionPassByReferenceA */ $fn = fn(array &$one) => 1; @@ -148,3 +197,14 @@ $fn = fn($param, &...$moreParams) => 1; /* testClosureReturnByReference */ $closure = function &($param) use ($value) {}; + +/* testBitwiseAndArrowFunctionInDefault */ +$fn = fn( $one = E_NOTICE & E_STRICT) => 1; + +/* testTokenizerIssue1284PHPCSlt280A */ +if ($foo) {} +[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c; + +/* testTokenizerIssue1284PHPCSlt280C */ +if ($foo) {} +[&$a, $b]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php index ea2dddbad..bbe31baef 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php @@ -1,20 +1,38 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class IsReferenceTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Files\File::isReference method. + * + * @covers \PHP_CodeSniffer\Files\File::isReference + */ +final class IsReferenceTest extends AbstractMethodUnitTest { + /** + * Test that false is returned when a non-"bitwise and" token is passed. + * + * @return void + */ + public function testNotBitwiseAndToken() + { + $target = $this->getTargetToken('/* testBitwiseAndA */', T_STRING); + $this->assertFalse(self::$phpcsFile->isReference($target)); + + }//end testNotBitwiseAndToken() + + /** * Test correctly identifying whether a "bitwise and" token is a reference or not. * @@ -39,206 +57,298 @@ public function testIsReference($identifier, $expected) * * @see testIsReference() * - * @return array + * @return array> */ - public function dataIsReference() + public static function dataIsReference() { return [ - [ - '/* testBitwiseAndA */', - false, + 'issue-1971-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */', + 'expected' => true, + ], + 'issue-1971-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */', + 'expected' => true, + ], + 'bitwise and: param in function call' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, first value' => [ + 'testMarker' => '/* testBitwiseAndB */', + 'expected' => false, + ], + 'bitwise and: in unkeyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndC */', + 'expected' => false, + ], + 'bitwise and: in unkeyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndD */', + 'expected' => false, + ], + 'bitwise and: in keyed short array, last value' => [ + 'testMarker' => '/* testBitwiseAndE */', + 'expected' => false, + ], + 'bitwise and: in keyed long array, last value' => [ + 'testMarker' => '/* testBitwiseAndF */', + 'expected' => false, + ], + 'bitwise and: in assignment' => [ + 'testMarker' => '/* testBitwiseAndG */', + 'expected' => false, + ], + 'bitwise and: in param default value in function declaration' => [ + 'testMarker' => '/* testBitwiseAndH */', + 'expected' => false, + ], + 'bitwise and: in param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndI */', + 'expected' => false, + ], + 'reference: function declared to return by reference' => [ + 'testMarker' => '/* testFunctionReturnByReference */', + 'expected' => true, + ], + 'reference: only param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceA */', + 'expected' => true, + ], + 'reference: last param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceB */', + 'expected' => true, + ], + 'reference: only param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceC */', + 'expected' => true, + ], + 'reference: last param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceD */', + 'expected' => true, + ], + 'reference: typed param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceE */', + 'expected' => true, + ], + 'reference: typed param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceF */', + 'expected' => true, + ], + 'reference: variadic param in function declaration, pass by reference' => [ + 'testMarker' => '/* testFunctionPassByReferenceG */', + 'expected' => true, + ], + 'reference: foreach value' => [ + 'testMarker' => '/* testForeachValueByReference */', + 'expected' => true, + ], + 'reference: foreach key' => [ + 'testMarker' => '/* testForeachKeyByReference */', + 'expected' => true, + ], + 'reference: keyed short array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceA */', + 'expected' => true, + ], + 'reference: keyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceB */', + 'expected' => true, + ], + 'reference: unkeyed short array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceC */', + 'expected' => true, ], - [ - '/* testBitwiseAndB */', - false, + 'reference: unkeyed short array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceD */', + 'expected' => true, ], - [ - '/* testBitwiseAndC */', - false, + 'reference: keyed long array, first value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceE */', + 'expected' => true, ], - [ - '/* testBitwiseAndD */', - false, + 'reference: keyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceF */', + 'expected' => true, ], - [ - '/* testBitwiseAndE */', - false, + 'reference: unkeyed long array, only value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceG */', + 'expected' => true, ], - [ - '/* testBitwiseAndF */', - false, + 'reference: unkeyed long array, last value, value by reference' => [ + 'testMarker' => '/* testArrayValueByReferenceH */', + 'expected' => true, ], - [ - '/* testBitwiseAndG */', - false, + 'reference: variable, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceA */', + 'expected' => true, ], - [ - '/* testBitwiseAndH */', - false, + 'reference: variable, assign by reference, spacing variation' => [ + 'testMarker' => '/* testAssignByReferenceB */', + 'expected' => true, ], - [ - '/* testBitwiseAndI */', - false, + 'reference: variable, assign by reference, concat assign' => [ + 'testMarker' => '/* testAssignByReferenceC */', + 'expected' => true, ], - [ - '/* testFunctionReturnByReference */', - true, + 'reference: property, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceD */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceA */', - true, + 'reference: function return value, assign by reference' => [ + 'testMarker' => '/* testAssignByReferenceE */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceB */', - true, + 'reference: function return value, assign by reference, null coalesce assign' => [ + 'testMarker' => '/* testAssignByReferenceF */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceC */', - true, + 'reference: unkeyed short list, first var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyA */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceD */', - true, + 'reference: unkeyed short list, second var, assign by reference' => [ + 'testMarker' => '/* testShortListAssignByReferenceNoKeyB */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceE */', - true, + 'reference: unkeyed short list, nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceNoKey */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceF */', - true, + 'reference: unkeyed long list, second var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyA */', + 'expected' => true, ], - [ - '/* testFunctionPassByReferenceG */', - true, + 'reference: unkeyed long list, first nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyB */', + 'expected' => true, ], - [ - '/* testForeachValueByReference */', - true, + 'reference: unkeyed long list, last nested var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceNoKeyC */', + 'expected' => true, ], - [ - '/* testForeachKeyByReference */', - true, + 'reference: keyed short list, first nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyA */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceA */', - true, + 'reference: keyed short list, last nested var, assign by reference' => [ + 'testMarker' => '/* testNestedShortListAssignByReferenceWithKeyB */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceB */', - true, + 'reference: keyed long list, only var, assign by reference' => [ + 'testMarker' => '/* testLongListAssignByReferenceWithKeyA */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceC */', - true, + 'reference: first param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceA */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceD */', - true, + 'reference: last param in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceB */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceE */', - true, + 'reference: property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceC */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceF */', - true, + 'reference: hierarchical self property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceD */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceG */', - true, + 'reference: hierarchical parent property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceE */', + 'expected' => true, ], - [ - '/* testArrayValueByReferenceH */', - true, + 'reference: hierarchical static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceF */', + 'expected' => true, ], - [ - '/* testAssignByReferenceA */', - true, + 'reference: static property in function call, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceG */', + 'expected' => true, ], - [ - '/* testAssignByReferenceB */', - true, + 'reference: static property in function call, first with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceH */', + 'expected' => true, ], - [ - '/* testAssignByReferenceC */', - true, + 'reference: static property in function call, last with FQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceI */', + 'expected' => true, ], - [ - '/* testAssignByReferenceD */', - true, + 'reference: static property in function call, last with namespace relative name, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceJ */', + 'expected' => true, ], - [ - '/* testAssignByReferenceE */', - true, + 'reference: static property in function call, last with PQN, pass by reference' => [ + 'testMarker' => '/* testPassByReferencePartiallyQualifiedName */', + 'expected' => true, ], - [ - '/* testPassByReferenceA */', - true, + 'reference: new by reference' => [ + 'testMarker' => '/* testNewByReferenceA */', + 'expected' => true, ], - [ - '/* testPassByReferenceB */', - true, + 'reference: new by reference as function call param' => [ + 'testMarker' => '/* testNewByReferenceB */', + 'expected' => true, ], - [ - '/* testPassByReferenceC */', - true, + 'reference: closure use by reference' => [ + 'testMarker' => '/* testUseByReference */', + 'expected' => true, ], - [ - '/* testPassByReferenceD */', - true, + 'reference: closure use by reference, first param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentFirstParam */', + 'expected' => true, ], - [ - '/* testPassByReferenceE */', - true, + 'reference: closure use by reference, last param, with comment' => [ + 'testMarker' => '/* testUseByReferenceWithCommentSecondParam */', + 'expected' => true, ], - [ - '/* testPassByReferenceF */', - true, + 'reference: arrow fn declared to return by reference' => [ + 'testMarker' => '/* testArrowFunctionReturnByReference */', + 'expected' => true, ], - [ - '/* testPassByReferenceG */', - true, + 'bitwise and: first param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterA */', + 'expected' => false, ], - [ - '/* testPassByReferenceH */', - true, + 'reference: param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterB */', + 'expected' => true, ], - [ - '/* testPassByReferenceI */', - true, + 'reference: variadic param in closure declaration, pass by reference' => [ + 'testMarker' => '/* testPassByReferenceExactParameterC */', + 'expected' => true, ], - [ - '/* testPassByReferenceJ */', - true, + 'bitwise and: last param default value in closure declaration' => [ + 'testMarker' => '/* testBitwiseAndExactParameterD */', + 'expected' => false, ], - [ - '/* testNewByReferenceA */', - true, + 'reference: typed param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceA */', + 'expected' => true, ], - [ - '/* testNewByReferenceB */', - true, + 'reference: variadic param in arrow fn declaration, pass by reference' => [ + 'testMarker' => '/* testArrowFunctionPassByReferenceB */', + 'expected' => true, ], - [ - '/* testUseByReference */', - true, + 'reference: closure declared to return by reference' => [ + 'testMarker' => '/* testClosureReturnByReference */', + 'expected' => true, ], - [ - '/* testArrowFunctionReturnByReference */', - true, + 'bitwise and: param default value in arrow fn declaration' => [ + 'testMarker' => '/* testBitwiseAndArrowFunctionInDefault */', + 'expected' => false, ], - [ - '/* testArrowFunctionPassByReferenceA */', - true, + 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', + 'expected' => true, ], - [ - '/* testArrowFunctionPassByReferenceB */', - true, + 'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */', + 'expected' => true, ], - [ - '/* testClosureReturnByReference */', - true, + 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280C */', + 'expected' => true, ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php new file mode 100644 index 000000000..d196ce691 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php @@ -0,0 +1,227 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\Filter; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; +use RecursiveIteratorIterator; + +/** + * Base functionality and utilities for testing Filter classes. + */ +abstract class AbstractFilterTestCase extends TestCase +{ + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Config + */ + protected static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + protected static $ruleset; + + + /** + * Initialize the config and ruleset objects. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + self::$config = new ConfigDouble(['--extensions=php,inc/php,js,css']); + self::$ruleset = new Ruleset(self::$config); + + }//end initializeConfigAndRuleset() + + + /** + * Helper method to retrieve a mock object for a Filter class. + * + * The `setMethods()` method was silently deprecated in PHPUnit 9 and removed in PHPUnit 10. + * + * Note: direct access to the `getMockBuilder()` method is soft deprecated as of PHPUnit 10, + * and expected to be hard deprecated in PHPUnit 11 and removed in PHPUnit 12. + * Dealing with that is something for a later iteration of the test suite. + * + * @param string $className Fully qualified name of the class under test. + * @param array $constructorArgs Optional. Array of parameters to pass to the class constructor. + * @param array|null $methodsToMock Optional. The methods to mock in the class under test. + * Needed for PHPUnit cross-version support as PHPUnit 4.x does + * not have a `setMethodsExcept()` method yet. + * If not passed, no methods will be replaced. + * + * @return \PHPUnit\Framework\MockObject\MockObject + */ + protected function getMockedClass($className, array $constructorArgs=[], $methodsToMock=null) + { + $mockedObj = $this->getMockBuilder($className); + + if (method_exists($mockedObj, 'onlyMethods') === true) { + // PHPUnit 8+. + if (is_array($methodsToMock) === true) { + return $mockedObj + ->setConstructorArgs($constructorArgs) + ->onlyMethods($methodsToMock) + ->getMock(); + } + + return $mockedObj->getMock() + ->setConstructorArgs($constructorArgs); + } + + // PHPUnit < 8. + return $mockedObj + ->setConstructorArgs($constructorArgs) + ->setMethods($methodsToMock) + ->getMock(); + + }//end getMockedClass() + + + /** + * Retrieve an array of files which were accepted by a filter. + * + * @param \PHP_CodeSniffer\Filters\Filter $filter The Filter object under test. + * + * @return array + */ + protected function getFilteredResultsAsArray(Filter $filter) + { + $iterator = new RecursiveIteratorIterator($filter); + $files = []; + foreach ($iterator as $file) { + $files[] = $file; + } + + return $files; + + }//end getFilteredResultsAsArray() + + + /** + * Retrieve the basedir to use for tests using the `getFakeFileList()` method. + * + * @return string + */ + protected static function getBaseDir() + { + return dirname(dirname(dirname(__DIR__))); + + }//end getBaseDir() + + + /** + * Retrieve a file list containing a range of paths for testing purposes. + * + * This list **must** contain files which exist in this project (well, except for some which don't exist + * purely for testing purposes), as `realpath()` is used in the logic under test and `realpath()` will + * return `false` for any non-existent files, which will automatically filter them out before + * we get to the code under test. + * + * Note this list does not include `.` and `..` as \PHP_CodeSniffer\Files\FileList uses `SKIP_DOTS`. + * + * @return array + */ + protected static function getFakeFileList() + { + $basedir = self::getBaseDir(); + return [ + $basedir.'/.gitignore', + $basedir.'/.yamllint.yml', + $basedir.'/phpcs.xml', + $basedir.'/phpcs.xml.dist', + $basedir.'/autoload.php', + $basedir.'/bin', + $basedir.'/bin/phpcs', + $basedir.'/bin/phpcs.bat', + $basedir.'/scripts', + $basedir.'/scripts/build-phar.php', + $basedir.'/src', + $basedir.'/src/WillNotExist.php', + $basedir.'/src/WillNotExist.bak', + $basedir.'/src/WillNotExist.orig', + $basedir.'/src/Ruleset.php', + $basedir.'/src/Generators', + $basedir.'/src/Generators/Markdown.php', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + $basedir.'/src/Standards/Generic/Tests', + $basedir.'/src/Standards/Generic/Tests/Classes', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc', + // Will rarely exist when running the tests. + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.1.inc.bak', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.2.inc', + $basedir.'/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.php', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Docs', + $basedir.'/src/Standards/Squiz/Docs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ]; + + }//end getFakeFileList() + + + /** + * Translate Linux paths to Windows paths, when necessary. + * + * These type of tests should be able to run and pass on both *nix as well as Windows + * based dev systems. This method is a helper to allow for this. + * + * @param array $paths A single or multi-dimensional array containing + * file paths. + * + * @return array + */ + protected static function mapPathsToRuntimeOs(array $paths) + { + if (DIRECTORY_SEPARATOR !== '\\') { + return $paths; + } + + foreach ($paths as $key => $value) { + if (is_string($value) === true) { + $paths[$key] = strtr($value, '/', '\\\\'); + } else if (is_array($value) === true) { + $paths[$key] = self::mapPathsToRuntimeOs($value); + } + } + + return $paths; + + }//end mapPathsToRuntimeOs() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php index 2c9f57cd3..8d622061d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php @@ -5,75 +5,47 @@ * @author Willington Vega * @author Juliette Reinders Folmer * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Filters\Filter; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Filters\Filter; use PHP_CodeSniffer\Ruleset; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; -class AcceptTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Filters\Filter::accept method. + * + * @covers \PHP_CodeSniffer\Filters\Filter + */ +final class AcceptTest extends AbstractFilterTestCase { - /** - * The Config object. - * - * @var \PHP_CodeSniffer\Config - */ - protected static $config; - - /** - * The Ruleset object. - * - * @var \PHP_CodeSniffer\Ruleset - */ - protected static $ruleset; - - - /** - * Initialize the test. - * - * @return void - */ - public function setUp() - { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - - }//end setUp() - /** * Initialize the config and ruleset objects based on the `AcceptTest.xml` ruleset file. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // This test will be skipped. - return; - } - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; - self::$config = new Config(["--standard=$standard", "--ignore=*/somethingelse/*"]); + self::$config = new ConfigDouble(["--standard=$standard", '--ignore=*/somethingelse/*']); self::$ruleset = new Ruleset(self::$config); - }//end setUpBeforeClass() + }//end initializeConfigAndRuleset() /** * Test filtering a file list for excluded paths. * - * @param array $inputPaths List of file paths to be filtered. - * @param array $expectedOutput Expected filtering result. + * @param array $inputPaths List of file paths to be filtered. + * @param array $expectedOutput Expected filtering result. * * @dataProvider dataExcludePatterns * @@ -81,16 +53,10 @@ public static function setUpBeforeClass() */ public function testExcludePatterns($inputPaths, $expectedOutput) { - $fakeDI = new \RecursiveArrayIterator($inputPaths); - $filter = new Filter($fakeDI, '/', self::$config, self::$ruleset); - $iterator = new \RecursiveIteratorIterator($filter); - $files = []; - - foreach ($iterator as $file) { - $files[] = $file; - } + $fakeDI = new RecursiveArrayIterator($inputPaths); + $filter = new Filter($fakeDI, '/', self::$config, self::$ruleset); - $this->assertEquals($expectedOutput, $files); + $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($filter)); }//end testExcludePatterns() @@ -100,34 +66,34 @@ public function testExcludePatterns($inputPaths, $expectedOutput) * * @see testExcludePatterns * - * @return array + * @return array>> */ - public function dataExcludePatterns() + public static function dataExcludePatterns() { $testCases = [ // Test top-level exclude patterns. - [ - [ + 'Non-sniff specific path based excludes from ruleset and command line are respected and don\'t filter out too much' => [ + 'inputPaths' => [ '/path/to/src/Main.php', '/path/to/src/Something/Main.php', '/path/to/src/Somethingelse/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php', '/path/to/src/Other/Main.php', ], - [ + 'expectedOutput' => [ '/path/to/src/Main.php', '/path/to/src/SomethingelseEvenLonger/Main.php', ], ], // Test ignoring standard/sniff specific exclude patterns. - [ - [ + 'Filter should not act on standard/sniff specific exclude patterns' => [ + 'inputPaths' => [ '/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php', ], - [ + 'expectedOutput' => [ '/path/to/src/generic-project/Main.php', '/path/to/src/generic/Main.php', '/path/to/src/anything-generic/Main.php', @@ -136,17 +102,7 @@ public function dataExcludePatterns() ]; // Allow these tests to work on Windows as well. - if (DIRECTORY_SEPARATOR === '\\') { - foreach ($testCases as $key => $case) { - foreach ($case as $nr => $param) { - foreach ($param as $file => $value) { - $testCases[$key][$nr][$file] = strtr($value, '/', '\\'); - } - } - } - } - - return $testCases; + return self::mapPathsToRuntimeOs($testCases); }//end dataExcludePatterns() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php new file mode 100644 index 000000000..1b2189f90 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php @@ -0,0 +1,268 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\GitModified; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; +use ReflectionMethod; + +/** + * Tests for the \PHP_CodeSniffer\Filters\GitModified class. + * + * @covers \PHP_CodeSniffer\Filters\GitModified + */ +final class GitModifiedTest extends AbstractFilterTestCase +{ + + + /** + * Test filtering a file list for excluded paths. + * + * @return void + */ + public function testFileNamePassesAsBasePathWillTranslateToDirname() + { + $rootFile = self::getBaseDir().'/autoload.php'; + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $constructorArgs = [ + $fakeDI, + $rootFile, + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitModified', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn(['autoload.php']); + + $this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + + }//end testFileNamePassesAsBasePathWillTranslateToDirname() + + + /** + * Test filtering a file list for excluded paths. + * + * @param array $inputPaths List of file paths to be filtered. + * @param array $outputGitModified Simulated "git modified" output. + * @param array $expectedOutput Expected filtering result. + * + * @dataProvider dataAcceptOnlyGitModified + * + * @return void + */ + public function testAcceptOnlyGitModified($inputPaths, $outputGitModified, $expectedOutput) + { + $fakeDI = new RecursiveArrayIterator($inputPaths); + $constructorArgs = [ + $fakeDI, + self::getBaseDir(), + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitModified', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn($outputGitModified); + + $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + + }//end testAcceptOnlyGitModified() + + + /** + * Data provider. + * + * @see testAcceptOnlyGitModified + * + * @return array>> + */ + public static function dataAcceptOnlyGitModified() + { + $basedir = self::getBaseDir(); + $fakeFileList = self::getFakeFileList(); + + $testCases = [ + 'no files marked as git modified' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [], + 'expectedOutput' => [], + ], + + 'files marked as git modified which don\'t actually exist' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'src/WillNotExist.php', + 'src/WillNotExist.bak', + 'src/WillNotExist.orig', + ], + 'expectedOutput' => [], + ], + + 'single file marked as git modified - file in root dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'autoload.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + ], + ], + 'single file marked as git modified - file in sub dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, none valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.gitignore', + 'phpcs.xml.dist', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + ], + ], + + 'multiple files marked as git modified, only one file valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.gitignore', + 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, multiple files valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitModified' => [ + '.yamllint.yml', + 'autoload.php', + 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + ], + ]; + + return $testCases; + + }//end dataAcceptOnlyGitModified() + + + /** + * Test filtering a file list for excluded paths. + * + * @param string $cmd Command to run. + * @param array $expected Expected return value. + * + * @dataProvider dataExecAlwaysReturnsArray + * + * @return void + */ + public function testExecAlwaysReturnsArray($cmd, $expected) + { + if (is_dir(__DIR__.'/../../../.git') === false) { + $this->markTestSkipped('Not a git repository'); + } + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $filter = new GitModified($fakeDI, '/', self::$config, self::$ruleset); + + $reflMethod = new ReflectionMethod($filter, 'exec'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($filter, $cmd); + + $this->assertSame($expected, $result); + + }//end testExecAlwaysReturnsArray() + + + /** + * Data provider. + * + * @see testExecAlwaysReturnsArray + * + * {@internal Missing: test with a command which yields a `false` return value. + * JRF: I've not managed to find a command which does so, let alone one, which then + * doesn't have side-effects of uncatchable output while running the tests.} + * + * @return array>> + */ + public static function dataExecAlwaysReturnsArray() + { + return [ + 'valid command which won\'t have any output unless files in the bin dir have been modified' => [ + // Largely using the command used in the filter, but only checking the bin dir. + // This should prevent the test unexpectedly failing during local development (in most cases). + 'cmd' => 'git ls-files -o -m --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [], + ], + 'valid command which will have output' => [ + 'cmd' => 'git ls-files --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [ + 'bin/phpcbf', + 'bin/phpcbf.bat', + 'bin/phpcs', + 'bin/phpcs.bat', + ], + ], + ]; + + }//end dataExecAlwaysReturnsArray() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php new file mode 100644 index 000000000..545f5839f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php @@ -0,0 +1,268 @@ + + * @copyright 2023 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Filters; + +use PHP_CodeSniffer\Filters\GitStaged; +use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; +use RecursiveArrayIterator; +use ReflectionMethod; + +/** + * Tests for the \PHP_CodeSniffer\Filters\GitStaged class. + * + * @covers \PHP_CodeSniffer\Filters\GitStaged + */ +final class GitStagedTest extends AbstractFilterTestCase +{ + + + /** + * Test filtering a file list for excluded paths. + * + * @return void + */ + public function testFileNamePassesAsBasePathWillTranslateToDirname() + { + $rootFile = self::getBaseDir().'/autoload.php'; + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $constructorArgs = [ + $fakeDI, + $rootFile, + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitStaged', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn(['autoload.php']); + + $this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + + }//end testFileNamePassesAsBasePathWillTranslateToDirname() + + + /** + * Test filtering a file list for excluded paths. + * + * @param array $inputPaths List of file paths to be filtered. + * @param array $outputGitStaged Simulated "git staged" output. + * @param array $expectedOutput Expected filtering result. + * + * @dataProvider dataAcceptOnlyGitStaged + * + * @return void + */ + public function testAcceptOnlyGitStaged($inputPaths, $outputGitStaged, $expectedOutput) + { + $fakeDI = new RecursiveArrayIterator($inputPaths); + $constructorArgs = [ + $fakeDI, + self::getBaseDir(), + self::$config, + self::$ruleset, + ]; + $mockObj = $this->getMockedClass('PHP_CodeSniffer\Filters\GitStaged', $constructorArgs, ['exec']); + + $mockObj->expects($this->once()) + ->method('exec') + ->willReturn($outputGitStaged); + + $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + + }//end testAcceptOnlyGitStaged() + + + /** + * Data provider. + * + * @see testAcceptOnlyGitStaged + * + * @return array>> + */ + public static function dataAcceptOnlyGitStaged() + { + $basedir = self::getBaseDir(); + $fakeFileList = self::getFakeFileList(); + + $testCases = [ + 'no files marked as git modified' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [], + 'expectedOutput' => [], + ], + + 'files marked as git modified which don\'t actually exist' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'src/WillNotExist.php', + 'src/WillNotExist.bak', + 'src/WillNotExist.orig', + ], + 'expectedOutput' => [], + ], + + 'single file marked as git modified - file in root dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'autoload.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + ], + ], + 'single file marked as git modified - file in sub dir' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, none valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.gitignore', + 'phpcs.xml.dist', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + ], + ], + + 'multiple files marked as git modified, only one file valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.gitignore', + 'src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml', + 'src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + 'expectedOutput' => [ + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Generic', + $basedir.'/src/Standards/Generic/Docs', + $basedir.'/src/Standards/Generic/Docs/Classes', + $basedir.'/src/Standards/Generic/Sniffs', + $basedir.'/src/Standards/Generic/Sniffs/Classes', + $basedir.'/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php', + ], + ], + + 'multiple files marked as git modified, multiple files valid for scan' => [ + 'inputPaths' => $fakeFileList, + 'outputGitStaged' => [ + '.yamllint.yml', + 'autoload.php', + 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + 'expectedOutput' => [ + $basedir.'/autoload.php', + $basedir.'/src', + $basedir.'/src/Standards', + $basedir.'/src/Standards/Squiz', + $basedir.'/src/Standards/Squiz/Sniffs', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace', + $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', + $basedir.'/src/Standards/Squiz/Tests', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', + ], + ], + ]; + + return $testCases; + + }//end dataAcceptOnlyGitStaged() + + + /** + * Test filtering a file list for excluded paths. + * + * @param string $cmd Command to run. + * @param array $expected Expected return value. + * + * @dataProvider dataExecAlwaysReturnsArray + * + * @return void + */ + public function testExecAlwaysReturnsArray($cmd, $expected) + { + if (is_dir(__DIR__.'/../../../.git') === false) { + $this->markTestSkipped('Not a git repository'); + } + + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); + $filter = new GitStaged($fakeDI, '/', self::$config, self::$ruleset); + + $reflMethod = new ReflectionMethod($filter, 'exec'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($filter, $cmd); + + $this->assertSame($expected, $result); + + }//end testExecAlwaysReturnsArray() + + + /** + * Data provider. + * + * @see testExecAlwaysReturnsArray + * + * {@internal Missing: test with a command which yields a `false` return value. + * JRF: I've not managed to find a command which does so, let alone one, which then + * doesn't have side-effects of uncatchable output while running the tests.} + * + * @return array>> + */ + public static function dataExecAlwaysReturnsArray() + { + return [ + 'valid command which won\'t have any output unless files in the bin dir have been modified & staged' => [ + // Largely using the command used in the filter, but only checking the bin dir. + // This should prevent the test unexpectedly failing during local development (in most cases). + 'cmd' => 'git diff --cached --name-only -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [], + ], + 'valid command which will have output' => [ + 'cmd' => 'git ls-files --exclude-standard -- '.escapeshellarg(self::getBaseDir().'/bin'), + 'expected' => [ + 'bin/phpcbf', + 'bin/phpcbf.bat', + 'bin/phpcs', + 'bin/phpcs.bat', + ], + ], + ]; + + }//end dataExecAlwaysReturnsArray() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml new file mode 100644 index 000000000..cbca4fd51 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml new file mode 100644 index 000000000..159b7efa8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php new file mode 100644 index 000000000..fc84f88ac --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php @@ -0,0 +1,258 @@ + + * @copyright 2023 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Runner; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::explain() function. + * + * @covers \PHP_CodeSniffer\Ruleset::explain + */ +final class ExplainTest extends TestCase +{ + + + /** + * Test the output of the "explain" command. + * + * @return void + */ + public function testExplain() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1', '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplain() + + + /** + * Test the output of the "explain" command is not influenced by a user set report width. + * + * @return void + */ + public function testExplainAlwaysDisplaysCompleteSniffName() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1', '-e', '--report-width=30']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainAlwaysDisplaysCompleteSniffName() + + + /** + * Test the output of the "explain" command when a ruleset only contains a single sniff. + * + * This is mostly about making sure that the summary line uses the correct grammar. + * + * @return void + */ + public function testExplainSingleSniff() + { + // Set up the ruleset. + $standard = __DIR__.'/ExplainSingleSniffTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainSingleSniff() + + + /** + * Test that "explain" works correctly with custom rulesets. + * + * Verifies that: + * - The "standard" name is taken from the custom ruleset. + * - Any and all sniff additions and exclusions in the ruleset are taken into account correctly. + * - That the displayed list will have both the standards as well as the sniff names + * ordered alphabetically. + * + * @return void + */ + public function testExplainCustomRuleset() + { + // Set up the ruleset. + $standard = __DIR__.'/ExplainCustomRulesetTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The ExplainCustomRulesetTest standard contains 10 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (2 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'PSR12 (2 sniffs)'.PHP_EOL; + $expected .= '----------------'.PHP_EOL; + $expected .= ' PSR12.ControlStructures.BooleanOperatorPlacement'.PHP_EOL; + $expected .= ' PSR12.ControlStructures.ControlStructureSpacing'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (2 sniffs)'.PHP_EOL; + $expected .= '----------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainCustomRuleset() + + + /** + * Test the output of the "explain" command for a standard containing both deprecated + * and non-deprecated sniffs. + * + * Tests that: + * - Deprecated sniffs are marked with an asterix in the list. + * - A footnote is displayed explaining the asterix. + * - And that the "standard uses # deprecated sniffs" listing is **not** displayed. + * + * @return void + */ + public function testExplainWithDeprecatedSniffs() + { + // Set up the ruleset. + $standard = __DIR__."/ShowSniffDeprecationsTest.xml"; + $config = new ConfigDouble(["--standard=$standard", '-e']); + $ruleset = new Ruleset($config); + + $expected = PHP_EOL; + $expected .= 'The SniffDeprecationTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; + + $expected .= 'Fixtures (9 sniffs)'.PHP_EOL; + $expected .= '-------------------'.PHP_EOL; + $expected .= ' Fixtures.Deprecated.WithLongReplacement *'.PHP_EOL; + $expected .= ' Fixtures.Deprecated.WithoutReplacement *'.PHP_EOL; + $expected .= ' Fixtures.Deprecated.WithReplacement *'.PHP_EOL; + $expected .= ' Fixtures.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; + $expected .= ' Fixtures.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; + $expected .= ' Fixtures.SetProperty.AllowedAsDeclared'.PHP_EOL; + $expected .= ' Fixtures.SetProperty.AllowedViaMagicMethod'.PHP_EOL; + $expected .= ' Fixtures.SetProperty.AllowedViaStdClass'.PHP_EOL; + $expected .= ' Fixtures.SetProperty.NotAllowedViaAttribute'.PHP_EOL.PHP_EOL; + + $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->explain(); + + }//end testExplainWithDeprecatedSniffs() + + + /** + * Test that each standard passed on the command-line is explained separately. + * + * @covers \PHP_CodeSniffer\Runner::runPHPCS + * + * @return void + */ + public function testExplainWillExplainEachStandardSeparately() + { + $standard = __DIR__.'/ExplainSingleSniffTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '-e', + "--standard=PSR1,$standard", + '--report-width=80', + ]; + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL.PHP_EOL; + + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $runner = new Runner(); + $exitCode = $runner->runPHPCS(); + + }//end testExplainWillExplainEachStandardSeparately() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php new file mode 100644 index 000000000..40c23113d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php @@ -0,0 +1,41 @@ +magic[$name] = $value; + } + + public function __get($name) + { + if (isset($this->magic[$name])) { + return $this->magic[$name]; + } + + return null; + } + + public function register() + { + return [T_WHITESPACE]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php new file mode 100644 index 000000000..30418729d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/SetProperty/AllowedViaStdClassSniff.php @@ -0,0 +1,26 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php index 8b138e0b0..1955ce2a4 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php @@ -4,16 +4,21 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class RuleInclusionAbsoluteLinuxTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class using a Linux-style absolute path to include a sniff. + * + * @covers \PHP_CodeSniffer\Ruleset + */ +final class RuleInclusionAbsoluteLinuxTest extends TestCase { /** @@ -41,17 +46,12 @@ class RuleInclusionAbsoluteLinuxTest extends TestCase /** * Initialize the config and ruleset objects. * + * @before + * * @return void */ - public function setUp() + public function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -71,22 +71,24 @@ public function setUp() } // Initialize the config and ruleset objects for the test. - $config = new Config(["--standard={$this->standard}"]); + $config = new ConfigDouble(["--standard={$this->standard}"]); $this->ruleset = new Ruleset($config); - }//end setUp() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + public function resetRuleset() { file_put_contents($this->standard, $this->contents); - }//end tearDown() + }//end resetRuleset() /** @@ -98,7 +100,6 @@ public function tearDown() public function testLinuxStylePathRuleInclusion() { // Test that the sniff is correctly registered. - $this->assertObjectHasAttribute('sniffCodes', $this->ruleset); $this->assertCount(1, $this->ruleset->sniffCodes); $this->assertArrayHasKey('Generic.Formatting.SpaceAfterNot', $this->ruleset->sniffCodes); $this->assertSame( diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml index 64d1aae68..2978cef9f 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php index f8e3255b8..cba45ee39 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php @@ -4,16 +4,21 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; -class RuleInclusionAbsoluteWindowsTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff. + * + * @covers \PHP_CodeSniffer\Ruleset + */ +final class RuleInclusionAbsoluteWindowsTest extends TestCase { /** @@ -41,21 +46,16 @@ class RuleInclusionAbsoluteWindowsTest extends TestCase /** * Initialize the config and ruleset objects. * + * @before + * * @return void */ - public function setUp() + public function initializeConfigAndRuleset() { if (DIRECTORY_SEPARATOR === '/') { $this->markTestSkipped('Windows specific test'); } - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -70,24 +70,26 @@ public function setUp() } // Initialize the config and ruleset objects for the test. - $config = new Config(["--standard={$this->standard}"]); + $config = new ConfigDouble(["--standard={$this->standard}"]); $this->ruleset = new Ruleset($config); - }//end setUp() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + public function resetRuleset() { if (DIRECTORY_SEPARATOR !== '/') { file_put_contents($this->standard, $this->contents); } - }//end tearDown() + }//end resetRuleset() /** @@ -99,7 +101,6 @@ public function tearDown() public function testWindowsStylePathRuleInclusion() { // Test that the sniff is correctly registered. - $this->assertObjectHasAttribute('sniffCodes', $this->ruleset); $this->assertCount(1, $this->ruleset->sniffCodes); $this->assertArrayHasKey('Generic.Formatting.SpaceAfterCast', $this->ruleset->sniffCodes); $this->assertSame( diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml index 15710d209..e92c68842 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml index ca116d45e..d95af20d9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php index 24abe8dab..039c99748 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php @@ -4,16 +4,22 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Ruleset; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; +use ReflectionObject; -class RuleInclusionTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Ruleset class. + * + * @covers \PHP_CodeSniffer\Ruleset + */ +final class RuleInclusionTest extends TestCase { /** @@ -38,35 +44,15 @@ class RuleInclusionTest extends TestCase private static $contents = ''; - /** - * Initialize the test. - * - * @return void - */ - public function setUp() - { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // PEAR installs test and sniff files into different locations - // so these tests will not pass as they directly reference files - // by relative location. - $this->markTestSkipped('Test cannot run from a PEAR install'); - } - - }//end setUp() - - /** * Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeConfigAndRuleset() { - if ($GLOBALS['PHP_CODESNIFFER_PEAR'] === true) { - // This test will be skipped. - return; - } - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; self::$standard = $standard; @@ -88,22 +74,24 @@ public static function setUpBeforeClass() self::markTestSkipped('On the fly ruleset adjustment failed'); } - $config = new Config(["--standard=$standard"]); + $config = new ConfigDouble(["--standard=$standard"]); self::$ruleset = new Ruleset($config); - }//end setUpBeforeClass() + }//end initializeConfigAndRuleset() /** * Reset ruleset file. * + * @after + * * @return void */ - public function tearDown() + public function resetRuleset() { file_put_contents(self::$standard, self::$contents); - }//end tearDown() + }//end resetRuleset() /** @@ -113,14 +101,13 @@ public function tearDown() */ public function testHasSniffCodes() { - $this->assertObjectHasAttribute('sniffCodes', self::$ruleset); - $this->assertCount(14, self::$ruleset->sniffCodes); + $this->assertCount(48, self::$ruleset->sniffCodes); }//end testHasSniffCodes() /** - * Test that sniffs are correctly registered, independently on the syntax used to include the sniff. + * Test that sniffs are correctly registered, independently of the syntax used to include the sniff. * * @param string $key Expected array key. * @param string $value Expected array value. @@ -142,11 +129,59 @@ public function testRegisteredSniffCodes($key, $value) * * @see self::testRegisteredSniffCodes() * - * @return array + * @return array> */ - public function dataRegisteredSniffCodes() + public static function dataRegisteredSniffCodes() { return [ + [ + 'PSR2.Classes.ClassDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff', + ], + [ + 'PSR2.Classes.PropertyDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\PropertyDeclarationSniff', + ], + [ + 'PSR2.ControlStructures.ControlStructureSpacing', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ControlStructureSpacingSniff', + ], + [ + 'PSR2.ControlStructures.ElseIfDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\ElseIfDeclarationSniff', + ], + [ + 'PSR2.ControlStructures.SwitchDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff', + ], + [ + 'PSR2.Files.ClosingTag', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\ClosingTagSniff', + ], + [ + 'PSR2.Files.EndFileNewline', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Files\EndFileNewlineSniff', + ], + [ + 'PSR2.Methods.FunctionCallSignature', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + ], + [ + 'PSR2.Methods.FunctionClosingBrace', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionClosingBraceSniff', + ], + [ + 'PSR2.Methods.MethodDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\MethodDeclarationSniff', + ], + [ + 'PSR2.Namespaces.NamespaceDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\NamespaceDeclarationSniff', + ], + [ + 'PSR2.Namespaces.UseDeclaration', + 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Namespaces\UseDeclarationSniff', + ], [ 'PSR1.Classes.ClassDeclaration', 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', @@ -180,8 +215,100 @@ public function dataRegisteredSniffCodes() 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\UpperCaseConstantNameSniff', ], [ - 'Zend.NamingConventions.ValidVariableName', - 'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff', + 'Generic.Files.LineEndings', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineEndingsSniff', + ], + [ + 'Generic.Files.LineLength', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', + ], + [ + 'Squiz.WhiteSpace.SuperfluousWhitespace', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\SuperfluousWhitespaceSniff', + ], + [ + 'Generic.Formatting.DisallowMultipleStatements', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting\DisallowMultipleStatementsSniff', + ], + [ + 'Generic.WhiteSpace.ScopeIndent', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff', + ], + [ + 'Generic.WhiteSpace.DisallowTabIndent', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\DisallowTabIndentSniff', + ], + [ + 'Generic.PHP.LowerCaseKeyword', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseKeywordSniff', + ], + [ + 'Generic.PHP.LowerCaseConstant', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseConstantSniff', + ], + [ + 'Squiz.Scope.MethodScope', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Scope\MethodScopeSniff', + ], + [ + 'Squiz.WhiteSpace.ScopeKeywordSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeKeywordSpacingSniff', + ], + [ + 'Squiz.Functions.FunctionDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationSniff', + ], + [ + 'Squiz.Functions.LowercaseFunctionKeywords', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\LowercaseFunctionKeywordsSniff', + ], + [ + 'Squiz.Functions.FunctionDeclarationArgumentSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\FunctionDeclarationArgumentSpacingSniff', + ], + [ + 'PEAR.Functions.ValidDefaultValue', + 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff', + ], + [ + 'Squiz.Functions.MultiLineFunctionDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Functions\MultiLineFunctionDeclarationSniff', + ], + [ + 'Generic.Functions.FunctionCallArgumentSpacing', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\Functions\FunctionCallArgumentSpacingSniff', + ], + [ + 'Squiz.ControlStructures.ControlSignature', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ControlSignatureSniff', + ], + [ + 'Squiz.WhiteSpace.ControlStructureSpacing', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ControlStructureSpacingSniff', + ], + [ + 'Squiz.WhiteSpace.ScopeClosingBrace', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\ScopeClosingBraceSniff', + ], + [ + 'Squiz.ControlStructures.ForEachLoopDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForEachLoopDeclarationSniff', + ], + [ + 'Squiz.ControlStructures.ForLoopDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\ForLoopDeclarationSniff', + ], + [ + 'Squiz.ControlStructures.LowercaseDeclaration', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures\LowercaseDeclarationSniff', + ], + [ + 'Generic.ControlStructures.InlineControlStructure', + 'PHP_CodeSniffer\Standards\Generic\Sniffs\ControlStructures\InlineControlStructureSniff', + ], + [ + 'PSR12.Operators.OperatorSpacing', + 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', ], [ 'Generic.Arrays.ArrayIndent', @@ -191,10 +318,6 @@ public function dataRegisteredSniffCodes() 'Generic.Metrics.CyclomaticComplexity', 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', ], - [ - 'Generic.Files.LineLength', - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', - ], [ 'Generic.NamingConventions.CamelCapsFunctionName', 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', @@ -212,9 +335,9 @@ public function dataRegisteredSniffCodes() * Test that setting properties for standards, categories, sniffs works for all supported rule * inclusion methods. * - * @param string $sniffClass The name of the sniff class. - * @param string $propertyName The name of the changed property. - * @param mixed $expectedValue The value expected for the property. + * @param string $sniffClass The name of the sniff class. + * @param string $propertyName The name of the changed property. + * @param string|int|bool $expectedValue The value expected for the property. * * @dataProvider dataSettingProperties * @@ -222,9 +345,11 @@ public function dataRegisteredSniffCodes() */ public function testSettingProperties($sniffClass, $propertyName, $expectedValue) { - $this->assertObjectHasAttribute('sniffs', self::$ruleset); $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs); - $this->assertObjectHasAttribute($propertyName, self::$ruleset->sniffs[$sniffClass]); + + $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); + $errorMsg = sprintf('Property %s does not exist on sniff class %s', $propertyName, $sniffClass); + $this->assertTrue($hasProperty, $errorMsg); $actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName; $this->assertSame($expectedValue, $actualValue); @@ -237,61 +362,117 @@ public function testSettingProperties($sniffClass, $propertyName, $expectedValue * * @see self::testSettingProperties() * - * @return array + * @return array> */ - public function dataSettingProperties() + public static function dataSettingProperties() { return [ - 'ClassDeclarationSniff' => [ - 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', - 'setforallsniffs', - true, + 'Set property for complete standard: PSR2 ClassDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'SideEffectsSniff' => [ - 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Files\SideEffectsSniff', - 'setforallsniffs', - true, + 'Set property for complete standard: PSR2 SwitchDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\ControlStructures\SwitchDeclarationSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'ValidVariableNameSniff' => [ - 'PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions\ValidVariableNameSniff', - 'setforallincategory', - true, + 'Set property for complete standard: PSR2 FunctionCallSignature' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + 'propertyName' => 'indent', + 'expectedValue' => '20', ], - 'ArrayIndentSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff', - 'indent', - '2', + 'Set property for complete category: PSR12 OperatorSpacing' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', + 'propertyName' => 'ignoreSpacingBeforeAssignments', + 'expectedValue' => false, ], - 'LineLengthSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', - 'lineLimit', - '10', + 'Set property for individual sniff: Generic ArrayIndent' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff', + 'propertyName' => 'indent', + 'expectedValue' => '2', ], - 'CamelCapsFunctionNameSniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', - 'strict', - false, + 'Set property for individual sniff using sniff file inclusion: Generic LineLength' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff', + 'propertyName' => 'lineLimit', + 'expectedValue' => '10', ], - 'NestingLevelSniff-nestingLevel' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', - 'nestingLevel', - '2', + 'Set property for individual sniff using sniff file inclusion: CamelCapsFunctionName' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', + 'propertyName' => 'strict', + 'expectedValue' => false, ], - 'NestingLevelSniff-setforsniffsinincludedruleset' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', - 'setforsniffsinincludedruleset', - true, + 'Set property for individual sniff via included ruleset: NestingLevel - nestingLevel' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', + 'propertyName' => 'nestingLevel', + 'expectedValue' => '2', + ], + 'Set property for all sniffs in an included ruleset: NestingLevel - absoluteNestingLevel' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\NestingLevelSniff', + 'propertyName' => 'absoluteNestingLevel', + 'expectedValue' => true, ], // Testing that setting a property at error code level does *not* work. - 'CyclomaticComplexitySniff' => [ - 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', - 'complexity', - 10, + 'Set property for error code will not change the sniff property value: CyclomaticComplexity' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', + 'propertyName' => 'complexity', + 'expectedValue' => 10, ], ]; }//end dataSettingProperties() + /** + * Test that setting properties for standards, categories on sniffs which don't support the property will + * silently ignore the property and not set it. + * + * @param string $sniffClass The name of the sniff class. + * @param string $propertyName The name of the property which should not be set. + * + * @dataProvider dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails + * + * @return void + */ + public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails($sniffClass, $propertyName) + { + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); + $errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass); + $this->assertFalse($hasProperty, $errorMsg); + + }//end testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + + + /** + * Data provider. + * + * @see self::testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + * + * @return arraystring, string>> + */ + public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + { + return [ + 'Set property for complete standard: PSR2 ClassDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'propertyName' => 'setforallsniffs', + ], + 'Set property for complete standard: PSR2 FunctionCallSignature' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\FunctionCallSignatureSniff', + 'propertyName' => 'setforallsniffs', + ], + 'Set property for complete category: PSR12 OperatorSpacing' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', + 'propertyName' => 'setforallincategory', + ], + ]; + + }//end dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml index 06ce040e7..e1812bbba 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml @@ -1,15 +1,17 @@ - + + - + + @@ -38,8 +40,9 @@ + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml new file mode 100644 index 000000000..5840d0c36 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml new file mode 100644 index 000000000..7ff217824 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml new file mode 100644 index 000000000..387f419e8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml new file mode 100644 index 000000000..7c4ca4fd3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml new file mode 100644 index 000000000..979b48f52 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml new file mode 100644 index 000000000..48a36a831 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml new file mode 100644 index 000000000..7caae3d39 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml new file mode 100644 index 000000000..5dca1a010 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php new file mode 100644 index 000000000..5b0227874 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -0,0 +1,405 @@ + + * @copyright 2022 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; +use ReflectionObject; + +/** + * These tests specifically focus on the changes made to work around the PHP 8.2 dynamic properties deprecation. + * + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class SetSniffPropertyTest extends TestCase +{ + + + /** + * Test that setting a property via the ruleset works in all situations which allow for it. + * + * @param string $name Name of the test. Used for the sniff name, the ruleset file name etc. + * + * @dataProvider dataSniffPropertiesGetSetWhenAllowed + * + * @return void + */ + public function testSniffPropertiesGetSetWhenAllowed($name) + { + $sniffCode = "Fixtures.SetProperty.{$name}"; + $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $properties = [ + 'arbitrarystring' => 'arbitraryvalue', + 'arbitraryarray' => [ + 'mykey' => 'myvalue', + 'otherkey' => 'othervalue', + ], + ]; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + foreach ($properties as $name => $expectedValue) { + $this->assertSame($expectedValue, $sniffObject->$name, 'Property value not set to expected value'); + } + + }//end testSniffPropertiesGetSetWhenAllowed() + + + /** + * Data provider. + * + * @see self::testSniffPropertiesGetSetWhenAllowed() + * + * @return array> + */ + public static function dataSniffPropertiesGetSetWhenAllowed() + { + return [ + 'Property allowed as explicitly declared' => ['AllowedAsDeclared'], + 'Property allowed as sniff extends stdClass' => ['AllowedViaStdClass'], + 'Property allowed as sniff has magic __set() method' => ['AllowedViaMagicMethod'], + ]; + + }//end dataSniffPropertiesGetSetWhenAllowed() + + + /** + * Test that setting a property for a category will apply it correctly to those sniffs which support the + * property, but won't apply it to sniffs which don't. + * + * Note: this test intentionally uses the `PEAR.Functions` category as two sniffs in that category + * have a public property with the same name (`indent`) and one sniff doesn't, which makes it a great + * test case for this. + * + * @return void + */ + public function testSetPropertyAppliesPropertyToMultipleSniffsInCategory() + { + $propertyName = 'indent'; + $expectedValue = '10'; + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Test that the two sniffs which support the property have received the value. + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionCallSignatureSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass); + + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\FunctionDeclarationSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($expectedValue, $sniffObject->$propertyName, 'Property value not set to expected value for '.$sniffClass); + + // Test that the property doesn't get set for the one sniff which doesn't support the property. + $sniffClass = 'PHP_CodeSniffer\Standards\PEAR\Sniffs\Functions\ValidDefaultValueSniff'; + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); + + $hasProperty = (new ReflectionObject($ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); + $errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass); + $this->assertFalse($hasProperty, $errorMsg); + + }//end testSetPropertyAppliesPropertyToMultipleSniffsInCategory() + + + /** + * Test that attempting to set a non-existent property directly on a sniff will throw an error + * when the sniff does not explicitly declare the property, extends stdClass or has magic methods. + * + * @return void + */ + public function testSetPropertyThrowsErrorOnInvalidProperty() + { + $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + $exceptionMsg = 'Ruleset invalid. Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent'; + if (method_exists($this, 'expectException') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedException($exceptionClass, $exceptionMsg); + } + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyThrowsErrorOnInvalidPropertyTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + }//end testSetPropertyThrowsErrorOnInvalidProperty() + + + /** + * Test that attempting to set a non-existent property directly on a sniff will throw an error + * when the sniff does not explicitly declare the property, extends stdClass or has magic methods, + * even though the sniff has the PHP 8.2 `#[AllowDynamicProperties]` attribute set. + * + * @return void + */ + public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() + { + $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff Fixtures.SetProperty.NotAllowedViaAttribute'; + if (method_exists($this, 'expectException') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedException($exceptionClass, $exceptionMsg); + } + + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyNotAllowedViaAttributeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + }//end testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() + + + /** + * Test that attempting to set a non-existent property on a sniff when the property directive is + * for the whole standard, does not yield an error. + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard() + { + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard() + + + /** + * Test that attempting to set a non-existent property on a sniff when the property directive is + * for a whole category, does not yield an error. + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + { + // Set up the ruleset. + $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * sets the property correctly when using the new $settings array format. + * + * @return void + */ + public function testDirectCallWithNewArrayFormatSetsProperty() + { + $name = 'AllowedAsDeclared'; + $sniffCode = "Fixtures.SetProperty.{$name}"; + $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $propertyName = 'arbitrarystring'; + $propertyValue = 'new value'; + + $ruleset->setSniffProperty( + $sniffClass, + $propertyName, + [ + 'scope' => 'sniff', + 'value' => $propertyValue, + ] + ); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value'); + + }//end testDirectCallWithNewArrayFormatSetsProperty() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * sets the property correctly when using the old $settings array format. + * + * Tested by silencing the deprecation notice as otherwise the test would fail on the deprecation notice. + * + * @param mixed $propertyValue Value for the property to set. + * + * @dataProvider dataDirectCallWithOldArrayFormatSetsProperty + * + * @return void + */ + public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue) + { + $name = 'AllowedAsDeclared'; + $sniffCode = "Fixtures.SetProperty.{$name}"; + $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $propertyName = 'arbitrarystring'; + + @$ruleset->setSniffProperty( + $sniffClass, + $propertyName, + $propertyValue + ); + + // Verify that the sniff has been registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame($sniffClass, $ruleset->sniffCodes[$sniffCode], 'Target sniff not registered with the correct class'); + + // Test that the property as declared in the ruleset has been set on the sniff. + $this->assertArrayHasKey($sniffClass, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[$sniffClass]; + $this->assertSame($propertyValue, $sniffObject->$propertyName, 'Property value not set to expected value'); + + }//end testDirectCallWithOldArrayFormatSetsProperty() + + + /** + * Data provider. + * + * @see self::testDirectCallWithOldArrayFormatSetsProperty() + * + * @return array> + */ + public static function dataDirectCallWithOldArrayFormatSetsProperty() + { + return [ + 'Property value is not an array (boolean)' => [ + 'propertyValue' => false, + ], + 'Property value is not an array (string)' => [ + 'propertyValue' => 'a string', + ], + 'Property value is an empty array' => [ + 'propertyValue' => [], + ], + 'Property value is an array without keys' => [ + 'propertyValue' => [ + 'value', + false, + ], + ], + 'Property value is an array without the "scope" or "value" keys' => [ + 'propertyValue' => [ + 'key1' => 'value', + 'key2' => false, + ], + ], + 'Property value is an array without the "scope" key' => [ + 'propertyValue' => [ + 'key1' => 'value', + 'value' => true, + ], + ], + 'Property value is an array without the "value" key' => [ + 'propertyValue' => [ + 'scope' => 'value', + 'key2' => 1234, + ], + ], + ]; + + }//end dataDirectCallWithOldArrayFormatSetsProperty() + + + /** + * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method + * throws a deprecation notice when using the old $settings array format. + * + * Note: as PHPUnit stops as soon as it sees the deprecation notice, the setting of the property + * value is not tested here. + * + * @return void + */ + public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice() + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $exceptionMsg = 'the format of the $settings parameter has changed from (mixed) $value to array(\'scope\' => \'sniff|standard\', \'value\' => $value). Please update your integration code. See PR #3629 for more information.'; + + if (method_exists($this, 'expectException') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedException($exceptionClass, $exceptionMsg); + } + + $name = 'AllowedAsDeclared'; + $sniffCode = "Fixtures.SetProperty.{$name}"; + $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + + // Set up the ruleset. + $standard = __DIR__."/SetProperty{$name}Test.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $propertyName = 'arbitrarystring'; + + $ruleset->setSniffProperty( + $sniffClass, + 'arbitrarystring', + ['key' => 'value'] + ); + + }//end testDirectCallWithOldArrayFormatThrowsDeprecationNotice() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml new file mode 100644 index 000000000..5e2480bf2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml new file mode 100644 index 000000000..6e667375a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml new file mode 100644 index 000000000..d32516799 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml new file mode 100644 index 000000000..89d83ab52 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml new file mode 100644 index 000000000..c1eb062e1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml new file mode 100644 index 000000000..3ce96ce89 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml new file mode 100644 index 000000000..9f1cc8515 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php new file mode 100644 index 000000000..8e81f96a2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -0,0 +1,510 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests PHPCS native handling of sniff deprecations. + * + * @covers \PHP_CodeSniffer\Ruleset::hasSniffDeprecations + * @covers \PHP_CodeSniffer\Ruleset::showSniffDeprecations + */ +final class ShowSniffDeprecationsTest extends TestCase +{ + + + /** + * Test the return value of the hasSniffDeprecations() method. + * + * @param string $standard The standard to use for the test. + * @param bool $expected The expected function return value. + * + * @dataProvider dataHasSniffDeprecations + * + * @return void + */ + public function testHasSniffDeprecations($standard, $expected) + { + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->hasSniffDeprecations()); + + }//end testHasSniffDeprecations() + + + /** + * Data provider. + * + * @see testHasSniffDeprecations() + * + * @return array> + */ + public static function dataHasSniffDeprecations() + { + return [ + 'Standard not using deprecated sniffs: PSR1' => [ + 'standard' => 'PSR1', + 'expected' => false, + ], + 'Standard using deprecated sniffs: Test Fixture' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'expected' => true, + ], + ]; + + }//end dataHasSniffDeprecations() + + + /** + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used. + * + * @param string $standard The standard to use for the test. + * @param array $additionalArgs Optional. Additional arguments to pass. + * + * @dataProvider dataDeprecatedSniffsListDoesNotShow + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs=[]) + { + $args = $additionalArgs; + $args[] = '.'; + $args[] = "--standard=$standard"; + + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShow() + + + /** + * Data provider. + * + * @see testDeprecatedSniffsListDoesNotShow() + * + * @return array>> + */ + public static function dataDeprecatedSniffsListDoesNotShow() + { + return [ + 'Standard not using deprecated sniffs: PSR1' => [ + 'standard' => 'PSR1', + ], + 'Standard using deprecated sniffs; explain mode' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['-e'], + ], + 'Standard using deprecated sniffs; quiet mode' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['-q'], + ], + 'Standard using deprecated sniffs; documentation is requested' => [ + 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', + 'additionalArgs' => ['--generator=text'], + ], + ]; + + }//end dataDeprecatedSniffsListDoesNotShow() + + + /** + * Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs, + * but only running select non-deprecated sniffs (using `--sniffs=...`). + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + /* + * Apply sniff restrictions. + * For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use. + */ + + $restrictions = []; + $sniffs = [ + 'Fixtures.SetProperty.AllowedAsDeclared', + 'Fixtures.SetProperty.AllowedViaStdClass', + ]; + foreach ($sniffs as $sniffCode) { + $parts = explode('.', strtolower($sniffCode)); + $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $restrictions[strtolower($sniffName)] = true; + } + + $sniffFiles = []; + $allSniffs = $ruleset->sniffCodes; + foreach ($allSniffs as $sniffName) { + $sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php'; + $sniffFiles[] = $sniffFile; + } + + $ruleset->registerSniffs($allSniffs, $restrictions, []); + $ruleset->populateTokenListeners(); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDeprecated() + + + /** + * Test that the listing with deprecated sniffs will not show when using a standard containing deprecated sniffs, + * but all deprecated sniffs have been excluded from the run (using `--exclude=...`). + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard"]); + $ruleset = new Ruleset($config); + + /* + * Apply sniff restrictions. + * For tests we need to manually trigger this if the standard is "installed", like with the fixtures these tests use. + */ + + $exclusions = []; + $exclude = [ + 'Fixtures.Deprecated.WithLongReplacement', + 'Fixtures.Deprecated.WithoutReplacement', + 'Fixtures.Deprecated.WithReplacement', + 'Fixtures.Deprecated.WithReplacementContainingLinuxNewlines', + 'Fixtures.Deprecated.WithReplacementContainingNewlines', + ]; + foreach ($exclude as $sniffCode) { + $parts = explode('.', strtolower($sniffCode)); + $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $exclusions[strtolower($sniffName)] = true; + } + + $sniffFiles = []; + $allSniffs = $ruleset->sniffCodes; + foreach ($allSniffs as $sniffName) { + $sniffFile = str_replace('\\', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.$sniffFile.'.php'; + $sniffFiles[] = $sniffFile; + } + + $ruleset->registerSniffs($allSniffs, [], $exclusions); + $ruleset->populateTokenListeners(); + + $this->expectOutputString(''); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExcluded() + + + /** + * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * + * This tests a number of different aspects: + * 1. That the summary line uses the correct grammar when there is are multiple deprecated sniffs. + * 2. That there is no trailing whitespace when the sniff does not provide a custom message. + * 3. That custom messages containing new line characters (any type) are handled correctly and + * that those new line characters are converted to the OS supported new line char. + * + * @return void + */ + public function testDeprecatedSniffsWarning() + { + $standard = __DIR__.'/ShowSniffDeprecationsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '--no-colors']); + $ruleset = new Ruleset($config); + + $expected = 'WARNING: The SniffDeprecationTest standard uses 5 deprecated sniffs'.PHP_EOL; + $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL; + $expected .= ' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL; + $expected .= ' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL; + $expected .= ' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL; + $expected .= ' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL; + $expected .= ' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL; + $expected .= ' libero.'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; + $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; + $expected .= ' sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL; + $expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem.'.PHP_EOL; + $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; + $expected .= ' lectus at egestas.'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; + $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; + $expected .= ' sed.'.PHP_EOL; + $expected .= ' Fusce egestas congue massa semper cursus. Donec quis pretium tellus.'.PHP_EOL; + $expected .= ' In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL; + $expected .= ' eros sapien at sem.'.PHP_EOL; + $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; + $expected .= ' lectus at egestas'.PHP_EOL.PHP_EOL; + $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; + $expected .= 'future.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->showSniffDeprecations(); + + }//end testDeprecatedSniffsWarning() + + + /** + * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * + * This tests the following aspects: + * 1. That the summary line uses the correct grammar when there is a single deprecated sniff. + * 2. That the separator line below the summary maximizes at the longest line length. + * 3. That the word wrapping respects the maximum report width. + * 4. That the sniff name is truncated if it is longer than the max report width. + * + * @param int $reportWidth Report width for the test. + * @param string $expectedOutput Expected output. + * + * @dataProvider dataReportWidthIsRespected + * + * @return void + */ + public function testReportWidthIsRespected($reportWidth, $expectedOutput) + { + // Set up the ruleset. + $standard = __DIR__.'/ShowSniffDeprecationsReportWidthTest.xml'; + $config = new ConfigDouble(['.', "--standard=$standard", "--report-width=$reportWidth", '--no-colors']); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expectedOutput); + + $ruleset->showSniffDeprecations(); + + }//end testReportWidthIsRespected() + + + /** + * Data provider. + * + * @see testReportWidthIsRespected() + * + * @return array> + */ + public static function dataReportWidthIsRespected() + { + $summaryLine = 'WARNING: The SniffDeprecationTest standard uses 1 deprecated sniff'.PHP_EOL; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Report width small: 40; with truncated sniff name and wrapped header and footer lines' => [ + 'reportWidth' => 40, + 'expectedOutput' => 'WARNING: The SniffDeprecationTest'.PHP_EOL + .'standard uses 1 deprecated sniff'.PHP_EOL + .'----------------------------------------'.PHP_EOL + .'- Fixtures.Deprecated.WithLongRepla...'.PHP_EOL + .' This sniff has been deprecated since'.PHP_EOL + .' v3.8.0 and will be removed in'.PHP_EOL + .' v4.0.0. Lorem ipsum dolor sit amet,'.PHP_EOL + .' consectetur adipiscing elit. Fusce'.PHP_EOL + .' vel vestibulum nunc. Sed luctus'.PHP_EOL + .' dolor tortor, eu euismod purus'.PHP_EOL + .' pretium sed. Fusce egestas congue'.PHP_EOL + .' massa semper cursus. Donec quis'.PHP_EOL + .' pretium tellus. In lacinia, augue ut'.PHP_EOL + .' ornare porttitor, diam nunc faucibus'.PHP_EOL + .' purus, et accumsan eros sapien at'.PHP_EOL + .' sem. Sed pulvinar aliquam malesuada.'.PHP_EOL + .' Aliquam erat volutpat. Mauris'.PHP_EOL + .' gravida rutrum lectus at egestas.'.PHP_EOL + .' Fusce tempus elit in tincidunt'.PHP_EOL + .' dictum. Suspendisse dictum egestas'.PHP_EOL + .' sapien, eget ullamcorper metus'.PHP_EOL + .' elementum semper. Vestibulum sem'.PHP_EOL + .' justo, consectetur ac tincidunt et,'.PHP_EOL + .' finibus eget libero.'.PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but'.PHP_EOL + .'will stop working at some point in the'.PHP_EOL + .'future.'.PHP_EOL.PHP_EOL, + ], + 'Report width default: 80' => [ + 'reportWidth' => 80, + 'expectedOutput' => $summaryLine.str_repeat('-', 80).PHP_EOL + .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL + .' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL + .' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL + .' Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In'.PHP_EOL + .' lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan'.PHP_EOL + .' eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat.'.PHP_EOL + .' Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt'.PHP_EOL + .' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL + .' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL + .' libero.'.PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL + .'future.'.PHP_EOL.PHP_EOL, + ], + 'Report width matches longest line: 666; the message should not wrap' => [ + // Length = 4 padding + 75 base line + 587 custom message. + 'reportWidth' => 666, + 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL + .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' + .PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, + ], + 'Report width wide: 1000; delimiter line length should match longest line' => [ + 'reportWidth' => 1000, + 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL + .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' + .PHP_EOL.PHP_EOL + .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataReportWidthIsRespected() + + + /** + * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * + * Additionally, this test verifies that deprecated sniffs are still registered to run. + * + * @return void + */ + public function testDeprecatedSniffsAreListedAlphabetically() + { + // Set up the ruleset. + $standard = __DIR__.'/ShowSniffDeprecationsOrderTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '--no-colors']); + $ruleset = new Ruleset($config); + + $expected = 'WARNING: The SniffDeprecationTest standard uses 2 deprecated sniffs'.PHP_EOL; + $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; + $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL.PHP_EOL; + $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; + $expected .= 'future.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + $ruleset->showSniffDeprecations(); + + // Verify that the sniffs have been registered to run. + $this->assertCount(2, $ruleset->sniffCodes, 'Incorrect number of sniff codes registered'); + $this->assertArrayHasKey( + 'Fixtures.Deprecated.WithoutReplacement', + $ruleset->sniffCodes, + 'WithoutReplacement sniff not registered' + ); + $this->assertArrayHasKey( + 'Fixtures.Deprecated.WithReplacement', + $ruleset->sniffCodes, + 'WithReplacement sniff not registered' + ); + + }//end testDeprecatedSniffsAreListedAlphabetically() + + + /** + * Test that an exception is thrown when any of the interface required methods does not + * comply with the return type/value requirements. + * + * @param string $standard The standard to use for the test. + * @param string $exceptionMessage The contents of the expected exception message. + * + * @dataProvider dataExceptionIsThrownOnIncorrectlyImplementedInterface + * + * @return void + */ + public function testExceptionIsThrownOnIncorrectlyImplementedInterface($standard, $exceptionMessage) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($exceptionMessage); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMessage); + } + + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $ruleset->showSniffDeprecations(); + + }//end testExceptionIsThrownOnIncorrectlyImplementedInterface() + + + /** + * Data provider. + * + * @see testExceptionIsThrownOnIncorrectlyImplementedInterface() + * + * @return array> + */ + public static function dataExceptionIsThrownOnIncorrectlyImplementedInterface() + { + return [ + 'getDeprecationVersion() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidDeprecationVersionTest.xml', + 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', + ], + 'getRemovalVersion() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidRemovalVersionTest.xml', + 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', + ], + 'getDeprecationMessage() does not return a string' => [ + 'standard' => 'ShowSniffDeprecationsInvalidDeprecationMessageTest.xml', + 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', + ], + 'getDeprecationVersion() returns an empty string' => [ + 'standard' => 'ShowSniffDeprecationsEmptyDeprecationVersionTest.xml', + 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', + ], + 'getRemovalVersion() returns an empty string' => [ + 'standard' => 'ShowSniffDeprecationsEmptyRemovalVersionTest.xml', + 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', + ], + ]; + + }//end dataExceptionIsThrownOnIncorrectlyImplementedInterface() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml new file mode 100644 index 000000000..4c1dec220 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php index 20c28d60b..f074d9500 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php @@ -4,14 +4,19 @@ * * @author Greg Sherwood * @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Sniffs; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; -class AbstractArraySniffTest extends AbstractMethodUnitTest +/** + * Tests for the \PHP_CodeSniffer\Sniffs\AbstractArraySniff. + * + * @covers \PHP_CodeSniffer\Sniffs\AbstractArraySniff + */ +final class AbstractArraySniffTest extends AbstractMethodUnitTest { /** @@ -31,14 +36,16 @@ class AbstractArraySniffTest extends AbstractMethodUnitTest * The test case file for a unit test class has to be in the same directory * directory and use the same file name as the test class, using the .inc extension. * + * @beforeClass + * * @return void */ - public static function setUpBeforeClass() + public static function initializeFile() { self::$sniff = new AbstractArraySniffTestable(); - parent::setUpBeforeClass(); + parent::initializeFile(); - }//end setUpBeforeClass() + }//end initializeFile() /** diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php index a224012f2..751b01a8b 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTestable.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Sniffs; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php new file mode 100644 index 000000000..3225fe6fa --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php @@ -0,0 +1,124 @@ + + * @copyright 2018-2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHPUnit\Framework\TestCase; +use ReflectionProperty; + +abstract class AbstractTokenizerTestCase extends TestCase +{ + + /** + * The file extension of the test case file (without leading dot). + * + * This allows child classes to overrule the default `inc` with, for instance, + * `js` or `css` when applicable. + * + * @var string + */ + protected $fileExtension = 'inc'; + + /** + * The tab width setting to use when tokenizing the file. + * + * This allows for test case files to use a different tab width than the default. + * + * @var integer + */ + protected $tabWidth = 4; + + /** + * The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file. + * + * @var \PHP_CodeSniffer\Files\File + */ + protected $phpcsFile; + + + /** + * Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file. + * + * The test case file for a unit test class has to be in the same directory + * directory and use the same file name as the test class, using the .inc extension. + * + * @before + * + * @return void + */ + protected function initializeFile() + { + if (isset($this->phpcsFile) === false) { + $config = new ConfigDouble(); + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = $this->tabWidth; + + $ruleset = new Ruleset($config); + + // Default to a file with the same name as the test class. Extension is property based. + $relativeCN = str_replace(__NAMESPACE__, '', get_called_class()); + $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeCN); + $pathToTestFile = realpath(__DIR__).$relativePath.'.'.$this->fileExtension; + + // Make sure the file gets parsed correctly based on the file type. + $contents = 'phpcs_input_file: '.$pathToTestFile.PHP_EOL; + $contents .= file_get_contents($pathToTestFile); + + $this->phpcsFile = new DummyFile($contents, $ruleset, $config); + $this->phpcsFile->process(); + } + + }//end initializeFile() + + + /** + * Get the token pointer for a target token based on a specific comment found on the line before. + * + * Note: the test delimiter comment MUST start with "/* test" to allow this function to + * distinguish between comments used *in* a test and test delimiters. + * + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. + * + * @return int + */ + protected function getTargetToken($commentString, $tokenType, $tokenContent=null) + { + return AbstractMethodUnitTest::getTargetTokenFromFile($this->phpcsFile, $commentString, $tokenType, $tokenContent); + + }//end getTargetToken() + + + /** + * Clear the static "resolved tokens" cache property on the Tokenizer\PHP class. + * + * This method should be used selectively by tests to ensure the code under test is actually hit + * by the test testing the code. + * + * @return void + */ + public static function clearResolvedTokensCache() + { + $property = new ReflectionProperty('PHP_CodeSniffer\Tokenizers\PHP', 'resolveTokenCache'); + $property->setAccessible(true); + $property->setValue(null, []); + $property->setAccessible(false); + + }//end clearResolvedTokensCache() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc index 5867691c6..3ee1afd0d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc @@ -5,6 +5,11 @@ $anonClass = new class { function __construct() {} }; +/* testReadonlyNoParentheses */ +$anonClass = new readonly class { + function __construct() {} +}; + /* testNoParenthesesAndEmptyTokens */ $anonClass = new class // phpcs:ignore Standard.Cat { @@ -14,6 +19,11 @@ $anonClass = new class // phpcs:ignore Standard.Cat /* testWithParentheses */ $anonClass = new class() {}; +/* testReadonlyWithParentheses */ +$anonClass = new readonly class() { + function __construct() {} +}; + /* testWithParenthesesAndEmptyTokens */ $anonClass = new class /*comment */ () {}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php index a4bc49f9a..79eb742e1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest +final class AnonClassParenthesisOwnerTest extends AbstractTokenizerTestCase { @@ -27,7 +25,7 @@ class AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest */ public function testAnonClassNoParentheses($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); $this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass])); @@ -50,7 +48,7 @@ public function testAnonClassNoParentheses($testMarker) */ public function testAnonClassNoParenthesesNextOpenClose($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $function = $this->getTargetToken($testMarker, T_FUNCTION); $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); @@ -70,13 +68,20 @@ public function testAnonClassNoParenthesesNextOpenClose($testMarker) * @see testAnonClassNoParentheses() * @see testAnonClassNoParenthesesNextOpenClose() * - * @return array + * @return array> */ - public function dataAnonClassNoParentheses() + public static function dataAnonClassNoParentheses() { return [ - ['/* testNoParentheses */'], - ['/* testNoParenthesesAndEmptyTokens */'], + 'plain' => [ + 'testMarker' => '/* testNoParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyNoParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testNoParenthesesAndEmptyTokens */', + ], ]; }//end dataAnonClassNoParentheses() @@ -95,7 +100,7 @@ public function dataAnonClassNoParentheses() */ public function testAnonClassWithParentheses($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); @@ -129,13 +134,20 @@ public function testAnonClassWithParentheses($testMarker) * * @see testAnonClassWithParentheses() * - * @return array + * @return array> */ - public function dataAnonClassWithParentheses() + public static function dataAnonClassWithParentheses() { return [ - ['/* testWithParentheses */'], - ['/* testWithParenthesesAndEmptyTokens */'], + 'plain' => [ + 'testMarker' => '/* testWithParentheses */', + ], + 'readonly' => [ + 'testMarker' => '/* testReadonlyWithParentheses */', + ], + 'declaration contains comments and extra whitespace' => [ + 'testMarker' => '/* testWithParenthesesAndEmptyTokens */', + ], ]; }//end dataAnonClassWithParentheses() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc index ce5c553cf..ce211bda2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc @@ -21,10 +21,10 @@ $var = array( ); /* testFunctionDeclarationParamType */ -function foo(array $a) {} +function typedParam(array $a) {} /* testFunctionDeclarationReturnType */ -function foo($a) : int|array|null {} +function returnType($a) : int|array|null {} class Bar { /* testClassConst */ @@ -32,4 +32,10 @@ class Bar { /* testClassMethod */ public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; } diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php index 237258a62..f81706c33 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ArrayKeywordTest extends AbstractMethodUnitTest +final class ArrayKeywordTest extends AbstractTokenizerTestCase { @@ -29,7 +27,7 @@ class ArrayKeywordTest extends AbstractMethodUnitTest */ public function testArrayKeyword($testMarker, $testContent='array') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -49,19 +47,30 @@ public function testArrayKeyword($testMarker, $testContent='array') * * @see testArrayKeyword() * - * @return array + * @return array> */ - public function dataArrayKeyword() + public static function dataArrayKeyword() { return [ - 'empty array' => ['/* testEmptyArray */'], - 'array with space before parenthesis' => ['/* testArrayWithSpace */'], + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], 'array with comment before parenthesis' => [ - '/* testArrayWithComment */', - 'Array', + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', ], - 'nested: outer array' => ['/* testNestingArray */'], - 'nested: inner array' => ['/* testNestedArray */'], ]; }//end dataArrayKeyword() @@ -81,7 +90,7 @@ public function dataArrayKeyword() */ public function testArrayType($testMarker, $testContent='array') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -101,17 +110,27 @@ public function testArrayType($testMarker, $testContent='array') * * @see testArrayType() * - * @return array + * @return array> */ - public function dataArrayType() + public static function dataArrayType() { return [ 'closure return type' => [ - '/* testClosureReturnType */', - 'Array', + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', ], - 'function param type' => ['/* testFunctionDeclarationParamType */'], - 'function union return type' => ['/* testFunctionDeclarationReturnType */'], ]; }//end dataArrayType() @@ -132,7 +151,7 @@ public function dataArrayType() */ public function testNotArrayKeyword($testMarker, $testContent='array') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -152,16 +171,22 @@ public function testNotArrayKeyword($testMarker, $testContent='array') * * @see testNotArrayKeyword() * - * @return array + * @return array> */ - public function dataNotArrayKeyword() + public static function dataNotArrayKeyword() { return [ - 'class-constant-name' => [ - '/* testClassConst */', - 'ARRAY', + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', ], - 'class-method-name' => ['/* testClassMethod */'], ]; }//end dataNotArrayKeyword() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php index 8ac826f2f..764a9bef4 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php @@ -4,23 +4,21 @@ * * @author Alessandro Chitolina * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class AttributesTest extends AbstractMethodUnitTest +final class AttributesTest extends AbstractTokenizerTestCase { /** * Test that attributes are parsed correctly. * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. - * @param array $tokenCodes The codes of tokens inside the attributes. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $length The number of tokens between opener and closer. + * @param array $tokenCodes The codes of tokens inside the attributes. * * @dataProvider dataAttribute * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -31,7 +29,7 @@ class AttributesTest extends AbstractMethodUnitTest */ public function testAttribute($testMarker, $length, $tokenCodes) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); @@ -64,20 +62,22 @@ function ($token) use ($attribute, $length) { * * @see testAttribute() * - * @return array + * @return array>> */ - public function dataAttribute() + public static function dataAttribute() { return [ - [ - '/* testAttribute */', - 2, - [ T_STRING ], + 'class attribute' => [ + 'testMarker' => '/* testAttribute */', + 'length' => 2, + 'tokenCodes' => [ + T_STRING + ], ], - [ - '/* testAttributeWithParams */', - 7, - [ + 'class attribute with param' => [ + 'testMarker' => '/* testAttributeWithParams */', + 'length' => 7, + 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, T_STRING, @@ -86,10 +86,10 @@ public function dataAttribute() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testAttributeWithNamedParam */', - 10, - [ + 'class attribute with named param' => [ + 'testMarker' => '/* testAttributeWithNamedParam */', + 'length' => 10, + 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, T_PARAM_NAME, @@ -101,15 +101,17 @@ public function dataAttribute() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testAttributeOnFunction */', - 2, - [ T_STRING ], + 'function attribute' => [ + 'testMarker' => '/* testAttributeOnFunction */', + 'length' => 2, + 'tokenCodes' => [ + T_STRING + ], ], - [ - '/* testAttributeOnFunctionWithParams */', - 17, - [ + 'function attribute with params' => [ + 'testMarker' => '/* testAttributeOnFunctionWithParams */', + 'length' => 17, + 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, T_CONSTANT_ENCAPSED_STRING, @@ -128,10 +130,10 @@ public function dataAttribute() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testAttributeWithShortClosureParameter */', - 17, - [ + 'function attribute with arrow function as param' => [ + 'testMarker' => '/* testAttributeWithShortClosureParameter */', + 'length' => 17, + 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, T_STATIC, @@ -150,10 +152,10 @@ public function dataAttribute() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testAttributeGrouping */', - 26, - [ + 'function attribute; multiple comma separated classes' => [ + 'testMarker' => '/* testAttributeGrouping */', + 'length' => 26, + 'tokenCodes' => [ T_STRING, T_COMMA, T_WHITESPACE, @@ -181,10 +183,10 @@ public function dataAttribute() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testAttributeMultiline */', - 31, - [ + 'function attribute; multiple comma separated classes, one per line' => [ + 'testMarker' => '/* testAttributeMultiline */', + 'length' => 31, + 'tokenCodes' => [ T_WHITESPACE, T_WHITESPACE, T_STRING, @@ -217,10 +219,49 @@ public function dataAttribute() T_WHITESPACE, ], ], - [ - '/* testFqcnAttribute */', - 13, - [ + 'function attribute; multiple comma separated classes, one per line, with comments' => [ + 'testMarker' => '/* testAttributeMultilineWithComment */', + 'length' => 34, + 'tokenCodes' => [ + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_COMMA, + T_WHITESPACE, + T_COMMENT, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_COMMENT, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_PARENTHESIS, + T_COMMA, + T_WHITESPACE, + T_WHITESPACE, + T_STRING, + T_OPEN_PARENTHESIS, + T_CONSTANT_ENCAPSED_STRING, + T_COMMA, + T_WHITESPACE, + T_PARAM_NAME, + T_COLON, + T_WHITESPACE, + T_OPEN_SHORT_ARRAY, + T_CONSTANT_ENCAPSED_STRING, + T_WHITESPACE, + T_DOUBLE_ARROW, + T_WHITESPACE, + T_CONSTANT_ENCAPSED_STRING, + T_CLOSE_SHORT_ARRAY, + T_CLOSE_PARENTHESIS, + T_WHITESPACE, + ], + ], + 'function attribute; using partially qualified and fully qualified class names' => [ + 'testMarker' => '/* testFqcnAttribute */', + 'length' => 13, + 'tokenCodes' => [ T_STRING, T_NS_SEPARATOR, T_STRING, @@ -251,7 +292,7 @@ public function dataAttribute() */ public function testTwoAttributesOnTheSameLine() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $attribute = $this->getTargetToken('/* testTwoAttributeOnTheSameLine */', T_ATTRIBUTE); $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); @@ -275,7 +316,7 @@ public function testTwoAttributesOnTheSameLine() */ public function testAttributeAndLineComment() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $attribute = $this->getTargetToken('/* testAttributeAndCommentOnTheSameLine */', T_ATTRIBUTE); $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); @@ -290,10 +331,10 @@ public function testAttributeAndLineComment() /** * Test that attributes on function declaration parameters are parsed correctly. * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. - * @param int $length The number of tokens between opener and closer. - * @param array $tokenCodes The codes of tokens inside the attributes. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. + * @param int $length The number of tokens between opener and closer. + * @param array $tokenCodes The codes of tokens inside the attributes. * * @dataProvider dataAttributeOnParameters * @@ -305,7 +346,7 @@ public function testAttributeAndLineComment() */ public function testAttributeOnParameters($testMarker, $position, $length, array $tokenCodes) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $function = $this->getTargetToken($testMarker, T_FUNCTION); $attribute = ($function + $position); @@ -343,22 +384,24 @@ function ($token) use ($attribute, $length) { * * @see testAttributeOnParameters() * - * @return array + * @return array>> */ - public function dataAttributeOnParameters() + public static function dataAttributeOnParameters() { return [ - [ - '/* testSingleAttributeOnParameter */', - 4, - 2, - [T_STRING], + 'parameter attribute; single, inline' => [ + 'testMarker' => '/* testSingleAttributeOnParameter */', + 'position' => 4, + 'length' => 2, + 'tokenCodes' => [ + T_STRING + ], ], - [ - '/* testMultipleAttributesOnParameter */', - 4, - 10, - [ + 'parameter attribute; multiple comma separated, inline' => [ + 'testMarker' => '/* testMultipleAttributesOnParameter */', + 'position' => 4, + 'length' => 10, + 'tokenCodes' => [ T_STRING, T_COMMA, T_WHITESPACE, @@ -370,11 +413,11 @@ public function dataAttributeOnParameters() T_CLOSE_PARENTHESIS, ], ], - [ - '/* testMultilineAttributesOnParameter */', - 4, - 13, - [ + 'parameter attribute; single, multiline' => [ + 'testMarker' => '/* testMultilineAttributesOnParameter */', + 'position' => 4, + 'length' => 13, + 'tokenCodes' => [ T_WHITESPACE, T_WHITESPACE, T_STRING, @@ -397,10 +440,10 @@ public function dataAttributeOnParameters() /** * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly. * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. - * @param array $expectedTokensAttribute The codes of tokens inside the attributes. - * @param array $expectedTokensAfter The codes of tokens after the attributes. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $length The number of tokens between opener and closer. + * @param array> $expectedTokensAttribute The codes of tokens inside the attributes. + * @param array $expectedTokensAfter The codes of tokens after the attributes. * * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute * @@ -410,7 +453,7 @@ public function dataAttributeOnParameters() */ public function testAttributeContainingTextLookingLikeCloseTag($testMarker, $length, array $expectedTokensAttribute, array $expectedTokensAfter) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); @@ -449,15 +492,15 @@ public function testAttributeContainingTextLookingLikeCloseTag($testMarker, $len * * @see dataAttributeOnTextLookingLikeCloseTag() * - * @return array + * @return array>|array>> */ - public function dataAttributeOnTextLookingLikeCloseTag() + public static function dataAttributeOnTextLookingLikeCloseTag() { return [ - [ - '/* testAttributeContainingTextLookingLikeCloseTag */', - 5, - [ + 'function attribute; string param with "?>"' => [ + 'testMarker' => '/* testAttributeContainingTextLookingLikeCloseTag */', + 'length' => 5, + 'expectedTokensAttribute' => [ [ 'T_STRING', 'DeprecationReason', @@ -479,7 +522,7 @@ public function dataAttributeOnTextLookingLikeCloseTag() ']', ], ], - [ + 'expectedTokensAfter' => [ T_WHITESPACE, T_FUNCTION, T_WHITESPACE, @@ -491,10 +534,10 @@ public function dataAttributeOnTextLookingLikeCloseTag() T_CLOSE_CURLY_BRACKET, ], ], - [ - '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', - 8, - [ + 'function attribute; string param with "?>"; multiline' => [ + 'testMarker' => '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', + 'length' => 8, + 'expectedTokensAttribute' => [ [ 'T_STRING', 'DeprecationReason', @@ -528,7 +571,7 @@ public function dataAttributeOnTextLookingLikeCloseTag() ']', ], ], - [ + 'expectedTokensAfter' => [ T_WHITESPACE, T_FUNCTION, T_WHITESPACE, @@ -556,7 +599,7 @@ public function dataAttributeOnTextLookingLikeCloseTag() */ public function testInvalidAttribute() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $attribute = $this->getTargetToken('/* testInvalidAttribute */', T_ATTRIBUTE); @@ -572,12 +615,13 @@ public function testInvalidAttribute() * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize * @covers PHP_CodeSniffer\Tokenizers\PHP::findCloser * @covers PHP_CodeSniffer\Tokenizers\PHP::parsePhpAttribute + * @covers PHP_CodeSniffer\Tokenizers\PHP::createAttributesNestingMap * * @return void */ public function testNestedAttributes() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $tokenCodes = [ T_STRING, T_NS_SEPARATOR, diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc index 82bfe24fd..16624ecce 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc @@ -66,10 +66,6 @@ enum /* comment */ Name case SOME_CASE; } -enum /* testEnumUsedAsEnumName */ Enum -{ -} - /* testEnumUsedAsNamespaceName */ namespace Enum; /* testEnumUsedAsPartOfNamespaceName */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php index 33cff3a2c..3ce48f655 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php @@ -4,14 +4,12 @@ * * @author Jaroslav Hanslík * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillEnumTest extends AbstractMethodUnitTest +final class BackfillEnumTest extends AbstractTokenizerTestCase { @@ -30,21 +28,21 @@ class BackfillEnumTest extends AbstractMethodUnitTest */ public function testEnums($testMarker, $testContent, $openerOffset, $closerOffset) { - $tokens = self::$phpcsFile->getTokens(); - - $enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokens = $this->phpcsFile->getTokens(); + $enum = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$enum]; - $this->assertSame(T_ENUM, $tokens[$enum]['code']); - $this->assertSame('T_ENUM', $tokens[$enum]['type']); + $this->assertSame(T_ENUM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (code)'); + $this->assertSame('T_ENUM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM (type)'); - $this->assertArrayHasKey('scope_condition', $tokens[$enum]); - $this->assertArrayHasKey('scope_opener', $tokens[$enum]); - $this->assertArrayHasKey('scope_closer', $tokens[$enum]); + $this->assertArrayHasKey('scope_condition', $tokenArray); + $this->assertArrayHasKey('scope_opener', $tokenArray); + $this->assertArrayHasKey('scope_closer', $tokenArray); - $this->assertSame($enum, $tokens[$enum]['scope_condition']); + $this->assertSame($enum, $tokenArray['scope_condition']); - $scopeOpener = $tokens[$enum]['scope_opener']; - $scopeCloser = $tokens[$enum]['scope_closer']; + $scopeOpener = $tokenArray['scope_opener']; + $scopeCloser = $tokenArray['scope_closer']; $expectedScopeOpener = ($enum + $openerOffset); $expectedScopeCloser = ($enum + $closerOffset); @@ -73,52 +71,52 @@ public function testEnums($testMarker, $testContent, $openerOffset, $closerOffse * * @see testEnums() * - * @return array + * @return array> */ - public function dataEnums() + public static function dataEnums() { return [ - [ - '/* testPureEnum */', - 'enum', - 4, - 12, - ], - [ - '/* testBackedIntEnum */', - 'enum', - 7, - 29, - ], - [ - '/* testBackedStringEnum */', - 'enum', - 8, - 30, - ], - [ - '/* testComplexEnum */', - 'enum', - 11, - 72, - ], - [ - '/* testEnumWithEnumAsClassName */', - 'enum', - 6, - 7, - ], - [ - '/* testEnumIsCaseInsensitive */', - 'EnUm', - 4, - 5, - ], - [ - '/* testDeclarationContainingComment */', - 'enum', - 6, - 14, + 'enum - pure' => [ + 'testMarker' => '/* testPureEnum */', + 'testContent' => 'enum', + 'openerOffset' => 4, + 'closerOffset' => 12, + ], + 'enum - backed int' => [ + 'testMarker' => '/* testBackedIntEnum */', + 'testContent' => 'enum', + 'openerOffset' => 7, + 'closerOffset' => 29, + ], + 'enum - backed string' => [ + 'testMarker' => '/* testBackedStringEnum */', + 'testContent' => 'enum', + 'openerOffset' => 8, + 'closerOffset' => 30, + ], + 'enum - backed int + implements' => [ + 'testMarker' => '/* testComplexEnum */', + 'testContent' => 'enum', + 'openerOffset' => 11, + 'closerOffset' => 72, + ], + 'enum keyword when "enum" is the name for the construct (yes, this is allowed)' => [ + 'testMarker' => '/* testEnumWithEnumAsClassName */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 7, + ], + 'enum - keyword is case insensitive' => [ + 'testMarker' => '/* testEnumIsCaseInsensitive */', + 'testContent' => 'EnUm', + 'openerOffset' => 4, + 'closerOffset' => 5, + ], + 'enum - declaration containing comment' => [ + 'testMarker' => '/* testDeclarationContainingComment */', + 'testContent' => 'enum', + 'openerOffset' => 6, + 'closerOffset' => 14, ], ]; @@ -138,11 +136,12 @@ public function dataEnums() */ public function testNotEnums($testMarker, $testContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); + $tokenArray = $tokens[$target]; - $target = $this->getTargetToken($testMarker, [T_ENUM, T_STRING], $testContent); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testNotEnums() @@ -152,74 +151,70 @@ public function testNotEnums($testMarker, $testContent) * * @see testNotEnums() * - * @return array + * @return array> */ - public function dataNotEnums() + public static function dataNotEnums() { return [ - [ - '/* testEnumAsClassNameAfterEnumKeyword */', - 'Enum', - ], - [ - '/* testEnumUsedAsClassName */', - 'Enum', + 'not enum - construct named enum' => [ + 'testMarker' => '/* testEnumAsClassNameAfterEnumKeyword */', + 'testContent' => 'Enum', ], - [ - '/* testEnumUsedAsClassConstantName */', - 'ENUM', + 'not enum - class named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassName */', + 'testContent' => 'Enum', ], - [ - '/* testEnumUsedAsMethodName */', - 'enum', + 'not enum - class constant named enum' => [ + 'testMarker' => '/* testEnumUsedAsClassConstantName */', + 'testContent' => 'ENUM', ], - [ - '/* testEnumUsedAsPropertyName */', - 'enum', + 'not enum - method named enum' => [ + 'testMarker' => '/* testEnumUsedAsMethodName */', + 'testContent' => 'enum', ], - [ - '/* testEnumUsedAsFunctionName */', - 'enum', + 'not enum - class property named enum' => [ + 'testMarker' => '/* testEnumUsedAsPropertyName */', + 'testContent' => 'enum', ], - [ - '/* testEnumUsedAsEnumName */', - 'Enum', + 'not enum - global function named enum' => [ + 'testMarker' => '/* testEnumUsedAsFunctionName */', + 'testContent' => 'enum', ], - [ - '/* testEnumUsedAsNamespaceName */', - 'Enum', + 'not enum - namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsNamespaceName */', + 'testContent' => 'Enum', ], - [ - '/* testEnumUsedAsPartOfNamespaceName */', - 'Enum', + 'not enum - part of namespace named enum' => [ + 'testMarker' => '/* testEnumUsedAsPartOfNamespaceName */', + 'testContent' => 'Enum', ], - [ - '/* testEnumUsedInObjectInitialization */', - 'Enum', + 'not enum - class instantiation for class enum' => [ + 'testMarker' => '/* testEnumUsedInObjectInitialization */', + 'testContent' => 'Enum', ], - [ - '/* testEnumAsFunctionCall */', - 'enum', + 'not enum - function call' => [ + 'testMarker' => '/* testEnumAsFunctionCall */', + 'testContent' => 'enum', ], - [ - '/* testEnumAsFunctionCallWithNamespace */', - 'enum', + 'not enum - namespace relative function call' => [ + 'testMarker' => '/* testEnumAsFunctionCallWithNamespace */', + 'testContent' => 'enum', ], - [ - '/* testClassConstantFetchWithEnumAsClassName */', - 'Enum', + 'not enum - class constant fetch with enum as class name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsClassName */', + 'testContent' => 'Enum', ], - [ - '/* testClassConstantFetchWithEnumAsConstantName */', - 'ENUM', + 'not enum - class constant fetch with enum as constant name' => [ + 'testMarker' => '/* testClassConstantFetchWithEnumAsConstantName */', + 'testContent' => 'ENUM', ], - [ - '/* testParseErrorMissingName */', - 'enum', + 'parse error, not enum - enum declaration without name' => [ + 'testMarker' => '/* testParseErrorMissingName */', + 'testContent' => 'enum', ], - [ - '/* testParseErrorLiveCoding */', - 'enum', + 'parse error, not enum - enum declaration with curlies' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', + 'testContent' => 'enum', ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc index 154d48950..eb907ed39 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc @@ -26,3 +26,6 @@ $foo = 0o28_2; /* testInvalid6 */ $foo = 0o2_82; + +/* testInvalid7 */ +$foo = 0o; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php index e1c55bd93..609a54c00 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php @@ -4,14 +4,12 @@ * * @author Mark Baker * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillExplicitOctalNotationTest extends AbstractMethodUnitTest +final class BackfillExplicitOctalNotationTest extends AbstractTokenizerTestCase { @@ -30,7 +28,7 @@ class BackfillExplicitOctalNotationTest extends AbstractMethodUnitTest */ public function testExplicitOctalNotation($marker, $value, $nextToken, $nextContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $number = $this->getTargetToken($marker, [T_LNUMBER]); @@ -47,65 +45,71 @@ public function testExplicitOctalNotation($marker, $value, $nextToken, $nextCont * * @see testExplicitOctalNotation() * - * @return array + * @return array> */ - public function dataExplicitOctalNotation() + public static function dataExplicitOctalNotation() { return [ - [ + 'Explicit octal' => [ 'marker' => '/* testExplicitOctal */', 'value' => '0o137041', 'nextToken' => T_SEMICOLON, 'nextContent' => ';', ], - [ + 'Explicit octal - capitalized O' => [ 'marker' => '/* testExplicitOctalCapitalised */', 'value' => '0O137041', 'nextToken' => T_SEMICOLON, 'nextContent' => ';', ], - [ + 'Explicit octal - with numeric literal separator' => [ 'marker' => '/* testExplicitOctalWithNumericSeparator */', 'value' => '0o137_041', 'nextToken' => T_SEMICOLON, 'nextContent' => ';', ], - [ + 'Invalid explicit octal - numeric literal separator directly after "0o"' => [ 'marker' => '/* testInvalid1 */', 'value' => '0', 'nextToken' => T_STRING, 'nextContent' => 'o_137', ], - [ + 'Invalid explicit octal - numeric literal separator directly after "0O" (capitalized O)' => [ 'marker' => '/* testInvalid2 */', 'value' => '0', 'nextToken' => T_STRING, 'nextContent' => 'O_41', ], - [ + 'Invalid explicit octal - number out of octal range' => [ 'marker' => '/* testInvalid3 */', 'value' => '0', 'nextToken' => T_STRING, 'nextContent' => 'o91', ], - [ + 'Invalid explicit octal - part of the number out of octal range' => [ 'marker' => '/* testInvalid4 */', 'value' => '0O2', 'nextToken' => T_LNUMBER, 'nextContent' => '82', ], - [ + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator after' => [ 'marker' => '/* testInvalid5 */', 'value' => '0o2', 'nextToken' => T_LNUMBER, 'nextContent' => '8_2', ], - [ + 'Invalid explicit octal - part of the number out of octal range with numeric literal separator before' => [ 'marker' => '/* testInvalid6 */', 'value' => '0o2', 'nextToken' => T_STRING, 'nextContent' => '_82', ], + 'Invalid explicit octal - explicit notation without number' => [ + 'marker' => '/* testInvalid7 */', + 'value' => '0', + 'nextToken' => T_STRING, + 'nextContent' => 'o', + ], ]; }//end dataExplicitOctalNotation() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php index 4d0f4c064..8245b1875 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php @@ -4,14 +4,12 @@ * * @author Greg Sherwood * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillFnTokenTest extends AbstractMethodUnitTest +final class BackfillFnTokenTest extends AbstractTokenizerTestCase { @@ -106,7 +104,7 @@ public function testNestedOuter() */ public function testNestedInner() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken('/* testNestedInner */', T_FN); $this->backfillHelper($token, true); @@ -137,7 +135,7 @@ public function testNestedInner() */ public function testNestedSharedCloser() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken('/* testNestedSharedCloserOuter */', T_FN); $this->backfillHelper($token); @@ -380,7 +378,7 @@ public function testNamespaceOperatorInTypes() */ public function testKeywordReturnTypes() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $testMarkers = [ 'Self', @@ -453,7 +451,7 @@ public function testUnionReturnType() */ public function testTernary() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken('/* testTernary */', T_FN); $this->backfillHelper($token); @@ -505,7 +503,7 @@ public function testTernary() */ public function testTernaryWithTypes() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN); $this->backfillHelper($token); @@ -563,7 +561,7 @@ public function testWithMatchValueAndMore() */ public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $expectedCloserType, $expectedCloserFriendlyName) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, T_FN); $this->backfillHelper($token); @@ -579,38 +577,38 @@ public function testInMatchValue($testMarker, $openerOffset, $closerOffset, $exp * * @see testInMatchValue() * - * @return array + * @return array> */ - public function dataInMatchValue() + public static function dataInMatchValue() { return [ 'not_last_value' => [ - '/* testInMatchNotLastValue */', - 5, - 11, - 'T_COMMA', - 'comma', + 'testMarker' => '/* testInMatchNotLastValue */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', ], 'last_value_with_trailing_comma' => [ - '/* testInMatchLastValueWithTrailingComma */', - 5, - 11, - 'T_COMMA', - 'comma', + 'testMarker' => '/* testInMatchLastValueWithTrailingComma */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_COMMA', + 'expectedCloserFriendlyName' => 'comma', ], 'last_value_without_trailing_comma_1' => [ - '/* testInMatchLastValueNoTrailingComma1 */', - 5, - 10, - 'T_CLOSE_PARENTHESIS', - 'close parenthesis', + 'testMarker' => '/* testInMatchLastValueNoTrailingComma1 */', + 'openerOffset' => 5, + 'closerOffset' => 10, + 'expectedCloserType' => 'T_CLOSE_PARENTHESIS', + 'expectedCloserFriendlyName' => 'close parenthesis', ], 'last_value_without_trailing_comma_2' => [ - '/* testInMatchLastValueNoTrailingComma2 */', - 5, - 11, - 'T_VARIABLE', - '$y variable', + 'testMarker' => '/* testInMatchLastValueNoTrailingComma2 */', + 'openerOffset' => 5, + 'closerOffset' => 11, + 'expectedCloserType' => 'T_VARIABLE', + 'expectedCloserFriendlyName' => '$y variable', ], ]; @@ -647,7 +645,7 @@ public function testNestedInMethod() */ public function testNotAnArrowFunction($testMarker, $testContent='fn') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_STRING, T_FN], $testContent); $tokenArray = $tokens[$token]; @@ -669,47 +667,63 @@ public function testNotAnArrowFunction($testMarker, $testContent='fn') * * @see testNotAnArrowFunction() * - * @return array + * @return array> */ - public function dataNotAnArrowFunction() + public static function dataNotAnArrowFunction() { return [ - ['/* testFunctionName */'], - [ - '/* testConstantDeclaration */', - 'FN', + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testFunctionName */', + ], + 'name of a constant, context: declaration using "const" keyword - uppercase' => [ + 'testMarker' => '/* testConstantDeclaration */', + 'testContent' => 'FN', + ], + 'name of a constant, context: declaration using "const" keyword - lowercase' => [ + 'testMarker' => '/* testConstantDeclarationLower */', + 'testContent' => 'fn', + ], + 'name of a (static) method, context: declaration' => [ + 'testMarker' => '/* testStaticMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testPropertyAssignment */', + ], + 'name of a method, context: declaration in an anon class - mixed case' => [ + 'testMarker' => '/* testAnonClassMethodName */', + 'testContent' => 'fN', + ], + 'name of a method, context: static method call' => [ + 'testMarker' => '/* testNonArrowStaticMethodCall */', + ], + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testNonArrowConstantAccess */', + 'testContent' => 'FN', + ], + 'name of a constant, context: constant access - mixed case' => [ + 'testMarker' => '/* testNonArrowConstantAccessMixed */', + 'testContent' => 'Fn', ], - [ - '/* testConstantDeclarationLower */', - 'fn', + 'name of a method, context: method call on object - lowercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCall */', ], - ['/* testStaticMethodName */'], - ['/* testPropertyAssignment */'], - [ - '/* testAnonClassMethodName */', - 'fN', + 'name of a method, context: method call on object - uppercase' => [ + 'testMarker' => '/* testNonArrowObjectMethodCallUpper */', + 'testContent' => 'FN', ], - ['/* testNonArrowStaticMethodCall */'], - [ - '/* testNonArrowConstantAccess */', - 'FN', + 'name of a (namespaced) function, context: partially qualified function call' => [ + 'testMarker' => '/* testNonArrowNamespacedFunctionCall */', + 'testContent' => 'Fn', ], - [ - '/* testNonArrowConstantAccessMixed */', - 'Fn', + 'name of a (namespaced) function, context: namespace relative function call' => [ + 'testMarker' => '/* testNonArrowNamespaceOperatorFunctionCall */', ], - ['/* testNonArrowObjectMethodCall */'], - [ - '/* testNonArrowObjectMethodCallUpper */', - 'FN', + 'name of a function, context: declaration with union types for param and return' => [ + 'testMarker' => '/* testNonArrowFunctionNameWithUnionTypes */', ], - [ - '/* testNonArrowNamespacedFunctionCall */', - 'Fn', + 'unknown - live coding/parse error' => [ + 'testMarker' => '/* testLiveCoding */', ], - ['/* testNonArrowNamespaceOperatorFunctionCall */'], - ['/* testNonArrowFunctionNameWithUnionTypes */'], - ['/* testLiveCoding */'], ]; }//end dataNotAnArrowFunction() @@ -729,7 +743,7 @@ public function dataNotAnArrowFunction() */ private function backfillHelper($token, $skipScopeCloserCheck=false) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $this->assertTrue(array_key_exists('scope_condition', $tokens[$token]), 'Scope condition is not set'); $this->assertTrue(array_key_exists('scope_opener', $tokens[$token]), 'Scope opener is not set'); @@ -781,7 +795,7 @@ private function backfillHelper($token, $skipScopeCloserCheck=false) */ private function scopePositionTestHelper($token, $openerOffset, $closerOffset, $expectedCloserType='semicolon') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $expectedScopeOpener = ($token + $openerOffset); $expectedScopeCloser = ($token + $closerOffset); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php index 80f909acd..9f7df3540 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php @@ -5,15 +5,14 @@ * * @author Juliette Reinders Folmer * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class BackfillMatchTokenTest extends AbstractMethodUnitTest +final class BackfillMatchTokenTest extends AbstractTokenizerTestCase { @@ -32,7 +31,7 @@ class BackfillMatchTokenTest extends AbstractMethodUnitTest */ public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $testContent='match') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); $tokenArray = $tokens[$token]; @@ -51,147 +50,147 @@ public function testMatchExpression($testMarker, $openerOffset, $closerOffset, $ * * @see testMatchExpression() * - * @return array + * @return array> */ - public function dataMatchExpression() + public static function dataMatchExpression() { return [ 'simple_match' => [ - '/* testMatchSimple */', - 6, - 33, + 'testMarker' => '/* testMatchSimple */', + 'openerOffset' => 6, + 'closerOffset' => 33, ], 'no_trailing_comma' => [ - '/* testMatchNoTrailingComma */', - 6, - 24, + 'testMarker' => '/* testMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 24, ], 'with_default_case' => [ - '/* testMatchWithDefault */', - 6, - 33, + 'testMarker' => '/* testMatchWithDefault */', + 'openerOffset' => 6, + 'closerOffset' => 33, ], 'expression_in_condition' => [ - '/* testMatchExpressionInCondition */', - 6, - 77, + 'testMarker' => '/* testMatchExpressionInCondition */', + 'openerOffset' => 6, + 'closerOffset' => 77, ], 'multicase' => [ - '/* testMatchMultiCase */', - 6, - 40, + 'testMarker' => '/* testMatchMultiCase */', + 'openerOffset' => 6, + 'closerOffset' => 40, ], 'multicase_trailing_comma_in_case' => [ - '/* testMatchMultiCaseTrailingCommaInCase */', - 6, - 47, + 'testMarker' => '/* testMatchMultiCaseTrailingCommaInCase */', + 'openerOffset' => 6, + 'closerOffset' => 47, ], 'in_closure_not_lowercase' => [ - '/* testMatchInClosureNotLowercase */', - 6, - 36, - 'Match', + 'testMarker' => '/* testMatchInClosureNotLowercase */', + 'openerOffset' => 6, + 'closerOffset' => 36, + 'testContent' => 'Match', ], 'in_arrow_function' => [ - '/* testMatchInArrowFunction */', - 5, - 36, + 'testMarker' => '/* testMatchInArrowFunction */', + 'openerOffset' => 5, + 'closerOffset' => 36, ], 'arrow_function_in_match_no_trailing_comma' => [ - '/* testArrowFunctionInMatchNoTrailingComma */', - 6, - 44, + 'testMarker' => '/* testArrowFunctionInMatchNoTrailingComma */', + 'openerOffset' => 6, + 'closerOffset' => 44, ], 'in_function_call_param_not_lowercase' => [ - '/* testMatchInFunctionCallParamNotLowercase */', - 8, - 32, - 'MATCH', + 'testMarker' => '/* testMatchInFunctionCallParamNotLowercase */', + 'openerOffset' => 8, + 'closerOffset' => 32, + 'testContent' => 'MATCH', ], 'in_method_call_param' => [ - '/* testMatchInMethodCallParam */', - 5, - 13, + 'testMarker' => '/* testMatchInMethodCallParam */', + 'openerOffset' => 5, + 'closerOffset' => 13, ], 'discard_result' => [ - '/* testMatchDiscardResult */', - 6, - 18, + 'testMarker' => '/* testMatchDiscardResult */', + 'openerOffset' => 6, + 'closerOffset' => 18, ], 'duplicate_conditions_and_comments' => [ - '/* testMatchWithDuplicateConditionsWithComments */', - 12, - 59, + 'testMarker' => '/* testMatchWithDuplicateConditionsWithComments */', + 'openerOffset' => 12, + 'closerOffset' => 59, ], 'nested_match_outer' => [ - '/* testNestedMatchOuter */', - 6, - 33, + 'testMarker' => '/* testNestedMatchOuter */', + 'openerOffset' => 6, + 'closerOffset' => 33, ], 'nested_match_inner' => [ - '/* testNestedMatchInner */', - 6, - 14, + 'testMarker' => '/* testNestedMatchInner */', + 'openerOffset' => 6, + 'closerOffset' => 14, ], 'ternary_condition' => [ - '/* testMatchInTernaryCondition */', - 6, - 21, + 'testMarker' => '/* testMatchInTernaryCondition */', + 'openerOffset' => 6, + 'closerOffset' => 21, ], 'ternary_then' => [ - '/* testMatchInTernaryThen */', - 6, - 21, + 'testMarker' => '/* testMatchInTernaryThen */', + 'openerOffset' => 6, + 'closerOffset' => 21, ], 'ternary_else' => [ - '/* testMatchInTernaryElse */', - 6, - 21, + 'testMarker' => '/* testMatchInTernaryElse */', + 'openerOffset' => 6, + 'closerOffset' => 21, ], 'array_value' => [ - '/* testMatchInArrayValue */', - 6, - 21, + 'testMarker' => '/* testMatchInArrayValue */', + 'openerOffset' => 6, + 'closerOffset' => 21, ], 'array_key' => [ - '/* testMatchInArrayKey */', - 6, - 21, + 'testMarker' => '/* testMatchInArrayKey */', + 'openerOffset' => 6, + 'closerOffset' => 21, ], 'returning_array' => [ - '/* testMatchreturningArray */', - 6, - 125, + 'testMarker' => '/* testMatchreturningArray */', + 'openerOffset' => 6, + 'closerOffset' => 125, ], 'nested_in_switch_case_1' => [ - '/* testMatchWithDefaultNestedInSwitchCase1 */', - 6, - 25, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 6, + 'closerOffset' => 25, ], 'nested_in_switch_case_2' => [ - '/* testMatchWithDefaultNestedInSwitchCase2 */', - 6, - 25, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 6, + 'closerOffset' => 25, ], 'nested_in_switch_default' => [ - '/* testMatchWithDefaultNestedInSwitchDefault */', - 6, - 25, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 6, + 'closerOffset' => 25, ], 'match_with_nested_switch' => [ - '/* testMatchContainingSwitch */', - 6, - 180, + 'testMarker' => '/* testMatchContainingSwitch */', + 'openerOffset' => 6, + 'closerOffset' => 180, ], 'no_cases' => [ - '/* testMatchNoCases */', - 6, - 7, + 'testMarker' => '/* testMatchNoCases */', + 'openerOffset' => 6, + 'closerOffset' => 7, ], 'multi_default' => [ - '/* testMatchMultiDefault */', - 6, - 40, + 'testMarker' => '/* testMatchMultiDefault */', + 'openerOffset' => 6, + 'closerOffset' => 40, ], ]; @@ -213,7 +212,7 @@ public function dataMatchExpression() */ public function testNotAMatchStructure($testMarker, $testContent='match') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_STRING, T_MATCH], $testContent); $tokenArray = $tokens[$token]; @@ -228,7 +227,7 @@ public function testNotAMatchStructure($testMarker, $testContent='match') $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - $next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true); + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($token + 1), null, true); if ($next !== false && $tokens[$next]['code'] === T_OPEN_PARENTHESIS) { $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set for opener after'); } @@ -241,76 +240,102 @@ public function testNotAMatchStructure($testMarker, $testContent='match') * * @see testNotAMatchStructure() * - * @return array + * @return array> */ - public function dataNotAMatchStructure() + public static function dataNotAMatchStructure() { return [ - 'static_method_call' => ['/* testNoMatchStaticMethodCall */'], + 'static_method_call' => [ + 'testMarker' => '/* testNoMatchStaticMethodCall */', + ], 'class_constant_access' => [ - '/* testNoMatchClassConstantAccess */', - 'MATCH', + 'testMarker' => '/* testNoMatchClassConstantAccess */', + 'testContent' => 'MATCH', ], 'class_constant_array_access' => [ - '/* testNoMatchClassConstantArrayAccessMixedCase */', - 'Match', + 'testMarker' => '/* testNoMatchClassConstantArrayAccessMixedCase */', + 'testContent' => 'Match', + ], + 'method_call' => [ + 'testMarker' => '/* testNoMatchMethodCall */', ], - 'method_call' => ['/* testNoMatchMethodCall */'], 'method_call_uppercase' => [ - '/* testNoMatchMethodCallUpper */', - 'MATCH', - ], - 'property_access' => ['/* testNoMatchPropertyAccess */'], - 'namespaced_function_call' => ['/* testNoMatchNamespacedFunctionCall */'], - 'namespace_operator_function_call' => ['/* testNoMatchNamespaceOperatorFunctionCall */'], - 'interface_method_declaration' => ['/* testNoMatchInterfaceMethodDeclaration */'], - 'class_constant_declaration' => ['/* testNoMatchClassConstantDeclarationLower */'], - 'class_method_declaration' => ['/* testNoMatchClassMethodDeclaration */'], - 'property_assigment' => ['/* testNoMatchPropertyAssignment */'], + 'testMarker' => '/* testNoMatchMethodCallUpper */', + 'testContent' => 'MATCH', + ], + 'property_access' => [ + 'testMarker' => '/* testNoMatchPropertyAccess */', + ], + 'namespaced_function_call' => [ + 'testMarker' => '/* testNoMatchNamespacedFunctionCall */', + ], + 'namespace_operator_function_call' => [ + 'testMarker' => '/* testNoMatchNamespaceOperatorFunctionCall */', + ], + 'interface_method_declaration' => [ + 'testMarker' => '/* testNoMatchInterfaceMethodDeclaration */', + ], + 'class_constant_declaration' => [ + 'testMarker' => '/* testNoMatchClassConstantDeclarationLower */', + ], + 'class_method_declaration' => [ + 'testMarker' => '/* testNoMatchClassMethodDeclaration */', + ], + 'property_assigment' => [ + 'testMarker' => '/* testNoMatchPropertyAssignment */', + ], 'class_instantiation' => [ - '/* testNoMatchClassInstantiation */', - 'Match', + 'testMarker' => '/* testNoMatchClassInstantiation */', + 'testContent' => 'Match', ], 'anon_class_method_declaration' => [ - '/* testNoMatchAnonClassMethodDeclaration */', - 'maTCH', + 'testMarker' => '/* testNoMatchAnonClassMethodDeclaration */', + 'testContent' => 'maTCH', ], 'class_declaration' => [ - '/* testNoMatchClassDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchClassDeclaration */', + 'testContent' => 'Match', ], 'interface_declaration' => [ - '/* testNoMatchInterfaceDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchInterfaceDeclaration */', + 'testContent' => 'Match', ], 'trait_declaration' => [ - '/* testNoMatchTraitDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchTraitDeclaration */', + 'testContent' => 'Match', ], 'constant_declaration' => [ - '/* testNoMatchConstantDeclaration */', - 'MATCH', + 'testMarker' => '/* testNoMatchConstantDeclaration */', + 'testContent' => 'MATCH', + ], + 'function_declaration' => [ + 'testMarker' => '/* testNoMatchFunctionDeclaration */', ], - 'function_declaration' => ['/* testNoMatchFunctionDeclaration */'], 'namespace_declaration' => [ - '/* testNoMatchNamespaceDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchNamespaceDeclaration */', + 'testContent' => 'Match', ], 'class_extends_declaration' => [ - '/* testNoMatchExtendedClassDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchExtendedClassDeclaration */', + 'testContent' => 'Match', ], 'class_implements_declaration' => [ - '/* testNoMatchImplementedClassDeclaration */', - 'Match', + 'testMarker' => '/* testNoMatchImplementedClassDeclaration */', + 'testContent' => 'Match', ], 'use_statement' => [ - '/* testNoMatchInUseStatement */', - 'Match', + 'testMarker' => '/* testNoMatchInUseStatement */', + 'testContent' => 'Match', + ], + 'unsupported_inline_control_structure' => [ + 'testMarker' => '/* testNoMatchMissingCurlies */', + ], + 'unsupported_alternative_syntax' => [ + 'testMarker' => '/* testNoMatchAlternativeSyntax */', + ], + 'live_coding' => [ + 'testMarker' => '/* testLiveCoding */', ], - 'unsupported_inline_control_structure' => ['/* testNoMatchMissingCurlies */'], - 'unsupported_alternative_syntax' => ['/* testNoMatchAlternativeSyntax */'], - 'live_coding' => ['/* testLiveCoding */'], ]; }//end dataNotAMatchStructure() @@ -344,25 +369,25 @@ public function testSwitchExpression($testMarker, $openerOffset, $closerOffset) * * @see testSwitchExpression() * - * @return array + * @return array> */ - public function dataSwitchExpression() + public static function dataSwitchExpression() { return [ 'switch_containing_match' => [ - '/* testSwitchContainingMatch */', - 6, - 174, + 'testMarker' => '/* testSwitchContainingMatch */', + 'openerOffset' => 6, + 'closerOffset' => 174, ], 'match_containing_switch_1' => [ - '/* testSwitchNestedInMatch1 */', - 5, - 63, + 'testMarker' => '/* testSwitchNestedInMatch1 */', + 'openerOffset' => 5, + 'closerOffset' => 63, ], 'match_containing_switch_2' => [ - '/* testSwitchNestedInMatch2 */', - 5, - 63, + 'testMarker' => '/* testSwitchNestedInMatch2 */', + 'openerOffset' => 5, + 'closerOffset' => 63, ], ]; @@ -397,35 +422,35 @@ public function testSwitchCaseVersusMatch($testMarker, $openerOffset, $closerOff * * @see testSwitchCaseVersusMatch() * - * @return array + * @return array> */ - public function dataSwitchCaseVersusMatch() + public static function dataSwitchCaseVersusMatch() { return [ 'switch_with_nested_match_case_1' => [ - '/* testMatchWithDefaultNestedInSwitchCase1 */', - 3, - 55, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase1 */', + 'openerOffset' => 3, + 'closerOffset' => 55, ], 'switch_with_nested_match_case_2' => [ - '/* testMatchWithDefaultNestedInSwitchCase2 */', - 4, - 21, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchCase2 */', + 'openerOffset' => 4, + 'closerOffset' => 21, ], 'switch_with_nested_match_default_case' => [ - '/* testMatchWithDefaultNestedInSwitchDefault */', - 1, - 38, + 'testMarker' => '/* testMatchWithDefaultNestedInSwitchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 38, ], 'match_with_nested_switch_case' => [ - '/* testSwitchDefaultNestedInMatchCase */', - 1, - 18, + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerOffset' => 1, + 'closerOffset' => 18, ], 'match_with_nested_switch_default_case' => [ - '/* testSwitchDefaultNestedInMatchDefault */', - 1, - 20, + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 20, ], ]; @@ -451,7 +476,7 @@ public function dataSwitchCaseVersusMatch() */ private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScopeCloserCheck=false) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $tokenArray = $tokens[$token]; $tokenType = $tokenArray['type']; $expectedScopeOpener = ($token + $openerOffset); @@ -506,7 +531,7 @@ private function scopeTestHelper($token, $openerOffset, $closerOffset, $skipScop */ private function parenthesisTestHelper($token) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $tokenArray = $tokens[$token]; $tokenType = $tokenArray['type']; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php index 645088fd6..b27dd8a05 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php @@ -4,35 +4,38 @@ * * @author Greg Sherwood * @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; -class BackfillNumericSeparatorTest extends AbstractMethodUnitTest +final class BackfillNumericSeparatorTest extends AbstractTokenizerTestCase { /** * Test that numbers using numeric separators are tokenized correctly. * - * @param array $testData The data required for the specific test case. + * @param string $marker The comment which prefaces the target token in the test file. + * @param string $type The expected token type. + * @param string $value The expected token content. * * @dataProvider dataTestBackfill * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize * * @return void */ - public function testBackfill($testData) + public function testBackfill($marker, $type, $value) { - $tokens = self::$phpcsFile->getTokens(); - $number = $this->getTargetToken($testData['marker'], [T_LNUMBER, T_DNUMBER]); + $tokens = $this->phpcsFile->getTokens(); + $number = $this->getTargetToken($marker, [T_LNUMBER, T_DNUMBER]); + $tokenArray = $tokens[$number]; - $this->assertSame(constant($testData['type']), $tokens[$number]['code']); - $this->assertSame($testData['type'], $tokens[$number]['type']); - $this->assertSame($testData['value'], $tokens[$number]['content']); + $this->assertSame(constant($type), $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (code)'); + $this->assertSame($type, $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not '.$type.' (type)'); + $this->assertSame($value, $tokenArray['content']); }//end testBackfill() @@ -42,9 +45,9 @@ public function testBackfill($testData) * * @see testBackfill() * - * @return array + * @return array> */ - public function dataTestBackfill() + public static function dataTestBackfill() { $testHexType = 'T_LNUMBER'; if (PHP_INT_MAX < 0xCAFEF00D) { @@ -62,96 +65,70 @@ public function dataTestBackfill() } return [ - [ - [ - 'marker' => '/* testSimpleLNumber */', - 'type' => 'T_LNUMBER', - 'value' => '1_000_000_000', - ], + 'decimal integer' => [ + 'marker' => '/* testSimpleLNumber */', + 'type' => 'T_LNUMBER', + 'value' => '1_000_000_000', ], - [ - [ - 'marker' => '/* testSimpleDNumber */', - 'type' => 'T_DNUMBER', - 'value' => '107_925_284.88', - ], + 'float' => [ + 'marker' => '/* testSimpleDNumber */', + 'type' => 'T_DNUMBER', + 'value' => '107_925_284.88', ], - [ - [ - 'marker' => '/* testFloat */', - 'type' => 'T_DNUMBER', - 'value' => '6.674_083e-11', - ], + 'float, scientific notation, negative exponent with sigh' => [ + 'marker' => '/* testFloat */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e-11', ], - [ - [ - 'marker' => '/* testFloat2 */', - 'type' => 'T_DNUMBER', - 'value' => '6.674_083e+11', - ], + 'float, scientific notation, positive exponent with sign' => [ + 'marker' => '/* testFloat2 */', + 'type' => 'T_DNUMBER', + 'value' => '6.674_083e+11', ], - [ - [ - 'marker' => '/* testFloat3 */', - 'type' => 'T_DNUMBER', - 'value' => '1_2.3_4e1_23', - ], + 'float, scientific notation, positive exponent without sign' => [ + 'marker' => '/* testFloat3 */', + 'type' => 'T_DNUMBER', + 'value' => '1_2.3_4e1_23', ], - [ - [ - 'marker' => '/* testHex */', - 'type' => $testHexType, - 'value' => '0xCAFE_F00D', - ], + 'hexidecimal integer/float' => [ + 'marker' => '/* testHex */', + 'type' => $testHexType, + 'value' => '0xCAFE_F00D', ], - [ - [ - 'marker' => '/* testHexMultiple */', - 'type' => $testHexMultipleType, - 'value' => '0x42_72_6F_77_6E', - ], + 'hexidecimal integer/float with multiple underscores' => [ + 'marker' => '/* testHexMultiple */', + 'type' => $testHexMultipleType, + 'value' => '0x42_72_6F_77_6E', ], - [ - [ - 'marker' => '/* testHexInt */', - 'type' => 'T_LNUMBER', - 'value' => '0x42_72_6F', - ], + 'hexidecimal integer' => [ + 'marker' => '/* testHexInt */', + 'type' => 'T_LNUMBER', + 'value' => '0x42_72_6F', ], - [ - [ - 'marker' => '/* testBinary */', - 'type' => 'T_LNUMBER', - 'value' => '0b0101_1111', - ], + 'binary integer' => [ + 'marker' => '/* testBinary */', + 'type' => 'T_LNUMBER', + 'value' => '0b0101_1111', ], - [ - [ - 'marker' => '/* testOctal */', - 'type' => 'T_LNUMBER', - 'value' => '0137_041', - ], + 'octal integer' => [ + 'marker' => '/* testOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0137_041', ], - [ - [ - 'marker' => '/* testExplicitOctal */', - 'type' => 'T_LNUMBER', - 'value' => '0o137_041', - ], + 'octal integer using explicit octal notation' => [ + 'marker' => '/* testExplicitOctal */', + 'type' => 'T_LNUMBER', + 'value' => '0o137_041', ], - [ - [ - 'marker' => '/* testExplicitOctalCapitalised */', - 'type' => 'T_LNUMBER', - 'value' => '0O137_041', - ], + 'octal integer using explicit octal notation with capital O' => [ + 'marker' => '/* testExplicitOctalCapitalised */', + 'type' => 'T_LNUMBER', + 'value' => '0O137_041', ], - [ - [ - 'marker' => '/* testIntMoreThanMax */', - 'type' => $testIntMoreThanMaxType, - 'value' => '10_223_372_036_854_775_807', - ], + 'integer more than PHP_INT_MAX becomes a float' => [ + 'marker' => '/* testIntMoreThanMax */', + 'type' => $testIntMoreThanMaxType, + 'value' => '10_223_372_036_854_775_807', ], ]; @@ -162,8 +139,8 @@ public function dataTestBackfill() * Test that numbers using numeric separators which are considered parse errors and/or * which aren't relevant to the backfill, do not incorrectly trigger the backfill anyway. * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param array $expectedTokens The token type and content of the expected token sequence. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The token type and content of the expected token sequence. * * @dataProvider dataNoBackfill * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -172,12 +149,16 @@ public function dataTestBackfill() */ public function testNoBackfill($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $number = $this->getTargetToken($testMarker, [T_LNUMBER, T_DNUMBER]); foreach ($expectedTokens as $key => $expectedToken) { $i = ($number + $key); - $this->assertSame($expectedToken['code'], $tokens[$i]['code']); + $this->assertSame( + $expectedToken['code'], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($expectedToken['code']) + ); $this->assertSame($expectedToken['content'], $tokens[$i]['content']); } @@ -189,14 +170,14 @@ public function testNoBackfill($testMarker, $expectedTokens) * * @see testBackfill() * - * @return array + * @return array>>> */ - public function dataNoBackfill() + public static function dataNoBackfill() { return [ - [ - '/* testInvalid1 */', - [ + 'invalid: trailing underscore' => [ + 'testMarker' => '/* testInvalid1 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '100', @@ -207,9 +188,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid2 */', - [ + 'invalid: two consecutive underscores' => [ + 'testMarker' => '/* testInvalid2 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '1', @@ -220,9 +201,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid3 */', - [ + 'invalid: underscore directly before decimal point' => [ + 'testMarker' => '/* testInvalid3 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '1', @@ -237,9 +218,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid4 */', - [ + 'invalid: underscore directly after decimal point' => [ + 'testMarker' => '/* testInvalid4 */', + 'expectedTokens' => [ [ 'code' => T_DNUMBER, 'content' => '1.', @@ -250,9 +231,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid5 */', - [ + 'invalid: hex int - underscore directly after x' => [ + 'testMarker' => '/* testInvalid5 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '0', @@ -263,9 +244,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid6 */', - [ + 'invalid: binary int - underscore directly after b' => [ + 'testMarker' => '/* testInvalid6 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '0', @@ -276,9 +257,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid7 */', - [ + 'invalid: scientific float - underscore directly before e' => [ + 'testMarker' => '/* testInvalid7 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '1', @@ -289,9 +270,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid8 */', - [ + 'invalid: scientific float - underscore directly after e' => [ + 'testMarker' => '/* testInvalid8 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '1', @@ -302,9 +283,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid9 */', - [ + 'invalid: space between parts of the number' => [ + 'testMarker' => '/* testInvalid9 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '107_925_284', @@ -319,9 +300,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid10 */', - [ + 'invalid: comment within the number' => [ + 'testMarker' => '/* testInvalid10 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '107_925_284', @@ -336,9 +317,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid11 */', - [ + 'invalid: explicit octal int - underscore directly after o' => [ + 'testMarker' => '/* testInvalid11 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '0', @@ -349,9 +330,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testInvalid12 */', - [ + 'invalid: explicit octal int - underscore directly after capital O' => [ + 'testMarker' => '/* testInvalid12 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '0', @@ -362,9 +343,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* testCalc1 */', - [ + 'calculations should be untouched - int - int' => [ + 'testMarker' => '/* testCalc1 */', + 'expectedTokens' => [ [ 'code' => T_LNUMBER, 'content' => '667_083', @@ -387,9 +368,9 @@ public function dataNoBackfill() ], ], ], - [ - '/* test Calc2 */', - [ + 'calculations should be untouched - scientific float + int' => [ + 'testMarker' => '/* test Calc2 */', + 'expectedTokens' => [ [ 'code' => T_DNUMBER, 'content' => '6.674_08e3', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc index eaf0b4b3c..eb36e3870 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc @@ -49,9 +49,7 @@ class Foo public ReAdOnLy string $caseInsensitiveProperty; /* testReadonlyConstructorPropertyPromotion */ - public function __construct(private readonly bool $constructorPropertyPromotion) - { - } + public function __construct(private readonly bool $constructorPropertyPromotion) {} /* testReadonlyConstructorPropertyPromotionWithReference */ public function __construct(private ReadOnly bool &$constructorPropertyPromotion) {} @@ -68,8 +66,6 @@ class ClassName { /* testReadonlyUsedAsMethodName */ public function readonly() { - // Do something. - /* testReadonlyUsedAsPropertyName */ $this->readonly = 'foo'; @@ -79,9 +75,10 @@ class ClassName { } /* testReadonlyUsedAsFunctionName */ -function readonly() -{ -} +function readonly() {} + +/* testReadonlyUsedAsFunctionNameWithReturnByRef */ +function &readonly() {} /* testReadonlyUsedAsNamespaceName */ namespace Readonly; @@ -89,12 +86,71 @@ namespace Readonly; namespace My\Readonly\Collection; /* testReadonlyAsFunctionCall */ $var = readonly($a, $b); +/* testReadonlyAsNamespacedFunctionCall */ +$var = My\NS\readonly($a, $b); +/* testReadonlyAsNamespaceRelativeFunctionCall */ +$var = namespace\ReadOnly($a, $b); +/* testReadonlyAsMethodCall */ +$var = $obj->readonly($a, $b); +/* testReadonlyAsNullsafeMethodCall */ +$var = $obj?->readOnly($a, $b); +/* testReadonlyAsStaticMethodCallWithSpace */ +$var = ClassName::readonly ($a, $b); /* testClassConstantFetchWithReadonlyAsConstantName */ echo ClassName::READONLY; /* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */ $var = readonly /* comment */ (); +// These test cases are inspired by +// https://github.com/php/php-src/commit/08b75395838b4b42a41e3c70684fa6c6b113eee0 +class ReadonlyWithDisjunctiveNormalForm +{ + /* testReadonlyPropertyDNFTypeUnqualified */ + readonly (B&C)|A $h; + + /* testReadonlyPropertyDNFTypeFullyQualified */ + public readonly (\Fully\Qualified\B&\Full\C)|\Foo\Bar $j; + + /* testReadonlyPropertyDNFTypePartiallyQualified */ + protected readonly (Partially\Qualified&C)|A $l; + + /* testReadonlyPropertyDNFTypeRelativeName */ + private readonly (namespace\Relative&C)|A $n; + + /* testReadonlyPropertyDNFTypeMultipleSets */ + private readonly (A&C)|(B&C)|(C&D) $m; + + /* testReadonlyPropertyDNFTypeWithArray */ + private readonly (B & C)|array $o; + + /* testReadonlyPropertyDNFTypeWithSpacesAndComments */ + private readonly ( B & C /*something*/) | A $q; + + public function __construct( + /* testReadonlyConstructorPropertyPromotionWithDNF */ + private readonly (B&C)|A $b1, + /* testReadonlyConstructorPropertyPromotionWithDNFAndReference */ + readonly (B&C)|A &$b2, + ) {} + + /* testReadonlyUsedAsMethodNameWithDNFParam */ + public function readonly (A&B $param): void {} +} + +/* testReadonlyAnonClassWithParens */ +$anon = new readonly class() {}; + +/* testReadonlyAnonClassWithoutParens */ +$anon = new Readonly class {}; + +/* testReadonlyAnonClassWithCommentsAndWhitespace */ +$anon = new +// comment +READONLY +// phpcs:ignore Stnd.Cat.Sniff +class {}; + /* testParseErrorLiveCoding */ // This must be the last test in the file. readonly diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php index dddc18ebc..0befb47b7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php @@ -4,14 +4,12 @@ * * @author Jaroslav Hanslík * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BackfillReadonlyTest extends AbstractMethodUnitTest +final class BackfillReadonlyTest extends AbstractTokenizerTestCase { @@ -19,20 +17,22 @@ class BackfillReadonlyTest extends AbstractMethodUnitTest * Test that the "readonly" keyword is tokenized as such. * * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". * * @dataProvider dataReadonly * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testReadonly($testMarker, $testContent) + public function testReadonly($testMarker, $testContent='readonly') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; - $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); - $this->assertSame(T_READONLY, $tokens[$target]['code']); - $this->assertSame('T_READONLY', $tokens[$target]['type']); + $this->assertSame(T_READONLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (code)'); + $this->assertSame('T_READONLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_READONLY (type)'); }//end testReadonly() @@ -42,118 +42,128 @@ public function testReadonly($testMarker, $testContent) * * @see testReadonly() * - * @return array + * @return array> */ - public function dataReadonly() + public static function dataReadonly() { return [ - [ - '/* testReadonlyProperty */', - 'readonly', + 'property declaration, no visibility' => [ + 'testMarker' => '/* testReadonlyProperty */', + ], + 'property declaration, var keyword before' => [ + 'testMarker' => '/* testVarReadonlyProperty */', + ], + 'property declaration, var keyword after' => [ + 'testMarker' => '/* testReadonlyVarProperty */', + ], + 'property declaration, static before' => [ + 'testMarker' => '/* testStaticReadonlyProperty */', + ], + 'property declaration, static after' => [ + 'testMarker' => '/* testReadonlyStaticProperty */', + ], + 'constant declaration, with visibility' => [ + 'testMarker' => '/* testConstReadonlyProperty */', + ], + 'property declaration, missing type' => [ + 'testMarker' => '/* testReadonlyPropertyWithoutType */', + ], + 'property declaration, public before' => [ + 'testMarker' => '/* testPublicReadonlyProperty */', + ], + 'property declaration, protected before' => [ + 'testMarker' => '/* testProtectedReadonlyProperty */', + ], + 'property declaration, private before' => [ + 'testMarker' => '/* testPrivateReadonlyProperty */', ], - [ - '/* testVarReadonlyProperty */', - 'readonly', + 'property declaration, public after' => [ + 'testMarker' => '/* testPublicReadonlyPropertyWithReadonlyFirst */', ], - [ - '/* testReadonlyVarProperty */', - 'readonly', + 'property declaration, protected after' => [ + 'testMarker' => '/* testProtectedReadonlyPropertyWithReadonlyFirst */', ], - [ - '/* testStaticReadonlyProperty */', - 'readonly', + 'property declaration, private after' => [ + 'testMarker' => '/* testPrivateReadonlyPropertyWithReadonlyFirst */', ], - [ - '/* testReadonlyStaticProperty */', - 'readonly', + 'property declaration, private before, comments in declaration' => [ + 'testMarker' => '/* testReadonlyWithCommentsInDeclaration */', ], - [ - '/* testConstReadonlyProperty */', - 'readonly', + 'property declaration, private before, nullable type' => [ + 'testMarker' => '/* testReadonlyWithNullableProperty */', ], - [ - '/* testReadonlyPropertyWithoutType */', - 'readonly', + 'property declaration, private before, union type, null first' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */', ], - [ - '/* testPublicReadonlyProperty */', - 'readonly', + 'property declaration, private before, union type, null last' => [ + 'testMarker' => '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */', ], - [ - '/* testProtectedReadonlyProperty */', - 'readonly', + 'property declaration, private before, array type' => [ + 'testMarker' => '/* testReadonlyPropertyWithArrayTypeHint */', ], - [ - '/* testPrivateReadonlyProperty */', - 'readonly', + 'property declaration, private before, self type' => [ + 'testMarker' => '/* testReadonlyPropertyWithSelfTypeHint */', ], - [ - '/* testPublicReadonlyPropertyWithReadonlyFirst */', - 'readonly', + 'property declaration, private before, parent type' => [ + 'testMarker' => '/* testReadonlyPropertyWithParentTypeHint */', ], - [ - '/* testProtectedReadonlyPropertyWithReadonlyFirst */', - 'readonly', + 'property declaration, private before, FQN type' => [ + 'testMarker' => '/* testReadonlyPropertyWithFullyQualifiedTypeHint */', ], - [ - '/* testPrivateReadonlyPropertyWithReadonlyFirst */', - 'readonly', + 'property declaration, public before, mixed case' => [ + 'testMarker' => '/* testReadonlyIsCaseInsensitive */', + 'testContent' => 'ReAdOnLy', ], - [ - '/* testReadonlyWithCommentsInDeclaration */', - 'readonly', + 'property declaration, constructor property promotion' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotion */', ], - [ - '/* testReadonlyWithNullableProperty */', - 'readonly', + 'property declaration, constructor property promotion with reference, mixed case' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithReference */', + 'testContent' => 'ReadOnly', ], - [ - '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullFirst */', - 'readonly', + 'property declaration, in anonymous class' => [ + 'testMarker' => '/* testReadonlyPropertyInAnonymousClass */', ], - [ - '/* testReadonlyNullablePropertyWithUnionTypeHintAndNullLast */', - 'readonly', + 'property declaration, no visibility, DNF type, unqualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeUnqualified */', ], - [ - '/* testReadonlyPropertyWithArrayTypeHint */', - 'readonly', + 'property declaration, public before, DNF type, fully qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeFullyQualified */', ], - [ - '/* testReadonlyPropertyWithSelfTypeHint */', - 'readonly', + 'property declaration, protected before, DNF type, partially qualified' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypePartiallyQualified */', ], - [ - '/* testReadonlyPropertyWithParentTypeHint */', - 'readonly', + 'property declaration, private before, DNF type, namespace relative name' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeRelativeName */', ], - [ - '/* testReadonlyPropertyWithFullyQualifiedTypeHint */', - 'readonly', + 'property declaration, private before, DNF type, multiple sets' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeMultipleSets */', ], - [ - '/* testReadonlyIsCaseInsensitive */', - 'ReAdOnLy', + 'property declaration, private before, DNF type, union with array' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithArray */', ], - [ - '/* testReadonlyConstructorPropertyPromotion */', - 'readonly', + 'property declaration, private before, DNF type, with spaces and comment' => [ + 'testMarker' => '/* testReadonlyPropertyDNFTypeWithSpacesAndComments */', ], - [ - '/* testReadonlyConstructorPropertyPromotionWithReference */', - 'ReadOnly', + 'property declaration, constructor property promotion, DNF type' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNF */', ], - [ - '/* testReadonlyPropertyInAnonymousClass */', - 'readonly', + 'property declaration, constructor property promotion, DNF type and reference' => [ + 'testMarker' => '/* testReadonlyConstructorPropertyPromotionWithDNFAndReference */', ], - [ - '/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */', - 'readonly', + 'anon class declaration, with parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithParens */', ], - [ - '/* testParseErrorLiveCoding */', - 'readonly', + 'anon class declaration, without parentheses' => [ + 'testMarker' => '/* testReadonlyAnonClassWithoutParens */', + 'testContent' => 'Readonly', + ], + 'anon class declaration, with comments and whitespace' => [ + 'testMarker' => '/* testReadonlyAnonClassWithCommentsAndWhitespace */', + 'testContent' => 'READONLY', + ], + 'live coding / parse error' => [ + 'testMarker' => '/* testParseErrorLiveCoding */', ], ]; @@ -164,20 +174,22 @@ public function dataReadonly() * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. * * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $testContent The token content to look for. + * @param string $testContent Optional. The token content to look for. + * Defaults to lowercase "readonly". * * @dataProvider dataNotReadonly * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testNotReadonly($testMarker, $testContent) + public function testNotReadonly($testMarker, $testContent='readonly') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); + $tokenArray = $tokens[$target]; - $target = $this->getTargetToken($testMarker, [T_READONLY, T_STRING], $testContent); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testNotReadonly() @@ -187,46 +199,67 @@ public function testNotReadonly($testMarker, $testContent) * * @see testNotReadonly() * - * @return array + * @return array> */ - public function dataNotReadonly() + public static function dataNotReadonly() { return [ - [ - '/* testReadonlyUsedAsClassConstantName */', - 'READONLY', + 'name of a constant, context: declaration using "const" keyword, uppercase' => [ + 'testMarker' => '/* testReadonlyUsedAsClassConstantName */', + 'testContent' => 'READONLY', + ], + 'name of a method, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodName */', + ], + 'name of a property, context: property access' => [ + 'testMarker' => '/* testReadonlyUsedAsPropertyName */', + ], + 'name of a property, context: property access in ternary' => [ + 'testMarker' => '/* testReadonlyPropertyInTernaryOperator */', + ], + 'name of a function, context: declaration' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionName */', + ], + 'name of a function, context: declaration with return by ref' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionNameWithReturnByRef */', + ], + 'name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsNamespaceName */', + 'testContent' => 'Readonly', + ], + 'partial name of namespace, context: declaration, mixed case' => [ + 'testMarker' => '/* testReadonlyUsedAsPartOfNamespaceName */', + 'testContent' => 'Readonly', + ], + 'name of a function, context: call' => [ + 'testMarker' => '/* testReadonlyAsFunctionCall */', ], - [ - '/* testReadonlyUsedAsMethodName */', - 'readonly', + 'name of a namespaced function, context: partially qualified call' => [ + 'testMarker' => '/* testReadonlyAsNamespacedFunctionCall */', ], - [ - '/* testReadonlyUsedAsPropertyName */', - 'readonly', + 'name of a function, context: namespace relative call, mixed case' => [ + 'testMarker' => '/* testReadonlyAsNamespaceRelativeFunctionCall */', + 'testContent' => 'ReadOnly', ], - [ - '/* testReadonlyPropertyInTernaryOperator */', - 'readonly', + 'name of a method, context: method call on object' => [ + 'testMarker' => '/* testReadonlyAsMethodCall */', ], - [ - '/* testReadonlyUsedAsFunctionName */', - 'readonly', + 'name of a method, context: nullsafe method call on object' => [ + 'testMarker' => '/* testReadonlyAsNullsafeMethodCall */', + 'testContent' => 'readOnly', ], - [ - '/* testReadonlyUsedAsNamespaceName */', - 'Readonly', + 'name of a method, context: static method call with space after' => [ + 'testMarker' => '/* testReadonlyAsStaticMethodCallWithSpace */', ], - [ - '/* testReadonlyUsedAsPartOfNamespaceName */', - 'Readonly', + 'name of a constant, context: constant access - uppercase' => [ + 'testMarker' => '/* testClassConstantFetchWithReadonlyAsConstantName */', + 'testContent' => 'READONLY', ], - [ - '/* testReadonlyAsFunctionCall */', - 'readonly', + 'name of a function, context: call with space and comment between keyword and parens' => [ + 'testMarker' => '/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */', ], - [ - '/* testClassConstantFetchWithReadonlyAsConstantName */', - 'READONLY', + 'name of a method, context: declaration with DNF parameter' => [ + 'testMarker' => '/* testReadonlyUsedAsMethodNameWithDNFParam */', ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc index bfdbdc18c..5afc1e5bd 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc @@ -9,6 +9,30 @@ $result = $value | $test /* testBitwiseOr2 */ | $another; class TypeUnion { + /* testTypeUnionOOConstSimple */ + public const Foo|Bar SIMPLE = new Foo; + + /* testTypeUnionOOConstReverseModifierOrder */ + protected final const int|float MODIFIERS_REVERSED /* testBitwiseOrOOConstDefaultValue */ = E_WARNING | E_NOTICE; + + const + /* testTypeUnionOOConstMulti1 */ + array | + /* testTypeUnionOOConstMulti2 */ + Traversable | // phpcs:ignore Stnd.Cat.Sniff + false + /* testTypeUnionOOConstMulti3 */ + | null MULTI_UNION = false; + + /* testTypeUnionOOConstNamespaceRelative */ + final protected const namespace\Sub\NameA|namespace\Sub\NameB NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testTypeUnionOOConstPartiallyQualified */ + const Partially\Qualified\NameA|Partially\Qualified\NameB PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testTypeUnionOOConstFullyQualified */ + const \Fully\Qualified\NameA|\Fully\Qualified\NameB FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + /* testTypeUnionPropertySimple */ public static Foo|Bar $obj; @@ -48,6 +72,9 @@ class TypeUnion /* testTypeUnionPropertyWithOnlyReadOnlyKeyword */ readonly string|null $nullableString; + /* testTypeUnionPropertyWithOnlyStaticKeyword */ + static Foo|Bar $obj; + public function paramTypes( /* testTypeUnionParam1 */ int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B, @@ -68,12 +95,12 @@ class TypeUnion \Fully\Qualified\NameA|\Fully\Qualified\NameB $paramC, ) {} - /* testTypeUnionReturnType */ - public function returnType() : int|false {} - /* testTypeUnionConstructorPropertyPromotion */ public function __construct( public bool|null $property) {} + /* testTypeUnionReturnType */ + public function returnType() : int|false {} + /* testTypeUnionAbstractMethodReturnType1 */ abstract public function abstractMethod(): object|array /* testTypeUnionAbstractMethodReturnType2 */ |false; @@ -87,9 +114,6 @@ class TypeUnion public function identifierNamesReturnFQ() : \Fully\Qualified\NameA|\Fully\Qualified\NameB {} } -/* testTypeUnionClosureParamIllegalNullable */ -$closureWithParamType = function (?string|null $string) {}; - function globalFunctionWithSpreadAndReference( /* testTypeUnionWithReference */ float|null &$paramA, @@ -97,6 +121,9 @@ function globalFunctionWithSpreadAndReference( string|int ...$paramB ) {} +/* testTypeUnionClosureParamIllegalNullable */ +$closureWithParamType = function (?string|null $string) {}; + /* testBitwiseOrClosureParamDefault */ $closureWithReturnType = function ($string = NONSENSE | FAKE)/* testTypeUnionClosureReturn */ : \Package\MyA|PackageB {}; @@ -129,6 +156,15 @@ $obj->fn($something | $else); /* testTypeUnionNonArrowFunctionDeclaration */ function &fn(int|false $something) {} +/* testTypeUnionPHP82TrueFirst */ +function trueTypeParam(true|null $param) {} + +/* testTypeUnionPHP82TrueMiddle */ +function trueTypeReturn($param): array|true|null {} + +/* testTypeUnionPHP82TrueLast */ +$closure = function ($param): array|true {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. return function( type| diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php index d56e7340a..8e3e264f5 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class BitwiseOrTest extends AbstractMethodUnitTest +final class BitwiseOrTest extends AbstractTokenizerTestCase { @@ -27,11 +25,12 @@ class BitwiseOrTest extends AbstractMethodUnitTest */ public function testBitwiseOr($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; - $opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); - $this->assertSame(T_BITWISE_OR, $tokens[$opener]['code']); - $this->assertSame('T_BITWISE_OR', $tokens[$opener]['type']); + $this->assertSame(T_BITWISE_OR, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_OR (type)'); }//end testBitwiseOr() @@ -41,26 +40,27 @@ public function testBitwiseOr($testMarker) * * @see testBitwiseOr() * - * @return array + * @return array> */ - public function dataBitwiseOr() + public static function dataBitwiseOr() { return [ - ['/* testBitwiseOr1 */'], - ['/* testBitwiseOr2 */'], - ['/* testBitwiseOrPropertyDefaultValue */'], - ['/* testBitwiseOrParamDefaultValue */'], - ['/* testBitwiseOr3 */'], - ['/* testBitwiseOrClosureParamDefault */'], - ['/* testBitwiseOrArrowParamDefault */'], - ['/* testBitwiseOrArrowExpression */'], - ['/* testBitwiseOrInArrayKey */'], - ['/* testBitwiseOrInArrayValue */'], - ['/* testBitwiseOrInShortArrayKey */'], - ['/* testBitwiseOrInShortArrayValue */'], - ['/* testBitwiseOrTryCatch */'], - ['/* testBitwiseOrNonArrowFnFunctionCall */'], - ['/* testLiveCoding */'], + 'in simple assignment 1' => ['/* testBitwiseOr1 */'], + 'in simple assignment 2' => ['/* testBitwiseOr2 */'], + 'in OO constant default value' => ['/* testBitwiseOrOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseOrPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseOrParamDefaultValue */'], + 'in return statement' => ['/* testBitwiseOr3 */'], + 'in closure parameter default value' => ['/* testBitwiseOrClosureParamDefault */'], + 'in arrow function parameter default value' => ['/* testBitwiseOrArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseOrArrowExpression */'], + 'in long array key' => ['/* testBitwiseOrInArrayKey */'], + 'in long array value' => ['/* testBitwiseOrInArrayValue */'], + 'in short array key' => ['/* testBitwiseOrInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseOrInShortArrayValue */'], + 'in catch condition' => ['/* testBitwiseOrTryCatch */'], + 'in parameter in function call' => ['/* testBitwiseOrNonArrowFnFunctionCall */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], ]; }//end dataBitwiseOr() @@ -78,11 +78,12 @@ public function dataBitwiseOr() */ public function testTypeUnion($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); + $tokenArray = $tokens[$target]; - $opener = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION]); - $this->assertSame(T_TYPE_UNION, $tokens[$opener]['code']); - $this->assertSame('T_TYPE_UNION', $tokens[$opener]['type']); + $this->assertSame(T_TYPE_UNION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_UNION (type)'); }//end testTypeUnion() @@ -92,44 +93,56 @@ public function testTypeUnion($testMarker) * * @see testTypeUnion() * - * @return array + * @return array> */ - public function dataTypeUnion() + public static function dataTypeUnion() { return [ - ['/* testTypeUnionPropertySimple */'], - ['/* testTypeUnionPropertyReverseModifierOrder */'], - ['/* testTypeUnionPropertyMulti1 */'], - ['/* testTypeUnionPropertyMulti2 */'], - ['/* testTypeUnionPropertyMulti3 */'], - ['/* testTypeUnionPropertyNamespaceRelative */'], - ['/* testTypeUnionPropertyPartiallyQualified */'], - ['/* testTypeUnionPropertyFullyQualified */'], - ['/* testTypeUnionPropertyWithReadOnlyKeyword */'], - ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], - ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], - ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], - ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], - ['/* testTypeUnionParam1 */'], - ['/* testTypeUnionParam2 */'], - ['/* testTypeUnionParam3 */'], - ['/* testTypeUnionParamNamespaceRelative */'], - ['/* testTypeUnionParamPartiallyQualified */'], - ['/* testTypeUnionParamFullyQualified */'], - ['/* testTypeUnionReturnType */'], - ['/* testTypeUnionConstructorPropertyPromotion */'], - ['/* testTypeUnionAbstractMethodReturnType1 */'], - ['/* testTypeUnionAbstractMethodReturnType2 */'], - ['/* testTypeUnionReturnTypeNamespaceRelative */'], - ['/* testTypeUnionReturnPartiallyQualified */'], - ['/* testTypeUnionReturnFullyQualified */'], - ['/* testTypeUnionClosureParamIllegalNullable */'], - ['/* testTypeUnionWithReference */'], - ['/* testTypeUnionWithSpreadOperator */'], - ['/* testTypeUnionClosureReturn */'], - ['/* testTypeUnionArrowParam */'], - ['/* testTypeUnionArrowReturnType */'], - ['/* testTypeUnionNonArrowFunctionDeclaration */'], + 'type for OO constant' => ['/* testTypeUnionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeUnionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-union' => ['/* testTypeUnionOOConstMulti1 */'], + 'type for OO constant, middle of multi-union + comments' => ['/* testTypeUnionOOConstMulti2 */'], + 'type for OO constant, last of multi-union' => ['/* testTypeUnionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeUnionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeUnionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeUnionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeUnionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeUnionPropertyReverseModifierOrder */'], + 'type for property, first of multi-union' => ['/* testTypeUnionPropertyMulti1 */'], + 'type for property, middle of multi-union, also comments' => ['/* testTypeUnionPropertyMulti2 */'], + 'type for property, last of multi-union' => ['/* testTypeUnionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeUnionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeUnionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeUnionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeUnionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'], + 'type for readonly property using var keyword' => ['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'], + 'type for readonly property, reversed modifier order' => ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], + 'type for readonly property, no visibility' => ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], + 'type for static property, no visibility' => ['/* testTypeUnionPropertyWithOnlyStaticKeyword */'], + 'type for method parameter' => ['/* testTypeUnionParam1 */'], + 'type for method parameter, first in multi-union' => ['/* testTypeUnionParam2 */'], + 'type for method parameter, last in multi-union' => ['/* testTypeUnionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeUnionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeUnionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeUnionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeUnionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeUnionReturnType */'], + 'return type for method, first of multi-union' => ['/* testTypeUnionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-union' => ['/* testTypeUnionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeUnionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeUnionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeUnionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeUnionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeUnionWithSpreadOperator */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeUnionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeUnionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeUnionArrowParam */'], + 'return type for arrow function' => ['/* testTypeUnionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeUnionNonArrowFunctionDeclaration */'], + 'type for function param with true type first' => ['/* testTypeUnionPHP82TrueFirst */'], + 'type for function param with true type middle' => ['/* testTypeUnionPHP82TrueMiddle */'], + 'type for function param with true type last' => ['/* testTypeUnionPHP82TrueLast */'], ]; }//end dataTypeUnion() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc index e3c10ad8e..2d471285c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc @@ -53,7 +53,6 @@ class ContextSensitiveKeywords const /* testMatch */ MATCH = 'MATCH'; const /* testNamespace */ NAMESPACE = 'NAMESPACE'; const /* testNew */ NEW = 'NEW'; - const /* testParent */ PARENT = 'PARENT'; const /* testPrint */ PRINT = 'PRINT'; const /* testPrivate */ PRIVATE = 'PRIVATE'; const /* testProtected */ PROTECTED = 'PROTECTED'; @@ -62,7 +61,6 @@ class ContextSensitiveKeywords const /* testRequire */ REQUIRE = 'REQUIRE'; const /* testRequireOnce */ REQUIRE_ONCE = 'REQUIRE_ONCE'; const /* testReturn */ RETURN = 'RETURN'; - const /* testSelf */ SELF = 'SELF'; const /* testStatic */ STATIC = 'STATIC'; const /* testSwitch */ SWITCH = 'SWITCH'; const /* testThrows */ THROW = 'THROW'; @@ -78,6 +76,12 @@ class ContextSensitiveKeywords const /* testAnd */ AND = 'LOGICAL_AND'; const /* testOr */ OR = 'LOGICAL_OR'; const /* testXor */ XOR = 'LOGICAL_XOR'; + + const /* testArrayIsTstringInConstType */ array /* testArrayNameForTypedConstant */ ARRAY = /* testArrayIsKeywordInConstDefault */ array(); + const /* testStaticIsKeywordAsConstType */ static /* testStaticIsNameForTypedConstant */ STATIC = new /* testStaticIsKeywordAsConstDefault */ static; + + const int|bool /* testPrivateNameForUnionTypedConstant */ PRIVATE = 'PRIVATE'; + const Foo&Bar /* testFinalNameForIntersectionTypedConstant */ FINAL = 'FINAL'; } namespace /* testKeywordAfterNamespaceShouldBeString */ class; @@ -101,16 +105,16 @@ namespace /* testNamespaceNameIsString1 */ my\ /* testNamespaceNameIsString2 */ /* testVarIsKeyword */ var $var; /* testStaticIsKeyword */ static $static; - /* testReadonlyIsKeyword */ readonly $readonly; + /* testReadonlyIsKeywordForProperty */ readonly $readonly; /* testFinalIsKeyword */ final /* testFunctionIsKeyword */ function someFunction( /* testCallableIsKeyword */ callable $callable, - /* testSelfIsKeyword */ - self $self, - /* testParentIsKeyword */ - parent $parent ) { + $anon = new /* testReadonlyIsKeywordForAnonClass */ readonly class() { + public function foo() {} + }; + /* testReturnIsKeyword */ return $this; } @@ -216,12 +220,18 @@ $anonymousClass = new /* testAnonymousClassIsKeyword */ class {}; $anonymousClass2 = new class /* testExtendsInAnonymousClassIsKeyword */ extends SomeParent {}; $anonymousClass3 = new class /* testImplementsInAnonymousClassIsKeyword */ implements SomeInterface {}; -$instantiated1 = new /* testClassInstantiationParentIsKeyword */ parent(); -$instantiated2 = new /* testClassInstantiationSelfIsKeyword */ SELF; -$instantiated3 = new /* testClassInstantiationStaticIsKeyword */ static($param); +$instantiated = new /* testClassInstantiationStaticIsKeyword */ static($param); class Foo extends /* testNamespaceInNameIsKeyword */ namespace\Exception {} function /* testKeywordAfterFunctionShouldBeString */ eval() {} function /* testKeywordAfterFunctionByRefShouldBeString */ &switch() {} + +function /* testKeywordStaticAfterFunctionByRefShouldBeString */ &static() {} + +/* testKeywordAsFunctionCallNameShouldBeStringStatic */ static(); +$obj-> /* testKeywordAsMethodCallNameShouldBeStringStatic */ static(); + +$function = /* testStaticIsKeywordBeforeClosure */ static function(/* testStaticIsKeywordWhenParamType */ static $param) {}; +$arrow = /* testStaticIsKeywordBeforeArrow */ static fn(): /* testStaticIsKeywordWhenReturnType */ static => 10; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php index a747e573c..51c545387 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php @@ -1,18 +1,17 @@ * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class ContextSensitiveKeywordsTest extends AbstractMethodUnitTest +final class ContextSensitiveKeywordsTest extends AbstractTokenizerTestCase { @@ -28,12 +27,12 @@ class ContextSensitiveKeywordsTest extends AbstractMethodUnitTest */ public function testStrings($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING])); + $tokenArray = $tokens[$target]; - $token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING])); - - $this->assertSame(T_STRING, $tokens[$token]['code']); - $this->assertSame('T_STRING', $tokens[$token]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testStrings() @@ -43,91 +42,99 @@ public function testStrings($testMarker) * * @see testStrings() * - * @return array + * @return array> */ - public function dataStrings() + public static function dataStrings() { return [ - ['/* testAbstract */'], - ['/* testArray */'], - ['/* testAs */'], - ['/* testBreak */'], - ['/* testCallable */'], - ['/* testCase */'], - ['/* testCatch */'], - ['/* testClass */'], - ['/* testClone */'], - ['/* testConst */'], - ['/* testContinue */'], - ['/* testDeclare */'], - ['/* testDefault */'], - ['/* testDo */'], - ['/* testEcho */'], - ['/* testElse */'], - ['/* testElseIf */'], - ['/* testEmpty */'], - ['/* testEndDeclare */'], - ['/* testEndFor */'], - ['/* testEndForeach */'], - ['/* testEndIf */'], - ['/* testEndSwitch */'], - ['/* testEndWhile */'], - ['/* testEnum */'], - ['/* testEval */'], - ['/* testExit */'], - ['/* testExtends */'], - ['/* testFinal */'], - ['/* testFinally */'], - ['/* testFn */'], - ['/* testFor */'], - ['/* testForeach */'], - ['/* testFunction */'], - ['/* testGlobal */'], - ['/* testGoto */'], - ['/* testIf */'], - ['/* testImplements */'], - ['/* testInclude */'], - ['/* testIncludeOnce */'], - ['/* testInstanceOf */'], - ['/* testInsteadOf */'], - ['/* testInterface */'], - ['/* testIsset */'], - ['/* testList */'], - ['/* testMatch */'], - ['/* testNamespace */'], - ['/* testNew */'], - ['/* testParent */'], - ['/* testPrint */'], - ['/* testPrivate */'], - ['/* testProtected */'], - ['/* testPublic */'], - ['/* testReadonly */'], - ['/* testRequire */'], - ['/* testRequireOnce */'], - ['/* testReturn */'], - ['/* testSelf */'], - ['/* testStatic */'], - ['/* testSwitch */'], - ['/* testThrows */'], - ['/* testTrait */'], - ['/* testTry */'], - ['/* testUnset */'], - ['/* testUse */'], - ['/* testVar */'], - ['/* testWhile */'], - ['/* testYield */'], - ['/* testYieldFrom */'], - ['/* testAnd */'], - ['/* testOr */'], - ['/* testXor */'], - - ['/* testKeywordAfterNamespaceShouldBeString */'], - ['/* testNamespaceNameIsString1 */'], - ['/* testNamespaceNameIsString2 */'], - ['/* testNamespaceNameIsString3 */'], - - ['/* testKeywordAfterFunctionShouldBeString */'], - ['/* testKeywordAfterFunctionByRefShouldBeString */'], + 'constant declaration: abstract' => ['/* testAbstract */'], + 'constant declaration: array' => ['/* testArray */'], + 'constant declaration: as' => ['/* testAs */'], + 'constant declaration: break' => ['/* testBreak */'], + 'constant declaration: callable' => ['/* testCallable */'], + 'constant declaration: case' => ['/* testCase */'], + 'constant declaration: catch' => ['/* testCatch */'], + 'constant declaration: class' => ['/* testClass */'], + 'constant declaration: clone' => ['/* testClone */'], + 'constant declaration: const' => ['/* testConst */'], + 'constant declaration: continue' => ['/* testContinue */'], + 'constant declaration: declare' => ['/* testDeclare */'], + 'constant declaration: default' => ['/* testDefault */'], + 'constant declaration: do' => ['/* testDo */'], + 'constant declaration: echo' => ['/* testEcho */'], + 'constant declaration: else' => ['/* testElse */'], + 'constant declaration: elseif' => ['/* testElseIf */'], + 'constant declaration: empty' => ['/* testEmpty */'], + 'constant declaration: enddeclare' => ['/* testEndDeclare */'], + 'constant declaration: endfor' => ['/* testEndFor */'], + 'constant declaration: endforeach' => ['/* testEndForeach */'], + 'constant declaration: endif' => ['/* testEndIf */'], + 'constant declaration: endswitch' => ['/* testEndSwitch */'], + 'constant declaration: endwhile' => ['/* testEndWhile */'], + 'constant declaration: enum' => ['/* testEnum */'], + 'constant declaration: eval' => ['/* testEval */'], + 'constant declaration: exit' => ['/* testExit */'], + 'constant declaration: extends' => ['/* testExtends */'], + 'constant declaration: final' => ['/* testFinal */'], + 'constant declaration: finally' => ['/* testFinally */'], + 'constant declaration: fn' => ['/* testFn */'], + 'constant declaration: for' => ['/* testFor */'], + 'constant declaration: foreach' => ['/* testForeach */'], + 'constant declaration: function' => ['/* testFunction */'], + 'constant declaration: global' => ['/* testGlobal */'], + 'constant declaration: goto' => ['/* testGoto */'], + 'constant declaration: if' => ['/* testIf */'], + 'constant declaration: implements' => ['/* testImplements */'], + 'constant declaration: include' => ['/* testInclude */'], + 'constant declaration: include_once' => ['/* testIncludeOnce */'], + 'constant declaration: instanceof' => ['/* testInstanceOf */'], + 'constant declaration: insteadof' => ['/* testInsteadOf */'], + 'constant declaration: interface' => ['/* testInterface */'], + 'constant declaration: isset' => ['/* testIsset */'], + 'constant declaration: list' => ['/* testList */'], + 'constant declaration: match' => ['/* testMatch */'], + 'constant declaration: namespace' => ['/* testNamespace */'], + 'constant declaration: new' => ['/* testNew */'], + 'constant declaration: print' => ['/* testPrint */'], + 'constant declaration: private' => ['/* testPrivate */'], + 'constant declaration: protected' => ['/* testProtected */'], + 'constant declaration: public' => ['/* testPublic */'], + 'constant declaration: readonly' => ['/* testReadonly */'], + 'constant declaration: require' => ['/* testRequire */'], + 'constant declaration: require_once' => ['/* testRequireOnce */'], + 'constant declaration: return' => ['/* testReturn */'], + 'constant declaration: static' => ['/* testStatic */'], + 'constant declaration: switch' => ['/* testSwitch */'], + 'constant declaration: throws' => ['/* testThrows */'], + 'constant declaration: trait' => ['/* testTrait */'], + 'constant declaration: try' => ['/* testTry */'], + 'constant declaration: unset' => ['/* testUnset */'], + 'constant declaration: use' => ['/* testUse */'], + 'constant declaration: var' => ['/* testVar */'], + 'constant declaration: while' => ['/* testWhile */'], + 'constant declaration: yield' => ['/* testYield */'], + 'constant declaration: yield_from' => ['/* testYieldFrom */'], + 'constant declaration: and' => ['/* testAnd */'], + 'constant declaration: or' => ['/* testOr */'], + 'constant declaration: xor' => ['/* testXor */'], + + 'constant declaration: array in type' => ['/* testArrayIsTstringInConstType */'], + 'constant declaration: array, name after type' => ['/* testArrayNameForTypedConstant */'], + 'constant declaration: static, name after type' => ['/* testStaticIsNameForTypedConstant */'], + 'constant declaration: private, name after type' => ['/* testPrivateNameForUnionTypedConstant */'], + 'constant declaration: final, name after type' => ['/* testFinalNameForIntersectionTypedConstant */'], + + 'namespace declaration: class' => ['/* testKeywordAfterNamespaceShouldBeString */'], + 'namespace declaration (partial): my' => ['/* testNamespaceNameIsString1 */'], + 'namespace declaration (partial): class' => ['/* testNamespaceNameIsString2 */'], + 'namespace declaration (partial): foreach' => ['/* testNamespaceNameIsString3 */'], + + 'function declaration: eval' => ['/* testKeywordAfterFunctionShouldBeString */'], + 'function declaration with return by ref: switch' => ['/* testKeywordAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: static' => ['/* testKeywordStaticAfterFunctionByRefShouldBeString */'], + + 'function call: static' => ['/* testKeywordAsFunctionCallNameShouldBeStringStatic */'], + 'method call: static' => ['/* testKeywordAsMethodCallNameShouldBeStringStatic */'], ]; }//end dataStrings() @@ -146,12 +153,20 @@ public function dataStrings() */ public function testKeywords($testMarker, $expectedTokenType) { - $tokens = self::$phpcsFile->getTokens(); - - $token = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_PARENT, T_SELF, T_STRING])); - - $this->assertSame(constant($expectedTokenType), $tokens[$token]['code']); - $this->assertSame($expectedTokenType, $tokens[$token]['type']); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_STRING])); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); }//end testKeywords() @@ -163,343 +178,361 @@ public function testKeywords($testMarker, $expectedTokenType) * * @return array */ - public function dataKeywords() + public static function dataKeywords() { return [ - [ - '/* testNamespaceIsKeyword */', - 'T_NAMESPACE', + 'namespace: declaration' => [ + 'testMarker' => '/* testNamespaceIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + 'array: default value in const decl' => [ + 'testMarker' => '/* testArrayIsKeywordInConstDefault */', + 'expectedTokenType' => 'T_ARRAY', ], - [ - '/* testAbstractIsKeyword */', - 'T_ABSTRACT', + 'static: type in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstType */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testClassIsKeyword */', - 'T_CLASS', + 'static: value in constant declaration' => [ + 'testMarker' => '/* testStaticIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testExtendsIsKeyword */', - 'T_EXTENDS', + + 'abstract: class declaration' => [ + 'testMarker' => '/* testAbstractIsKeyword */', + 'expectedTokenType' => 'T_ABSTRACT', + ], + 'class: declaration' => [ + 'testMarker' => '/* testClassIsKeyword */', + 'expectedTokenType' => 'T_CLASS', ], - [ - '/* testImplementsIsKeyword */', - 'T_IMPLEMENTS', + 'extends: in class declaration' => [ + 'testMarker' => '/* testExtendsIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', ], - [ - '/* testUseIsKeyword */', - 'T_USE', + 'implements: in class declaration' => [ + 'testMarker' => '/* testImplementsIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', ], - [ - '/* testInsteadOfIsKeyword */', - 'T_INSTEADOF', + 'use: in trait import' => [ + 'testMarker' => '/* testUseIsKeyword */', + 'expectedTokenType' => 'T_USE', ], - [ - '/* testAsIsKeyword */', - 'T_AS', + 'insteadof: in trait import' => [ + 'testMarker' => '/* testInsteadOfIsKeyword */', + 'expectedTokenType' => 'T_INSTEADOF', ], - [ - '/* testConstIsKeyword */', - 'T_CONST', + 'as: in trait import' => [ + 'testMarker' => '/* testAsIsKeyword */', + 'expectedTokenType' => 'T_AS', ], - [ - '/* testPrivateIsKeyword */', - 'T_PRIVATE', + 'const: declaration' => [ + 'testMarker' => '/* testConstIsKeyword */', + 'expectedTokenType' => 'T_CONST', ], - [ - '/* testProtectedIsKeyword */', - 'T_PROTECTED', + 'private: property declaration' => [ + 'testMarker' => '/* testPrivateIsKeyword */', + 'expectedTokenType' => 'T_PRIVATE', ], - [ - '/* testPublicIsKeyword */', - 'T_PUBLIC', + 'protected: property declaration' => [ + 'testMarker' => '/* testProtectedIsKeyword */', + 'expectedTokenType' => 'T_PROTECTED', ], - [ - '/* testVarIsKeyword */', - 'T_VAR', + 'public: property declaration' => [ + 'testMarker' => '/* testPublicIsKeyword */', + 'expectedTokenType' => 'T_PUBLIC', ], - [ - '/* testStaticIsKeyword */', - 'T_STATIC', + 'var: property declaration' => [ + 'testMarker' => '/* testVarIsKeyword */', + 'expectedTokenType' => 'T_VAR', ], - [ - '/* testReadonlyIsKeyword */', - 'T_READONLY', + 'static: property declaration' => [ + 'testMarker' => '/* testStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testFinalIsKeyword */', - 'T_FINAL', + 'readonly: property declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForProperty */', + 'expectedTokenType' => 'T_READONLY', ], - [ - '/* testFunctionIsKeyword */', - 'T_FUNCTION', + 'final: function declaration' => [ + 'testMarker' => '/* testFinalIsKeyword */', + 'expectedTokenType' => 'T_FINAL', ], - [ - '/* testCallableIsKeyword */', - 'T_CALLABLE', + 'function: declaration' => [ + 'testMarker' => '/* testFunctionIsKeyword */', + 'expectedTokenType' => 'T_FUNCTION', ], - [ - '/* testSelfIsKeyword */', - 'T_SELF', + 'callable: param type declaration' => [ + 'testMarker' => '/* testCallableIsKeyword */', + 'expectedTokenType' => 'T_CALLABLE', ], - [ - '/* testParentIsKeyword */', - 'T_PARENT', + 'readonly: anon class declaration' => [ + 'testMarker' => '/* testReadonlyIsKeywordForAnonClass */', + 'expectedTokenType' => 'T_READONLY', ], - [ - '/* testReturnIsKeyword */', - 'T_RETURN', + 'return: statement' => [ + 'testMarker' => '/* testReturnIsKeyword */', + 'expectedTokenType' => 'T_RETURN', ], - [ - '/* testInterfaceIsKeyword */', - 'T_INTERFACE', + 'interface: declaration' => [ + 'testMarker' => '/* testInterfaceIsKeyword */', + 'expectedTokenType' => 'T_INTERFACE', ], - [ - '/* testTraitIsKeyword */', - 'T_TRAIT', + 'trait: declaration' => [ + 'testMarker' => '/* testTraitIsKeyword */', + 'expectedTokenType' => 'T_TRAIT', ], - [ - '/* testEnumIsKeyword */', - 'T_ENUM', + 'enum: declaration' => [ + 'testMarker' => '/* testEnumIsKeyword */', + 'expectedTokenType' => 'T_ENUM', ], - [ - '/* testNewIsKeyword */', - 'T_NEW', + 'new: named instantiation' => [ + 'testMarker' => '/* testNewIsKeyword */', + 'expectedTokenType' => 'T_NEW', ], - [ - '/* testInstanceOfIsKeyword */', - 'T_INSTANCEOF', + 'instanceof: comparison' => [ + 'testMarker' => '/* testInstanceOfIsKeyword */', + 'expectedTokenType' => 'T_INSTANCEOF', ], - [ - '/* testCloneIsKeyword */', - 'T_CLONE', + 'clone' => [ + 'testMarker' => '/* testCloneIsKeyword */', + 'expectedTokenType' => 'T_CLONE', ], - [ - '/* testIfIsKeyword */', - 'T_IF', + 'if' => [ + 'testMarker' => '/* testIfIsKeyword */', + 'expectedTokenType' => 'T_IF', ], - [ - '/* testEmptyIsKeyword */', - 'T_EMPTY', + 'empty' => [ + 'testMarker' => '/* testEmptyIsKeyword */', + 'expectedTokenType' => 'T_EMPTY', ], - [ - '/* testElseIfIsKeyword */', - 'T_ELSEIF', + 'elseif' => [ + 'testMarker' => '/* testElseIfIsKeyword */', + 'expectedTokenType' => 'T_ELSEIF', ], - [ - '/* testElseIsKeyword */', - 'T_ELSE', + 'else' => [ + 'testMarker' => '/* testElseIsKeyword */', + 'expectedTokenType' => 'T_ELSE', ], - [ - '/* testEndIfIsKeyword */', - 'T_ENDIF', + 'endif' => [ + 'testMarker' => '/* testEndIfIsKeyword */', + 'expectedTokenType' => 'T_ENDIF', ], - [ - '/* testForIsKeyword */', - 'T_FOR', + 'for' => [ + 'testMarker' => '/* testForIsKeyword */', + 'expectedTokenType' => 'T_FOR', ], - [ - '/* testEndForIsKeyword */', - 'T_ENDFOR', + 'endfor' => [ + 'testMarker' => '/* testEndForIsKeyword */', + 'expectedTokenType' => 'T_ENDFOR', ], - [ - '/* testForeachIsKeyword */', - 'T_FOREACH', + 'foreach' => [ + 'testMarker' => '/* testForeachIsKeyword */', + 'expectedTokenType' => 'T_FOREACH', ], - [ - '/* testEndForeachIsKeyword */', - 'T_ENDFOREACH', + 'endforeach' => [ + 'testMarker' => '/* testEndForeachIsKeyword */', + 'expectedTokenType' => 'T_ENDFOREACH', ], - [ - '/* testSwitchIsKeyword */', - 'T_SWITCH', + 'switch' => [ + 'testMarker' => '/* testSwitchIsKeyword */', + 'expectedTokenType' => 'T_SWITCH', ], - [ - '/* testCaseIsKeyword */', - 'T_CASE', + 'case: in switch' => [ + 'testMarker' => '/* testCaseIsKeyword */', + 'expectedTokenType' => 'T_CASE', ], - [ - '/* testDefaultIsKeyword */', - 'T_DEFAULT', + 'default: in switch' => [ + 'testMarker' => '/* testDefaultIsKeyword */', + 'expectedTokenType' => 'T_DEFAULT', ], - [ - '/* testEndSwitchIsKeyword */', - 'T_ENDSWITCH', + 'endswitch' => [ + 'testMarker' => '/* testEndSwitchIsKeyword */', + 'expectedTokenType' => 'T_ENDSWITCH', ], - [ - '/* testBreakIsKeyword */', - 'T_BREAK', + 'break: in switch' => [ + 'testMarker' => '/* testBreakIsKeyword */', + 'expectedTokenType' => 'T_BREAK', ], - [ - '/* testContinueIsKeyword */', - 'T_CONTINUE', + 'continue: in switch' => [ + 'testMarker' => '/* testContinueIsKeyword */', + 'expectedTokenType' => 'T_CONTINUE', ], - [ - '/* testDoIsKeyword */', - 'T_DO', + 'do' => [ + 'testMarker' => '/* testDoIsKeyword */', + 'expectedTokenType' => 'T_DO', ], - [ - '/* testWhileIsKeyword */', - 'T_WHILE', + 'while' => [ + 'testMarker' => '/* testWhileIsKeyword */', + 'expectedTokenType' => 'T_WHILE', ], - [ - '/* testEndWhileIsKeyword */', - 'T_ENDWHILE', + 'endwhile' => [ + 'testMarker' => '/* testEndWhileIsKeyword */', + 'expectedTokenType' => 'T_ENDWHILE', ], - [ - '/* testTryIsKeyword */', - 'T_TRY', + 'try' => [ + 'testMarker' => '/* testTryIsKeyword */', + 'expectedTokenType' => 'T_TRY', ], - [ - '/* testThrowIsKeyword */', - 'T_THROW', + 'throw: statement' => [ + 'testMarker' => '/* testThrowIsKeyword */', + 'expectedTokenType' => 'T_THROW', ], - [ - '/* testCatchIsKeyword */', - 'T_CATCH', + 'catch' => [ + 'testMarker' => '/* testCatchIsKeyword */', + 'expectedTokenType' => 'T_CATCH', ], - [ - '/* testFinallyIsKeyword */', - 'T_FINALLY', + 'finally' => [ + 'testMarker' => '/* testFinallyIsKeyword */', + 'expectedTokenType' => 'T_FINALLY', ], - [ - '/* testGlobalIsKeyword */', - 'T_GLOBAL', + 'global' => [ + 'testMarker' => '/* testGlobalIsKeyword */', + 'expectedTokenType' => 'T_GLOBAL', ], - [ - '/* testEchoIsKeyword */', - 'T_ECHO', + 'echo' => [ + 'testMarker' => '/* testEchoIsKeyword */', + 'expectedTokenType' => 'T_ECHO', ], - [ - '/* testPrintIsKeyword */', - 'T_PRINT', + 'print: statement' => [ + 'testMarker' => '/* testPrintIsKeyword */', + 'expectedTokenType' => 'T_PRINT', ], - [ - '/* testDieIsKeyword */', - 'T_EXIT', + 'die: statement' => [ + 'testMarker' => '/* testDieIsKeyword */', + 'expectedTokenType' => 'T_EXIT', ], - [ - '/* testEvalIsKeyword */', - 'T_EVAL', + 'eval' => [ + 'testMarker' => '/* testEvalIsKeyword */', + 'expectedTokenType' => 'T_EVAL', ], - [ - '/* testExitIsKeyword */', - 'T_EXIT', + 'exit: statement' => [ + 'testMarker' => '/* testExitIsKeyword */', + 'expectedTokenType' => 'T_EXIT', ], - [ - '/* testIssetIsKeyword */', - 'T_ISSET', + 'isset' => [ + 'testMarker' => '/* testIssetIsKeyword */', + 'expectedTokenType' => 'T_ISSET', ], - [ - '/* testUnsetIsKeyword */', - 'T_UNSET', + 'unset' => [ + 'testMarker' => '/* testUnsetIsKeyword */', + 'expectedTokenType' => 'T_UNSET', ], - [ - '/* testIncludeIsKeyword */', - 'T_INCLUDE', + 'include' => [ + 'testMarker' => '/* testIncludeIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE', ], - [ - '/* testIncludeOnceIsKeyword */', - 'T_INCLUDE_ONCE', + 'include_once' => [ + 'testMarker' => '/* testIncludeOnceIsKeyword */', + 'expectedTokenType' => 'T_INCLUDE_ONCE', ], - [ - '/* testRequireIsKeyword */', - 'T_REQUIRE', + 'require' => [ + 'testMarker' => '/* testRequireIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE', ], - [ - '/* testRequireOnceIsKeyword */', - 'T_REQUIRE_ONCE', + 'require_once' => [ + 'testMarker' => '/* testRequireOnceIsKeyword */', + 'expectedTokenType' => 'T_REQUIRE_ONCE', ], - [ - '/* testListIsKeyword */', - 'T_LIST', + 'list' => [ + 'testMarker' => '/* testListIsKeyword */', + 'expectedTokenType' => 'T_LIST', ], - [ - '/* testGotoIsKeyword */', - 'T_GOTO', + 'goto' => [ + 'testMarker' => '/* testGotoIsKeyword */', + 'expectedTokenType' => 'T_GOTO', ], - [ - '/* testMatchIsKeyword */', - 'T_MATCH', + 'match' => [ + 'testMarker' => '/* testMatchIsKeyword */', + 'expectedTokenType' => 'T_MATCH', ], - [ - '/* testMatchDefaultIsKeyword */', - 'T_MATCH_DEFAULT', + 'default: in match expression' => [ + 'testMarker' => '/* testMatchDefaultIsKeyword */', + 'expectedTokenType' => 'T_MATCH_DEFAULT', ], - [ - '/* testFnIsKeyword */', - 'T_FN', + 'fn' => [ + 'testMarker' => '/* testFnIsKeyword */', + 'expectedTokenType' => 'T_FN', ], - [ - '/* testYieldIsKeyword */', - 'T_YIELD', + 'yield' => [ + 'testMarker' => '/* testYieldIsKeyword */', + 'expectedTokenType' => 'T_YIELD', ], - [ - '/* testYieldFromIsKeyword */', - 'T_YIELD_FROM', + 'yield from' => [ + 'testMarker' => '/* testYieldFromIsKeyword */', + 'expectedTokenType' => 'T_YIELD_FROM', ], - [ - '/* testDeclareIsKeyword */', - 'T_DECLARE', + 'declare' => [ + 'testMarker' => '/* testDeclareIsKeyword */', + 'expectedTokenType' => 'T_DECLARE', ], - [ - '/* testEndDeclareIsKeyword */', - 'T_ENDDECLARE', + 'enddeclare' => [ + 'testMarker' => '/* testEndDeclareIsKeyword */', + 'expectedTokenType' => 'T_ENDDECLARE', ], - [ - '/* testAndIsKeyword */', - 'T_LOGICAL_AND', + 'and: in if' => [ + 'testMarker' => '/* testAndIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_AND', ], - [ - '/* testOrIsKeyword */', - 'T_LOGICAL_OR', + 'or: in if' => [ + 'testMarker' => '/* testOrIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_OR', ], - [ - '/* testXorIsKeyword */', - 'T_LOGICAL_XOR', + 'xor: in if' => [ + 'testMarker' => '/* testXorIsKeyword */', + 'expectedTokenType' => 'T_LOGICAL_XOR', ], - [ - '/* testAnonymousClassIsKeyword */', - 'T_ANON_CLASS', + 'class: anon class declaration' => [ + 'testMarker' => '/* testAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_ANON_CLASS', + ], + 'extends: anon class declaration' => [ + 'testMarker' => '/* testExtendsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_EXTENDS', ], - [ - '/* testExtendsInAnonymousClassIsKeyword */', - 'T_EXTENDS', + 'implements: anon class declaration' => [ + 'testMarker' => '/* testImplementsInAnonymousClassIsKeyword */', + 'expectedTokenType' => 'T_IMPLEMENTS', ], - [ - '/* testImplementsInAnonymousClassIsKeyword */', - 'T_IMPLEMENTS', + 'static: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationStaticIsKeyword */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testClassInstantiationParentIsKeyword */', - 'T_PARENT', + 'namespace: operator' => [ + 'testMarker' => '/* testNamespaceInNameIsKeyword */', + 'expectedTokenType' => 'T_NAMESPACE', + ], + + 'static: closure declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeClosure */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testClassInstantiationSelfIsKeyword */', - 'T_SELF', + 'static: parameter type (illegal)' => [ + 'testMarker' => '/* testStaticIsKeywordWhenParamType */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testClassInstantiationStaticIsKeyword */', - 'T_STATIC', + 'static: arrow function declaration' => [ + 'testMarker' => '/* testStaticIsKeywordBeforeArrow */', + 'expectedTokenType' => 'T_STATIC', ], - [ - '/* testNamespaceInNameIsKeyword */', - 'T_NAMESPACE', + 'static: return type for arrow function' => [ + 'testMarker' => '/* testStaticIsKeywordWhenReturnType */', + 'expectedTokenType' => 'T_STATIC', ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php index 9a5b061a0..cee3d263d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php @@ -5,14 +5,12 @@ * * @author Juliette Reinders Folmer * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class DefaultKeywordTest extends AbstractMethodUnitTest +final class DefaultKeywordTest extends AbstractTokenizerTestCase { @@ -33,7 +31,7 @@ class DefaultKeywordTest extends AbstractMethodUnitTest */ public function testMatchDefault($testMarker, $testContent='default') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -53,40 +51,50 @@ public function testMatchDefault($testMarker, $testContent='default') * * @see testMatchDefault() * - * @return array + * @return array> */ - public function dataMatchDefault() + public static function dataMatchDefault() { return [ - 'simple_match_default' => ['/* testSimpleMatchDefault */'], - 'match_default_in_switch_case_1' => ['/* testMatchDefaultNestedInSwitchCase1 */'], - 'match_default_in_switch_case_2' => ['/* testMatchDefaultNestedInSwitchCase2 */'], - 'match_default_in_switch_default' => ['/* testMatchDefaultNestedInSwitchDefault */'], - 'match_default_containing_switch' => ['/* testMatchDefault */'], + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], 'match_default_with_nested_long_array_and_default_key' => [ - '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', ], 'match_default_with_nested_long_array_and_default_key_2' => [ - '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', ], 'match_default_with_nested_short_array_and_default_key' => [ - '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', ], 'match_default_with_nested_short_array_and_default_key_2' => [ - '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', ], 'match_default_in_long_array' => [ - '/* testMatchDefaultNestedInLongArray */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', ], 'match_default_in_short_array' => [ - '/* testMatchDefaultNestedInShortArray */', - 'DEFAULT', + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', ], ]; @@ -113,7 +121,7 @@ public function dataMatchDefault() */ public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null, $testContent='default') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -169,40 +177,40 @@ public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $co * * @see testSwitchDefault() * - * @return array + * @return array> */ - public function dataSwitchDefault() + public static function dataSwitchDefault() { return [ 'simple_switch_default' => [ - '/* testSimpleSwitchDefault */', - 1, - 4, + 'testMarker' => '/* testSimpleSwitchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 4, ], 'simple_switch_default_with_curlies' => [ // For a default structure with curly braces, the scope opener // will be the open curly and the closer the close curly. // However, scope conditions will not be set for open to close, // but only for the open token up to the "break/return/continue" etc. - '/* testSimpleSwitchDefaultWithCurlies */', - 3, - 12, - 6, + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + 'openerOffset' => 3, + 'closerOffset' => 12, + 'conditionStop' => 6, ], 'switch_default_toplevel' => [ - '/* testSwitchDefault */', - 1, - 43, + 'testMarker' => '/* testSwitchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 43, ], 'switch_default_nested_in_match_case' => [ - '/* testSwitchDefaultNestedInMatchCase */', - 1, - 20, + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerOffset' => 1, + 'closerOffset' => 20, ], 'switch_default_nested_in_match_default' => [ - '/* testSwitchDefaultNestedInMatchDefault */', - 1, - 18, + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerOffset' => 1, + 'closerOffset' => 18, ], ]; @@ -224,7 +232,7 @@ public function dataSwitchDefault() */ public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); $tokenArray = $tokens[$token]; @@ -244,34 +252,68 @@ public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') * * @see testNotDefaultKeyword() * - * @return array + * @return array> */ - public function dataNotDefaultKeyword() + public static function dataNotDefaultKeyword() { return [ - 'class-constant-as-short-array-key' => ['/* testClassConstantAsShortArrayKey */'], - 'class-property-as-short-array-key' => ['/* testClassPropertyAsShortArrayKey */'], - 'namespaced-constant-as-short-array-key' => ['/* testNamespacedConstantAsShortArrayKey */'], - 'fqn-global-constant-as-short-array-key' => ['/* testFQNGlobalConstantAsShortArrayKey */'], - 'class-constant-as-long-array-key' => ['/* testClassConstantAsLongArrayKey */'], - 'class-constant-as-yield-key' => ['/* testClassConstantAsYieldKey */'], - - 'class-constant-as-long-array-key-nested-in-match' => ['/* testClassConstantAsLongArrayKeyNestedInMatch */'], - 'class-constant-as-long-array-key-nested-in-match-2' => ['/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */'], - 'class-constant-as-short-array-key-nested-in-match' => ['/* testClassConstantAsShortArrayKeyNestedInMatch */'], - 'class-constant-as-short-array-key-nested-in-match-2' => ['/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */'], - 'class-constant-as-long-array-key-with-nested-match' => ['/* testClassConstantAsLongArrayKeyWithNestedMatch */'], - 'class-constant-as-short-array-key-with-nested-match' => ['/* testClassConstantAsShortArrayKeyWithNestedMatch */'], - - 'class-constant-in-switch-case' => ['/* testClassConstantInSwitchCase */'], - 'class-property-in-switch-case' => ['/* testClassPropertyInSwitchCase */'], - 'namespaced-constant-in-switch-case' => ['/* testNamespacedConstantInSwitchCase */'], - 'namespace-relative-constant-in-switch-case' => ['/* testNamespaceRelativeConstantInSwitchCase */'], - - 'class-constant-declaration' => ['/* testClassConstant */'], + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], 'class-method-declaration' => [ - '/* testMethodDeclaration */', - 'default', + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', ], ]; @@ -283,11 +325,14 @@ public function dataNotDefaultKeyword() * * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * * @return void */ public function testIssue3326() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); $tokenArray = $tokens[$token]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php index ad1a411ff..768ff65d7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php @@ -6,14 +6,12 @@ * * @author Juliette Reinders Folmer * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class DoubleArrowTest extends AbstractMethodUnitTest +final class DoubleArrowTest extends AbstractTokenizerTestCase { @@ -29,7 +27,7 @@ class DoubleArrowTest extends AbstractMethodUnitTest */ public function testDoubleArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -45,9 +43,9 @@ public function testDoubleArrow($testMarker) * * @see testDoubleArrow() * - * @return array + * @return array> */ - public function dataDoubleArrow() + public static function dataDoubleArrow() { return [ 'simple_long_array' => ['/* testLongArrayArrowSimple */'], @@ -114,7 +112,7 @@ public function dataDoubleArrow() */ public function testMatchArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -130,9 +128,9 @@ public function testMatchArrow($testMarker) * * @see testMatchArrow() * - * @return array + * @return array> */ - public function dataMatchArrow() + public static function dataMatchArrow() { return [ 'single_case' => ['/* testMatchArrowSimpleSingleCase */'], @@ -201,7 +199,7 @@ public function dataMatchArrow() */ public function testFnArrow($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_DOUBLE_ARROW, T_MATCH_ARROW, T_FN_ARROW]); $tokenArray = $tokens[$token]; @@ -217,9 +215,9 @@ public function testFnArrow($testMarker) * * @see testFnArrow() * - * @return array + * @return array> */ - public function dataFnArrow() + public static function dataFnArrow() { return [ 'simple_fn' => ['/* testFnArrowSimple */'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php index cc9fe49ec..83ba0aab7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php @@ -5,14 +5,12 @@ * * @author Juliette Reinders Folmer * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class DoubleQuotedStringTest extends AbstractMethodUnitTest +final class DoubleQuotedStringTest extends AbstractTokenizerTestCase { @@ -29,7 +27,7 @@ class DoubleQuotedStringTest extends AbstractMethodUnitTest */ public function testDoubleQuotedString($testMarker, $expectedContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $target = $this->getTargetToken($testMarker, T_DOUBLE_QUOTED_STRING); $this->assertSame($expectedContent, $tokens[$target]['content']); @@ -40,90 +38,98 @@ public function testDoubleQuotedString($testMarker, $expectedContent) /** * Data provider. * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * * @see testDoubleQuotedString() * - * @return array + * @return array> */ - public function dataDoubleQuotedString() + public static function dataDoubleQuotedString() { return [ - [ + 'Type 1: simple variable' => [ 'testMarker' => '/* testSimple1 */', 'expectedContent' => '"$foo"', ], - [ + 'Type 2: simple variable' => [ 'testMarker' => '/* testSimple2 */', 'expectedContent' => '"{$foo}"', ], - [ + 'Type 3: simple variable' => [ 'testMarker' => '/* testSimple3 */', 'expectedContent' => '"${foo}"', ], - [ + 'Type 1: array offset' => [ 'testMarker' => '/* testDIM1 */', 'expectedContent' => '"$foo[bar]"', ], - [ + 'Type 2: array offset' => [ 'testMarker' => '/* testDIM2 */', 'expectedContent' => '"{$foo[\'bar\']}"', ], - [ + 'Type 3: array offset' => [ 'testMarker' => '/* testDIM3 */', 'expectedContent' => '"${foo[\'bar\']}"', ], - [ + 'Type 1: object property' => [ 'testMarker' => '/* testProperty1 */', 'expectedContent' => '"$foo->bar"', ], - [ + 'Type 2: object property' => [ 'testMarker' => '/* testProperty2 */', 'expectedContent' => '"{$foo->bar}"', ], - [ + 'Type 2: object method call' => [ 'testMarker' => '/* testMethod1 */', 'expectedContent' => '"{$foo->bar()}"', ], - [ + 'Type 2: closure function call' => [ 'testMarker' => '/* testClosure1 */', 'expectedContent' => '"{$foo()}"', ], - [ + 'Type 2: chaining various syntaxes' => [ 'testMarker' => '/* testChain1 */', 'expectedContent' => '"{$foo[\'bar\']->baz()()}"', ], - [ + 'Type 4: variable variables' => [ 'testMarker' => '/* testVariableVar1 */', 'expectedContent' => '"${$bar}"', ], - [ + 'Type 4: variable constants' => [ 'testMarker' => '/* testVariableVar2 */', 'expectedContent' => '"${(foo)}"', ], - [ + 'Type 4: object property' => [ 'testMarker' => '/* testVariableVar3 */', 'expectedContent' => '"${foo->bar}"', ], - [ + 'Type 4: variable variable nested in array offset' => [ 'testMarker' => '/* testNested1 */', 'expectedContent' => '"${foo["${bar}"]}"', ], - [ + 'Type 4: variable array offset nested in array offset' => [ 'testMarker' => '/* testNested2 */', 'expectedContent' => '"${foo["${bar[\'baz\']}"]}"', ], - [ + 'Type 4: variable object property' => [ 'testMarker' => '/* testNested3 */', 'expectedContent' => '"${foo->{$baz}}"', ], - [ + 'Type 4: variable object property - complex with single quotes' => [ 'testMarker' => '/* testNested4 */', 'expectedContent' => '"${foo->{${\'a\'}}}"', ], - [ + 'Type 4: variable object property - complex with single and double quotes' => [ 'testMarker' => '/* testNested5 */', 'expectedContent' => '"${foo->{"${\'a\'}"}}"', ], - [ + 'Type 4: live coding/parse error' => [ 'testMarker' => '/* testParseError */', 'expectedContent' => '"${foo["${bar ', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php index 61141da4f..f5b68507d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php @@ -4,14 +4,12 @@ * * @author Jaroslav Hanslík * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class EnumCaseTest extends AbstractMethodUnitTest +final class EnumCaseTest extends AbstractTokenizerTestCase { @@ -28,16 +26,16 @@ class EnumCaseTest extends AbstractMethodUnitTest */ public function testEnumCases($testMarker) { - $tokens = self::$phpcsFile->getTokens(); - - $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; - $this->assertSame(T_ENUM_CASE, $tokens[$enumCase]['code']); - $this->assertSame('T_ENUM_CASE', $tokens[$enumCase]['type']); + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + $this->assertSame('T_ENUM_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (type)'); - $this->assertArrayNotHasKey('scope_condition', $tokens[$enumCase], 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokens[$enumCase], 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokens[$enumCase], 'Scope closer is set'); + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); }//end testEnumCases() @@ -47,18 +45,18 @@ public function testEnumCases($testMarker) * * @see testEnumCases() * - * @return array + * @return array> */ - public function dataEnumCases() + public static function dataEnumCases() { return [ - ['/* testPureEnumCase */'], - ['/* testBackingIntegerEnumCase */'], - ['/* testBackingStringEnumCase */'], - ['/* testEnumCaseInComplexEnum */'], - ['/* testEnumCaseIsCaseInsensitive */'], - ['/* testEnumCaseAfterSwitch */'], - ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], ]; }//end dataEnumCases() @@ -77,16 +75,16 @@ public function dataEnumCases() */ public function testNotEnumCases($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$case]; - $case = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + $this->assertSame('T_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (type)'); - $this->assertSame(T_CASE, $tokens[$case]['code']); - $this->assertSame('T_CASE', $tokens[$case]['type']); - - $this->assertArrayHasKey('scope_condition', $tokens[$case], 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$case], 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$case], 'Scope closer is not set'); + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); }//end testNotEnumCases() @@ -96,18 +94,18 @@ public function testNotEnumCases($testMarker) * * @see testNotEnumCases() * - * @return array + * @return array> */ - public function dataNotEnumCases() + public static function dataNotEnumCases() { return [ - ['/* testCaseWithSemicolonIsNotEnumCase */'], - ['/* testCaseWithConstantIsNotEnumCase */'], - ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], - ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], - ['/* testIsNotEnumCaseIsCaseInsensitive */'], - ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], - ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], + 'switch case with constant, semicolon condition end' => ['/* testCaseWithSemicolonIsNotEnumCase */'], + 'switch case with constant, colon condition end' => ['/* testCaseWithConstantIsNotEnumCase */'], + 'switch case with constant, comparison' => ['/* testCaseWithConstantAndIdenticalIsNotEnumCase */'], + 'switch case with constant, assignment' => ['/* testCaseWithAssigmentToConstantIsNotEnumCase */'], + 'switch case with constant, keyword in mixed case' => ['/* testIsNotEnumCaseIsCaseInsensitive */'], + 'switch case, body in curlies declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch1 */'], + 'switch case, body after semicolon declares enum' => ['/* testCaseInSwitchWhenCreatingEnumInSwitch2 */'], ]; }//end dataNotEnumCases() @@ -125,12 +123,12 @@ public function dataNotEnumCases() */ public function testKeywordAsEnumCaseNameShouldBeString($testMarker) { - $tokens = self::$phpcsFile->getTokens(); - + $tokens = $this->phpcsFile->getTokens(); $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; - $this->assertSame(T_STRING, $tokens[$enumCaseName]['code']); - $this->assertSame('T_STRING', $tokens[$enumCaseName]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testKeywordAsEnumCaseNameShouldBeString() @@ -140,15 +138,18 @@ public function testKeywordAsEnumCaseNameShouldBeString($testMarker) * * @see testKeywordAsEnumCaseNameShouldBeString() * - * @return array + * @return array> */ - public function dataKeywordAsEnumCaseNameShouldBeString() + public static function dataKeywordAsEnumCaseNameShouldBeString() { return [ - ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], - ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], ]; }//end dataKeywordAsEnumCaseNameShouldBeString() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php index 2b28bc5d3..a73ac57e5 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class FinallyTest extends AbstractMethodUnitTest +final class FinallyTest extends AbstractTokenizerTestCase { @@ -27,11 +25,12 @@ class FinallyTest extends AbstractMethodUnitTest */ public function testFinallyKeyword($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; - $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); - $this->assertSame(T_FINALLY, $tokens[$target]['code']); - $this->assertSame('T_FINALLY', $tokens[$target]['type']); + $this->assertSame(T_FINALLY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (code)'); + $this->assertSame('T_FINALLY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_FINALLY (type)'); }//end testFinallyKeyword() @@ -41,14 +40,14 @@ public function testFinallyKeyword($testMarker) * * @see testFinallyKeyword() * - * @return array + * @return array> */ - public function dataFinallyKeyword() + public static function dataFinallyKeyword() { return [ - ['/* testTryCatchFinally */'], - ['/* testTryFinallyCatch */'], - ['/* testTryFinally */'], + 'finally after try and catch' => ['/* testTryCatchFinally */'], + 'finally between try and catch' => ['/* testTryFinallyCatch */'], + 'finally after try, no catch' => ['/* testTryFinally */'], ]; }//end dataFinallyKeyword() @@ -66,11 +65,12 @@ public function dataFinallyKeyword() */ public function testFinallyNonKeyword($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); + $tokenArray = $tokens[$target]; - $target = $this->getTargetToken($testMarker, [T_FINALLY, T_STRING]); - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testFinallyNonKeyword() @@ -80,14 +80,14 @@ public function testFinallyNonKeyword($testMarker) * * @see testFinallyNonKeyword() * - * @return array + * @return array> */ - public function dataFinallyNonKeyword() + public static function dataFinallyNonKeyword() { return [ - ['/* testFinallyUsedAsClassConstantName */'], - ['/* testFinallyUsedAsMethodName */'], - ['/* testFinallyUsedAsPropertyName */'], + 'finally used as class constant name' => ['/* testFinallyUsedAsClassConstantName */'], + 'finally used as method name' => ['/* testFinallyUsedAsMethodName */'], + 'finally used as property name' => ['/* testFinallyUsedAsPropertyName */'], ]; }//end dataFinallyNonKeyword() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php index 0f937cc8b..6917e939e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class GotoLabelTest extends AbstractMethodUnitTest +final class GotoLabelTest extends AbstractTokenizerTestCase { @@ -28,11 +26,11 @@ class GotoLabelTest extends AbstractMethodUnitTest */ public function testGotoStatement($testMarker, $testContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken($testMarker, T_STRING); - $this->assertInternalType('int', $label); + $this->assertTrue(is_int($label)); $this->assertSame($testContent, $tokens[$label]['content']); }//end testGotoStatement() @@ -43,18 +41,18 @@ public function testGotoStatement($testMarker, $testContent) * * @see testGotoStatement() * - * @return array + * @return array> */ - public function dataGotoStatement() + public static function dataGotoStatement() { return [ - [ - '/* testGotoStatement */', - 'marker', + 'label for goto statement' => [ + 'testMarker' => '/* testGotoStatement */', + 'testContent' => 'marker', ], - [ - '/* testGotoStatementInLoop */', - 'end', + 'label for goto statement in loop, keyword capitalized' => [ + 'testMarker' => '/* testGotoStatementInLoop */', + 'testContent' => 'end', ], ]; @@ -74,11 +72,11 @@ public function dataGotoStatement() */ public function testGotoDeclaration($testMarker, $testContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken($testMarker, T_GOTO_LABEL); - $this->assertInternalType('int', $label); + $this->assertTrue(is_int($label)); $this->assertSame($testContent, $tokens[$label]['content']); }//end testGotoDeclaration() @@ -89,18 +87,18 @@ public function testGotoDeclaration($testMarker, $testContent) * * @see testGotoDeclaration() * - * @return array + * @return array> */ - public function dataGotoDeclaration() + public static function dataGotoDeclaration() { return [ - [ - '/* testGotoDeclaration */', - 'marker:', + 'label in goto declaration - marker' => [ + 'testMarker' => '/* testGotoDeclaration */', + 'testContent' => 'marker:', ], - [ - '/* testGotoDeclarationOutsideLoop */', - 'end:', + 'label in goto declaration - end' => [ + 'testMarker' => '/* testGotoDeclarationOutsideLoop */', + 'testContent' => 'end:', ], ]; @@ -120,11 +118,12 @@ public function dataGotoDeclaration() */ public function testNotAGotoDeclaration($testMarker, $testContent) { - $tokens = self::$phpcsFile->getTokens(); - $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); + $tokenArray = $tokens[$target]; - $this->assertSame(T_STRING, $tokens[$target]['code']); - $this->assertSame('T_STRING', $tokens[$target]['type']); + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); }//end testNotAGotoDeclaration() @@ -134,38 +133,38 @@ public function testNotAGotoDeclaration($testMarker, $testContent) * * @see testNotAGotoDeclaration() * - * @return array + * @return array> */ - public function dataNotAGotoDeclaration() + public static function dataNotAGotoDeclaration() { return [ - [ - '/* testNotGotoDeclarationGlobalConstant */', - 'CONSTANT', + 'not goto label - global constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstant */', + 'testContent' => 'CONSTANT', ], - [ - '/* testNotGotoDeclarationNamespacedConstant */', - 'CONSTANT', + 'not goto label - namespaced constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationNamespacedConstant */', + 'testContent' => 'CONSTANT', ], - [ - '/* testNotGotoDeclarationClassConstant */', - 'CONSTANT', + 'not goto label - class constant followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassConstant */', + 'testContent' => 'CONSTANT', ], - [ - '/* testNotGotoDeclarationClassProperty */', - 'property', + 'not goto label - class property use followed by switch-case colon' => [ + 'testMarker' => '/* testNotGotoDeclarationClassProperty */', + 'testContent' => 'property', ], - [ - '/* testNotGotoDeclarationGlobalConstantInTernary */', - 'CONST_A', + 'not goto label - global constant followed by ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_A', ], - [ - '/* testNotGotoDeclarationGlobalConstantInTernary */', - 'CONST_B', + 'not goto label - global constant after ternary else' => [ + 'testMarker' => '/* testNotGotoDeclarationGlobalConstantInTernary */', + 'testContent' => 'CONST_B', ], - [ - '/* testNotGotoDeclarationEnumWithType */', - 'Suit', + 'not goto label - name of backed enum' => [ + 'testMarker' => '/* testNotGotoDeclarationEnumWithType */', + 'testContent' => 'Suit', ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php index 6e3224070..d43768f0e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php @@ -1,64 +1,28 @@ * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Config; -use PHP_CodeSniffer\Ruleset; -use PHP_CodeSniffer\Files\DummyFile; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - /** * Heredoc/nowdoc closer token test. * * @requires PHP 7.3 */ -class HeredocNowdocCloserTest extends AbstractMethodUnitTest +final class HeredocNowdocCloserTest extends AbstractTokenizerTestCase { - /** - * Initialize & tokenize \PHP_CodeSniffer\Files\File with code from the test case file. - * - * {@internal This is a near duplicate of the original method. Only difference is that - * tab replacement is enabled for this test.} - * - * @return void - */ - public static function setUpBeforeClass() - { - $config = new Config(); - $config->standards = ['PSR1']; - $config->tabWidth = 4; - - $ruleset = new Ruleset($config); - - // Default to a file with the same name as the test class. Extension is property based. - $relativeCN = str_replace(__NAMESPACE__, '', get_called_class()); - $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativeCN); - $pathToTestFile = realpath(__DIR__).$relativePath.'.'.static::$fileExtension; - - // Make sure the file gets parsed correctly based on the file type. - $contents = 'phpcs_input_file: '.$pathToTestFile.PHP_EOL; - $contents .= file_get_contents($pathToTestFile); - - self::$phpcsFile = new DummyFile($contents, $ruleset, $config); - self::$phpcsFile->process(); - - }//end setUpBeforeClass() - - /** * Verify that leading (indent) whitespace in a heredoc/nowdoc closer token get the tab replacement treatment. * - * @param string $testMarker The comment prefacing the target token. - * @param array $expected Expectations for the token array. + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. * * @dataProvider dataHeredocNowdocCloserTabReplacement * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap @@ -67,7 +31,7 @@ public static function setUpBeforeClass() */ public function testHeredocNowdocCloserTabReplacement($testMarker, $expected) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $closer = $this->getTargetToken($testMarker, [T_END_HEREDOC, T_END_NOWDOC]); @@ -89,12 +53,12 @@ public function testHeredocNowdocCloserTabReplacement($testMarker, $expected) * * @see testHeredocNowdocCloserTabReplacement() * - * @return array + * @return array>> */ - public function dataHeredocNowdocCloserTabReplacement() + public static function dataHeredocNowdocCloserTabReplacement() { return [ - [ + 'Heredoc closer without indent' => [ 'testMarker' => '/* testHeredocCloserNoIndent */', 'expected' => [ 'length' => 3, @@ -102,7 +66,7 @@ public function dataHeredocNowdocCloserTabReplacement() 'orig_content' => null, ], ], - [ + 'Nowdoc closer without indent' => [ 'testMarker' => '/* testNowdocCloserNoIndent */', 'expected' => [ 'length' => 3, @@ -110,7 +74,7 @@ public function dataHeredocNowdocCloserTabReplacement() 'orig_content' => null, ], ], - [ + 'Heredoc closer with indent, spaces' => [ 'testMarker' => '/* testHeredocCloserSpaceIndent */', 'expected' => [ 'length' => 7, @@ -118,7 +82,7 @@ public function dataHeredocNowdocCloserTabReplacement() 'orig_content' => null, ], ], - [ + 'Nowdoc closer with indent, spaces' => [ 'testMarker' => '/* testNowdocCloserSpaceIndent */', 'expected' => [ 'length' => 8, @@ -126,7 +90,7 @@ public function dataHeredocNowdocCloserTabReplacement() 'orig_content' => null, ], ], - [ + 'Heredoc closer with indent, tabs' => [ 'testMarker' => '/* testHeredocCloserTabIndent */', 'expected' => [ 'length' => 8, @@ -134,7 +98,7 @@ public function dataHeredocNowdocCloserTabReplacement() 'orig_content' => ' END', ], ], - [ + 'Nowdoc closer with indent, tabs' => [ 'testMarker' => '/* testNowdocCloserTabIndent */', 'expected' => [ 'length' => 7, diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php index 2c808be90..da3f361b2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php @@ -5,14 +5,12 @@ * * @author Juliette Reinders Folmer * @copyright 2022 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class HeredocStringTest extends AbstractMethodUnitTest +final class HeredocStringTest extends AbstractTokenizerTestCase { @@ -29,7 +27,7 @@ class HeredocStringTest extends AbstractMethodUnitTest */ public function testHeredocString($testMarker, $expectedContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $target = $this->getTargetToken($testMarker, T_HEREDOC); $this->assertSame($expectedContent."\n", $tokens[$target]['content']); @@ -50,7 +48,7 @@ public function testHeredocString($testMarker, $expectedContent) */ public function testHeredocStringWrapped($testMarker, $expectedContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $testMarker = substr($testMarker, 0, -3).'Wrapped */'; $target = $this->getTargetToken($testMarker, T_HEREDOC); @@ -62,86 +60,94 @@ public function testHeredocStringWrapped($testMarker, $expectedContent) /** * Data provider. * + * Type reference: + * 1. Directly embedded variables. + * 2. Braces outside the variable. + * 3. Braces after the dollar sign. + * 4. Variable variables and expressions. + * + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation + * * @see testHeredocString() * - * @return array + * @return array> */ - public function dataHeredocString() + public static function dataHeredocString() { return [ - [ + 'Type 1: simple variable' => [ 'testMarker' => '/* testSimple1 */', 'expectedContent' => '$foo', ], - [ + 'Type 2: simple variable' => [ 'testMarker' => '/* testSimple2 */', 'expectedContent' => '{$foo}', ], - [ + 'Type 3: simple variable' => [ 'testMarker' => '/* testSimple3 */', 'expectedContent' => '${foo}', ], - [ + 'Type 1: array offset' => [ 'testMarker' => '/* testDIM1 */', 'expectedContent' => '$foo[bar]', ], - [ + 'Type 2: array offset' => [ 'testMarker' => '/* testDIM2 */', 'expectedContent' => '{$foo[\'bar\']}', ], - [ + 'Type 3: array offset' => [ 'testMarker' => '/* testDIM3 */', 'expectedContent' => '${foo[\'bar\']}', ], - [ + 'Type 1: object property' => [ 'testMarker' => '/* testProperty1 */', 'expectedContent' => '$foo->bar', ], - [ + 'Type 2: object property' => [ 'testMarker' => '/* testProperty2 */', 'expectedContent' => '{$foo->bar}', ], - [ + 'Type 2: object method call' => [ 'testMarker' => '/* testMethod1 */', 'expectedContent' => '{$foo->bar()}', ], - [ + 'Type 2: closure function call' => [ 'testMarker' => '/* testClosure1 */', 'expectedContent' => '{$foo()}', ], - [ + 'Type 2: chaining various syntaxes' => [ 'testMarker' => '/* testChain1 */', 'expectedContent' => '{$foo[\'bar\']->baz()()}', ], - [ + 'Type 4: variable variables' => [ 'testMarker' => '/* testVariableVar1 */', 'expectedContent' => '${$bar}', ], - [ + 'Type 4: variable constants' => [ 'testMarker' => '/* testVariableVar2 */', 'expectedContent' => '${(foo)}', ], - [ + 'Type 4: object property' => [ 'testMarker' => '/* testVariableVar3 */', 'expectedContent' => '${foo->bar}', ], - [ + 'Type 4: variable variable nested in array offset' => [ 'testMarker' => '/* testNested1 */', 'expectedContent' => '${foo["${bar}"]}', ], - [ + 'Type 4: variable array offset nested in array offset' => [ 'testMarker' => '/* testNested2 */', 'expectedContent' => '${foo["${bar[\'baz\']}"]}', ], - [ + 'Type 4: variable object property' => [ 'testMarker' => '/* testNested3 */', 'expectedContent' => '${foo->{$baz}}', ], - [ + 'Type 4: variable object property - complex with single quotes' => [ 'testMarker' => '/* testNested4 */', 'expectedContent' => '${foo->{${\'a\'}}}', ], - [ + 'Type 4: variable object property - complex with single and double quotes' => [ 'testMarker' => '/* testNested5 */', 'expectedContent' => '${foo->{"${\'a\'}"}}', ], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc index b9c0df24d..2f1d20bf0 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc @@ -32,13 +32,13 @@ array_fill( value: 50 ); -/* testNamespaceOperatorFunction */ +/* testNamespaceRelativeFunction */ namespace\function_name(label:$string, more: false); -/* testNamespaceRelativeFunction */ +/* testPartiallyQualifiedFunction */ Partially\Qualified\function_name(label:$string, more: false); -/* testNamespacedFQNFunction */ +/* testFullyQualifiedFunction */ \Fully\Qualified\function_name(label: $string, more:false); /* testVariableFunction */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php index cc57637c6..058129f56 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php @@ -1,18 +1,17 @@ * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class NamedFunctionCallArgumentsTest extends AbstractMethodUnitTest +final class NamedFunctionCallArgumentsTest extends AbstractTokenizerTestCase { @@ -20,8 +19,8 @@ class NamedFunctionCallArgumentsTest extends AbstractMethodUnitTest * Verify that parameter labels are tokenized as T_PARAM_NAME and that * the colon after it is tokenized as a T_COLON. * - * @param string $testMarker The comment prefacing the target token. - * @param array $parameters The token content for each parameter label to look for. + * @param string $testMarker The comment prefacing the target token. + * @param array $parameters The token content for each parameter label to look for. * * @dataProvider dataNamedFunctionCallArguments * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -30,7 +29,7 @@ class NamedFunctionCallArgumentsTest extends AbstractMethodUnitTest */ public function testNamedFunctionCallArguments($testMarker, $parameters) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); foreach ($parameters as $content) { $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); @@ -47,7 +46,7 @@ public function testNamedFunctionCallArguments($testMarker, $parameters) ); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -74,135 +73,141 @@ public function testNamedFunctionCallArguments($testMarker, $parameters) * * @see testNamedFunctionCallArguments() * - * @return array + * @return array>> */ - public function dataNamedFunctionCallArguments() + public static function dataNamedFunctionCallArguments() { return [ - [ - '/* testNamedArgs */', - [ + 'function call, single line, all named args' => [ + 'testMarker' => '/* testNamedArgs */', + 'parameters' => [ 'start_index', 'count', 'value', ], ], - [ - '/* testNamedArgsMultiline */', - [ + 'function call, multi-line, all named args' => [ + 'testMarker' => '/* testNamedArgsMultiline */', + 'parameters' => [ 'start_index', 'count', 'value', ], ], - [ - '/* testNamedArgsWithWhitespaceAndComments */', - [ + 'function call, single line, all named args; comments and whitespace' => [ + 'testMarker' => '/* testNamedArgsWithWhitespaceAndComments */', + 'parameters' => [ 'start_index', 'count', 'value', ], ], - [ - '/* testMixedPositionalAndNamedArgs */', - ['double_encode'], + 'function call, single line, mixed positional and named args' => [ + 'testMarker' => '/* testMixedPositionalAndNamedArgs */', + 'parameters' => [ + 'double_encode', + ], ], - [ - '/* testNestedFunctionCallOuter */', - [ + 'function call containing nested function call values' => [ + 'testMarker' => '/* testNestedFunctionCallOuter */', + 'parameters' => [ 'start_index', 'count', 'value', ], ], - [ - '/* testNestedFunctionCallInner1 */', - ['skip'], + 'function call nested in named arg [1]' => [ + 'testMarker' => '/* testNestedFunctionCallInner1 */', + 'parameters' => [ + 'skip', + ], ], - [ - '/* testNestedFunctionCallInner2 */', - ['array_or_countable'], + 'function call nested in named arg [2]' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'parameters' => [ + 'array_or_countable', + ], ], - [ - '/* testNamespaceOperatorFunction */', - [ + 'namespace relative function call' => [ + 'testMarker' => '/* testNamespaceRelativeFunction */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testNamespaceRelativeFunction */', - [ + 'partially qualified function call' => [ + 'testMarker' => '/* testPartiallyQualifiedFunction */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testNamespacedFQNFunction */', - [ + 'fully qualified function call' => [ + 'testMarker' => '/* testFullyQualifiedFunction */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testVariableFunction */', - [ + 'variable function call' => [ + 'testMarker' => '/* testVariableFunction */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testVariableVariableFunction */', - [ + 'variable variable function call' => [ + 'testMarker' => '/* testVariableVariableFunction */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testMethodCall */', - [ + 'method call' => [ + 'testMarker' => '/* testMethodCall */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testVariableMethodCall */', - [ + 'variable method call' => [ + 'testMarker' => '/* testVariableMethodCall */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testClassInstantiation */', - [ + 'class instantiation' => [ + 'testMarker' => '/* testClassInstantiation */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testClassInstantiationSelf */', - [ + 'class instantiation with "self"' => [ + 'testMarker' => '/* testClassInstantiationSelf */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testClassInstantiationStatic */', - [ + 'class instantiation with "static"' => [ + 'testMarker' => '/* testClassInstantiationStatic */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testAnonClass */', - [ + 'anonymous class instantiation' => [ + 'testMarker' => '/* testAnonClass */', + 'parameters' => [ 'label', 'more', ], ], - [ - '/* testNonAsciiNames */', - [ + 'function call with non-ascii characters in the variable name labels' => [ + 'testMarker' => '/* testNonAsciiNames */', + 'parameters' => [ '💩💩💩', 'Пасха', '_valid', @@ -210,48 +215,66 @@ public function dataNamedFunctionCallArguments() ], // Coding errors which should still be handled. - [ - '/* testCompileErrorNamedBeforePositional */', - ['param'], + 'invalid: named arg before positional (compile error)' => [ + 'testMarker' => '/* testCompileErrorNamedBeforePositional */', + 'parameters' => [ + 'param', + ], ], - [ - '/* testDuplicateName1 */', - ['param'], + 'invalid: duplicate parameter name [1]' => [ + 'testMarker' => '/* testDuplicateName1 */', + 'parameters' => [ + 'param', + ], ], - [ - '/* testDuplicateName2 */', - ['param'], + 'invalid: duplicate parameter name [2]' => [ + 'testMarker' => '/* testDuplicateName2 */', + 'parameters' => [ + 'param', + ], ], - [ - '/* testIncorrectOrderWithVariadic */', - ['start_index'], + 'invalid: named arg before variadic (error exception)' => [ + 'testMarker' => '/* testIncorrectOrderWithVariadic */', + 'parameters' => [ + 'start_index', + ], ], - [ - '/* testCompileErrorIncorrectOrderWithVariadic */', - ['param'], + 'invalid: named arg after variadic (compile error)' => [ + 'testMarker' => '/* testCompileErrorIncorrectOrderWithVariadic */', + 'parameters' => [ + 'param', + ], ], - [ - '/* testParseErrorNoValue */', - [ + 'invalid: named arg without value (parse error)' => [ + 'testMarker' => '/* testParseErrorNoValue */', + 'parameters' => [ 'param1', 'param2', ], ], - [ - '/* testParseErrorExit */', - ['status'], + 'invalid: named arg in exit() (parse error)' => [ + 'testMarker' => '/* testParseErrorExit */', + 'parameters' => [ + 'status', + ], ], - [ - '/* testParseErrorEmpty */', - ['variable'], + 'invalid: named arg in empty() (parse error)' => [ + 'testMarker' => '/* testParseErrorEmpty */', + 'parameters' => [ + 'variable', + ], ], - [ - '/* testParseErrorEval */', - ['code'], + 'invalid: named arg in eval() (parse error)' => [ + 'testMarker' => '/* testParseErrorEval */', + 'parameters' => [ + 'code', + ], ], - [ - '/* testParseErrorArbitraryParentheses */', - ['something'], + 'invalid: named arg in arbitrary parentheses (parse error)' => [ + 'testMarker' => '/* testParseErrorArbitraryParentheses */', + 'parameters' => [ + 'something', + ], ], ]; @@ -271,7 +294,7 @@ public function dataNamedFunctionCallArguments() */ public function testOtherTstringInFunctionCall($testMarker, $content) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken($testMarker, [T_STRING, T_PARAM_NAME], $content); @@ -294,26 +317,26 @@ public function testOtherTstringInFunctionCall($testMarker, $content) * * @see testOtherTstringInFunctionCall() * - * @return array + * @return array> */ - public function dataOtherTstringInFunctionCall() + public static function dataOtherTstringInFunctionCall() { return [ - [ - '/* testPositionalArgs */', - 'START_INDEX', + 'not arg name - global constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'START_INDEX', ], - [ - '/* testPositionalArgs */', - 'COUNT', + 'not arg name - fully qualified constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'COUNT', ], - [ - '/* testPositionalArgs */', - 'VALUE', + 'not arg name - namespace relative constant' => [ + 'testMarker' => '/* testPositionalArgs */', + 'content' => 'VALUE', ], - [ - '/* testNestedFunctionCallInner2 */', - 'count', + 'not arg name - unqualified function call' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'content' => 'count', ], ]; @@ -330,12 +353,12 @@ public function dataOtherTstringInFunctionCall() */ public function testMixedPositionalAndNamedArgsWithTernary() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $true = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_TRUE); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); $this->assertSame( T_INLINE_ELSE, @@ -351,7 +374,7 @@ public function testMixedPositionalAndNamedArgsWithTernary() $label = $this->getTargetToken('/* testMixedPositionalAndNamedArgsWithTernary */', T_PARAM_NAME, 'name'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -382,7 +405,7 @@ public function testMixedPositionalAndNamedArgsWithTernary() */ public function testNamedArgWithTernary() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); /* * First argument. @@ -391,7 +414,7 @@ public function testNamedArgWithTernary() $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'label'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -412,7 +435,7 @@ public function testNamedArgWithTernary() $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_TRUE); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); $this->assertSame( T_INLINE_ELSE, @@ -432,7 +455,7 @@ public function testNamedArgWithTernary() $label = $this->getTargetToken('/* testNamedArgWithTernary */', T_PARAM_NAME, 'more'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -453,7 +476,7 @@ public function testNamedArgWithTernary() $true = $this->getTargetToken('/* testNamedArgWithTernary */', T_STRING, 'CONSTANT_A'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($true + 1), null, true); $this->assertSame( T_INLINE_ELSE, @@ -479,7 +502,7 @@ public function testNamedArgWithTernary() */ public function testTernaryWithFunctionCallsInThenElse() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); /* * Then. @@ -488,7 +511,7 @@ public function testTernaryWithFunctionCallsInThenElse() $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'label'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -509,7 +532,7 @@ public function testTernaryWithFunctionCallsInThenElse() $closeParens = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_CLOSE_PARENTHESIS); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closeParens + 1), null, true); $this->assertSame( T_INLINE_ELSE, @@ -529,7 +552,7 @@ public function testTernaryWithFunctionCallsInThenElse() $label = $this->getTargetToken('/* testTernaryWithFunctionCallsInThenElse */', T_PARAM_NAME, 'more'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -559,12 +582,12 @@ public function testTernaryWithFunctionCallsInThenElse() */ public function testTernaryWithConstantsInThenElse() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $constant = $this->getTargetToken('/* testTernaryWithConstantsInThenElse */', T_STRING, 'CONSTANT_NAME'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($constant + 1), null, true); $this->assertSame( T_INLINE_ELSE, @@ -589,12 +612,12 @@ public function testTernaryWithConstantsInThenElse() */ public function testSwitchStatement() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken('/* testSwitchCaseWithConstant */', T_STRING, 'MY_CONSTANT'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( T_COLON, @@ -610,7 +633,7 @@ public function testSwitchStatement() $label = $this->getTargetToken('/* testSwitchCaseWithClassProperty */', T_STRING, 'property'); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( T_COLON, @@ -626,7 +649,7 @@ public function testSwitchStatement() $default = $this->getTargetToken('/* testSwitchDefault */', T_DEFAULT); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($default + 1), null, true); $this->assertSame( T_COLON, @@ -651,7 +674,7 @@ public function testSwitchStatement() */ public function testParseErrorVariableLabel() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken('/* testParseErrorDynamicName */', [T_VARIABLE, T_PARAM_NAME], '$variableStoringParamName'); @@ -667,7 +690,7 @@ public function testParseErrorVariableLabel() ); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -688,13 +711,78 @@ public function testParseErrorVariableLabel() }//end testParseErrorVariableLabel() + /** + * Verify whether the colons are tokenized correctly when a return type is used for an inline + * closure/arrow function declaration in a ternary. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataOtherColonsInTernary + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testOtherColonsInTernary($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $startOfStatement = $this->getTargetToken($testMarker, T_VARIABLE); + + // Walk the statement and check the tokenization. + // There should be no T_PARAM_NAME tokens. + // First colon should be T_COLON for the return type. + // Second colon should be T_INLINE_ELSE for the ternary. + // Third colon should be T_COLON for the return type. + $colonCount = 0; + for ($i = ($startOfStatement + 1); $tokens[$i]['line'] === $tokens[$startOfStatement]['line']; $i++) { + $this->assertNotEquals(T_PARAM_NAME, $tokens[$i]['code'], "Token $i is tokenized as parameter label"); + + if ($tokens[$i]['content'] === ':') { + ++$colonCount; + + if ($colonCount === 1) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'First colon is not tokenized as T_COLON'); + } else if ($colonCount === 2) { + $this->assertSame(T_INLINE_ELSE, $tokens[$i]['code'], 'Second colon is not tokenized as T_INLINE_ELSE'); + } else if ($colonCount === 3) { + $this->assertSame(T_COLON, $tokens[$i]['code'], 'Third colon is not tokenized as T_COLON'); + } else { + $this->fail('Unexpected colon encountered in statement'); + } + } + } + + }//end testOtherColonsInTernary() + + + /** + * Data provider. + * + * @see testOtherColonsInTernary() + * + * @return array> + */ + public static function dataOtherColonsInTernary() + { + return [ + 'closures with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithClosuresAndReturnTypes */', + ], + 'arrow functions with return types in ternary' => [ + 'testMarker' => '/* testTernaryWithArrowFunctionsAndReturnTypes */', + ], + ]; + + }//end dataOtherColonsInTernary() + + /** * Verify that reserved keywords used as a parameter label are tokenized as T_PARAM_NAME * and that the colon after it is tokenized as a T_COLON. * - * @param string $testMarker The comment prefacing the target token. - * @param array $tokenTypes The token codes to look for. - * @param string $tokenContent The token content to look for. + * @param string $testMarker The comment prefacing the target token. + * @param array $tokenTypes The token codes to look for. + * @param string $tokenContent The token content to look for. * * @dataProvider dataReservedKeywordsAsName * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -703,7 +791,7 @@ public function testParseErrorVariableLabel() */ public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenContent) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $label = $this->getTargetToken($testMarker, $tokenTypes, $tokenContent); $this->assertSame( @@ -718,7 +806,7 @@ public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenConte ); // Get the next non-empty token. - $colon = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); + $colon = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true); $this->assertSame( ':', @@ -744,9 +832,9 @@ public function testReservedKeywordsAsName($testMarker, $tokenTypes, $tokenConte * * @see testReservedKeywordsAsName() * - * @return array + * @return array>> */ - public function dataReservedKeywordsAsName() + public static function dataReservedKeywordsAsName() { $reservedKeywords = [ // '__halt_compiler', NOT TESTABLE diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php index 8e465a3be..f97ff6978 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php @@ -4,21 +4,20 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class NullsafeObjectOperatorTest extends AbstractMethodUnitTest +final class NullsafeObjectOperatorTest extends AbstractTokenizerTestCase { /** * Tokens to search for. * - * @var array + * @var array */ protected $find = [ T_NULLSAFE_OBJECT_OPERATOR, @@ -36,7 +35,7 @@ class NullsafeObjectOperatorTest extends AbstractMethodUnitTest */ public function testObjectOperator() { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $operator = $this->getTargetToken('/* testObjectOperator */', $this->find); $this->assertSame(T_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is object operator'); @@ -57,7 +56,7 @@ public function testObjectOperator() */ public function testNullsafeObjectOperator($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $operator = $this->getTargetToken($testMarker, $this->find); $this->assertSame(T_NULLSAFE_OBJECT_OPERATOR, $tokens[$operator]['code'], 'Failed asserting code is nullsafe object operator'); @@ -71,13 +70,13 @@ public function testNullsafeObjectOperator($testMarker) * * @see testNullsafeObjectOperator() * - * @return array + * @return array> */ - public function dataNullsafeObjectOperator() + public static function dataNullsafeObjectOperator() { return [ - ['/* testNullsafeObjectOperator */'], - ['/* testNullsafeObjectOperatorWriteContext */'], + 'nullsafe operator' => ['/* testNullsafeObjectOperator */'], + 'illegal nullsafe operator (write context)' => ['/* testNullsafeObjectOperatorWriteContext */'], ]; }//end dataNullsafeObjectOperator() @@ -97,14 +96,14 @@ public function dataNullsafeObjectOperator() */ public function testTernaryThen($testMarker, $testObjectOperator=false) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $operator = $this->getTargetToken($testMarker, $this->find); $this->assertSame(T_INLINE_THEN, $tokens[$operator]['code'], 'Failed asserting code is inline then'); $this->assertSame('T_INLINE_THEN', $tokens[$operator]['type'], 'Failed asserting type is inline then'); if ($testObjectOperator === true) { - $next = self::$phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true); + $next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($operator + 1), null, true); $this->assertSame(T_OBJECT_OPERATOR, $tokens[$next]['code'], 'Failed asserting code is object operator'); $this->assertSame('T_OBJECT_OPERATOR', $tokens[$next]['type'], 'Failed asserting type is object operator'); } @@ -117,21 +116,25 @@ public function testTernaryThen($testMarker, $testObjectOperator=false) * * @see testTernaryThen() * - * @return array + * @return array> */ - public function dataTernaryThen() + public static function dataTernaryThen() { return [ - ['/* testTernaryThen */'], - [ - '/* testParseErrorWhitespaceNotAllowed */', - true, + 'ternary then' => [ + 'testMarker' => '/* testTernaryThen */', ], - [ - '/* testParseErrorCommentNotAllowed */', - true, + 'whitespace between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorWhitespaceNotAllowed */', + 'testObjectOperator' => true, + ], + 'comment between question mark and object operator' => [ + 'testMarker' => '/* testParseErrorCommentNotAllowed */', + 'testObjectOperator' => true, + ], + 'parse error/live coding' => [ + 'testMarker' => '/* testLiveCoding */', ], - ['/* testLiveCoding */'], ]; }//end dataTernaryThen() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc new file mode 100644 index 000000000..50b2c2ee2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc @@ -0,0 +1,67 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer; + +/** + * Tests the conversion of PHPCS native context sensitive keyword tokens to T_STRING. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::standardiseToken + */ +final class OtherContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: parent' => ['/* testParent */'], + 'constant declaration: self' => ['/* testSelf */'], + 'constant declaration: false' => ['/* testFalse */'], + 'constant declaration: true' => ['/* testTrue */'], + 'constant declaration: null' => ['/* testNull */'], + + 'function declaration with return by ref: self' => ['/* testKeywordSelfAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: parent' => ['/* testKeywordParentAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: false' => ['/* testKeywordFalseAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: true' => ['/* testKeywordTrueAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: null' => ['/* testKeywordNullAfterFunctionByRefShouldBeString */'], + + 'function call: self' => ['/* testKeywordAsFunctionCallNameShouldBeStringSelf */'], + 'function call: parent' => ['/* testKeywordAsFunctionCallNameShouldBeStringParent */'], + 'function call: false' => ['/* testKeywordAsFunctionCallNameShouldBeStringFalse */'], + 'function call: true' => ['/* testKeywordAsFunctionCallNameShouldBeStringTrue */'], + 'function call: null; with comment between keyword and parentheses' => ['/* testKeywordAsFunctionCallNameShouldBeStringNull */'], + + 'class instantiation: false' => ['/* testClassInstantiationFalseIsString */'], + 'class instantiation: true' => ['/* testClassInstantiationTrueIsString */'], + 'class instantiation: null' => ['/* testClassInstantiationNullIsString */'], + + 'constant declaration: false as name after type' => ['/* testFalseIsNameForTypedConstant */'], + 'constant declaration: true as name after type' => ['/* testTrueIsNameForTypedConstant */'], + 'constant declaration: null as name after type' => ['/* testNullIsNameForTypedConstant */'], + 'constant declaration: self as name after type' => ['/* testSelfIsNameForTypedConstant */'], + 'constant declaration: parent as name after type' => ['/* testParentIsNameForTypedConstant */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array + */ + public static function dataKeywords() + { + return [ + 'self: param type declaration' => [ + 'testMarker' => '/* testSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: param type declaration' => [ + 'testMarker' => '/* testParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'parent: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + + 'false: param type declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: param type declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: param type declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: return type declaration in union' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: return type declaration in union' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: return type declaration in union' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: in comparison' => [ + 'testMarker' => '/* testFalseIsKeywordInComparison */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: in comparison' => [ + 'testMarker' => '/* testTrueIsKeywordInComparison */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: in comparison' => [ + 'testMarker' => '/* testNullIsKeywordInComparison */', + 'expectedTokenType' => 'T_NULL', + ], + + 'false: type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + ]; + + }//end dataKeywords() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.inc new file mode 100644 index 000000000..d7383d8e6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.inc @@ -0,0 +1,51 @@ + $var; + +/* testBooleanNot */ +$a = ! $var; + +/* testComma */ +echo $a, $b, $c; + +/* testAsperand */ +$a = @callMe(); + +/* testDollarAndCurlies */ +echo ${$var}; + +/* testBacktick */ +$a = `ls -e`; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php new file mode 100644 index 000000000..706b1fe3c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php @@ -0,0 +1,432 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer; + +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests that simple tokens are assigned the correct token type and code. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::resolveSimpleToken + */ +final class ResolveSimpleTokenTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Verify tokenization of parentheses, square brackets, curly brackets and a switch colon. + * + * @return void + */ + public function testBracesAndColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_VARIABLE, + T_OPEN_SQUARE_BRACKET, + T_LNUMBER, + T_CLOSE_SQUARE_BRACKET, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CASE, + T_STRING, + T_COLON, + T_BREAK, + T_SEMICOLON, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_SWITCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBracesAndColon() + + + /** + * Verify tokenization of colon after named parameter. + * + * @return void + */ + public function testNamedParamColon() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_PARAM_NAME, + T_COLON, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testNamedParamColon() + + + /** + * Verify tokenization of colon for a return type. + * + * @return void + */ + public function testReturnTypeColon() + { + $expectedSequence = [ + T_EQUAL, + T_CLOSURE, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_COLON, + T_STRING, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testReturnTypeColon() + + + /** + * Verify tokenization of a concatenation operator. + * + * @return void + */ + public function testConcat() + { + $expectedSequence = [ + T_STRING_CONCAT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CONSTANT_ENCAPSED_STRING); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testConcat() + + + /** + * Verify tokenization of simple math operators. + * + * @return void + */ + public function testSimpleMathTokens() + { + $expectedSequence = [ + T_EQUAL, + T_LNUMBER, + T_MULTIPLY, + T_LNUMBER, + T_DIVIDE, + T_LNUMBER, + T_PLUS, + T_LNUMBER, + T_MINUS, + T_LNUMBER, + T_MODULUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testSimpleMathTokens() + + + /** + * Verify tokenization of unary plus/minus operators. + * + * @return void + */ + public function testUnaryPlusMinus() + { + $expectedSequence = [ + T_EQUAL, + T_PLUS, + T_LNUMBER, + T_DIVIDE, + T_MINUS, + T_LNUMBER, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testUnaryPlusMinus() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseTokens() + { + $expectedSequence = [ + T_EQUAL, + T_STRING, + T_BITWISE_XOR, + T_STRING, + T_BITWISE_AND, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_BITWISE_NOT, + T_STRING, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseTokens() + + + /** + * Verify tokenization of bitwise operator tokens. + * + * @return void + */ + public function testBitwiseOrInCatch() + { + $expectedSequence = [ + T_OPEN_PARENTHESIS, + T_STRING, + T_BITWISE_OR, + T_STRING, + T_VARIABLE, + T_CLOSE_PARENTHESIS, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_CATCH); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBitwiseOrInCatch() + + + /** + * Verify tokenization of a less than operator. + * + * @return void + */ + public function testLessThan() + { + $expectedSequence = [ + T_LESS_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testLessThan() + + + /** + * Verify tokenization of a greater than operator. + * + * @return void + */ + public function testGreaterThan() + { + $expectedSequence = [ + T_GREATER_THAN, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_LNUMBER); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testGreaterThan() + + + /** + * Verify tokenization of a boolean not operator. + * + * @return void + */ + public function testBooleanNot() + { + $expectedSequence = [ + T_BOOLEAN_NOT, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBooleanNot() + + + /** + * Verify tokenization of commas. + * + * @return void + */ + public function testComma() + { + $expectedSequence = [ + T_COMMA, + T_VARIABLE, + T_COMMA, + T_VARIABLE, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_VARIABLE); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testComma() + + + /** + * Verify tokenization of the silence operator. + * + * @return void + */ + public function testAsperand() + { + $expectedSequence = [ + T_ASPERAND, + T_STRING, + T_OPEN_PARENTHESIS, + T_CLOSE_PARENTHESIS, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testAsperand() + + + /** + * Verify tokenization of the dollar token and curlies for a variable variable. + * + * @return void + */ + public function testDollarAndCurlies() + { + $expectedSequence = [ + T_DOLLAR, + T_OPEN_CURLY_BRACKET, + T_VARIABLE, + T_CLOSE_CURLY_BRACKET, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_ECHO); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testDollarAndCurlies() + + + /** + * Verify tokenization of the backtick operator. + * + * @return void + */ + public function testBacktick() + { + $expectedSequence = [ + T_BACKTICK, + T_ENCAPSED_AND_WHITESPACE, + T_BACKTICK, + T_SEMICOLON, + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_EQUAL); + + $this->checkTokenSequence(($target + 1), $expectedSequence); + + }//end testBacktick() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array $expectedSequence The consecutive token constants to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those for these tests. + continue; + } + + $expectedTokenName = Tokens::tokenName($expectedSequence[$sequenceKey]); + + $this->assertSame( + $expectedSequence[$sequenceKey], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedTokenName.' (code)' + ); + + $this->assertSame( + $expectedTokenName, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedTokenName.' (type)' + ); + + ++$sequenceKey; + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php index 23cbd9877..5359b7282 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php @@ -1,27 +1,25 @@ * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ScopeSettingWithNamespaceOperatorTest extends AbstractMethodUnitTest +final class ScopeSettingWithNamespaceOperatorTest extends AbstractTokenizerTestCase { /** * Test that the scope opener/closers are set correctly when the namespace keyword is encountered as an operator. * - * @param string $testMarker The comment which prefaces the target tokens in the test file. - * @param int|string[] $tokenTypes The token type to search for. - * @param int|string[] $open Optional. The token type for the scope opener. - * @param int|string[] $close Optional. The token type for the scope closer. + * @param string $testMarker The comment which prefaces the target tokens in the test file. + * @param array $tokenTypes The token type to search for. + * @param array $open Optional. The token type for the scope opener. + * @param array $close Optional. The token type for the scope closer. * * @dataProvider dataScopeSetting * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap @@ -30,7 +28,7 @@ class ScopeSettingWithNamespaceOperatorTest extends AbstractMethodUnitTest */ public function testScopeSetting($testMarker, $tokenTypes, $open=T_OPEN_CURLY_BRACKET, $close=T_CLOSE_CURLY_BRACKET) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $target = $this->getTargetToken($testMarker, $tokenTypes); $opener = $this->getTargetToken($testMarker, $open); @@ -59,36 +57,36 @@ public function testScopeSetting($testMarker, $tokenTypes, $open=T_OPEN_CURLY_BR * * @see testScopeSetting() * - * @return array + * @return array>> */ - public function dataScopeSetting() + public static function dataScopeSetting() { return [ - [ - '/* testClassExtends */', - [T_CLASS], + 'class which extends namespace relative name' => [ + 'testMarker' => '/* testClassExtends */', + 'tokenTypes' => [T_CLASS], ], - [ - '/* testClassImplements */', - [T_ANON_CLASS], + 'class which implements namespace relative name' => [ + 'testMarker' => '/* testClassImplements */', + 'tokenTypes' => [T_ANON_CLASS], ], - [ - '/* testInterfaceExtends */', - [T_INTERFACE], + 'interface which extend namespace relative name' => [ + 'testMarker' => '/* testInterfaceExtends */', + 'tokenTypes' => [T_INTERFACE], ], - [ - '/* testFunctionReturnType */', - [T_FUNCTION], + 'namespace relative name in function return type' => [ + 'testMarker' => '/* testFunctionReturnType */', + 'tokenTypes' => [T_FUNCTION], ], - [ - '/* testClosureReturnType */', - [T_CLOSURE], + 'namespace relative name in closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'tokenTypes' => [T_CLOSURE], ], - [ - '/* testArrowFunctionReturnType */', - [T_FN], - [T_FN_ARROW], - [T_SEMICOLON], + 'namespace relative name in arrow function return type' => [ + 'testMarker' => '/* testArrowFunctionReturnType */', + 'tokenTypes' => [T_FN], + 'open' => [T_FN_ARROW], + 'close' => [T_SEMICOLON], ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php index 1d97894f5..189523863 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php @@ -4,14 +4,12 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class ShortArrayTest extends AbstractMethodUnitTest +final class ShortArrayTest extends AbstractTokenizerTestCase { @@ -27,16 +25,19 @@ class ShortArrayTest extends AbstractMethodUnitTest */ public function testSquareBrackets($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; - $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); - $this->assertSame(T_OPEN_SQUARE_BRACKET, $tokens[$opener]['code']); - $this->assertSame('T_OPEN_SQUARE_BRACKET', $tokens[$opener]['type']); + $this->assertSame(T_OPEN_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (code)'); + $this->assertSame('T_OPEN_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SQUARE_BRACKET (type)'); if (isset($tokens[$opener]['bracket_closer']) === true) { - $closer = $tokens[$opener]['bracket_closer']; - $this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokens[$closer]['code']); - $this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokens[$closer]['type']); + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SQUARE_BRACKET, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (code)'); + $this->assertSame('T_CLOSE_SQUARE_BRACKET', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SQUARE_BRACKET (type)'); } }//end testSquareBrackets() @@ -47,9 +48,9 @@ public function testSquareBrackets($testMarker) * * @see testSquareBrackets() * - * @return array + * @return array> */ - public function dataSquareBrackets() + public static function dataSquareBrackets() { return [ 'array access 1' => ['/* testArrayAccess1 */'], @@ -92,16 +93,19 @@ public function dataSquareBrackets() */ public function testShortArrays($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); + $tokenArray = $tokens[$opener]; - $opener = $this->getTargetToken($testMarker, [T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY]); - $this->assertSame(T_OPEN_SHORT_ARRAY, $tokens[$opener]['code']); - $this->assertSame('T_OPEN_SHORT_ARRAY', $tokens[$opener]['type']); + $this->assertSame(T_OPEN_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (code)'); + $this->assertSame('T_OPEN_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_OPEN_SHORT_ARRAY (type)'); if (isset($tokens[$opener]['bracket_closer']) === true) { - $closer = $tokens[$opener]['bracket_closer']; - $this->assertSame(T_CLOSE_SHORT_ARRAY, $tokens[$closer]['code']); - $this->assertSame('T_CLOSE_SHORT_ARRAY', $tokens[$closer]['type']); + $closer = $tokens[$opener]['bracket_closer']; + $tokenArray = $tokens[$closer]; + + $this->assertSame(T_CLOSE_SHORT_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (code)'); + $this->assertSame('T_CLOSE_SHORT_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CLOSE_SHORT_ARRAY (type)'); } }//end testShortArrays() @@ -112,9 +116,9 @@ public function testShortArrays($testMarker) * * @see testShortArrays() * - * @return array + * @return array> */ - public function dataShortArrays() + public static function dataShortArrays() { return [ 'short array empty' => ['/* testShortArrayDeclarationEmpty */'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php index 389bb74e6..b3b19c6ba 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php @@ -10,23 +10,22 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class StableCommentWhitespaceTest extends AbstractMethodUnitTest +final class StableCommentWhitespaceTest extends AbstractTokenizerTestCase { /** * Test that comment tokenization with new lines at the end of the comment is stable. * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. * * @dataProvider dataCommentTokenization * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -35,12 +34,20 @@ class StableCommentWhitespaceTest extends AbstractMethodUnitTest */ public function testCommentTokenization($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$comment]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$comment]['type']); + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); ++$comment; @@ -54,14 +61,14 @@ public function testCommentTokenization($testMarker, $expectedTokens) * * @see testCommentTokenization() * - * @return array + * @return array>>> */ - public function dataCommentTokenization() + public static function dataCommentTokenization() { return [ - [ - '/* testSingleLineSlashComment */', - [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -74,9 +81,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentTrailing */', - [ + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -89,9 +96,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashAnnotation */', - [ + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_DISABLE', 'content' => '// phpcs:disable Stnd.Cat @@ -104,9 +111,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashComment */', - [ + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -129,9 +136,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithIndent */', - [ + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -162,9 +169,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationStart */', - [ + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '// phpcs:ignore Stnd.Cat @@ -187,9 +194,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationMiddle */', - [ + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -212,9 +219,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationEnd */', - [ + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -237,9 +244,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarComment */', - [ + 'star comment, single line' => [ + 'testMarker' => '/* testSingleLineStarComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Single line star comment */', @@ -251,9 +258,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarCommentTrailing */', - [ + 'star comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineStarCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment */', @@ -265,9 +272,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineStarAnnotation */', - [ + 'star ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineStarAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '/* phpcs:ignore Stnd.Cat */', @@ -279,9 +286,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarComment */', - [ + 'star comment, multi-line' => [ + 'testMarker' => '/* testMultiLineStarComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -303,9 +310,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithIndent */', - [ + 'star comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineStarCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -327,9 +334,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationStart */', - [ + 'star comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationStart */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '/* @phpcs:ignore Stnd.Cat @@ -351,9 +358,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationMiddle */', - [ + 'star comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationMiddle */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -375,9 +382,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineStarCommentWithAnnotationEnd */', - [ + 'star comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineStarCommentWithAnnotationEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment1 @@ -400,9 +407,9 @@ public function dataCommentTokenization() ], ], - [ - '/* testSingleLineDocblockComment */', - [ + 'docblock comment, single line' => [ + 'testMarker' => '/* testSingleLineDocblockComment */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -426,9 +433,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineDocblockCommentTrailing */', - [ + 'docblock comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineDocblockCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -452,9 +459,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineDocblockAnnotation */', - [ + 'docblock ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineDocblockAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -479,9 +486,9 @@ public function dataCommentTokenization() ], ], - [ - '/* testMultiLineDocblockComment */', - [ + 'docblock comment, multi-line' => [ + 'testMarker' => '/* testMultiLineDocblockComment */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -590,9 +597,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithIndent */', - [ + 'docblock comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -701,9 +708,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithAnnotation */', - [ + 'docblock comment, multi-line, ignore annotation' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -812,9 +819,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineDocblockCommentWithTagAnnotation */', - [ + 'docblock comment, multi-line, ignore annotation as tag' => [ + 'testMarker' => '/* testMultiLineDocblockCommentWithTagAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_DOC_COMMENT_OPEN_TAG', 'content' => '/**', @@ -923,9 +930,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashComment */', - [ + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -938,9 +945,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentTrailing */', - [ + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -953,9 +960,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashComment */', - [ + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -978,9 +985,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashCommentWithIndent */', - [ + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -1011,9 +1018,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentNoNewLineAtEnd */', - [ + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Slash ', @@ -1025,9 +1032,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentNoNewLineAtEnd */', - [ + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Hash ', @@ -1039,9 +1046,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testCommentAtEndOfFile */', - [ + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php index 9ab66e9c7..2d0ce30d8 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php @@ -7,23 +7,22 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; -class StableCommentWhitespaceWinTest extends AbstractMethodUnitTest +final class StableCommentWhitespaceWinTest extends AbstractTokenizerTestCase { /** * Test that comment tokenization with new lines at the end of the comment is stable. * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. * * @dataProvider dataCommentTokenization * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -32,12 +31,20 @@ class StableCommentWhitespaceWinTest extends AbstractMethodUnitTest */ public function testCommentTokenization($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$comment]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$comment]['type']); + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$comment]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$comment]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$comment]['type'], + 'Token tokenized as '.$tokens[$comment]['type'].', not '.$tokenInfo['type'].' (type)' + ); $this->assertSame($tokenInfo['content'], $tokens[$comment]['content']); ++$comment; @@ -51,14 +58,14 @@ public function testCommentTokenization($testMarker, $expectedTokens) * * @see testCommentTokenization() * - * @return array + * @return array>>> */ - public function dataCommentTokenization() + public static function dataCommentTokenization() { return [ - [ - '/* testSingleLineSlashComment */', - [ + 'slash comment, single line' => [ + 'testMarker' => '/* testSingleLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -71,9 +78,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentTrailing */', - [ + 'slash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineSlashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment @@ -86,9 +93,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashAnnotation */', - [ + 'slash ignore annotation, single line' => [ + 'testMarker' => '/* testSingleLineSlashAnnotation */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_DISABLE', 'content' => '// phpcs:disable Stnd.Cat @@ -101,9 +108,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashComment */', - [ + 'slash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineSlashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -126,9 +133,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithIndent */', - [ + 'slash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -159,9 +166,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationStart */', - [ + 'slash comment, multi-line, ignore annotation as first line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationStart */', + 'expectedTokens' => [ [ 'type' => 'T_PHPCS_IGNORE', 'content' => '// phpcs:ignore Stnd.Cat @@ -184,9 +191,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationMiddle */', - [ + 'slash comment, multi-line, ignore annotation as middle line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationMiddle */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -209,9 +216,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineSlashCommentWithAnnotationEnd */', - [ + 'slash comment, multi-line, ignore annotation as last line' => [ + 'testMarker' => '/* testMultiLineSlashCommentWithAnnotationEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Comment1 @@ -234,9 +241,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineSlashCommentNoNewLineAtEnd */', - [ + 'slash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineSlashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '// Slash ', @@ -248,9 +255,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashComment */', - [ + 'hash comment, single line' => [ + 'testMarker' => '/* testSingleLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -263,9 +270,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentTrailing */', - [ + 'hash comment, single line, trailing' => [ + 'testMarker' => '/* testSingleLineHashCommentTrailing */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment @@ -278,9 +285,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashComment */', - [ + 'hash comment, multi-line' => [ + 'testMarker' => '/* testMultiLineHashComment */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -303,9 +310,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testMultiLineHashCommentWithIndent */', - [ + 'hash comment, multi-line, indented' => [ + 'testMarker' => '/* testMultiLineHashCommentWithIndent */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Comment1 @@ -336,9 +343,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testSingleLineHashCommentNoNewLineAtEnd */', - [ + 'hash comment, single line, without new line at end' => [ + 'testMarker' => '/* testSingleLineHashCommentNoNewLineAtEnd */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '# Hash ', @@ -350,9 +357,9 @@ public function dataCommentTokenization() ], ], ], - [ - '/* testCommentAtEndOfFile */', - [ + 'unclosed star comment at end of file' => [ + 'testMarker' => '/* testCommentAtEndOfFile */', + 'expectedTokens' => [ [ 'type' => 'T_COMMENT', 'content' => '/* Comment', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc index abf9b85ba..d9a68db36 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc @@ -9,6 +9,30 @@ $result = $value & $test /* testBitwiseAnd2 */ & $another; class TypeIntersection { + /* testTypeIntersectionOOConstSimple */ + public const Foo&Bar SIMPLE = new Foo(); + + /* testTypeIntersectionOOConstReverseModifierOrder */ + protected final const Something&Nothing MODIFIERS_REVERSED /* testBitwiseAndOOConstDefaultValue */ = E_WARNING & E_NOTICE; + + const + /* testTypeIntersectionOOConstMulti1 */ + Foo & + /* testTypeIntersectionOOConstMulti2 */ + Traversable & // phpcs:ignore Stnd.Cat.Sniff + Boo + /* testTypeIntersectionOOConstMulti3 */ + & Bar MULTI_INTERSECTION = false; + + /* testTypeIntersectionOOConstNamespaceRelative */ + const namespace\Sub\NameA&namespace\Sub\NameB NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testTypeIntersectionOOConstPartiallyQualified */ + const Partially\Qualified\NameA&Partially\Qualified\NameB PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testTypeIntersectionOOConstFullyQualified */ + const \Fully\Qualified\NameA&\Fully\Qualified\NameB FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + /* testTypeIntersectionPropertySimple */ public static Foo&Bar $obj; @@ -36,6 +60,9 @@ class TypeIntersection /* testTypeIntersectionPropertyWithReadOnlyKeyword */ protected readonly Foo&Bar $fooBar; + /* testTypeIntersectionPropertyWithStaticKeyword */ + static Foo&Bar $obj; + public function paramTypes( /* testTypeIntersectionParam1 */ Foo&Bar $paramA /* testBitwiseAndParamDefaultValue */ = CONSTANT_A & CONSTANT_B, @@ -56,12 +83,12 @@ class TypeIntersection \Fully\Qualified\NameA&\Fully\Qualified\NameB $paramC, ) {} - /* testTypeIntersectionReturnType */ - public function returnType() : Foo&Bar {} - /* testTypeIntersectionConstructorPropertyPromotion */ public function __construct( public Foo&Bar $property) {} + /* testTypeIntersectionReturnType */ + public function returnType() : Foo&Bar {} + /* testTypeIntersectionAbstractMethodReturnType1 */ abstract public function abstractMethod(): Foo&Bar /* testTypeIntersectionAbstractMethodReturnType2 */ &Baz; @@ -75,9 +102,6 @@ class TypeIntersection public function identifierNamesReturnFQ() : \Fully\Qualified\NameA&\Fully\Qualified\NameB {} } -/* testTypeIntersectionClosureParamIllegalNullable */ -$closureWithParamType = function (?Foo&Bar $string) {}; - function globalFunctionWithSpreadAndReference( /* testTypeIntersectionWithReference */ Foo&Bar /* testBitwiseAnd5 */ &$paramA, @@ -85,6 +109,9 @@ function globalFunctionWithSpreadAndReference( Foo&Bar ...$paramB ) {} +/* testTypeIntersectionClosureParamIllegalNullable */ +$closureWithParamType = function (?Foo&Bar $string) {}; + /* testBitwiseAndClosureParamDefault */ $closureWithReturnType = function ($string = NONSENSE & FAKE)/* testTypeIntersectionClosureReturn */ : \Package\MyA&PackageB {}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php index 217002193..c719850c1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php @@ -5,14 +5,12 @@ * @author Juliette Reinders Folmer * @author Jaroslav Hanslík * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; - -class TypeIntersectionTest extends AbstractMethodUnitTest +final class TypeIntersectionTest extends AbstractTokenizerTestCase { @@ -28,11 +26,12 @@ class TypeIntersectionTest extends AbstractMethodUnitTest */ public function testBitwiseAnd($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; - $opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); - $this->assertSame(T_BITWISE_AND, $tokens[$opener]['code']); - $this->assertSame('T_BITWISE_AND', $tokens[$opener]['type']); + $this->assertSame(T_BITWISE_AND, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_BITWISE_AND (type)'); }//end testBitwiseAnd() @@ -42,28 +41,29 @@ public function testBitwiseAnd($testMarker) * * @see testBitwiseAnd() * - * @return array + * @return array> */ - public function dataBitwiseAnd() + public static function dataBitwiseAnd() { return [ - ['/* testBitwiseAnd1 */'], - ['/* testBitwiseAnd2 */'], - ['/* testBitwiseAndPropertyDefaultValue */'], - ['/* testBitwiseAndParamDefaultValue */'], - ['/* testBitwiseAnd3 */'], - ['/* testBitwiseAnd4 */'], - ['/* testBitwiseAnd5 */'], - ['/* testBitwiseAndClosureParamDefault */'], - ['/* testBitwiseAndArrowParamDefault */'], - ['/* testBitwiseAndArrowExpression */'], - ['/* testBitwiseAndInArrayKey */'], - ['/* testBitwiseAndInArrayValue */'], - ['/* testBitwiseAndInShortArrayKey */'], - ['/* testBitwiseAndInShortArrayValue */'], - ['/* testBitwiseAndNonArrowFnFunctionCall */'], - ['/* testBitwiseAnd6 */'], - ['/* testLiveCoding */'], + 'in simple assignment 1' => ['/* testBitwiseAnd1 */'], + 'in simple assignment 2' => ['/* testBitwiseAnd2 */'], + 'in OO constant default value' => ['/* testBitwiseAndOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseAndPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseAndParamDefaultValue */'], + 'reference for method parameter' => ['/* testBitwiseAnd3 */'], + 'in return statement' => ['/* testBitwiseAnd4 */'], + 'reference for function parameter' => ['/* testBitwiseAnd5 */'], + 'in closure parameter default value' => ['/* testBitwiseAndClosureParamDefault */'], + 'in arrow function parameter default value' => ['/* testBitwiseAndArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseAndArrowExpression */'], + 'in long array key' => ['/* testBitwiseAndInArrayKey */'], + 'in long array value' => ['/* testBitwiseAndInArrayValue */'], + 'in short array key' => ['/* testBitwiseAndInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseAndInShortArrayValue */'], + 'in parameter in function call' => ['/* testBitwiseAndNonArrowFnFunctionCall */'], + 'function return by reference' => ['/* testBitwiseAnd6 */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], ]; }//end dataBitwiseAnd() @@ -81,11 +81,12 @@ public function dataBitwiseAnd() */ public function testTypeIntersection($testMarker) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); + $tokenArray = $tokens[$target]; - $opener = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION]); - $this->assertSame(T_TYPE_INTERSECTION, $tokens[$opener]['code']); - $this->assertSame('T_TYPE_INTERSECTION', $tokens[$opener]['type']); + $this->assertSame(T_TYPE_INTERSECTION, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (code)'); + $this->assertSame('T_TYPE_INTERSECTION', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_TYPE_INTERSECTION (type)'); }//end testTypeIntersection() @@ -95,41 +96,50 @@ public function testTypeIntersection($testMarker) * * @see testTypeIntersection() * - * @return array + * @return array> */ - public function dataTypeIntersection() + public static function dataTypeIntersection() { return [ - ['/* testTypeIntersectionPropertySimple */'], - ['/* testTypeIntersectionPropertyReverseModifierOrder */'], - ['/* testTypeIntersectionPropertyMulti1 */'], - ['/* testTypeIntersectionPropertyMulti2 */'], - ['/* testTypeIntersectionPropertyMulti3 */'], - ['/* testTypeIntersectionPropertyNamespaceRelative */'], - ['/* testTypeIntersectionPropertyPartiallyQualified */'], - ['/* testTypeIntersectionPropertyFullyQualified */'], - ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], - ['/* testTypeIntersectionParam1 */'], - ['/* testTypeIntersectionParam2 */'], - ['/* testTypeIntersectionParam3 */'], - ['/* testTypeIntersectionParamNamespaceRelative */'], - ['/* testTypeIntersectionParamPartiallyQualified */'], - ['/* testTypeIntersectionParamFullyQualified */'], - ['/* testTypeIntersectionReturnType */'], - ['/* testTypeIntersectionConstructorPropertyPromotion */'], - ['/* testTypeIntersectionAbstractMethodReturnType1 */'], - ['/* testTypeIntersectionAbstractMethodReturnType2 */'], - ['/* testTypeIntersectionReturnTypeNamespaceRelative */'], - ['/* testTypeIntersectionReturnPartiallyQualified */'], - ['/* testTypeIntersectionReturnFullyQualified */'], - ['/* testTypeIntersectionClosureParamIllegalNullable */'], - ['/* testTypeIntersectionWithReference */'], - ['/* testTypeIntersectionWithSpreadOperator */'], - ['/* testTypeIntersectionClosureReturn */'], - ['/* testTypeIntersectionArrowParam */'], - ['/* testTypeIntersectionArrowReturnType */'], - ['/* testTypeIntersectionNonArrowFunctionDeclaration */'], - ['/* testTypeIntersectionWithInvalidTypes */'], + 'type for OO constant' => ['/* testTypeIntersectionOOConstSimple */'], + 'type for OO constant, reversed modifier order' => ['/* testTypeIntersectionOOConstReverseModifierOrder */'], + 'type for OO constant, first of multi-intersect' => ['/* testTypeIntersectionOOConstMulti1 */'], + 'type for OO constant, middle of multi-intersect + comments' => ['/* testTypeIntersectionOOConstMulti2 */'], + 'type for OO constant, last of multi-intersect' => ['/* testTypeIntersectionOOConstMulti3 */'], + 'type for OO constant, using namespace relative names' => ['/* testTypeIntersectionOOConstNamespaceRelative */'], + 'type for OO constant, using partially qualified names' => ['/* testTypeIntersectionOOConstPartiallyQualified */'], + 'type for OO constant, using fully qualified names' => ['/* testTypeIntersectionOOConstFullyQualified */'], + 'type for static property' => ['/* testTypeIntersectionPropertySimple */'], + 'type for static property, reversed modifier order' => ['/* testTypeIntersectionPropertyReverseModifierOrder */'], + 'type for property, first of multi-intersect' => ['/* testTypeIntersectionPropertyMulti1 */'], + 'type for property, middle of multi-intersect, also comments' => ['/* testTypeIntersectionPropertyMulti2 */'], + 'type for property, last of multi-intersect' => ['/* testTypeIntersectionPropertyMulti3 */'], + 'type for property using namespace relative names' => ['/* testTypeIntersectionPropertyNamespaceRelative */'], + 'type for property using partially qualified names' => ['/* testTypeIntersectionPropertyPartiallyQualified */'], + 'type for property using fully qualified names' => ['/* testTypeIntersectionPropertyFullyQualified */'], + 'type for readonly property' => ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], + 'type for static readonly property' => ['/* testTypeIntersectionPropertyWithStaticKeyword */'], + 'type for method parameter' => ['/* testTypeIntersectionParam1 */'], + 'type for method parameter, first in multi-intersect' => ['/* testTypeIntersectionParam2 */'], + 'type for method parameter, last in multi-intersect' => ['/* testTypeIntersectionParam3 */'], + 'type for method parameter with namespace relative names' => ['/* testTypeIntersectionParamNamespaceRelative */'], + 'type for method parameter with partially qualified names' => ['/* testTypeIntersectionParamPartiallyQualified */'], + 'type for method parameter with fully qualified names' => ['/* testTypeIntersectionParamFullyQualified */'], + 'type for property in constructor property promotion' => ['/* testTypeIntersectionConstructorPropertyPromotion */'], + 'return type for method' => ['/* testTypeIntersectionReturnType */'], + 'return type for method, first of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType1 */'], + 'return type for method, last of multi-intersect' => ['/* testTypeIntersectionAbstractMethodReturnType2 */'], + 'return type for method with namespace relative names' => ['/* testTypeIntersectionReturnTypeNamespaceRelative */'], + 'return type for method with partially qualified names' => ['/* testTypeIntersectionReturnPartiallyQualified */'], + 'return type for method with fully qualified names' => ['/* testTypeIntersectionReturnFullyQualified */'], + 'type for function parameter with reference' => ['/* testTypeIntersectionWithReference */'], + 'type for function parameter with spread operator' => ['/* testTypeIntersectionWithSpreadOperator */'], + 'type for closure parameter with illegal nullable' => ['/* testTypeIntersectionClosureParamIllegalNullable */'], + 'return type for closure' => ['/* testTypeIntersectionClosureReturn */'], + 'type for arrow function parameter' => ['/* testTypeIntersectionArrowParam */'], + 'return type for arrow function' => ['/* testTypeIntersectionArrowReturnType */'], + 'type for function parameter, return by ref' => ['/* testTypeIntersectionNonArrowFunctionDeclaration */'], + 'type for function parameter with invalid types' => ['/* testTypeIntersectionWithInvalidTypes */'], ]; }//end dataTypeIntersection() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc new file mode 100644 index 000000000..a68831392 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc @@ -0,0 +1,132 @@ +const ? 0 : 1; + +/* testGlobalConstantCannotBeTyped */ +const GLOBAL_UNTYPED = true; + +/* testGlobalConstantTypedShouldStillBeHandled */ +const ?int GLOBAL_TYPED = true; + +class ClassWithPlainTypedConstants { + /* testClassConstFinalUntyped */ + final const FINAL_UNTYPED = true; + + /* testClassConstVisibilityUntyped */ + public const /*comment*/VISIBLE_UNTYPED = true; + + /* testClassConstTypedTrue */ + const true TYPED_TRUE = true; + /* testClassConstTypedFalse */ + final const false TYPED_FALSE = false; + /* testClassConstTypedNull */ + public const null TYPED_NULL = null; + /* testClassConstTypedBool */ + final protected const/*comment*/bool TYPED_BOOL = false; + /* testClassConstTypedInt */ + private const int TYPED_INT = 0; + /* testClassConstTypedFloat */ + const float TYPED_FLOAT = 0.5; + /* testClassConstTypedString */ + public final const string/*comment*/TYPED_STRING = 'string'; + /* testClassConstTypedArray */ + private final const array TYPED_ARRAY = []; + /* testClassConstTypedObject */ + const + object + TYPED_OBJECT = MyClass::getInstance(); + /* testClassConstTypedIterable */ + const iterable typed_iterable = []; + /* testClassConstTypedMixed */ + const mixed TYPED_MIXED = 'string'; + + /* testClassConstTypedClassUnqualified */ + const MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassFullyQualified */ + public const \MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassNamespaceRelative */ + protected const namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedClassPartiallyQualified */ + private const Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testClassConstTypedParent */ + const parent TYPED_PARENT = parent::getInstance(); + + // Illegal types - the fact that these are not allowed in PHP is not the concern of the PHPCS tokenizer. + /* testClassConstTypedCallable */ + protected const callable TYPED_CALLABLE = 'function_name'; + /* testClassConstTypedVoid */ + protected const void TYPED_VOID = null; + /* testClassConstTypedNever */ + protected const NEVER TYPED_NEVER = null; +} + +trait TraitWithNullableTypedConstants { + /* testTraitConstTypedNullableTrue */ + const ?true TYPED_TRUE = true; + /* testTraitConstTypedNullableFalse */ + final const ?false TYPED_FALSE = false; + /* testTraitConstTypedNullableNull */ + public const ?null TYPED_NULL = null; + /* testTraitConstTypedNullableBool */ + final protected const ?bool TYPED_BOOL = false; + /* testTraitConstTypedNullableInt */ + private const ?int TYPED_INT = 0; + /* testTraitConstTypedNullableFloat */ + const ? /*comment*/ float TYPED_FLOAT = 0.5; + /* testTraitConstTypedNullableString */ + public final const ?string TYPED_STRING = 'string'; + /* testTraitConstTypedNullableArray */ + private final const ? array TYPED_ARRAY = []; + /* testTraitConstTypedNullableObject */ + const ?object TYPED_OBJECT = MyClass::getInstance(); + /* testTraitConstTypedNullableIterable */ + const ?iterable TYPED_ITERABLE = []; + /* testTraitConstTypedNullableMixed */ + const ?mixed TYPED_MIXED = 'string'; + + /* testTraitConstTypedNullableClassUnqualified */ + const ?MyClass TYPED_UNQUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassFullyQualified */ + public const ?\MyClass TYPED_FULLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassNamespaceRelative */ + protected const ?namespace\MyClass TYPED_NAMESPACE_RELATIVE_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableClassPartiallyQualified */ + private const ?Partial\MyClass TYPED_PARTIALLY_QUALIFIED_CLASSNAME = MyClass::getInstance(); + /* testTraitConstTypedNullableParent */ + const ?parent TYPED_PARENT = parent::getInstance(); +} + +interface InterfaceWithUnionTypedConstants { + /* testInterfaceConstTypedUnionTrueNull */ + const true|null /*comment*/ UNION_TRUE_NULL = true; + /* testInterfaceConstTypedUnionArrayObject */ + const array|object UNION_ARRAY_OBJECT = []; + /* testInterfaceConstTypedUnionStringArrayInt */ + const string | array | int UNION_STRING_ARRAY_INT = 'array middle'; + /* testInterfaceConstTypedUnionFloatBoolArray */ + const float /*comment*/| bool|array UNION_FLOAT_BOOL_ARRAY = false; + /* testInterfaceConstTypedUnionIterableFalse */ + const iterable|false UNION_ITERABLE_FALSE = false; + /* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */ + const Unqualified|namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */ + const \Fully\Qualified|Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} + +enum EnumWithIntersectionTypedConstants { + // Illegal types in a class, but legal in an enum. + /* testEnumConstTypedSelf */ + final const self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedStatic */ + const static TYPED_STATIC = static::getInstance(); + /* testEnumConstTypedNullableSelf */ + public const ?self TYPED_SELF = self::getInstance(); + /* testEnumConstTypedNullableStatic */ + const ?static TYPED_STATIC = static::getInstance(); + + /* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */ + const Unqualified&namespace\Relative UNION_UNQUALIFIED_NSRELATIVE = new Unqualified(); + /* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */ + const \Fully\Qualified&Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php new file mode 100644 index 000000000..0c4a9b614 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php @@ -0,0 +1,515 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizer; + +use PHP_CodeSniffer\Util\Tokens; + +final class TypedConstantsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that a ? after a "const" which is not the constant keyword is tokenized as ternary then, not as the nullable operator. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTernaryIsInlineThen() + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken('/* testTernaryIsTernaryAfterConst */', [T_NULLABLE, T_INLINE_THEN]); + + $this->assertSame( + T_INLINE_THEN, + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not T_INLINE_THEN (code)' + ); + $this->assertSame( + 'T_INLINE_THEN', + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not T_INLINE_THEN (type)' + ); + + }//end testTernaryIsInlineThen() + + + /** + * Test the token name for an untyped constant is tokenized as T_STRING. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataUntypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testUntypedConstant($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + T_STRING, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not T_STRING (code)' + ); + $this->assertSame( + 'T_STRING', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_STRING (type)' + ); + } + + }//end testUntypedConstant() + + + /** + * Data provider. + * + * @see testUntypedConstant() + * + * @return array> + */ + public static function dataUntypedConstant() + { + return [ + 'non OO constant (untyped)' => [ + 'testMarker' => '/* testGlobalConstantCannotBeTyped */', + ], + 'OO constant, final, untyped' => [ + 'testMarker' => '/* testClassConstFinalUntyped */', + ], + 'OO constant, public, untyped, with comment' => [ + 'testMarker' => '/* testClassConstVisibilityUntyped */', + ], + ]; + + }//end dataUntypedConstant() + + + /** + * Test the tokens in the type of a typed constant as well as the constant name are tokenized correctly. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $sequence The expected token sequence. + * + * @dataProvider dataTypedConstant + * @dataProvider dataNullableTypedConstant + * @dataProvider dataUnionTypedConstant + * @dataProvider dataIntersectionTypedConstant + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testTypedConstant($testMarker, array $sequence) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, T_CONST); + + $current = 0; + for ($i = ($target + 1); $tokens[$i]['code'] !== T_EQUAL; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + // Ignore whitespace and comments, not interested in the tokenization of those. + continue; + } + + $this->assertSame( + $sequence[$current], + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.Tokens::tokenName($sequence[$current]).' (code)' + ); + + ++$current; + } + + }//end testTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array> + */ + public static function dataTypedConstant() + { + $data = [ + 'simple type: true' => [ + 'testMarker' => '/* testClassConstTypedTrue */', + 'sequence' => [T_TRUE], + ], + 'simple type: false' => [ + 'testMarker' => '/* testClassConstTypedFalse */', + 'sequence' => [T_FALSE], + ], + 'simple type: null' => [ + 'testMarker' => '/* testClassConstTypedNull */', + 'sequence' => [T_NULL], + ], + 'simple type: bool' => [ + 'testMarker' => '/* testClassConstTypedBool */', + 'sequence' => [T_STRING], + ], + 'simple type: int' => [ + 'testMarker' => '/* testClassConstTypedInt */', + 'sequence' => [T_STRING], + ], + 'simple type: float' => [ + 'testMarker' => '/* testClassConstTypedFloat */', + 'sequence' => [T_STRING], + ], + 'simple type: string' => [ + 'testMarker' => '/* testClassConstTypedString */', + 'sequence' => [T_STRING], + ], + 'simple type: array' => [ + 'testMarker' => '/* testClassConstTypedArray */', + 'sequence' => [T_STRING], + ], + 'simple type: object' => [ + 'testMarker' => '/* testClassConstTypedObject */', + 'sequence' => [T_STRING], + ], + 'simple type: iterable' => [ + 'testMarker' => '/* testClassConstTypedIterable */', + 'sequence' => [T_STRING], + ], + 'simple type: mixed' => [ + 'testMarker' => '/* testClassConstTypedMixed */', + 'sequence' => [T_STRING], + ], + 'simple type: unqualified name' => [ + 'testMarker' => '/* testClassConstTypedClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'simple type: fully qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: namespace relative name' => [ + 'testMarker' => '/* testClassConstTypedClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: partially qualified name' => [ + 'testMarker' => '/* testClassConstTypedClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'simple type: parent' => [ + 'testMarker' => '/* testClassConstTypedParent */', + 'sequence' => [T_PARENT], + ], + + 'simple type: callable (invalid)' => [ + 'testMarker' => '/* testClassConstTypedCallable */', + 'sequence' => [T_CALLABLE], + ], + 'simple type: void (invalid)' => [ + 'testMarker' => '/* testClassConstTypedVoid */', + 'sequence' => [T_STRING], + ], + 'simple type: NEVER (invalid)' => [ + 'testMarker' => '/* testClassConstTypedNever */', + 'sequence' => [T_STRING], + ], + + 'simple type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedSelf */', + 'sequence' => [T_SELF], + ], + 'simple type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array> + */ + public static function dataNullableTypedConstant() + { + $data = [ + // Global constants cannot be typed in PHP, but that's not our concern. + 'global typed constant, invalid, ?int' => [ + 'testMarker' => '/* testGlobalConstantTypedShouldStillBeHandled */', + 'sequence' => [T_STRING], + ], + + // OO constants. + 'nullable type: true' => [ + 'testMarker' => '/* testTraitConstTypedNullableTrue */', + 'sequence' => [T_TRUE], + ], + 'nullable type: false' => [ + 'testMarker' => '/* testTraitConstTypedNullableFalse */', + 'sequence' => [T_FALSE], + ], + 'nullable type: null' => [ + 'testMarker' => '/* testTraitConstTypedNullableNull */', + 'sequence' => [T_NULL], + ], + 'nullable type: bool' => [ + 'testMarker' => '/* testTraitConstTypedNullableBool */', + 'sequence' => [T_STRING], + ], + 'nullable type: int' => [ + 'testMarker' => '/* testTraitConstTypedNullableInt */', + 'sequence' => [T_STRING], + ], + 'nullable type: float' => [ + 'testMarker' => '/* testTraitConstTypedNullableFloat */', + 'sequence' => [T_STRING], + ], + 'nullable type: string' => [ + 'testMarker' => '/* testTraitConstTypedNullableString */', + 'sequence' => [T_STRING], + ], + 'nullable type: array' => [ + 'testMarker' => '/* testTraitConstTypedNullableArray */', + 'sequence' => [T_STRING], + ], + 'nullable type: object' => [ + 'testMarker' => '/* testTraitConstTypedNullableObject */', + 'sequence' => [T_STRING], + ], + 'nullable type: iterable' => [ + 'testMarker' => '/* testTraitConstTypedNullableIterable */', + 'sequence' => [T_STRING], + ], + 'nullable type: mixed' => [ + 'testMarker' => '/* testTraitConstTypedNullableMixed */', + 'sequence' => [T_STRING], + ], + 'nullable type: unqualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassUnqualified */', + 'sequence' => [T_STRING], + ], + 'nullable type: fully qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassFullyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: namespace relative name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassNamespaceRelative */', + 'sequence' => [ + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: partially qualified name' => [ + 'testMarker' => '/* testTraitConstTypedNullableClassPartiallyQualified */', + 'sequence' => [ + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'nullable type: parent' => [ + 'testMarker' => '/* testTraitConstTypedNullableParent */', + 'sequence' => [T_PARENT], + ], + + 'nullable type: self (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableSelf */', + 'sequence' => [T_SELF], + ], + 'nullable type: static (only valid in enum)' => [ + 'testMarker' => '/* testEnumConstTypedNullableStatic */', + 'sequence' => [T_STATIC], + ], + ]; + + // The nullable operator, as the first token in the sequence, is always T_NULLABLE. + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + array_unshift($data[$key]['sequence'], T_NULLABLE); + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataNullableTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array> + */ + public static function dataUnionTypedConstant() + { + $data = [ + 'union type: true|null' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionTrueNull */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_NULL, + ], + ], + 'union type: array|object' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionArrayObject */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: string|array|int' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionStringArrayInt */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: float|bool|array' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFloatBoolArray */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_STRING, + T_TYPE_UNION, + T_STRING, + ], + ], + 'union type: iterable|false' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionIterableFalse */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'union type: Unqualified|Namespace\Relative' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'union type: FQN|Partial' => [ + 'testMarker' => '/* testInterfaceConstTypedUnionFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataUnionTypedConstant() + + + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array> + */ + public static function dataIntersectionTypedConstant() + { + $data = [ + 'intersection type: Unqualified&Namespace\Relative' => [ + 'testMarker' => '/* testEnumConstTypedIntersectUnqualifiedNamespaceRelative */', + 'sequence' => [ + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'intersection type: FQN&Partial' => [ + 'testMarker' => '/* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */', + 'sequence' => [ + T_NS_SEPARATOR, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataIntersectionTypedConstant() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc index 540f72c9d..65c551a84 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc @@ -79,7 +79,7 @@ class MyClass /* testFunctionCallUnqualified */ echo function_name(); - /* testFunctionPartiallyQualified */ + /* testFunctionCallPartiallyQualified */ echo Level\function_name(); /* testCatchRelative */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php index 24667e486..9e1038dcf 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php @@ -14,22 +14,22 @@ * * @author Juliette Reinders Folmer * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Core\Tokenizer; -use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; -class UndoNamespacedNameSingleTokenTest extends AbstractMethodUnitTest +final class UndoNamespacedNameSingleTokenTest extends AbstractTokenizerTestCase { /** * Test that identifier names are tokenized the same across PHP versions, based on the PHP 5/7 tokenization. * - * @param string $testMarker The comment prefacing the test. - * @param array $expectedTokens The tokenization expected. + * @param string $testMarker The comment prefacing the test. + * @param array> $expectedTokens The tokenization expected. * * @dataProvider dataIdentifierTokenization * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize @@ -38,12 +38,20 @@ class UndoNamespacedNameSingleTokenTest extends AbstractMethodUnitTest */ public function testIdentifierTokenization($testMarker, $expectedTokens) { - $tokens = self::$phpcsFile->getTokens(); + $tokens = $this->phpcsFile->getTokens(); $identifier = $this->getTargetToken($testMarker, constant($expectedTokens[0]['type'])); foreach ($expectedTokens as $key => $tokenInfo) { - $this->assertSame(constant($tokenInfo['type']), $tokens[$identifier]['code']); - $this->assertSame($tokenInfo['type'], $tokens[$identifier]['type']); + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$identifier]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$identifier]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$identifier]['type'], + 'Token tokenized as '.$tokens[$identifier]['type'].', not '.$tokenInfo['type'].' (type)' + ); $this->assertSame($tokenInfo['content'], $tokens[$identifier]['content']); ++$identifier; @@ -57,14 +65,14 @@ public function testIdentifierTokenization($testMarker, $expectedTokens) * * @see testIdentifierTokenization() * - * @return array + * @return array>>> */ - public function dataIdentifierTokenization() + public static function dataIdentifierTokenization() { return [ - [ - '/* testNamespaceDeclaration */', - [ + 'namespace declaration' => [ + 'testMarker' => '/* testNamespaceDeclaration */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Package', @@ -75,9 +83,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNamespaceDeclarationWithLevels */', - [ + 'namespace declaration, multi-level' => [ + 'testMarker' => '/* testNamespaceDeclarationWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -104,9 +112,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testUseStatement */', - [ + 'import use statement, class' => [ + 'testMarker' => '/* testUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -117,9 +125,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testUseStatementWithLevels */', - [ + 'import use statement, class, multi-level' => [ + 'testMarker' => '/* testUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -146,9 +154,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionUseStatement */', - [ + 'import use statement, function' => [ + 'testMarker' => '/* testFunctionUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function', @@ -167,9 +175,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionUseStatementWithLevels */', - [ + 'import use statement, function, multi-level' => [ + 'testMarker' => '/* testFunctionUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function', @@ -204,9 +212,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testConstantUseStatement */', - [ + 'import use statement, constant' => [ + 'testMarker' => '/* testConstantUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'const', @@ -225,9 +233,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testConstantUseStatementWithLevels */', - [ + 'import use statement, constant, multi-level' => [ + 'testMarker' => '/* testConstantUseStatementWithLevels */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'const', @@ -262,9 +270,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testMultiUseUnqualified */', - [ + 'import use statement, multi-statement, unqualified class' => [ + 'testMarker' => '/* testMultiUseUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'UnqualifiedClassName', @@ -275,9 +283,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testMultiUsePartiallyQualified */', - [ + 'import use statement, multi-statement, partially qualified class' => [ + 'testMarker' => '/* testMultiUsePartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Sublevel', @@ -296,9 +304,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testGroupUseStatement */', - [ + 'group use statement, multi-level prefix, mix inside group' => [ + 'testMarker' => '/* testGroupUseStatement */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Vendor', @@ -492,9 +500,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testClassName */', - [ + 'class declaration' => [ + 'testMarker' => '/* testClassName */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'MyClass', @@ -506,9 +514,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testExtendedFQN */', - [ + 'class declaration, extends fully qualified name' => [ + 'testMarker' => '/* testExtendedFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -540,9 +548,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsRelative */', - [ + 'class declaration, implements namespace relative name' => [ + 'testMarker' => '/* testImplementsRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -561,9 +569,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsFQN */', - [ + 'class declaration, implements fully qualified name' => [ + 'testMarker' => '/* testImplementsFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -586,9 +594,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsUnqualified */', - [ + 'class declaration, implements unqualified name' => [ + 'testMarker' => '/* testImplementsUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Unqualified', @@ -599,9 +607,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testImplementsPartiallyQualified */', - [ + 'class declaration, implements partially qualified name' => [ + 'testMarker' => '/* testImplementsPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Sub', @@ -629,9 +637,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionName */', - [ + 'method declaration' => [ + 'testMarker' => '/* testFunctionName */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function_name', @@ -642,9 +650,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationRelative */', - [ + 'param type declaration, namespace relative name' => [ + 'testMarker' => '/* testTypeDeclarationRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -667,9 +675,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationFQN */', - [ + 'param type declaration, fully qualified name' => [ + 'testMarker' => '/* testTypeDeclarationFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -700,9 +708,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationUnqualified */', - [ + 'param type declaration, unqualified name' => [ + 'testMarker' => '/* testTypeDeclarationUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Unqualified', @@ -717,9 +725,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testTypeDeclarationPartiallyQualified */', - [ + 'param type declaration, partially qualified name' => [ + 'testMarker' => '/* testTypeDeclarationPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_NULLABLE', 'content' => '?', @@ -742,9 +750,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testReturnTypeFQN */', - [ + 'return type declaration, fully qualified name' => [ + 'testMarker' => '/* testReturnTypeFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NULLABLE', 'content' => '?', @@ -763,9 +771,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallRelative */', - [ + 'function call, namespace relative name' => [ + 'testMarker' => '/* testFunctionCallRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'NameSpace', @@ -784,9 +792,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallFQN */', - [ + 'function call, fully qualified name' => [ + 'testMarker' => '/* testFunctionCallFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -817,9 +825,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionCallUnqualified */', - [ + 'function call, unqualified name' => [ + 'testMarker' => '/* testFunctionCallUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'function_name', @@ -830,9 +838,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testFunctionPartiallyQualified */', - [ + 'function call, partially qualified name' => [ + 'testMarker' => '/* testFunctionCallPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -851,9 +859,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchRelative */', - [ + 'catch, namespace relative name' => [ + 'testMarker' => '/* testCatchRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -880,9 +888,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchFQN */', - [ + 'catch, fully qualified name' => [ + 'testMarker' => '/* testCatchFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -897,9 +905,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchUnqualified */', - [ + 'catch, unqualified name' => [ + 'testMarker' => '/* testCatchUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Exception', @@ -910,9 +918,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testCatchPartiallyQualified */', - [ + 'catch, partially qualified name' => [ + 'testMarker' => '/* testCatchPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -931,9 +939,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewRelative */', - [ + 'class instantiation, namespace relative name' => [ + 'testMarker' => '/* testNewRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -952,9 +960,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewFQN */', - [ + 'class instantiation, fully qualified name' => [ + 'testMarker' => '/* testNewFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -977,9 +985,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewUnqualified */', - [ + 'class instantiation, unqualified name' => [ + 'testMarker' => '/* testNewUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -990,9 +998,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testNewPartiallyQualified */', - [ + 'class instantiation, partially qualified name' => [ + 'testMarker' => '/* testNewPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -1011,9 +1019,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonRelative */', - [ + 'double colon class access, namespace relative name' => [ + 'testMarker' => '/* testDoubleColonRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1032,9 +1040,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonFQN */', - [ + 'double colon class access, fully qualified name' => [ + 'testMarker' => '/* testDoubleColonFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -1049,9 +1057,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonUnqualified */', - [ + 'double colon class access, unqualified name' => [ + 'testMarker' => '/* testDoubleColonUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -1062,9 +1070,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testDoubleColonPartiallyQualified */', - [ + 'double colon class access, partially qualified name' => [ + 'testMarker' => '/* testDoubleColonPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Level', @@ -1083,9 +1091,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfRelative */', - [ + 'instanceof, namespace relative name' => [ + 'testMarker' => '/* testInstanceOfRelative */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1104,9 +1112,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfFQN */', - [ + 'instanceof, fully qualified name' => [ + 'testMarker' => '/* testInstanceOfFQN */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', @@ -1129,9 +1137,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfUnqualified */', - [ + 'instanceof, unqualified name' => [ + 'testMarker' => '/* testInstanceOfUnqualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'ClassName', @@ -1142,9 +1150,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInstanceOfPartiallyQualified */', - [ + 'instanceof, partially qualified name' => [ + 'testMarker' => '/* testInstanceOfPartiallyQualified */', + 'expectedTokens' => [ [ 'type' => 'T_STRING', 'content' => 'Partially', @@ -1163,9 +1171,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInvalidInPHP8Whitespace */', - [ + 'function call, namespace relative, with whitespace (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Whitespace */', + 'expectedTokens' => [ [ 'type' => 'T_NAMESPACE', 'content' => 'namespace', @@ -1213,9 +1221,9 @@ public function dataIdentifierTokenization() ], ], ], - [ - '/* testInvalidInPHP8Comments */', - [ + 'double colon class access, fully qualified, with whitespace and comments (invalid in PHP 8)' => [ + 'testMarker' => '/* testInvalidInPHP8Comments */', + 'expectedTokens' => [ [ 'type' => 'T_NS_SEPARATOR', 'content' => '\\', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php index b60d524b0..4d15a41fe 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/IsCamelCapsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php @@ -4,15 +4,20 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core; +namespace PHP_CodeSniffer\Tests\Core\Util; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; -class IsCamelCapsTest extends TestCase +/** + * Tests for the \PHP_CodeSniffer\Util\Common::isCamelCaps method. + * + * @covers \PHP_CodeSniffer\Util\Common::isCamelCaps + */ +final class IsCamelCapsTest extends TestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php new file mode 100644 index 000000000..48790a888 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php @@ -0,0 +1,224 @@ + + * @copyright 2019 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Sniffs\Comments::suggestType() method. + * + * @covers \PHP_CodeSniffer\Util\Common::suggestType + */ +final class SuggestTypeTest extends TestCase +{ + + + /** + * Test passing an empty type to the suggestType() method. + * + * @return void + */ + public function testSuggestTypeEmpty() + { + $this->assertSame('', Common::suggestType('')); + + }//end testSuggestTypeEmpty() + + + /** + * Test passing one of the allowed types to the suggestType() method. + * + * @param string $varType The type. + * + * @dataProvider dataSuggestTypeAllowedType + * + * @return void + */ + public function testSuggestTypeAllowedType($varType) + { + $result = Common::suggestType($varType); + $this->assertSame($varType, $result); + + }//end testSuggestTypeAllowedType() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedType() + * + * @return array> + */ + public static function dataSuggestTypeAllowedType() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Type: '.$type] = [$type]; + } + + return $data; + + }//end dataSuggestTypeAllowedType() + + + /** + * Test passing one of the allowed types in the wrong case to the suggestType() method. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeAllowedTypeWrongCase + * + * @return void + */ + public function testSuggestTypeAllowedTypeWrongCase($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeAllowedTypeWrongCase() + + + /** + * Data provider. + * + * @see testSuggestTypeAllowedTypeWrongCase() + * + * @return array> + */ + public static function dataSuggestTypeAllowedTypeWrongCase() + { + $data = []; + foreach (Common::$allowedTypes as $type) { + $data['Mixed case: '.$type] = [ + 'varType' => ucfirst($type), + 'expected' => $type, + ]; + $data['Uppercase: '.$type] = [ + 'varType' => strtoupper($type), + 'expected' => $type, + ]; + } + + return $data; + + }//end dataSuggestTypeAllowedTypeWrongCase() + + + /** + * Test the suggestType() method for all other cases. + * + * @param string $varType The type found. + * @param string $expected Expected suggested type. + * + * @dataProvider dataSuggestTypeOther + * + * @return void + */ + public function testSuggestTypeOther($varType, $expected) + { + $result = Common::suggestType($varType); + $this->assertSame($expected, $result); + + }//end testSuggestTypeOther() + + + /** + * Data provider. + * + * @see testSuggestTypeOther() + * + * @return array> + */ + public static function dataSuggestTypeOther() + { + return [ + // Short forms. + 'Short form type: bool, lowercase' => [ + 'varType' => 'bool', + 'expected' => 'boolean', + ], + 'Short form type: bool, uppercase' => [ + 'varType' => 'BOOL', + 'expected' => 'boolean', + ], + 'Short form type: double, lowercase' => [ + 'varType' => 'double', + 'expected' => 'float', + ], + 'Short form type: real, mixed case' => [ + 'varType' => 'Real', + 'expected' => 'float', + ], + 'Short form type: double, mixed case' => [ + 'varType' => 'DoUbLe', + 'expected' => 'float', + ], + 'Short form type: int, lowercase' => [ + 'varType' => 'int', + 'expected' => 'integer', + ], + 'Short form type: int, uppercase' => [ + 'varType' => 'INT', + 'expected' => 'integer', + ], + + // Array types. + 'Array type: mixed case keyword, empty parentheses' => [ + 'varType' => 'Array()', + 'expected' => 'array', + ], + 'Array type: short form type as value within the parentheses' => [ + 'varType' => 'array(real)', + 'expected' => 'array(float)', + ], + 'Array type: short form type as key within the parentheses' => [ + 'varType' => 'array(int => object)', + 'expected' => 'array(integer => object)', + ], + 'Array type: valid specification' => [ + 'varType' => 'array(integer => array(string => resource))', + 'expected' => 'array(integer => array(string => resource))', + ], + 'Array type: short form + uppercase types within the parentheses' => [ + 'varType' => 'ARRAY(BOOL => DOUBLE)', + 'expected' => 'array(boolean => float)', + ], + 'Array type: no space around the arrow within the parentheses' => [ + 'varType' => 'array(string=>resource)', + 'expected' => 'array(string => resource)', + ], + + // Incomplete array type. + 'Array type: incomplete specification' => [ + 'varType' => 'array(int =>', + 'expected' => 'array', + ], + + // Custom types are returned unchanged. + 'Unknown type: " => "' => [ + 'varType' => ' => ', + 'expected' => ' => ', + ], + 'Unknown type: "string[]"' => [ + 'varType' => 'string[]', + 'expected' => 'string[]', + ], + 'Unknown type: "\DateTime"' => [ + 'varType' => '\DateTime', + 'expected' => '\DateTime', + ], + ]; + + }//end dataSuggestTypeOther() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php index 8ef57b7af..1672411de 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php @@ -4,7 +4,7 @@ * * @author Juliette Reinders Folmer * @copyright 2019 Juliette Reinders Folmer. All rights reserved. - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php index c050a0c2a..c40075846 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php @@ -8,15 +8,15 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Standards; -use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; @@ -50,15 +50,17 @@ abstract class AbstractSniffUnitTest extends TestCase /** * Sets up this unit test. * + * @before + * * @return void */ - protected function setUp() + protected function setUpPrerequisites() { $class = get_class($this); $this->standardsDir = $GLOBALS['PHP_CODESNIFFER_STANDARD_DIRS'][$class]; $this->testsDir = $GLOBALS['PHP_CODESNIFFER_TEST_DIRS'][$class]; - }//end setUp() + }//end setUpPrerequisites() /** @@ -88,7 +90,7 @@ protected function getTestFiles($testFileBase) } // Put them in order. - sort($testFiles); + sort($testFiles, SORT_NATURAL); return $testFiles; @@ -132,7 +134,7 @@ final public function testSniff() if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG']) === true) { $config = $GLOBALS['PHP_CODESNIFFER_CONFIG']; } else { - $config = new Config(); + $config = new ConfigDouble(); $config->cache = false; $GLOBALS['PHP_CODESNIFFER_CONFIG'] = $config; } @@ -188,15 +190,17 @@ final public function testSniff() // Check for a .fixed file to check for accuracy of fixes. $fixedFile = $testFile.'.fixed'; + $filename = basename($testFile); if (file_exists($fixedFile) === true) { $diff = $phpcsFile->fixer->generateDiff($fixedFile); if (trim($diff) !== '') { - $filename = basename($testFile); $fixedFilename = basename($fixedFile); $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; } + } else if (is_callable([$this, 'addWarning']) === true) { + $this->addWarning("Missing fixed version of $filename to verify the accuracy of fixes, while the sniff is making fixes against the test case file"); } - } + }//end if // Restore the config. $config->setSettings($oldConfig); @@ -431,7 +435,6 @@ public function generateFailureMessages(LocalFile $file) */ public function setCliValues($filename, $config) { - return; }//end setCliValues() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php index 24527dd51..e355d90da 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests\Standards; @@ -61,20 +61,11 @@ public static function suite() foreach ($installedStandards as $standard => $details) { Autoload::addSearchPath($details['path'], $details['namespace']); - // If the test is running PEAR installed, the built-in standards - // are split into different directories; one for the sniffs and - // a different file system location for tests. - if ($isInstalled === true && is_dir(dirname($details['path']).DIRECTORY_SEPARATOR.'Generic') === true) { - $testPath = realpath(__DIR__.'/../../src/Standards/'.$standard); - } else { - $testPath = $details['path']; - } - if (in_array($standard, $ignoreTestsForStandards, true) === true) { continue; } - $testsDir = $testPath.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR; + $testsDir = $details['path'].DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR; if (is_dir($testsDir) === false) { // No tests for this standard. continue; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php index 9eb269f8b..ff7bde7e4 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php index 43db293d5..a4dabf5fc 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Tests; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php index 47084d113..8d91b156f 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php @@ -4,7 +4,7 @@ * * @author Greg Sherwood * @copyright 2006-2017 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ if (defined('PHP_CODESNIFFER_IN_TESTS') === false) { @@ -44,13 +44,6 @@ class_alias('PHPUnit_TextUI_TestRunner', 'PHPUnit'.'\TextUI\TestRunner'); class_alias('PHPUnit_Framework_TestResult', 'PHPUnit'.'\Framework\TestResult'); } -// Determine whether this is a PEAR install or not. -$GLOBALS['PHP_CODESNIFFER_PEAR'] = false; - -if (is_file(__DIR__.'/../autoload.php') === false) { - $GLOBALS['PHP_CODESNIFFER_PEAR'] = true; -} - /** * A global util function to help print unit test fixing data. diff --git a/app/vendor/symfony/config/Builder/ClassBuilder.php b/app/vendor/symfony/config/Builder/ClassBuilder.php index 8194a1526..619ebd857 100644 --- a/app/vendor/symfony/config/Builder/ClassBuilder.php +++ b/app/vendor/symfony/config/Builder/ClassBuilder.php @@ -119,7 +119,7 @@ public function addMethod(string $name, string $body, array $params = []): void $this->methods[] = new Method(strtr($body, ['NAME' => $this->camelCase($name)] + $params)); } - public function addProperty(string $name, string $classType = null, string $defaultValue = null): Property + public function addProperty(string $name, ?string $classType = null, ?string $defaultValue = null): Property { $property = new Property($name, '_' !== $name[0] ? $this->camelCase($name) : $name); if (null !== $classType) { diff --git a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php index 2f00a99be..d43d814eb 100644 --- a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php +++ b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php @@ -478,8 +478,8 @@ private function buildToArray(ClassBuilder $class): void if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() - ? 'array_map(function ($v) { return $v instanceof CLASS ? $v->toArray() : $v; }, $this->PROPERTY)' - : 'array_map(function ($v) { return $v->toArray(); }, $this->PROPERTY)' + ? 'array_map(fn ($v) => $v instanceof CLASS ? $v->toArray() : $v, $this->PROPERTY)' + : 'array_map(fn ($v) => $v->toArray(), $this->PROPERTY)' ; } else { $code = $p->areScalarsAllowed() @@ -514,8 +514,8 @@ private function buildConstructor(ClassBuilder $class): void if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() - ? 'array_map(function ($v) { return \is_array($v) ? new '.$p->getType().'($v) : $v; }, $value[\'ORG_NAME\'])' - : 'array_map(function ($v) { return new '.$p->getType().'($v); }, $value[\'ORG_NAME\'])' + ? 'array_map(fn ($v) => \is_array($v) ? new '.$p->getType().'($v) : $v, $value[\'ORG_NAME\'])' + : 'array_map(fn ($v) => new '.$p->getType().'($v), $value[\'ORG_NAME\'])' ; } else { $code = $p->areScalarsAllowed() @@ -589,7 +589,6 @@ private function hasNormalizationClosures(NodeInterface $node): bool } catch (\ReflectionException) { return false; } - $r->setAccessible(true); return [] !== $r->getValue($node); } diff --git a/app/vendor/symfony/config/ConfigCacheInterface.php b/app/vendor/symfony/config/ConfigCacheInterface.php index be7f0986c..f8d270634 100644 --- a/app/vendor/symfony/config/ConfigCacheInterface.php +++ b/app/vendor/symfony/config/ConfigCacheInterface.php @@ -43,5 +43,5 @@ public function isFresh(): bool; * * @throws \RuntimeException When the cache file cannot be written */ - public function write(string $content, array $metadata = null); + public function write(string $content, ?array $metadata = null); } diff --git a/app/vendor/symfony/config/Definition/BaseNode.php b/app/vendor/symfony/config/Definition/BaseNode.php index 85f0f7eeb..6e2a19227 100644 --- a/app/vendor/symfony/config/Definition/BaseNode.php +++ b/app/vendor/symfony/config/Definition/BaseNode.php @@ -46,7 +46,7 @@ abstract class BaseNode implements NodeInterface /** * @throws \InvalidArgumentException if the name contains a period */ - public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR) { if (str_contains($name = (string) $name, $pathSeparator)) { throw new \InvalidArgumentException('The name must not contain ".'.$pathSeparator.'".'); diff --git a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php index 0110f0502..7a82334ee 100644 --- a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -37,7 +37,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition protected $nodeBuilder; protected $normalizeKeys = true; - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { parent::__construct($name, $parent); @@ -126,7 +126,7 @@ public function addDefaultsIfNotSet(): static * * @return $this */ - public function addDefaultChildrenIfNoneSet(int|string|array $children = null): static + public function addDefaultChildrenIfNoneSet(int|string|array|null $children = null): static { $this->addDefaultChildren = $children; @@ -169,7 +169,7 @@ public function disallowNewKeysInSubsequentConfigs(): static * * @return $this */ - public function fixXmlConfig(string $singular, string $plural = null): static + public function fixXmlConfig(string $singular, ?string $plural = null): static { $this->normalization()->remap($singular, $plural); @@ -348,7 +348,7 @@ protected function getNodeBuilder(): NodeBuilder protected function createNode(): NodeInterface { - if (null === $this->prototype) { + if (!isset($this->prototype)) { $node = new ArrayNode($this->name, $this->parent, $this->pathSeparator); $this->validateConcreteNode($node); @@ -382,7 +382,7 @@ protected function createNode(): NodeInterface if (false !== $this->addDefaultChildren) { $node->setAddChildrenIfNoneSet($this->addDefaultChildren); - if ($this->prototype instanceof static && null === $this->prototype->prototype) { + if ($this->prototype instanceof static && !isset($this->prototype->prototype)) { $this->prototype->addDefaultsIfNotSet(); } } @@ -404,18 +404,18 @@ protected function createNode(): NodeInterface $node->setDeprecated($this->deprecation['package'], $this->deprecation['version'], $this->deprecation['message']); } - if (null !== $this->normalization) { + if (isset($this->normalization)) { $node->setNormalizationClosures($this->normalization->before); $node->setNormalizedTypes($this->normalization->declaredTypes); $node->setXmlRemappings($this->normalization->remappings); } - if (null !== $this->merge) { + if (isset($this->merge)) { $node->setAllowOverwrite($this->merge->allowOverwrite); $node->setAllowFalse($this->merge->allowFalse); } - if (null !== $this->validation) { + if (isset($this->validation)) { $node->setFinalValidationClosures($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php index 3d8fad4d5..15e63961a 100644 --- a/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php @@ -21,7 +21,7 @@ */ class BooleanNodeDefinition extends ScalarNodeDefinition { - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { parent::__construct($name, $parent); diff --git a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php index 9cb441481..93cdb49dd 100644 --- a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php @@ -42,7 +42,7 @@ public function __construct(NodeDefinition $node) * * @return $this */ - public function always(\Closure $then = null): static + public function always(?\Closure $then = null): static { $this->ifPart = static fn () => true; $this->allowedTypes = self::TYPE_ANY; @@ -61,7 +61,7 @@ public function always(\Closure $then = null): static * * @return $this */ - public function ifTrue(\Closure $closure = null): static + public function ifTrue(?\Closure $closure = null): static { $this->ifPart = $closure ?? static fn ($v) => true === $v; $this->allowedTypes = self::TYPE_ANY; diff --git a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php index 7cda0bc7d..93069d437 100644 --- a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php @@ -39,7 +39,7 @@ public function __construct() * * @return $this */ - public function setParent(ParentNodeDefinitionInterface $parent = null): static + public function setParent(?ParentNodeDefinitionInterface $parent = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/form', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php index 1cd32ca3e..cf2173e17 100644 --- a/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/NodeDefinition.php @@ -38,7 +38,7 @@ abstract class NodeDefinition implements NodeParentInterface protected $parent; protected $attributes = []; - public function __construct(?string $name, NodeParentInterface $parent = null) + public function __construct(?string $name, ?NodeParentInterface $parent = null) { $this->parent = $parent; $this->name = $name; @@ -91,7 +91,7 @@ public function attribute(string $key, mixed $value): static /** * Returns the parent node. */ - public function end(): NodeParentInterface|NodeBuilder|NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition|null + public function end(): NodeParentInterface|NodeBuilder|self|ArrayNodeDefinition|VariableNodeDefinition|null { return $this->parent; } @@ -105,7 +105,7 @@ public function getNode(bool $forceRootNode = false): NodeInterface $this->parent = null; } - if (null !== $this->normalization) { + if (isset($this->normalization)) { $allowedTypes = []; foreach ($this->normalization->before as $expr) { $allowedTypes[] = $expr->allowedTypes; @@ -115,7 +115,7 @@ public function getNode(bool $forceRootNode = false): NodeInterface $this->normalization->declaredTypes = $allowedTypes; } - if (null !== $this->validation) { + if (isset($this->validation)) { $this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php b/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php index 0e362d9fa..1f6b34441 100644 --- a/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php @@ -36,7 +36,7 @@ public function __construct(NodeDefinition $node) * * @return $this */ - public function remap(string $key, string $plural = null): static + public function remap(string $key, ?string $plural = null): static { $this->remappings[] = [$key, null === $plural ? $key.'s' : $plural]; @@ -48,7 +48,7 @@ public function remap(string $key, string $plural = null): static * * @return ExprBuilder|$this */ - public function before(\Closure $closure = null): ExprBuilder|static + public function before(?\Closure $closure = null): ExprBuilder|static { if (null !== $closure) { $this->before[] = $closure; diff --git a/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php b/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php index 4f868f703..f7da3e794 100644 --- a/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/TreeBuilder.php @@ -20,10 +20,17 @@ */ class TreeBuilder implements NodeParentInterface { + /** + * @var NodeInterface|null + */ protected $tree; + + /** + * @var NodeDefinition + */ protected $root; - public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null) + public function __construct(string $name, string $type = 'array', ?NodeBuilder $builder = null) { $builder ??= new NodeBuilder(); $this->root = $builder->node($name, $type)->setParent($this); @@ -44,11 +51,7 @@ public function getRootNode(): NodeDefinition|ArrayNodeDefinition */ public function buildTree(): NodeInterface { - if (null !== $this->tree) { - return $this->tree; - } - - return $this->tree = $this->root->getNode(true); + return $this->tree ??= $this->root->getNode(true); } /** diff --git a/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php b/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php index 1bee851b6..64623d6d6 100644 --- a/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/ValidationBuilder.php @@ -31,7 +31,7 @@ public function __construct(NodeDefinition $node) * * @return ExprBuilder|$this */ - public function rule(\Closure $closure = null): ExprBuilder|static + public function rule(?\Closure $closure = null): ExprBuilder|static { if (null !== $closure) { $this->rules[] = $closure; diff --git a/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php index c49391f44..a4cc53a55 100644 --- a/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php @@ -33,11 +33,11 @@ protected function createNode(): NodeInterface { $node = $this->instantiateNode(); - if (null !== $this->normalization) { + if (isset($this->normalization)) { $node->setNormalizationClosures($this->normalization->before); } - if (null !== $this->merge) { + if (isset($this->merge)) { $node->setAllowOverwrite($this->merge->allowOverwrite); } @@ -55,7 +55,7 @@ protected function createNode(): NodeInterface $node->setDeprecated($this->deprecation['package'], $this->deprecation['version'], $this->deprecation['message']); } - if (null !== $this->validation) { + if (isset($this->validation)) { $node->setFinalValidationClosures($this->validation->rules); } diff --git a/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php b/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php index 006a444be..13fe45ca4 100644 --- a/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php +++ b/app/vendor/symfony/config/Definition/Configurator/DefinitionConfigurator.php @@ -29,7 +29,7 @@ public function __construct( ) { } - public function import(string $resource, string $type = null, bool $ignoreErrors = false): void + public function import(string $resource, ?string $type = null, bool $ignoreErrors = false): void { $this->loader->setCurrentDir(\dirname($this->path)); $this->loader->import($resource, $type, $ignoreErrors, $this->file); diff --git a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php index 34f93ce07..aac2d8456 100644 --- a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php @@ -34,7 +34,7 @@ class XmlReferenceDumper /** * @return string */ - public function dump(ConfigurationInterface $configuration, string $namespace = null) + public function dump(ConfigurationInterface $configuration, ?string $namespace = null) { return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace); } @@ -42,7 +42,7 @@ public function dump(ConfigurationInterface $configuration, string $namespace = /** * @return string */ - public function dumpNode(NodeInterface $node, string $namespace = null) + public function dumpNode(NodeInterface $node, ?string $namespace = null) { $this->reference = ''; $this->writeNode($node, 0, true, $namespace); @@ -52,7 +52,7 @@ public function dumpNode(NodeInterface $node, string $namespace = null) return $ref; } - private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null): void + private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, ?string $namespace = null): void { $rootName = ($root ? 'config' : $node->getName()); $rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null)); diff --git a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php index 97a391ada..67caa05a5 100644 --- a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -80,7 +80,7 @@ public function dumpNode(NodeInterface $node) return $ref; } - private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void + private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false): void { $comments = []; $default = ''; diff --git a/app/vendor/symfony/config/Definition/EnumNode.php b/app/vendor/symfony/config/Definition/EnumNode.php index 4edeae904..f5acbe906 100644 --- a/app/vendor/symfony/config/Definition/EnumNode.php +++ b/app/vendor/symfony/config/Definition/EnumNode.php @@ -22,7 +22,7 @@ class EnumNode extends ScalarNode { private array $values; - public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { if (!$values) { throw new \InvalidArgumentException('$values must contain at least one element.'); diff --git a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php index 506f787ca..940b894f7 100644 --- a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php +++ b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php @@ -34,7 +34,7 @@ public function __construct( parent::__construct($locator); } - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { // the loader variable is exposed to the included file below $loader = $this; @@ -57,7 +57,7 @@ public function load(mixed $resource, string $type = null): mixed return null; } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { if (!\is_string($resource)) { return false; diff --git a/app/vendor/symfony/config/Definition/NumericNode.php b/app/vendor/symfony/config/Definition/NumericNode.php index da32b843a..22359fd25 100644 --- a/app/vendor/symfony/config/Definition/NumericNode.php +++ b/app/vendor/symfony/config/Definition/NumericNode.php @@ -23,7 +23,7 @@ class NumericNode extends ScalarNode protected $min; protected $max; - public function __construct(?string $name, NodeInterface $parent = null, int|float $min = null, int|float $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) + public function __construct(?string $name, ?NodeInterface $parent = null, int|float|null $min = null, int|float|null $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { parent::__construct($name, $parent, $pathSeparator); $this->min = $min; diff --git a/app/vendor/symfony/config/Definition/Processor.php b/app/vendor/symfony/config/Definition/Processor.php index dc3d4c69b..272ddcc44 100644 --- a/app/vendor/symfony/config/Definition/Processor.php +++ b/app/vendor/symfony/config/Definition/Processor.php @@ -67,7 +67,7 @@ public function processConfiguration(ConfigurationInterface $configuration, arra * @param string $key The key to normalize * @param string|null $plural The plural form of the key if it is irregular */ - public static function normalizeConfig(array $config, string $key, string $plural = null): array + public static function normalizeConfig(array $config, string $key, ?string $plural = null): array { $plural ??= $key.'s'; diff --git a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php index da0b55ba8..2d2a4de00 100644 --- a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php +++ b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php @@ -18,7 +18,7 @@ */ class FileLoaderImportCircularReferenceException extends LoaderLoadException { - public function __construct(array $resources, int $code = 0, \Throwable $previous = null) + public function __construct(array $resources, int $code = 0, ?\Throwable $previous = null) { $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]); diff --git a/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php b/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php index c5173ae58..a3fcc901b 100644 --- a/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php +++ b/app/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php @@ -20,7 +20,7 @@ class FileLocatorFileNotFoundException extends \InvalidArgumentException { private array $paths; - public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = []) + public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null, array $paths = []) { parent::__construct($message, $code, $previous); diff --git a/app/vendor/symfony/config/Exception/LoaderLoadException.php b/app/vendor/symfony/config/Exception/LoaderLoadException.php index 57afd6a8d..2b40688a5 100644 --- a/app/vendor/symfony/config/Exception/LoaderLoadException.php +++ b/app/vendor/symfony/config/Exception/LoaderLoadException.php @@ -25,7 +25,7 @@ class LoaderLoadException extends \Exception * @param \Throwable|null $previous A previous exception * @param string|null $type The type of resource */ - public function __construct(mixed $resource, string $sourceResource = null, int $code = 0, \Throwable $previous = null, string $type = null) + public function __construct(mixed $resource, ?string $sourceResource = null, int $code = 0, ?\Throwable $previous = null, ?string $type = null) { if (!\is_string($resource)) { try { diff --git a/app/vendor/symfony/config/FileLocator.php b/app/vendor/symfony/config/FileLocator.php index e147d9b1a..99c35bd26 100644 --- a/app/vendor/symfony/config/FileLocator.php +++ b/app/vendor/symfony/config/FileLocator.php @@ -31,9 +31,11 @@ public function __construct(string|array $paths = []) } /** - * @return string|array + * @return string|string[] + * + * @psalm-return ($first is true ? string : string[]) */ - public function locate(string $name, string $currentPath = null, bool $first = true) + public function locate(string $name, ?string $currentPath = null, bool $first = true) { if ('' === $name) { throw new \InvalidArgumentException('An empty file name is not valid to be located.'); diff --git a/app/vendor/symfony/config/FileLocatorInterface.php b/app/vendor/symfony/config/FileLocatorInterface.php index e3ca1d49c..755cf018a 100644 --- a/app/vendor/symfony/config/FileLocatorInterface.php +++ b/app/vendor/symfony/config/FileLocatorInterface.php @@ -25,10 +25,12 @@ interface FileLocatorInterface * @param string|null $currentPath The current path * @param bool $first Whether to return the first occurrence or an array of filenames * - * @return string|array The full path to the file or an array of file paths + * @return string|string[] The full path to the file or an array of file paths * * @throws \InvalidArgumentException If $name is empty * @throws FileLocatorFileNotFoundException If a file is not found + * + * @psalm-return ($first is true ? string : string[]) */ - public function locate(string $name, string $currentPath = null, bool $first = true); + public function locate(string $name, ?string $currentPath = null, bool $first = true); } diff --git a/app/vendor/symfony/config/Loader/DelegatingLoader.php b/app/vendor/symfony/config/Loader/DelegatingLoader.php index fac3724e9..045a559e2 100644 --- a/app/vendor/symfony/config/Loader/DelegatingLoader.php +++ b/app/vendor/symfony/config/Loader/DelegatingLoader.php @@ -28,7 +28,7 @@ public function __construct(LoaderResolverInterface $resolver) $this->resolver = $resolver; } - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { if (false === $loader = $this->resolver->resolve($resource, $type)) { throw new LoaderLoadException($resource, null, 0, null, $type); @@ -37,7 +37,7 @@ public function load(mixed $resource, string $type = null): mixed return $loader->load($resource, $type); } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { return false !== $this->resolver->resolve($resource, $type); } diff --git a/app/vendor/symfony/config/Loader/FileLoader.php b/app/vendor/symfony/config/Loader/FileLoader.php index 8cfaa23ba..8275ffcd3 100644 --- a/app/vendor/symfony/config/Loader/FileLoader.php +++ b/app/vendor/symfony/config/Loader/FileLoader.php @@ -31,7 +31,7 @@ abstract class FileLoader extends Loader private ?string $currentDir = null; - public function __construct(FileLocatorInterface $locator, string $env = null) + public function __construct(FileLocatorInterface $locator, ?string $env = null) { $this->locator = $locator; parent::__construct($env); @@ -70,7 +70,7 @@ public function getLocator(): FileLocatorInterface * @throws FileLoaderImportCircularReferenceException * @throws FileLocatorFileNotFoundException */ - public function import(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null, string|array $exclude = null) + public function import(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, string|array|null $exclude = null) { if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) { $excluded = []; @@ -101,7 +101,7 @@ public function import(mixed $resource, string $type = null, bool $ignoreErrors /** * @internal */ - protected function glob(string $pattern, bool $recursive, array|GlobResource &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable + protected function glob(string $pattern, bool $recursive, array|GlobResource|null &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []): iterable { if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) { $prefix = $pattern; @@ -133,7 +133,7 @@ protected function glob(string $pattern, bool $recursive, array|GlobResource &$r yield from $resource; } - private function doImport(mixed $resource, string $type = null, bool $ignoreErrors = false, string $sourceResource = null): mixed + private function doImport(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null): mixed { try { $loader = $this->resolve($resource, $type); diff --git a/app/vendor/symfony/config/Loader/GlobFileLoader.php b/app/vendor/symfony/config/Loader/GlobFileLoader.php index f921ec555..31eebf69d 100644 --- a/app/vendor/symfony/config/Loader/GlobFileLoader.php +++ b/app/vendor/symfony/config/Loader/GlobFileLoader.php @@ -18,12 +18,12 @@ */ class GlobFileLoader extends FileLoader { - public function load(mixed $resource, string $type = null): mixed + public function load(mixed $resource, ?string $type = null): mixed { return $this->import($resource); } - public function supports(mixed $resource, string $type = null): bool + public function supports(mixed $resource, ?string $type = null): bool { return 'glob' === $type; } diff --git a/app/vendor/symfony/config/Loader/Loader.php b/app/vendor/symfony/config/Loader/Loader.php index 36e85ad34..66c38bbea 100644 --- a/app/vendor/symfony/config/Loader/Loader.php +++ b/app/vendor/symfony/config/Loader/Loader.php @@ -23,7 +23,7 @@ abstract class Loader implements LoaderInterface protected $resolver; protected $env; - public function __construct(string $env = null) + public function __construct(?string $env = null) { $this->env = $env; } @@ -46,7 +46,7 @@ public function setResolver(LoaderResolverInterface $resolver) * * @return mixed */ - public function import(mixed $resource, string $type = null) + public function import(mixed $resource, ?string $type = null) { return $this->resolve($resource, $type)->load($resource, $type); } @@ -56,7 +56,7 @@ public function import(mixed $resource, string $type = null) * * @throws LoaderLoadException If no loader is found */ - public function resolve(mixed $resource, string $type = null): LoaderInterface + public function resolve(mixed $resource, ?string $type = null): LoaderInterface { if ($this->supports($resource, $type)) { return $this; diff --git a/app/vendor/symfony/config/Loader/LoaderInterface.php b/app/vendor/symfony/config/Loader/LoaderInterface.php index 4e0746d4d..190d2c630 100644 --- a/app/vendor/symfony/config/Loader/LoaderInterface.php +++ b/app/vendor/symfony/config/Loader/LoaderInterface.php @@ -25,7 +25,7 @@ interface LoaderInterface * * @throws \Exception If something went wrong */ - public function load(mixed $resource, string $type = null); + public function load(mixed $resource, ?string $type = null); /** * Returns whether this class supports the given resource. @@ -34,7 +34,7 @@ public function load(mixed $resource, string $type = null); * * @return bool */ - public function supports(mixed $resource, string $type = null); + public function supports(mixed $resource, ?string $type = null); /** * Gets the loader resolver. diff --git a/app/vendor/symfony/config/Loader/LoaderResolver.php b/app/vendor/symfony/config/Loader/LoaderResolver.php index 670e32012..72ab33411 100644 --- a/app/vendor/symfony/config/Loader/LoaderResolver.php +++ b/app/vendor/symfony/config/Loader/LoaderResolver.php @@ -36,7 +36,7 @@ public function __construct(array $loaders = []) } } - public function resolve(mixed $resource, string $type = null): LoaderInterface|false + public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false { foreach ($this->loaders as $loader) { if ($loader->supports($resource, $type)) { diff --git a/app/vendor/symfony/config/Loader/LoaderResolverInterface.php b/app/vendor/symfony/config/Loader/LoaderResolverInterface.php index 076c5207c..a8bb3a437 100644 --- a/app/vendor/symfony/config/Loader/LoaderResolverInterface.php +++ b/app/vendor/symfony/config/Loader/LoaderResolverInterface.php @@ -23,5 +23,5 @@ interface LoaderResolverInterface * * @param string|null $type The resource type or null if unknown */ - public function resolve(mixed $resource, string $type = null): LoaderInterface|false; + public function resolve(mixed $resource, ?string $type = null): LoaderInterface|false; } diff --git a/app/vendor/symfony/config/Resource/ClassExistenceResource.php b/app/vendor/symfony/config/Resource/ClassExistenceResource.php index 2f262bac8..eab04b8d0 100644 --- a/app/vendor/symfony/config/Resource/ClassExistenceResource.php +++ b/app/vendor/symfony/config/Resource/ClassExistenceResource.php @@ -34,7 +34,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface * @param string $resource The fully-qualified class name * @param bool|null $exists Boolean when the existence check has already been done */ - public function __construct(string $resource, bool $exists = null) + public function __construct(string $resource, ?bool $exists = null) { $this->resource = $resource; if (null !== $exists) { @@ -116,7 +116,7 @@ public function __sleep(): array /** * @internal */ - public function __wakeup() + public function __wakeup(): void { if (\is_bool($this->exists)) { $this->exists = [$this->exists, null]; @@ -139,7 +139,7 @@ public function __wakeup() * * @internal */ - public static function throwOnRequiredClass(string $class, \Exception $previous = null): void + public static function throwOnRequiredClass(string $class, ?\Exception $previous = null): void { // If the passed class is the resource being checked, we shouldn't throw. if (null === $previous && self::$autoloadedClass === $class) { diff --git a/app/vendor/symfony/config/Resource/DirectoryResource.php b/app/vendor/symfony/config/Resource/DirectoryResource.php index 7560cd3b3..df486a085 100644 --- a/app/vendor/symfony/config/Resource/DirectoryResource.php +++ b/app/vendor/symfony/config/Resource/DirectoryResource.php @@ -29,7 +29,7 @@ class DirectoryResource implements SelfCheckingResourceInterface * * @throws \InvalidArgumentException */ - public function __construct(string $resource, string $pattern = null) + public function __construct(string $resource, ?string $pattern = null) { $resolvedResource = realpath($resource) ?: (file_exists($resource) ? $resource : false); $this->pattern = $pattern; diff --git a/app/vendor/symfony/config/Resource/FileExistenceResource.php b/app/vendor/symfony/config/Resource/FileExistenceResource.php index e7b91ff38..666866ee4 100644 --- a/app/vendor/symfony/config/Resource/FileExistenceResource.php +++ b/app/vendor/symfony/config/Resource/FileExistenceResource.php @@ -38,7 +38,7 @@ public function __construct(string $resource) public function __toString(): string { - return $this->resource; + return 'existence.'.$this->resource; } public function getResource(): string diff --git a/app/vendor/symfony/config/Resource/ResourceInterface.php b/app/vendor/symfony/config/Resource/ResourceInterface.php index 4fbe32183..a97671d14 100644 --- a/app/vendor/symfony/config/Resource/ResourceInterface.php +++ b/app/vendor/symfony/config/Resource/ResourceInterface.php @@ -16,7 +16,7 @@ * * @author Fabien Potencier */ -interface ResourceInterface +interface ResourceInterface extends \Stringable { /** * Returns a string representation of the Resource. diff --git a/app/vendor/symfony/config/ResourceCheckerConfigCache.php b/app/vendor/symfony/config/ResourceCheckerConfigCache.php index a8478a8cc..1e58d21ed 100644 --- a/app/vendor/symfony/config/ResourceCheckerConfigCache.php +++ b/app/vendor/symfony/config/ResourceCheckerConfigCache.php @@ -109,7 +109,7 @@ public function isFresh(): bool * * @throws \RuntimeException When cache file can't be written */ - public function write(string $content, array $metadata = null) + public function write(string $content, ?array $metadata = null) { $mode = 0666; $umask = umask(); @@ -150,7 +150,7 @@ private function safelyUnserialize(string $file): mixed $signalingException = new \UnexpectedValueException(); $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { - if (__FILE__ === $file) { + if (__FILE__ === $file && !\in_array($type, [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { throw $signalingException; } diff --git a/app/vendor/symfony/config/Util/XmlUtils.php b/app/vendor/symfony/config/Util/XmlUtils.php index cc024da46..eb6f0f51a 100644 --- a/app/vendor/symfony/config/Util/XmlUtils.php +++ b/app/vendor/symfony/config/Util/XmlUtils.php @@ -42,7 +42,7 @@ private function __construct() * @throws InvalidXmlException When parsing of XML with schema or callable produces any errors unrelated to the XML parsing itself * @throws \RuntimeException When DOM extension is missing */ - public static function parse(string $content, string|callable $schemaOrCallable = null): \DOMDocument + public static function parse(string $content, string|callable|null $schemaOrCallable = null): \DOMDocument { if (!\extension_loaded('dom')) { throw new \LogicException('Extension DOM is required.'); @@ -112,7 +112,7 @@ public static function parse(string $content, string|callable $schemaOrCallable * @throws XmlParsingException When XML parsing returns any errors * @throws \RuntimeException When DOM extension is missing */ - public static function loadFile(string $file, string|callable $schemaOrCallable = null): \DOMDocument + public static function loadFile(string $file, string|callable|null $schemaOrCallable = null): \DOMDocument { if (!is_file($file)) { throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file)); diff --git a/app/vendor/symfony/config/composer.json b/app/vendor/symfony/config/composer.json index a4b72c36a..dbd34f13b 100644 --- a/app/vendor/symfony/config/composer.json +++ b/app/vendor/symfony/config/composer.json @@ -18,15 +18,15 @@ "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", "symfony/polyfill-ctype": "~1.8" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/finder": "<5.4", diff --git a/app/vendor/symfony/console/Application.php b/app/vendor/symfony/console/Application.php index b7aaa6a29..b97d0872f 100644 --- a/app/vendor/symfony/console/Application.php +++ b/app/vendor/symfony/console/Application.php @@ -79,6 +79,7 @@ class Application implements ResetInterface private string $version; private ?CommandLoaderInterface $commandLoader = null; private bool $catchExceptions = true; + private bool $catchErrors = false; private bool $autoExit = true; private InputDefinition $definition; private HelperSet $helperSet; @@ -142,7 +143,7 @@ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) * * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. */ - public function run(InputInterface $input = null, OutputInterface $output = null): int + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int { if (\function_exists('putenv')) { @putenv('LINES='.$this->terminal->getHeight()); @@ -172,8 +173,11 @@ public function run(InputInterface $input = null, OutputInterface $output = null try { $exitCode = $this->doRun($input, $output); - } catch (\Exception $e) { - if (!$this->catchExceptions) { + } catch (\Throwable $e) { + if ($e instanceof \Exception && !$this->catchExceptions) { + throw $e; + } + if (!$e instanceof \Exception && !$this->catchErrors) { throw $e; } @@ -427,6 +431,14 @@ public function setCatchExceptions(bool $boolean) $this->catchExceptions = $boolean; } + /** + * Sets whether to catch errors or not during commands execution. + */ + public function setCatchErrors(bool $catchErrors = true): void + { + $this->catchErrors = $catchErrors; + } + /** * Gets whether to automatically exit after a command execution or not. */ @@ -783,7 +795,7 @@ public function find(string $name) * * @return Command[] */ - public function all(string $namespace = null) + public function all(?string $namespace = null) { $this->init(); @@ -1034,7 +1046,10 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } if (false !== $exitCode) { - exit($exitCode); + $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + + exit($event->getExitCode()); } }); } @@ -1162,7 +1177,7 @@ private function getAbbreviationSuggestions(array $abbrevs): string * * This method is not part of public API and should not be used directly. */ - public function extractNamespace(string $name, int $limit = null): string + public function extractNamespace(string $name, ?int $limit = null): string { $parts = explode(':', $name, -1); diff --git a/app/vendor/symfony/console/CHANGELOG.md b/app/vendor/symfony/console/CHANGELOG.md index 3428a57de..9ccb41d94 100644 --- a/app/vendor/symfony/console/CHANGELOG.md +++ b/app/vendor/symfony/console/CHANGELOG.md @@ -1,6 +1,15 @@ CHANGELOG ========= +6.4 +--- + + * Add `SignalMap` to map signal value to its name + * Multi-line text in vertical tables is aligned properly + * The application can also catch errors with `Application::setCatchErrors(true)` + * Add `RunCommandMessage` and `RunCommandMessageHandler` + * Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()` + 6.3 --- diff --git a/app/vendor/symfony/console/CI/GithubActionReporter.php b/app/vendor/symfony/console/CI/GithubActionReporter.php index 7e5565469..2cae6fd8b 100644 --- a/app/vendor/symfony/console/CI/GithubActionReporter.php +++ b/app/vendor/symfony/console/CI/GithubActionReporter.php @@ -57,7 +57,7 @@ public static function isGithubActionEnvironment(): bool * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message */ - public function error(string $message, string $file = null, int $line = null, int $col = null): void + public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('error', $message, $file, $line, $col); } @@ -67,7 +67,7 @@ public function error(string $message, string $file = null, int $line = null, in * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message */ - public function warning(string $message, string $file = null, int $line = null, int $col = null): void + public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('warning', $message, $file, $line, $col); } @@ -77,12 +77,12 @@ public function warning(string $message, string $file = null, int $line = null, * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message */ - public function debug(string $message, string $file = null, int $line = null, int $col = null): void + public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { $this->log('debug', $message, $file, $line, $col); } - private function log(string $type, string $message, string $file = null, int $line = null, int $col = null): void + private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void { // Some values must be encoded. $message = strtr($message, self::ESCAPED_DATA); diff --git a/app/vendor/symfony/console/Command/Command.php b/app/vendor/symfony/console/Command/Command.php index 704b112d1..9f9cb2f53 100644 --- a/app/vendor/symfony/console/Command/Command.php +++ b/app/vendor/symfony/console/Command/Command.php @@ -111,7 +111,7 @@ public static function getDefaultDescription(): ?string * * @throws LogicException When the command name is empty */ - public function __construct(string $name = null) + public function __construct(?string $name = null) { $this->definition = new InputDefinition(); @@ -152,7 +152,7 @@ public function ignoreValidationErrors() /** * @return void */ - public function setApplication(Application $application = null) + public function setApplication(?Application $application = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -460,7 +460,7 @@ public function getNativeDefinition(): InputDefinition * * @throws InvalidArgumentException When argument mode is not valid */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { @@ -484,7 +484,7 @@ public function addArgument(string $name, int $mode = null, string $description * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { diff --git a/app/vendor/symfony/console/Command/CompleteCommand.php b/app/vendor/symfony/console/Command/CompleteCommand.php index 058578d8b..23be5577b 100644 --- a/app/vendor/symfony/console/Command/CompleteCommand.php +++ b/app/vendor/symfony/console/Command/CompleteCommand.php @@ -44,9 +44,9 @@ final class CompleteCommand extends Command */ protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; - private $completionOutputs; + private array $completionOutputs; - private $isDebug = false; + private bool $isDebug = false; /** * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value diff --git a/app/vendor/symfony/console/Command/LazyCommand.php b/app/vendor/symfony/console/Command/LazyCommand.php index d56058221..b94da6665 100644 --- a/app/vendor/symfony/console/Command/LazyCommand.php +++ b/app/vendor/symfony/console/Command/LazyCommand.php @@ -45,7 +45,7 @@ public function ignoreValidationErrors(): void $this->getCommand()->ignoreValidationErrors(); } - public function setApplication(Application $application = null): void + public function setApplication(?Application $application = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -116,7 +116,7 @@ public function getNativeDefinition(): InputDefinition /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); @@ -127,7 +127,7 @@ public function addArgument(string $name, int $mode = null, string $description /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); diff --git a/app/vendor/symfony/console/Command/LockableTrait.php b/app/vendor/symfony/console/Command/LockableTrait.php index c1006a65c..cd7548f02 100644 --- a/app/vendor/symfony/console/Command/LockableTrait.php +++ b/app/vendor/symfony/console/Command/LockableTrait.php @@ -29,7 +29,7 @@ trait LockableTrait /** * Locks a command. */ - private function lock(string $name = null, bool $blocking = false): bool + private function lock(?string $name = null, bool $blocking = false): bool { if (!class_exists(SemaphoreStore::class)) { throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); diff --git a/app/vendor/symfony/console/Command/SignalableCommandInterface.php b/app/vendor/symfony/console/Command/SignalableCommandInterface.php index 4d0876003..f8eb8e522 100644 --- a/app/vendor/symfony/console/Command/SignalableCommandInterface.php +++ b/app/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -27,7 +27,7 @@ public function getSubscribedSignals(): array; * The method will be called when the application is signaled. * * @param int|false $previousExitCode - + * * @return int|false The exit code to return or false to continue the normal execution */ public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); diff --git a/app/vendor/symfony/console/Command/TraceableCommand.php b/app/vendor/symfony/console/Command/TraceableCommand.php new file mode 100644 index 000000000..9ffb68da3 --- /dev/null +++ b/app/vendor/symfony/console/Command/TraceableCommand.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Command; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Helper\HelperInterface; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @internal + * + * @author Jules Pietri + */ +final class TraceableCommand extends Command implements SignalableCommandInterface +{ + public readonly Command $command; + public int $exitCode; + public ?int $interruptedBySignal = null; + public bool $ignoreValidation; + public bool $isInteractive = false; + public string $duration = 'n/a'; + public string $maxMemoryUsage = 'n/a'; + public InputInterface $input; + public OutputInterface $output; + /** @var array */ + public array $arguments; + /** @var array */ + public array $options; + /** @var array */ + public array $interactiveInputs = []; + public array $handledSignals = []; + + public function __construct( + Command $command, + private readonly Stopwatch $stopwatch, + ) { + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + + $this->command = $command; + + // prevent call to self::getDefaultDescription() + $this->setDescription($command->getDescription()); + + parent::__construct($command->getName()); + + // init below enables calling {@see parent::run()} + [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () { + return [$this->code, $this->processTitle, $this->ignoreValidationErrors]; + }, $command, Command::class)(); + + if (\is_callable($code)) { + $this->setCode($code); + } + + if ($processTitle) { + parent::setProcessTitle($processTitle); + } + + if ($ignoreValidationErrors) { + parent::ignoreValidationErrors(); + } + + $this->ignoreValidation = $ignoreValidationErrors; + } + + public function __call(string $name, array $arguments): mixed + { + return $this->command->{$name}(...$arguments); + } + + public function getSubscribedSignals(): array + { + return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : []; + } + + public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false + { + if (!$this->command instanceof SignalableCommandInterface) { + return false; + } + + $event = $this->stopwatch->start($this->getName().'.handle_signal'); + + $exit = $this->command->handleSignal($signal, $previousExitCode); + + $event->stop(); + + if (!isset($this->handledSignals[$signal])) { + $this->handledSignals[$signal] = [ + 'handled' => 0, + 'duration' => 0, + 'memory' => 0, + ]; + } + + ++$this->handledSignals[$signal]['handled']; + $this->handledSignals[$signal]['duration'] += $event->getDuration(); + $this->handledSignals[$signal]['memory'] = max( + $this->handledSignals[$signal]['memory'], + $event->getMemory() >> 20 + ); + + return $exit; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function ignoreValidationErrors(): void + { + $this->ignoreValidation = true; + $this->command->ignoreValidationErrors(); + + parent::ignoreValidationErrors(); + } + + public function setApplication(?Application $application = null): void + { + $this->command->setApplication($application); + } + + public function getApplication(): ?Application + { + return $this->command->getApplication(); + } + + public function setHelperSet(HelperSet $helperSet): void + { + $this->command->setHelperSet($helperSet); + } + + public function getHelperSet(): ?HelperSet + { + return $this->command->getHelperSet(); + } + + public function isEnabled(): bool + { + return $this->command->isEnabled(); + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + $this->command->complete($input, $suggestions); + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setCode(callable $code): static + { + $this->command->setCode($code); + + return parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int { + $event = $this->stopwatch->start($this->getName().'.code'); + + $this->exitCode = $code($input, $output); + + $event->stop(); + + return $this->exitCode; + }); + } + + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = true): void + { + $this->command->mergeApplicationDefinition($mergeArgs); + } + + public function setDefinition(array|InputDefinition $definition): static + { + $this->command->setDefinition($definition); + + return $this; + } + + public function getDefinition(): InputDefinition + { + return $this->command->getDefinition(); + } + + public function getNativeDefinition(): InputDefinition + { + return $this->command->getNativeDefinition(); + } + + public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addArgument($name, $mode, $description, $default, $suggestedValues); + + return $this; + } + + public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static + { + $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + + return $this; + } + + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function setProcessTitle(string $title): static + { + $this->command->setProcessTitle($title); + + return parent::setProcessTitle($title); + } + + public function setHelp(string $help): static + { + $this->command->setHelp($help); + + return $this; + } + + public function getHelp(): string + { + return $this->command->getHelp(); + } + + public function getProcessedHelp(): string + { + return $this->command->getProcessedHelp(); + } + + public function getSynopsis(bool $short = false): string + { + return $this->command->getSynopsis($short); + } + + public function addUsage(string $usage): static + { + $this->command->addUsage($usage); + + return $this; + } + + public function getUsages(): array + { + return $this->command->getUsages(); + } + + public function getHelper(string $name): HelperInterface + { + return $this->command->getHelper($name); + } + + public function run(InputInterface $input, OutputInterface $output): int + { + $this->input = $input; + $this->output = $output; + $this->arguments = $input->getArguments(); + $this->options = $input->getOptions(); + $event = $this->stopwatch->start($this->getName(), 'command'); + + try { + $this->exitCode = parent::run($input, $output); + } finally { + $event->stop(); + + if ($output instanceof ConsoleOutputInterface && $output->isDebug()) { + $output->getErrorOutput()->writeln((string) $event); + } + + $this->duration = $event->getDuration().' ms'; + $this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB'; + + if ($this->isInteractive) { + $this->extractInteractiveInputs($input->getArguments(), $input->getOptions()); + } + } + + return $this->exitCode; + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + $event = $this->stopwatch->start($this->getName().'.init', 'command'); + + $this->command->initialize($input, $output); + + $event->stop(); + } + + protected function interact(InputInterface $input, OutputInterface $output): void + { + if (!$this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) { + return; + } + + $event = $this->stopwatch->start($this->getName().'.interact', 'command'); + + $this->command->interact($input, $output); + + $event->stop(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $event = $this->stopwatch->start($this->getName().'.execute', 'command'); + + $exitCode = $this->command->execute($input, $output); + + $event->stop(); + + return $exitCode; + } + + private function extractInteractiveInputs(array $arguments, array $options): void + { + foreach ($arguments as $argName => $argValue) { + if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) { + continue; + } + + $this->interactiveInputs[$argName] = $argValue; + } + + foreach ($options as $optName => $optValue) { + if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) { + continue; + } + + $this->interactiveInputs['--'.$optName] = $optValue; + } + } +} diff --git a/app/vendor/symfony/console/Completion/CompletionInput.php b/app/vendor/symfony/console/Completion/CompletionInput.php index 800b7235a..7ba41c083 100644 --- a/app/vendor/symfony/console/Completion/CompletionInput.php +++ b/app/vendor/symfony/console/Completion/CompletionInput.php @@ -31,11 +31,11 @@ final class CompletionInput extends ArgvInput public const TYPE_OPTION_NAME = 'option_name'; public const TYPE_NONE = 'none'; - private $tokens; - private $currentIndex; - private $completionType; - private $completionName; - private $completionValue = ''; + private array $tokens; + private int $currentIndex; + private string $completionType; + private ?string $completionName = null; + private string $completionValue = ''; /** * Converts a terminal string into tokens. @@ -141,7 +141,9 @@ public function bind(InputDefinition $definition): void * TYPE_OPTION_NAME when completing the name of an input option * TYPE_NONE when nothing should be completed * - * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component + * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component. + * + * @return self::TYPE_* */ public function getCompletionType(): string { diff --git a/app/vendor/symfony/console/Completion/CompletionSuggestions.php b/app/vendor/symfony/console/Completion/CompletionSuggestions.php index 719118177..549bbafbd 100644 --- a/app/vendor/symfony/console/Completion/CompletionSuggestions.php +++ b/app/vendor/symfony/console/Completion/CompletionSuggestions.php @@ -20,8 +20,8 @@ */ final class CompletionSuggestions { - private $valueSuggestions = []; - private $optionSuggestions = []; + private array $valueSuggestions = []; + private array $optionSuggestions = []; /** * Add a suggested value for an input option or argument. diff --git a/app/vendor/symfony/console/Cursor.php b/app/vendor/symfony/console/Cursor.php index b7f5a17e0..69fd3821c 100644 --- a/app/vendor/symfony/console/Cursor.php +++ b/app/vendor/symfony/console/Cursor.php @@ -19,6 +19,7 @@ final class Cursor { private OutputInterface $output; + /** @var resource */ private $input; /** diff --git a/app/vendor/symfony/console/DataCollector/CommandDataCollector.php b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php new file mode 100644 index 000000000..45138c7dc --- /dev/null +++ b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\DataCollector; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Debug\CliRequest; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\SignalRegistry\SignalMap; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * @internal + * + * @author Jules Pietri + */ +final class CommandDataCollector extends DataCollector +{ + public function collect(Request $request, Response $response, ?\Throwable $exception = null): void + { + if (!$request instanceof CliRequest) { + return; + } + + $command = $request->command; + $application = $command->getApplication(); + + $this->data = [ + 'command' => $this->cloneVar($command->command), + 'exit_code' => $command->exitCode, + 'interrupted_by_signal' => $command->interruptedBySignal, + 'duration' => $command->duration, + 'max_memory_usage' => $command->maxMemoryUsage, + 'verbosity_level' => match ($command->output->getVerbosity()) { + OutputInterface::VERBOSITY_QUIET => 'quiet', + OutputInterface::VERBOSITY_NORMAL => 'normal', + OutputInterface::VERBOSITY_VERBOSE => 'verbose', + OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose', + OutputInterface::VERBOSITY_DEBUG => 'debug', + }, + 'interactive' => $command->isInteractive, + 'validate_input' => !$command->ignoreValidation, + 'enabled' => $command->isEnabled(), + 'visible' => !$command->isHidden(), + 'input' => $this->cloneVar($command->input), + 'output' => $this->cloneVar($command->output), + 'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs), + 'signalable' => $command->getSubscribedSignals(), + 'handled_signals' => $command->handledSignals, + 'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())), + ]; + + $baseDefinition = $application->getDefinition(); + + foreach ($command->arguments as $argName => $argValue) { + if ($baseDefinition->hasArgument($argName)) { + $this->data['application_inputs'][$argName] = $this->cloneVar($argValue); + } else { + $this->data['arguments'][$argName] = $this->cloneVar($argValue); + } + } + + foreach ($command->options as $optName => $optValue) { + if ($baseDefinition->hasOption($optName)) { + $this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue); + } else { + $this->data['options'][$optName] = $this->cloneVar($optValue); + } + } + } + + public function getName(): string + { + return 'command'; + } + + /** + * @return array{ + * class?: class-string, + * executor?: string, + * file: string, + * line: int, + * } + */ + public function getCommand(): array + { + $class = $this->data['command']->getType(); + $r = new \ReflectionMethod($class, 'execute'); + + if (Command::class !== $r->getDeclaringClass()) { + return [ + 'executor' => $class.'::'.$r->name, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + $r = new \ReflectionClass($class); + + return [ + 'class' => $class, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + } + + public function getInterruptedBySignal(): ?string + { + if (isset($this->data['interrupted_by_signal'])) { + return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + } + + return null; + } + + public function getDuration(): string + { + return $this->data['duration']; + } + + public function getMaxMemoryUsage(): string + { + return $this->data['max_memory_usage']; + } + + public function getVerbosityLevel(): string + { + return $this->data['verbosity_level']; + } + + public function getInteractive(): bool + { + return $this->data['interactive']; + } + + public function getValidateInput(): bool + { + return $this->data['validate_input']; + } + + public function getEnabled(): bool + { + return $this->data['enabled']; + } + + public function getVisible(): bool + { + return $this->data['visible']; + } + + public function getInput(): Data + { + return $this->data['input']; + } + + public function getOutput(): Data + { + return $this->data['output']; + } + + /** + * @return Data[] + */ + public function getArguments(): array + { + return $this->data['arguments'] ?? []; + } + + /** + * @return Data[] + */ + public function getOptions(): array + { + return $this->data['options'] ?? []; + } + + /** + * @return Data[] + */ + public function getApplicationInputs(): array + { + return $this->data['application_inputs'] ?? []; + } + + /** + * @return Data[] + */ + public function getInteractiveInputs(): array + { + return $this->data['interactive_inputs'] ?? []; + } + + public function getSignalable(): array + { + return array_map( + static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + $this->data['signalable'] + ); + } + + public function getHandledSignals(): array + { + $keys = array_map( + static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + array_keys($this->data['handled_signals']) + ); + + return array_combine($keys, array_values($this->data['handled_signals'])); + } + + /** + * @return Data[] + */ + public function getHelperSet(): array + { + return $this->data['helper_set'] ?? []; + } + + public function reset(): void + { + $this->data = []; + } +} diff --git a/app/vendor/symfony/console/Debug/CliRequest.php b/app/vendor/symfony/console/Debug/CliRequest.php new file mode 100644 index 000000000..b023db07a --- /dev/null +++ b/app/vendor/symfony/console/Debug/CliRequest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Debug; + +use Symfony\Component\Console\Command\TraceableCommand; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * @internal + */ +final class CliRequest extends Request +{ + public function __construct( + public readonly TraceableCommand $command, + ) { + parent::__construct( + attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'], + server: $_SERVER, + ); + } + + // Methods below allow to populate a profile, thus enable search and filtering + public function getUri(): string + { + if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) { + $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME').' console'; + } else { + $binary = $this->server->get('argv')[0]; + } + + return $binary.' '.$this->command->input; + } + + public function getMethod(): string + { + return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH'; + } + + public function getResponse(): Response + { + return new class($this->command->exitCode) extends Response { + public function __construct(private readonly int $exitCode) + { + parent::__construct(); + } + + public function getStatusCode(): int + { + return $this->exitCode; + } + }; + } + + public function getClientIp(): string + { + $application = $this->command->getApplication(); + + return $application->getName().' '.$application->getVersion(); + } +} diff --git a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php index f8ed18045..ef9e8a63b 100644 --- a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -39,7 +39,7 @@ class ApplicationDescription */ private array $aliases = []; - public function __construct(Application $application, string $namespace = null, bool $showHidden = false) + public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false) { $this->application = $application; $this->namespace = $namespace; diff --git a/app/vendor/symfony/console/Descriptor/XmlDescriptor.php b/app/vendor/symfony/console/Descriptor/XmlDescriptor.php index 72580fd98..866c71856 100644 --- a/app/vendor/symfony/console/Descriptor/XmlDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -79,7 +79,7 @@ public function getCommandDocument(Command $command, bool $short = false): \DOMD return $dom; } - public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument + public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($rootXml = $dom->createElement('symfony')); diff --git a/app/vendor/symfony/console/Event/ConsoleCommandEvent.php b/app/vendor/symfony/console/Event/ConsoleCommandEvent.php index 31c9ee99a..0757a23f6 100644 --- a/app/vendor/symfony/console/Event/ConsoleCommandEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleCommandEvent.php @@ -12,7 +12,10 @@ namespace Symfony\Component\Console\Event; /** - * Allows to do things before the command is executed, like skipping the command or changing the input. + * Allows to do things before the command is executed, like skipping the command or executing code before the command is + * going to be executed. + * + * Changing the input arguments will have no effect. * * @author Fabien Potencier */ diff --git a/app/vendor/symfony/console/Event/ConsoleErrorEvent.php b/app/vendor/symfony/console/Event/ConsoleErrorEvent.php index d4a691216..7be2ff83e 100644 --- a/app/vendor/symfony/console/Event/ConsoleErrorEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleErrorEvent.php @@ -25,7 +25,7 @@ final class ConsoleErrorEvent extends ConsoleEvent private \Throwable $error; private int $exitCode; - public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null) + public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null) { parent::__construct($command, $input, $output); diff --git a/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php index de63c8ffa..38f7253a5 100644 --- a/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php +++ b/app/vendor/symfony/console/Event/ConsoleTerminateEvent.php @@ -19,16 +19,18 @@ * Allows to manipulate the exit code of a command after its execution. * * @author Francesco Levorato + * @author Jules Pietri */ final class ConsoleTerminateEvent extends ConsoleEvent { - private int $exitCode; - - public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode) - { + public function __construct( + Command $command, + InputInterface $input, + OutputInterface $output, + private int $exitCode, + private readonly ?int $interruptingSignal = null, + ) { parent::__construct($command, $input, $output); - - $this->setExitCode($exitCode); } public function setExitCode(int $exitCode): void @@ -40,4 +42,9 @@ public function getExitCode(): int { return $this->exitCode; } + + public function getInterruptingSignal(): ?int + { + return $this->interruptingSignal; + } } diff --git a/app/vendor/symfony/console/EventListener/ErrorListener.php b/app/vendor/symfony/console/EventListener/ErrorListener.php index 9925a5f74..c9ec24434 100644 --- a/app/vendor/symfony/console/EventListener/ErrorListener.php +++ b/app/vendor/symfony/console/EventListener/ErrorListener.php @@ -26,7 +26,7 @@ class ErrorListener implements EventSubscriberInterface { private ?LoggerInterface $logger; - public function __construct(LoggerInterface $logger = null) + public function __construct(?LoggerInterface $logger = null) { $this->logger = $logger; } diff --git a/app/vendor/symfony/console/Exception/CommandNotFoundException.php b/app/vendor/symfony/console/Exception/CommandNotFoundException.php index 1e9f1c793..541b32b23 100644 --- a/app/vendor/symfony/console/Exception/CommandNotFoundException.php +++ b/app/vendor/symfony/console/Exception/CommandNotFoundException.php @@ -26,7 +26,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce * @param int $code Exception code * @param \Throwable|null $previous Previous exception used for the exception chaining */ - public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null) + public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); diff --git a/app/vendor/symfony/console/Exception/RunCommandFailedException.php b/app/vendor/symfony/console/Exception/RunCommandFailedException.php new file mode 100644 index 000000000..5d87ec949 --- /dev/null +++ b/app/vendor/symfony/console/Exception/RunCommandFailedException.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\Console\Exception; + +use Symfony\Component\Console\Messenger\RunCommandContext; + +/** + * @author Kevin Bond + */ +final class RunCommandFailedException extends RuntimeException +{ + public function __construct(\Throwable|string $exception, public readonly RunCommandContext $context) + { + parent::__construct( + $exception instanceof \Throwable ? $exception->getMessage() : $exception, + $exception instanceof \Throwable ? $exception->getCode() : 0, + $exception instanceof \Throwable ? $exception : null, + ); + } +} diff --git a/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php b/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php index c2ce7d14c..ae23decb1 100644 --- a/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php +++ b/app/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php @@ -21,7 +21,7 @@ public function apply(string $text): string return $text; } - public function setBackground(string $color = null): void + public function setBackground(?string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -29,7 +29,7 @@ public function setBackground(string $color = null): void // do nothing } - public function setForeground(string $color = null): void + public function setForeground(?string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Formatter/OutputFormatter.php b/app/vendor/symfony/console/Formatter/OutputFormatter.php index 9cb631048..3e4897c33 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatter.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatter.php @@ -13,6 +13,8 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; +use function Symfony\Component\String\b; + /** * Formatter class for console output. * @@ -241,7 +243,7 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } preg_match('~(\\n)$~', $text, $matches); - $text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text); + $text = $prefix.$this->addLineBreaks($text, $width); $text = rtrim($text, "\n").($matches[1] ?? ''); if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) { @@ -265,4 +267,11 @@ private function applyCurrentStyle(string $text, string $current, int $width, in return implode("\n", $lines); } + + private function addLineBreaks(string $text, int $width): string + { + $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8'; + + return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); + } } diff --git a/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php index 346a474c6..21e7f5ab0 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -33,7 +33,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface * @param string|null $foreground The style foreground color name * @param string|null $background The style background color name */ - public function __construct(string $foreground = null, string $background = null, array $options = []) + public function __construct(?string $foreground = null, ?string $background = null, array $options = []) { $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } @@ -41,7 +41,7 @@ public function __construct(string $foreground = null, string $background = null /** * @return void */ - public function setForeground(string $color = null) + public function setForeground(?string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -52,7 +52,7 @@ public function setForeground(string $color = null) /** * @return void */ - public function setBackground(string $color = null) + public function setBackground(?string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php index f98c2eff7..62d2ca0e7 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -26,7 +26,7 @@ class OutputFormatterStyleStack implements ResetInterface private OutputFormatterStyleInterface $emptyStyle; - public function __construct(OutputFormatterStyleInterface $emptyStyle = null) + public function __construct(?OutputFormatterStyleInterface $emptyStyle = null) { $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); $this->reset(); @@ -57,7 +57,7 @@ public function push(OutputFormatterStyleInterface $style) * * @throws InvalidArgumentException When style tags incorrectly nested */ - public function pop(OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface + public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface { if (!$this->styles) { return $this->emptyStyle; diff --git a/app/vendor/symfony/console/Helper/Dumper.php b/app/vendor/symfony/console/Helper/Dumper.php index 8c6a94d51..a3b8e3952 100644 --- a/app/vendor/symfony/console/Helper/Dumper.php +++ b/app/vendor/symfony/console/Helper/Dumper.php @@ -26,7 +26,7 @@ final class Dumper private ?ClonerInterface $cloner; private \Closure $handler; - public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) + public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null) { $this->output = $output; $this->dumper = $dumper; diff --git a/app/vendor/symfony/console/Helper/Helper.php b/app/vendor/symfony/console/Helper/Helper.php index 3631b30f6..05be64787 100644 --- a/app/vendor/symfony/console/Helper/Helper.php +++ b/app/vendor/symfony/console/Helper/Helper.php @@ -26,7 +26,7 @@ abstract class Helper implements HelperInterface /** * @return void */ - public function setHelperSet(HelperSet $helperSet = null) + public function setHelperSet(?HelperSet $helperSet = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -80,7 +80,7 @@ public static function length(?string $string): int /** * Returns the subset of a string, using mb_substr if it is available. */ - public static function substr(?string $string, int $from, int $length = null): string + public static function substr(?string $string, int $from, ?int $length = null): string { $string ??= ''; @@ -94,33 +94,44 @@ public static function substr(?string $string, int $from, int $length = null): s /** * @return string */ - public static function formatTime(int|float $secs) + public static function formatTime(int|float $secs, int $precision = 1) { + $secs = (int) floor($secs); + + if (0 === $secs) { + return '< 1 sec'; + } + static $timeFormats = [ - [0, '< 1 sec'], - [1, '1 sec'], - [2, 'secs', 1], - [60, '1 min'], - [120, 'mins', 60], - [3600, '1 hr'], - [7200, 'hrs', 3600], - [86400, '1 day'], - [172800, 'days', 86400], + [1, '1 sec', 'secs'], + [60, '1 min', 'mins'], + [3600, '1 hr', 'hrs'], + [86400, '1 day', 'days'], ]; + $times = []; foreach ($timeFormats as $index => $format) { - if ($secs >= $format[0]) { - if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0]) - || $index == \count($timeFormats) - 1 - ) { - if (2 == \count($format)) { - return $format[1]; - } - - return floor($secs / $format[2]).' '.$format[1]; - } + $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs; + + if (isset($times[$index - $precision])) { + unset($times[$index - $precision]); + } + + if (0 === $seconds) { + continue; } + + $unitCount = ($seconds / $format[0]); + $times[$index] = 1 === $unitCount ? $format[1] : $unitCount.' '.$format[2]; + + if ($secs === $seconds) { + break; + } + + $secs -= $seconds; } + + return implode(', ', array_reverse($times)); } /** diff --git a/app/vendor/symfony/console/Helper/HelperSet.php b/app/vendor/symfony/console/Helper/HelperSet.php index dc5d499ca..f8c74ca2c 100644 --- a/app/vendor/symfony/console/Helper/HelperSet.php +++ b/app/vendor/symfony/console/Helper/HelperSet.php @@ -38,7 +38,7 @@ public function __construct(array $helpers = []) /** * @return void */ - public function set(HelperInterface $helper, string $alias = null) + public function set(HelperInterface $helper, ?string $alias = null) { $this->helpers[$helper->getName()] = $helper; if (null !== $alias) { diff --git a/app/vendor/symfony/console/Helper/ProcessHelper.php b/app/vendor/symfony/console/Helper/ProcessHelper.php index 26d35a1a8..3ef6f71f7 100644 --- a/app/vendor/symfony/console/Helper/ProcessHelper.php +++ b/app/vendor/symfony/console/Helper/ProcessHelper.php @@ -32,7 +32,7 @@ class ProcessHelper extends Helper * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR */ - public function run(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process + public function run(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process { if (!class_exists(Process::class)) { throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); @@ -94,7 +94,7 @@ public function run(OutputInterface $output, array|Process $cmd, string $error = * * @see run() */ - public function mustRun(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null): Process + public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process { $process = $this->run($output, $cmd, $error, $callback); @@ -108,7 +108,7 @@ public function mustRun(OutputInterface $output, array|Process $cmd, string $err /** * Wraps a Process callback to add debugging output. */ - public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable + public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); diff --git a/app/vendor/symfony/console/Helper/ProgressBar.php b/app/vendor/symfony/console/Helper/ProgressBar.php index 19faea47c..f4eec051c 100644 --- a/app/vendor/symfony/console/Helper/ProgressBar.php +++ b/app/vendor/symfony/console/Helper/ProgressBar.php @@ -305,9 +305,15 @@ public function maxSecondsBetweenRedraws(float $seconds): void /** * Returns an iterator that will automatically update the progress bar when iterated. * - * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable */ - public function iterate(iterable $iterable, int $max = null): iterable + public function iterate(iterable $iterable, ?int $max = null): iterable { $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0)); @@ -326,7 +332,7 @@ public function iterate(iterable $iterable, int $max = null): iterable * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar) */ - public function start(int $max = null, int $startAt = 0): void + public function start(?int $max = null, int $startAt = 0): void { $this->startTime = time(); $this->step = $startAt; @@ -534,20 +540,20 @@ private static function initPlaceholderFormatters(): array return $display; }, - 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime()), + 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2), 'remaining' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); } - return Helper::formatTime($bar->getRemaining()); + return Helper::formatTime($bar->getRemaining(), 2); }, 'estimated' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); } - return Helper::formatTime($bar->getEstimated()); + return Helper::formatTime($bar->getEstimated(), 2); }, 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), diff --git a/app/vendor/symfony/console/Helper/ProgressIndicator.php b/app/vendor/symfony/console/Helper/ProgressIndicator.php index 84dbef950..92106caf6 100644 --- a/app/vendor/symfony/console/Helper/ProgressIndicator.php +++ b/app/vendor/symfony/console/Helper/ProgressIndicator.php @@ -50,7 +50,7 @@ class ProgressIndicator * @param int $indicatorChangeInterval Change interval in milliseconds * @param array|null $indicatorValues Animated indicator characters */ - public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null) + public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null) { $this->output = $output; @@ -228,7 +228,7 @@ private static function initPlaceholderFormatters(): array return [ 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], 'message' => fn (self $indicator) => $indicator->message, - 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime), + 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime, 2), 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), ]; } diff --git a/app/vendor/symfony/console/Helper/QuestionHelper.php b/app/vendor/symfony/console/Helper/QuestionHelper.php index f32813c6c..b40b13191 100644 --- a/app/vendor/symfony/console/Helper/QuestionHelper.php +++ b/app/vendor/symfony/console/Helper/QuestionHelper.php @@ -501,19 +501,7 @@ private function isInteractiveInput($inputStream): bool return self::$stdinIsInteractive; } - if (\function_exists('stream_isatty')) { - return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); - } - - if (\function_exists('posix_isatty')) { - return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); - } - - if (!\function_exists('shell_exec')) { - return self::$stdinIsInteractive = true; - } - - return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); + return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); } /** diff --git a/app/vendor/symfony/console/Helper/Table.php b/app/vendor/symfony/console/Helper/Table.php index cf714873f..6aad9e95b 100644 --- a/app/vendor/symfony/console/Helper/Table.php +++ b/app/vendor/symfony/console/Helper/Table.php @@ -364,14 +364,27 @@ public function render() $maxRows = max(\count($headers), \count($row)); for ($i = 0; $i < $maxRows; ++$i) { $cell = (string) ($row[$i] ?? ''); - if ($headers && !$containsColspan) { - $rows[] = [sprintf( - '%s: %s', - str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), - $cell - )]; - } elseif ('' !== $cell) { - $rows[] = [$cell]; + + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $parts = explode($eol, $cell); + foreach ($parts as $idx => $part) { + if ($headers && !$containsColspan) { + if (0 === $idx) { + $rows[] = [sprintf( + '%s: %s', + str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $part + )]; + } else { + $rows[] = [sprintf( + '%s %s', + str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $part + )]; + } + } elseif ('' !== $cell) { + $rows[] = [$part]; + } } } } @@ -411,7 +424,7 @@ public function render() if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator( - $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, + self::SEPARATOR_TOP, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); @@ -421,7 +434,7 @@ public function render() if ($isFirstRow) { $this->renderRowSeparator( - $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, + $horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); @@ -454,7 +467,7 @@ public function render() * * +-----+-----------+-------+ */ - private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void + private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null): void { if (!$count = $this->numberOfColumns) { return; @@ -519,7 +532,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ - private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void + private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null): void { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); @@ -624,9 +637,10 @@ private function buildTableRows(array $rows): TableRows if (!str_contains($cell ?? '', "\n")) { continue; } - $escaped = implode("\n", array_map(OutputFormatter::escapeTrailingBackslash(...), explode("\n", $cell))); + $eol = str_contains($cell ?? '', "\r\n") ? "\r\n" : "\n"; + $escaped = implode($eol, array_map(OutputFormatter::escapeTrailingBackslash(...), explode($eol, $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; - $lines = explode("\n", str_replace("\n", "\n", $cell)); + $lines = explode($eol, str_replace($eol, ''.$eol, $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); @@ -688,8 +702,9 @@ private function fillNextRows(array $rows, int $line): array $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (str_contains($cell, "\n")) { - $lines = explode("\n", str_replace("\n", "\n", $cell)); - $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; + $eol = str_contains($cell, "\r\n") ? "\r\n" : "\n"; + $lines = explode($eol, str_replace($eol, ''.$eol.'', $cell)); + $nbLines = \count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); diff --git a/app/vendor/symfony/console/Helper/TableStyle.php b/app/vendor/symfony/console/Helper/TableStyle.php index bbad98e73..be956c109 100644 --- a/app/vendor/symfony/console/Helper/TableStyle.php +++ b/app/vendor/symfony/console/Helper/TableStyle.php @@ -88,7 +88,7 @@ public function getPaddingChar(): string * * @return $this */ - public function setHorizontalBorderChars(string $outside, string $inside = null): static + public function setHorizontalBorderChars(string $outside, ?string $inside = null): static { $this->horizontalOutsideBorderChar = $outside; $this->horizontalInsideBorderChar = $inside ?? $outside; @@ -113,7 +113,7 @@ public function setHorizontalBorderChars(string $outside, string $inside = null) * * @return $this */ - public function setVerticalBorderChars(string $outside, string $inside = null): static + public function setVerticalBorderChars(string $outside, ?string $inside = null): static { $this->verticalOutsideBorderChar = $outside; $this->verticalInsideBorderChar = $inside ?? $outside; @@ -167,7 +167,7 @@ public function getBorderChars(): array * * @return $this */ - public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): static + public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): static { $this->crossingChar = $cross; $this->crossingTopLeftChar = $topLeft; diff --git a/app/vendor/symfony/console/Input/ArgvInput.php b/app/vendor/symfony/console/Input/ArgvInput.php index 59f9217ec..ab9f28c54 100644 --- a/app/vendor/symfony/console/Input/ArgvInput.php +++ b/app/vendor/symfony/console/Input/ArgvInput.php @@ -43,7 +43,7 @@ class ArgvInput extends Input private array $tokens; private array $parsed; - public function __construct(array $argv = null, InputDefinition $definition = null) + public function __construct(?array $argv = null, ?InputDefinition $definition = null) { $argv ??= $_SERVER['argv'] ?? []; diff --git a/app/vendor/symfony/console/Input/ArrayInput.php b/app/vendor/symfony/console/Input/ArrayInput.php index 355de61dd..c1bc914ca 100644 --- a/app/vendor/symfony/console/Input/ArrayInput.php +++ b/app/vendor/symfony/console/Input/ArrayInput.php @@ -27,7 +27,7 @@ class ArrayInput extends Input { private array $parameters; - public function __construct(array $parameters, InputDefinition $definition = null) + public function __construct(array $parameters, ?InputDefinition $definition = null) { $this->parameters = $parameters; diff --git a/app/vendor/symfony/console/Input/Input.php b/app/vendor/symfony/console/Input/Input.php index 0f5617cd1..1c21573bc 100644 --- a/app/vendor/symfony/console/Input/Input.php +++ b/app/vendor/symfony/console/Input/Input.php @@ -28,12 +28,13 @@ abstract class Input implements InputInterface, StreamableInputInterface { protected $definition; + /** @var resource */ protected $stream; protected $options = []; protected $arguments = []; protected $interactive = true; - public function __construct(InputDefinition $definition = null) + public function __construct(?InputDefinition $definition = null) { if (null === $definition) { $this->definition = new InputDefinition(); diff --git a/app/vendor/symfony/console/Input/InputArgument.php b/app/vendor/symfony/console/Input/InputArgument.php index 5cb151488..4ef79feb7 100644 --- a/app/vendor/symfony/console/Input/InputArgument.php +++ b/app/vendor/symfony/console/Input/InputArgument.php @@ -44,7 +44,7 @@ class InputArgument * * @throws InvalidArgumentException When argument mode is not valid */ - public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|array $suggestedValues = []) + public function __construct(string $name, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, \Closure|array $suggestedValues = []) { if (null === $mode) { $mode = self::OPTIONAL; @@ -95,7 +95,7 @@ public function isArray(): bool * * @throws LogicException When incorrect default value is given */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Input/InputOption.php b/app/vendor/symfony/console/Input/InputOption.php index fdf88dcc2..bb533801f 100644 --- a/app/vendor/symfony/console/Input/InputOption.php +++ b/app/vendor/symfony/console/Input/InputOption.php @@ -65,7 +65,7 @@ class InputOption * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null, array|\Closure $suggestedValues = []) + public function __construct(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', string|bool|int|float|array|null $default = null, array|\Closure $suggestedValues = []) { if (str_starts_with($name, '--')) { $name = substr($name, 2); @@ -75,7 +75,7 @@ public function __construct(string $name, string|array $shortcut = null, int $mo throw new InvalidArgumentException('An option name cannot be empty.'); } - if (empty($shortcut)) { + if ('' === $shortcut || [] === $shortcut || false === $shortcut) { $shortcut = null; } @@ -84,10 +84,10 @@ public function __construct(string $name, string|array $shortcut = null, int $mo $shortcut = implode('|', $shortcut); } $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); - $shortcuts = array_filter($shortcuts); + $shortcuts = array_filter($shortcuts, 'strlen'); $shortcut = implode('|', $shortcuts); - if (empty($shortcut)) { + if ('' === $shortcut) { throw new InvalidArgumentException('An option shortcut cannot be empty.'); } } @@ -181,7 +181,7 @@ public function isNegatable(): bool /** * @return void */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/Messenger/RunCommandContext.php b/app/vendor/symfony/console/Messenger/RunCommandContext.php new file mode 100644 index 000000000..2ee5415c6 --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandContext.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\Console\Messenger; + +/** + * @author Kevin Bond + */ +final class RunCommandContext +{ + public function __construct( + public readonly RunCommandMessage $message, + public readonly int $exitCode, + public readonly string $output, + ) { + } +} diff --git a/app/vendor/symfony/console/Messenger/RunCommandMessage.php b/app/vendor/symfony/console/Messenger/RunCommandMessage.php new file mode 100644 index 000000000..b530c438c --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandMessage.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Messenger; + +use Symfony\Component\Console\Exception\RunCommandFailedException; + +/** + * @author Kevin Bond + */ +class RunCommandMessage implements \Stringable +{ + /** + * @param bool $throwOnFailure If the command has a non-zero exit code, throw {@see RunCommandFailedException} + * @param bool $catchExceptions @see Application::setCatchExceptions() + */ + public function __construct( + public readonly string $input, + public readonly bool $throwOnFailure = true, + public readonly bool $catchExceptions = false, + ) { + } + + public function __toString(): string + { + return $this->input; + } +} diff --git a/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php new file mode 100644 index 000000000..14f9c1764 --- /dev/null +++ b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.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\Console\Messenger; + +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\RunCommandFailedException; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\BufferedOutput; + +/** + * @author Kevin Bond + */ +final class RunCommandMessageHandler +{ + public function __construct(private readonly Application $application) + { + } + + public function __invoke(RunCommandMessage $message): RunCommandContext + { + $input = new StringInput($message->input); + $output = new BufferedOutput(); + + $this->application->setCatchExceptions($message->catchExceptions); + + try { + $exitCode = $this->application->run($input, $output); + } catch (\Throwable $e) { + throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); + } + + if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { + throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + } + + return new RunCommandContext($message, $exitCode, $output->fetch()); + } +} diff --git a/app/vendor/symfony/console/Output/ConsoleOutput.php b/app/vendor/symfony/console/Output/ConsoleOutput.php index c1eb7cd14..5837e74a3 100644 --- a/app/vendor/symfony/console/Output/ConsoleOutput.php +++ b/app/vendor/symfony/console/Output/ConsoleOutput.php @@ -37,7 +37,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ - public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) + public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); diff --git a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php index 3f3f1434b..f2d7933bb 100644 --- a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php +++ b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -48,9 +48,9 @@ public function __construct($stream, array &$sections, int $verbosity, bool $dec public function setMaxHeight(int $maxHeight): void { // when changing max height, clear output of current section and redraw again with the new height - $existingContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $this->lines) : $this->lines); - + $previousMaxHeight = $this->maxHeight; $this->maxHeight = $maxHeight; + $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines); parent::doWrite($this->getVisibleContent(), false); parent::doWrite($existingContent, false); @@ -63,7 +63,7 @@ public function setMaxHeight(int $maxHeight): void * * @return void */ - public function clear(int $lines = null) + public function clear(?int $lines = null) { if (empty($this->content) || !$this->isDecorated()) { return; @@ -119,8 +119,7 @@ public function addContent(string $input, bool $newline = true): int // re-add the line break (that has been removed in the above `explode()` for // - every line that is not the last line // - if $newline is required, also add it to the last line - // - if it's not new line, but input ending with `\PHP_EOL` - if ($i < $count || $newline || str_ends_with($input, \PHP_EOL)) { + if ($i < $count || $newline) { $lineContent .= \PHP_EOL; } @@ -168,6 +167,12 @@ public function addNewLineOfInputSubmit(): void */ protected function doWrite(string $message, bool $newline) { + // Simulate newline behavior for consistent output formatting, avoiding extra logic + if (!$newline && str_ends_with($message, \PHP_EOL)) { + $message = substr($message, 0, -\strlen(\PHP_EOL)); + $newline = true; + } + if (!$this->isDecorated()) { parent::doWrite($message, $newline); @@ -213,7 +218,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr break; } - $numberOfLinesToClear += $section->lines; + $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines; if ('' !== $sectionContent = $section->getVisibleContent()) { if (!str_ends_with($sectionContent, \PHP_EOL)) { $sectionContent .= \PHP_EOL; diff --git a/app/vendor/symfony/console/Output/Output.php b/app/vendor/symfony/console/Output/Output.php index 3a06311a8..00f481e03 100644 --- a/app/vendor/symfony/console/Output/Output.php +++ b/app/vendor/symfony/console/Output/Output.php @@ -37,7 +37,7 @@ abstract class Output implements OutputInterface * @param bool $decorated Whether to decorate messages * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ - public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) + public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; $this->formatter = $formatter ?? new OutputFormatter(); diff --git a/app/vendor/symfony/console/Output/OutputInterface.php b/app/vendor/symfony/console/Output/OutputInterface.php index fb1557720..19a817901 100644 --- a/app/vendor/symfony/console/Output/OutputInterface.php +++ b/app/vendor/symfony/console/Output/OutputInterface.php @@ -54,12 +54,16 @@ public function writeln(string|iterable $messages, int $options = 0); /** * Sets the verbosity of the output. * + * @param self::VERBOSITY_* $level + * * @return void */ public function setVerbosity(int $level); /** * Gets the current verbosity of the output. + * + * @return self::VERBOSITY_* */ public function getVerbosity(): int; diff --git a/app/vendor/symfony/console/Output/StreamOutput.php b/app/vendor/symfony/console/Output/StreamOutput.php index 155066ea0..218bc9ef2 100644 --- a/app/vendor/symfony/console/Output/StreamOutput.php +++ b/app/vendor/symfony/console/Output/StreamOutput.php @@ -29,6 +29,7 @@ */ class StreamOutput extends Output { + /** @var resource */ private $stream; /** @@ -39,7 +40,7 @@ class StreamOutput extends Output * * @throws InvalidArgumentException When first argument is not a real stream */ - public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) + public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) { if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); @@ -96,18 +97,29 @@ protected function hasColorSupport(): bool return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($this->stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { + return true; + } + + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - return stream_isatty($this->stream); + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } } diff --git a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php index b00445ece..23a2be8c3 100644 --- a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php +++ b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -24,7 +24,7 @@ class TrimmedBufferOutput extends Output private int $maxLength; private string $buffer = ''; - public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) + public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); diff --git a/app/vendor/symfony/console/Question/Question.php b/app/vendor/symfony/console/Question/Question.php index 26896bb53..94c688fa8 100644 --- a/app/vendor/symfony/console/Question/Question.php +++ b/app/vendor/symfony/console/Question/Question.php @@ -36,7 +36,7 @@ class Question * @param string $question The question to ask to the user * @param string|bool|int|float|null $default The default answer to return if the user enters nothing */ - public function __construct(string $question, string|bool|int|float $default = null) + public function __construct(string $question, string|bool|int|float|null $default = null) { $this->question = $question; $this->default = $default; @@ -175,7 +175,7 @@ public function getAutocompleterCallback(): ?callable * * @return $this */ - public function setAutocompleterCallback(callable $callback = null): static + public function setAutocompleterCallback(?callable $callback = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); @@ -194,7 +194,7 @@ public function setAutocompleterCallback(callable $callback = null): static * * @return $this */ - public function setValidator(callable $validator = null): static + public function setValidator(?callable $validator = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); diff --git a/app/vendor/symfony/console/README.md b/app/vendor/symfony/console/README.md index bfd488109..e9013182a 100644 --- a/app/vendor/symfony/console/README.md +++ b/app/vendor/symfony/console/README.md @@ -7,7 +7,7 @@ interfaces. Sponsor ------- -The Console component for Symfony 6.3 is [backed][1] by [Les-Tilleuls.coop][2]. +The Console component for Symfony 6.4 is [backed][1] by [Les-Tilleuls.coop][2]. Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and fix your projects. They provide a wide range of professional services including development, diff --git a/app/vendor/symfony/console/SignalRegistry/SignalMap.php b/app/vendor/symfony/console/SignalRegistry/SignalMap.php new file mode 100644 index 000000000..de419bda7 --- /dev/null +++ b/app/vendor/symfony/console/SignalRegistry/SignalMap.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\SignalRegistry; + +/** + * @author Grégoire Pineau + */ +class SignalMap +{ + private static array $map; + + public static function getSignalName(int $signal): ?string + { + if (!\extension_loaded('pcntl')) { + return null; + } + + if (!isset(self::$map)) { + $r = new \ReflectionExtension('pcntl'); + $c = $r->getConstants(); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_'), \ARRAY_FILTER_USE_KEY); + self::$map = array_flip($map); + } + + return self::$map[$signal] ?? null; + } +} diff --git a/app/vendor/symfony/console/SingleCommandApplication.php b/app/vendor/symfony/console/SingleCommandApplication.php index 4f0b5ba3c..ff1c17247 100644 --- a/app/vendor/symfony/console/SingleCommandApplication.php +++ b/app/vendor/symfony/console/SingleCommandApplication.php @@ -46,7 +46,7 @@ public function setAutoExit(bool $autoExit): static return $this; } - public function run(InputInterface $input = null, OutputInterface $output = null): int + public function run(?InputInterface $input = null, ?OutputInterface $output = null): int { if ($this->running) { return parent::run($input, $output); diff --git a/app/vendor/symfony/console/Style/StyleInterface.php b/app/vendor/symfony/console/Style/StyleInterface.php index e25a65bd2..6bced158a 100644 --- a/app/vendor/symfony/console/Style/StyleInterface.php +++ b/app/vendor/symfony/console/Style/StyleInterface.php @@ -91,12 +91,12 @@ public function table(array $headers, array $rows); /** * Asks a question. */ - public function ask(string $question, string $default = null, callable $validator = null): mixed; + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed; /** * Asks a question with the user input hidden. */ - public function askHidden(string $question, callable $validator = null): mixed; + public function askHidden(string $question, ?callable $validator = null): mixed; /** * Asks for confirmation. diff --git a/app/vendor/symfony/console/Style/SymfonyStyle.php b/app/vendor/symfony/console/Style/SymfonyStyle.php index cecce6c01..03bda8784 100644 --- a/app/vendor/symfony/console/Style/SymfonyStyle.php +++ b/app/vendor/symfony/console/Style/SymfonyStyle.php @@ -63,7 +63,7 @@ public function __construct(InputInterface $input, OutputInterface $output) * * @return void */ - public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) + public function block(string|array $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) { $messages = \is_array($messages) ? array_values($messages) : [$messages]; @@ -249,7 +249,7 @@ public function definitionList(string|array|TableSeparator ...$list) $this->horizontalTable($headers, [$row]); } - public function ask(string $question, string $default = null, callable $validator = null): mixed + public function ask(string $question, ?string $default = null, ?callable $validator = null): mixed { $question = new Question($question, $default); $question->setValidator($validator); @@ -257,7 +257,7 @@ public function ask(string $question, string $default = null, callable $validato return $this->askQuestion($question); } - public function askHidden(string $question, callable $validator = null): mixed + public function askHidden(string $question, ?callable $validator = null): mixed { $question = new Question($question); @@ -327,8 +327,16 @@ public function createProgressBar(int $max = 0): ProgressBar /** * @see ProgressBar::iterate() + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable */ - public function progressIterate(iterable $iterable, int $max = null): iterable + public function progressIterate(iterable $iterable, ?int $max = null): iterable { yield from $this->createProgressBar()->iterate($iterable, $max); @@ -448,7 +456,7 @@ private function writeBuffer(string $message, bool $newLine, int $type): void $this->bufferedOutput->write($message, $newLine, $type); } - private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array + private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array { $indentLength = 0; $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); diff --git a/app/vendor/symfony/console/Tester/CommandCompletionTester.php b/app/vendor/symfony/console/Tester/CommandCompletionTester.php index ade732752..a90fe52ef 100644 --- a/app/vendor/symfony/console/Tester/CommandCompletionTester.php +++ b/app/vendor/symfony/console/Tester/CommandCompletionTester.php @@ -22,7 +22,7 @@ */ class CommandCompletionTester { - private $command; + private Command $command; public function __construct(Command $command) { diff --git a/app/vendor/symfony/console/Tester/TesterTrait.php b/app/vendor/symfony/console/Tester/TesterTrait.php index 497b8c8c7..1ab7a70aa 100644 --- a/app/vendor/symfony/console/Tester/TesterTrait.php +++ b/app/vendor/symfony/console/Tester/TesterTrait.php @@ -130,7 +130,7 @@ public function setInputs(array $inputs): static */ private function initOutput(array $options): void { - $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; + $this->captureStreamsIndependently = $options['capture_stderr_separately'] ?? false; if (!$this->captureStreamsIndependently) { $this->output = new StreamOutput(fopen('php://memory', 'w', false)); if (isset($options['decorated'])) { diff --git a/app/vendor/symfony/console/composer.json b/app/vendor/symfony/console/composer.json index c34421299..1610f7341 100644 --- a/app/vendor/symfony/console/composer.json +++ b/app/vendor/symfony/console/composer.json @@ -20,15 +20,19 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", "psr/log": "^1|^2|^3" }, "provide": { diff --git a/app/vendor/symfony/filesystem/CHANGELOG.md b/app/vendor/symfony/filesystem/CHANGELOG.md index fcb7170ca..b4bd22eb5 100644 --- a/app/vendor/symfony/filesystem/CHANGELOG.md +++ b/app/vendor/symfony/filesystem/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.0 +--- + + * Add argument `$lock` to `Filesystem::appendToFile()` + 5.4 --- diff --git a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php index 48b640809..06b732b16 100644 --- a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php +++ b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php @@ -19,7 +19,7 @@ */ class FileNotFoundException extends IOException { - public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null) + public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { if (null === $message) { if (null === $path) { diff --git a/app/vendor/symfony/filesystem/Exception/IOException.php b/app/vendor/symfony/filesystem/Exception/IOException.php index a3c544553..df3a0850a 100644 --- a/app/vendor/symfony/filesystem/Exception/IOException.php +++ b/app/vendor/symfony/filesystem/Exception/IOException.php @@ -22,7 +22,7 @@ class IOException extends \RuntimeException implements IOExceptionInterface { private ?string $path; - public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null) + public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { $this->path = $path; diff --git a/app/vendor/symfony/filesystem/Filesystem.php b/app/vendor/symfony/filesystem/Filesystem.php index a379ce186..b7fc70118 100644 --- a/app/vendor/symfony/filesystem/Filesystem.php +++ b/app/vendor/symfony/filesystem/Filesystem.php @@ -22,7 +22,7 @@ */ class Filesystem { - private static $lastError; + private static ?string $lastError = null; /** * Copies a file. @@ -31,12 +31,10 @@ class Filesystem * If the target file is newer, it is overwritten only when the * $overwriteNewerFiles option is set to true. * - * @return void - * * @throws FileNotFoundException When originFile doesn't exist * @throws IOException When copy fails */ - public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false) + public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false): void { $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://'); if ($originIsLocal && !is_file($originFile)) { @@ -84,11 +82,9 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe /** * Creates a directory recursively. * - * @return void - * * @throws IOException On any directory creation failure */ - public function mkdir(string|iterable $dirs, int $mode = 0777) + public function mkdir(string|iterable $dirs, int $mode = 0777): void { foreach ($this->toIterable($dirs) as $dir) { if (is_dir($dir)) { @@ -127,11 +123,9 @@ public function exists(string|iterable $files): bool * @param int|null $time The touch time as a Unix timestamp, if not supplied the current system time is used * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used * - * @return void - * * @throws IOException When touch fails */ - public function touch(string|iterable $files, int $time = null, int $atime = null) + public function touch(string|iterable $files, ?int $time = null, ?int $atime = null): void { foreach ($this->toIterable($files) as $file) { if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { @@ -143,11 +137,9 @@ public function touch(string|iterable $files, int $time = null, int $atime = nul /** * Removes files or directories. * - * @return void - * * @throws IOException When removal fails */ - public function remove(string|iterable $files) + public function remove(string|iterable $files): void { if ($files instanceof \Traversable) { $files = iterator_to_array($files, false); @@ -211,11 +203,9 @@ private static function doRemove(array $files, bool $isRecursive): void * @param int $umask The mode mask (octal) * @param bool $recursive Whether change the mod recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false) + public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if (!self::box('chmod', $file, $mode & ~$umask)) { @@ -233,11 +223,9 @@ public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chown(string|iterable $files, string|int $user, bool $recursive = false) + public function chown(string|iterable $files, string|int $user, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { @@ -261,11 +249,9 @@ public function chown(string|iterable $files, string|int $user, bool $recursive * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * - * @return void - * * @throws IOException When the change fails */ - public function chgrp(string|iterable $files, string|int $group, bool $recursive = false) + public function chgrp(string|iterable $files, string|int $group, bool $recursive = false): void { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { @@ -286,12 +272,10 @@ public function chgrp(string|iterable $files, string|int $group, bool $recursive /** * Renames a file or a directory. * - * @return void - * * @throws IOException When target file or directory already exists * @throws IOException When origin cannot be renamed */ - public function rename(string $origin, string $target, bool $overwrite = false) + public function rename(string $origin, string $target, bool $overwrite = false): void { // we check that target does not exist if (!$overwrite && $this->isReadable($target)) { @@ -329,11 +313,9 @@ private function isReadable(string $filename): bool /** * Creates a symbolic link or copy a directory. * - * @return void - * * @throws IOException When symlink fails */ - public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false) + public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false): void { self::assertFunctionExists('symlink'); @@ -367,12 +349,10 @@ public function symlink(string $originDir, string $targetDir, bool $copyOnWindow * * @param string|string[] $targetFiles The target file(s) * - * @return void - * * @throws FileNotFoundException When original file is missing or not a file * @throws IOException When link fails, including if link already exists */ - public function hardlink(string $originFile, string|iterable $targetFiles) + public function hardlink(string $originFile, string|iterable $targetFiles): void { self::assertFunctionExists('link'); @@ -526,11 +506,9 @@ public function makePathRelative(string $endPath, string $startPath): string * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * - * @return void - * * @throws IOException When file type is unknown */ - public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []) + public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = []): void { $targetDir = rtrim($targetDir, '/\\'); $originDir = rtrim($originDir, '/\\'); @@ -652,11 +630,9 @@ public function tempnam(string $dir, string $prefix, string $suffix = ''): strin * * @param string|resource $content The data to write into the file * - * @return void - * * @throws IOException if the file cannot be written to */ - public function dumpFile(string $filename, $content) + public function dumpFile(string $filename, $content): void { if (\is_array($content)) { throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); @@ -699,11 +675,9 @@ public function dumpFile(string $filename, $content) * @param string|resource $content The content to append * @param bool $lock Whether the file should be locked when writing to it * - * @return void - * * @throws IOException If the file is not writable */ - public function appendToFile(string $filename, $content/* , bool $lock = false */) + public function appendToFile(string $filename, $content, bool $lock = false): void { if (\is_array($content)) { throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); @@ -715,8 +689,6 @@ public function appendToFile(string $filename, $content/* , bool $lock = false * $this->mkdir($dir); } - $lock = \func_num_args() > 2 && func_get_arg(2); - if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) { throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } @@ -749,7 +721,7 @@ private static function box(string $func, mixed ...$args): mixed self::assertFunctionExists($func); self::$lastError = null; - set_error_handler(__CLASS__.'::handleError'); + set_error_handler(self::handleError(...)); try { return $func(...$args); } finally { diff --git a/app/vendor/symfony/filesystem/Path.php b/app/vendor/symfony/filesystem/Path.php index 8ddbac8f4..01b561724 100644 --- a/app/vendor/symfony/filesystem/Path.php +++ b/app/vendor/symfony/filesystem/Path.php @@ -42,12 +42,9 @@ final class Path * * @var array */ - private static $buffer = []; + private static array $buffer = []; - /** - * @var int - */ - private static $bufferSize = 0; + private static int $bufferSize = 0; /** * Canonicalizes the given path. @@ -257,7 +254,7 @@ public static function getRoot(string $path): string * @param string|null $extension if specified, only that extension is cut * off (may contain leading dot) */ - public static function getFilenameWithoutExtension(string $path, string $extension = null): string + public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string { if ('' === $path) { return ''; diff --git a/app/vendor/symfony/filesystem/composer.json b/app/vendor/symfony/filesystem/composer.json index 10a7a531c..1e054b682 100644 --- a/app/vendor/symfony/filesystem/composer.json +++ b/app/vendor/symfony/filesystem/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, diff --git a/app/vendor/symfony/finder/CHANGELOG.md b/app/vendor/symfony/finder/CHANGELOG.md index 1a12afe65..e83830247 100644 --- a/app/vendor/symfony/finder/CHANGELOG.md +++ b/app/vendor/symfony/finder/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.4 +--- + + * Add early directory pruning to `Finder::filter()` + 6.2 --- diff --git a/app/vendor/symfony/finder/Finder.php b/app/vendor/symfony/finder/Finder.php index a3bf9a1a7..d062a60a4 100644 --- a/app/vendor/symfony/finder/Finder.php +++ b/app/vendor/symfony/finder/Finder.php @@ -50,6 +50,7 @@ class Finder implements \IteratorAggregate, \Countable private array $notNames = []; private array $exclude = []; private array $filters = []; + private array $pruneFilters = []; private array $depths = []; private array $sizes = []; private bool $followLinks = false; @@ -396,10 +397,8 @@ public function ignoreVCSIgnored(bool $ignoreVCSIgnored): static * @see ignoreVCS() * * @param string|string[] $pattern VCS patterns to ignore - * - * @return void */ - public static function addVCSPattern(string|array $pattern) + public static function addVCSPattern(string|array $pattern): void { foreach ((array) $pattern as $p) { self::$vcsPatterns[] = $p; @@ -580,14 +579,21 @@ public function sortByModifiedTime(): static * The anonymous function receives a \SplFileInfo and must return false * to remove files. * + * @param \Closure(SplFileInfo): bool $closure + * @param bool $prune Whether to skip traversing directories further + * * @return $this * * @see CustomFilterIterator */ - public function filter(\Closure $closure): static + public function filter(\Closure $closure, bool $prune = false): static { $this->filters[] = $closure; + if ($prune) { + $this->pruneFilters[] = $closure; + } + return $this; } @@ -741,6 +747,10 @@ private function searchInDirectory(string $dir): \Iterator $exclude = $this->exclude; $notPaths = $this->notPaths; + if ($this->pruneFilters) { + $exclude = array_merge($exclude, $this->pruneFilters); + } + if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { $exclude = array_merge($exclude, self::$vcsPatterns); } diff --git a/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php b/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php index 699b1acbf..ebbc76ec7 100644 --- a/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -27,12 +27,15 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi /** @var \Iterator */ private \Iterator $iterator; private bool $isRecursive; + /** @var array */ private array $excludedDirs = []; private ?string $excludedPattern = null; + /** @var list */ + private array $pruneFilters = []; /** - * @param \Iterator $iterator The Iterator to filter - * @param string[] $directories An array of directories to exclude + * @param \Iterator $iterator The Iterator to filter + * @param list $directories An array of directories to exclude */ public function __construct(\Iterator $iterator, array $directories) { @@ -40,6 +43,16 @@ public function __construct(\Iterator $iterator, array $directories) $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = []; foreach ($directories as $directory) { + if (!\is_string($directory)) { + if (!\is_callable($directory)) { + throw new \InvalidArgumentException('Invalid PHP callback.'); + } + + $this->pruneFilters[] = $directory; + + continue; + } + $directory = rtrim($directory, '/'); if (!$this->isRecursive || str_contains($directory, '/')) { $patterns[] = preg_quote($directory, '#'); @@ -70,6 +83,14 @@ public function accept(): bool return !preg_match($this->excludedPattern, $path); } + if ($this->pruneFilters && $this->hasChildren()) { + foreach ($this->pruneFilters as $pruneFilter) { + if (!$pruneFilter($this->current())) { + return false; + } + } + } + return true; } diff --git a/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php b/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php index 82a9df301..3450c49d4 100644 --- a/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php @@ -23,8 +23,8 @@ */ abstract class MultiplePcreFilterIterator extends \FilterIterator { - protected $matchRegexps = []; - protected $noMatchRegexps = []; + protected array $matchRegexps = []; + protected array $noMatchRegexps = []; /** * @param \Iterator $iterator The Iterator to filter @@ -80,11 +80,7 @@ protected function isAccepted(string $string): bool */ protected function isRegex(string $str): bool { - $availableModifiers = 'imsxuADU'; - - if (\PHP_VERSION_ID >= 80200) { - $availableModifiers .= 'n'; - } + $availableModifiers = 'imsxuADUn'; if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) { $start = substr($m[1], 0, 1); diff --git a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php index 7e6051d38..ddd700772 100644 --- a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php @@ -18,20 +18,17 @@ */ final class VcsIgnoredFilterIterator extends \FilterIterator { - /** - * @var string - */ - private $baseDir; + private string $baseDir; /** * @var array */ - private $gitignoreFilesCache = []; + private array $gitignoreFilesCache = []; /** * @var array */ - private $ignoredPathsCache = []; + private array $ignoredPathsCache = []; /** * @param \Iterator $iterator diff --git a/app/vendor/symfony/finder/composer.json b/app/vendor/symfony/finder/composer.json index 06d129c56..2b70600d0 100644 --- a/app/vendor/symfony/finder/composer.json +++ b/app/vendor/symfony/finder/composer.json @@ -16,10 +16,10 @@ } ], "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.4|^7.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" }, diff --git a/app/vendor/symfony/polyfill-ctype/LICENSE b/app/vendor/symfony/polyfill-ctype/LICENSE index 3f853aaf3..7536caeae 100644 --- a/app/vendor/symfony/polyfill-ctype/LICENSE +++ b/app/vendor/symfony/polyfill-ctype/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +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 diff --git a/app/vendor/symfony/polyfill-ctype/composer.json b/app/vendor/symfony/polyfill-ctype/composer.json index 1b3efff57..b222fdab9 100644 --- a/app/vendor/symfony/polyfill-ctype/composer.json +++ b/app/vendor/symfony/polyfill-ctype/composer.json @@ -30,9 +30,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-intl-grapheme/LICENSE b/app/vendor/symfony/polyfill-intl-grapheme/LICENSE index 4cd8bdd30..6e3afce69 100644 --- a/app/vendor/symfony/polyfill-intl-grapheme/LICENSE +++ b/app/vendor/symfony/polyfill-intl-grapheme/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-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 diff --git a/app/vendor/symfony/polyfill-intl-grapheme/composer.json b/app/vendor/symfony/polyfill-intl-grapheme/composer.json index fde5537fc..a20d3faaf 100644 --- a/app/vendor/symfony/polyfill-intl-grapheme/composer.json +++ b/app/vendor/symfony/polyfill-intl-grapheme/composer.json @@ -27,9 +27,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-intl-normalizer/LICENSE b/app/vendor/symfony/polyfill-intl-normalizer/LICENSE index 4cd8bdd30..6e3afce69 100644 --- a/app/vendor/symfony/polyfill-intl-normalizer/LICENSE +++ b/app/vendor/symfony/polyfill-intl-normalizer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-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 diff --git a/app/vendor/symfony/polyfill-intl-normalizer/composer.json b/app/vendor/symfony/polyfill-intl-normalizer/composer.json index 65f72d645..1b93573ae 100644 --- a/app/vendor/symfony/polyfill-intl-normalizer/composer.json +++ b/app/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -28,9 +28,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-mbstring/LICENSE b/app/vendor/symfony/polyfill-mbstring/LICENSE index 4cd8bdd30..6e3afce69 100644 --- a/app/vendor/symfony/polyfill-mbstring/LICENSE +++ b/app/vendor/symfony/polyfill-mbstring/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-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 diff --git a/app/vendor/symfony/polyfill-mbstring/Mbstring.php b/app/vendor/symfony/polyfill-mbstring/Mbstring.php index bce5c4a84..2e0b96940 100644 --- a/app/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/app/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -69,7 +69,7 @@ final class Mbstring { public const MB_CASE_FOLD = \PHP_INT_MAX; - private const CASE_FOLD = [ + private const SIMPLE_CASE_FOLD = [ ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; @@ -301,7 +301,11 @@ public static function mb_convert_case($s, $mode, $encoding = null) $map = $upper; } else { if (self::MB_CASE_FOLD === $mode) { - $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + static $caseFolding = null; + if (null === $caseFolding) { + $caseFolding = self::getData('caseFolding'); + } + $s = strtr($s, $caseFolding); } static $lower = null; @@ -406,6 +410,12 @@ public static function mb_encoding_aliases($encoding) public static function mb_check_encoding($var = null, $encoding = null) { + if (PHP_VERSION_ID < 70200 && \is_array($var)) { + trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); + + return null; + } + if (null === $encoding) { if (null === $var) { return false; @@ -413,7 +423,21 @@ public static function mb_check_encoding($var = null, $encoding = null) $encoding = self::$internalEncoding; } - return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + if (!\is_array($var)) { + return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + } + + foreach ($var as $key => $value) { + if (!self::mb_check_encoding($key, $encoding)) { + return false; + } + if (!self::mb_check_encoding($value, $encoding)) { + return false; + } + } + + return true; + } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) @@ -638,8 +662,10 @@ public static function mb_substr($s, $start, $length = null, $encoding = null) public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ + self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), + self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), + ]); return self::mb_strpos($haystack, $needle, $offset, $encoding); } @@ -674,8 +700,11 @@ public static function mb_strrichr($haystack, $needle, $part = false, $encoding public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); + $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); + + $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); + $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); return self::mb_strrpos($haystack, $needle, $offset, $encoding); } @@ -798,6 +827,50 @@ public static function mb_ord($s, $encoding = null) return $code; } + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string + { + if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { + throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); + } + + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } + + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + if (self::mb_strlen($pad_string, $encoding) <= 0) { + throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); + } + + $paddingRequired = $length - self::mb_strlen($string, $encoding); + + if ($paddingRequired < 1) { + return $string; + } + + switch ($pad_type) { + case \STR_PAD_LEFT: + return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; + case \STR_PAD_RIGHT: + return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); + default: + $leftPaddingLength = floor($paddingRequired / 2); + $rightPaddingLength = $paddingRequired - $leftPaddingLength; + + return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); + } + } + private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { diff --git a/app/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php b/app/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php new file mode 100644 index 000000000..512bba0bf --- /dev/null +++ b/app/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php @@ -0,0 +1,119 @@ + 'i̇', + 'µ' => 'μ', + 'ſ' => 's', + 'ͅ' => 'ι', + 'ς' => 'σ', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϵ' => 'ε', + 'ẛ' => 'ṡ', + 'ι' => 'ι', + 'ß' => 'ss', + 'ʼn' => 'ʼn', + 'ǰ' => 'ǰ', + 'ΐ' => 'ΐ', + 'ΰ' => 'ΰ', + 'և' => 'եւ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẚ' => 'aʾ', + 'ẞ' => 'ss', + 'ὐ' => 'ὐ', + 'ὒ' => 'ὒ', + 'ὔ' => 'ὔ', + 'ὖ' => 'ὖ', + 'ᾀ' => 'ἀι', + 'ᾁ' => 'ἁι', + 'ᾂ' => 'ἂι', + 'ᾃ' => 'ἃι', + 'ᾄ' => 'ἄι', + 'ᾅ' => 'ἅι', + 'ᾆ' => 'ἆι', + 'ᾇ' => 'ἇι', + 'ᾈ' => 'ἀι', + 'ᾉ' => 'ἁι', + 'ᾊ' => 'ἂι', + 'ᾋ' => 'ἃι', + 'ᾌ' => 'ἄι', + 'ᾍ' => 'ἅι', + 'ᾎ' => 'ἆι', + 'ᾏ' => 'ἇι', + 'ᾐ' => 'ἠι', + 'ᾑ' => 'ἡι', + 'ᾒ' => 'ἢι', + 'ᾓ' => 'ἣι', + 'ᾔ' => 'ἤι', + 'ᾕ' => 'ἥι', + 'ᾖ' => 'ἦι', + 'ᾗ' => 'ἧι', + 'ᾘ' => 'ἠι', + 'ᾙ' => 'ἡι', + 'ᾚ' => 'ἢι', + 'ᾛ' => 'ἣι', + 'ᾜ' => 'ἤι', + 'ᾝ' => 'ἥι', + 'ᾞ' => 'ἦι', + 'ᾟ' => 'ἧι', + 'ᾠ' => 'ὠι', + 'ᾡ' => 'ὡι', + 'ᾢ' => 'ὢι', + 'ᾣ' => 'ὣι', + 'ᾤ' => 'ὤι', + 'ᾥ' => 'ὥι', + 'ᾦ' => 'ὦι', + 'ᾧ' => 'ὧι', + 'ᾨ' => 'ὠι', + 'ᾩ' => 'ὡι', + 'ᾪ' => 'ὢι', + 'ᾫ' => 'ὣι', + 'ᾬ' => 'ὤι', + 'ᾭ' => 'ὥι', + 'ᾮ' => 'ὦι', + 'ᾯ' => 'ὧι', + 'ᾲ' => 'ὰι', + 'ᾳ' => 'αι', + 'ᾴ' => 'άι', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾶι', + 'ᾼ' => 'αι', + 'ῂ' => 'ὴι', + 'ῃ' => 'ηι', + 'ῄ' => 'ήι', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῆι', + 'ῌ' => 'ηι', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'ῲ' => 'ὼι', + 'ῳ' => 'ωι', + 'ῴ' => 'ώι', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῶι', + 'ῼ' => 'ωι', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', +]; diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap.php b/app/vendor/symfony/polyfill-mbstring/bootstrap.php index 1fedd1f7c..ecf1a0352 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -132,6 +132,10 @@ function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } } +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php index 82f5ac4d0..2f9fb5b42 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -128,6 +128,10 @@ function mb_scrub(?string $string, ?string $encoding = null): string { $encoding function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } } +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/composer.json b/app/vendor/symfony/polyfill-mbstring/composer.json index 44895536b..bd99d4b9d 100644 --- a/app/vendor/symfony/polyfill-mbstring/composer.json +++ b/app/vendor/symfony/polyfill-mbstring/composer.json @@ -30,9 +30,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php73/LICENSE b/app/vendor/symfony/polyfill-php73/LICENSE index 3f853aaf3..7536caeae 100644 --- a/app/vendor/symfony/polyfill-php73/LICENSE +++ b/app/vendor/symfony/polyfill-php73/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +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 diff --git a/app/vendor/symfony/polyfill-php73/composer.json b/app/vendor/symfony/polyfill-php73/composer.json index b5c58ec19..3d47d1541 100644 --- a/app/vendor/symfony/polyfill-php73/composer.json +++ b/app/vendor/symfony/polyfill-php73/composer.json @@ -25,9 +25,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php80/LICENSE b/app/vendor/symfony/polyfill-php80/LICENSE index 5593b1d84..0ed3a2465 100644 --- a/app/vendor/symfony/polyfill-php80/LICENSE +++ b/app/vendor/symfony/polyfill-php80/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020 Fabien Potencier +Copyright (c) 2020-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 diff --git a/app/vendor/symfony/polyfill-php80/composer.json b/app/vendor/symfony/polyfill-php80/composer.json index bd9a3262a..46ccde203 100644 --- a/app/vendor/symfony/polyfill-php80/composer.json +++ b/app/vendor/symfony/polyfill-php80/composer.json @@ -29,9 +29,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/polyfill-php81/LICENSE b/app/vendor/symfony/polyfill-php81/LICENSE index efb17f98e..99c6bdf35 100644 --- a/app/vendor/symfony/polyfill-php81/LICENSE +++ b/app/vendor/symfony/polyfill-php81/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2021 Fabien Potencier +Copyright (c) 2021-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 diff --git a/app/vendor/symfony/polyfill-php81/README.md b/app/vendor/symfony/polyfill-php81/README.md index 7d8dd1907..c07ef7820 100644 --- a/app/vendor/symfony/polyfill-php81/README.md +++ b/app/vendor/symfony/polyfill-php81/README.md @@ -7,6 +7,7 @@ This component provides features added to PHP 8.1 core: - [`enum_exists`](https://php.net/enum-exists) - [`MYSQLI_REFRESH_REPLICA`](https://php.net/mysqli.constants#constantmysqli-refresh-replica) constant - [`ReturnTypeWillChange`](https://wiki.php.net/rfc/internal_method_return_types) +- [`CURLStringFile`](https://php.net/CURLStringFile) (but only if PHP >= 7.4 is used) More information can be found in the [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). diff --git a/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php new file mode 100644 index 000000000..eb5952ee3 --- /dev/null +++ b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) { + /** + * @property string $data + */ + class CURLStringFile extends CURLFile + { + private $data; + + public function __construct(string $data, string $postname, string $mime = 'application/octet-stream') + { + $this->data = $data; + parent::__construct('data://application/octet-stream;base64,'.base64_encode($data), $mime, $postname); + } + + public function __set(string $name, $value): void + { + if ('data' !== $name) { + $this->$name = $value; + + return; + } + + if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) { + throw new \TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); + } + + $this->name = 'data://application/octet-stream;base64,'.base64_encode($value); + } + + public function __isset(string $name): bool + { + return isset($this->$name); + } + + public function &__get(string $name) + { + return $this->$name; + } + } +} diff --git a/app/vendor/symfony/polyfill-php81/composer.json b/app/vendor/symfony/polyfill-php81/composer.json index 149b59821..381af79ac 100644 --- a/app/vendor/symfony/polyfill-php81/composer.json +++ b/app/vendor/symfony/polyfill-php81/composer.json @@ -25,9 +25,6 @@ }, "minimum-stability": "dev", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" diff --git a/app/vendor/symfony/process/CHANGELOG.md b/app/vendor/symfony/process/CHANGELOG.md index 31b9ee6a2..e26819b5b 100644 --- a/app/vendor/symfony/process/CHANGELOG.md +++ b/app/vendor/symfony/process/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +6.4 +--- + + * Add `PhpSubprocess` to handle PHP subprocesses that take over the + configuration from their parent + * Add `RunProcessMessage` and `RunProcessMessageHandler` + * Support using `Process::findExecutable()` independently of `open_basedir` + 5.2.0 ----- diff --git a/app/vendor/symfony/process/Exception/ProcessFailedException.php b/app/vendor/symfony/process/Exception/ProcessFailedException.php index cf006daeb..499809eef 100644 --- a/app/vendor/symfony/process/Exception/ProcessFailedException.php +++ b/app/vendor/symfony/process/Exception/ProcessFailedException.php @@ -20,7 +20,7 @@ */ class ProcessFailedException extends RuntimeException { - private $process; + private Process $process; public function __construct(Process $process) { @@ -47,10 +47,7 @@ public function __construct(Process $process) $this->process = $process; } - /** - * @return Process - */ - public function getProcess() + public function getProcess(): Process { return $this->process; } diff --git a/app/vendor/symfony/process/Exception/ProcessSignaledException.php b/app/vendor/symfony/process/Exception/ProcessSignaledException.php index d4d322756..0fed8ac30 100644 --- a/app/vendor/symfony/process/Exception/ProcessSignaledException.php +++ b/app/vendor/symfony/process/Exception/ProcessSignaledException.php @@ -20,7 +20,7 @@ */ final class ProcessSignaledException extends RuntimeException { - private $process; + private Process $process; public function __construct(Process $process) { diff --git a/app/vendor/symfony/process/Exception/ProcessTimedOutException.php b/app/vendor/symfony/process/Exception/ProcessTimedOutException.php index e507ca309..252e11127 100644 --- a/app/vendor/symfony/process/Exception/ProcessTimedOutException.php +++ b/app/vendor/symfony/process/Exception/ProcessTimedOutException.php @@ -23,8 +23,8 @@ class ProcessTimedOutException extends RuntimeException public const TYPE_GENERAL = 1; public const TYPE_IDLE = 2; - private $process; - private $timeoutType; + private Process $process; + private int $timeoutType; public function __construct(Process $process, int $timeoutType) { @@ -38,26 +38,17 @@ public function __construct(Process $process, int $timeoutType) )); } - /** - * @return Process - */ - public function getProcess() + public function getProcess(): Process { return $this->process; } - /** - * @return bool - */ - public function isGeneralTimeout() + public function isGeneralTimeout(): bool { return self::TYPE_GENERAL === $this->timeoutType; } - /** - * @return bool - */ - public function isIdleTimeout() + public function isIdleTimeout(): bool { return self::TYPE_IDLE === $this->timeoutType; } diff --git a/app/vendor/symfony/process/Exception/RunProcessFailedException.php b/app/vendor/symfony/process/Exception/RunProcessFailedException.php new file mode 100644 index 000000000..e7219d351 --- /dev/null +++ b/app/vendor/symfony/process/Exception/RunProcessFailedException.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\Process\Exception; + +use Symfony\Component\Process\Messenger\RunProcessContext; + +/** + * @author Kevin Bond + */ +final class RunProcessFailedException extends RuntimeException +{ + public function __construct(ProcessFailedException $exception, public readonly RunProcessContext $context) + { + parent::__construct($exception->getMessage(), $exception->getCode()); + } +} diff --git a/app/vendor/symfony/process/ExecutableFinder.php b/app/vendor/symfony/process/ExecutableFinder.php index e3387dfe1..ceb7a5588 100644 --- a/app/vendor/symfony/process/ExecutableFinder.php +++ b/app/vendor/symfony/process/ExecutableFinder.php @@ -19,24 +19,20 @@ */ class ExecutableFinder { - private $suffixes = ['.exe', '.bat', '.cmd', '.com']; + private array $suffixes = ['.exe', '.bat', '.cmd', '.com']; /** * Replaces default suffixes of executable. - * - * @return void */ - public function setSuffixes(array $suffixes) + public function setSuffixes(array $suffixes): void { $this->suffixes = $suffixes; } /** * Adds new possible suffix to check for executable. - * - * @return void */ - public function addSuffix(string $suffix) + public function addSuffix(string $suffix): void { $this->suffixes[] = $suffix; } @@ -48,27 +44,12 @@ public function addSuffix(string $suffix) * @param string|null $default The default to return if no executable is found * @param array $extraDirs Additional dirs to check into */ - public function find(string $name, string $default = null, array $extraDirs = []): ?string + public function find(string $name, ?string $default = null, array $extraDirs = []): ?string { - if (\ini_get('open_basedir')) { - $searchPath = array_merge(explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs); - $dirs = []; - foreach ($searchPath as $path) { - // Silencing against https://bugs.php.net/69240 - if (@is_dir($path)) { - $dirs[] = $path; - } else { - if (basename($path) == $name && @is_executable($path)) { - return $path; - } - } - } - } else { - $dirs = array_merge( - explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), - $extraDirs - ); - } + $dirs = array_merge( + explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), + $extraDirs + ); $suffixes = ['']; if ('\\' === \DIRECTORY_SEPARATOR) { @@ -80,9 +61,18 @@ public function find(string $name, string $default = null, array $extraDirs = [] if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) { return $file; } + + if (!@is_dir($dir) && basename($dir) === $name.$suffix && @is_executable($dir)) { + return $dir; + } } } + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --'; + if (\function_exists('exec') && ($executablePath = strtok(@exec($command.' '.escapeshellarg($name)), \PHP_EOL)) && @is_executable($executablePath)) { + return $executablePath; + } + return $default; } } diff --git a/app/vendor/symfony/process/InputStream.php b/app/vendor/symfony/process/InputStream.php index 086f5a9ed..cd91029e8 100644 --- a/app/vendor/symfony/process/InputStream.php +++ b/app/vendor/symfony/process/InputStream.php @@ -22,19 +22,16 @@ */ class InputStream implements \IteratorAggregate { - /** @var callable|null */ - private $onEmpty; - private $input = []; - private $open = true; + private ?\Closure $onEmpty = null; + private array $input = []; + private bool $open = true; /** * Sets a callback that is called when the write buffer becomes empty. - * - * @return void */ - public function onEmpty(callable $onEmpty = null) + public function onEmpty(?callable $onEmpty = null): void { - $this->onEmpty = $onEmpty; + $this->onEmpty = null !== $onEmpty ? $onEmpty(...) : null; } /** @@ -42,10 +39,8 @@ public function onEmpty(callable $onEmpty = null) * * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar, * stream resource or \Traversable - * - * @return void */ - public function write(mixed $input) + public function write(mixed $input): void { if (null === $input) { return; @@ -58,20 +53,16 @@ public function write(mixed $input) /** * Closes the write buffer. - * - * @return void */ - public function close() + public function close(): void { $this->open = false; } /** * Tells whether the write buffer is closed or not. - * - * @return bool */ - public function isClosed() + public function isClosed(): bool { return !$this->open; } diff --git a/app/vendor/symfony/process/Messenger/RunProcessContext.php b/app/vendor/symfony/process/Messenger/RunProcessContext.php new file mode 100644 index 000000000..b5ade0722 --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessContext.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Messenger; + +use Symfony\Component\Process\Process; + +/** + * @author Kevin Bond + */ +final class RunProcessContext +{ + public readonly ?int $exitCode; + public readonly ?string $output; + public readonly ?string $errorOutput; + + public function __construct( + public readonly RunProcessMessage $message, + Process $process, + ) { + $this->exitCode = $process->getExitCode(); + $this->output = $process->isOutputDisabled() ? null : $process->getOutput(); + $this->errorOutput = $process->isOutputDisabled() ? null : $process->getErrorOutput(); + } +} diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessage.php b/app/vendor/symfony/process/Messenger/RunProcessMessage.php new file mode 100644 index 000000000..b2c33fe3b --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessMessage.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\Process\Messenger; + +/** + * @author Kevin Bond + */ +class RunProcessMessage implements \Stringable +{ + public function __construct( + public readonly array $command, + public readonly ?string $cwd = null, + public readonly ?array $env = null, + public readonly mixed $input = null, + public readonly ?float $timeout = 60.0, + ) { + } + + public function __toString(): string + { + return implode(' ', $this->command); + } +} diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php new file mode 100644 index 000000000..41c1934cc --- /dev/null +++ b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process\Messenger; + +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Exception\RunProcessFailedException; +use Symfony\Component\Process\Process; + +/** + * @author Kevin Bond + */ +final class RunProcessMessageHandler +{ + public function __invoke(RunProcessMessage $message): RunProcessContext + { + $process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout); + + try { + return new RunProcessContext($message, $process->mustRun()); + } catch (ProcessFailedException $e) { + throw new RunProcessFailedException($e, new RunProcessContext($message, $e->getProcess())); + } + } +} diff --git a/app/vendor/symfony/process/PhpExecutableFinder.php b/app/vendor/symfony/process/PhpExecutableFinder.php index 9ab8ac23f..4a882e0f2 100644 --- a/app/vendor/symfony/process/PhpExecutableFinder.php +++ b/app/vendor/symfony/process/PhpExecutableFinder.php @@ -19,7 +19,7 @@ */ class PhpExecutableFinder { - private $executableFinder; + private ExecutableFinder $executableFinder; public function __construct() { @@ -33,8 +33,8 @@ public function find(bool $includeArgs = true): string|false { if ($php = getenv('PHP_BINARY')) { if (!is_executable($php)) { - $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; - if ($php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) { + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --'; + if (\function_exists('exec') && $php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) { if (!is_executable($php)) { return false; } diff --git a/app/vendor/symfony/process/PhpProcess.php b/app/vendor/symfony/process/PhpProcess.php index ef54a3d2b..01d88954d 100644 --- a/app/vendor/symfony/process/PhpProcess.php +++ b/app/vendor/symfony/process/PhpProcess.php @@ -32,7 +32,7 @@ class PhpProcess extends Process * @param int $timeout The timeout in seconds * @param array|null $php Path to the PHP binary to use with any additional arguments */ - public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null) + public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) { if (null === $php) { $executableFinder = new PhpExecutableFinder(); @@ -50,15 +50,12 @@ public function __construct(string $script, string $cwd = null, array $env = nul parent::__construct($php, $cwd, $env, $script, $timeout); } - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } - /** - * @return void - */ - public function start(callable $callback = null, array $env = []) + public function start(?callable $callback = null, array $env = []): void { if (null === $this->getCommandLine()) { throw new RuntimeException('Unable to find the PHP executable.'); diff --git a/app/vendor/symfony/process/PhpSubprocess.php b/app/vendor/symfony/process/PhpSubprocess.php new file mode 100644 index 000000000..a97f8b26e --- /dev/null +++ b/app/vendor/symfony/process/PhpSubprocess.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Process; + +use Symfony\Component\Process\Exception\LogicException; +use Symfony\Component\Process\Exception\RuntimeException; + +/** + * PhpSubprocess runs a PHP command as a subprocess while keeping the original php.ini settings. + * + * For this, it generates a temporary php.ini file taking over all the current settings and disables + * loading additional .ini files. Basically, your command gets prefixed using "php -n -c /tmp/temp.ini". + * + * Given your php.ini contains "memory_limit=-1" and you have a "MemoryTest.php" with the following content: + * + * run(); + * print $p->getOutput()."\n"; + * + * This will output "string(2) "-1", because the process is started with the default php.ini settings. + * + * $p = new PhpSubprocess(['MemoryTest.php'], null, null, 60, ['php', '-d', 'memory_limit=256M']); + * $p->run(); + * print $p->getOutput()."\n"; + * + * This will output "string(4) "256M"", because the process is started with the temporarily created php.ini settings. + * + * @author Yanick Witschi + * @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson + */ +class PhpSubprocess extends Process +{ + /** + * @param array $command The command to run and its arguments listed as separate entries. They will automatically + * get prefixed with the PHP binary + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param int $timeout The timeout in seconds + * @param array|null $php Path to the PHP binary to use with any additional arguments + */ + public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) + { + if (null === $php) { + $executableFinder = new PhpExecutableFinder(); + $php = $executableFinder->find(false); + $php = false === $php ? null : array_merge([$php], $executableFinder->findArguments()); + } + + if (null === $php) { + throw new RuntimeException('Unable to find PHP binary.'); + } + + $tmpIni = $this->writeTmpIni($this->getAllIniFiles(), sys_get_temp_dir()); + + $php = array_merge($php, ['-n', '-c', $tmpIni]); + register_shutdown_function('unlink', $tmpIni); + + $command = array_merge($php, $command); + + parent::__construct($command, $cwd, $env, null, $timeout); + } + + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static + { + throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + } + + public function start(?callable $callback = null, array $env = []): void + { + if (null === $this->getCommandLine()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + + parent::start($callback, $env); + } + + private function writeTmpIni(array $iniFiles, string $tmpDir): string + { + if (false === $tmpfile = @tempnam($tmpDir, '')) { + throw new RuntimeException('Unable to create temporary ini file.'); + } + + // $iniFiles has at least one item and it may be empty + if ('' === $iniFiles[0]) { + array_shift($iniFiles); + } + + $content = ''; + + foreach ($iniFiles as $file) { + // Check for inaccessible ini files + if (($data = @file_get_contents($file)) === false) { + throw new RuntimeException('Unable to read ini: '.$file); + } + // Check and remove directives after HOST and PATH sections + if (preg_match('/^\s*\[(?:PATH|HOST)\s*=/mi', $data, $matches)) { + $data = substr($data, 0, $matches[0][1]); + } + + $content .= $data."\n"; + } + + // Merge loaded settings into our ini content, if it is valid + $config = parse_ini_string($content); + $loaded = ini_get_all(null, false); + + if (false === $config || false === $loaded) { + throw new RuntimeException('Unable to parse ini data.'); + } + + $content .= $this->mergeLoadedConfig($loaded, $config); + + // Work-around for https://bugs.php.net/bug.php?id=75932 + $content .= "opcache.enable_cli=0\n"; + + if (false === @file_put_contents($tmpfile, $content)) { + throw new RuntimeException('Unable to write temporary ini file.'); + } + + return $tmpfile; + } + + private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): string + { + $content = ''; + + foreach ($loadedConfig as $name => $value) { + if (!\is_string($value)) { + continue; + } + + if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) { + // Double-quote escape each value + $content .= $name.'="'.addcslashes($value, '\\"')."\"\n"; + } + } + + return $content; + } + + private function getAllIniFiles(): array + { + $paths = [(string) php_ini_loaded_file()]; + + if (false !== $scanned = php_ini_scanned_files()) { + $paths = array_merge($paths, array_map('trim', explode(',', $scanned))); + } + + return $paths; + } +} diff --git a/app/vendor/symfony/process/Pipes/AbstractPipes.php b/app/vendor/symfony/process/Pipes/AbstractPipes.php index ba3a97a3f..cbbb72770 100644 --- a/app/vendor/symfony/process/Pipes/AbstractPipes.php +++ b/app/vendor/symfony/process/Pipes/AbstractPipes.php @@ -22,20 +22,19 @@ abstract class AbstractPipes implements PipesInterface { public array $pipes = []; - private $inputBuffer = ''; + private string $inputBuffer = ''; + /** @var resource|string|\Iterator */ private $input; - private $blocked = true; - private $lastError; + private bool $blocked = true; + private ?string $lastError = null; /** - * @param resource|string|int|float|bool|\Iterator|null $input + * @param resource|string|\Iterator $input */ - public function __construct(mixed $input) + public function __construct($input) { if (\is_resource($input) || $input instanceof \Iterator) { $this->input = $input; - } elseif (\is_string($input)) { - $this->inputBuffer = $input; } else { $this->inputBuffer = (string) $input; } diff --git a/app/vendor/symfony/process/Pipes/UnixPipes.php b/app/vendor/symfony/process/Pipes/UnixPipes.php index aba0efced..7bd0db0e9 100644 --- a/app/vendor/symfony/process/Pipes/UnixPipes.php +++ b/app/vendor/symfony/process/Pipes/UnixPipes.php @@ -22,9 +22,9 @@ */ class UnixPipes extends AbstractPipes { - private $ttyMode; - private $ptyMode; - private $haveReadSupport; + private ?bool $ttyMode; + private bool $ptyMode; + private bool $haveReadSupport; public function __construct(?bool $ttyMode, bool $ptyMode, mixed $input, bool $haveReadSupport) { @@ -40,7 +40,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } diff --git a/app/vendor/symfony/process/Pipes/WindowsPipes.php b/app/vendor/symfony/process/Pipes/WindowsPipes.php index 0d6ab12d3..8033442a4 100644 --- a/app/vendor/symfony/process/Pipes/WindowsPipes.php +++ b/app/vendor/symfony/process/Pipes/WindowsPipes.php @@ -26,14 +26,14 @@ */ class WindowsPipes extends AbstractPipes { - private $files = []; - private $fileHandles = []; - private $lockHandles = []; - private $readBytes = [ + private array $files = []; + private array $fileHandles = []; + private array $lockHandles = []; + private array $readBytes = [ Process::STDOUT => 0, Process::STDERR => 0, ]; - private $haveReadSupport; + private bool $haveReadSupport; public function __construct(mixed $input, bool $haveReadSupport) { @@ -93,7 +93,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -140,7 +140,7 @@ public function readAndWrite(bool $blocking, bool $close = false): array if ($w) { @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); } elseif ($this->fileHandles) { - usleep(Process::TIMEOUT_PRECISION * 1E6); + usleep((int) (Process::TIMEOUT_PRECISION * 1E6)); } } foreach ($this->fileHandles as $type => $fileHandle) { diff --git a/app/vendor/symfony/process/Process.php b/app/vendor/symfony/process/Process.php index 40dbd4162..1aaf730de 100644 --- a/app/vendor/symfony/process/Process.php +++ b/app/vendor/symfony/process/Process.php @@ -17,7 +17,6 @@ use Symfony\Component\Process\Exception\ProcessSignaledException; use Symfony\Component\Process\Exception\ProcessTimedOutException; use Symfony\Component\Process\Exception\RuntimeException; -use Symfony\Component\Process\Pipes\PipesInterface; use Symfony\Component\Process\Pipes\UnixPipes; use Symfony\Component\Process\Pipes\WindowsPipes; @@ -51,44 +50,46 @@ class Process implements \IteratorAggregate public const ITER_SKIP_OUT = 4; // Use this flag to skip STDOUT while iterating public const ITER_SKIP_ERR = 8; // Use this flag to skip STDERR while iterating - private $callback; - private $hasCallback = false; - private $commandline; - private $cwd; - private $env = []; + private ?\Closure $callback = null; + private array|string $commandline; + private ?string $cwd; + private array $env = []; + /** @var resource|string|\Iterator|null */ private $input; - private $starttime; - private $lastOutputTime; - private $timeout; - private $idleTimeout; - private $exitcode; - private $fallbackStatus = []; - private $processInformation; - private $outputDisabled = false; + private ?float $starttime = null; + private ?float $lastOutputTime = null; + private ?float $timeout = null; + private ?float $idleTimeout = null; + private ?int $exitcode = null; + private array $fallbackStatus = []; + private array $processInformation; + private bool $outputDisabled = false; + /** @var resource */ private $stdout; + /** @var resource */ private $stderr; + /** @var resource|null */ private $process; - private $status = self::STATUS_READY; - private $incrementalOutputOffset = 0; - private $incrementalErrorOutputOffset = 0; - private $tty = false; - private $pty; - private $options = ['suppress_errors' => true, 'bypass_shell' => true]; + private string $status = self::STATUS_READY; + private int $incrementalOutputOffset = 0; + private int $incrementalErrorOutputOffset = 0; + private bool $tty = false; + private bool $pty; + private array $options = ['suppress_errors' => true, 'bypass_shell' => true]; - private $useFileHandles = false; - /** @var PipesInterface */ - private $processPipes; + private WindowsPipes|UnixPipes $processPipes; - private $latestSignal; + private ?int $latestSignal = null; + private ?int $cachedExitCode = null; - private static $sigchild; + private static ?bool $sigchild = null; /** * Exit codes translation table. * * User-defined errors must use exit codes in the 64-113 range. */ - public static $exitCodes = [ + public static array $exitCodes = [ 0 => 'OK', 1 => 'General error', 2 => 'Misuse of shell builtins', @@ -140,7 +141,7 @@ class Process implements \IteratorAggregate * * @throws LogicException When proc_open is not installed */ - public function __construct(array $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60) + public function __construct(array $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60) { if (!\function_exists('proc_open')) { throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.'); @@ -162,7 +163,6 @@ public function __construct(array $command, string $cwd = null, array $env = nul $this->setInput($input); $this->setTimeout($timeout); - $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR; $this->pty = false; } @@ -187,7 +187,7 @@ public function __construct(array $command, string $cwd = null, array $env = nul * * @throws LogicException When proc_open is not installed */ - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { $process = new static([], $cwd, $env, $input, $timeout); $process->commandline = $command; @@ -200,7 +200,7 @@ public function __sleep(): array throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup() + public function __wakeup(): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -242,7 +242,7 @@ public function __clone() * * @final */ - public function run(callable $callback = null, array $env = []): int + public function run(?callable $callback = null, array $env = []): int { $this->start($callback, $env); @@ -261,7 +261,7 @@ public function run(callable $callback = null, array $env = []): int * * @final */ - public function mustRun(callable $callback = null, array $env = []): static + public function mustRun(?callable $callback = null, array $env = []): static { if (0 !== $this->run($callback, $env)) { throw new ProcessFailedException($this); @@ -285,13 +285,11 @@ public function mustRun(callable $callback = null, array $env = []): static * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * - * @return void - * * @throws RuntimeException When process can't be launched * @throws RuntimeException When process is already running * @throws LogicException In case a callback is provided and output has been disabled */ - public function start(callable $callback = null, array $env = []) + public function start(?callable $callback = null, array $env = []): void { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -300,8 +298,7 @@ public function start(callable $callback = null, array $env = []) $this->resetProcessData(); $this->starttime = $this->lastOutputTime = microtime(true); $this->callback = $this->buildCallback($callback); - $this->hasCallback = null !== $callback; - $descriptors = $this->getDescriptors(); + $descriptors = $this->getDescriptors(null !== $callback); if ($this->env) { $env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env; @@ -322,17 +319,13 @@ public function start(callable $callback = null, array $env = []) if ('\\' === \DIRECTORY_SEPARATOR) { $commandline = $this->prepareWindowsCommandLine($commandline, $env); - } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) { + } elseif ($this->isSigchildEnabled()) { // last exit code is output on the fourth pipe and caught to work around --enable-sigchild $descriptors[3] = ['pipe', 'w']; // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; - $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code'; - - // Workaround for the bug, when PTS functionality is enabled. - // @see : https://bugs.php.net/69442 - $ptsWorkaround = fopen(__FILE__, 'r'); + $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code'; } $envPairs = []; @@ -346,11 +339,12 @@ public function start(callable $callback = null, array $env = []) throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd)); } - $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + $process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); - if (!\is_resource($this->process)) { + if (!\is_resource($process)) { throw new RuntimeException('Unable to launch a new process.'); } + $this->process = $process; $this->status = self::STATUS_STARTED; if (isset($descriptors[3])) { @@ -380,7 +374,7 @@ public function start(callable $callback = null, array $env = []) * * @final */ - public function restart(callable $callback = null, array $env = []): static + public function restart(?callable $callback = null, array $env = []): static { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -407,7 +401,7 @@ public function restart(callable $callback = null, array $env = []): static * @throws ProcessSignaledException When process stopped after receiving signal * @throws LogicException When process is not yet started */ - public function wait(callable $callback = null): int + public function wait(?callable $callback = null): int { $this->requireProcessIsStarted(__FUNCTION__); @@ -880,7 +874,7 @@ public function getStatus(): string * * @return int|null The exit-code of the process or null if it's not running */ - public function stop(float $timeout = 10, int $signal = null): ?int + public function stop(float $timeout = 10, ?int $signal = null): ?int { $timeoutMicro = microtime(true) + $timeout; if ($this->isRunning()) { @@ -1119,7 +1113,7 @@ public function getInput() * * This content will be passed to the underlying process standard input. * - * @param string|int|float|bool|resource|\Traversable|null $input The content + * @param string|resource|\Traversable|self|null $input The content * * @return $this * @@ -1142,11 +1136,9 @@ public function setInput(mixed $input): static * In case you run a background process (with the start method), you should * trigger this method regularly to ensure the process timeout * - * @return void - * * @throws ProcessTimedOutException In case the timeout was reached */ - public function checkTimeout() + public function checkTimeout(): void { if (self::STATUS_STARTED !== $this->status) { return; @@ -1184,10 +1176,8 @@ public function getStartTime(): float * * Enabling the "create_new_console" option allows a subprocess to continue * to run after the main process exited, on both Windows and *nix - * - * @return void */ - public function setOptions(array $options) + public function setOptions(array $options): void { if ($this->isRunning()) { throw new RuntimeException('Setting options while the process is running is not possible.'); @@ -1236,15 +1226,15 @@ public static function isPtySupported(): bool /** * Creates the descriptors needed by the proc_open. */ - private function getDescriptors(): array + private function getDescriptors(bool $hasCallback): array { if ($this->input instanceof \Iterator) { $this->input->rewind(); } if ('\\' === \DIRECTORY_SEPARATOR) { - $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback); + $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $hasCallback); } else { - $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback); + $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $hasCallback); } return $this->processPipes->getDescriptors(); @@ -1258,7 +1248,7 @@ private function getDescriptors(): array * * @param callable|null $callback The user defined PHP callback */ - protected function buildCallback(callable $callback = null): \Closure + protected function buildCallback(?callable $callback = null): \Closure { if ($this->outputDisabled) { return fn ($type, $data): bool => null !== $callback && $callback($type, $data); @@ -1281,10 +1271,8 @@ protected function buildCallback(callable $callback = null): \Closure * Updates the status of the process, reads pipes. * * @param bool $blocking Whether to use a blocking read call - * - * @return void */ - protected function updateStatus(bool $blocking) + protected function updateStatus(bool $blocking): void { if (self::STATUS_STARTED !== $this->status) { return; @@ -1293,6 +1281,19 @@ protected function updateStatus(bool $blocking) $this->processInformation = proc_get_status($this->process); $running = $this->processInformation['running']; + // In PHP < 8.3, "proc_get_status" only returns the correct exit status on the first call. + // Subsequent calls return -1 as the process is discarded. This workaround caches the first + // retrieved exit status for consistent results in later calls, mimicking PHP 8.3 behavior. + if (\PHP_VERSION_ID < 80300) { + if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) { + $this->cachedExitCode = $this->processInformation['exitcode']; + } + + if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) { + $this->processInformation['exitcode'] = $this->cachedExitCode; + } + } + $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); if ($this->fallbackStatus && $this->isSigchildEnabled()) { @@ -1421,7 +1422,7 @@ private function resetProcessData(): void $this->callback = null; $this->exitcode = null; $this->fallbackStatus = []; - $this->processInformation = null; + $this->processInformation = []; $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->process = null; diff --git a/app/vendor/symfony/process/ProcessUtils.php b/app/vendor/symfony/process/ProcessUtils.php index 744399d98..092c5ccf7 100644 --- a/app/vendor/symfony/process/ProcessUtils.php +++ b/app/vendor/symfony/process/ProcessUtils.php @@ -43,9 +43,6 @@ public static function validateInput(string $caller, mixed $input): mixed if (\is_resource($input)) { return $input; } - if (\is_string($input)) { - return $input; - } if (\is_scalar($input)) { return (string) $input; } diff --git a/app/vendor/symfony/process/composer.json b/app/vendor/symfony/process/composer.json index 317c07e71..dda5575ed 100644 --- a/app/vendor/symfony/process/composer.json +++ b/app/vendor/symfony/process/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.1" + "php": ">=8.2" }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" }, diff --git a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php index 45c8d910d..b62ec3e53 100644 --- a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php +++ b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -31,7 +31,7 @@ trait ServiceLocatorTrait private array $providedTypes; /** - * @param callable[] $factories + * @param array $factories */ public function __construct(array $factories) { diff --git a/app/vendor/symfony/service-contracts/ServiceProviderInterface.php b/app/vendor/symfony/service-contracts/ServiceProviderInterface.php index c05e4bfe7..2e71f00c6 100644 --- a/app/vendor/symfony/service-contracts/ServiceProviderInterface.php +++ b/app/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -39,7 +39,7 @@ public function has(string $id): bool; * * ['foo' => '?'] means the container provides service name "foo" of unspecified type * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null * - * @return string[] The provided service types, keyed by service names + * @return array The provided service types, keyed by service names */ public function getProvidedServices(): array; } diff --git a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php index a0f20a6a7..65a3fe337 100644 --- a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php +++ b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -12,7 +12,9 @@ namespace Symfony\Contracts\Service\Test; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Symfony\Contracts\Service\ServiceLocatorTrait; abstract class ServiceLocatorTestCase extends TestCase @@ -27,9 +29,9 @@ protected function getServiceLocator(array $factories): ContainerInterface public function testHas() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', + fn () => 'dummy', ]); $this->assertTrue($locator->has('foo')); @@ -40,8 +42,8 @@ function () { return 'dummy'; }, public function testGet() { $locator = $this->getServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, + 'foo' => fn () => 'bar', + 'bar' => fn () => 'baz', ]); $this->assertSame('bar', $locator->get('foo')); @@ -66,27 +68,29 @@ public function testGetDoesNotMemoize() public function testThrowsOnUndefinedInternalService() { - if (!$this->getExpectedException()) { - $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } $locator = $this->getServiceLocator([ 'foo' => function () use (&$locator) { return $locator->get('bar'); }, ]); + if (!$this->getExpectedException()) { + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator->get('foo'); } public function testThrowsOnCircularReference() { - $this->expectException(\Psr\Container\ContainerExceptionInterface::class); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); $locator = $this->getServiceLocator([ 'foo' => function () use (&$locator) { return $locator->get('bar'); }, 'bar' => function () use (&$locator) { return $locator->get('baz'); }, 'baz' => function () use (&$locator) { return $locator->get('bar'); }, ]); + $this->expectException(ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator->get('foo'); } } diff --git a/app/vendor/symfony/service-contracts/composer.json b/app/vendor/symfony/service-contracts/composer.json index a64188b51..32bb8a316 100644 --- a/app/vendor/symfony/service-contracts/composer.json +++ b/app/vendor/symfony/service-contracts/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" diff --git a/app/vendor/symfony/string/AbstractString.php b/app/vendor/symfony/string/AbstractString.php index bf491f88d..253d2dcb6 100644 --- a/app/vendor/symfony/string/AbstractString.php +++ b/app/vendor/symfony/string/AbstractString.php @@ -39,8 +39,8 @@ abstract class AbstractString implements \Stringable, \JsonSerializable public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; - protected $string = ''; - protected $ignoreCase = false; + protected string $string = ''; + protected ?bool $ignoreCase = false; abstract public function __construct(string $string = ''); @@ -383,7 +383,7 @@ public function isEmpty(): bool return '' === $this->string; } - abstract public function join(array $strings, string $lastGlue = null): static; + abstract public function join(array $strings, ?string $lastGlue = null): static; public function jsonSerialize(): string { @@ -429,16 +429,16 @@ abstract public function replaceMatches(string $fromRegexp, string|callable $to) abstract public function reverse(): static; - abstract public function slice(int $start = 0, int $length = null): static; + abstract public function slice(int $start = 0, ?int $length = null): static; abstract public function snake(): static; - abstract public function splice(string $replacement, int $start = 0, int $length = null): static; + abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static; /** * @return static[] */ - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (null === $flags) { throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); @@ -448,7 +448,7 @@ public function split(string $delimiter, int $limit = null, int $flags = null): $delimiter .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) { @@ -495,7 +495,7 @@ public function startsWith(string|iterable $prefix): bool abstract public function title(bool $allWords = false): static; - public function toByteString(string $toEncoding = null): ByteString + public function toByteString(?string $toEncoding = null): ByteString { $b = new ByteString(); @@ -507,20 +507,14 @@ public function toByteString(string $toEncoding = null): ByteString return $b; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); - try { - try { - $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); - } catch (InvalidArgumentException $e) { - if (!\function_exists('iconv')) { - throw $e; - } - - $b->string = iconv('UTF-8', $toEncoding, $this->string); + $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); + } catch (\ValueError $e) { + if (!\function_exists('iconv')) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } - } finally { - restore_error_handler(); + + $b->string = iconv('UTF-8', $toEncoding, $this->string); } return $b; diff --git a/app/vendor/symfony/string/AbstractUnicodeString.php b/app/vendor/symfony/string/AbstractUnicodeString.php index d19a61a9c..673ad8ce9 100644 --- a/app/vendor/symfony/string/AbstractUnicodeString.php +++ b/app/vendor/symfony/string/AbstractUnicodeString.php @@ -44,9 +44,9 @@ abstract class AbstractUnicodeString extends AbstractString private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; - private static $transliterators = []; - private static $tableZero; - private static $tableWide; + private static array $transliterators = []; + private static array $tableZero; + private static array $tableWide; public static function fromCodePoints(int ...$codes): static { @@ -198,7 +198,7 @@ public function folded(bool $compat = true): static return $str; } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = clone $this; @@ -228,7 +228,7 @@ public function match(string $regexp, int $flags = 0, int $offset = 0): array $regexp .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { @@ -312,7 +312,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static $replace = 'preg_replace'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) { diff --git a/app/vendor/symfony/string/ByteString.php b/app/vendor/symfony/string/ByteString.php index 212290fed..3ebe43c10 100644 --- a/app/vendor/symfony/string/ByteString.php +++ b/app/vendor/symfony/string/ByteString.php @@ -42,7 +42,7 @@ public function __construct(string $string = '') * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) */ - public static function fromRandom(int $length = 16, string $alphabet = null): self + public static function fromRandom(int $length = 16, ?string $alphabet = null): self { if ($length <= 0) { throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); @@ -205,7 +205,7 @@ public function isUtf8(): bool return '' === $this->string || preg_match('//u', $this->string); } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = clone $this; @@ -236,7 +236,7 @@ public function match(string $regexp, int $flags = 0, int $offset = 0): array $regexp .= 'i'; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { @@ -300,7 +300,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { if (null === $string = $replace($fromRegexp, $to, $this->string)) { @@ -332,7 +332,7 @@ public function reverse(): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX); @@ -348,7 +348,7 @@ public function snake(): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { $str = clone $this; $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); @@ -356,7 +356,7 @@ public function splice(string $replacement, int $start = 0, int $length = null): return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); @@ -402,12 +402,12 @@ public function title(bool $allWords = false): static return $str; } - public function toUnicodeString(string $fromEncoding = null): UnicodeString + public function toUnicodeString(?string $fromEncoding = null): UnicodeString { return new UnicodeString($this->toCodePointString($fromEncoding)->string); } - public function toCodePointString(string $fromEncoding = null): CodePointString + public function toCodePointString(?string $fromEncoding = null): CodePointString { $u = new CodePointString(); @@ -417,7 +417,7 @@ public function toCodePointString(string $fromEncoding = null): CodePointString return $u; } - set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); + set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m)); try { try { diff --git a/app/vendor/symfony/string/CodePointString.php b/app/vendor/symfony/string/CodePointString.php index f5c900fb2..337bfc12a 100644 --- a/app/vendor/symfony/string/CodePointString.php +++ b/app/vendor/symfony/string/CodePointString.php @@ -186,7 +186,7 @@ public function replace(string $from, string $to): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; $str->string = mb_substr($this->string, $start, $length, 'UTF-8'); @@ -194,7 +194,7 @@ public function slice(int $start = 0, int $length = null): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { if (!preg_match('//u', $replacement)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); @@ -208,7 +208,7 @@ public function splice(string $replacement, int $start = 0, int $length = null): return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); diff --git a/app/vendor/symfony/string/Inflector/EnglishInflector.php b/app/vendor/symfony/string/Inflector/EnglishInflector.php index 2cd6bb87b..dc7b08e7e 100644 --- a/app/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/app/vendor/symfony/string/Inflector/EnglishInflector.php @@ -21,7 +21,7 @@ final class EnglishInflector implements InflectorInterface private const PLURAL_MAP = [ // First entry: plural suffix, reversed // Second entry: length of plural suffix - // Third entry: Whether the suffix may succeed a vocal + // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal @@ -162,10 +162,13 @@ final class EnglishInflector implements InflectorInterface private const SINGULAR_MAP = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix - // Third entry: Whether the suffix may succeed a vocal + // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal + // axes (axis) + ['sixa', 4, false, false, 'axes'], + // criterion (criteria) ['airetirc', 8, false, false, 'criterion'], @@ -253,6 +256,9 @@ final class EnglishInflector implements InflectorInterface // seasons (season), treasons (treason), poisons (poison), lessons (lesson) ['nos', 3, true, true, 'sons'], + // icons (icon) + ['noc', 3, true, true, 'cons'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['no', 2, true, true, 'a'], @@ -285,6 +291,12 @@ final class EnglishInflector implements InflectorInterface // circuses (circus) ['suc', 3, true, true, 'cuses'], + // hippocampi (hippocampus) + ['supmacoppih', 11, false, false, 'hippocampi'], + + // campuses (campus) + ['sup', 3, true, true, 'puses'], + // status (status) ['sutats', 6, true, true, ['status', 'statuses']], @@ -343,15 +355,30 @@ final class EnglishInflector implements InflectorInterface // deer 'reed', + // equipment + 'tnempiuqe', + // feedback 'kcabdeef', // fish 'hsif', + // health + 'htlaeh', + + // history + 'yrotsih', + // info 'ofni', + // information + 'noitamrofni', + + // money + 'yenom', + // moose 'esoom', @@ -363,6 +390,12 @@ final class EnglishInflector implements InflectorInterface // species 'seiceps', + + // traffic + 'ciffart', + + // aircraft + 'tfarcria', ]; public function singularize(string $plural): array @@ -396,14 +429,14 @@ public function singularize(string $plural): array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $pluralLength) { - $nextIsVocal = str_contains('aeiou', $lowerPluralRev[$j]); + $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]); - if (!$map[2] && $nextIsVocal) { - // suffix may not succeed a vocal but next char is one + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one break; } - if (!$map[3] && !$nextIsVocal) { + if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } @@ -473,14 +506,14 @@ public function pluralize(string $singular): array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $singularLength) { - $nextIsVocal = str_contains('aeiou', $lowerSingularRev[$j]); + $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]); - if (!$map[2] && $nextIsVocal) { - // suffix may not succeed a vocal but next char is one + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one break; } - if (!$map[3] && !$nextIsVocal) { + if (!$map[3] && !$nextIsVowel) { // suffix may not succeed a consonant but next char is one break; } diff --git a/app/vendor/symfony/string/LazyString.php b/app/vendor/symfony/string/LazyString.php index 3128ebb36..519b54ab9 100644 --- a/app/vendor/symfony/string/LazyString.php +++ b/app/vendor/symfony/string/LazyString.php @@ -39,7 +39,7 @@ public static function fromCallable(callable|array $callback, mixed ...$argument $callback[1] ??= '__invoke'; } $value = $callback(...$arguments); - $callback = self::getPrettyName($callback); + $callback = !\is_scalar($value) && !$value instanceof \Stringable ? self::getPrettyName($callback) : 'callable'; $arguments = null; } @@ -129,7 +129,7 @@ private static function getPrettyName(callable $callback): string } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); - if (str_contains($r->name, '{closure}') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { + if (str_contains($r->name, '{closure}') || !$class = $r->getClosureCalledClass()) { return $r->name; } diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php index 5a647e67b..8314c8fd5 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:36+02:00 + * Unicode version: 15.1.0 + * Date: 2023-09-13T11:47:12+00:00 */ return [ @@ -166,7 +166,7 @@ ], [ 12272, - 12283, + 12287, ], [ 12288, @@ -396,6 +396,10 @@ 12736, 12771, ], + [ + 12783, + 12783, + ], [ 12784, 12799, @@ -1110,6 +1114,14 @@ ], [ 191457, + 191471, + ], + [ + 191472, + 192093, + ], + [ + 192094, 194559, ], [ diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php index 9ae733032..e5b26a215 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php @@ -3,8 +3,8 @@ /* * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.0.0 - * Date: 2022-10-05T17:16:37+02:00 + * Unicode version: 15.1.0 + * Date: 2023-09-13T11:47:13+00:00 */ return [ diff --git a/app/vendor/symfony/string/Slugger/AsciiSlugger.php b/app/vendor/symfony/string/Slugger/AsciiSlugger.php index 6e550c61c..fd47770c2 100644 --- a/app/vendor/symfony/string/Slugger/AsciiSlugger.php +++ b/app/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -68,16 +68,13 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface */ private array $transliterators = []; - public function __construct(string $defaultLocale = null, array|\Closure $symbolsMap = null) + public function __construct(?string $defaultLocale = null, array|\Closure|null $symbolsMap = null) { $this->defaultLocale = $defaultLocale; $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } - /** - * @return void - */ - public function setLocale(string $locale) + public function setLocale(string $locale): void { $this->defaultLocale = $locale; } @@ -104,7 +101,7 @@ public function withEmoji(bool|string $emoji = true): static return $new; } - public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString { $locale ??= $this->defaultLocale; diff --git a/app/vendor/symfony/string/Slugger/SluggerInterface.php b/app/vendor/symfony/string/Slugger/SluggerInterface.php index c679ed933..dd0d58102 100644 --- a/app/vendor/symfony/string/Slugger/SluggerInterface.php +++ b/app/vendor/symfony/string/Slugger/SluggerInterface.php @@ -23,5 +23,5 @@ interface SluggerInterface /** * Creates a slug for the given string and locale, using appropriate transliteration when needed. */ - public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString; + public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString; } diff --git a/app/vendor/symfony/string/UnicodeString.php b/app/vendor/symfony/string/UnicodeString.php index a64c6a9df..4b16caf9f 100644 --- a/app/vendor/symfony/string/UnicodeString.php +++ b/app/vendor/symfony/string/UnicodeString.php @@ -34,23 +34,32 @@ class UnicodeString extends AbstractUnicodeString { public function __construct(string $string = '') { - $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string); + if ('' === $string || normalizer_is_normalized($this->string = $string)) { + return; + } - if (false === $this->string) { + if (false === $string = normalizer_normalize($string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + + $this->string = $string; } public function append(string ...$suffix): static { $str = clone $this; $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix)); - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } @@ -176,7 +185,7 @@ public function indexOfLast(string|iterable|AbstractString $needle, int $offset return false === $i ? null : $i; } - public function join(array $strings, string $lastGlue = null): static + public function join(array $strings, ?string $lastGlue = null): static { $str = parent::join($strings, $lastGlue); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); @@ -209,12 +218,17 @@ public function prepend(string ...$prefix): static { $str = clone $this; $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } @@ -235,11 +249,16 @@ public function replace(string $from, string $to): static } $str->string = $result.$tail; - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + + $str->string = $string; } return $str; @@ -253,7 +272,7 @@ public function replaceMatches(string $fromRegexp, string|callable $to): static return $str; } - public function slice(int $start = 0, int $length = null): static + public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; @@ -262,23 +281,28 @@ public function slice(int $start = 0, int $length = null): static return $str; } - public function splice(string $replacement, int $start = 0, int $length = null): static + public function splice(string $replacement, int $start = 0, ?int $length = null): static { $str = clone $this; $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); - normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); - if (false === $str->string) { + if (normalizer_is_normalized($str->string)) { + return $str; + } + + if (false === $string = normalizer_normalize($str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } + $str->string = $string; + return $str; } - public function split(string $delimiter, int $limit = null, int $flags = null): array + public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array { if (1 > $limit ??= 2147483647) { throw new InvalidArgumentException('Split limit must be a positive integer.'); @@ -338,7 +362,7 @@ public function startsWith(string|iterable|AbstractString $prefix): bool return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); } - public function __wakeup() + public function __wakeup(): void { if (!\is_string($this->string)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); diff --git a/app/vendor/symfony/string/composer.json b/app/vendor/symfony/string/composer.json index 3545c8531..26ce26da3 100644 --- a/app/vendor/symfony/string/composer.json +++ b/app/vendor/symfony/string/composer.json @@ -16,18 +16,18 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/intl": "^6.2", - "symfony/http-client": "^5.4|^6.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^6.4|^7.0" }, "conflict": { "symfony/translation-contracts": "<2.5" diff --git a/app/vendor/symfony/var-dumper/CHANGELOG.md b/app/vendor/symfony/var-dumper/CHANGELOG.md index 932987501..f7021f59a 100644 --- a/app/vendor/symfony/var-dumper/CHANGELOG.md +++ b/app/vendor/symfony/var-dumper/CHANGELOG.md @@ -1,6 +1,18 @@ CHANGELOG ========= +7.0 +--- + + * Add argument `$label` to `VarDumper::dump()` + * Require explicit argument when calling `VarDumper::setHandler()` + * Remove display of backtrace in `Twig_Template`, only `Twig\Template` is supported + +6.4 +--- + + * Dump uninitialized properties + 6.3 --- diff --git a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php index 22026f46a..68b1a65ff 100644 --- a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php @@ -46,10 +46,7 @@ class AmqpCaster \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', ]; - /** - * @return array - */ - public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested) + public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -82,10 +79,7 @@ public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested) + public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -108,10 +102,7 @@ public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $ return $a; } - /** - * @return array - */ - public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested) + public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -134,10 +125,7 @@ public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested) + public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -165,10 +153,7 @@ public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/Caster.php b/app/vendor/symfony/var-dumper/Caster/Caster.php index 32c69ee04..d9577e7ae 100644 --- a/app/vendor/symfony/var-dumper/Caster/Caster.php +++ b/app/vendor/symfony/var-dumper/Caster/Caster.php @@ -32,6 +32,7 @@ class Caster public const EXCLUDE_EMPTY = 128; public const EXCLUDE_NOT_IMPORTANT = 256; public const EXCLUDE_STRICT = 512; + public const EXCLUDE_UNINITIALIZED = 1024; public const PREFIX_VIRTUAL = "\0~\0"; public const PREFIX_DYNAMIC = "\0+\0"; @@ -39,12 +40,14 @@ class Caster // usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property) public const PATTERN_PRIVATE = "\0%s\0%s"; + private static array $classProperties = []; + /** * Casts objects to arrays and adds the dynamic property prefix. * * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not */ - public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array + public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, ?string $debugClass = null): array { if ($hasDebugInfo) { try { @@ -61,20 +64,17 @@ public static function castObject(object $obj, string $class, bool $hasDebugInfo return $a; } + $classProperties = self::$classProperties[$class] ??= self::getClassProperties(new \ReflectionClass($class)); + $a = array_replace($classProperties, $a); + if ($a) { - static $publicProperties = []; $debugClass ??= get_debug_type($obj); $i = 0; $prefixedKeys = []; foreach ($a as $k => $v) { if ("\0" !== ($k[0] ?? '')) { - if (!isset($publicProperties[$class])) { - foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { - $publicProperties[$class][$prop->name] = true; - } - } - if (!isset($publicProperties[$class][$k])) { + if (!isset($classProperties[$k])) { $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; } } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { @@ -131,6 +131,8 @@ public static function filter(array $a, int $filter, array $listedProperties = [ $type |= self::EXCLUDE_EMPTY & $filter; } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { $type |= self::EXCLUDE_EMPTY & $filter; + } elseif ($v instanceof UninitializedStub) { + $type |= self::EXCLUDE_UNINITIALIZED & $filter; } if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { $type |= self::EXCLUDE_NOT_IMPORTANT; @@ -169,4 +171,28 @@ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array return $a; } + + private static function getClassProperties(\ReflectionClass $class): array + { + $classProperties = []; + $className = $class->name; + + if ($parent = $class->getParentClass()) { + $classProperties += self::$classProperties[$parent->name] ??= self::getClassProperties($parent); + } + + foreach ($class->getProperties() as $p) { + if ($p->isStatic()) { + continue; + } + + $classProperties[match (true) { + $p->isPublic() => $p->name, + $p->isProtected() => self::PREFIX_PROTECTED.$p->name, + default => "\0".$className."\0".$p->name, + }] = new UninitializedStub($p); + } + + return $classProperties; + } } diff --git a/app/vendor/symfony/var-dumper/Caster/ClassStub.php b/app/vendor/symfony/var-dumper/Caster/ClassStub.php index 86b44dd2a..5b9ce6407 100644 --- a/app/vendor/symfony/var-dumper/Caster/ClassStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ClassStub.php @@ -24,7 +24,7 @@ class ClassStub extends ConstStub * @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name * @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier */ - public function __construct(string $identifier, callable|array|string $callable = null) + public function __construct(string $identifier, callable|array|string|null $callable = null) { $this->value = $identifier; @@ -85,10 +85,7 @@ public function __construct(string $identifier, callable|array|string $callable } } - /** - * @return mixed - */ - public static function wrapCallable(mixed $callable) + public static function wrapCallable(mixed $callable): mixed { if (\is_object($callable) || !\is_callable($callable)) { return $callable; diff --git a/app/vendor/symfony/var-dumper/Caster/ConstStub.php b/app/vendor/symfony/var-dumper/Caster/ConstStub.php index d7d1812bd..587c6c398 100644 --- a/app/vendor/symfony/var-dumper/Caster/ConstStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ConstStub.php @@ -20,7 +20,7 @@ */ class ConstStub extends Stub { - public function __construct(string $name, string|int|float $value = null) + public function __construct(string $name, string|int|float|null $value = null) { $this->class = $name; $this->value = 1 < \func_num_args() ? $value : $name; diff --git a/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php b/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php index 0e4fb363d..5912e13d8 100644 --- a/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php +++ b/app/vendor/symfony/var-dumper/Caster/CutArrayStub.php @@ -18,7 +18,7 @@ */ class CutArrayStub extends CutStub { - public $preservedSubset; + public array $preservedSubset; public function __construct(array $value, array $preservedKeys) { diff --git a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php index d2d3fc129..ca1ffcea6 100644 --- a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php @@ -63,10 +63,7 @@ class DOMCaster \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; - /** - * @return array - */ - public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested) + public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested): array { $k = Caster::PREFIX_PROTECTED.'code'; if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { @@ -76,10 +73,7 @@ public static function castException(\DOMException $e, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castLength($dom, array $a, Stub $stub, bool $isNested) + public static function castLength($dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'length' => $dom->length, @@ -88,10 +82,7 @@ public static function castLength($dom, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested) + public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'Core' => '1.0', @@ -101,10 +92,7 @@ public static function castImplementation(\DOMImplementation $dom, array $a, Stu return $a; } - /** - * @return array - */ - public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested) + public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -128,10 +116,7 @@ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested) + public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -147,10 +132,7 @@ public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub return $a; } - /** - * @return array - */ - public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ 'doctype' => $dom->doctype, @@ -184,10 +166,7 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested) + public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'data' => $dom->data, @@ -197,10 +176,7 @@ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub return $a; } - /** - * @return array - */ - public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested) + public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, @@ -213,10 +189,7 @@ public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested) + public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'tagName' => $dom->tagName, @@ -226,10 +199,7 @@ public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested) + public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'wholeText' => $dom->wholeText, @@ -238,10 +208,7 @@ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested) + public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, @@ -255,10 +222,7 @@ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $s return $a; } - /** - * @return array - */ - public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested) + public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -268,10 +232,7 @@ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested) + public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -285,10 +246,7 @@ public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $i return $a; } - /** - * @return array - */ - public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested) + public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'target' => $dom->target, @@ -298,10 +256,7 @@ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, return $a; } - /** - * @return array - */ - public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested) + public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'document' => $dom->document, diff --git a/app/vendor/symfony/var-dumper/Caster/DateCaster.php b/app/vendor/symfony/var-dumper/Caster/DateCaster.php index a0cbddb76..cc8593940 100644 --- a/app/vendor/symfony/var-dumper/Caster/DateCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DateCaster.php @@ -24,10 +24,7 @@ class DateCaster { private const PERIOD_LIMIT = 3; - /** - * @return array - */ - public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter) + public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter): array { $prefix = Caster::PREFIX_VIRTUAL; $location = $d->getTimezone() ? $d->getTimezone()->getLocation() : null; @@ -50,10 +47,7 @@ public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter) + public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter): array { $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp(); @@ -82,10 +76,7 @@ private static function formatInterval(\DateInterval $i): string return $i->format(rtrim($format)); } - /** - * @return array - */ - public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter) + public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter): array { $location = $timeZone->getLocation(); $formatted = (new \DateTimeImmutable('now', $timeZone))->format($location ? 'e (P)' : 'P'); @@ -96,10 +87,7 @@ public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stu return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; } - /** - * @return array - */ - public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter) + public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter): array { $dates = []; foreach (clone $p as $i => $d) { @@ -119,7 +107,7 @@ public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $is self::formatInterval($p->getDateInterval()), $p->include_start_date ? '[' : ']', self::formatDateTime($p->getStartDate()), - ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' + ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).($p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' ); $p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))]; diff --git a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php index 3120c3d91..74c06a416 100644 --- a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php @@ -25,10 +25,7 @@ */ class DoctrineCaster { - /** - * @return array - */ - public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested) + public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested): array { foreach (['__cloner__', '__initializer__'] as $k) { if (\array_key_exists($k, $a)) { @@ -40,10 +37,7 @@ public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested) + public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested): array { foreach (['_entityPersister', '_identifier'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { @@ -55,10 +49,7 @@ public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested) + public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested): array { foreach (['snapshot', 'association', 'typeClass'] as $k) { if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { diff --git a/app/vendor/symfony/var-dumper/Caster/DsPairStub.php b/app/vendor/symfony/var-dumper/Caster/DsPairStub.php index 22112af9c..afa2727b1 100644 --- a/app/vendor/symfony/var-dumper/Caster/DsPairStub.php +++ b/app/vendor/symfony/var-dumper/Caster/DsPairStub.php @@ -18,7 +18,7 @@ */ class DsPairStub extends Stub { - public function __construct(string|int $key, mixed $value) + public function __construct(mixed $key, mixed $value) { $this->value = [ Caster::PREFIX_VIRTUAL.'key' => $key, diff --git a/app/vendor/symfony/var-dumper/Caster/EnumStub.php b/app/vendor/symfony/var-dumper/Caster/EnumStub.php index 7a4e98a21..02ed1745e 100644 --- a/app/vendor/symfony/var-dumper/Caster/EnumStub.php +++ b/app/vendor/symfony/var-dumper/Caster/EnumStub.php @@ -20,7 +20,7 @@ */ class EnumStub extends Stub { - public $dumpKeys = true; + public bool $dumpKeys = true; public function __construct(array $values, bool $dumpKeys = true) { diff --git a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php index 02efb1b02..ec2afb431 100644 --- a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php @@ -47,26 +47,17 @@ class ExceptionCaster private static array $framesCache = []; - /** - * @return array - */ - public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0): array { return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); } - /** - * @return array - */ - public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0): array { return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); } - /** - * @return array - */ - public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested) + public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested): array { if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); @@ -75,10 +66,7 @@ public static function castErrorException(\ErrorException $e, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested) + public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested): array { $trace = Caster::PREFIX_VIRTUAL.'trace'; $prefix = Caster::PREFIX_PROTECTED; @@ -96,10 +84,7 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a return $a; } - /** - * @return array - */ - public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested) + public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested): array { $sPrefix = "\0".SilencedErrorContext::class."\0"; @@ -126,10 +111,7 @@ public static function castSilencedErrorContext(SilencedErrorContext $e, array $ return $a; } - /** - * @return array - */ - public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested) + public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -203,10 +185,7 @@ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested) + public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -235,7 +214,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo $ellipsis = $ellipsis->attr['ellipsis'] ?? 0; if (is_file($f['file']) && 0 <= self::$srcContext) { - if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) { + if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig\Template')) { $template = null; if (isset($f['object'])) { $template = $f['object']; @@ -289,10 +268,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo return $a; } - /** - * @return array - */ - public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested) + public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $k = sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); diff --git a/app/vendor/symfony/var-dumper/Caster/FFICaster.php b/app/vendor/symfony/var-dumper/Caster/FFICaster.php index 7d90e7b57..f1984eef3 100644 --- a/app/vendor/symfony/var-dumper/Caster/FFICaster.php +++ b/app/vendor/symfony/var-dumper/Caster/FFICaster.php @@ -97,7 +97,7 @@ private static function castFFIFunction(Stub $stub, CType $type): array return [Caster::PREFIX_VIRTUAL.'returnType' => $returnType]; } - private static function castFFIPointer(Stub $stub, CType $type, CData $data = null): array + private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = null): array { $ptr = $type->getPointerType(); @@ -132,7 +132,7 @@ private static function castFFIStringValue(CData $data): string|CutStub return $stub; } - private static function castFFIStructLike(CType $type, CData $data = null): array + private static function castFFIStructLike(CType $type, ?CData $data = null): array { $isUnion = ($type->getAttributes() & CType::ATTR_UNION) === CType::ATTR_UNION; diff --git a/app/vendor/symfony/var-dumper/Caster/FiberCaster.php b/app/vendor/symfony/var-dumper/Caster/FiberCaster.php index b797dbd63..c9df7087a 100644 --- a/app/vendor/symfony/var-dumper/Caster/FiberCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/FiberCaster.php @@ -20,10 +20,7 @@ */ final class FiberCaster { - /** - * @return array - */ - public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/FrameStub.php b/app/vendor/symfony/var-dumper/Caster/FrameStub.php index 878675528..9968c1101 100644 --- a/app/vendor/symfony/var-dumper/Caster/FrameStub.php +++ b/app/vendor/symfony/var-dumper/Caster/FrameStub.php @@ -18,8 +18,8 @@ */ class FrameStub extends EnumStub { - public $keepArgs; - public $inTraceStub; + public bool $keepArgs; + public bool $inTraceStub; public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) { diff --git a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php index a4590f4b5..f386c7215 100644 --- a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php @@ -21,10 +21,7 @@ */ class IntlCaster { - /** - * @return array - */ - public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested) + public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), @@ -34,10 +31,7 @@ public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub return self::castError($c, $a); } - /** - * @return array - */ - public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), @@ -114,10 +108,7 @@ public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $ return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested) + public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(), @@ -134,10 +125,7 @@ public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'type' => $c->getType(), @@ -154,10 +142,7 @@ public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, return self::castError($c, $a); } - /** - * @return array - */ - public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $a += [ Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), diff --git a/app/vendor/symfony/var-dumper/Caster/LinkStub.php b/app/vendor/symfony/var-dumper/Caster/LinkStub.php index df95f8b0e..3acd4fd67 100644 --- a/app/vendor/symfony/var-dumper/Caster/LinkStub.php +++ b/app/vendor/symfony/var-dumper/Caster/LinkStub.php @@ -18,12 +18,12 @@ */ class LinkStub extends ConstStub { - public $inVendor = false; + public bool $inVendor = false; private static array $vendorRoots; private static array $composerRoots = []; - public function __construct(string $label, int $line = 0, string $href = null) + public function __construct(string $label, int $line = 0, ?string $href = null) { $this->value = $label; diff --git a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php index 2f161e8cb..740785cea 100644 --- a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php @@ -23,10 +23,7 @@ class MemcachedCaster private static array $optionConstants; private static array $defaultOptions; - /** - * @return array - */ - public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested) + public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(), diff --git a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php index d68eae216..1d364cdf0 100644 --- a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php @@ -59,10 +59,7 @@ class PdoCaster ], ]; - /** - * @return array - */ - public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) + public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested): array { $attr = []; $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE); @@ -111,10 +108,7 @@ public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested) + public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $a[$prefix.'errorInfo'] = $c->errorInfo(); diff --git a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php index 0d8b3d919..7e7450086 100644 --- a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php @@ -69,20 +69,14 @@ class PgSqlCaster 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, ]; - /** - * @return array - */ - public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested) + public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested): array { $a['seek position'] = pg_lo_tell($lo); return $a; } - /** - * @return array - */ - public static function castLink($link, array $a, Stub $stub, bool $isNested) + public static function castLink($link, array $a, Stub $stub, bool $isNested): array { $a['status'] = pg_connection_status($link); $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']); @@ -114,10 +108,7 @@ public static function castLink($link, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castResult($result, array $a, Stub $stub, bool $isNested) + public static function castResult($result, array $a, Stub $stub, bool $isNested): array { $a['num rows'] = pg_num_rows($result); $a['status'] = pg_result_status($result); diff --git a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php index eb6c88db6..736a6e758 100644 --- a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php @@ -21,10 +21,7 @@ */ class ProxyManagerCaster { - /** - * @return array - */ - public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested) + public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested): array { if ($parent = get_parent_class($c)) { $stub->class .= ' - '.$parent; diff --git a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php index fcaa1b768..5445b2d4b 100644 --- a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php @@ -31,10 +31,7 @@ */ class RdKafkaCaster { - /** - * @return array - */ - public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested) + public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -54,10 +51,7 @@ public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) + public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -68,10 +62,7 @@ public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castTopicPartition(TopicPartition $c, array $a) + public static function castTopicPartition(TopicPartition $c, array $a): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -84,10 +75,7 @@ public static function castTopicPartition(TopicPartition $c, array $a) return $a; } - /** - * @return array - */ - public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested) + public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -98,10 +86,7 @@ public static function castMessage(Message $c, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) + public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -112,10 +97,7 @@ public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested) + public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -126,10 +108,7 @@ public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $i return $a; } - /** - * @return array - */ - public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested) + public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -142,20 +121,14 @@ public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested): array { $a += iterator_to_array($c); return $a; } - /** - * @return array - */ - public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -167,10 +140,7 @@ public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, return $a; } - /** - * @return array - */ - public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -183,10 +153,7 @@ public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stu return $a; } - /** - * @return array - */ - public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested) + public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -199,10 +166,7 @@ public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stu return $a; } - /** - * @return array - */ - private static function extractMetadata(KafkaConsumer|\RdKafka $c) + private static function extractMetadata(KafkaConsumer|\RdKafka $c): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php index 6ff046754..5224bc05d 100644 --- a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -47,10 +47,7 @@ class RedisCaster \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', ]; - /** - * @return array - */ - public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested) + public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -76,10 +73,7 @@ public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $is ]; } - /** - * @return array - */ - public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested) + public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -91,10 +85,7 @@ public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool ]; } - /** - * @return array - */ - public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested) + public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER); diff --git a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php index 4adb9bc9f..f42d06cb6 100644 --- a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php @@ -35,10 +35,7 @@ class ReflectionCaster 'isVariadic' => 'isVariadic', ]; - /** - * @return array - */ - public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; $c = new \ReflectionFunction($c); @@ -74,10 +71,7 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNe return $a; } - /** - * @return array - */ - public static function unsetClosureFileInfo(\Closure $c, array $a) + public static function unsetClosureFileInfo(\Closure $c, array $a): array { unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); @@ -98,10 +92,7 @@ public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $ return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) + public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -123,10 +114,7 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $ return $a; } - /** - * @return array - */ - public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested) + public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested): array { self::addMap($a, $c, [ 'name' => 'getName', @@ -136,10 +124,7 @@ public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested) + public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -174,10 +159,7 @@ public static function castReflectionGenerator(\ReflectionGenerator $c, array $a return $a; } - /** - * @return array - */ - public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -208,17 +190,14 @@ public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0): array { $prefix = Caster::PREFIX_VIRTUAL; self::addMap($a, $c, [ 'returnsReference' => 'returnsReference', 'returnType' => 'getReturnType', - 'class' => \PHP_VERSION_ID >= 80111 ? 'getClosureCalledClass' : 'getClosureScopeClass', + 'class' => 'getClosureCalledClass', 'this' => 'getClosureThis', ]); @@ -269,10 +248,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra return $a; } - /** - * @return array - */ - public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested) + public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); $a[Caster::PREFIX_VIRTUAL.'value'] = $c->getValue(); @@ -282,20 +258,14 @@ public static function castClassConstant(\ReflectionClassConstant $c, array $a, return $a; } - /** - * @return array - */ - public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested) + public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); return $a; } - /** - * @return array - */ - public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested) + public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; @@ -335,10 +305,7 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested) + public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); @@ -348,20 +315,14 @@ public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub return $a; } - /** - * @return array - */ - public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested) + public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); return $a; } - /** - * @return array - */ - public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested) + public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested): array { self::addMap($a, $c, [ 'version' => 'getVersion', @@ -377,10 +338,7 @@ public static function castExtension(\ReflectionExtension $c, array $a, Stub $st return $a; } - /** - * @return array - */ - public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested) + public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested): array { self::addMap($a, $c, [ 'version' => 'getVersion', @@ -392,10 +350,7 @@ public static function castZendExtension(\ReflectionZendExtension $c, array $a, return $a; } - /** - * @return string - */ - public static function getSignature(array $a) + public static function getSignature(array $a): string { $prefix = Caster::PREFIX_VIRTUAL; $signature = ''; diff --git a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php index f3bbf3be4..f775f81ca 100644 --- a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php @@ -27,10 +27,7 @@ public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNe return curl_getinfo($h); } - /** - * @return array - */ - public static function castDba($dba, array $a, Stub $stub, bool $isNested) + public static function castDba($dba, array $a, Stub $stub, bool $isNested): array { $list = dba_list(); $a['file'] = $list[(int) $dba]; @@ -38,10 +35,7 @@ public static function castDba($dba, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castProcess($process, array $a, Stub $stub, bool $isNested) + public static function castProcess($process, array $a, Stub $stub, bool $isNested): array { return proc_get_status($process); } @@ -56,18 +50,12 @@ public static function castStream($stream, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested) + public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested): array { return @stream_context_get_params($stream) ?: $a; } - /** - * @return array - */ - public static function castGd($gd, array $a, Stub $stub, bool $isNested) + public static function castGd($gd, array $a, Stub $stub, bool $isNested): array { $a['size'] = imagesx($gd).'x'.imagesy($gd); $a['trueColor'] = imageistruecolor($gd); @@ -75,10 +63,7 @@ public static function castGd($gd, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested) + public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested): array { $stub->cut = -1; $info = openssl_x509_parse($h, false); diff --git a/app/vendor/symfony/var-dumper/Caster/SplCaster.php b/app/vendor/symfony/var-dumper/Caster/SplCaster.php index 814d824d1..c6953646b 100644 --- a/app/vendor/symfony/var-dumper/Caster/SplCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SplCaster.php @@ -29,26 +29,17 @@ class SplCaster \SplFileObject::READ_CSV => 'READ_CSV', ]; - /** - * @return array - */ - public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested) + public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested): array { return self::castSplArray($c, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested) + public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested): array { return self::castSplArray($c, $a, $stub, $isNested); } - /** - * @return array - */ - public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested) + public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), @@ -57,10 +48,7 @@ public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNest return $a; } - /** - * @return array - */ - public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested) + public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; $mode = $c->getIteratorMode(); @@ -75,10 +63,7 @@ public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, S return $a; } - /** - * @return array - */ - public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested) + public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested): array { static $map = [ 'path' => 'getPath', @@ -154,10 +139,7 @@ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested) + public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested): array { static $map = [ 'csvControl' => 'getCsvControl', @@ -194,10 +176,7 @@ public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, b return $a; } - /** - * @return array - */ - public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested) + public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested): array { $storage = []; unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 @@ -218,30 +197,21 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s return $a; } - /** - * @return array - */ - public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested) + public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); return $a; } - /** - * @return array - */ - public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested) + public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); return $a; } - /** - * @return array - */ - public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested) + public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested): array { $map = []; diff --git a/app/vendor/symfony/var-dumper/Caster/StubCaster.php b/app/vendor/symfony/var-dumper/Caster/StubCaster.php index 4b93ff76f..56742b018 100644 --- a/app/vendor/symfony/var-dumper/Caster/StubCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/StubCaster.php @@ -22,10 +22,7 @@ */ class StubCaster { - /** - * @return array - */ - public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) + public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->type = $c->type; @@ -46,18 +43,12 @@ public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested) + public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested): array { return $isNested ? $c->preservedSubset : $a; } - /** - * @return array - */ - public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) + public static function cutInternals($obj, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->cut += \count($a); @@ -68,10 +59,7 @@ public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) return $a; } - /** - * @return array - */ - public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested) + public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested): array { if ($isNested) { $stub->class = $c->dumpKeys ? '' : null; @@ -94,10 +82,7 @@ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNeste return $a; } - /** - * @return array - */ - public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub) + public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub): array { $stub->type = Stub::TYPE_SCALAR; $stub->attr['value'] = $scalarStub->value; diff --git a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php index ebc00f90e..5cd90f734 100644 --- a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php @@ -31,10 +31,7 @@ class SymfonyCaster 'format' => 'getRequestFormat', ]; - /** - * @return array - */ - public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested) + public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested): array { $clone = null; @@ -49,10 +46,7 @@ public static function castRequest(Request $request, array $a, Stub $stub, bool return $a; } - /** - * @return array - */ - public static function castHttpClient($client, array $a, Stub $stub, bool $isNested) + public static function castHttpClient($client, array $a, Stub $stub, bool $isNested): array { $multiKey = sprintf("\0%s\0multi", $client::class); if (isset($a[$multiKey])) { @@ -62,10 +56,7 @@ public static function castHttpClient($client, array $a, Stub $stub, bool $isNes return $a; } - /** - * @return array - */ - public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested) + public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested): array { $stub->cut += \count($a); $a = []; @@ -77,10 +68,7 @@ public static function castHttpClientResponse($response, array $a, Stub $stub, b return $a; } - /** - * @return array - */ - public static function castLazyObjectState($state, array $a, Stub $stub, bool $isNested) + public static function castLazyObjectState($state, array $a, Stub $stub, bool $isNested): array { if (!$isNested) { return $a; @@ -105,10 +93,7 @@ public static function castLazyObjectState($state, array $a, Stub $stub, bool $i return $a; } - /** - * @return array - */ - public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested) + public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $uuid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toBase32'] = $uuid->toBase32(); @@ -121,10 +106,7 @@ public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested return $a; } - /** - * @return array - */ - public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested) + public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested): array { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $ulid->toBase58(); $a[Caster::PREFIX_VIRTUAL.'toRfc4122'] = $ulid->toRfc4122(); diff --git a/app/vendor/symfony/var-dumper/Caster/TraceStub.php b/app/vendor/symfony/var-dumper/Caster/TraceStub.php index 5eea1c876..5766e5169 100644 --- a/app/vendor/symfony/var-dumper/Caster/TraceStub.php +++ b/app/vendor/symfony/var-dumper/Caster/TraceStub.php @@ -20,12 +20,12 @@ */ class TraceStub extends Stub { - public $keepArgs; - public $sliceOffset; - public $sliceLength; - public $numberingOffset; + public bool $keepArgs; + public int $sliceOffset; + public ?int $sliceLength; + public int $numberingOffset; - public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0) + public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, ?int $sliceLength = null, int $numberingOffset = 0) { $this->value = $trace; $this->keepArgs = $keepArgs; diff --git a/app/vendor/symfony/var-dumper/Caster/UninitializedStub.php b/app/vendor/symfony/var-dumper/Caster/UninitializedStub.php new file mode 100644 index 000000000..a9bdd9b81 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/UninitializedStub.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\VarDumper\Caster; + +/** + * Represents an uninitialized property. + * + * @author Nicolas Grekas + */ +class UninitializedStub extends ConstStub +{ + public function __construct(\ReflectionProperty $property) + { + parent::__construct('?'.($property->hasType() ? ' '.$property->getType() : ''), 'Uninitialized property'); + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php index d802bbf2a..672fec68f 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -43,10 +43,7 @@ class XmlReaderCaster \XMLReader::XML_DECLARATION => 'XML_DECLARATION', ]; - /** - * @return array - */ - public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested) + public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested): array { try { $properties = [ @@ -85,6 +82,7 @@ public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, b $info[$props]->cut = $count; } + $a = Caster::filter($a, Caster::EXCLUDE_UNINITIALIZED, [], $count); $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count); // +2 because hasValue and hasAttributes are always filtered $stub->cut += $count + 2; diff --git a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php index 0cf42584a..fd3d3a2ab 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php @@ -47,10 +47,7 @@ class XmlResourceCaster \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', ]; - /** - * @return array - */ - public static function castXml($h, array $a, Stub $stub, bool $isNested) + public static function castXml($h, array $a, Stub $stub, bool $isNested): array { $a['current_byte_index'] = xml_get_current_byte_index($h); $a['current_column_number'] = xml_get_current_column_number($h); diff --git a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php index 6a746b88e..e7cb39469 100644 --- a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php +++ b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php @@ -21,7 +21,7 @@ */ abstract class AbstractCloner implements ClonerInterface { - public static $defaultCasters = [ + public static array $defaultCasters = [ '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], @@ -197,9 +197,9 @@ abstract class AbstractCloner implements ClonerInterface 'FFI\CType' => ['Symfony\Component\VarDumper\Caster\FFICaster', 'castCTypeOrCData'], ]; - protected $maxItems = 2500; - protected $maxString = -1; - protected $minDepth = 1; + protected int $maxItems = 2500; + protected int $maxString = -1; + protected int $minDepth = 1; /** * @var array> @@ -219,7 +219,7 @@ abstract class AbstractCloner implements ClonerInterface * * @see addCasters */ - public function __construct(array $casters = null) + public function __construct(?array $casters = null) { $this->addCasters($casters ?? static::$defaultCasters); } @@ -233,10 +233,8 @@ public function __construct(array $casters = null) * see e.g. static::$defaultCasters. * * @param callable[] $casters A map of casters - * - * @return void */ - public function addCasters(array $casters) + public function addCasters(array $casters): void { foreach ($casters as $type => $callback) { $this->casters[$type][] = $callback; @@ -245,20 +243,16 @@ public function addCasters(array $casters) /** * Sets the maximum number of items to clone past the minimum depth in nested structures. - * - * @return void */ - public function setMaxItems(int $maxItems) + public function setMaxItems(int $maxItems): void { $this->maxItems = $maxItems; } /** * Sets the maximum cloned length for strings. - * - * @return void */ - public function setMaxString(int $maxString) + public function setMaxString(int $maxString): void { $this->maxString = $maxString; } @@ -266,10 +260,8 @@ public function setMaxString(int $maxString) /** * Sets the minimum tree depth where we are guaranteed to clone all the items. After this * depth is reached, only setMaxItems items will be cloned. - * - * @return void */ - public function setMinDepth(int $minDepth) + public function setMinDepth(int $minDepth): void { $this->minDepth = $minDepth; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Cursor.php b/app/vendor/symfony/var-dumper/Cloner/Cursor.php index 1fd796d67..8923007ff 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Cursor.php +++ b/app/vendor/symfony/var-dumper/Cloner/Cursor.php @@ -23,21 +23,21 @@ class Cursor public const HASH_OBJECT = Stub::TYPE_OBJECT; public const HASH_RESOURCE = Stub::TYPE_RESOURCE; - public $depth = 0; - public $refIndex = 0; - public $softRefTo = 0; - public $softRefCount = 0; - public $softRefHandle = 0; - public $hardRefTo = 0; - public $hardRefCount = 0; - public $hardRefHandle = 0; - public $hashType; - public $hashKey; - public $hashKeyIsBinary; - public $hashIndex = 0; - public $hashLength = 0; - public $hashCut = 0; - public $stop = false; - public $attr = []; - public $skipChildren = false; + public int $depth = 0; + public int $refIndex = 0; + public int $softRefTo = 0; + public int $softRefCount = 0; + public int $softRefHandle = 0; + public int $hardRefTo = 0; + public int $hardRefCount = 0; + public int $hardRefHandle = 0; + public int $hashType; + public string|int|null $hashKey = null; + public bool $hashKeyIsBinary; + public int $hashIndex = 0; + public int $hashLength = 0; + public int $hashCut = 0; + public bool $stop = false; + public array $attr = []; + public bool $skipChildren = false; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Data.php b/app/vendor/symfony/var-dumper/Cloner/Data.php index 928f72d7a..71e78a6b7 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Data.php +++ b/app/vendor/symfony/var-dumper/Cloner/Data.php @@ -17,7 +17,7 @@ /** * @author Nicolas Grekas */ -class Data implements \ArrayAccess, \Countable, \IteratorAggregate +class Data implements \ArrayAccess, \Countable, \IteratorAggregate, \Stringable { private array $data; private int $position = 0; @@ -121,7 +121,7 @@ public function getIterator(): \Traversable yield from $value; } - public function __get(string $key) + public function __get(string $key): mixed { if (null !== $data = $this->seek($key)) { $item = $this->getStub($data->data[$data->position][$data->key]); @@ -262,10 +262,8 @@ public function seek(string|int $key): ?static /** * Dumps data with a DumperInterface dumper. - * - * @return void */ - public function dump(DumperInterface $dumper) + public function dump(DumperInterface $dumper): void { $refs = [0]; $cursor = new Cursor(); diff --git a/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php b/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php index 4c5b315b6..10f2da08a 100644 --- a/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php +++ b/app/vendor/symfony/var-dumper/Cloner/DumperInterface.php @@ -20,10 +20,8 @@ interface DumperInterface { /** * Dumps a scalar value. - * - * @return void */ - public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value); + public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value): void; /** * Dumps a string. @@ -31,10 +29,8 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n * @param string $str The string being dumped * @param bool $bin Whether $str is UTF-8 or binary encoded * @param int $cut The number of characters $str has been cut by - * - * @return void */ - public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): void; /** * Dumps while entering an hash. @@ -42,10 +38,8 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); * @param int $type A Cursor::HASH_* const for the type of hash * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item - * - * @return void */ - public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild); + public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild): void; /** * Dumps while leaving an hash. @@ -54,8 +48,6 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by - * - * @return void */ - public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut); + public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut): void; } diff --git a/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.php b/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.php new file mode 100644 index 000000000..ed9db9884 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Cloner/Internal/NoDefault.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\VarDumper\Cloner\Internal; + +/** + * Flags a typed property that has no default value. + * + * This dummy object is used to distinguish a property with a default value of null + * from a property that is uninitialized by default. + * + * @internal + */ +enum NoDefault +{ + case NoDefault; +} diff --git a/app/vendor/symfony/var-dumper/Cloner/Stub.php b/app/vendor/symfony/var-dumper/Cloner/Stub.php index 0c2a4b9d0..4070b981d 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Stub.php +++ b/app/vendor/symfony/var-dumper/Cloner/Stub.php @@ -11,6 +11,8 @@ namespace Symfony\Component\VarDumper\Cloner; +use Symfony\Component\VarDumper\Cloner\Internal\NoDefault; + /** * Represents the main properties of a PHP variable. * @@ -31,14 +33,14 @@ class Stub public const ARRAY_ASSOC = 1; public const ARRAY_INDEXED = 2; - public $type = self::TYPE_REF; - public $class = ''; - public $value; - public $cut = 0; - public $handle = 0; - public $refCount = 0; - public $position = 0; - public $attr = []; + public int $type = self::TYPE_REF; + public string|int|null $class = ''; + public mixed $value; + public int $cut = 0; + public int $handle = 0; + public int $refCount = 0; + public int $position = 0; + public array $attr = []; private static array $defaultProperties = []; @@ -50,15 +52,20 @@ public function __sleep(): array $properties = []; if (!isset(self::$defaultProperties[$c = static::class])) { - self::$defaultProperties[$c] = get_class_vars($c); + $reflection = new \ReflectionClass($c); + self::$defaultProperties[$c] = []; + + foreach ($reflection->getProperties() as $p) { + if ($p->isStatic()) { + continue; + } - foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { - unset(self::$defaultProperties[$c][$k]); + self::$defaultProperties[$c][$p->name] = $p->hasDefaultValue() ? $p->getDefaultValue() : ($p->hasType() ? NoDefault::NoDefault : null); } } foreach (self::$defaultProperties[$c] as $k => $v) { - if ($this->$k !== $v) { + if (NoDefault::NoDefault === $v || $this->$k !== $v) { $properties[] = $k; } } diff --git a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php index 053a90972..ce57b36d3 100644 --- a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php @@ -26,14 +26,17 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface public const DUMP_COMMA_SEPARATOR = 4; public const DUMP_TRAILING_COMMA = 8; + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://output'; - protected $line = ''; + protected string $line = ''; + /** @var callable|null */ protected $lineDumper; + /** @var resource|null */ protected $outputStream; - protected $decimalPoint = '.'; - protected $indentPad = ' '; - protected $flags; + protected string $decimalPoint = '.'; + protected string $indentPad = ' '; + protected int $flags; private string $charset = ''; @@ -42,7 +45,7 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface * @param string|null $charset The default character encoding to use for non-UTF8 strings * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation */ - public function __construct($output = null, string $charset = null, int $flags = 0) + public function __construct($output = null, ?string $charset = null, int $flags = 0) { $this->flags = $flags; $this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'); @@ -55,9 +58,9 @@ public function __construct($output = null, string $charset = null, int $flags = /** * Sets the output destination of the dumps. * - * @param callable|resource|string $output A line dumper callable, an opened stream or an output path + * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path * - * @return callable|resource|string The previous output destination + * @return callable|resource|string|null The previous output destination */ public function setOutput($output) { @@ -155,10 +158,8 @@ public function dump(Data $data, $output = null): ?string * * @param int $depth The recursive depth in the dumped structure for the line being dumped, * or -1 to signal the end-of-dump to the line dumper callable - * - * @return void */ - protected function dumpLine(int $depth) + protected function dumpLine(int $depth): void { ($this->lineDumper)($this->line, $depth, $this->indentPad); $this->line = ''; @@ -166,10 +167,8 @@ protected function dumpLine(int $depth) /** * Generic line dumper callback. - * - * @return void */ - protected function echoLine(string $line, int $depth, string $indentPad) + protected function echoLine(string $line, int $depth, string $indentPad): void { if (-1 !== $depth) { fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); diff --git a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php index c155d4c79..76d295dc5 100644 --- a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Dumper; +use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter; use Symfony\Component\VarDumper\Cloner\Cursor; use Symfony\Component\VarDumper\Cloner\Stub; @@ -21,12 +22,13 @@ */ class CliDumper extends AbstractDumper { - public static $defaultColors; + public static bool $defaultColors; + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://stdout'; - protected $colors; - protected $maxStringWidth = 0; - protected $styles = [ + protected bool $colors; + protected int $maxStringWidth = 0; + protected array $styles = [ // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 'default' => '0;38;5;208', 'num' => '1;38;5;38', @@ -42,8 +44,8 @@ class CliDumper extends AbstractDumper 'index' => '38;5;38', ]; - protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/'; - protected static $controlCharsMap = [ + protected static string $controlCharsRx = '/[\x00-\x1F\x7F]+/'; + protected static array $controlCharsMap = [ "\t" => '\t', "\n" => '\n', "\v" => '\v', @@ -51,10 +53,10 @@ class CliDumper extends AbstractDumper "\r" => '\r', "\033" => '\e', ]; - protected static $unicodeCharsRx = "/[\u{00A0}\u{00AD}\u{034F}\u{061C}\u{115F}\u{1160}\u{17B4}\u{17B5}\u{180E}\u{2000}-\u{200F}\u{202F}\u{205F}\u{2060}-\u{2064}\u{206A}-\u{206F}\u{3000}\u{2800}\u{3164}\u{FEFF}\u{FFA0}\u{1D159}\u{1D173}-\u{1D17A}]/u"; + protected static string $unicodeCharsRx = "/[\u{00A0}\u{00AD}\u{034F}\u{061C}\u{115F}\u{1160}\u{17B4}\u{17B5}\u{180E}\u{2000}-\u{200F}\u{202F}\u{205F}\u{2060}-\u{2064}\u{206A}-\u{206F}\u{3000}\u{2800}\u{3164}\u{FEFF}\u{FFA0}\u{1D159}\u{1D173}-\u{1D17A}]/u"; - protected $collapseNextHash = false; - protected $expandNextHash = false; + protected bool $collapseNextHash = false; + protected bool $expandNextHash = false; private array $displayOptions = [ 'fileLinkFormat' => null, @@ -62,7 +64,7 @@ class CliDumper extends AbstractDumper private bool $handlesHrefGracefully; - public function __construct($output = null, string $charset = null, int $flags = 0) + public function __construct($output = null, ?string $charset = null, int $flags = 0) { parent::__construct($output, $charset, $flags); @@ -81,25 +83,21 @@ public function __construct($output = null, string $charset = null, int $flags = ]); } - $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; + $this->displayOptions['fileLinkFormat'] = class_exists(FileLinkFormatter::class) ? new FileLinkFormatter() : (\ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'); } /** * Enables/disables colored output. - * - * @return void */ - public function setColors(bool $colors) + public function setColors(bool $colors): void { $this->colors = $colors; } /** * Sets the maximum number of characters per line for dumped strings. - * - * @return void */ - public function setMaxStringWidth(int $maxStringWidth) + public function setMaxStringWidth(int $maxStringWidth): void { $this->maxStringWidth = $maxStringWidth; } @@ -108,10 +106,8 @@ public function setMaxStringWidth(int $maxStringWidth) * Configures styles. * * @param array $styles A map of style names to style definitions - * - * @return void */ - public function setStyles(array $styles) + public function setStyles(array $styles): void { $this->styles = $styles + $this->styles; } @@ -120,20 +116,16 @@ public function setStyles(array $styles) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior - * - * @return void */ - public function setDisplayOptions(array $displayOptions) + public function setDisplayOptions(array $displayOptions): void { $this->displayOptions = $displayOptions + $this->displayOptions; } - /** - * @return void - */ - public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value) + public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value): void { $this->dumpKey($cursor); + $this->collapseNextHash = $this->expandNextHash = false; $style = 'const'; $attr = $cursor->attr; @@ -191,12 +183,10 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n $this->endValue($cursor); } - /** - * @return void - */ - public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): void { $this->dumpKey($cursor); + $this->collapseNextHash = $this->expandNextHash = false; $attr = $cursor->attr; if ($bin) { @@ -282,14 +272,12 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) } } - /** - * @return void - */ - public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild) + public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild): void { $this->colors ??= $this->supportsColors(); $this->dumpKey($cursor); + $this->expandNextHash = false; $attr = $cursor->attr; if ($this->collapseNextHash) { @@ -321,10 +309,7 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo } } - /** - * @return void - */ - public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut) + public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut): void { if (empty($cursor->attr['cut_hash'])) { $this->dumpEllipsis($cursor, $hasChild, $cut); @@ -339,10 +324,8 @@ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, boo * * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by - * - * @return void */ - protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) + protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut): void { if ($cut) { $this->line .= ' …'; @@ -357,10 +340,8 @@ protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) /** * Dumps a key in a hash structure. - * - * @return void */ - protected function dumpKey(Cursor $cursor) + protected function dumpKey(Cursor $cursor): void { if (null !== $key = $cursor->hashKey) { if ($cursor->hashKeyIsBinary) { @@ -534,7 +515,7 @@ protected function supportsColors(): bool if ($this->outputStream !== static::$defaultOutput) { return $this->hasColorSupport($this->outputStream); } - if (null !== static::$defaultColors) { + if (isset(static::$defaultColors)) { return static::$defaultColors; } if (isset($_SERVER['argv'][1])) { @@ -568,21 +549,15 @@ protected function supportsColors(): bool return static::$defaultColors = $this->hasColorSupport($h); } - /** - * @return void - */ - protected function dumpLine(int $depth, bool $endOfValue = false) + protected function dumpLine(int $depth, bool $endOfValue = false): void { - if ($this->colors) { + if ($this->colors ??= $this->supportsColors()) { $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); } parent::dumpLine($depth); } - /** - * @return void - */ - protected function endValue(Cursor $cursor) + protected function endValue(Cursor $cursor): void { if (-1 === $cursor->hashType) { return; @@ -616,19 +591,30 @@ private function hasColorSupport(mixed $stream): bool return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@stream_isatty($stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($stream)) { + return true; + } + + if ('Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('COLORTERM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + ) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); + if ('dumb' === $term = (string) getenv('TERM')) { + return false; } - return stream_isatty($stream); + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); } /** diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php index 790285c97..9477e5312 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php @@ -11,7 +11,7 @@ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; -use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\VarDumper; @@ -30,7 +30,7 @@ final class SourceContextProvider implements ContextProviderInterface private ?string $projectDir; private ?FileLinkFormatter $fileLinkFormatter; - public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) + public function __construct(?string $charset = null, ?string $projectDir = null, ?FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) { $this->charset = $charset; $this->projectDir = $projectDir; diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php index 84cfb4259..6de34d97b 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php @@ -31,10 +31,7 @@ public function __construct(DataDumperInterface $wrappedDumper, array $contextPr $this->contextProviders = $contextProviders; } - /** - * @return string|null - */ - public function dump(Data $data) + public function dump(Data $data): ?string { $context = $data->getContext(); foreach ($this->contextProviders as $contextProvider) { diff --git a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php index 8a2570b2c..74468fff1 100644 --- a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php @@ -21,6 +21,7 @@ */ class HtmlDumper extends CliDumper { + /** @var callable|resource|string|null */ public static $defaultOutput = 'php://output'; protected static $themes = [ @@ -58,14 +59,13 @@ class HtmlDumper extends CliDumper ], ]; - protected $dumpHeader; - protected $dumpPrefix = '
';
-    protected $dumpSuffix = '
'; - protected $dumpId = 'sf-dump'; - protected $colors = true; + protected ?string $dumpHeader = null; + protected string $dumpPrefix = '
';
+    protected string $dumpSuffix = '
'; + protected string $dumpId; + protected bool $colors = true; protected $headerIsDumped = false; - protected $lastDepth = -1; - protected $styles; + protected int $lastDepth = -1; private array $displayOptions = [ 'maxDepth' => 1, @@ -74,7 +74,7 @@ class HtmlDumper extends CliDumper ]; private array $extraDisplayOptions = []; - public function __construct($output = null, string $charset = null, int $flags = 0) + public function __construct($output = null, ?string $charset = null, int $flags = 0) { AbstractDumper::__construct($output, $charset, $flags); $this->dumpId = 'sf-dump-'.mt_rand(); @@ -82,19 +82,13 @@ public function __construct($output = null, string $charset = null, int $flags = $this->styles = static::$themes['dark'] ?? self::$themes['dark']; } - /** - * @return void - */ - public function setStyles(array $styles) + public function setStyles(array $styles): void { $this->headerIsDumped = false; $this->styles = $styles + $this->styles; } - /** - * @return void - */ - public function setTheme(string $themeName) + public function setTheme(string $themeName): void { if (!isset(static::$themes[$themeName])) { throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); @@ -107,10 +101,8 @@ public function setTheme(string $themeName) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior - * - * @return void */ - public function setDisplayOptions(array $displayOptions) + public function setDisplayOptions(array $displayOptions): void { $this->headerIsDumped = false; $this->displayOptions = $displayOptions + $this->displayOptions; @@ -118,20 +110,16 @@ public function setDisplayOptions(array $displayOptions) /** * Sets an HTML header that will be dumped once in the output stream. - * - * @return void */ - public function setDumpHeader(?string $header) + public function setDumpHeader(?string $header): void { $this->dumpHeader = $header; } /** * Sets an HTML prefix and suffix that will encapse every single dump. - * - * @return void */ - public function setDumpBoundaries(string $prefix, string $suffix) + public function setDumpBoundaries(string $prefix, string $suffix): void { $this->dumpPrefix = $prefix; $this->dumpSuffix = $suffix; @@ -148,10 +136,8 @@ public function dump(Data $data, $output = null, array $extraDisplayOptions = [] /** * Dumps the HTML header. - * - * @return string */ - protected function getDumpHeader() + protected function getDumpHeader(): string { $this->headerIsDumped = $this->outputStream ?? $this->lineDumper; @@ -162,7 +148,6 @@ protected function getDumpHeader() $line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML'