diff --git a/composer.json b/composer.json index dff5a079..2f9143db 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ }, "require": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "laminas/laminas-servicemanager": "^3.21.0", + "laminas/laminas-servicemanager": "^4.1.0", "laminas/laminas-stdlib": "^3.13", "laminas/laminas-translator": "^1.0", "psr/http-message": "^1.0.1 || ^2.0.0" diff --git a/composer.lock b/composer.lock index 230c5cba..75591c53 100644 --- a/composer.lock +++ b/composer.lock @@ -4,63 +4,111 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f60ed8d25850730dee1fed5ebbac79cf", + "content-hash": "dd63fffe59f6f41b7e195b18b10dc733", "packages": [ + { + "name": "brick/varexporter", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/brick/varexporter.git", + "reference": "2fd038f7c9d12d468130c6e1b3ce06e4160a7dbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/varexporter/zipball/2fd038f7c9d12d468130c6e1b3ce06e4160a7dbb", + "reference": "2fd038f7c9d12d468130c6e1b3ce06e4160a7dbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^8.5 || ^9.0", + "vimeo/psalm": "5.15.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\VarExporter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A powerful alternative to var_export(), which can export closures and objects without __set_state()", + "keywords": [ + "var_export" + ], + "support": { + "issues": "https://github.com/brick/varexporter/issues", + "source": "https://github.com/brick/varexporter/tree/0.4.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2023-09-01T21:10:07+00:00" + }, { "name": "laminas/laminas-servicemanager", - "version": "3.22.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "de98d297d4743956a0558a6d71616979ff779328" + "reference": "ae01570ecdf4559aef2f15d4e79e8c36874f7416" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/de98d297d4743956a0558a6d71616979ff779328", - "reference": "de98d297d4743956a0558a6d71616979ff779328", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/ae01570ecdf4559aef2f15d4e79e8c36874f7416", + "reference": "ae01570ecdf4559aef2f15d4e79e8c36874f7416", "shasum": "" }, "require": { + "brick/varexporter": "^0.3.8 || ^0.4.0", "laminas/laminas-stdlib": "^3.17", "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "psr/container": "^1.0" + "psr/container": "^1.1 || ^2.0" }, "conflict": { - "ext-psr": "*", "laminas/laminas-code": "<4.10.0", - "zendframework/zend-code": "<3.3.1", - "zendframework/zend-servicemanager": "*" + "zendframework/zend-code": "<3.3.1" }, "provide": { - "psr/container-implementation": "^1.0" - }, - "replace": { - "container-interop/container-interop": "^1.2.0" + "psr/container-implementation": "^1.0 || ^2.0" }, "require-dev": { + "boesing/psalm-plugin-stringf": "^1.4", "composer/package-versions-deprecated": "^1.11.99.5", - "friendsofphp/proxy-manager-lts": "^1.0.14", - "laminas/laminas-code": "^4.10.0", + "friendsofphp/proxy-manager-lts": "^1", + "laminas/laminas-cli": "^1.8", "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-container-config-test": "^0.8", - "mikey179/vfsstream": "^1.6.11", - "phpbench/phpbench": "^1.2.9", + "laminas/laminas-container-config-test": "^1.0", + "lctrs/psalm-psr-container-plugin": "^1.9", + "mikey179/vfsstream": "^1.6.11@alpha", + "phpbench/phpbench": "^1.2.7", "phpunit/phpunit": "^10.4", "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.8.0" + "symfony/console": "^6.0", + "vimeo/psalm": "^5.22" }, "suggest": { - "friendsofphp/proxy-manager-lts": "ProxyManager ^2.1.1 to handle lazy initialization of services" + "friendsofphp/proxy-manager-lts": "To handle lazy initialization of services", + "laminas/laminas-cli": "To consume CLI commands provided by this component" }, - "bin": [ - "bin/generate-deps-for-config-factory", - "bin/generate-factory-for-class" - ], "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\ServiceManager\\ConfigProvider", + "module": "Laminas\\ServiceManager" + } + }, "autoload": { - "files": [ - "src/autoload.php" - ], "psr-4": { "Laminas\\ServiceManager\\": "src/" } @@ -82,11 +130,9 @@ ], "support": { "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-servicemanager/", "forum": "https://discourse.laminas.dev", "issues": "https://github.com/laminas/laminas-servicemanager/issues", - "rss": "https://github.com/laminas/laminas-servicemanager/releases.atom", - "source": "https://github.com/laminas/laminas-servicemanager" + "source": "https://github.com/laminas/laminas-servicemanager/tree/4.1.0" }, "funding": [ { @@ -94,7 +140,7 @@ "type": "community_bridge" } ], - "time": "2023-10-24T11:19:47+00:00" + "time": "2024-04-03T20:39:36+00:00" }, { "name": "laminas/laminas-stdlib", @@ -208,24 +254,85 @@ ], "time": "2024-06-18T15:09:24+00:00" }, + { + "name": "nikic/php-parser", + "version": "v4.19.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + }, + "time": "2024-03-17T08:10:35+00:00" + }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -252,9 +359,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "psr/http-message", @@ -1203,62 +1310,6 @@ }, "time": "2024-01-31T06:18:54+00:00" }, - { - "name": "nikic/php-parser", - "version": "v4.19.1", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.1" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" - }, - "time": "2024-03-17T08:10:35+00:00" - }, { "name": "phar-io/manifest", "version": "2.0.4", diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 7387df1c..0891e691 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -254,13 +254,11 @@ - - getPluginManager()->build($name, $options)]]> - + getPluginManager()->build($name, $options)]]> getPluginManager()->build($name, $options)]]> getPluginManager()->get($validator)]]> getPluginManager()->get($validator)]]> @@ -1128,28 +1126,18 @@ - - + + - - - - - - get('MvcTranslator')]]> - - - - - - - - - getServiceLocator()]]> - + + + + + + @@ -1157,18 +1145,9 @@ - - - - - - - - - @@ -1787,4 +1766,9 @@ + + + + + diff --git a/src/ValidatorChain.php b/src/ValidatorChain.php index b347182f..95673b72 100644 --- a/src/ValidatorChain.php +++ b/src/ValidatorChain.php @@ -105,7 +105,7 @@ public function setPluginManager(ValidatorPluginManager $plugins) public function plugin($name, ?array $options = null) { $plugins = $this->getPluginManager(); - return $plugins->get($name, $options); + return $plugins->build($name, $options); } /** diff --git a/src/ValidatorPluginManager.php b/src/ValidatorPluginManager.php index 2689f37f..16909e94 100644 --- a/src/ValidatorPluginManager.php +++ b/src/ValidatorPluginManager.php @@ -4,337 +4,250 @@ namespace Laminas\Validator; -use Laminas\ServiceManager\AbstractPluginManager; -use Laminas\ServiceManager\Exception\InvalidServiceException; +use Closure; +use Laminas\ServiceManager\AbstractSingleInstancePluginManager; use Laminas\ServiceManager\Factory\InvokableFactory; use Laminas\ServiceManager\ServiceManager; use Laminas\Translator\TranslatorInterface; use Psr\Container\ContainerInterface; -use function get_debug_type; -use function method_exists; -use function sprintf; +use function array_replace_recursive; +use function assert; /** * @psalm-import-type ServiceManagerConfiguration from ServiceManager - * @extends AbstractPluginManager + * @extends AbstractSingleInstancePluginManager */ -final class ValidatorPluginManager extends AbstractPluginManager +final class ValidatorPluginManager extends AbstractSingleInstancePluginManager { - /** - * Default set of aliases - * - * @inheritDoc - */ - protected $aliases = [ - 'barcode' => Barcode::class, - 'Barcode' => Barcode::class, - 'BIC' => BusinessIdentifierCode::class, - 'bic' => BusinessIdentifierCode::class, - 'bitwise' => Bitwise::class, - 'Bitwise' => Bitwise::class, - 'BusinessIdentifierCode' => BusinessIdentifierCode::class, - 'businessidentifiercode' => BusinessIdentifierCode::class, - 'callback' => Callback::class, - 'Callback' => Callback::class, - 'creditcard' => CreditCard::class, - 'creditCard' => CreditCard::class, - 'CreditCard' => CreditCard::class, - 'date' => Date::class, - 'Date' => Date::class, - 'datestep' => DateStep::class, - 'dateStep' => DateStep::class, - 'DateStep' => DateStep::class, - 'digits' => Digits::class, - 'Digits' => Digits::class, - 'emailaddress' => EmailAddress::class, - 'emailAddress' => EmailAddress::class, - 'EmailAddress' => EmailAddress::class, - 'explode' => Explode::class, - 'Explode' => Explode::class, - 'filecount' => File\Count::class, - 'fileCount' => File\Count::class, - 'FileCount' => File\Count::class, - 'filecrc32' => File\Crc32::class, - 'fileCrc32' => File\Crc32::class, - 'FileCrc32' => File\Crc32::class, - 'fileexcludeextension' => File\ExcludeExtension::class, - 'fileExcludeExtension' => File\ExcludeExtension::class, - 'FileExcludeExtension' => File\ExcludeExtension::class, - 'fileexcludemimetype' => File\ExcludeMimeType::class, - 'fileExcludeMimeType' => File\ExcludeMimeType::class, - 'FileExcludeMimeType' => File\ExcludeMimeType::class, - 'fileexists' => File\Exists::class, - 'fileExists' => File\Exists::class, - 'FileExists' => File\Exists::class, - 'fileextension' => File\Extension::class, - 'fileExtension' => File\Extension::class, - 'FileExtension' => File\Extension::class, - 'filefilessize' => File\FilesSize::class, - 'fileFilesSize' => File\FilesSize::class, - 'FileFilesSize' => File\FilesSize::class, - 'filehash' => File\Hash::class, - 'fileHash' => File\Hash::class, - 'FileHash' => File\Hash::class, - 'fileimagesize' => File\ImageSize::class, - 'fileImageSize' => File\ImageSize::class, - 'FileImageSize' => File\ImageSize::class, - 'fileiscompressed' => File\IsCompressed::class, - 'fileIsCompressed' => File\IsCompressed::class, - 'FileIsCompressed' => File\IsCompressed::class, - 'fileisimage' => File\IsImage::class, - 'fileIsImage' => File\IsImage::class, - 'FileIsImage' => File\IsImage::class, - 'filemd5' => File\Md5::class, - 'fileMd5' => File\Md5::class, - 'FileMd5' => File\Md5::class, - 'filemimetype' => File\MimeType::class, - 'fileMimeType' => File\MimeType::class, - 'FileMimeType' => File\MimeType::class, - 'filenotexists' => File\NotExists::class, - 'fileNotExists' => File\NotExists::class, - 'FileNotExists' => File\NotExists::class, - 'filesha1' => File\Sha1::class, - 'fileSha1' => File\Sha1::class, - 'FileSha1' => File\Sha1::class, - 'filesize' => File\Size::class, - 'fileSize' => File\Size::class, - 'FileSize' => File\Size::class, - 'fileupload' => File\Upload::class, - 'fileUpload' => File\Upload::class, - 'FileUpload' => File\Upload::class, - 'fileuploadfile' => File\UploadFile::class, - 'fileUploadFile' => File\UploadFile::class, - 'FileUploadFile' => File\UploadFile::class, - 'filewordcount' => File\WordCount::class, - 'fileWordCount' => File\WordCount::class, - 'FileWordCount' => File\WordCount::class, - 'gpspoint' => GpsPoint::class, - 'gpsPoint' => GpsPoint::class, - 'GpsPoint' => GpsPoint::class, - 'hex' => Hex::class, - 'Hex' => Hex::class, - 'hostname' => Hostname::class, - 'Hostname' => Hostname::class, - 'iban' => Iban::class, - 'Iban' => Iban::class, - 'identical' => Identical::class, - 'Identical' => Identical::class, - 'inarray' => InArray::class, - 'inArray' => InArray::class, - 'InArray' => InArray::class, - 'ip' => Ip::class, - 'Ip' => Ip::class, - 'IsArray' => IsArray::class, - 'isbn' => Isbn::class, - 'Isbn' => Isbn::class, - 'isCountable' => IsCountable::class, - 'IsCountable' => IsCountable::class, - 'iscountable' => IsCountable::class, - 'isinstanceof' => IsInstanceOf::class, - 'isInstanceOf' => IsInstanceOf::class, - 'IsInstanceOf' => IsInstanceOf::class, - 'notempty' => NotEmpty::class, - 'notEmpty' => NotEmpty::class, - 'NotEmpty' => NotEmpty::class, - 'regex' => Regex::class, - 'Regex' => Regex::class, - 'sitemapchangefreq' => Sitemap\Changefreq::class, - 'sitemapChangefreq' => Sitemap\Changefreq::class, - 'SitemapChangefreq' => Sitemap\Changefreq::class, - 'sitemaplastmod' => Sitemap\Lastmod::class, - 'sitemapLastmod' => Sitemap\Lastmod::class, - 'SitemapLastmod' => Sitemap\Lastmod::class, - 'sitemaploc' => Sitemap\Loc::class, - 'sitemapLoc' => Sitemap\Loc::class, - 'SitemapLoc' => Sitemap\Loc::class, - 'sitemappriority' => Sitemap\Priority::class, - 'sitemapPriority' => Sitemap\Priority::class, - 'SitemapPriority' => Sitemap\Priority::class, - 'stringlength' => StringLength::class, - 'stringLength' => StringLength::class, - 'StringLength' => StringLength::class, - 'step' => Step::class, - 'Step' => Step::class, - 'timezone' => Timezone::class, - 'Timezone' => Timezone::class, - 'uri' => Uri::class, - 'Uri' => Uri::class, - 'uuid' => Uuid::class, - 'Uuid' => Uuid::class, - ]; - - /** - * Default set of factories - * - * @inheritDoc - */ - protected $factories = [ - Barcode::class => InvokableFactory::class, - Bitwise::class => InvokableFactory::class, - BusinessIdentifierCode::class => InvokableFactory::class, - Callback::class => InvokableFactory::class, - CreditCard::class => InvokableFactory::class, - DateStep::class => InvokableFactory::class, - Date::class => InvokableFactory::class, - DateComparison::class => InvokableFactory::class, - Digits::class => InvokableFactory::class, - EmailAddress::class => InvokableFactory::class, - Explode::class => InvokableFactory::class, - File\Count::class => InvokableFactory::class, - File\Crc32::class => InvokableFactory::class, - File\ExcludeExtension::class => InvokableFactory::class, - File\ExcludeMimeType::class => InvokableFactory::class, - File\Exists::class => InvokableFactory::class, - File\Extension::class => InvokableFactory::class, - File\FilesSize::class => InvokableFactory::class, - File\Hash::class => InvokableFactory::class, - File\ImageSize::class => InvokableFactory::class, - File\IsCompressed::class => InvokableFactory::class, - File\IsImage::class => InvokableFactory::class, - File\Md5::class => InvokableFactory::class, - File\MimeType::class => InvokableFactory::class, - File\NotExists::class => InvokableFactory::class, - File\Sha1::class => InvokableFactory::class, - File\Size::class => InvokableFactory::class, - File\Upload::class => InvokableFactory::class, - File\UploadFile::class => InvokableFactory::class, - File\WordCount::class => InvokableFactory::class, - GpsPoint::class => InvokableFactory::class, - Hex::class => InvokableFactory::class, - Hostname::class => InvokableFactory::class, - HostWithPublicIPv4Address::class => InvokableFactory::class, - Iban::class => InvokableFactory::class, - Identical::class => InvokableFactory::class, - InArray::class => InvokableFactory::class, - Ip::class => InvokableFactory::class, - IsArray::class => InvokableFactory::class, - Isbn::class => InvokableFactory::class, - IsCountable::class => InvokableFactory::class, - IsInstanceOf::class => InvokableFactory::class, - IsJsonString::class => InvokableFactory::class, - NotEmpty::class => InvokableFactory::class, - NumberComparison::class => InvokableFactory::class, - Regex::class => InvokableFactory::class, - Sitemap\Changefreq::class => InvokableFactory::class, - Sitemap\Lastmod::class => InvokableFactory::class, - Sitemap\Loc::class => InvokableFactory::class, - Sitemap\Priority::class => InvokableFactory::class, - StringLength::class => InvokableFactory::class, - Step::class => InvokableFactory::class, - Timezone::class => InvokableFactory::class, - Uri::class => InvokableFactory::class, - Uuid::class => InvokableFactory::class, + private const DEFAULT_CONFIGURATION = [ + 'factories' => [ + Barcode::class => InvokableFactory::class, + Bitwise::class => InvokableFactory::class, + BusinessIdentifierCode::class => InvokableFactory::class, + Callback::class => InvokableFactory::class, + CreditCard::class => InvokableFactory::class, + DateStep::class => InvokableFactory::class, + Date::class => InvokableFactory::class, + DateComparison::class => InvokableFactory::class, + Digits::class => InvokableFactory::class, + EmailAddress::class => InvokableFactory::class, + Explode::class => InvokableFactory::class, + File\Count::class => InvokableFactory::class, + File\Crc32::class => InvokableFactory::class, + File\ExcludeExtension::class => InvokableFactory::class, + File\ExcludeMimeType::class => InvokableFactory::class, + File\Exists::class => InvokableFactory::class, + File\Extension::class => InvokableFactory::class, + File\FilesSize::class => InvokableFactory::class, + File\Hash::class => InvokableFactory::class, + File\ImageSize::class => InvokableFactory::class, + File\IsCompressed::class => InvokableFactory::class, + File\IsImage::class => InvokableFactory::class, + File\Md5::class => InvokableFactory::class, + File\MimeType::class => InvokableFactory::class, + File\NotExists::class => InvokableFactory::class, + File\Sha1::class => InvokableFactory::class, + File\Size::class => InvokableFactory::class, + File\Upload::class => InvokableFactory::class, + File\UploadFile::class => InvokableFactory::class, + File\WordCount::class => InvokableFactory::class, + GpsPoint::class => InvokableFactory::class, + Hex::class => InvokableFactory::class, + Hostname::class => InvokableFactory::class, + HostWithPublicIPv4Address::class => InvokableFactory::class, + Iban::class => InvokableFactory::class, + Identical::class => InvokableFactory::class, + InArray::class => InvokableFactory::class, + Ip::class => InvokableFactory::class, + IsArray::class => InvokableFactory::class, + Isbn::class => InvokableFactory::class, + IsCountable::class => InvokableFactory::class, + IsInstanceOf::class => InvokableFactory::class, + IsJsonString::class => InvokableFactory::class, + NotEmpty::class => InvokableFactory::class, + NumberComparison::class => InvokableFactory::class, + Regex::class => InvokableFactory::class, + Sitemap\Changefreq::class => InvokableFactory::class, + Sitemap\Lastmod::class => InvokableFactory::class, + Sitemap\Loc::class => InvokableFactory::class, + Sitemap\Priority::class => InvokableFactory::class, + StringLength::class => InvokableFactory::class, + Step::class => InvokableFactory::class, + Timezone::class => InvokableFactory::class, + Uri::class => InvokableFactory::class, + Uuid::class => InvokableFactory::class, + ], + 'aliases' => [ + 'barcode' => Barcode::class, + 'Barcode' => Barcode::class, + 'BIC' => BusinessIdentifierCode::class, + 'bic' => BusinessIdentifierCode::class, + 'bitwise' => Bitwise::class, + 'Bitwise' => Bitwise::class, + 'BusinessIdentifierCode' => BusinessIdentifierCode::class, + 'businessidentifiercode' => BusinessIdentifierCode::class, + 'callback' => Callback::class, + 'Callback' => Callback::class, + 'creditcard' => CreditCard::class, + 'creditCard' => CreditCard::class, + 'CreditCard' => CreditCard::class, + 'date' => Date::class, + 'Date' => Date::class, + 'datestep' => DateStep::class, + 'dateStep' => DateStep::class, + 'DateStep' => DateStep::class, + 'digits' => Digits::class, + 'Digits' => Digits::class, + 'emailaddress' => EmailAddress::class, + 'emailAddress' => EmailAddress::class, + 'EmailAddress' => EmailAddress::class, + 'explode' => Explode::class, + 'Explode' => Explode::class, + 'filecount' => File\Count::class, + 'fileCount' => File\Count::class, + 'FileCount' => File\Count::class, + 'filecrc32' => File\Crc32::class, + 'fileCrc32' => File\Crc32::class, + 'FileCrc32' => File\Crc32::class, + 'fileexcludeextension' => File\ExcludeExtension::class, + 'fileExcludeExtension' => File\ExcludeExtension::class, + 'FileExcludeExtension' => File\ExcludeExtension::class, + 'fileexcludemimetype' => File\ExcludeMimeType::class, + 'fileExcludeMimeType' => File\ExcludeMimeType::class, + 'FileExcludeMimeType' => File\ExcludeMimeType::class, + 'fileexists' => File\Exists::class, + 'fileExists' => File\Exists::class, + 'FileExists' => File\Exists::class, + 'fileextension' => File\Extension::class, + 'fileExtension' => File\Extension::class, + 'FileExtension' => File\Extension::class, + 'filefilessize' => File\FilesSize::class, + 'fileFilesSize' => File\FilesSize::class, + 'FileFilesSize' => File\FilesSize::class, + 'filehash' => File\Hash::class, + 'fileHash' => File\Hash::class, + 'FileHash' => File\Hash::class, + 'fileimagesize' => File\ImageSize::class, + 'fileImageSize' => File\ImageSize::class, + 'FileImageSize' => File\ImageSize::class, + 'fileiscompressed' => File\IsCompressed::class, + 'fileIsCompressed' => File\IsCompressed::class, + 'FileIsCompressed' => File\IsCompressed::class, + 'fileisimage' => File\IsImage::class, + 'fileIsImage' => File\IsImage::class, + 'FileIsImage' => File\IsImage::class, + 'filemd5' => File\Md5::class, + 'fileMd5' => File\Md5::class, + 'FileMd5' => File\Md5::class, + 'filemimetype' => File\MimeType::class, + 'fileMimeType' => File\MimeType::class, + 'FileMimeType' => File\MimeType::class, + 'filenotexists' => File\NotExists::class, + 'fileNotExists' => File\NotExists::class, + 'FileNotExists' => File\NotExists::class, + 'filesha1' => File\Sha1::class, + 'fileSha1' => File\Sha1::class, + 'FileSha1' => File\Sha1::class, + 'filesize' => File\Size::class, + 'fileSize' => File\Size::class, + 'FileSize' => File\Size::class, + 'fileupload' => File\Upload::class, + 'fileUpload' => File\Upload::class, + 'FileUpload' => File\Upload::class, + 'fileuploadfile' => File\UploadFile::class, + 'fileUploadFile' => File\UploadFile::class, + 'FileUploadFile' => File\UploadFile::class, + 'filewordcount' => File\WordCount::class, + 'fileWordCount' => File\WordCount::class, + 'FileWordCount' => File\WordCount::class, + 'gpspoint' => GpsPoint::class, + 'gpsPoint' => GpsPoint::class, + 'GpsPoint' => GpsPoint::class, + 'hex' => Hex::class, + 'Hex' => Hex::class, + 'hostname' => Hostname::class, + 'Hostname' => Hostname::class, + 'iban' => Iban::class, + 'Iban' => Iban::class, + 'identical' => Identical::class, + 'Identical' => Identical::class, + 'inarray' => InArray::class, + 'inArray' => InArray::class, + 'InArray' => InArray::class, + 'ip' => Ip::class, + 'Ip' => Ip::class, + 'IsArray' => IsArray::class, + 'isbn' => Isbn::class, + 'Isbn' => Isbn::class, + 'isCountable' => IsCountable::class, + 'IsCountable' => IsCountable::class, + 'iscountable' => IsCountable::class, + 'isinstanceof' => IsInstanceOf::class, + 'isInstanceOf' => IsInstanceOf::class, + 'IsInstanceOf' => IsInstanceOf::class, + 'notempty' => NotEmpty::class, + 'notEmpty' => NotEmpty::class, + 'NotEmpty' => NotEmpty::class, + 'regex' => Regex::class, + 'Regex' => Regex::class, + 'sitemapchangefreq' => Sitemap\Changefreq::class, + 'sitemapChangefreq' => Sitemap\Changefreq::class, + 'SitemapChangefreq' => Sitemap\Changefreq::class, + 'sitemaplastmod' => Sitemap\Lastmod::class, + 'sitemapLastmod' => Sitemap\Lastmod::class, + 'SitemapLastmod' => Sitemap\Lastmod::class, + 'sitemaploc' => Sitemap\Loc::class, + 'sitemapLoc' => Sitemap\Loc::class, + 'SitemapLoc' => Sitemap\Loc::class, + 'sitemappriority' => Sitemap\Priority::class, + 'sitemapPriority' => Sitemap\Priority::class, + 'SitemapPriority' => Sitemap\Priority::class, + 'stringlength' => StringLength::class, + 'stringLength' => StringLength::class, + 'StringLength' => StringLength::class, + 'step' => Step::class, + 'Step' => Step::class, + 'timezone' => Timezone::class, + 'Timezone' => Timezone::class, + 'uri' => Uri::class, + 'Uri' => Uri::class, + 'uuid' => Uuid::class, + 'Uuid' => Uuid::class, + ], ]; /** - * Whether or not to share by default; default to false (v2) - * - * @var bool + * Whether to share by default; default to false */ - protected $shareByDefault = false; + protected bool $sharedByDefault = false; - /** - * Whether or not to share by default; default to false (v3) - * - * @var bool - */ - protected $sharedByDefault = false; + protected string $instanceOf = ValidatorInterface::class; /** - * Default instance type - * - * @inheritDoc + * @param ServiceManagerConfiguration $config */ - protected $instanceOf = ValidatorInterface::class; - - /** - * Constructor - * - * After invoking parent constructor, add an initializer to inject the - * attached translator, if any, to the currently requested helper. - * - * {@inheritDoc} - * - * @param ServiceManagerConfiguration $v3config - */ - public function __construct($configOrContainerInstance = null, array $v3config = []) + public function __construct(ContainerInterface $creationContext, array $config = []) { - parent::__construct($configOrContainerInstance, $v3config); - - $this->addInitializer([$this, 'injectTranslator']); - $this->addInitializer([$this, 'injectValidatorPluginManager']); - } - - /** - * @param mixed $instance - * @psalm-assert ValidatorInterface $instance - */ - public function validate($instance) - { - if (! $instance instanceof $this->instanceOf) { - throw new InvalidServiceException(sprintf( - '%s expects only to create instances of %s; %s is invalid', - static::class, - (string) $this->instanceOf, - get_debug_type($instance) - )); - } - } + /** @var ServiceManagerConfiguration $config */ + $config = array_replace_recursive(self::DEFAULT_CONFIGURATION, $config); + parent::__construct($creationContext, $config); - /** - * For v2 compatibility: validate plugin instance. - * - * Proxies to `validate()`. - * - * @return void - * @throws Exception\RuntimeException - */ - public function validatePlugin(mixed $plugin) - { - try { - $this->validate($plugin); - } catch (InvalidServiceException $e) { - throw new Exception\RuntimeException(sprintf( - 'Plugin of type %s is invalid; must implement %s', - get_debug_type($plugin), - ValidatorInterface::class - ), $e->getCode(), $e); - } + $this->addInitializer(Closure::fromCallable([$this, 'injectTranslator'])); + $this->addInitializer(Closure::fromCallable([$this, 'injectValidatorPluginManager'])); } - /** - * Inject a validator instance with the registered translator - * - * @param ContainerInterface|object $first - * @param ContainerInterface|object $second - * @return void - */ - public function injectTranslator($first, $second) + /** @internal */ + protected function injectTranslator(ContainerInterface $container, object $validator): void { - if ($first instanceof ContainerInterface) { - $container = $first; - $validator = $second; - } else { - $container = $second; - $validator = $first; - } - if (! $validator instanceof Translator\TranslatorAwareInterface) { return; } - // V2 means we pull it from the parent container - if ($container === $this && method_exists($container, 'getServiceLocator') && $container->getServiceLocator()) { - $container = $container->getServiceLocator(); - } - - if (! $container instanceof ContainerInterface) { - return; - } - if ($container->has('MvcTranslator')) { - $validator->setTranslator($container->get('MvcTranslator')); + $translator = $container->get('MvcTranslator'); + assert($translator instanceof TranslatorInterface); + $validator->setTranslator($translator); return; } @@ -344,22 +257,15 @@ public function injectTranslator($first, $second) } } - /** - * Inject a validator plugin manager - * - * @param ContainerInterface|object $first - * @param ContainerInterface|object $second - * @return void - */ - public function injectValidatorPluginManager($first, $second) - { - if ($first instanceof ContainerInterface) { - $validator = $second; - } else { - $validator = $first; - } - if ($validator instanceof ValidatorPluginManagerAwareInterface) { - $validator->setValidatorPluginManager($this); + /** @internal */ + protected function injectValidatorPluginManager( + ContainerInterface $container, + object $validator, + ): void { + if (! $validator instanceof ValidatorPluginManagerAwareInterface) { + return; } + + $validator->setValidatorPluginManager($this); } } diff --git a/src/ValidatorPluginManagerFactory.php b/src/ValidatorPluginManagerFactory.php index 4b2d393b..5980a1c0 100644 --- a/src/ValidatorPluginManagerFactory.php +++ b/src/ValidatorPluginManagerFactory.php @@ -4,9 +4,6 @@ namespace Laminas\Validator; -use Laminas\ServiceManager\Config; -use Laminas\ServiceManager\FactoryInterface; -use Laminas\ServiceManager\ServiceLocatorInterface; use Laminas\ServiceManager\ServiceManager; use Psr\Container\ContainerInterface; @@ -17,71 +14,28 @@ * * @psalm-import-type ServiceManagerConfiguration from ServiceManager */ -final class ValidatorPluginManagerFactory implements FactoryInterface +final class ValidatorPluginManagerFactory { - /** - * laminas-servicemanager v2 support for invocation options. - * - * @var null|ServiceManagerConfiguration - */ - protected $creationOptions; - - /** - * {@inheritDoc} - * - * @param string $name - * @param ServiceManagerConfiguration|null $options - * @return ValidatorPluginManager - * @psalm-suppress MoreSpecificImplementedParamType - */ - public function __invoke(ContainerInterface $container, $name, ?array $options = null) + public function __invoke(ContainerInterface $container): ValidatorPluginManager { - $pluginManager = new ValidatorPluginManager($container, $options ?? []); - // If this is in a laminas-mvc application, the ServiceListener will inject // merged configuration during bootstrap. if ($container->has('ServiceListener')) { - return $pluginManager; + return new ValidatorPluginManager($container); } // If we do not have a config service, nothing more to do if (! $container->has('config')) { - return $pluginManager; + return new ValidatorPluginManager($container); } $config = $container->get('config'); // If we do not have validators configuration, nothing more to do if (! isset($config['validators']) || ! is_array($config['validators'])) { - return $pluginManager; + return new ValidatorPluginManager($container); } - // Wire service configuration for validators - (new Config($config['validators']))->configureServiceManager($pluginManager); - - return $pluginManager; - } - - /** - * {@inheritDoc} - * - * @param string|null $name - * @param string|null $requestedName - * @return ValidatorPluginManager - */ - public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null) - { - return $this($container, $requestedName ?? ValidatorPluginManager::class, $this->creationOptions); - } - - /** - * laminas-servicemanager v2 support for invocation options. - * - * @param ServiceManagerConfiguration $options - * @return void - */ - public function setCreationOptions(array $options) - { - $this->creationOptions = $options; + return new ValidatorPluginManager($container, $config['validators']); } } diff --git a/test/StaticAnalysis/PluginManager.php b/test/StaticAnalysis/PluginManager.php index 062a3ecd..b732c455 100644 --- a/test/StaticAnalysis/PluginManager.php +++ b/test/StaticAnalysis/PluginManager.php @@ -4,6 +4,7 @@ namespace LaminasTest\Validator\StaticAnalysis; +use Laminas\ServiceManager\ServiceManager; use Laminas\Validator\Uuid; use Laminas\Validator\ValidatorInterface; use Laminas\Validator\ValidatorPluginManager; @@ -13,13 +14,13 @@ final class PluginManager { public function validateAssertsPluginType(mixed $input): ValidatorInterface { - (new ValidatorPluginManager())->validate($input); + (new ValidatorPluginManager(new ServiceManager()))->validate($input); return $input; } public function getWithClassStringReturnsCorrectInstanceType(): ValidatorInterface { - return (new ValidatorPluginManager())->get(Uuid::class); + return (new ValidatorPluginManager(new ServiceManager()))->get(Uuid::class); } } diff --git a/test/ValidatorPluginManagerCompatibilityTest.php b/test/ValidatorPluginManagerCompatibilityTest.php index dc012db5..32da2bd9 100644 --- a/test/ValidatorPluginManagerCompatibilityTest.php +++ b/test/ValidatorPluginManagerCompatibilityTest.php @@ -4,13 +4,13 @@ namespace LaminasTest\Validator; +use Laminas\ServiceManager\AbstractSingleInstancePluginManager; use Laminas\ServiceManager\ServiceManager; use Laminas\ServiceManager\Test\CommonPluginManagerTrait; use Laminas\Validator\Barcode; use Laminas\Validator\Bitwise; use Laminas\Validator\Callback; use Laminas\Validator\DateComparison; -use Laminas\Validator\Exception\RuntimeException; use Laminas\Validator\Explode; use Laminas\Validator\File\ExcludeExtension; use Laminas\Validator\File\Extension; @@ -21,12 +21,13 @@ use Laminas\Validator\ValidatorInterface; use Laminas\Validator\ValidatorPluginManager; use PHPUnit\Framework\TestCase; -use ReflectionProperty; +use ReflectionClass; use function assert; use function in_array; use function is_string; +/** @psalm-import-type ServiceManagerConfiguration from ServiceManager */ final class ValidatorPluginManagerCompatibilityTest extends TestCase { use CommonPluginManagerTrait; @@ -45,14 +46,14 @@ final class ValidatorPluginManagerCompatibilityTest extends TestCase IsInstanceOf::class, ]; - protected static function getPluginManager(): ValidatorPluginManager + /** + * Returns the plugin manager to test + * + * @param ServiceManagerConfiguration $config + */ + protected static function getPluginManager(array $config = []): AbstractSingleInstancePluginManager { - return new ValidatorPluginManager(new ServiceManager()); - } - - protected function getV2InvalidPluginException(): string - { - return RuntimeException::class; + return new ValidatorPluginManager(new ServiceManager(), $config); } protected function getInstanceOf(): string @@ -63,14 +64,14 @@ protected function getInstanceOf(): string /** @return array */ public static function aliasProvider(): array { - $out = []; - $pluginManager = self::getPluginManager(); + $class = new ReflectionClass(ValidatorPluginManager::class); + $config = $class->getConstant('DEFAULT_CONFIGURATION'); + self::assertIsArray($config); + self::assertIsArray($config['aliases'] ?? null); - $r = new ReflectionProperty($pluginManager, 'aliases'); - $aliases = $r->getValue($pluginManager); - self::assertIsArray($aliases); + $out = []; - foreach ($aliases as $alias => $target) { + foreach ($config['aliases'] as $alias => $target) { assert(is_string($target)); assert(is_string($alias)); diff --git a/test/ValidatorPluginManagerFactoryTest.php b/test/ValidatorPluginManagerFactoryTest.php index 97f12138..a2907d11 100644 --- a/test/ValidatorPluginManagerFactoryTest.php +++ b/test/ValidatorPluginManagerFactoryTest.php @@ -10,7 +10,6 @@ use Laminas\Validator\ValidatorPluginManager; use Laminas\Validator\ValidatorPluginManagerFactory; use LaminasTest\Validator\TestAsset\InMemoryContainer; -use PHPUnit\Framework\Attributes\Depends; use PHPUnit\Framework\TestCase; final class ValidatorPluginManagerFactoryTest extends TestCase @@ -18,44 +17,11 @@ final class ValidatorPluginManagerFactoryTest extends TestCase public function testFactoryReturnsPluginManager(): void { $factory = new ValidatorPluginManagerFactory(); - $validators = $factory(new InMemoryContainer(), ValidatorPluginManagerFactory::class); + $validators = $factory(new InMemoryContainer()); self::assertInstanceOf(ValidatorPluginManager::class, $validators); } - #[Depends('testFactoryReturnsPluginManager')] - public function testFactoryConfiguresPluginManagerUnderContainerInterop(): void - { - $validator = $this->createMock(ValidatorInterface::class); - - $factory = new ValidatorPluginManagerFactory(); - $validators = $factory(new InMemoryContainer(), ValidatorPluginManagerFactory::class, [ - 'services' => [ - 'test' => $validator, - ], - ]); - - self::assertSame($validator, $validators->get('test')); - } - - #[Depends('testFactoryReturnsPluginManager')] - public function testFactoryConfiguresPluginManagerUnderServiceManagerV2(): void - { - $container = $this->createMock(ServiceLocatorInterface::class); - $validator = $this->createMock(ValidatorInterface::class); - - $factory = new ValidatorPluginManagerFactory(); - $factory->setCreationOptions([ - 'services' => [ - 'test' => $validator, - ], - ]); - - $validators = $factory->createService($container); - - self::assertSame($validator, $validators->get('test')); - } - public function testConfiguresValidatorServicesWhenFound(): void { $validator = $this->createMock(ValidatorInterface::class); @@ -74,7 +40,7 @@ public function testConfiguresValidatorServicesWhenFound(): void $container->set('config', $config); $factory = new ValidatorPluginManagerFactory(); - $validators = $factory($container, 'ValidatorManager'); + $validators = $factory($container); self::assertInstanceOf(ValidatorPluginManager::class, $validators); self::assertTrue($validators->has('test')); @@ -99,7 +65,7 @@ public function testDoesNotConfigureValidatorServicesWhenServiceListenerPresent( ->with('config'); $factory = new ValidatorPluginManagerFactory(); - $validators = $factory($container, 'ValidatorManager'); + $validators = $factory($container); self::assertInstanceOf(ValidatorPluginManager::class, $validators); self::assertFalse($validators->has('test')); @@ -110,7 +76,7 @@ public function testDoesNotConfigureValidatorServicesWhenConfigServiceNotPresent { $container = new InMemoryContainer(); $factory = new ValidatorPluginManagerFactory(); - $validators = $factory($container, 'ValidatorManager'); + $validators = $factory($container); self::assertInstanceOf(ValidatorPluginManager::class, $validators); } @@ -120,7 +86,7 @@ public function testDoesNotConfigureValidatorServicesWhenConfigServiceDoesNotCon $container = new InMemoryContainer(); $container->set('config', ['foo' => 'bar']); $factory = new ValidatorPluginManagerFactory(); - $validators = $factory($container, 'ValidatorManager'); + $validators = $factory($container); self::assertInstanceOf(ValidatorPluginManager::class, $validators); self::assertFalse($validators->has('foo')); diff --git a/test/ValidatorPluginManagerTest.php b/test/ValidatorPluginManagerTest.php index 9f5b5b5a..30be16ea 100644 --- a/test/ValidatorPluginManagerTest.php +++ b/test/ValidatorPluginManagerTest.php @@ -6,6 +6,7 @@ use Exception; use Laminas\ServiceManager\Exception\InvalidServiceException; +use Laminas\ServiceManager\Factory\InvokableFactory; use Laminas\ServiceManager\ServiceManager; use Laminas\Translator\TranslatorInterface; use Laminas\Validator\AbstractValidator; @@ -92,27 +93,15 @@ public function testAllowsInjectingTranslatorInterface(): void public function testNoTranslatorInjectedWhenTranslatorIsNotPresent(): void { - $container = $this->createMock(ContainerInterface::class); - - $container - ->expects(self::exactly(2)) - ->method('has') - ->willReturnMap( - [ - ['MvcTranslator', false], - [TranslatorInterface::class, false], - ], - ); - - $container - ->expects(self::never()) - ->method('get'); + $container = new ServiceManager(); + self::assertFalse($container->has('MvcTranslator')); + self::assertFalse($container->has(TranslatorInterface::class)); $validators = new ValidatorPluginManager($container); $validator = $validators->get(NotEmpty::class); - self::assertInstanceOf(AbstractValidator::class, $validator); + self::assertInstanceOf(NotEmpty::class, $validator); self::assertNull($validator->getTranslator()); } @@ -133,10 +122,20 @@ public function testRegisteringInvalidValidatorRaisesException(): void public function testLoadingInvalidValidatorRaisesException(): void { - $this->validators->setInvokableClass('test', InMemoryContainer::class); + $pluginManager = new ValidatorPluginManager( + new ServiceManager(), + [ + 'factories' => [ + InMemoryContainer::class => InvokableFactory::class, + ], + 'aliases' => [ + 'test' => InMemoryContainer::class, + ], + ], + ); try { - $this->validators->get('test'); + $pluginManager->get('test'); self::fail('An exception should have been thrown'); } catch (InvalidServiceException | RuntimeException $e) { self::assertStringContainsString(ValidatorInterface::class, $e->getMessage());