diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index a4cd12634..000000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "🐛 Bug Report" -about: "If something isn't working as expected 🤔" - ---- - -Version: ?.?.? - -### Bug Description -... A clear and concise description of what the bug is. A good bug report shouldn't leave others needing to chase you up for more information. - -### Steps To Reproduce -... If possible a minimal demo of the problem ... - -### Expected Behavior -... A clear and concise description of what you expected to happen. - -### Possible Solution -... Only if you have suggestions on a fix for the bug diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index d2e219489..000000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: "🚀 Feature Request" -about: "I have a suggestion (and may want to implement it) 🙂" - ---- - -- Is your feature request related to a problem? Please describe. -- Explain your intentions. -- It's up to you to make a strong case to convince the project's developers of the merits of this feature. diff --git a/.github/ISSUE_TEMPLATE/Support_question.md b/.github/ISSUE_TEMPLATE/Support_question.md deleted file mode 100644 index 75c48b6ed..000000000 --- a/.github/ISSUE_TEMPLATE/Support_question.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: "🤗 Support Question" -about: "If you have a question 💬, please check out our forum!" - ---- - ---------------^ Click "Preview" for a nicer view! -We primarily use GitHub as an issue tracker; for usage and support questions, please check out these resources below. Thanks! 😁. - -* Nette Forum: https://forum.nette.org -* Nette Gitter: https://gitter.im/nette/nette -* Slack (czech): https://pehapkari.slack.com/messages/C2R30BLKA diff --git a/.github/ISSUE_TEMPLATE/Support_us.md b/.github/ISSUE_TEMPLATE/Support_us.md deleted file mode 100644 index 92d8a4c3a..000000000 --- a/.github/ISSUE_TEMPLATE/Support_us.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: "❤️ Support us" -about: "If you would like to support our efforts in maintaining this project 🙌" - ---- - ---------------^ Click "Preview" for a nicer view! - -> https://nette.org/donate - -Help support Nette! - -We develop Nette Framework for more than 14 years. In order to make your life more comfortable. Nette cares about the safety of your sites. Nette saves you time. And gives job opportunities. - -Nette earns you money. And is absolutely free. - -To ensure future development and improving the documentation, we need your donation. - -Whether you are chief of IT company which benefits from Nette, or developer who goes for advice on our forum, if you like Nette, [please make a donation now](https://nette.org/donate). - -Thank you! diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 25adc9520..000000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: dg -custom: "https://nette.org/donate" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index f8aa3f408..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,11 +0,0 @@ -- bug fix / new feature? -- BC break? yes/no -- doc PR: nette/docs#??? - - diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index 337a0a631..00abb989e 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.1 + php-version: 8.0 coverage: none - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index b0692d716..f985b0526 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none - run: composer install --no-progress --prefer-dist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index de8c8e95e..82b6f1861 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + php: ['8.0', '8.1'] fail-fast: false @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.1 + php-version: 8.0 coverage: none - run: composer update --no-progress --prefer-dist --prefer-lowest --prefer-stable @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none - run: composer install --no-progress --prefer-dist diff --git a/composer.json b/composer.json index 497ddb293..009c46b1a 100644 --- a/composer.json +++ b/composer.json @@ -15,18 +15,18 @@ } ], "require": { - "php": ">=7.1 <8.2", + "php": ">=8.0 <8.2", "ext-tokenizer": "*", "nette/neon": "^3.3 || ^4.0", "nette/php-generator": "^3.5.4 || ^4.0", - "nette/robot-loader": "^3.2", - "nette/schema": "^1.1", - "nette/utils": "^3.1.6" + "nette/robot-loader": "^3.3.1 || ^4.0", + "nette/schema": "^1.2.2", + "nette/utils": "^4.0" }, "require-dev": { - "nette/tester": "^2.2", - "tracy/tracy": "^2.3", - "phpstan/phpstan": "^0.12" + "nette/tester": "^2.4", + "tracy/tracy": "^2.8", + "phpstan/phpstan": "^1.0" }, "conflict": { "nette/bootstrap": "<3.0" @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } } } diff --git a/contributing.md b/contributing.md deleted file mode 100644 index 184152c02..000000000 --- a/contributing.md +++ /dev/null @@ -1,33 +0,0 @@ -How to contribute & use the issue tracker -========================================= - -Nette welcomes your contributions. There are several ways to help out: - -* Create an issue on GitHub, if you have found a bug -* Write test cases for open bug issues -* Write fixes for open bug/feature issues, preferably with test cases included -* Contribute to the [documentation](https://nette.org/en/writing) - -Issues ------- - -Please **do not use the issue tracker to ask questions**. We will be happy to help you -on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette). - -A good bug report shouldn't leave others needing to chase you up for more -information. Please try to be as detailed as possible in your report. - -**Feature requests** are welcome. But take a moment to find out whether your idea -fits with the scope and aims of the project. It's up to *you* to make a strong -case to convince the project's developers of the merits of this feature. - -Contributing ------------- - -If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing). - -The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them. - -Please do not fix whitespace, format code, or make a purely cosmetic patch. - -Thanks! :heart: diff --git a/readme.md b/readme.md index 642cfc2fd..49dea9d54 100644 --- a/readme.md +++ b/readme.md @@ -37,7 +37,7 @@ The recommended way to install is via Composer: composer require nette/di ``` -It requires PHP version 7.1 and supports PHP up to 8.1. +It requires PHP version 8.0 and supports PHP up to 8.1. Usage @@ -50,8 +50,8 @@ We have the object representing email: ```php class Mail { - public $subject; - public $message; + public string $subject; + public string $message; } ``` @@ -60,7 +60,7 @@ An object which can send emails: ```php interface Mailer { - function send(Mail $mail, $to); + function send(Mail $mail, string $to): void; } ``` @@ -69,7 +69,7 @@ A support for logging: ```php interface Logger { - function log($message); + function log(string $message): void; } ``` @@ -78,23 +78,25 @@ And finally, a class that provides sending newsletters: ```php class NewsletterManager { - private $mailer; - private $logger; + private Mailer $mailer; + private Logger $logger; - function __construct(Mailer $mailer, Logger $logger) + public function __construct(Mailer $mailer, Logger $logger) { $this->mailer = $mailer; $this->logger = $logger; } - function distribute(array $recipients) + public function distribute(array $recipients): void { $mail = new Mail; - ... + $mail->subject = '...'; + $mail->message = '...'; + foreach ($recipients as $recipient) { $this->mailer->send($mail, $recipient); } - $this->logger->log(...); + $this->logger->log('...'); } } ``` @@ -106,7 +108,7 @@ Also, we have a ability to implement own `Logger` or `Mailer`, like this: ```php class SendMailMailer implements Mailer { - function send(Mail $mail, $to) + public function send(Mail $mail, string $to): void { mail($to, $mail->subject, $mail->message); } @@ -114,14 +116,14 @@ class SendMailMailer implements Mailer class FileLogger implements Logger { - private $file; + private string $file; - function __construct($file) + public function __construct(string $file) { $this->file = $file; } - function log($message) + public function log(string $message): void { file_put_contents($this->file, $message . "\n", FILE_APPEND); } @@ -135,26 +137,26 @@ Container for our application might look like this: ```php class Container { - private $logger; - private $mailer; + private ?Logger $logger; + private ?Mailer $mailer; - function getLogger() + public function getLogger(): Logger { - if (!$this->logger) { + if (!isset($this->logger)) { $this->logger = new FileLogger('log.txt'); } return $this->logger; } - function getMailer() + public function getMailer(): Mailer { - if (!$this->mailer) { + if (!isset($this->mailer)) { $this->mailer = new SendMailMailer; } return $this->mailer; } - function createNewsletterManager() + public function createNewsletterManager(): NewsletterManager { return new NewsletterManager($this->getMailer(), $this->getLogger()); } @@ -213,7 +215,7 @@ The container will be generated only once and the code is stored in cache (in di During development it is useful to activate auto-refresh mode which automatically regenerate the container when any class or configuration file is changed. Just in the constructor `ContainerLoader` append `true` as the second argument: ```php -$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true); +$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', autoRebuild: true); ``` @@ -244,9 +246,9 @@ Class of the service: ```php class NewsletterManager { - private $anotherService; + private AnotherService $anotherService; - public function setAnotherService(AnotherService $service) + public function setAnotherService(AnotherService $service): void { $this->anotherService = $service; } @@ -254,7 +256,7 @@ class NewsletterManager ... ``` -We can also add the `inject: yes` directive. This directive will enable automatic call of `inject*` methods and passing dependencies to public variables with `@inject` annotations: +We can also add the `inject: yes` directive. This directive will enable automatic call of `inject*` methods and passing dependencies to public variables with #[Inject] attribute: ```neon services: @@ -266,21 +268,23 @@ services: Dependency `Service1` will be passed by calling the `inject*` method, dependency `Service2` will be assigned to the `$service2` variable: ```php +use Nette\DI\Attributes\Inject; + class FooClass { - private $service1; + private Service1 $service1; // 1) inject* method: - public function injectService1(Service1 $service) + public function injectService1(Service1 $service): void { $this->service1 = $service1; } - // 2) Assign to the variable with the @inject annotation: + // 2) Assign to the variable with the #[Inject] attribute: - /** @inject @var Service2 */ - public $service2; + #[Inject] + public Service2 $service2; } ``` @@ -291,17 +295,14 @@ However, this method is not ideal, because the variable must be declared as publ Factories --------- -We can use factories generated from an interface. The interface must declare the returning type in the `@return` annotation of the method. Nette will generate a proper implementation of the interface. +We can use factories generated from an interface. The interface must declare the returning type of the method. Nette will generate a proper implementation of the interface. The interface must have exactly one method named `create`. Our factory interface could be declared in the following way: ```php -interface IBarFactory +interface BarFactory { - /** - * @return Bar - */ - public function create(); + function create(): Bar; } ``` @@ -310,7 +311,7 @@ The `create` method will instantiate an `Bar` with the following definition: ```php class Bar { - private $logger; + private Logger $logger; public function __construct(Logger $logger) { @@ -323,7 +324,7 @@ The factory will be registered in the `config.neon` file: ```neon services: - - IBarFactory + - BarFactory ``` Nette will check if the declared service is an interface. If yes, it will also generate the corresponding implementation of the factory. The definition can be also written in a more verbose form: @@ -331,7 +332,7 @@ Nette will check if the declared service is an interface. If yes, it will also g ```neon services: barFactory: - implement: IBarFactory + implement: BarFactory ``` This full definition allows us to declare additional configuration of the object using the `arguments` and `setup` sections, similarly as for all other services. @@ -341,14 +342,14 @@ In our code, we only have to obtain the factory instance and call the `create` m ```php class Foo { - private $barFactory; + private BarFactory $barFactory; - function __construct(IBarFactory $barFactory) + function __construct(BarFactory $barFactory) { $this->barFactory = $barFactory; } - function bar() + function bar(): void { $bar = $this->barFactory->create(); } diff --git a/src/Bridges/DITracy/ContainerPanel.php b/src/Bridges/DITracy/ContainerPanel.php index a86747e14..5767f64cd 100644 --- a/src/Bridges/DITracy/ContainerPanel.php +++ b/src/Bridges/DITracy/ContainerPanel.php @@ -21,14 +21,11 @@ class ContainerPanel implements Tracy\IBarPanel { use Nette\SmartObject; - /** @var float|null */ - public static $compilationTime; + public static ?float $compilationTime = null; - /** @var Nette\DI\Container */ - private $container; + private Nette\DI\Container $container; - /** @var float|null */ - private $elapsedTime; + private ?float $elapsedTime; public function __construct(Container $container) @@ -62,7 +59,7 @@ public function getPanel(): string $types = []; foreach ($rc->getMethods() as $method) { if (preg_match('#^createService(.+)#', $method->name, $m) && $method->getReturnType()) { - $types[lcfirst(str_replace('__', '.', $m[1]))] = $method->getReturnType()->getName(); + $types[lcfirst(str_replace('__', '.', $m[1]))] = (string) $method->getReturnType(); } } diff --git a/src/DI/Autowiring.php b/src/DI/Autowiring.php index 5a5164912..dbc72f60f 100644 --- a/src/DI/Autowiring.php +++ b/src/DI/Autowiring.php @@ -19,17 +19,16 @@ class Autowiring { use Nette\SmartObject; - /** @var ContainerBuilder */ - private $builder; + private ContainerBuilder $builder; /** @var array[] type => services, used by getByType() */ - private $highPriority = []; + private array $highPriority = []; /** @var array[] type => services, used by findByType() */ - private $lowPriority = []; + private array $lowPriority = []; /** @var string[] of classes excluded from autowiring */ - private $excludedClasses = []; + private array $excludedClasses = []; public function __construct(ContainerBuilder $builder) @@ -40,7 +39,6 @@ public function __construct(ContainerBuilder $builder) /** * Resolves service name by type. - * @param bool $throw exception if service not found? * @throws MissingServiceException when not found * @throws ServiceCreationException when multiple found */ @@ -65,13 +63,13 @@ public function getByType(string $type, bool $throw = false): ?string } else { $list = $types[$type]; natsort($list); - $hint = count($list) === 2 && ($tmp = strpos($list[0], '.') xor strpos($list[1], '.')) + $hint = count($list) === 2 && ($tmp = str_contains($list[0], '.') xor str_contains($list[1], '.')) ? '. If you want to overwrite service ' . $list[$tmp ? 0 : 1] . ', give it proper name.' : ''; throw new ServiceCreationException(sprintf( "Multiple services of type $type found: %s%s", implode(', ', $list), - $hint + $hint, )); } } @@ -133,7 +131,7 @@ public function rebuild(): void throw new ServiceCreationException(sprintf( "Incompatible class %s in autowiring definition of service '%s'.", $autowiredType, - $name + $name, )); } } diff --git a/src/DI/Compiler.php b/src/DI/Compiler.php index c4ecfc2dc..6a24cdf39 100644 --- a/src/DI/Compiler.php +++ b/src/DI/Compiler.php @@ -26,25 +26,15 @@ class Compiler DI = 'di'; /** @var CompilerExtension[] */ - private $extensions = []; - - /** @var ContainerBuilder */ - private $builder; - - /** @var array */ - private $config = []; + private array $extensions = []; + private ContainerBuilder $builder; + private array $config = []; /** @var array [section => array[]] */ - private $configs = []; - - /** @var string */ - private $sources = ''; - - /** @var DependencyChecker */ - private $dependencies; - - /** @var string */ - private $className = 'Container'; + private array $configs = []; + private string $sources = ''; + private DependencyChecker $dependencies; + private string $className = 'Container'; public function __construct(?ContainerBuilder $builder = null) @@ -58,9 +48,8 @@ public function __construct(?ContainerBuilder $builder = null) /** * Add custom configurator extension. - * @return static */ - public function addExtension(?string $name, CompilerExtension $extension) + public function addExtension(?string $name, CompilerExtension $extension): static { if ($name === null) { $name = '_' . count($this->extensions); @@ -74,7 +63,7 @@ public function addExtension(?string $name, CompilerExtension $extension) throw new Nette\InvalidArgumentException(sprintf( "Name of extension '%s' has the same name as '%s' in a case-insensitive manner.", $name, - $nm + $nm, )); } } @@ -87,7 +76,7 @@ public function addExtension(?string $name, CompilerExtension $extension) public function getExtensions(?string $type = null): array { return $type - ? array_filter($this->extensions, function ($item) use ($type): bool { return $item instanceof $type; }) + ? array_filter($this->extensions, fn($item): bool => $item instanceof $type) : $this->extensions; } @@ -98,8 +87,7 @@ public function getContainerBuilder(): ContainerBuilder } - /** @return static */ - public function setClassName(string $className) + public function setClassName(string $className): static { $this->className = $className; return $this; @@ -108,9 +96,8 @@ public function setClassName(string $className) /** * Adds new configuration. - * @return static */ - public function addConfig(array $config) + public function addConfig(array $config): static { foreach ($config as $section => $data) { $this->configs[$section][] = $data; @@ -123,9 +110,8 @@ public function addConfig(array $config) /** * Adds new configuration from file. - * @return static */ - public function loadConfig(string $file, ?Config\Loader $loader = null) + public function loadConfig(string $file, ?Config\Loader $loader = null): static { $sources = $this->sources . "// source: $file\n"; $loader = $loader ?: new Config\Loader; @@ -151,9 +137,8 @@ public function getConfig(): array /** * Sets the names of dynamic parameters. - * @return static */ - public function setDynamicParameterNames(array $names) + public function setDynamicParameterNames(array $names): static { assert($this->extensions[self::Parameters] instanceof Extensions\ParametersExtension); $this->extensions[self::Parameters]->dynamicParams = $names; @@ -164,9 +149,8 @@ public function setDynamicParameterNames(array $names) /** * Adds dependencies to the list. * @param array $deps of ReflectionClass|\ReflectionFunctionAbstract|string - * @return static */ - public function addDependencies(array $deps) + public function addDependencies(array $deps): static { $this->dependencies->add(array_filter($deps)); return $this; @@ -182,8 +166,7 @@ public function exportDependencies(): array } - /** @return static */ - public function addExportedTag(string $tag) + public function addExportedTag(string $tag): static { if (isset($this->extensions[self::DI])) { assert($this->extensions[self::DI] instanceof Extensions\DIExtension); @@ -194,8 +177,7 @@ public function addExportedTag(string $tag) } - /** @return static */ - public function addExportedType(string $type) + public function addExportedType(string $type): static { if (isset($this->extensions[self::DI])) { assert($this->extensions[self::DI] instanceof Extensions\DIExtension); @@ -217,7 +199,11 @@ public function compile(): string /** @internal */ public function processExtensions(): void { - $first = $this->getExtensions(Extensions\ParametersExtension::class) + $this->getExtensions(Extensions\ExtensionsExtension::class); + $extensionsExtensionName = Nette\DI\Extensions\ExtensionsExtension::class; + if (array_key_exists('extensions', $this->extensions)) { + $extensionsExtensionName = get_class($this->extensions['extensions']); + } + $first = $this->getExtensions(Extensions\ParametersExtension::class) + $this->getExtensions($extensionsExtensionName); foreach ($first as $name => $extension) { $config = $this->processSchema($extension->getConfigSchema(), $this->configs[$name] ?? [], $name); $extension->setConfig($this->config[$name] = $config); @@ -250,14 +236,14 @@ public function processExtensions(): void if ($extra = array_diff_key($this->extensions, $extensions, $first, [self::Services => 1])) { throw new Nette\DeprecatedException(sprintf( "Extensions '%s' were added while container was being compiled.", - implode("', '", array_keys($extra)) + implode("', '", array_keys($extra)), )); } elseif ($extra = key(array_diff_key($this->configs, $this->extensions))) { $hint = Nette\Utils\Helpers::getSuggestion(array_keys($this->extensions), $extra); throw new InvalidConfigurationException( sprintf("Found section '%s' in configuration, but corresponding extension is missing", $extra) - . ($hint ? ", did you mean '$hint'?" : '.') + . ($hint ? ", did you mean '$hint'?" : '.'), ); } } @@ -278,9 +264,8 @@ private function processBeforeCompile(): void /** * Merges and validates configurations against scheme. - * @return array|object */ - private function processSchema(Schema\Schema $schema, array $configs, $name = null) + private function processSchema(Schema\Schema $schema, array $configs, $name = null): array|object { $processor = new Schema\Processor; $processor->onNewContext[] = function (Schema\Context $context) use ($name) { @@ -332,18 +317,4 @@ protected function createPhpGenerator(): PhpGenerator { return new PhpGenerator($this->builder); } - - - /** @deprecated use non-static Compiler::loadDefinitionsFromConfig() */ - public static function loadDefinitions(): void - { - throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated, use non-static Compiler::loadDefinitionsFromConfig(array $configList).'); - } - - - /** @deprecated use non-static Compiler::loadDefinitionsFromConfig() */ - public static function loadDefinition(): void - { - throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated, use non-static Compiler::loadDefinitionsFromConfig(array $configList).'); - } } diff --git a/src/DI/CompilerExtension.php b/src/DI/CompilerExtension.php index 0523448ad..680570822 100644 --- a/src/DI/CompilerExtension.php +++ b/src/DI/CompilerExtension.php @@ -19,21 +19,13 @@ abstract class CompilerExtension { use Nette\SmartObject; - /** @var Compiler */ - protected $compiler; + protected Compiler $compiler; + protected string $name; + protected array|object $config = []; + protected Nette\PhpGenerator\Closure $initialization; - /** @var string */ - protected $name; - /** @var array|object */ - protected $config = []; - - /** @var Nette\PhpGenerator\Closure */ - protected $initialization; - - - /** @return static */ - public function setCompiler(Compiler $compiler, string $name) + public function setCompiler(Compiler $compiler, string $name): static { $this->initialization = new Nette\PhpGenerator\Closure; $this->compiler = $compiler; @@ -42,16 +34,8 @@ public function setCompiler(Compiler $compiler, string $name) } - /** - * @param array|object $config - * @return static - */ - public function setConfig($config) + public function setConfig(array|object $config): static { - if (!is_array($config) && !is_object($config)) { - throw new Nette\InvalidArgumentException; - } - $this->config = $config; return $this; } @@ -59,9 +43,8 @@ public function setConfig($config) /** * Returns extension configuration. - * @return array|object */ - public function getConfig() + public function getConfig(): array|object { return $this->config; } @@ -95,7 +78,7 @@ public function validateConfig(array $expected, ?array $config = null, ?string $ throw new Nette\DI\InvalidConfigurationException(sprintf( "Unknown configuration option '%s\u{a0}›\u{a0}%s'", $name, - $hint ? key($extra) : implode("', '{$name}\u{a0}›\u{a0}", array_keys($extra)) + $hint ? key($extra) : implode("', '{$name}\u{a0}›\u{a0}", array_keys($extra)), ) . ($hint ? ", did you mean '{$name}\u{a0}›\u{a0}{$hint}'?" : '.')); } @@ -154,7 +137,7 @@ public function getInitialization(): Nette\PhpGenerator\Closure */ public function prefix(string $id): string { - return substr_replace($id, $this->name . '.', substr($id, 0, 1) === '@' ? 1 : 0, 0); + return substr_replace($id, $this->name . '.', str_starts_with($id, '@') ? 1 : 0, 0); } diff --git a/src/DI/Config/Adapters/NeonAdapter.php b/src/DI/Config/Adapters/NeonAdapter.php index 5d15fd471..5af1e6908 100644 --- a/src/DI/Config/Adapters/NeonAdapter.php +++ b/src/DI/Config/Adapters/NeonAdapter.php @@ -44,6 +44,7 @@ public function load(string $file): array $node = $decoder->parseToNode($input); $traverser = new Neon\Traverser; $node = $traverser->traverse($node, [$this, 'removeUnderscoreVisitor']); + $node = $traverser->traverse($node, [$this, 'convertAtSignVisitor']); return $this->process((array) $node->toValue()); } @@ -53,12 +54,12 @@ public function process(array $arr): array { $res = []; foreach ($arr as $key => $val) { - if (is_string($key) && substr($key, -1) === self::PreventMergingSuffix) { + if (is_string($key) && str_ends_with($key, self::PreventMergingSuffix)) { if (!is_array($val) && $val !== null) { throw new Nette\DI\InvalidConfigurationException(sprintf( "Replacing operator is available only for arrays, item '%s' is not array (used in '%s')", $key, - $this->file + $this->file, )); } @@ -75,15 +76,15 @@ public function process(array $arr): array foreach ($this->process($val->attributes) as $st) { $tmp = new Statement( $tmp === null ? $st->getEntity() : [$tmp, ltrim(implode('::', (array) $st->getEntity()), ':')], - $st->arguments + $st->arguments, ); } $val = $tmp; } else { $tmp = $this->process([$val->value]); - if (is_string($tmp[0]) && strpos($tmp[0], '?') !== false) { - trigger_error("Operator ? is deprecated in config files (used in '$this->file')", E_USER_DEPRECATED); + if (is_string($tmp[0]) && str_contains($tmp[0], '?')) { + throw new Nette\DI\InvalidConfigurationException("Operator ? is deprecated in config file (used in '$this->file')"); } $val = new Statement($tmp[0], $this->process($val->attributes)); @@ -108,7 +109,7 @@ function (&$val): void { if ($val instanceof Statement) { $val = self::statementToEntity($val); } - } + }, ); return "# generated by Nette\n\n" . Neon\Neon::encode($data, Neon\Neon::BLOCK); } @@ -124,7 +125,7 @@ function (&$val): void { } elseif ($val instanceof Reference) { $val = '@' . $val->getValue(); } - } + }, ); $entity = $val->getEntity(); @@ -137,7 +138,7 @@ function (&$val): void { [ self::statementToEntity($entity[0]), new Neon\Entity('::' . $entity[1], $val->arguments), - ] + ], ); } elseif ($entity[0] instanceof Reference) { $entity = '@' . $entity[0]->getValue() . '::' . $entity[1]; @@ -150,6 +151,7 @@ function (&$val): void { } + /** @internal */ public function removeUnderscoreVisitor(Neon\Node $node) { if (!$node instanceof Neon\Node\EntityNode) { @@ -159,13 +161,38 @@ public function removeUnderscoreVisitor(Neon\Node $node) $index = false; foreach ($node->attributes as $i => $attr) { if ($index) { - $attr->key = $attr->key ?? new Neon\Node\LiteralNode((string) $i); + $attr->key ??= new Neon\Node\LiteralNode((string) $i); } if ($attr->value instanceof Neon\Node\LiteralNode && $attr->value->value === '_') { unset($node->attributes[$i]); $index = true; + + } elseif ($attr->value instanceof Neon\Node\LiteralNode && $attr->value->value === '...') { + throw new Nette\DI\InvalidConfigurationException("Replace ... with _ in configuration file '$this->file'."); + unset($node->attributes[$i]); + $index = true; + } + } + } + + + /** @internal */ + public function convertAtSignVisitor(Neon\Node $node) + { + if ($node instanceof Neon\Node\StringNode) { + if (substr($node->value, 0, 2) === '@@') { + trigger_error("There is no need to escape @ anymore, replace @@ with @ in: '$node->value' (used in $this->file)", E_USER_DEPRECATED); + } else { + $node->value = preg_replace('#^@#', '$0$0', $node->value); // escape } + + } elseif ( + $node instanceof Neon\Node\LiteralNode + && is_string($node->value) + && substr($node->value, 0, 2) === '@@' + ) { + trigger_error("There is no need to escape @ anymore, replace @@ with @ and put string in quotes: '$node->value' (used in $this->file)", E_USER_DEPRECATED); } } } diff --git a/src/DI/Config/Helpers.php b/src/DI/Config/Helpers.php index 531d88ba6..9124a5236 100644 --- a/src/DI/Config/Helpers.php +++ b/src/DI/Config/Helpers.php @@ -23,19 +23,14 @@ final class Helpers public const PREVENT_MERGING = '_prevent_merging'; - /** - * Merges configurations. Left has higher priority than right one. - * @return array|string - */ + /** @deprecated */ public static function merge($left, $right) { return Nette\Schema\Helpers::merge($left, $right); } - /** - * Return true if array prevents merging and removes this information. - */ + /** @deprecated */ public static function takeParent(&$data): bool { if (is_array($data) && isset($data[self::PREVENT_MERGING])) { diff --git a/src/DI/Config/Loader.php b/src/DI/Config/Loader.php index 1c56f2d47..a9273de1b 100644 --- a/src/DI/Config/Loader.php +++ b/src/DI/Config/Loader.php @@ -22,16 +22,13 @@ class Loader private const IncludesKey = 'includes'; - private $adapters = [ + private array $adapters = [ 'php' => Adapters\PhpAdapter::class, 'neon' => Adapters\NeonAdapter::class, ]; - - private $dependencies = []; - - private $loadedFiles = []; - - private $parameters = []; + private array $dependencies = []; + private array $loadedFiles = []; + private array $parameters = []; /** @@ -74,11 +71,10 @@ public function load(string $file, ?bool $merge = true): array } - /** - * Save configuration to file. - */ + /** @deprecated */ public function save(array $data, string $file): void { + trigger_error(__METHOD__ . "() is deprecated, use adapter's dump() method.", E_USER_DEPRECATED); if (file_put_contents($file, $this->getAdapter($file)->dump($data)) === false) { throw new Nette\IOException(sprintf("Cannot write file '%s'.", $file)); } @@ -107,10 +103,8 @@ public function expandIncludedFile(string $includedFile, string $mainFile): stri /** * Registers adapter for given file extension. - * @param string|Adapter $adapter - * @return static */ - public function addAdapter(string $extension, $adapter) + public function addAdapter(string $extension, string|Adapter $adapter): static { $this->adapters[strtolower($extension)] = $adapter; return $this; @@ -130,8 +124,7 @@ private function getAdapter(string $file): Adapter } - /** @return static */ - public function setParameters(array $params) + public function setParameters(array $params): static { $this->parameters = $params; return $this; diff --git a/src/DI/Container.php b/src/DI/Container.php index 09518b571..29b159bae 100644 --- a/src/DI/Container.php +++ b/src/DI/Container.php @@ -19,29 +19,26 @@ class Container { use Nette\SmartObject; - /** @var array user parameters */ - public $parameters = []; + public array $parameters = []; /** @var string[] services name => type (complete list of available services) */ - protected $types = []; + protected array $types = []; /** @var string[] alias => service name */ - protected $aliases = []; + protected array $aliases = []; /** @var array[] tag name => service name => tag value */ - protected $tags = []; + protected array $tags = []; /** @var array[] type => level => services */ - protected $wiring = []; + protected array $wiring = []; /** @var object[] service name => instance */ - private $instances = []; + private array $instances = []; - /** @var array circular reference detector */ - private $creating; - - /** @var array */ - private $methods; + /** circular reference detector */ + private array $creating; + private array $methods; public function __construct(array $params = []) @@ -49,7 +46,7 @@ public function __construct(array $params = []) $this->parameters = $params; $this->methods = array_flip(array_filter( get_class_methods($this), - function ($s) { return preg_match('#^createService.#', $s); } + fn($s) => preg_match('#^createService.#', $s), )); } @@ -63,23 +60,19 @@ public function getParameters(): array /** * Adds the service to the container. * @param object $service service or its factory - * @return static */ - public function addService(string $name, $service) + public function addService(string $name, object $service): static { $name = $this->aliases[$name] ?? $name; if (isset($this->instances[$name])) { throw new Nette\InvalidStateException(sprintf("Service '%s' already exists.", $name)); - - } elseif (!is_object($service)) { - throw new Nette\InvalidArgumentException(sprintf("Service '%s' must be a object, %s given.", $name, gettype($service))); } if ($service instanceof \Closure) { $rt = Nette\Utils\Type::fromReflection(new \ReflectionFunction($service)); $type = $rt ? Helpers::ensureClassType($rt, 'return type of closure') : ''; } else { - $type = get_class($service); + $type = $service::class; } if (!isset($this->methods[self::getMethodName($name)])) { @@ -90,7 +83,7 @@ public function addService(string $name, $service) "Service '%s' must be instance of %s, %s.", $name, $expectedType, - $type ? "$type given" : 'add typehint to closure' + $type ? "$type given" : 'add typehint to closure', )); } @@ -117,10 +110,9 @@ public function removeService(string $name): void /** * Gets the service object by name. - * @return object * @throws MissingServiceException */ - public function getService(string $name) + public function getService(string $name): object { if (!isset($this->instances[$name])) { if (isset($this->aliases[$name])) { @@ -136,10 +128,9 @@ public function getService(string $name) /** * Gets the service object by name. - * @return object * @throws MissingServiceException */ - public function getByName(string $name) + public function getByName(string $name): object { return $this->getService($name); } @@ -159,8 +150,7 @@ public function getServiceType(string $name): string return $this->types[$name]; } elseif (isset($this->methods[$method])) { - $type = (new \ReflectionMethod($this, $method))->getReturnType(); - return $type ? $type->getName() : ''; + return (string) (new \ReflectionMethod($this, $method))->getReturnType(); } else { throw new MissingServiceException(sprintf("Service '%s' not found.", $name)); @@ -194,10 +184,9 @@ public function isCreated(string $name): bool /** * Creates new instance of the service. - * @return object * @throws MissingServiceException */ - public function createService(string $name, array $args = []) + public function createService(string $name, array $args = []): object { $name = $this->aliases[$name] ?? $name; $method = self::getMethodName($name); @@ -222,7 +211,7 @@ public function createService(string $name, array $args = []) if (!is_object($service)) { throw new Nette\UnexpectedValueException(sprintf( "Unable to create service '$name', value returned by %s is not object.", - $cb instanceof \Closure ? 'closure' : "method $method()" + $cb instanceof \Closure ? 'closure' : "method $method()", )); } @@ -237,7 +226,7 @@ public function createService(string $name, array $args = []) * @return ?T * @throws MissingServiceException */ - public function getByType(string $type, bool $throw = true) + public function getByType(string $type, bool $throw = true): ?object { $type = Helpers::normalizeClass($type); if (!empty($this->wiring[$type][0])) { @@ -258,14 +247,14 @@ public function getByType(string $type, bool $throw = true) if (is_a($methodType, $type, true)) { throw new MissingServiceException(sprintf( "Service of type %s is not autowired or is missing in di\u{a0}›\u{a0}export\u{a0}›\u{a0}types.", - $type + $type, )); } } throw new MissingServiceException(sprintf( 'Service of type %s not found. Did you add it to configuration file?', - $type + $type, )); } @@ -313,10 +302,8 @@ public function findByTag(string $tag): array /** * Creates new instance using autowiring. - * @return object - * @throws Nette\InvalidArgumentException */ - public function createInstance(string $class, array $args = []) + public function createInstance(string $class, array $args = []): object { $rc = new \ReflectionClass($class); if (!$rc->isInstantiable()) { @@ -335,9 +322,8 @@ public function createInstance(string $class, array $args = []) /** * Calls all methods starting with with "inject" using autowiring. - * @param object $service */ - public function callInjects($service): void + public function callInjects(object $service): void { Extensions\InjectExtension::callInjects($this, $service); } @@ -345,9 +331,8 @@ public function callInjects($service): void /** * Calls method using autowiring. - * @return mixed */ - public function callMethod(callable $function, array $args = []) + public function callMethod(callable $function, array $args = []): mixed { return $function(...$this->autowireArguments(Nette\Utils\Callback::toReflection($function), $args)); } @@ -355,11 +340,9 @@ public function callMethod(callable $function, array $args = []) private function autowireArguments(\ReflectionFunctionAbstract $function, array $args = []): array { - return Resolver::autowireArguments($function, $args, function (string $type, bool $single) { - return $single + return Resolver::autowireArguments($function, $args, fn(string $type, bool $single) => $single ? $this->getByType($type) - : array_map([$this, 'getService'], $this->findAutowired($type)); - }); + : array_map([$this, 'getService'], $this->findAutowired($type))); } diff --git a/src/DI/ContainerBuilder.php b/src/DI/ContainerBuilder.php index ebdb1c4a2..e212b6a3f 100644 --- a/src/DI/ContainerBuilder.php +++ b/src/DI/ContainerBuilder.php @@ -24,26 +24,17 @@ class ContainerBuilder THIS_SERVICE = 'self', THIS_CONTAINER = 'container'; - /** @var array */ - public $parameters = []; + public array $parameters = []; /** @var Definition[] */ - private $definitions = []; + private array $definitions = []; - /** @var array of alias => service */ - private $aliases = []; - - /** @var Autowiring */ - private $autowiring; - - /** @var bool */ - private $needsResolve = true; - - /** @var bool */ - private $resolving = false; - - /** @var array */ - private $dependencies = []; + /** alias => service */ + private array $aliases = []; + private Autowiring $autowiring; + private bool $needsResolve = true; + private bool $resolving = false; + private array $dependencies = []; public function __construct() @@ -83,7 +74,7 @@ public function addDefinition(?string $name, ?Definition $definition = null): De throw new Nette\InvalidStateException(sprintf( "Service '%s' has the same name as '%s' in a case-insensitive manner.", $name, - $nm + $nm, )); } } @@ -206,9 +197,8 @@ public function getAliases(): array /** * @param string[] $types - * @return static */ - public function addExcludedClasses(array $types) + public function addExcludedClasses(array $types): static { $this->needsResolve = true; $this->autowiring->addExcludedClasses($types); @@ -218,7 +208,6 @@ public function addExcludedClasses(array $types) /** * Resolves autowired service name by type. - * @param bool $throw exception if service doesn't exist? * @throws MissingServiceException */ public function getByType(string $type, bool $throw = false): ?string @@ -336,11 +325,9 @@ public function complete(): void /** * Adds item to the list of dependencies. - * @param \ReflectionClass|\ReflectionFunctionAbstract|string $dep - * @return static * @internal */ - public function addDependency($dep) + public function addDependency(\ReflectionClass|\ReflectionFunctionAbstract|string $dep): static { $this->dependencies[] = $dep; return $this; @@ -399,7 +386,7 @@ public function exportMeta(): array public static function literal(string $code, ?array $args = null): Nette\PhpGenerator\PhpLiteral { return new Nette\PhpGenerator\PhpLiteral( - $args === null ? $code : (new Nette\PhpGenerator\Dumper)->format($code, ...$args) + $args === null ? $code : (new Nette\PhpGenerator\Dumper)->format($code, ...$args), ); } @@ -417,12 +404,4 @@ public function formatPhp(string $statement, array $args): string }); return (new PhpGenerator($this))->formatPhp($statement, $args); } - - - /** @deprecated use resolve() */ - public function prepareClassList(): void - { - trigger_error(__METHOD__ . '() is deprecated, use resolve()', E_USER_DEPRECATED); - $this->resolve(); - } } diff --git a/src/DI/ContainerLoader.php b/src/DI/ContainerLoader.php index d8b04cb62..c0e666aa2 100644 --- a/src/DI/ContainerLoader.php +++ b/src/DI/ContainerLoader.php @@ -19,11 +19,8 @@ class ContainerLoader { use Nette\SmartObject; - /** @var bool */ - private $autoRebuild = false; - - /** @var string */ - private $tempDirectory; + private bool $autoRebuild = false; + private string $tempDirectory; public function __construct(string $tempDirectory, bool $autoRebuild = false) @@ -35,9 +32,8 @@ public function __construct(string $tempDirectory, bool $autoRebuild = false) /** * @param callable $generator function (Nette\DI\Compiler $compiler): string|null - * @param mixed $key */ - public function load(callable $generator, $key = null): string + public function load(callable $generator, mixed $key = null): string { $class = $this->getClassName($key); if (!class_exists($class, false)) { @@ -48,10 +44,7 @@ public function load(callable $generator, $key = null): string } - /** - * @param mixed $key - */ - public function getClassName($key): string + public function getClassName(mixed $key): string { return 'Container_' . substr(md5(serialize($key)), 0, 10); } diff --git a/src/DI/Definitions/AccessorDefinition.php b/src/DI/Definitions/AccessorDefinition.php index f47c89a21..28dadec4c 100644 --- a/src/DI/Definitions/AccessorDefinition.php +++ b/src/DI/Definitions/AccessorDefinition.php @@ -21,18 +21,16 @@ final class AccessorDefinition extends Definition { private const MethodGet = 'get'; - /** @var Reference|null */ - private $reference; + private ?Reference $reference = null; - /** @return static */ - public function setImplement(string $interface) + public function setImplement(string $interface): static { if (!interface_exists($interface)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface '%s' not found.", - $this->getName(), - $interface + "[%s]\nInterface '%s' not found.", + $this->getDescriptor(), + $interface, )); } @@ -46,18 +44,20 @@ public function setImplement(string $interface) || count($rc->getMethods()) > 1 ) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface %s must have just one non-static method get().", - $this->getName(), - $interface + "[%s]\nInterface %s must have just one non-static method get().", + $this->getDescriptor(), + $interface, )); } elseif ($method->getNumberOfParameters()) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Method %s::get() must have no parameters.", - $this->getName(), - $interface + "[%s]\nMethod %s::get() must have no parameters.", + $this->getDescriptor(), + $interface, )); } + Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::get()", $this->getDescriptor()); + return parent::setType($interface); } @@ -68,16 +68,12 @@ public function getImplement(): ?string } - /** - * @param string|Reference $reference - * @return static - */ - public function setReference($reference) + public function setReference(string|Reference $reference): static { if ($reference instanceof Reference) { $this->reference = $reference; } else { - $this->reference = substr($reference, 0, 1) === '@' + $this->reference = str_starts_with($reference, '@') ? new Reference(substr($reference, 1)) : Reference::fromType($reference); } @@ -100,10 +96,12 @@ public function resolveType(Nette\DI\Resolver $resolver): void public function complete(Nette\DI\Resolver $resolver): void { if (!$this->reference) { - $interface = $this->getType(); - $method = new \ReflectionMethod($interface, self::MethodGet); - $type = Type::fromReflection($method) ?? Helpers::getReturnTypeAnnotation($method); - $this->setReference(Helpers::ensureClassType($type, "return type of $interface::get()")); + if (!$this->getType()) { + throw new Nette\DI\ServiceCreationException('Type is missing in definition of service.'); + } + + $method = new \ReflectionMethod($this->getType(), self::MethodGet); + $this->setReference(Type::fromReflection($method)->getSingleName()); } $this->reference = $resolver->normalizeReference($this->reference); diff --git a/src/DI/Definitions/Definition.php b/src/DI/Definitions/Definition.php index 7be002f54..530698ce8 100644 --- a/src/DI/Definitions/Definition.php +++ b/src/DI/Definitions/Definition.php @@ -19,27 +19,21 @@ abstract class Definition { use Nette\SmartObject; - /** @var string|null */ - private $name; - - /** @var string|null class or interface name */ - private $type; - - /** @var array */ - private $tags = []; + private ?string $name = null; + private ?string $type = null; + private array $tags = []; /** @var bool|string[] */ - private $autowired = true; + private bool|array $autowired = true; - /** @var callable|null */ + /** @var ?callable */ private $notifier; /** - * @return static * @internal This is managed by ContainerBuilder and should not be called by user */ - final public function setName(string $name) + final public function setName(string $name): static { if ($this->name) { throw new Nette\InvalidStateException('Name already has been set.'); @@ -56,8 +50,30 @@ final public function getName(): ?string } - /** @return static */ - protected function setType(?string $type) + final public function isAnonymous(): bool + { + return !$this->name || ctype_digit($this->name); + } + + + public function getDescriptor(): string + { + if (!$this->isAnonymous()) { + return "Service '$this->name'" . ($this->type ? " of type $this->type" : ''); + + } elseif ($this->type) { + return "Service of type $this->type"; + + } elseif ($this->name) { + return "Service '$this->name'"; + + } else { + return 'Service ?'; + } + } + + + protected function setType(?string $type): static { if ($this->autowired && $this->notifier && $this->type !== $type) { ($this->notifier)(); @@ -67,9 +83,9 @@ protected function setType(?string $type) $this->type = null; } elseif (!class_exists($type) && !interface_exists($type)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Class or interface '%s' not found.", - $this->name, - $type + "[%s]\nClass or interface '%s' not found.", + $this->getDescriptor(), + $type, )); } else { $this->type = Nette\DI\Helpers::normalizeClass($type); @@ -85,8 +101,7 @@ final public function getType(): ?string } - /** @return static */ - final public function setTags(array $tags) + final public function setTags(array $tags): static { $this->tags = $tags; return $this; @@ -99,29 +114,20 @@ final public function getTags(): array } - /** - * @param mixed $attr - * @return static - */ - final public function addTag(string $tag, $attr = true) + final public function addTag(string $tag, mixed $attr = true): static { $this->tags[$tag] = $attr; return $this; } - /** @return mixed */ - final public function getTag(string $tag) + final public function getTag(string $tag): mixed { return $this->tags[$tag] ?? null; } - /** - * @param bool|string|string[] $state - * @return static - */ - final public function setAutowired($state = true) + final public function setAutowired(bool|string|array $state = true): static { if ($this->notifier && $this->autowired !== $state) { ($this->notifier)(); @@ -135,14 +141,13 @@ final public function setAutowired($state = true) /** @return bool|string[] */ - final public function getAutowired() + final public function getAutowired(): bool|array { return $this->autowired; } - /** @return static */ - public function setExported(bool $state = true) + public function setExported(bool $state = true): static { return $this->addTag('nette.exported', $state); } @@ -198,6 +203,7 @@ public function getClass(): ?string /** @deprecated Use '$def instanceof Nette\DI\Definitions\ImportedDefinition' */ public function isDynamic(): bool { + trigger_error(sprintf('Service %s: %s() is deprecated, use "instanceof ImportedDefinition".', $this->getName(), __METHOD__), E_USER_DEPRECATED); return false; } @@ -205,6 +211,7 @@ public function isDynamic(): bool /** @deprecated Use Nette\DI\Definitions\FactoryDefinition or AccessorDefinition */ public function getImplement(): ?string { + trigger_error(sprintf('Service %s: %s() is deprecated.', $this->getName(), __METHOD__), E_USER_DEPRECATED); return null; } diff --git a/src/DI/Definitions/FactoryDefinition.php b/src/DI/Definitions/FactoryDefinition.php index c4fd315d0..d8d911521 100644 --- a/src/DI/Definitions/FactoryDefinition.php +++ b/src/DI/Definitions/FactoryDefinition.php @@ -13,7 +13,6 @@ use Nette\DI\Helpers; use Nette\DI\ServiceCreationException; use Nette\PhpGenerator as Php; -use Nette\Utils\Reflection; use Nette\Utils\Type; @@ -24,11 +23,7 @@ final class FactoryDefinition extends Definition { private const MethodCreate = 'create'; - /** @var array */ - public $parameters = []; - - /** @var Definition */ - private $resultDefinition; + private Definition $resultDefinition; public function __construct() @@ -37,14 +32,13 @@ public function __construct() } - /** @return static */ - public function setImplement(string $interface) + public function setImplement(string $interface): static { if (!interface_exists($interface)) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface '%s' not found.", - $this->getName(), - $interface + "[%s]\nInterface '%s' not found.", + $this->getDescriptor(), + $interface, )); } @@ -52,12 +46,14 @@ public function setImplement(string $interface) $method = $rc->getMethods()[0] ?? null; if (!$method || $method->isStatic() || $method->name !== self::MethodCreate || count($rc->getMethods()) > 1) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Interface %s must have just one non-static method create().", - $this->getName(), - $interface + "[%s]\nInterface %s must have just one non-static method create().", + $this->getDescriptor(), + $interface, )); } + Helpers::ensureClassType(Type::fromReflection($method), "return type of $interface::create()", $this->getDescriptor()); + return parent::setType($interface); } @@ -68,14 +64,13 @@ public function getImplement(): ?string } - final public function getResultType(): ?string + public function getResultType(): ?string { return $this->resultDefinition->getType(); } - /** @return static */ - public function setResultDefinition(Definition $definition) + public function setResultDefinition(Definition $definition): static { $this->resultDefinition = $definition; return $this; @@ -89,104 +84,13 @@ public function getResultDefinition(): Definition } - /** - * @deprecated use ->getResultDefinition()->setFactory() - * @return static - */ - public function setFactory($factory, array $args = []) - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->setFactory()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - $this->resultDefinition->setFactory($factory, $args); - return $this; - } - - - /** @deprecated use ->getResultDefinition()->getFactory() */ - public function getFactory(): ?Statement - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->getFactory()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - return $this->resultDefinition->getFactory(); - } - - - /** - * @deprecated use ->getResultDefinition()->getEntity() - * @return mixed - */ - public function getEntity() - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->getEntity()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - return $this->resultDefinition->getEntity(); - } - - - /** - * @deprecated use ->getResultDefinition()->setArguments() - * @return static - */ - public function setArguments(array $args = []) - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->setArguments()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - $this->resultDefinition->setArguments($args); - return $this; - } - - - /** - * @deprecated use ->getResultDefinition()->setSetup() - * @return static - */ - public function setSetup(array $setup) - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->setSetup()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - $this->resultDefinition->setSetup($setup); - return $this; - } - - - /** @deprecated use ->getResultDefinition()->getSetup() */ - public function getSetup(): array - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->getSetup()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - return $this->resultDefinition->getSetup(); - } - - - /** - * @deprecated use ->getResultDefinition()->addSetup() - * @return static - */ - public function addSetup($entity, array $args = []) - { - trigger_error(sprintf('Service %s: %s() is deprecated, use ->getResultDefinition()->addSetup()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - $this->resultDefinition->addSetup($entity, $args); - return $this; - } - - - /** @return static */ - public function setParameters(array $params) - { - $this->parameters = $params; - return $this; - } - - - public function getParameters(): array - { - return $this->parameters; - } - - public function resolveType(Nette\DI\Resolver $resolver): void { - $interface = $this->getType(); - if (!$interface) { + if (!$this->getType()) { throw new ServiceCreationException('Type is missing in definition of service.'); } - $method = new \ReflectionMethod($interface, self::MethodCreate); - $type = Type::fromReflection($method) ?? Helpers::getReturnTypeAnnotation($method); + $type = Type::fromReflection(new \ReflectionMethod($this->getType(), self::MethodCreate)); $resultDef = $this->resultDefinition; try { @@ -196,15 +100,16 @@ public function resolveType(Nette\DI\Resolver $resolver): void throw $e; } - $resultDef->setType(Helpers::ensureClassType($type, "return type of $interface::create()")); + $resultDef->setType($type->getSingleName()); $resolver->resolveDefinition($resultDef); } if ($type && !$type->allows($resultDef->getType())) { throw new ServiceCreationException(sprintf( - 'Factory for %s cannot create incompatible %s type.', + "[%s]\nFactory for %s cannot create incompatible %s type.", + $this->getDescriptor(), $type, - $resultDef->getType() + $resultDef->getType(), )); } } @@ -215,17 +120,15 @@ public function complete(Nette\DI\Resolver $resolver): void $resultDef = $this->resultDefinition; if ($resultDef instanceof ServiceDefinition) { - if (!$this->parameters) { - $this->completeParameters($resolver); - } + $this->completeParameters($resolver); - $this->convertArguments($resultDef->getFactory()->arguments); + $this->convertArguments($resultDef->getCreator()->arguments); foreach ($resultDef->getSetup() as $setup) { $this->convertArguments($setup->arguments); } - if ($resultDef->getEntity() instanceof Reference && !$resultDef->getFactory()->arguments) { - $resultDef->setFactory([ // render as $container->createMethod() + if ($resultDef->getEntity() instanceof Reference && !$resultDef->getCreator()->arguments) { + $resultDef->setCreator([ // render as $container->createMethod() new Reference(Nette\DI\ContainerBuilder::THIS_CONTAINER), Nette\DI\Container::getMethodName($resultDef->getEntity()->getValue()), ]); @@ -243,7 +146,7 @@ private function completeParameters(Nette\DI\Resolver $resolver): void $ctorParams = []; if ( - ($class = $resolver->resolveEntityType($this->resultDefinition->getFactory())) + ($class = $resolver->resolveEntityType($this->resultDefinition->getCreator())) && ($ctor = (new \ReflectionClass($class))->getConstructor()) ) { foreach ($ctor->getParameters() as $param) { @@ -252,36 +155,28 @@ private function completeParameters(Nette\DI\Resolver $resolver): void } foreach ($method->getParameters() as $param) { - $methodType = Type::fromReflection($param); if (isset($ctorParams[$param->name])) { $ctorParam = $ctorParams[$param->name]; $ctorType = Type::fromReflection($ctorParam); - if ($ctorType && !$ctorType->allows((string) $methodType)) { + if ($ctorType && !$ctorType->allows((string) Type::fromReflection($param))) { throw new ServiceCreationException(sprintf( "Type of \$%s in %s::create() doesn't match type in %s constructor.", $param->name, $interface, - $class + $class, )); } - $this->resultDefinition->getFactory()->arguments[$ctorParam->getPosition()] = new Php\Literal('$' . $ctorParam->name); + $this->resultDefinition->getCreator()->arguments[$ctorParam->getPosition()] = new Php\Literal('$' . $ctorParam->name); } elseif (!$this->resultDefinition->getSetup()) { $hint = Nette\Utils\Helpers::getSuggestion(array_keys($ctorParams), $param->name); throw new ServiceCreationException(sprintf( 'Unused parameter $%s when implementing method %s::create()', $param->name, - $interface + $interface, ) . ($hint ? ", did you mean \${$hint}?" : '.')); } - - $paramDef = $methodType . ' ' . $param->name; - if ($param->isDefaultValueAvailable()) { - $this->parameters[$paramDef] = Reflection::getParameterDefaultValue($param); - } else { - $this->parameters[] = $paramDef; - } } } @@ -317,8 +212,8 @@ public function generateMethod(Php\Method $method, Nette\DI\PhpGenerator $genera $rm = new \ReflectionMethod($this->getType(), self::MethodCreate); $methodCreate - ->setParameters($generator->convertParameters($this->parameters)) - ->setReturnType((string) (Type::fromReflection($rm) ?? $this->getResultType())) + ->setParameters(array_map([new Php\Factory, 'fromParameterReflection'], $rm->getParameters())) + ->setReturnType((string) Type::fromReflection($rm)) ->setBody($body); $method->setBody('return new class ($this) ' . $class . ';'); diff --git a/src/DI/Definitions/ImportedDefinition.php b/src/DI/Definitions/ImportedDefinition.php index e03c245b7..d02dc803a 100644 --- a/src/DI/Definitions/ImportedDefinition.php +++ b/src/DI/Definitions/ImportedDefinition.php @@ -18,8 +18,7 @@ */ final class ImportedDefinition extends Definition { - /** @return static */ - public function setType(?string $type) + public function setType(?string $type): static { return parent::setType($type); } @@ -40,7 +39,7 @@ public function generateMethod(Nette\PhpGenerator\Method $method, PhpGenerator $ $method->setReturnType('void') ->setBody( 'throw new Nette\\DI\\ServiceCreationException(?);', - ["Unable to create imported service '{$this->getName()}', it must be added using addService()"] + ["Unable to create imported service '{$this->getName()}', it must be added using addService()"], ); } @@ -48,6 +47,7 @@ public function generateMethod(Nette\PhpGenerator\Method $method, PhpGenerator $ /** @deprecated use '$def instanceof ImportedDefinition' */ public function isDynamic(): bool { + trigger_error(sprintf('Service %s: %s() is deprecated, use "instanceof ImportedDefinition".', $this->getName(), __METHOD__), E_USER_DEPRECATED); return true; } } diff --git a/src/DI/Definitions/LocatorDefinition.php b/src/DI/Definitions/LocatorDefinition.php index 416ec1970..479170478 100644 --- a/src/DI/Definitions/LocatorDefinition.php +++ b/src/DI/Definitions/LocatorDefinition.php @@ -18,22 +18,19 @@ final class LocatorDefinition extends Definition { /** @var Reference[] */ - private $references = []; + private array $references = []; + private ?string $tagged = null; - /** @var string|null */ - private $tagged; - - /** @return static */ - public function setImplement(string $interface) + public function setImplement(string $interface): static { if (!interface_exists($interface)) { - throw new Nette\InvalidArgumentException(sprintf("Service '%s': Interface '%s' not found.", $this->getName(), $interface)); + throw new Nette\InvalidArgumentException(sprintf("[%s]\nInterface '%s' not found.", $this->getDescriptor(), $interface)); } $methods = (new \ReflectionClass($interface))->getMethods(); if (!$methods) { - throw new Nette\InvalidArgumentException(sprintf("Service '%s': Interface %s must have at least one method.", $this->getName(), $interface)); + throw new Nette\InvalidArgumentException(sprintf("[%s]\nInterface %s must have at least one method.", $this->getDescriptor(), $interface)); } foreach ($methods as $method) { @@ -42,12 +39,16 @@ public function setImplement(string $interface) || (preg_match('#^(get|create)[A-Z]#', $method->name) && $method->getNumberOfParameters() === 0) )) { throw new Nette\InvalidArgumentException(sprintf( - "Service '%s': Method %s::%s() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static.", - $this->getName(), + "[%s]\nMethod %s::%s() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static.", + $this->getDescriptor(), $interface, - $method->name + $method->name, )); } + + if ($method->getNumberOfParameters() === 0) { + Nette\DI\Helpers::ensureClassType(Nette\Utils\Type::fromReflection($method), "return type of $interface::$method->name()", $this->getDescriptor(), true); + } } return parent::setType($interface); @@ -60,12 +61,11 @@ public function getImplement(): ?string } - /** @return static */ - public function setReferences(array $references) + public function setReferences(array $references): static { $this->references = []; foreach ($references as $name => $ref) { - $this->references[$name] = substr($ref, 0, 1) === '@' + $this->references[$name] = str_starts_with($ref, '@') ? new Reference(substr($ref, 1)) : Reference::fromType($ref); } @@ -81,8 +81,7 @@ public function getReferences(): array } - /** @return static */ - public function setTagged(?string $tagged) + public function setTagged(?string $tagged): static { $this->tagged = $tagged; return $this; @@ -107,10 +106,10 @@ public function complete(Nette\DI\Resolver $resolver): void foreach ($resolver->getContainerBuilder()->findByTag($this->tagged) as $name => $tag) { if (isset($this->references[$tag])) { trigger_error(sprintf( - "Service '%s': duplicated tag '%s' with value '%s'.", - $this->getName(), + "[%s]\nDuplicated tag '%s' with value '%s'.", + $this->getDescriptor(), $this->tagged, - $tag + $tag, ), E_USER_NOTICE); } @@ -146,7 +145,7 @@ public function generateMethod(Nette\PhpGenerator\Method $method, Nette\DI\PhpGe ->setReturnType((string) Nette\Utils\Type::fromReflection($rm)); if (!$name) { - $class->addProperty('mapping', array_map(function ($item) { return $item->getValue(); }, $this->references)) + $class->addProperty('mapping', array_map(fn($item) => $item->getValue(), $this->references)) ->setPrivate(); $methodInner->setBody('if (!isset($this->mapping[$name])) { diff --git a/src/DI/Definitions/Reference.php b/src/DI/Definitions/Reference.php index f6de3ade8..5396d15fd 100644 --- a/src/DI/Definitions/Reference.php +++ b/src/DI/Definitions/Reference.php @@ -21,13 +21,12 @@ final class Reference public const SELF = 'self'; - /** @var string */ - private $value; + private string $value; - public static function fromType(string $value): self + public static function fromType(string $value): static { - if (strpos($value, '\\') === false) { + if (!str_contains($value, '\\')) { $value = '\\' . $value; } @@ -49,13 +48,13 @@ public function getValue(): string public function isName(): bool { - return strpos($this->value, '\\') === false && $this->value !== self::SELF; + return !str_contains($this->value, '\\') && $this->value !== self::SELF; } public function isType(): bool { - return strpos($this->value, '\\') !== false; + return str_contains($this->value, '\\'); } diff --git a/src/DI/Definitions/ServiceDefinition.php b/src/DI/Definitions/ServiceDefinition.php index 924059bd1..79b06f7d0 100644 --- a/src/DI/Definitions/ServiceDefinition.php +++ b/src/DI/Definitions/ServiceDefinition.php @@ -16,110 +16,98 @@ /** * Definition of standard service. * - * @property string|null $class - * @property Statement $factory - * @property Statement[] $setup + * @property-deprecated string|null $class + * @property-deprecated Statement $factory + * @property-deprecated Statement[] $setup */ final class ServiceDefinition extends Definition { - /** @var Statement */ - private $factory; + private Statement $creator; /** @var Statement[] */ - private $setup = []; + private array $setup = []; public function __construct() { - $this->factory = new Statement(null); + $this->creator = new Statement(null); } - /** @deprecated Use setType() */ - public function setClass(?string $type) + public function getDescriptor(): string { - $this->setType($type); - if (func_num_args() > 1) { - trigger_error(sprintf('Service %s: %s() second parameter $args is deprecated, use setFactory()', $this->getName(), __METHOD__), E_USER_DEPRECATED); - if ($args = func_get_arg(1)) { - $this->setFactory($type, $args); - } + $entity = $this->getEntity(); + if ($entity && $this->isAnonymous()) { + return 'Service ' . (is_string($entity) ? "of type $entity" : Nette\DI\Helpers::entityToString($entity)); } - return $this; + return parent::getDescriptor(); } - /** @return static */ - public function setType(?string $type) + public function setType(?string $type): static { return parent::setType($type); } /** - * @param string|array|Definition|Reference|Statement $factory - * @return static + * Alias for setCreator() */ - public function setFactory($factory, array $args = []) + public function setFactory(string|array|Definition|Reference|Statement $factory, array $args = []): static { return $this->setCreator($factory, $args); } + /** + * Alias for getCreator() + */ public function getFactory(): Statement { return $this->getCreator(); } - /** - * @param string|array|Definition|Reference|Statement $factory - * @return static - */ - public function setCreator($factory, array $args = []) + public function setCreator(string|array|Definition|Reference|Statement $creator, array $args = []): static { - $this->factory = $factory instanceof Statement - ? $factory - : new Statement($factory, $args); + $this->creator = $creator instanceof Statement + ? $creator + : new Statement($creator, $args); return $this; } public function getCreator(): Statement { - return $this->factory; + return $this->creator; } - /** @return string|array|Definition|Reference|null */ - public function getEntity() + public function getEntity(): string|array|Definition|Reference|null { - return $this->factory->getEntity(); + return $this->creator->getEntity(); } - /** @return static */ - public function setArguments(array $args = []) + public function setArguments(array $args = []): static { - $this->factory->arguments = $args; + $this->creator->arguments = $args; return $this; } - /** @return static */ - public function setArgument($key, $value) + public function setArgument($key, $value): static { - $this->factory->arguments[$key] = $value; + $this->creator->arguments[$key] = $value; return $this; } /** * @param Statement[] $setup - * @return static */ - public function setSetup(array $setup) + public function setSetup(array $setup): static { foreach ($setup as $v) { if (!$v instanceof Statement) { @@ -139,11 +127,7 @@ public function getSetup(): array } - /** - * @param string|array|Definition|Reference|Statement $entity - * @return static - */ - public function addSetup($entity, array $args = []) + public function addSetup(string|array|Definition|Reference|Statement $entity, array $args = []): static { $this->setup[] = $entity instanceof Statement ? $entity @@ -152,43 +136,6 @@ public function addSetup($entity, array $args = []) } - /** @deprecated */ - public function setParameters(array $params) - { - throw new Nette\DeprecatedException(sprintf('Service %s: %s() is deprecated.', $this->getName(), __METHOD__)); - } - - - /** @deprecated */ - public function getParameters(): array - { - trigger_error(sprintf('Service %s: %s() is deprecated.', $this->getName(), __METHOD__), E_USER_DEPRECATED); - return []; - } - - - /** @deprecated use $builder->addImportedDefinition(...) */ - public function setDynamic(): void - { - throw new Nette\DeprecatedException(sprintf('Service %s: %s() is deprecated, use $builder->addImportedDefinition(...)', $this->getName(), __METHOD__)); - } - - - /** @deprecated use $builder->addFactoryDefinition(...) or addAccessorDefinition(...) */ - public function setImplement(): void - { - throw new Nette\DeprecatedException(sprintf('Service %s: %s() is deprecated, use $builder->addFactoryDefinition(...)', $this->getName(), __METHOD__)); - } - - - /** @deprecated use addTag('nette.inject') */ - public function setInject(bool $state = true) - { - trigger_error(sprintf('Service %s: %s() is deprecated, use addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT)', $this->getName(), __METHOD__), E_USER_DEPRECATED); - return $this->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT, $state); - } - - public function resolveType(Nette\DI\Resolver $resolver): void { if (!$this->getEntity()) { @@ -196,10 +143,10 @@ public function resolveType(Nette\DI\Resolver $resolver): void throw new ServiceCreationException('Factory and type are missing in definition of service.'); } - $this->setFactory($this->getType(), $this->factory->arguments ?? []); + $this->setCreator($this->getType(), $this->creator->arguments ?? []); } elseif (!$this->getType()) { - $type = $resolver->resolveEntityType($this->factory); + $type = $resolver->resolveEntityType($this->creator); if (!$type) { throw new ServiceCreationException('Unknown service type, specify it or declare return type of factory method.'); } @@ -217,13 +164,13 @@ public function resolveType(Nette\DI\Resolver $resolver): void public function complete(Nette\DI\Resolver $resolver): void { - $entity = $this->factory->getEntity(); - if ($entity instanceof Reference && !$this->factory->arguments && !$this->setup) { + $entity = $this->creator->getEntity(); + if ($entity instanceof Reference && !$this->creator->arguments && !$this->setup) { $ref = $resolver->normalizeReference($entity); - $this->setFactory([new Reference(Nette\DI\ContainerBuilder::THIS_CONTAINER), 'getService'], [$ref->getValue()]); + $this->setCreator([new Reference(Nette\DI\ContainerBuilder::THIS_CONTAINER), 'getService'], [$ref->getValue()]); } - $this->factory = $resolver->completeStatement($this->factory); + $this->creator = $resolver->completeStatement($this->creator); foreach ($this->setup as &$setup) { if ( @@ -240,8 +187,8 @@ public function complete(Nette\DI\Resolver $resolver): void public function generateMethod(Nette\PhpGenerator\Method $method, Nette\DI\PhpGenerator $generator): void { - $entity = $this->factory->getEntity(); - $code = $generator->formatStatement($this->factory) . ";\n"; + $entity = $this->creator->getEntity(); + $code = $generator->formatStatement($this->creator) . ";\n"; if (!$this->setup) { $method->setBody('return ' . $code); return; @@ -260,7 +207,7 @@ public function generateMethod(Nette\PhpGenerator\Method $method, Nette\DI\PhpGe public function __clone() { parent::__clone(); - $this->factory = unserialize(serialize($this->factory)); + $this->creator = unserialize(serialize($this->creator)); $this->setup = unserialize(serialize($this->setup)); } } diff --git a/src/DI/Definitions/Statement.php b/src/DI/Definitions/Statement.php index 47231c01e..dd7f44bd9 100644 --- a/src/DI/Definitions/Statement.php +++ b/src/DI/Definitions/Statement.php @@ -22,17 +22,11 @@ final class Statement implements Nette\Schema\DynamicParameter { use Nette\SmartObject; - /** @var array */ - public $arguments; + public array $arguments; + private string|array|Definition|Reference|null $entity; - /** @var string|array|Definition|Reference|null */ - private $entity; - - /** - * @param string|array|Definition|Reference|null $entity - */ - public function __construct($entity, array $arguments = []) + public function __construct(string|array|Definition|Reference|null $entity, array $arguments = []) { if ( $entity !== null @@ -54,9 +48,9 @@ public function __construct($entity, array $arguments = []) $entity = explode('::', $entity, 2); } - if (is_string($entity) && substr($entity, 0, 1) === '@') { // normalize @service to Reference + if (is_string($entity) && str_starts_with($entity, '@')) { // normalize @service to Reference $entity = new Reference(substr($entity, 1)); - } elseif (is_array($entity) && is_string($entity[0]) && substr($entity[0], 0, 1) === '@') { + } elseif (is_array($entity) && is_string($entity[0]) && str_starts_with($entity[0], '@')) { $entity[0] = new Reference(substr($entity[0], 1)); } @@ -65,8 +59,7 @@ public function __construct($entity, array $arguments = []) } - /** @return string|array|Definition|Reference|null */ - public function getEntity() + public function getEntity(): string|array|Definition|Reference|null { return $this->entity; } diff --git a/src/DI/DependencyChecker.php b/src/DI/DependencyChecker.php index 663543d51..dd32e5f4c 100644 --- a/src/DI/DependencyChecker.php +++ b/src/DI/DependencyChecker.php @@ -11,7 +11,6 @@ use Nette; use Nette\Utils\Reflection; -use Nette\Utils\Type; use ReflectionClass; use ReflectionMethod; @@ -25,15 +24,14 @@ class DependencyChecker public const VERSION = 1; - /** @var array of ReflectionClass|\ReflectionFunctionAbstract|string */ - private $dependencies = []; + /** @var array */ + private array $dependencies = []; /** * Adds dependencies to the list. - * @return static */ - public function add(array $deps) + public function add(array $deps): static { $this->dependencies = array_merge($this->dependencies, $deps); return $this; @@ -86,7 +84,7 @@ public static function isExpired( array &$phpFiles, array $classes, array $functions, - string $hash + string $hash, ): bool { try { $currentFiles = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist @@ -121,8 +119,8 @@ class_uses($name), $name, $prop->name, $prop->getDocComment(), - (string) Type::fromReflection($prop), - PHP_VERSION_ID >= 80000 ? count($prop->getAttributes(Attributes\Inject::class)) : null, + (string) $prop->getType(), + count($prop->getAttributes(Attributes\Inject::class)), ]; } } @@ -134,7 +132,7 @@ class_uses($name), $method->name, $method->getDocComment(), self::hashParameters($method), - (string) Type::fromReflection($method), + (string) $method->getReturnType(), ]; } } @@ -142,7 +140,7 @@ class_uses($name), $flip = array_flip($classes); foreach ($functions as $name) { - if (strpos($name, '::')) { + if (str_contains($name, '::')) { $method = new ReflectionMethod($name); $class = $method->getDeclaringClass(); if (isset($flip[$class->name])) { @@ -160,7 +158,7 @@ class_uses($name), $uses, $method->getDocComment(), self::hashParameters($method), - (string) Type::fromReflection($method), + (string) $method->getReturnType(), ]; } @@ -174,10 +172,10 @@ private static function hashParameters(\ReflectionFunctionAbstract $method): arr foreach ($method->getParameters() as $param) { $res[] = [ $param->name, - (string) Type::fromReflection($param), + (string) $param->getType(), $param->isVariadic(), $param->isDefaultValueAvailable() - ? is_object($tmp = Reflection::getParameterDefaultValue($param)) ? ['object' => get_class($tmp)] : ['value' => $tmp] + ? is_object($tmp = Reflection::getParameterDefaultValue($param)) ? ['object' => $tmp::class] : ['value' => $tmp] : null, ]; } diff --git a/src/DI/Extensions/ConstantsExtension.php b/src/DI/Extensions/ConstantsExtension.php deleted file mode 100644 index ab94e8766..000000000 --- a/src/DI/Extensions/ConstantsExtension.php +++ /dev/null @@ -1,26 +0,0 @@ -getConfig() as $name => $value) { - $this->initialization->addBody('define(?, ?);', [$name, $value]); - } - } -} diff --git a/src/DI/Extensions/DIExtension.php b/src/DI/Extensions/DIExtension.php index b96f6cf8e..0c1bb1d13 100644 --- a/src/DI/Extensions/DIExtension.php +++ b/src/DI/Extensions/DIExtension.php @@ -18,17 +18,10 @@ */ final class DIExtension extends Nette\DI\CompilerExtension { - /** @var array */ - public $exportedTags = []; - - /** @var array */ - public $exportedTypes = []; - - /** @var bool */ - private $debugMode; - - /** @var float */ - private $time; + public array $exportedTags = []; + public array $exportedTypes = []; + private bool $debugMode; + private float $time; public function __construct(bool $debugMode = false) @@ -37,27 +30,23 @@ public function __construct(bool $debugMode = false) $this->time = microtime(true); $this->config = new class { - /** @var ?bool */ - public $debugger; + public ?bool $debugger = null; /** @var string[] */ - public $excluded = []; + public array $excluded = []; - /** @var ?string */ - public $parentClass; + public ?string $parentClass = null; - /** @var object */ - public $export; + public object $export; }; $this->config->export = new class { - /** @var bool */ - public $parameters = true; + public bool $parameters = true; /** @var string[]|bool|null */ - public $tags = true; + public array|bool|null $tags = true; /** @var string[]|bool|null */ - public $types = true; + public array|bool|null $types = true; }; } @@ -92,8 +81,6 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class) ) { $this->enableTracyIntegration(); } - - $this->initializeTaggedServices(); } @@ -119,20 +106,11 @@ private function restrictTypes(Nette\PhpGenerator\ClassType $class): void $prop = $class->getProperty('wiring'); $prop->setValue(array_intersect_key( $prop->getValue(), - $this->exportedTypes + (is_array($option) ? array_flip($option) : []) + $this->exportedTypes + (is_array($option) ? array_flip($option) : []), )); } - private function initializeTaggedServices(): void - { - foreach (array_filter($this->getContainerBuilder()->findByTag('run')) as $name => $on) { - trigger_error("Tag 'run' used in service '$name' definition is deprecated.", E_USER_DEPRECATED); - $this->initialization->addBody('$this->getService(?);', [$name]); - } - } - - private function enableTracyIntegration(): void { Nette\Bridges\DITracy\ContainerPanel::$compilationTime = $this->time; diff --git a/src/DI/Extensions/DecoratorExtension.php b/src/DI/Extensions/DecoratorExtension.php index b570c3fc7..6aaa9cc27 100644 --- a/src/DI/Extensions/DecoratorExtension.php +++ b/src/DI/Extensions/DecoratorExtension.php @@ -25,7 +25,7 @@ public function getConfigSchema(): Nette\Schema\Schema 'setup' => Expect::list(), 'tags' => Expect::array(), 'inject' => Expect::bool(), - ]) + ]), ); } @@ -77,9 +77,10 @@ public function addTags(string $type, array $tags): void private function findByType(string $type): array { - return array_filter($this->getContainerBuilder()->getDefinitions(), function (Definitions\Definition $def) use ($type): bool { - return is_a($def->getType(), $type, true) - || ($def instanceof Definitions\FactoryDefinition && is_a($def->getResultType(), $type, true)); - }); + return array_filter( + $this->getContainerBuilder()->getDefinitions(), + fn(Definitions\Definition $def): bool => is_a($def->getType(), $type, true) + || ($def instanceof Definitions\FactoryDefinition && is_a($def->getResultType(), $type, true)), + ); } } diff --git a/src/DI/Config/DefinitionSchema.php b/src/DI/Extensions/DefinitionSchema.php similarity index 82% rename from src/DI/Config/DefinitionSchema.php rename to src/DI/Extensions/DefinitionSchema.php index 4249a91f9..9bf29a823 100644 --- a/src/DI/Config/DefinitionSchema.php +++ b/src/DI/Extensions/DefinitionSchema.php @@ -7,9 +7,10 @@ declare(strict_types=1); -namespace Nette\DI\Config; +namespace Nette\DI\Extensions; use Nette; +use Nette\DI\Config\Helpers; use Nette\DI\Definitions; use Nette\DI\Definitions\Statement; use Nette\Schema\Context; @@ -24,8 +25,7 @@ class DefinitionSchema implements Schema { use Nette\SmartObject; - /** @var Nette\DI\ContainerBuilder */ - private $builder; + private Nette\DI\ContainerBuilder $builder; public function __construct(Nette\DI\ContainerBuilder $builder) @@ -87,7 +87,7 @@ public function normalize($def, Context $context) if (array_keys($def->arguments) === ['tagged']) { $res += $def->arguments; } elseif (array_keys($def->arguments) === [0]) { - $res['factory'] = $def->arguments[0]; + $res['create'] = $def->arguments[0]; } elseif ($def->arguments) { $res['references'] = $def->arguments; } @@ -95,24 +95,24 @@ public function normalize($def, Context $context) return $res; } elseif (!is_array($def) || isset($def[0], $def[1])) { - return ['factory' => $def]; + return ['create' => $def]; } elseif (is_array($def)) { - if (isset($def['create']) && !isset($def['factory'])) { - $def['factory'] = $def['create']; - unset($def['create']); + // back compatibility + if (isset($def['factory']) && !isset($def['create'])) { + $def['create'] = $def['factory']; + unset($def['factory']); } - if (isset($def['class']) && !isset($def['type'])) { - if ($def['class'] instanceof Statement) { - $key = end($context->path); - trigger_error(sprintf("Service '%s': option 'class' should be changed to 'factory'.", $key), E_USER_DEPRECATED); - $def['factory'] = $def['class']; - unset($def['class']); - } elseif (!isset($def['factory']) && !isset($def['dynamic']) && !isset($def['imported'])) { - $def['factory'] = $def['class']; - unset($def['class']); - } + if ( + isset($def['class']) + && !isset($def['type']) + && !isset($def['create']) + && !isset($def['dynamic']) + && !isset($def['imported']) + ) { + $def['create'] = $def['class']; + unset($def['class']); } foreach (['class' => 'type', 'dynamic' => 'imported'] as $alias => $original) { @@ -122,7 +122,7 @@ public function normalize($def, Context $context) "Options '%s' and '%s' are aliases, use only '%s'.", $alias, $original, - $original + $original, )); } @@ -179,12 +179,6 @@ private function sniffType($key, array $def): string private function expandParameters(array $config): array { $params = $this->builder->parameters; - if (isset($config['parameters'])) { - foreach ((array) $config['parameters'] as $k => $v) { - $v = explode(' ', is_int($k) ? $v : $k); - $params[end($v)] = $this->builder::literal('$' . end($v)); - } - } return Nette\DI\Helpers::expand($config, $params); } @@ -208,7 +202,7 @@ private static function getServiceSchema(): Schema { return Expect::structure([ 'type' => Expect::type('string'), - 'factory' => Expect::type('callable|Nette\DI\Definitions\Statement'), + 'create' => Expect::type('callable|Nette\DI\Definitions\Statement'), 'arguments' => Expect::array(), 'setup' => Expect::listOf('callable|Nette\DI\Definitions\Statement|array:1'), 'inject' => Expect::bool(), @@ -225,7 +219,7 @@ private static function getAccessorSchema(): Schema return Expect::structure([ 'type' => Expect::string(), 'implement' => Expect::string(), - 'factory' => Expect::type('callable|Nette\DI\Definitions\Statement'), + 'create' => Expect::type('callable|Nette\DI\Definitions\Statement'), 'autowired' => Expect::type('bool|string|array'), 'tags' => Expect::array(), ]); @@ -236,11 +230,10 @@ private static function getFactorySchema(): Schema { return Expect::structure([ 'type' => Expect::string(), - 'factory' => Expect::type('callable|Nette\DI\Definitions\Statement'), + 'create' => Expect::type('callable|Nette\DI\Definitions\Statement'), 'implement' => Expect::string(), 'arguments' => Expect::array(), 'setup' => Expect::listOf('callable|Nette\DI\Definitions\Statement|array:1'), - 'parameters' => Expect::array(), 'references' => Expect::array(), 'tagged' => Expect::string(), 'inject' => Expect::bool(), diff --git a/src/DI/Extensions/ExtensionsExtension.php b/src/DI/Extensions/ExtensionsExtension.php index a44456016..556c16c3b 100644 --- a/src/DI/Extensions/ExtensionsExtension.php +++ b/src/DI/Extensions/ExtensionsExtension.php @@ -38,7 +38,7 @@ public function loadConfiguration() if (!is_a($class, Nette\DI\CompilerExtension::class, true)) { throw new Nette\DI\InvalidConfigurationException(sprintf( "Extension '%s' not found or is not Nette\\DI\\CompilerExtension descendant.", - $class + $class, )); } diff --git a/src/DI/Extensions/InjectExtension.php b/src/DI/Extensions/InjectExtension.php index 4b8273115..dc43574bb 100644 --- a/src/DI/Extensions/InjectExtension.php +++ b/src/DI/Extensions/InjectExtension.php @@ -46,7 +46,7 @@ public function beforeCompile() private function updateDefinition(Definitions\ServiceDefinition $def): void { - $resolvedType = (new DI\Resolver($this->getContainerBuilder()))->resolveEntityType($def->getFactory()); + $resolvedType = (new DI\Resolver($this->getContainerBuilder()))->resolveEntityType($def->getCreator()); $class = is_subclass_of($resolvedType, $def->getType()) ? $resolvedType : $def->getType(); @@ -63,6 +63,7 @@ private function updateDefinition(Definitions\ServiceDefinition $def): void } } + self::checkType($class, $property, $type, $builder, $def); array_unshift($setups, $inject); } @@ -90,17 +91,15 @@ public static function getInjectMethods(string $class): array { $classes = []; foreach (get_class_methods($class) as $name) { - if (substr($name, 0, 6) === 'inject') { + if (str_starts_with($name, 'inject')) { $classes[$name] = (new \ReflectionMethod($class, $name))->getDeclaringClass()->name; } } $methods = array_keys($classes); - uksort($classes, function (string $a, string $b) use ($classes, $methods): int { - return $classes[$a] === $classes[$b] + uksort($classes, fn(string $a, string $b): int => $classes[$a] === $classes[$b] ? array_search($a, $methods, true) <=> array_search($b, $methods, true) - : (is_a($classes[$a], $classes[$b], true) ? 1 : -1); - }); + : (is_a($classes[$a], $classes[$b], true) ? 1 : -1)); return array_keys($classes); } @@ -114,24 +113,19 @@ public static function getInjectProperties(string $class): array $res = []; foreach ((new \ReflectionClass($class))->getProperties() as $rp) { $name = $rp->getName(); - $hasAttr = PHP_VERSION_ID >= 80000 && $rp->getAttributes(DI\Attributes\Inject::class); - if ($hasAttr || DI\Helpers::parseAnnotation($rp, 'inject') !== null) { + if ( + $rp->getAttributes(DI\Attributes\Inject::class) + || DI\Helpers::parseAnnotation($rp, 'inject') !== null + ) { if (!$rp->isPublic() || $rp->isStatic()) { trigger_error(sprintf('Property %s for injection must be public and non-static.', Reflection::toString($rp)), E_USER_WARNING); - continue; - } - if (PHP_VERSION_ID >= 80100 && $rp->isReadOnly()) { + } elseif (PHP_VERSION_ID >= 80100 && $rp->isReadOnly()) { throw new Nette\InvalidStateException(sprintf('Property %s for injection must not be readonly.', Reflection::toString($rp))); - } - $type = Nette\Utils\Type::fromReflection($rp); - if (!$type && !$hasAttr && ($annotation = DI\Helpers::parseAnnotation($rp, 'var'))) { - $annotation = Reflection::expandClassName($annotation, Reflection::getPropertyDeclaringClass($rp)); - $type = Nette\Utils\Type::fromString($annotation); + } else { + $res[$name] = DI\Helpers::ensureClassType(Nette\Utils\Type::fromReflection($rp), 'type of property ' . Reflection::toString($rp)); } - - $res[$rp->getName()] = DI\Helpers::ensureClassType($type, 'type of property ' . Reflection::toString($rp)); } } @@ -142,20 +136,34 @@ public static function getInjectProperties(string $class): array /** * Calls all methods starting with with "inject" using autowiring. - * @param object $service */ - public static function callInjects(DI\Container $container, $service): void + public static function callInjects(DI\Container $container, object $service): void { - if (!is_object($service)) { - throw new Nette\InvalidArgumentException(sprintf('Service must be object, %s given.', gettype($service))); - } - - foreach (self::getInjectMethods(get_class($service)) as $method) { + foreach (self::getInjectMethods($service::class) as $method) { $container->callMethod([$service, $method]); } - foreach (self::getInjectProperties(get_class($service)) as $property => $type) { + foreach (self::getInjectProperties($service::class) as $property => $type) { + self::checkType($service, $property, $type, $container); $service->$property = $container->getByType($type); } } + + + private static function checkType( + object|string $class, + string $name, + ?string $type, + DI\Container|DI\ContainerBuilder|null $container, + Definitions\Definition $def = null, + ): void { + if ($container && !$container->getByType($type, false)) { + throw new Nette\DI\MissingServiceException(sprintf( + "%sService of type %s required by %s not found.\nDid you add it to configuration file?", + $def ? '[' . $def->getDescriptor() . "]\n" : '', + $type, + Reflection::toString(new \ReflectionProperty($class, $name)), + )); + } + } } diff --git a/src/DI/Extensions/ParametersExtension.php b/src/DI/Extensions/ParametersExtension.php index b97dfa4ad..98bc34406 100644 --- a/src/DI/Extensions/ParametersExtension.php +++ b/src/DI/Extensions/ParametersExtension.php @@ -19,13 +19,11 @@ final class ParametersExtension extends Nette\DI\CompilerExtension { /** @var string[] */ - public $dynamicParams = []; + public array $dynamicParams = []; /** @var string[][] */ - public $dynamicValidators = []; - - /** @var array */ - private $compilerConfig; + public array $dynamicValidators = []; + private array $compilerConfig; public function __construct(array &$compilerConfig) diff --git a/src/DI/Extensions/PhpExtension.php b/src/DI/Extensions/PhpExtension.php deleted file mode 100644 index 6a469e32f..000000000 --- a/src/DI/Extensions/PhpExtension.php +++ /dev/null @@ -1,52 +0,0 @@ -getConfig() as $name => $value) { - if ($value === null) { - continue; - - } elseif ($name === 'include_path') { - $this->initialization->addBody('set_include_path(?);', [str_replace(';', PATH_SEPARATOR, $value)]); - - } elseif ($name === 'ignore_user_abort') { - $this->initialization->addBody('ignore_user_abort(?);', [$value]); - - } elseif ($name === 'max_execution_time') { - $this->initialization->addBody('set_time_limit(?);', [$value]); - - } elseif ($name === 'date.timezone') { - $this->initialization->addBody('date_default_timezone_set(?);', [$value]); - - } elseif (function_exists('ini_set')) { - $this->initialization->addBody('ini_set(?, ?);', [$name, $value === false ? '0' : (string) $value]); - - } elseif (ini_get($name) !== (string) $value) { - throw new Nette\NotSupportedException('Required function ini_set() is disabled.'); - } - } - } -} diff --git a/src/DI/Extensions/SearchExtension.php b/src/DI/Extensions/SearchExtension.php index 34b6daea1..771f82b55 100644 --- a/src/DI/Extensions/SearchExtension.php +++ b/src/DI/Extensions/SearchExtension.php @@ -20,11 +20,8 @@ */ final class SearchExtension extends Nette\DI\CompilerExtension { - /** @var array */ - private $classes = []; - - /** @var string */ - private $tempDir; + private array $classes = []; + private string $tempDir; public function __construct(string $tempDir) @@ -48,12 +45,10 @@ public function getConfigSchema(): Nette\Schema\Schema 'implements' => Expect::anyOf(Expect::listOf('string'), Expect::string()->castTo('array'))->default([]), ]), 'tags' => Expect::array(), - ]) - )->before(function ($val) { - return is_string($val['in'] ?? null) + ]), + )->before(fn($val) => is_string($val['in'] ?? null) ? ['default' => $val] - : $val; - }); + : $val); } @@ -65,7 +60,7 @@ public function loadConfiguration() "Option '%s\u{a0}›\u{a0}%s\u{a0}›\u{a0}in' must be valid directory name, '%s' given.", $this->name, $name, - $batch->in + $batch->in, )); } @@ -97,7 +92,7 @@ public function findClasses(\stdClass $config): array if (!class_exists($class) && !interface_exists($class) && !trait_exists($class)) { throw new Nette\InvalidStateException(sprintf( 'Class %s was found, but it cannot be loaded by autoloading.', - $class + $class, )); } @@ -111,8 +106,8 @@ public function findClasses(\stdClass $config): array ) && (!$acceptRE || preg_match($acceptRE, $rc->name)) && (!$rejectRE || !preg_match($rejectRE, $rc->name)) - && (!$acceptParent || Arrays::some($acceptParent, function ($nm) use ($rc) { return $rc->isSubclassOf($nm); })) - && (!$rejectParent || Arrays::every($rejectParent, function ($nm) use ($rc) { return !$rc->isSubclassOf($nm); })) + && (!$acceptParent || Arrays::some($acceptParent, fn($nm) => $rc->isSubclassOf($nm))) + && (!$rejectParent || Arrays::every($rejectParent, fn($nm) => !$rc->isSubclassOf($nm))) ) { $found[] = $rc->name; } @@ -145,7 +140,7 @@ private static function buildNameRegexp(array $masks): ?string { $res = []; foreach ((array) $masks as $mask) { - $mask = (strpos($mask, '\\') === false ? '**\\' : '') . $mask; + $mask = (str_contains($mask, '\\') ? '' : '**\\') . $mask; $mask = preg_quote($mask, '#'); $mask = str_replace('\*\*\\\\', '(.*\\\\)?', $mask); $mask = str_replace('\\\\\*\*', '(\\\\.*)?', $mask); diff --git a/src/DI/Extensions/ServicesExtension.php b/src/DI/Extensions/ServicesExtension.php index 02e83f1fd..7d0dd0238 100644 --- a/src/DI/Extensions/ServicesExtension.php +++ b/src/DI/Extensions/ServicesExtension.php @@ -24,7 +24,7 @@ final class ServicesExtension extends Nette\DI\CompilerExtension public function getConfigSchema(): Nette\Schema\Schema { - return Nette\Schema\Expect::arrayOf(new Nette\DI\Config\DefinitionSchema($this->getContainerBuilder())); + return Nette\Schema\Expect::arrayOf(new DefinitionSchema($this->getContainerBuilder())); } @@ -55,7 +55,7 @@ private function loadDefinition(?string $name, \stdClass $config): void $this->getContainerBuilder()->removeDefinition($name); return; } elseif (!empty($config->alteration) && !$this->getContainerBuilder()->hasDefinition($name)) { - throw new Nette\DI\InvalidConfigurationException('missing original definition for alteration.'); + throw new Nette\DI\InvalidConfigurationException('Missing original definition for alteration.'); } $def = $this->retrieveDefinition($name, $config); @@ -70,7 +70,12 @@ private function loadDefinition(?string $name, \stdClass $config): void $this->{$methods[$config->defType]}($def, $config); $this->updateDefinition($def, $config); } catch (\Throwable $e) { - throw new Nette\DI\InvalidConfigurationException(($name ? "Service '$name': " : '') . $e->getMessage(), 0, $e); + $message = $e->getMessage(); + if ($name && !str_starts_with($message, '[Service ')) { + $message = "[Service '$name']\n$message"; + } + + throw new Nette\DI\InvalidConfigurationException($message, 0, $e); } } @@ -80,8 +85,8 @@ private function loadDefinition(?string $name, \stdClass $config): void */ private function updateServiceDefinition(Definitions\ServiceDefinition $definition, \stdClass $config): void { - if ($config->factory) { - $definition->setFactory(Helpers::filterArguments([$config->factory])[0]); + if ($config->create) { + $definition->setCreator(Helpers::filterArguments([$config->create])[0]); $definition->setType(null); } @@ -92,7 +97,7 @@ private function updateServiceDefinition(Definitions\ServiceDefinition $definiti if ($config->arguments) { $arguments = Helpers::filterArguments($config->arguments); if (empty($config->reset['arguments']) && !Nette\Utils\Arrays::isList($arguments)) { - $arguments = array_replace($definition->getFactory()->arguments, $arguments); + $arguments = array_replace($definition->getCreator()->arguments, $arguments); } $definition->setArguments($arguments); @@ -124,7 +129,7 @@ private function updateAccessorDefinition(Definitions\AccessorDefinition $defini $definition->setImplement($config->implement); } - if ($ref = $config->factory ?? $config->type ?? null) { + if ($ref = $config->create ?? $config->type ?? null) { $definition->setReference($ref); } } @@ -139,18 +144,18 @@ private function updateFactoryDefinition(Definitions\FactoryDefinition $definiti $definition->setAutowired(true); } - if ($config->factory) { - $resultDef->setFactory(Helpers::filterArguments([$config->factory])[0]); + if ($config->create) { + $resultDef->setCreator(Helpers::filterArguments([$config->create])[0]); } if ($config->type) { - $resultDef->setFactory($config->type); + $resultDef->setCreator($config->type); } if ($config->arguments) { $arguments = Helpers::filterArguments($config->arguments); if (empty($config->reset['arguments']) && !Nette\Utils\Arrays::isList($arguments)) { - $arguments = array_replace($resultDef->getFactory()->arguments, $arguments); + $arguments = array_replace($resultDef->getCreator()->arguments, $arguments); } $resultDef->setArguments($arguments); @@ -170,10 +175,6 @@ private function updateFactoryDefinition(Definitions\FactoryDefinition $definiti } } - if (isset($config->parameters)) { - $definition->setParameters($config->parameters); - } - if (isset($config->inject)) { $definition->addTag(InjectExtension::TAG_INJECT, $config->inject); } diff --git a/src/DI/Helpers.php b/src/DI/Helpers.php index 35d0328e9..688a845ad 100644 --- a/src/DI/Helpers.php +++ b/src/DI/Helpers.php @@ -26,12 +26,9 @@ final class Helpers /** * Expands %placeholders%. - * @param mixed $var - * @param bool|array $recursive - * @return mixed * @throws Nette\InvalidArgumentException */ - public static function expand($var, array $params, $recursive = false) + public static function expand(mixed $var, array $params, bool|array $recursive = false): mixed { if (is_array($var)) { $res = []; @@ -66,7 +63,7 @@ public static function expand($var, array $params, $recursive = false) } elseif (isset($recursive[$part])) { throw new Nette\InvalidArgumentException(sprintf( 'Circular reference detected for variables: %s.', - implode(', ', array_keys($recursive)) + implode(', ', array_keys($recursive)), )); } else { @@ -100,12 +97,10 @@ public static function expand($var, array $params, $recursive = false) } if ($php) { - $res = array_filter($res, function ($val): bool { return $val !== ''; }); - $res = array_map(function ($val): string { - return $val instanceof DynamicParameter + $res = array_filter($res, fn($val): bool => $val !== ''); + $res = array_map(fn($val): string => $val instanceof DynamicParameter ? "($val)" - : var_export((string) $val, true); - }, $res); + : var_export((string) $val, true), $res); return new DynamicParameter(implode(' . ', $res)); } @@ -115,10 +110,8 @@ public static function expand($var, array $params, $recursive = false) /** * Escapes '%' and '@' - * @param mixed $value - * @return mixed */ - public static function escape($value) + public static function escape(mixed $value): mixed { if (is_array($value)) { $res = []; @@ -137,14 +130,12 @@ public static function escape($value) /** - * Removes ... and process constants recursively. + * Process constants recursively. */ public static function filterArguments(array $args): array { foreach ($args as $k => $v) { - if ($v === '...') { - unset($args[$k]); - } elseif ( + if ( PHP_VERSION_ID >= 80100 && is_string($v) && preg_match('#^([\w\\\\]+)::\w+$#D', $v, $m) @@ -169,10 +160,8 @@ public static function filterArguments(array $args): array /** * Replaces @extension with real extension name in service definition. - * @param mixed $config - * @return mixed */ - public static function prefixServiceName($config, string $namespace) + public static function prefixServiceName(mixed $config, string $namespace): mixed { if (is_string($config)) { if (strncmp($config, '@extension.', 10) === 0) { @@ -185,7 +174,7 @@ public static function prefixServiceName($config, string $namespace) } elseif ($config instanceof Statement) { return new Statement( self::prefixServiceName($config->getEntity(), $namespace), - self::prefixServiceName($config->arguments, $namespace) + self::prefixServiceName($config->arguments, $namespace), ); } elseif (is_array($config)) { foreach ($config as &$val) { @@ -199,7 +188,6 @@ public static function prefixServiceName($config, string $namespace) /** * Returns an annotation value. - * @param \ReflectionFunctionAbstract|\ReflectionProperty|\ReflectionClass $ref */ public static function parseAnnotation(\Reflector $ref, string $name): ?string { @@ -216,31 +204,22 @@ public static function parseAnnotation(\Reflector $ref, string $name): ?string } - public static function getReturnTypeAnnotation(\ReflectionFunctionAbstract $func): ?Type - { - $type = preg_replace('#[|\s].*#', '', (string) self::parseAnnotation($func, 'return')); - if (!$type || $type === 'object' || $type === 'mixed') { - return null; - } elseif ($func instanceof \ReflectionMethod) { - $type = $type === '$this' ? 'static' : $type; - $type = Reflection::expandClassName($type, $func->getDeclaringClass()); - } - - return Type::fromString($type); - } - - - public static function ensureClassType(?Type $type, string $hint): string - { + public static function ensureClassType( + ?Type $type, + string $hint, + string $descriptor = '', + bool $allowNullable = false, + ): string { + $descriptor = $descriptor ? "[$descriptor]\n" : ''; if (!$type) { - throw new ServiceCreationException(sprintf('%s is not declared.', ucfirst($hint))); - } elseif (!$type->isClass() || $type->isUnion()) { - throw new ServiceCreationException(sprintf("%s is not expected to be nullable/union/intersection/built-in, '%s' given.", ucfirst($hint), $type)); + throw new ServiceCreationException(sprintf('%s%s is not declared.', $descriptor, ucfirst($hint))); + } elseif (!$type->isClass() || (!$allowNullable && $type->isUnion())) { + throw new ServiceCreationException(sprintf("%s%s is not expected to be %sunion/intersection/built-in, '%s' given.", $descriptor, ucfirst($hint), $allowNullable ? '' : 'nullable/', $type)); } $class = $type->getSingleName(); if (!class_exists($class) && !interface_exists($class)) { - throw new ServiceCreationException(sprintf("Class '%s' not found.\nCheck the %s.", $class, $hint)); + throw new ServiceCreationException(sprintf("%sClass '%s' not found.\nCheck the %s.", $descriptor, $class, $hint)); } return $class; @@ -257,11 +236,9 @@ public static function normalizeClass(string $type): string /** * Non data-loss type conversion. - * @param mixed $value - * @return mixed * @throws Nette\InvalidStateException */ - public static function convertType($value, string $type) + public static function convertType(mixed $value, string $type): mixed { if (is_scalar($value)) { $norm = ($value === false ? '0' : (string) $value); @@ -279,7 +256,25 @@ public static function convertType($value, string $type) throw new Nette\InvalidStateException(sprintf( 'Cannot convert %s to %s.', is_scalar($value) ? "'$value'" : gettype($value), - $type + $type, )); } + + + public static function entityToString(string|array|Reference $entity, bool $inner = false): string + { + if (is_string($entity)) { + return $entity . ($inner ? '()' : ''); + + } elseif ($entity instanceof Reference) { + return '@' . $entity->getValue(); + + } else { + [$a, $b] = $entity; + return self::entityToString($a instanceof Statement ? $a->entity : $a, true) + . '::' + . $b + . (str_contains($b, '$') ? '' : '()'); + } + } } diff --git a/src/DI/PhpGenerator.php b/src/DI/PhpGenerator.php index c5bad2448..ccb4b53e1 100644 --- a/src/DI/PhpGenerator.php +++ b/src/DI/PhpGenerator.php @@ -23,11 +23,8 @@ class PhpGenerator { use Nette\SmartObject; - /** @var ContainerBuilder */ - private $builder; - - /** @var string */ - private $className; + private ContainerBuilder $builder; + private ?string $className = null; public function __construct(ContainerBuilder $builder) @@ -52,7 +49,8 @@ public function generate(string $className): Php\ClassType foreach ($this->builder->exportMeta() as $key => $value) { $class->addProperty($key) ->setProtected() - ->setValue($value); + ->setValue($value) + ->setType(get_debug_type($value)); } $definitions = $this->builder->getDefinitions(); @@ -104,7 +102,7 @@ public function generateMethod(Definitions\Definition $def): Php\Method return $method; } catch (\Throwable $e) { - throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e); + throw new ServiceCreationException(sprintf("[%s]\n%s", $def->getDescriptor(), $e->getMessage()), 0, $e); } } @@ -121,6 +119,15 @@ public function formatStatement(Statement $statement): string case is_string($entity) && Strings::contains($entity, '?'): // PHP literal return $this->formatPhp($entity, $arguments); + case $entity === 'not': + return $this->formatPhp('!(?)', $arguments); + + case $entity === 'bool': + case $entity === 'int': + case $entity === 'float': + case $entity === 'string': + return $this->formatPhp('?::?(?, ?)', [Helpers::class, 'convertType', $arguments[0], $entity]); + case is_string($entity): // create class return $arguments ? $this->formatPhp("new $entity(...?:)", [$arguments]) @@ -130,7 +137,7 @@ public function formatStatement(Statement $statement): string switch (true) { case $entity[1][0] === '$': // property getter, setter or appender $name = substr($entity[1], 1); - if ($append = (substr($name, -2) === '[]')) { + if ($append = (str_ends_with($name, '[]'))) { $name = substr($name, 0, -2); } @@ -143,7 +150,7 @@ public function formatStatement(Statement $statement): string case $entity[0] instanceof Statement: $inner = $this->formatPhp('?', [$entity[0]]); - if (substr($inner, 0, 4) === 'new ') { + if (str_starts_with($inner, 'new ')) { $inner = "($inner)"; } @@ -189,29 +196,6 @@ public function formatPhp(string $statement, array $args): string } - /** - * Converts parameters from Definition to PhpGenerator. - * @return Php\Parameter[] - */ - public function convertParameters(array $parameters): array - { - $res = []; - foreach ($parameters as $k => $v) { - $tmp = explode(' ', is_int($k) ? $v : $k); - $param = $res[] = new Php\Parameter(end($tmp)); - if (!is_int($k)) { - $param->setDefaultValue($v); - } - - if (isset($tmp[1])) { - $param->setType($tmp[0]); - } - } - - return $res; - } - - public function getClassName(): ?string { return $this->className; diff --git a/src/DI/Resolver.php b/src/DI/Resolver.php index 8b02facbd..0291e723d 100644 --- a/src/DI/Resolver.php +++ b/src/DI/Resolver.php @@ -29,20 +29,13 @@ class Resolver { use Nette\SmartObject; - /** @var ContainerBuilder */ - private $builder; + private ContainerBuilder $builder; + private ?Definition $currentService = null; + private ?string $currentServiceType = null; + private bool $currentServiceAllowed = false; - /** @var Definition|null */ - private $currentService; - - /** @var string|null */ - private $currentServiceType; - - /** @var bool */ - private $currentServiceAllowed = false; - - /** @var \SplObjectStorage circular reference detector */ - private $recursive; + /** circular reference detector */ + private \SplObjectStorage $recursive; public function __construct(ContainerBuilder $builder) @@ -61,7 +54,7 @@ public function getContainerBuilder(): ContainerBuilder public function resolveDefinition(Definition $def): void { if ($this->recursive->contains($def)) { - $names = array_map(function ($item) { return $item->getName(); }, iterator_to_array($this->recursive)); + $names = array_map(fn($item) => $item->getName(), iterator_to_array($this->recursive)); throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', $names))); } @@ -129,12 +122,10 @@ public function resolveEntityType(Statement $statement): ?string $this->addDependency($reflection); - $type = Nette\Utils\Type::fromReflection($reflection) ?? Helpers::getReturnTypeAnnotation($reflection); - if ($type && !in_array((string) $type, ['object', 'mixed'], true)) { - return Helpers::ensureClassType($type, sprintf('return type of %s()', Callback::toString($entity))); - } - - return null; + $type = Nette\Utils\Type::fromReflection($reflection); + return $type && !in_array((string) $type, ['object', 'mixed'], true) + ? Helpers::ensureClassType($type, sprintf('return type of %s()', Callback::toString($entity))) + : null; } elseif ($entity instanceof Reference) { // alias or factory return $this->resolveReferenceType($entity); @@ -143,9 +134,9 @@ public function resolveEntityType(Statement $statement): ?string if (!class_exists($entity)) { throw new ServiceCreationException(sprintf( interface_exists($entity) - ? "Interface %s can not be used as 'factory', did you mean 'implement'?" + ? "Interface %s can not be used as 'create' or 'factory', did you mean 'implement'?" : "Class '%s' not found.", - $entity + $entity, )); } @@ -183,42 +174,22 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo $this->currentServiceAllowed = $currentServiceAllowed; $entity = $this->normalizeEntity($statement); $arguments = $this->convertReferences($statement->arguments); - $getter = function (string $type, bool $single) { - return $single + $getter = fn(string $type, bool $single) => $single ? $this->getByType($type) - : array_values(array_filter($this->builder->findAutowired($type), function ($obj) { return $obj !== $this->currentService; })); - }; + : array_values(array_filter($this->builder->findAutowired($type), fn($obj) => $obj !== $this->currentService)); switch (true) { case is_string($entity) && Strings::contains($entity, '?'): // PHP literal break; case $entity === 'not': - if (count($arguments) > 1) { - throw new ServiceCreationException(sprintf( - 'Function %s() expects at most 1 parameter, %s given.', - $entity, - count($arguments) - )); - } - - $entity = ['', '!']; - break; - case $entity === 'bool': case $entity === 'int': case $entity === 'float': case $entity === 'string': - if (count($arguments) > 1) { - throw new ServiceCreationException(sprintf( - 'Function %s() expects at most 1 parameter, %s given.', - $entity, - count($arguments) - )); + if (count($arguments) !== 1) { + throw new ServiceCreationException(sprintf('Function %s() expects 1 parameter, %s given.', $entity, count($arguments))); } - - $arguments = [$arguments[0], $entity]; - $entity = [Helpers::class, 'convertType']; break; case is_string($entity): // create class @@ -234,7 +205,7 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo } elseif ($arguments) { throw new ServiceCreationException(sprintf( 'Unable to pass arguments, class %s has no constructor.', - $entity + $entity, )); } @@ -248,7 +219,7 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo if (!preg_match('#^\$?(\\\\?' . PhpHelpers::PHP_IDENT . ')+(\[\])?$#D', $entity[1])) { throw new ServiceCreationException(sprintf( "Expected function, method or property name, '%s' given.", - $entity[1] + $entity[1], )); } @@ -257,7 +228,7 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo if (!Nette\Utils\Arrays::isList($arguments)) { throw new ServiceCreationException(sprintf( 'Unable to pass specified arguments to %s.', - $entity[0] + $entity[0], )); } elseif (!function_exists($entity[1])) { throw new ServiceCreationException(sprintf("Function %s doesn't exist.", $entity[1])); @@ -276,7 +247,7 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo case $entity[0] instanceof Reference: if ($entity[1][0] === '$') { // property getter, setter or appender Validators::assert($arguments, 'list:0..1', "setup arguments for '" . Callback::toString($entity) . "'"); - if (!$arguments && substr($entity[1], -2) === '[]') { + if (!$arguments && str_ends_with($entity[1], '[]')) { throw new ServiceCreationException(sprintf('Missing argument for %s.', $entity[1])); } } elseif ( @@ -303,9 +274,21 @@ public function completeStatement(Statement $statement, bool $currentServiceAllo try { $arguments = $this->completeArguments($arguments); + } catch (ServiceCreationException $e) { - if (!strpos($e->getMessage(), ' (used in')) { - $e->setMessage($e->getMessage() . " (used in {$this->entityToString($entity)})"); + if (!str_contains($e->getMessage(), "\nRelated to")) { + if (is_string($entity)) { + $desc = $entity . '::__construct()'; + } else { + $desc = Helpers::entityToString($entity); + $desc = preg_replace('~@self::~A', '', $desc); + } + + if ($currentServiceAllowed) { + $desc .= ' in setup'; + } + + $e->setMessage($e->getMessage() . "\nRelated to $desc."); } throw $e; @@ -345,8 +328,8 @@ public function completeArguments(array $arguments): array } - /** @return string|array|Reference literal, Class, Reference, [Class, member], [, globalFunc], [Reference, member], [Statement, member] */ - private function normalizeEntity(Statement $statement) + /** Returns literal, Class, Reference, [Class, member], [, globalFunc], [Reference, member], [Statement, member] */ + private function normalizeEntity(Statement $statement): string|array|Reference { $entity = $statement->getEntity(); if (is_array($entity)) { @@ -435,10 +418,8 @@ public function getByType(string $type): Reference /** * Adds item to the list of dependencies. - * @param \ReflectionClass|\ReflectionFunctionAbstract|string $dep - * @return static */ - public function addDependency($dep) + public function addDependency(\ReflectionClass|\ReflectionFunctionAbstract|string $dep): static { $this->builder->addDependency($dep); return $this; @@ -447,25 +428,16 @@ public function addDependency($dep) private function completeException(\Throwable $e, Definition $def): ServiceCreationException { - if ($e instanceof ServiceCreationException && Strings::startsWith($e->getMessage(), "Service '")) { + $message = $e->getMessage(); + if ($e instanceof ServiceCreationException && str_starts_with($message, '[Service ')) { return $e; } - $name = $def->getName(); - $type = $def->getType(); - if ($name && !ctype_digit($name)) { - $message = "Service '$name'" . ($type ? " (type of $type)" : '') . ': '; - } elseif ($type) { - $message = "Service of type $type: "; - } elseif ($def instanceof Definitions\ServiceDefinition && $def->getEntity()) { - $message = 'Service (' . $this->entityToString($def->getEntity()) . '): '; - } else { - $message = ''; + if ($tmp = $def->getType()) { + $message = str_replace(" $tmp::", ' ' . preg_replace('~.*\\\\~', '', $tmp) . '::', $message); } - $message .= $type - ? str_replace("$type::", preg_replace('~.*\\\\~', '', $type) . '::', $e->getMessage()) - : $e->getMessage(); + $message = '[' . $def->getDescriptor() . "]\n" . $message; return $e instanceof ServiceCreationException ? $e->setMessage($message) @@ -473,35 +445,6 @@ private function completeException(\Throwable $e, Definition $def): ServiceCreat } - private function entityToString($entity): string - { - $referenceToText = function (Reference $ref): string { - return $ref->isSelf() && $this->currentService - ? '@' . $this->currentService->getName() - : '@' . $ref->getValue(); - }; - if (is_string($entity)) { - return $entity . '::__construct()'; - } elseif ($entity instanceof Reference) { - $entity = $referenceToText($entity); - } elseif (is_array($entity)) { - if (strpos($entity[1], '$') === false) { - $entity[1] .= '()'; - } - - if ($entity[0] instanceof Reference) { - $entity[0] = $referenceToText($entity[0]); - } elseif (!is_string($entity[0])) { - return $entity[1]; - } - - return implode('::', $entity); - } - - return (string) $entity; - } - - private function convertReferences(array $arguments): array { array_walk_recursive($arguments, function (&$val): void { @@ -514,7 +457,7 @@ private function convertReferences(array $arguments): array } else { // @service::property $val = new Statement([new Reference($pair[0]), '$' . $pair[1]]); } - } elseif (is_string($val) && substr($val, 0, 2) === '@@') { // escaped text @@ + } elseif (is_string($val) && str_starts_with($val, '@@')) { // escaped text @@ $val = substr($val, 1); } }); @@ -530,9 +473,8 @@ private function convertReferences(array $arguments): array public static function autowireArguments( \ReflectionFunctionAbstract $method, array $arguments, - callable $getter + callable $getter, ): array { - $optCount = 0; $useName = false; $num = -1; $res = []; @@ -546,7 +488,7 @@ public static function autowireArguments( throw new ServiceCreationException(sprintf( 'Parameter %s must be array, %s given.', Reflection::toString($param), - gettype($arguments[$paramName]) + gettype($arguments[$paramName]), )); } @@ -563,9 +505,6 @@ public static function autowireArguments( $res = array_merge($res, $variadics); } - $optCount = 0; - break; - } elseif (array_key_exists($paramName, $arguments)) { $res[$useName ? $paramName : $num] = $arguments[$paramName]; unset($arguments[$paramName], $arguments[$num]); @@ -577,28 +516,21 @@ public static function autowireArguments( } elseif (($aw = self::autowireArgument($param, $getter)) !== null) { $res[$useName ? $paramName : $num] = $aw; - } elseif (PHP_VERSION_ID >= 80000) { - if ($param->isOptional()) { - $useName = true; - } else { - $res[$num] = null; - } + } elseif ($param->isOptional()) { + $useName = true; } else { - $res[$num] = $param->isDefaultValueAvailable() - ? Reflection::getParameterDefaultValue($param) - : null; - } + $res[$num] = null; - if (PHP_VERSION_ID < 80000) { - $optCount = $param->isOptional() && $res[$num] === ($param->isDefaultValueAvailable() ? Reflection::getParameterDefaultValue($param) : null) - ? $optCount + 1 - : 0; + trigger_error(sprintf( + 'The parameter %s should have a declared value in the configuration.', + Reflection::toString($param), + ), E_USER_DEPRECATED); } } // extra parameters - while (!$useName && !$optCount && array_key_exists(++$num, $arguments)) { + while (!$useName && array_key_exists(++$num, $arguments)) { $res[$num] = $arguments[$num]; unset($arguments[$num]); } @@ -606,10 +538,8 @@ public static function autowireArguments( if ($arguments) { throw new ServiceCreationException(sprintf( 'Unable to pass specified arguments to %s.', - Reflection::toString($method) + Reflection::toString($method), )); - } elseif ($optCount) { - $res = array_slice($res, 0, -$optCount); } return $res; @@ -620,70 +550,61 @@ public static function autowireArguments( * Resolves missing argument using autowiring. * @param (callable(string $type, bool $single): (object|object[]|null)) $getter * @throws ServiceCreationException - * @return mixed */ - private static function autowireArgument(\ReflectionParameter $parameter, callable $getter) + private static function autowireArgument(\ReflectionParameter $parameter, callable $getter): mixed { $method = $parameter->getDeclaringFunction(); $desc = Reflection::toString($parameter); $type = Nette\Utils\Type::fromReflection($parameter); - if ($parameter->getType() instanceof \ReflectionIntersectionType) { + if ($type?->isIntersection()) { throw new ServiceCreationException(sprintf( 'Parameter %s has intersection type, so its value must be specified.', - $desc + $desc, )); - } elseif ($type && $type->isClass()) { + } elseif ($type?->isClass()) { $class = $type->getSingleName(); try { $res = $getter($class, true); } catch (MissingServiceException $e) { $res = null; } catch (ServiceCreationException $e) { - throw new ServiceCreationException("{$e->getMessage()} (required by $desc)", 0, $e); + throw new ServiceCreationException(sprintf("%s\nRequired by %s.", $e->getMessage(), $desc), 0, $e); } if ($res !== null || $parameter->allowsNull()) { return $res; } elseif (class_exists($class) || interface_exists($class)) { throw new ServiceCreationException(sprintf( - 'Service of type %s required by %s not found. Did you add it to configuration file?', + "Service of type %s required by %s not found.\nDid you add it to configuration file?", $class, - $desc + $desc, )); } else { throw new ServiceCreationException(sprintf( - "Class '%s' required by %s not found. Check the parameter type and 'use' statements.", + "Class '%s' required by %s not found.\nCheck the parameter type and 'use' statements.", $class, - $desc + $desc, )); } } elseif ( $method instanceof \ReflectionMethod - && $type && $type->getSingleName() === 'array' + && $type?->getSingleName() === 'array' && preg_match('#@param[ \t]+(?|([\w\\\\]+)\[\]|array)[ \t]+\$' . $parameter->name . '#', (string) $method->getDocComment(), $m) && ($itemType = Reflection::expandClassName($m[1], $method->getDeclaringClass())) && (class_exists($itemType) || interface_exists($itemType)) ) { return $getter($itemType, false); - } elseif ( - ($type && $parameter->allowsNull()) - || $parameter->isOptional() - || $parameter->isDefaultValueAvailable() - ) { - // !optional + defaultAvailable, !optional + !defaultAvailable since 8.1.0 = func($a = null, $b) - // optional + !defaultAvailable, optional + defaultAvailable since 8.0.0 = i.e. Exception::__construct, mysqli::mysqli, ... - // optional + !defaultAvailable = variadics - // in other cases the optional and defaultAvailable are identical + } elseif ($parameter->isOptional()) { return null; } else { throw new ServiceCreationException(sprintf( 'Parameter %s has %s, so its value must be specified.', $desc, - $type && $type->isUnion() ? 'union type and no default value' : 'no class type or default value' + $type?->isUnion() ? 'union type and no default value' : 'no class type or default value', )); } } diff --git a/src/DI/exceptions.php b/src/DI/exceptions.php index b441c5ed3..83fcb526d 100644 --- a/src/DI/exceptions.php +++ b/src/DI/exceptions.php @@ -25,7 +25,7 @@ class MissingServiceException extends Nette\InvalidStateException */ class ServiceCreationException extends Nette\InvalidStateException { - public function setMessage(string $message): self + public function setMessage(string $message): static { $this->message = $message; return $this; diff --git a/tests/DI/Compiler.arguments.phpt b/tests/DI/Compiler.arguments.phpt index 176710d16..120dedfc0 100644 --- a/tests/DI/Compiler.arguments.phpt +++ b/tests/DI/Compiler.arguments.phpt @@ -19,7 +19,7 @@ class Lorem public $args; - public $var = 123; + public int $var = 123; public function __construct() @@ -41,18 +41,6 @@ class Lorem } -if (PHP_VERSION_ID < 80000) { - Assert::error(function () use (&$container) { - $container = createContainer(new DI\Compiler, ' - services: - dolor: Lorem(::MY_FAILING_CONSTANT_TEST) - '); - }, E_WARNING, "%a?%Couldn't find constant MY_FAILING_CONSTANT_TEST"); - Assert::same([null], $container->getService('dolor')->args[0]); -} - - - define('MY_CONSTANT_TEST', 'one'); $container = createContainer(new DI\Compiler, " diff --git a/tests/DI/Compiler.config.phpt b/tests/DI/Compiler.config.phpt index bcd1a7b03..26f804d62 100644 --- a/tests/DI/Compiler.config.phpt +++ b/tests/DI/Compiler.config.phpt @@ -17,7 +17,7 @@ test('Compiler config', function () { Assert::same( [], - $compiler->getConfig() + $compiler->getConfig(), ); $compiler->addConfig([ @@ -34,7 +34,7 @@ test('Compiler config', function () { ], 'services' => [], ], - $compiler->getConfig() + $compiler->getConfig(), ); }); @@ -55,6 +55,6 @@ parameters: Assert::same( ['php', 'node'], - $compiler->getConfig()['parameters']['languages'] + $compiler->getConfig()['parameters']['languages'], ); }); diff --git a/tests/DI/Compiler.configOverride.phpt b/tests/DI/Compiler.configOverride.phpt index 20669e361..63aa223f2 100644 --- a/tests/DI/Compiler.configOverride.phpt +++ b/tests/DI/Compiler.configOverride.phpt @@ -59,4 +59,5 @@ $compiler->addConfig([ Assert::exception(function () use ($compiler, $class) { $compiler->setClassName($class) ->compile(); -}, DI\InvalidConfigurationException::class, "Service 's3': missing original definition for alteration."); +}, DI\InvalidConfigurationException::class, "[Service 's3'] +Missing original definition for alteration."); diff --git a/tests/DI/Compiler.dependencies.phpt b/tests/DI/Compiler.dependencies.phpt index 6fe0e5169..d71c2914b 100644 --- a/tests/DI/Compiler.dependencies.phpt +++ b/tests/DI/Compiler.dependencies.phpt @@ -24,7 +24,7 @@ Assert::same( [], '40cd750bba9870f18aada2478b24840a', ], - $compiler->exportDependencies() + $compiler->exportDependencies(), ); Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); @@ -39,7 +39,7 @@ Assert::same( [], '40cd750bba9870f18aada2478b24840a', ], - $compiler->exportDependencies() + $compiler->exportDependencies(), ); Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); @@ -54,7 +54,7 @@ Assert::same( [], '40cd750bba9870f18aada2478b24840a', ], - $compiler->exportDependencies() + $compiler->exportDependencies(), ); $res = $compiler->exportDependencies(); @@ -77,7 +77,7 @@ if (PHP_VERSION_ID >= 80100) { [], 'ff31f9bba26681aa5b228503003778cc', ], - $compiler->exportDependencies() + $compiler->exportDependencies(), ); Assert::false(DependencyChecker::isExpired(...$compiler->exportDependencies())); diff --git a/tests/DI/Compiler.dynamicParameters.validator.phpt b/tests/DI/Compiler.dynamicParameters.validator.phpt index 0d6cb4eb7..efd4f208b 100644 --- a/tests/DI/Compiler.dynamicParameters.validator.phpt +++ b/tests/DI/Compiler.dynamicParameters.validator.phpt @@ -18,7 +18,7 @@ class FooExtension extends Nette\DI\CompilerExtension Expect::structure([ 'string' => Expect::string()->dynamic(), 'intnull' => Expect::int()->nullable()->dynamic(), - ]) + ]), ); } } diff --git a/tests/DI/Compiler.extension.defaultServices.phpt b/tests/DI/Compiler.extension.defaultServices.phpt index 454c4c4e5..0266b5d53 100644 --- a/tests/DI/Compiler.extension.defaultServices.phpt +++ b/tests/DI/Compiler.extension.defaultServices.phpt @@ -21,8 +21,7 @@ interface IIpsum } interface IIpsumFactory { - /** @return IIpsum */ - public function create(); + public function create(): IIpsum; } interface IFooBar { @@ -46,10 +45,7 @@ class FooBar implements IFooBar class Factory { - /** - * @return Lorem - */ - public static function createLorem() + public static function createLorem(): Lorem { return new Lorem; } diff --git a/tests/DI/Compiler.extensionOverride.errors.phpt b/tests/DI/Compiler.extensionOverride.errors.phpt index a4b942814..945f0e5b5 100644 --- a/tests/DI/Compiler.extensionOverride.errors.phpt +++ b/tests/DI/Compiler.extensionOverride.errors.phpt @@ -21,4 +21,5 @@ services: bad: alteration: yes '); -}, Nette\DI\InvalidConfigurationException::class, "Service 'bad': missing original definition for alteration."); +}, Nette\DI\InvalidConfigurationException::class, "[Service 'bad'] +Missing original definition for alteration."); diff --git a/tests/DI/Compiler.extensionOverride.phpt b/tests/DI/Compiler.extensionOverride.phpt index 6a9a38b73..24b8f0148 100644 --- a/tests/DI/Compiler.extensionOverride.phpt +++ b/tests/DI/Compiler.extensionOverride.phpt @@ -15,8 +15,7 @@ require __DIR__ . '/../bootstrap.php'; class Factory { - /** @return Lorem */ - public static function createLorem(...$args) + public static function createLorem(...$args): Lorem { return new Lorem(...$args); } @@ -25,8 +24,7 @@ class Factory class IpsumFactory { - /** @return Ipsum */ - public static function create(...$args) + public static function create(...$args): Ipsum { return new Ipsum(...$args); } @@ -57,79 +55,79 @@ class FooExtension extends Nette\DI\CompilerExtension $builder = $this->getContainerBuilder(); $builder->addDefinition('one1') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one2') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one3') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one4') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one5') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one6') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one7') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one8') - ->setFactory(Lorem::class, [1]) + ->setCreator(Lorem::class, [1]) ->addSetup('__construct', [2]); $builder->addDefinition('one9') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('one10') - ->setFactory(Lorem::class, [1]); + ->setCreator(Lorem::class, [1]); $builder->addDefinition('two1') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two2') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two3') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two4') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1, 2]); + ->setCreator('Factory::createLorem', [1, 2]); $builder->addDefinition('two5') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two6') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1, 2]); + ->setCreator('Factory::createLorem', [1, 2]); $builder->addDefinition('two7') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two8') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1, 2]); + ->setCreator('Factory::createLorem', [1, 2]); $builder->addDefinition('two9') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1, 2]); + ->setCreator('Factory::createLorem', [1, 2]); $builder->addDefinition('two10') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('two11') ->setType(Lorem::class) - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three1') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three2') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three3') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three4') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three5') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three6') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three7') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three8') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); $builder->addDefinition('three9') - ->setFactory('Factory::createLorem', [1]); + ->setCreator('Factory::createLorem', [1]); } } diff --git a/tests/DI/Compiler.functions.phpt b/tests/DI/Compiler.functions.phpt index b789deded..58596d7da 100644 --- a/tests/DI/Compiler.functions.phpt +++ b/tests/DI/Compiler.functions.phpt @@ -67,7 +67,7 @@ Assert::same( 'int' => [0, 1, 231, 123], 'float' => [0.0, 1.0, 231.0, 123.0], ], - $obj->args + $obj->args, ); Assert::exception(function () use ($container) { @@ -85,4 +85,6 @@ Assert::exception(function () { services: - Service(bool(123, 10)) '); -}, Nette\InvalidStateException::class, 'Service of type Service: Function bool() expects at most 1 parameter, 2 given. (used in Service::__construct())'); +}, Nette\InvalidStateException::class, '[Service of type Service] +Function bool() expects 1 parameter, 2 given. +Related to Service::__construct().'); diff --git a/tests/DI/Compiler.generatedAccessor.phpt b/tests/DI/Compiler.generatedAccessor.phpt index d6368d004..443770764 100644 --- a/tests/DI/Compiler.generatedAccessor.phpt +++ b/tests/DI/Compiler.generatedAccessor.phpt @@ -19,8 +19,7 @@ class Lorem interface ILoremAccessor { - /** @return Lorem */ - public function get(); + public function get(): Lorem; } diff --git a/tests/DI/Compiler.generatedFactory.nullableParameters.phpt b/tests/DI/Compiler.generatedFactory.nullableParameters.phpt deleted file mode 100644 index 43ca87089..000000000 --- a/tests/DI/Compiler.generatedFactory.nullableParameters.phpt +++ /dev/null @@ -1,74 +0,0 @@ -title = $title; - $this->foo = $foo; - $this->lorem = $lorem; - } -} - -$compiler = new DI\Compiler; -$container = createContainer($compiler, ' -services: - - article: - factory: Article(%title%, %foo%, %lorem%) - implement: IArticleFactory - parameters: [?string title, ?Foo foo, ?int lorem: null] - - article2: - implement: IArticleFactory - arguments: [%title%, %foo%, %lorem%] - parameters: [?string title, ?Foo foo, ?int lorem: null] - - article3: - implement: IArticleFactory -'); - -foreach (['article', 'article2', 'article3'] as $serviceName) { - $service = $container->getService($serviceName); - Assert::type(IArticleFactory::class, $service); - $article = $service->create('lorem-ipsum', $foo = new Foo, 1); - Assert::type(Article::class, $article); - Assert::same('lorem-ipsum', $article->title); - Assert::same($foo, $article->foo); - Assert::same(1, $article->lorem); - - $article = $service->create(null, null); - Assert::type(Article::class, $article); - Assert::null($article->title); - Assert::null($article->foo); - Assert::same($serviceName === 'article3' ? 1 : null, $article->lorem); -} diff --git a/tests/DI/Compiler.generatedFactory.phpt b/tests/DI/Compiler.generatedFactory.phpt index bc0161e0a..aafb12437 100644 --- a/tests/DI/Compiler.generatedFactory.phpt +++ b/tests/DI/Compiler.generatedFactory.phpt @@ -7,7 +7,6 @@ declare(strict_types=1); use Nette\DI; -use Nette\DI\Config\Adapters as Adapt; use Tester\Assert; @@ -16,10 +15,7 @@ require __DIR__ . '/../bootstrap.php'; interface ILoremFactory { - /** - * @return Lorem - */ - public function create(); + public function create(): Lorem; } class Lorem @@ -33,21 +29,9 @@ class Lorem } } -interface IFinderFactory -{ - /** - * @return Adapt\NeonAdapter comment - */ - public function create(); -} - interface IArticleFactory { - /** - * @param string - * @return Article - */ - public function create($title); + public function create($title): Article; } class Article @@ -98,11 +82,7 @@ class Baz interface IFooFactory { - /** - * @param Baz - * @return Foo - */ - public function create(?Baz $baz = null); + public function create(?Baz $baz = null): Foo; } class Dolor @@ -121,8 +101,7 @@ class Dolor interface DolorFactory { - /** @return Dolor */ - public function create(?Bar $bar, $foo); + public function create(?Bar $bar, $foo): Dolor; } @@ -142,8 +121,7 @@ class TestClass interface ITestClassFactory { - /** @return TestClass */ - public function create($bar); + public function create($bar): TestClass; } class TestExtension extends DI\CompilerExtension @@ -152,10 +130,9 @@ class TestExtension extends DI\CompilerExtension { $builder = $this->getContainerBuilder(); $builder->addFactoryDefinition('fooFactory2') - ->setParameters(['Baz baz' => null]) ->setImplement(IFooFactory::class) ->getResultDefinition() - ->setFactory(Foo::class) + ->setCreator(Foo::class) ->setArguments([1 => $builder::literal('$baz')]); $builder->addFactoryDefinition('overridenFactory') @@ -179,11 +156,6 @@ Assert::same($container->getService('ipsum'), $lorem->ipsum); Assert::type(ILoremFactory::class, $container->getByType(ILoremFactory::class)); -Assert::type(IFinderFactory::class, $container->getService('finder')); -$finder = $container->getService('finder')->create(); -Assert::type(Nette\DI\Config\Adapters\NeonAdapter::class, $finder); - - Assert::type(IArticleFactory::class, $container->getService('article')); $article = $container->getService('article')->create('nemam'); Assert::type(Article::class, $article); @@ -284,17 +256,16 @@ class Bad1 interface Bad2 { - public function create(Baz $bar); + public function create(Baz $bar): Bad1; } Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') - ->setImplement(Bad2::class) - ->getResultDefinition() - ->setFactory(Bad1::class); + ->setImplement(Bad2::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad2): Type of \$bar in Bad2::create() doesn't match type in Bad1 constructor."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad2] +Type of \$bar in Bad2::create() doesn't match type in Bad1 constructor."); @@ -307,17 +278,16 @@ class Bad3 interface Bad4 { - public function create($baz); + public function create($baz): Bad3; } Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') - ->setImplement(Bad4::class) - ->getResultDefinition() - ->setFactory(Bad3::class); + ->setImplement(Bad4::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad4): Unused parameter \$baz when implementing method Bad4::create(), did you mean \$bar?"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad4] +Unused parameter \$baz when implementing method Bad4::create(), did you mean \$bar?"); @@ -330,28 +300,27 @@ class Bad5 interface Bad6 { - public function create($baz); + public function create($baz): Bad5; } Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') - ->setImplement(Bad6::class) - ->getResultDefinition() - ->setFactory(Bad5::class); + ->setImplement(Bad6::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad6): Unused parameter \$baz when implementing method Bad6::create()."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad6] +Unused parameter \$baz when implementing method Bad6::create()."); interface Bad7 { - public function get(); + public function get(): stdClass; } Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition(stdClass::class)->setFactory(stdClass::class); + $builder->addDefinition(stdClass::class)->setCreator(stdClass::class); $builder->addAccessorDefinition('one') ->setImplement(Bad7::class) ->setClass(stdClass::class) diff --git a/tests/DI/Compiler.generatedFactory.returnTypes.phpt b/tests/DI/Compiler.generatedFactory.returnTypes.phpt index 2b05d9257..aa3dc92bf 100644 --- a/tests/DI/Compiler.generatedFactory.returnTypes.phpt +++ b/tests/DI/Compiler.generatedFactory.returnTypes.phpt @@ -37,14 +37,11 @@ $compiler = new DI\Compiler; $container = createContainer($compiler, ' services: article: - factory: Article(%title%) + factory: Article implement: IArticleFactory - parameters: [title] article2: implement: IArticleFactory - arguments: [%title%] - parameters: [title] article3: implement: IArticleFactory diff --git a/tests/DI/Compiler.generatedFactory.scalarParameters.phpt b/tests/DI/Compiler.generatedFactory.scalarParameters.phpt deleted file mode 100644 index be92ac892..000000000 --- a/tests/DI/Compiler.generatedFactory.scalarParameters.phpt +++ /dev/null @@ -1,63 +0,0 @@ -title = $title; - } -} - -$compiler = new DI\Compiler; -$container = createContainer($compiler, ' -services: - article: - factory: Article(%title%) - implement: IArticleFactory - parameters: [string title] - - article2: - implement: IArticleFactory - arguments: [%title%] - parameters: [string title] - - article3: - implement: IArticleFactory -'); - -Assert::type(IArticleFactory::class, $container->getService('article')); -$article = $container->getService('article')->create('lorem-ipsum'); -Assert::type(Article::class, $article); -Assert::same('lorem-ipsum', $article->title); - -Assert::type(IArticleFactory::class, $container->getService('article2')); -$article = $container->getService('article2')->create('lorem-ipsum'); -Assert::type(Article::class, $article); -Assert::same('lorem-ipsum', $article->title); - -Assert::type(IArticleFactory::class, $container->getService('article3')); -$article = $container->getService('article3')->create('lorem-ipsum'); -Assert::type(Article::class, $article); -Assert::same('lorem-ipsum', $article->title); diff --git a/tests/DI/Compiler.loadConfig.include.phpt b/tests/DI/Compiler.loadConfig.include.phpt index 4f3f78b1f..26d00f815 100644 --- a/tests/DI/Compiler.loadConfig.include.phpt +++ b/tests/DI/Compiler.loadConfig.include.phpt @@ -41,7 +41,7 @@ Assert::equal([ 'services' => [ 'a' => (object) [ 'type' => null, - 'factory' => stdClass::class, + 'create' => stdClass::class, 'arguments' => [], 'setup' => [], 'inject' => null, diff --git a/tests/DI/Compiler.referenceBug.phpt b/tests/DI/Compiler.referenceBug.phpt index 9d1311ded..4351067ae 100644 --- a/tests/DI/Compiler.referenceBug.phpt +++ b/tests/DI/Compiler.referenceBug.phpt @@ -32,7 +32,7 @@ services: - stdClass a: Lorem(x: true) b: Lorem(x: Lorem(x: true)) - c: Lorem(@@test) + c: Lorem("@test") '); diff --git a/tests/DI/Compiler.services.autowiring.phpt b/tests/DI/Compiler.services.autowiring.phpt index 57a5388f0..ec043dcd2 100644 --- a/tests/DI/Compiler.services.autowiring.phpt +++ b/tests/DI/Compiler.services.autowiring.phpt @@ -15,8 +15,7 @@ require __DIR__ . '/../bootstrap.php'; class Factory { - /** @return Model auto-wiring using annotation */ - public static function createModel() + public static function createModel(): Model { return new Model; } @@ -53,7 +52,7 @@ services: factory: Factory()::createModel setup: # local methods - - test(...) + - test(_) - @model::test() - @self::test() diff --git a/tests/DI/Compiler.services.create.phpt b/tests/DI/Compiler.services.create.phpt index 26a77e850..e9140ceea 100644 --- a/tests/DI/Compiler.services.create.phpt +++ b/tests/DI/Compiler.services.create.phpt @@ -15,8 +15,7 @@ require __DIR__ . '/../bootstrap.php'; class Factory { - /** @return Lorem */ - public static function createLorem($arg) + public static function createLorem($arg): Lorem { return new Lorem(__METHOD__ . ' ' . implode(' ', func_get_args())); } @@ -31,8 +30,7 @@ class Lorem } - /** @return Lorem */ - public function foo(...$args) + public function foo(...$args): self { $this->foo = $args; return $this; diff --git a/tests/DI/CompilerExtension.loadDefinitionsFromConfig.phpt b/tests/DI/CompilerExtension.loadDefinitionsFromConfig.phpt index 08cd2b8b0..17e1c2d04 100644 --- a/tests/DI/CompilerExtension.loadDefinitionsFromConfig.phpt +++ b/tests/DI/CompilerExtension.loadDefinitionsFromConfig.phpt @@ -27,6 +27,6 @@ $compilerExtension = (new CompilerExtension)->setCompiler($compiler, 'blog'); $compilerExtension->loadDefinitionsFromConfig($config['services']); -Assert::same('@blog.articles', $builder->getDefinition('blog.comments')->getFactory()->arguments[1]); -Assert::equal(new Reference('blog.articles'), $builder->getDefinition('blog.articlesList')->getFactory()->arguments[0]); -Assert::equal(new Reference('blog.comments'), $builder->getDefinition('blog.commentsControl')->getFactory()->arguments[0]->getEntity()); +Assert::same('@blog.articles', $builder->getDefinition('blog.comments')->getCreator()->arguments[1]); +Assert::equal(new Reference('blog.articles'), $builder->getDefinition('blog.articlesList')->getCreator()->arguments[0]); +Assert::equal(new Reference('blog.comments'), $builder->getDefinition('blog.commentsControl')->getCreator()->arguments[0]->getEntity()); diff --git a/tests/DI/CompilerExtension.validateConfig.phpt b/tests/DI/CompilerExtension.validateConfig.phpt index 1c6f2f35b..298603945 100644 --- a/tests/DI/CompilerExtension.validateConfig.phpt +++ b/tests/DI/CompilerExtension.validateConfig.phpt @@ -14,7 +14,7 @@ require __DIR__ . '/../bootstrap.php'; class MyExtension extends Nette\DI\CompilerExtension { - protected $name = 'my'; + protected string $name = 'my'; } diff --git a/tests/DI/ConstantsExtension.basic.phpt b/tests/DI/ConstantsExtension.basic.phpt deleted file mode 100644 index 421e49c2c..000000000 --- a/tests/DI/ConstantsExtension.basic.phpt +++ /dev/null @@ -1,26 +0,0 @@ -addExtension('constants', new Nette\DI\Extensions\ConstantsExtension); -$container = createContainer($compiler, ' -constants: - a: hello - A: WORLD -'); -$container->initialize(); - -Assert::same('hello', a); -Assert::same('WORLD', A); diff --git a/tests/DI/Container.dynamic.php80.phpt b/tests/DI/Container.dynamic.php80.phpt deleted file mode 100644 index a4166f118..000000000 --- a/tests/DI/Container.dynamic.php80.phpt +++ /dev/null @@ -1,22 +0,0 @@ -addService('six', function (): stdClass|Closure {}); // @ triggers service should be defined as "imported" - $container->getService('six'); -}, Nette\InvalidStateException::class, "Return type of closure is not expected to be nullable/union/intersection/built-in, 'stdClass|Closure' given."); diff --git a/tests/DI/Container.dynamic.phpt b/tests/DI/Container.dynamic.phpt index 827c5d475..9b44597e5 100644 --- a/tests/DI/Container.dynamic.phpt +++ b/tests/DI/Container.dynamic.phpt @@ -40,9 +40,7 @@ test('', function () use ($container) { test('closure', function () use ($container) { - @$container->addService('four', function () { // @ triggers service should be defined as "imported" - return new Service; - }); + @$container->addService('four', fn() => new Service); Assert::true($container->hasService('four')); Assert::false($container->isCreated('four')); @@ -55,9 +53,7 @@ test('closure', function () use ($container) { test('closure with typehint', function () use ($container) { - @$container->addService('five', function (): Service { // @ triggers service should be defined as "imported" - return new Service; - }); + @$container->addService('five', fn(): Service => new Service); Assert::same(Service::class, $container->getServiceType('five')); }); @@ -68,3 +64,10 @@ Assert::exception(function () use ($container) { @$container->addService('six', function () {}); // @ triggers service should be defined as "imported" $container->getService('six'); }, Nette\UnexpectedValueException::class, "Unable to create service 'six', value returned by closure is not object."); + + +// union type +Assert::exception(function () use ($container) { + @$container->addService('six', function (): stdClass|Closure {}); // @ triggers service should be defined as "imported" + $container->getService('six'); +}, Nette\InvalidStateException::class, "Return type of closure is not expected to be nullable/union/intersection/built-in, 'stdClass|Closure' given."); diff --git a/tests/DI/Container.errors.phpt b/tests/DI/Container.errors.phpt index 58e5d9ee1..244c46786 100644 --- a/tests/DI/Container.errors.phpt +++ b/tests/DI/Container.errors.phpt @@ -20,10 +20,6 @@ Assert::exception(function () use ($container, $service) { $container->addService('', $service); }, Nette\InvalidArgumentException::class, 'Service name must be a non-empty string.'); -Assert::exception(function () use ($container) { - $container->addService('one', null); -}, Nette\InvalidArgumentException::class, "Service 'one' must be a object, NULL given."); - Assert::exception(function () use ($container) { $container->getService('one'); }, Nette\DI\MissingServiceException::class, "Service 'one' not found."); diff --git a/tests/DI/Container.getServiceType.phpt b/tests/DI/Container.getServiceType.phpt index 9790cd102..d1dc352ee 100644 --- a/tests/DI/Container.getServiceType.phpt +++ b/tests/DI/Container.getServiceType.phpt @@ -15,7 +15,7 @@ require __DIR__ . '/../bootstrap.php'; class MyContainer extends Container { - protected $aliases = [ + protected array $aliases = [ 'three' => 'one', ]; diff --git a/tests/DI/Container.inject.properties.phpt b/tests/DI/Container.inject.properties.phpt index b633c0f8b..8b0203539 100644 --- a/tests/DI/Container.inject.properties.phpt +++ b/tests/DI/Container.inject.properties.phpt @@ -23,20 +23,17 @@ class Foo implements IFoo class Test1 { - /** @inject @var stdClass */ - public $varA; - - /** @var stdClass @inject */ - public $varB; + /** @inject */ + public stdClass $varA; } class Test2 extends Test1 { - /** @var stdClass @inject */ - public $varC; + /** @inject */ + public stdClass $varC; - /** @var IFoo @inject */ - public $varD; + /** @inject */ + public IFoo $varD; } @@ -52,6 +49,5 @@ $container = createContainer($builder); $test = new Test2; $container->callInjects($test); Assert::type(stdClass::class, $test->varA); -Assert::type(stdClass::class, $test->varB); Assert::type(stdClass::class, $test->varC); Assert::type(Foo::class, $test->varD); diff --git a/tests/DI/Container.static-dynamic.phpt b/tests/DI/Container.static-dynamic.phpt index 7d9e2a40d..1fde5b2c3 100644 --- a/tests/DI/Container.static-dynamic.phpt +++ b/tests/DI/Container.static-dynamic.phpt @@ -46,7 +46,7 @@ test('', function () { test('closure', function () { $container = new MyContainer; - $container->addService('one', function () { return new stdClass; }); + $container->addService('one', fn() => new stdClass); Assert::true($container->hasService('one')); Assert::same('', $container->getServiceType('one')); @@ -58,7 +58,7 @@ test('closure', function () { test('closure & typehint', function () { $container = new MyContainer; - $container->addService('one', function (): stdClass { return new stdClass; }); + $container->addService('one', fn(): stdClass => new stdClass); Assert::same(stdClass::class, $container->getServiceType('one')); Assert::true($container->hasService('one')); @@ -73,7 +73,7 @@ test('closure & matching typehint', function () { { } - $container->addService('typehint', function (): MyClass { return new MyClass; }); + $container->addService('typehint', fn(): MyClass => new MyClass); Assert::same(MyClass::class, $container->getServiceType('typehint')); Assert::true($container->hasService('typehint')); @@ -83,11 +83,11 @@ test('closure & matching typehint', function () { Assert::exception(function () { // closure & wrong typehint $container = new MyContainer; - $container->addService('typehint', function () { return new DateTime; }); + $container->addService('typehint', fn() => new DateTime); }, Nette\InvalidArgumentException::class, "Service 'typehint' must be instance of stdClass, add typehint to closure."); Assert::exception(function () { // closure & wrong typehint $container = new MyContainer; - $container->addService('typehint', function (): DateTime { return new DateTime; }); + $container->addService('typehint', fn(): DateTime => new DateTime); }, Nette\InvalidArgumentException::class, "Service 'typehint' must be instance of stdClass, DateTime given."); diff --git a/tests/DI/ContainerBuilder.accessor.phpt b/tests/DI/ContainerBuilder.accessor.phpt index 940538e26..73d39bcff 100644 --- a/tests/DI/ContainerBuilder.accessor.phpt +++ b/tests/DI/ContainerBuilder.accessor.phpt @@ -15,13 +15,7 @@ require __DIR__ . '/../bootstrap.php'; interface StdClassAccessor { - public function get(); -} - -interface AnnotatedAccessor -{ - /** @return stdClass */ - public function get(); + public function get(): stdClass; } class AccessorReceiver @@ -38,19 +32,16 @@ class AccessorReceiver $builder = new DI\ContainerBuilder; $builder->addDefinition('service') - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $builder->addDefinition('service2') ->setAutowired(false) - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $builder->addAccessorDefinition('one') ->setImplement(StdClassAccessor::class) ->setReference(stdClass::class); -$builder->addAccessorDefinition('two') - ->setImplement(AnnotatedAccessor::class); - $builder->addAccessorDefinition('three') ->setImplement(StdClassAccessor::class) ->setAutowired(false) @@ -65,9 +56,6 @@ $container = createContainer($builder); Assert::type(StdClassAccessor::class, $container->getService('one')); Assert::same($container->getService('one')->get(), $container->getService('service')); -Assert::type(AnnotatedAccessor::class, $container->getService('two')); -Assert::same($container->getService('two')->get(), $container->getService('service')); - Assert::type(StdClassAccessor::class, $container->getService('three')); Assert::same($container->getService('three')->get(), $container->getService('service2')); diff --git a/tests/DI/ContainerBuilder.aliases.phpt b/tests/DI/ContainerBuilder.aliases.phpt index 85c7e4e7b..2ff62dc18 100644 --- a/tests/DI/ContainerBuilder.aliases.phpt +++ b/tests/DI/ContainerBuilder.aliases.phpt @@ -19,49 +19,49 @@ class Service interface ServiceFactory { - public function create(); + public function create(): Service; } interface ServiceFactory2 { - public function create(); + public function create(): Service; } $builder = new DI\ContainerBuilder; $builder->addDefinition('aliasForFactory') - ->setFactory('@serviceFactory'); + ->setCreator('@serviceFactory'); $builder->addDefinition('aliasForFactoryViaClass') - ->setFactory('@\ServiceFactory'); + ->setCreator('@\ServiceFactory'); $builder->addFactoryDefinition('aliasedFactory') ->setImplement(ServiceFactory::class) ->setAutowired(false) ->getResultDefinition() - ->setFactory('@serviceFactory'); + ->setCreator('@service'); $builder->addFactoryDefinition('aliasedFactoryViaClass') ->setImplement(ServiceFactory::class) ->setAutowired(false) ->getResultDefinition() - ->setFactory('@\ServiceFactory'); + ->setCreator('@\Service'); $builder->addDefinition('aliasedService') - ->setFactory('@service'); + ->setCreator('@service'); $builder->addDefinition('aliasedServiceViaClass') - ->setFactory('@\Service'); + ->setCreator('@\Service'); $builder->addFactoryDefinition('serviceFactory') ->setImplement(ServiceFactory::class) ->getResultDefinition() - ->setFactory('@service'); + ->setCreator('@service'); $builder->addFactoryDefinition('serviceFactoryViaClass') ->setImplement(ServiceFactory2::class) ->getResultDefinition() - ->setFactory('@\Service'); + ->setCreator('@\Service'); $builder->addDefinition('service') ->setType(Service::class); diff --git a/tests/DI/ContainerBuilder.aliases2.phpt b/tests/DI/ContainerBuilder.aliases2.phpt index 4833db445..944cbbbe5 100644 --- a/tests/DI/ContainerBuilder.aliases2.phpt +++ b/tests/DI/ContainerBuilder.aliases2.phpt @@ -19,12 +19,12 @@ class Service interface ServiceFactory { - public function create(); + public function create(): Service; } interface ServiceFactory2 { - public function create(); + public function create(): Service; } $builder = new DI\ContainerBuilder; @@ -32,12 +32,12 @@ $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('serviceFactory') ->setImplement(ServiceFactory::class) ->getResultDefinition() - ->setFactory('@service'); + ->setCreator('@service'); $builder->addFactoryDefinition('serviceFactoryViaClass') ->setImplement(ServiceFactory2::class) ->getResultDefinition() - ->setFactory('@\Service'); + ->setCreator('@\Service'); $builder->addDefinition('service') ->setType(stdClass::class); diff --git a/tests/DI/ContainerBuilder.autowiring.chaining.phpt b/tests/DI/ContainerBuilder.autowiring.chaining.phpt index b4bb276b4..a8783d4ba 100644 --- a/tests/DI/ContainerBuilder.autowiring.chaining.phpt +++ b/tests/DI/ContainerBuilder.autowiring.chaining.phpt @@ -15,8 +15,7 @@ require __DIR__ . '/../bootstrap.php'; class Foo { - /** @return Bar */ - public static function create(Test $test) + public static function create(Test $test): Bar { return new Bar; } @@ -29,8 +28,7 @@ class Foo class Bar { - /** @return Baz */ - public function create(Test $test) + public function create(Test $test): Baz { return new Baz; } diff --git a/tests/DI/ContainerBuilder.autowiring.implement.phpt b/tests/DI/ContainerBuilder.autowiring.implement.phpt index 92c82783f..6c9ac20d9 100644 --- a/tests/DI/ContainerBuilder.autowiring.implement.phpt +++ b/tests/DI/ContainerBuilder.autowiring.implement.phpt @@ -15,8 +15,7 @@ require __DIR__ . '/../bootstrap.php'; interface ITestFactory { - /** @return Test */ - public function create(); + public function create(): Test; } class Foo diff --git a/tests/DI/ContainerBuilder.autowiring.novalue.phpt b/tests/DI/ContainerBuilder.autowiring.novalue.phpt index 1a9b7cca4..3aee26fda 100644 --- a/tests/DI/ContainerBuilder.autowiring.novalue.phpt +++ b/tests/DI/ContainerBuilder.autowiring.novalue.phpt @@ -24,7 +24,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType(Foo::class); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Foo): Parameter \$x in Foo::__construct() has no class type or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "[Service 'foo' of type Foo] +Parameter \$x in Foo::__construct() has no class type or default value, so its value must be specified."); class Bar @@ -38,7 +39,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType(Bar::class); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Bar): Parameter \$x in Bar::__construct() has no class type or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "[Service 'foo' of type Bar] +Parameter \$x in Bar::__construct() has no class type or default value, so its value must be specified."); class Bar2 diff --git a/tests/DI/ContainerBuilder.basic.phpt b/tests/DI/ContainerBuilder.basic.phpt index 6d761791a..02e380000 100644 --- a/tests/DI/ContainerBuilder.basic.phpt +++ b/tests/DI/ContainerBuilder.basic.phpt @@ -19,8 +19,7 @@ class Service public $methods; - /** @return Service */ - public static function create(?DI\Container $container = null) + public static function create(?DI\Container $container = null): self { return new self(array_slice(func_get_args(), 1)); } @@ -41,31 +40,31 @@ class Service $builder = new DI\ContainerBuilder; $builder->addDefinition('one') - ->setFactory(Service::class, ['@@string']); + ->setCreator(Service::class, ['@@string']); $builder->addDefinition('three') - ->setFactory(Service::class, ['a', 'b']); + ->setCreator(Service::class, ['a', 'b']); $builder->addDefinition('four') - ->setFactory(Service::class, ['a', 'b']) + ->setCreator(Service::class, ['a', 'b']) ->addSetup('methodA', ['a', 'b']) ->addSetup('@four::methodB', [1, 2]) ->addSetup('methodC', ['@self', '@container']) ->addSetup('methodD', ['@one']); $builder->addDefinition('five', null) - ->setFactory('Service::create'); + ->setCreator('Service::create'); $six = $builder->addDefinition('six') - ->setFactory('Service::create', ['@container', 'a', 'b']) + ->setCreator('Service::create', ['@container', 'a', 'b']) ->addSetup(['@six', 'methodA'], ['a', 'b']); $builder->addDefinition('seven') - ->setFactory([$six, 'create'], ['@container', $six]) + ->setCreator([$six, 'create'], ['@container', $six]) ->addSetup([$six, 'methodA']) ->addSetup('$service->methodA(?)', ['a']); $six = $builder->addDefinition('eight') - ->setFactory('Service::create', [new Reference('container'), 'a', 'b']) + ->setCreator('Service::create', [new Reference('container'), 'a', 'b']) ->addSetup([new Reference('self'), 'methodA'], [new Reference('eight'), new Reference('self')]) ->addSetup([new Reference('eight'), 'methodB']) ->addSetup([new Reference('six'), 'methodC']) diff --git a/tests/DI/ContainerBuilder.basic2.phpt b/tests/DI/ContainerBuilder.basic2.phpt index 087f8921b..a042e2e2f 100644 --- a/tests/DI/ContainerBuilder.basic2.phpt +++ b/tests/DI/ContainerBuilder.basic2.phpt @@ -20,8 +20,7 @@ class Factory } - /** @return Factory */ - public static function create() + public static function create(): self { return new self; } @@ -30,7 +29,7 @@ class Factory $builder = new DI\ContainerBuilder; $builder->addDefinition('one') - ->setFactory('Factory::create'); + ->setCreator('Factory::create'); $container = createContainer($builder); diff --git a/tests/DI/ContainerBuilder.basic3.phpt b/tests/DI/ContainerBuilder.basic3.phpt index 4bbcd7784..ad684c8ef 100644 --- a/tests/DI/ContainerBuilder.basic3.phpt +++ b/tests/DI/ContainerBuilder.basic3.phpt @@ -13,8 +13,7 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -/** @return stdClass */ -function create() +function create(): stdClass { return new stdClass; } @@ -22,7 +21,7 @@ function create() $builder = new DI\ContainerBuilder; $builder->addDefinition('one') - ->setFactory('::create'); + ->setCreator('::create'); $container = createContainer($builder); diff --git a/tests/DI/ContainerBuilder.basic4.phpt b/tests/DI/ContainerBuilder.basic4.phpt index 6fa263fc5..48663dcb2 100644 --- a/tests/DI/ContainerBuilder.basic4.phpt +++ b/tests/DI/ContainerBuilder.basic4.phpt @@ -9,8 +9,7 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -/** @return ClassA */ -function func() +function func(): ClassA { return new ClassA; } @@ -18,8 +17,7 @@ function func() class ClassA { - /** @return ClassB */ - public function funcA(stdClass $arg) + public function funcA(stdClass $arg): ClassB { return new ClassB; } @@ -27,8 +25,7 @@ class ClassA class ClassB { - /** @return ClassC */ - public function funcB(stdClass $arg) + public function funcB(stdClass $arg): ClassC { return new ClassC; } diff --git a/tests/DI/ContainerBuilder.byClass.phpt b/tests/DI/ContainerBuilder.byClass.phpt index 1b4c98d4d..744a47218 100644 --- a/tests/DI/ContainerBuilder.byClass.phpt +++ b/tests/DI/ContainerBuilder.byClass.phpt @@ -35,8 +35,7 @@ class AnnotatedFactory public $methods; - /** @return stdClass */ - public function create() + public function create(): stdClass { $this->methods[] = [__FUNCTION__, func_get_args()]; return new stdClass; @@ -57,8 +56,7 @@ class UninstantiableFactory } - /** @return stdClass */ - public function create() + public function create(): stdClass { } } @@ -74,30 +72,30 @@ $builder->addDefinition('annotatedFactory') $builder->addDefinition('two') ->setType(stdClass::class) ->setAutowired(false) - ->setFactory('@factory::create', ['@\Factory']) + ->setCreator('@factory::create', ['@\Factory']) ->addSetup(['@\Factory', 'create'], ['@\Factory']); $builder->addDefinition('three') ->setType(stdClass::class) ->setAutowired(false) - ->setFactory('@\Factory::create', ['@\Factory']); + ->setCreator('@\Factory::create', ['@\Factory']); $builder->addDefinition('four') ->setAutowired(false) - ->setFactory('@\AnnotatedFactory::create'); + ->setCreator('@\AnnotatedFactory::create'); $builder->addDefinition('five') ->setType(stdClass::class) ->setAutowired(false) - ->setFactory('@\IFactory::create'); + ->setCreator('@\IFactory::create'); $builder->addDefinition('uninstantiableFactory') ->setType(UninstantiableFactory::class) - ->setFactory('UninstantiableFactory::getInstance'); + ->setCreator('UninstantiableFactory::getInstance'); $builder->addDefinition('six') ->setAutowired(false) - ->setFactory('@\UninstantiableFactory::create'); + ->setCreator('@\UninstantiableFactory::create'); diff --git a/tests/DI/ContainerBuilder.create.error.phpt b/tests/DI/ContainerBuilder.create.error.phpt index b4d6381da..259e6b684 100644 --- a/tests/DI/ContainerBuilder.create.error.phpt +++ b/tests/DI/ContainerBuilder.create.error.phpt @@ -17,52 +17,59 @@ require __DIR__ . '/../bootstrap.php'; Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setType('X')->setFactory('Unknown'); -}, Nette\InvalidArgumentException::class, "Service 'one': Class or interface 'X' not found."); + $builder->addDefinition('one')->setType('X')->setCreator('Unknown'); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Class or interface 'X' not found."); Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition(null)->setFactory('Unknown'); + $builder->addDefinition(null)->setCreator('Unknown'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service (Unknown::__construct()): Class 'Unknown' not found."); +}, Nette\DI\ServiceCreationException::class, "[Service of type Unknown] +Class 'Unknown' not found."); Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('@two'); - $builder->addDefinition('two')->setFactory('Unknown'); + $builder->addDefinition('one')->setCreator('@two'); + $builder->addDefinition('two')->setCreator('Unknown'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'two': Class 'Unknown' not found."); +}, Nette\InvalidStateException::class, "[Service 'two'] +Class 'Unknown' not found."); Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory(new Reference('two')); - $builder->addDefinition('two')->setFactory('Unknown'); + $builder->addDefinition('one')->setCreator(new Reference('two')); + $builder->addDefinition('two')->setCreator('Unknown'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'two': Class 'Unknown' not found."); +}, Nette\InvalidStateException::class, "[Service 'two'] +Class 'Unknown' not found."); Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('stdClass::foo'); + $builder->addDefinition('one')->setCreator('stdClass::foo'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method stdClass::foo() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method stdClass::foo() is not callable."); Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('Nette\DI\Container::foo'); // has __magic + $builder->addDefinition('one')->setCreator('Nette\DI\Container::foo'); // has __magic $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method Nette\\DI\\Container::foo() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method Nette\\DI\\Container::foo() is not callable."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement('Unknown'); -}, Nette\InvalidArgumentException::class, "Service 'one': Interface 'Unknown' not found."); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Interface 'Unknown' not found."); @@ -75,8 +82,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement(Bad4::class); - $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad4): Return type of Bad4::create() is not declared."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Return type of Bad4::create() is not declared."); interface Bad5 @@ -89,7 +96,8 @@ Assert::exception(function () { $builder->addAccessorDefinition('one') ->setImplement(Bad5::class); $builder->complete(); -}, Nette\InvalidArgumentException::class, "Service 'one': Method Bad5::get() must have no parameters."); +}, Nette\InvalidArgumentException::class, "[Service 'one'] +Method Bad5::get() must have no parameters."); class Bad6 @@ -101,9 +109,10 @@ class Bad6 Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('Bad6::create'); + $builder->addDefinition('one')->setCreator('Bad6::create'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service 'one': Method Bad6::create() is not callable."); +}, Nette\DI\ServiceCreationException::class, "[Service 'one'] +Method Bad6::create() is not callable."); class Bad7 @@ -115,9 +124,10 @@ class Bad7 Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('Bad7::create'); + $builder->addDefinition('one')->setCreator('Bad7::create'); $builder->complete(); -}, Nette\DI\ServiceCreationException::class, "Service 'one': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'one'] +Unknown service type, specify it or declare return type of factory method."); class Bad8 @@ -131,7 +141,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setType(Bad8::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad8): Class Bad8 has private constructor."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad8] +Class Bad8 has private constructor."); class Good @@ -144,16 +155,20 @@ class Good // fail in argument Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory(Good::class, [new Statement('Unknown')]); + $builder->addDefinition('one')->setCreator(Good::class, [new Statement('Unknown')]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class 'Unknown' not found. (used in Good::__construct())"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Good] +Class 'Unknown' not found. +Related to Good::__construct()."); // fail in argument Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory(Good::class, [new Statement(Bad8::class)]); + $builder->addDefinition('one')->setCreator(Good::class, [new Statement(Bad8::class)]); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Good): Class Bad8 has private constructor. (used in Good::__construct())"); +}, Nette\InvalidStateException::class, "[Service 'one' of type Good] +Class Bad8 has private constructor. +Related to Good::__construct()."); abstract class Bad9 @@ -168,7 +183,8 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('one')->setType(Bad9::class); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of Bad9): Class Bad9 is abstract."); +}, Nette\InvalidStateException::class, "[Service 'one' of type Bad9] +Class Bad9 is abstract."); trait Bad10 @@ -181,9 +197,10 @@ trait Bad10 // trait cannot be instantiated Assert::exception(function () { $builder = new DI\ContainerBuilder; - $builder->addDefinition('one')->setFactory('Bad10::method'); + $builder->addDefinition('one')->setCreator('Bad10::method'); $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one': Method Bad10::method() is not callable."); +}, Nette\InvalidStateException::class, "[Service 'one'] +Method Bad10::method() is not callable."); class ConstructorParam @@ -208,7 +225,9 @@ services: b: stdClass bad: ConstructorParam '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b (required by \$x in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type ConstructorParam] +Multiple services of type stdClass found: a, b +Required by \$x in ConstructorParam::__construct()."); // forced autowiring fail @@ -219,7 +238,9 @@ services: b: stdClass bad: ConstructorParam(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of ConstructorParam): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type ConstructorParam] +Multiple services of type stdClass found: a, b +Related to ConstructorParam::__construct()."); // autowiring fail in chain @@ -230,7 +251,9 @@ services: b: stdClass bad: MethodParam()::foo() '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo()."); // forced autowiring fail in chain @@ -241,7 +264,9 @@ services: b: stdClass bad: MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo()."); // autowiring fail in argument @@ -252,7 +277,10 @@ services: b: stdClass bad: Good(ConstructorParam()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (required by \$x in ConstructorParam::__construct()) (used in Good::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Required by \$x in ConstructorParam::__construct(). +Related to Good::__construct()."); // forced autowiring fail in argument @@ -263,7 +291,9 @@ services: b: stdClass bad: Good(ConstructorParam(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in ConstructorParam::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to ConstructorParam::__construct()."); // autowiring fail in chain in argument @@ -274,7 +304,10 @@ services: b: stdClass bad: Good(MethodParam()::foo()) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo()) (used in Good::__construct())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo(). +Related to Good::__construct()."); // forced autowiring fail in chain in argument @@ -285,7 +318,9 @@ services: b: stdClass bad: Good(MethodParam()::foo(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo()."); // forced autowiring fail in property passing @@ -299,7 +334,9 @@ services: setup: - $a = @\stdClass '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::\$a)"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to \$a in setup."); // autowiring fail in rich property passing @@ -313,7 +350,9 @@ services: setup: - $a = MethodParam()::foo(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo() in setup."); // autowiring fail in method calling @@ -327,7 +366,9 @@ services: setup: - foo '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of MethodParam): Multiple services of type stdClass found: a, b (required by \$x in MethodParam::foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type MethodParam] +Multiple services of type stdClass found: a, b +Required by \$x in MethodParam::foo()."); // forced autowiring fail in method calling @@ -341,7 +382,9 @@ services: setup: - bar(@\stdClass) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in @bad::bar())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to bar() in setup."); // autowiring fail in rich method calling @@ -355,4 +398,6 @@ services: setup: - bar(MethodParam()::foo(@\stdClass)) '); -}, Nette\DI\ServiceCreationException::class, "Service 'bad' (type of Good): Multiple services of type stdClass found: a, b (used in foo())"); +}, Nette\DI\ServiceCreationException::class, "[Service 'bad' of type Good] +Multiple services of type stdClass found: a, b +Related to MethodParam()::foo() in setup."); diff --git a/tests/DI/ContainerBuilder.create.resolveClass.phpt b/tests/DI/ContainerBuilder.create.resolveClass.phpt index 4b6d9efa8..006cb75c7 100644 --- a/tests/DI/ContainerBuilder.create.resolveClass.phpt +++ b/tests/DI/ContainerBuilder.create.resolveClass.phpt @@ -31,7 +31,7 @@ $builder->addDefinition('one') ->setType(Factory::class); $builder->addDefinition('two') - ->setFactory('@one::createBar'); + ->setCreator('@one::createBar'); $container = createContainer($builder); diff --git a/tests/DI/ContainerBuilder.create.rich.phpt b/tests/DI/ContainerBuilder.create.rich.phpt index b26fdb0af..6bb079636 100644 --- a/tests/DI/ContainerBuilder.create.rich.phpt +++ b/tests/DI/ContainerBuilder.create.rich.phpt @@ -16,8 +16,7 @@ require __DIR__ . '/../bootstrap.php'; class Factory { - /** @return Obj */ - public function create() + public function create(): Obj { return new Obj; } @@ -31,8 +30,7 @@ class Factory class Obj { - /** @return Obj */ - public function foo(...$args) + public function foo(...$args): self { $this->args[] = $args; return $this; @@ -42,11 +40,11 @@ class Obj $builder = new DI\ContainerBuilder; $one = $builder->addDefinition('one') - ->setFactory([new Statement(Factory::class), 'create']) + ->setCreator([new Statement(Factory::class), 'create']) ->addSetup([new Statement(Factory::class), 'mark'], ['@self']); $two = $builder->addDefinition('two') - ->setFactory([new Statement([$one, 'foo'], [1]), 'foo'], [2]); + ->setCreator([new Statement([$one, 'foo'], [1]), 'foo'], [2]); $container = createContainer($builder); diff --git a/tests/DI/ContainerBuilder.error.phpt b/tests/DI/ContainerBuilder.error.phpt index 3bef4bab2..46e690429 100644 --- a/tests/DI/ContainerBuilder.error.phpt +++ b/tests/DI/ContainerBuilder.error.phpt @@ -7,6 +7,7 @@ declare(strict_types=1); use Nette\DI; +use Nette\DI\Definitions\Statement; use Tester\Assert; @@ -20,7 +21,8 @@ $builder->addDefinition('one') Assert::exception(function () use ($builder) { $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of stdClass): Expected function, method or property name, '1234' given."); +}, Nette\InvalidStateException::class, "[Service 'one' of type stdClass] +Expected function, method or property name, '1234' given."); @@ -43,4 +45,28 @@ $builder->addDefinition('one') Assert::exception(function () use ($builder) { $builder->complete(); -}, Nette\InvalidStateException::class, "Service 'one' (type of stdClass): Missing argument for \$prop[]."); +}, Nette\InvalidStateException::class, "[Service 'one' of type stdClass] +Missing argument for \$prop[]."); + + + +$builder = new DI\ContainerBuilder; +$builder->addDefinition(null) + ->setFactory([new Statement('Unknown'), 'foo']); + +Assert::exception(function () use ($builder) { + $builder->complete(); +}, Nette\DI\ServiceCreationException::class, "[Service Unknown()::foo()] +Class 'Unknown' not found."); + + + +$builder = new DI\ContainerBuilder; +$builder->addDefinition(null) + ->setFactory('stdClass') + ->addSetup([new Statement('Unknown'), 'foo']); + +Assert::exception(function () use ($builder) { + $builder->complete(); +}, Nette\DI\ServiceCreationException::class, "[Service of type stdClass] +Class 'Unknown' not found."); diff --git a/tests/DI/ContainerBuilder.factory.arguments.phpt b/tests/DI/ContainerBuilder.factory.arguments.phpt index 9af2779e3..8967dd02b 100644 --- a/tests/DI/ContainerBuilder.factory.arguments.phpt +++ b/tests/DI/ContainerBuilder.factory.arguments.phpt @@ -26,8 +26,7 @@ class Foo interface FooFactory { - /** @return Foo */ - public function create(); + public function create(): Foo; } diff --git a/tests/DI/ContainerBuilder.factory.params.phpt b/tests/DI/ContainerBuilder.factory.params.phpt index 2fbe0a464..fcadb2165 100644 --- a/tests/DI/ContainerBuilder.factory.params.phpt +++ b/tests/DI/ContainerBuilder.factory.params.phpt @@ -23,35 +23,20 @@ $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement(StdClassFactory::class) ->getResultDefinition() - ->setFactory(stdClass::class) + ->setCreator(stdClass::class) ->addSetup('$a', [$builder::literal('$a')]); -$builder->addFactoryDefinition('two') - ->setParameters(['stdClass foo', 'array bar', 'foobar' => null]) - ->setImplement(StdClassFactory::class) - ->getResultDefinition() - ->setFactory(stdClass::class) - ->addSetup('$a', [$builder::literal('$foo')]); - $builder->addDefinition('three') ->setType(stdClass::class); $builder->addDefinition('four') - ->setFactory('@one::create', [1 => [1]]) - ->setAutowired(false); - -$builder->addDefinition('five') - ->setFactory('@two::create', [1 => [1]]) + ->setCreator('@one::create', [1 => [1]]) ->setAutowired(false); $container = createContainer($builder); Assert::type(StdClassFactory::class, $container->getService('one')); -Assert::type(StdClassFactory::class, $container->getService('two')); Assert::type(stdClass::class, $container->getService('four')); Assert::same($container->getService('four')->a, $container->getService('three')); - -Assert::type(stdClass::class, $container->getService('five')); -Assert::same($container->getService('five')->a, $container->getService('three')); diff --git a/tests/DI/ContainerBuilder.factory.phpt b/tests/DI/ContainerBuilder.factory.phpt index 501c4a6b0..8f8dda8d8 100644 --- a/tests/DI/ContainerBuilder.factory.phpt +++ b/tests/DI/ContainerBuilder.factory.phpt @@ -15,13 +15,7 @@ require __DIR__ . '/../bootstrap.php'; interface StdClassFactory { - public function create(); -} - -interface AnnotatedFactory -{ - /** @return stdClass */ - public function create(); + public function create(): stdClass; } class FactoryReceiver @@ -36,16 +30,13 @@ $builder = new DI\ContainerBuilder; $builder->addFactoryDefinition('one') ->setImplement(StdClassFactory::class) ->getResultDefinition() - ->setFactory(stdClass::class); - -$builder->addFactoryDefinition('two') - ->setImplement(AnnotatedFactory::class); + ->setCreator(stdClass::class); $builder->addDefinition('three') ->setType(FactoryReceiver::class); $builder->addDefinition('four') - ->setFactory(FactoryReceiver::class, ['@one']); + ->setCreator(FactoryReceiver::class, ['@one']); $container = createContainer($builder); @@ -54,10 +45,6 @@ Assert::type(StdClassFactory::class, $container->getService('one')); Assert::type(stdClass::class, $container->getService('one')->create()); Assert::notSame($container->getService('one')->create(), $container->getService('one')->create()); -Assert::type(AnnotatedFactory::class, $container->getService('two')); -Assert::type(stdClass::class, $container->getService('two')->create()); -Assert::notSame($container->getService('two')->create(), $container->getService('two')->create()); - Assert::type(FactoryReceiver::class, $container->getService('three')); Assert::type(FactoryReceiver::class, $container->getService('four')); diff --git a/tests/DI/ContainerBuilder.factory.resolveClass.phpt b/tests/DI/ContainerBuilder.factory.resolveClass.phpt index af17c05b5..8f021c681 100644 --- a/tests/DI/ContainerBuilder.factory.resolveClass.phpt +++ b/tests/DI/ContainerBuilder.factory.resolveClass.phpt @@ -12,15 +12,13 @@ namespace A class Factory { - /** @return Foo */ - public function createFoo() + public function createFoo(): Foo { return new Foo; } - /** @return Bar */ - public function createBar() + public function createBar(): Bar { return new Bar; } @@ -45,26 +43,7 @@ namespace C { class SelfFactory { - /** @return self */ - public static function create() - { - return new self; - } - } - - class ThisFactory - { - /** @return $this */ - public static function create() - { - return new self; - } - } - - class StaticFactory - { - /** @return static */ - public static function create() + public static function create(): self { return new self; } @@ -82,7 +61,7 @@ namespace interface StdClassFactory { - public function create(); + public function create(): stdClass; } @@ -91,36 +70,33 @@ namespace $builder->addFactoryDefinition('one') ->setImplement(StdClassFactory::class) ->getResultDefinition() - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $builder->addFactoryDefinition('two') ->setImplement(StdClassFactory::class) ->getResultDefinition() - ->setFactory('@one'); + ->setCreator('@eight'); $builder->addFactoryDefinition('three') ->setImplement(StdClassFactory::class) ->getResultDefinition() - ->setFactory('@one::create') // alias + ->setCreator('@one::create') // alias ->setType(stdClass::class); // type is needed $builder->addDefinition('four') ->setType(A\Factory::class); $builder->addDefinition('five') - ->setFactory('@four::createFoo'); + ->setCreator('@four::createFoo'); $builder->addDefinition('six') - ->setFactory('@four::createBar'); + ->setCreator('@four::createBar'); $builder->addDefinition('seven') - ->setFactory('C\SelfFactory::create'); + ->setCreator('C\SelfFactory::create'); $builder->addDefinition('eight') - ->setFactory('C\ThisFactory::create'); - - $builder->addDefinition('nine') - ->setFactory('C\StaticFactory::create'); + ->setCreator('stdClass'); $container = createContainer($builder); @@ -128,7 +104,7 @@ namespace Assert::type(StdClassFactory::class, $container->getService('one')); Assert::type(StdClassFactory::class, $container->getService('two')); - Assert::type(StdClassFactory::class, $container->getService('two')->create()); + Assert::type(stdClass::class, $container->getService('two')->create()); Assert::notSame($container->getService('two')->create(), $container->getService('two')->create()); Assert::type(StdClassFactory::class, $container->getService('three')); @@ -139,6 +115,4 @@ namespace Assert::type(B\Bar::class, $container->getByType(B\Bar::class)); Assert::type(C\SelfFactory::class, $container->getByType(C\SelfFactory::class)); - Assert::type(C\ThisFactory::class, $container->getByType(C\ThisFactory::class)); - Assert::type(C\StaticFactory::class, $container->getByType(C\StaticFactory::class)); } diff --git a/tests/DI/ContainerBuilder.getByType.alias.phpt b/tests/DI/ContainerBuilder.getByType.alias.phpt index d3ed77234..a9a5aade0 100644 --- a/tests/DI/ContainerBuilder.getByType.alias.phpt +++ b/tests/DI/ContainerBuilder.getByType.alias.phpt @@ -39,15 +39,15 @@ Assert::exception(function () use ($builder) { Assert::same( ['one' => $builder->getDefinition('one'), 'two' => $builder->getDefinition('two')], - $builder->findByType(Service::class) + $builder->findByType(Service::class), ); Assert::same( ['one' => $builder->getDefinition('one'), 'two' => $builder->getDefinition('two')], - $builder->findByType(Alias::class) + $builder->findByType(Alias::class), ); Assert::same( ['one' => $builder->getDefinition('one'), 'two' => $builder->getDefinition('two')], - $builder->findByType('\service') + $builder->findByType('\service'), ); diff --git a/tests/DI/ContainerBuilder.getByType.phpt b/tests/DI/ContainerBuilder.getByType.phpt index 511b9d46c..89adb773d 100644 --- a/tests/DI/ContainerBuilder.getByType.phpt +++ b/tests/DI/ContainerBuilder.getByType.phpt @@ -73,6 +73,6 @@ Assert::same([ Assert::same( ['two' => $builder->getDefinition('two'), 'three' => $builder->getDefinition('three')], - $builder->findByType(Service2::class) + $builder->findByType(Service2::class), ); Assert::same([], $builder->findByType('unknown')); diff --git a/tests/DI/ContainerBuilder.metadata.phpt b/tests/DI/ContainerBuilder.metadata.phpt index b293ff6c2..30e75cd74 100644 --- a/tests/DI/ContainerBuilder.metadata.phpt +++ b/tests/DI/ContainerBuilder.metadata.phpt @@ -38,12 +38,12 @@ Assert::same( Nette\DI\Container::class => [['container']], stdClass::class => [['lorem']], ], - getPropertyValue($container, 'wiring') + getPropertyValue($container, 'wiring'), ); Assert::same( ['container' => Nette\DI\Container::class], - getPropertyValue($container, 'types') + getPropertyValue($container, 'types'), ); Assert::same( @@ -52,12 +52,12 @@ Assert::same( 'b' => ['lorem' => 'c'], 'd' => ['lorem' => ['e']], ], - getPropertyValue($container, 'tags') + getPropertyValue($container, 'tags'), ); Assert::same( [], - getPropertyValue($container, 'aliases') + getPropertyValue($container, 'aliases'), ); Assert::same(['lorem' => true], $container->findByTag('a')); diff --git a/tests/DI/ContainerBuilder.names.phpt b/tests/DI/ContainerBuilder.names.phpt index 5db877184..c6f134977 100644 --- a/tests/DI/ContainerBuilder.names.phpt +++ b/tests/DI/ContainerBuilder.names.phpt @@ -11,13 +11,13 @@ require __DIR__ . '/../bootstrap.php'; $builder = new DI\ContainerBuilder; $builder->addDefinition('01') - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $builder->addDefinition(null) - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $builder->addDefinition(null) - ->setFactory(stdClass::class); + ->setCreator(stdClass::class); $container = createContainer($builder); diff --git a/tests/DI/ContainerBuilder.recursive.phpt b/tests/DI/ContainerBuilder.recursive.phpt index 50ca69c71..d7ba6ff54 100644 --- a/tests/DI/ContainerBuilder.recursive.phpt +++ b/tests/DI/ContainerBuilder.recursive.phpt @@ -23,10 +23,11 @@ class Service $builder = new DI\ContainerBuilder; $builder->addDefinition('one') - ->setFactory('@two::get'); + ->setCreator('@two::get'); $builder->addDefinition('two') - ->setFactory('@one::get'); + ->setCreator('@one::get'); Assert::exception(function () use ($builder) { $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'two': Circular reference detected for services: one, two."); +}, Nette\DI\ServiceCreationException::class, "[Service 'two'] +Circular reference detected for services: one, two."); diff --git a/tests/DI/ContainerBuilder.resolveTypes.php80.phpt b/tests/DI/ContainerBuilder.resolveTypes.php80.phpt deleted file mode 100644 index 161e93e38..000000000 --- a/tests/DI/ContainerBuilder.resolveTypes.php80.phpt +++ /dev/null @@ -1,30 +0,0 @@ -addDefinition('a') - ->setFactory([Factory::class, 'createUnion']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createUnion() is not expected to be nullable/union/intersection/built-in, 'stdClass|array' given."); diff --git a/tests/DI/ContainerBuilder.resolveTypes.phpt b/tests/DI/ContainerBuilder.resolveTypes.phpt index 602cd36c6..bbd710270 100644 --- a/tests/DI/ContainerBuilder.resolveTypes.phpt +++ b/tests/DI/ContainerBuilder.resolveTypes.phpt @@ -8,52 +8,24 @@ use Tester\Assert; class Factory { - /** @return stdClass */ - public function createClassPhpDoc() - { - return []; - } - - public function createClass(): stdClass { return []; } - /** @return stdClass|null */ - public function createNullableClassPhpDoc() - { - return []; - } - - public function createNullableClass(): ?stdClass { return []; } - /** @return array */ - public function createScalarPhpDoc() - { - return []; - } - - public function createScalar(): array { return []; } - /** @return object */ - public function createObjectPhpDoc() - { - return (object) null; - } - - public function createObject(): object { return (object) null; @@ -66,13 +38,6 @@ class Factory } - /** @return mixed */ - public function createMixedPhpDoc() - { - return (object) null; - } - - public function createMixed(): mixed { return (object) null; @@ -87,93 +52,69 @@ class Factory { return (object) null; } -} -require __DIR__ . '/../bootstrap.php'; + public function createUnion(): stdClass|array + { + return []; + } +} -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setFactory([Factory::class, 'createClassPhpDoc']); - $container = createContainer($builder); -}); +require __DIR__ . '/../bootstrap.php'; -Assert::noError(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setFactory([Factory::class, 'createClass']); - $container = createContainer($builder); -}); Assert::noError(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createNullableClassPhpDoc']); + ->setCreator([Factory::class, 'createClass']); $container = createContainer($builder); }); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createNullableClass']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createNullableClass() is not expected to be nullable/union/intersection/built-in, '?stdClass' given."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setFactory([Factory::class, 'createScalarPhpDoc']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalarPhpDoc() is not expected to be nullable/union/intersection/built-in, 'array' given."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setFactory([Factory::class, 'createScalar']); - $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createScalar() is not expected to be nullable/union/intersection/built-in, 'array' given."); - -Assert::exception(function () { - $builder = new DI\ContainerBuilder; - $builder->addDefinition('a') - ->setFactory([Factory::class, 'createObjectPhpDoc']); + ->setCreator([Factory::class, 'createNullableClass']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createNullableClass() is not expected to be nullable/union/intersection/built-in, '?stdClass' given."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createObject']); + ->setCreator([Factory::class, 'createScalar']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createScalar() is not expected to be nullable/union/intersection/built-in, 'array' given."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createObjectNullable']); + ->setCreator([Factory::class, 'createObject']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Return type of Factory::createObjectNullable() is not expected to be nullable/union/intersection/built-in, '?object' given."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createMixedPhpDoc']); + ->setCreator([Factory::class, 'createObjectNullable']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createObjectNullable() is not expected to be nullable/union/intersection/built-in, '?object' given."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createMixed']); + ->setCreator([Factory::class, 'createMixed']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Unknown service type, specify it or declare return type of factory method."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Unknown service type, specify it or declare return type of factory method."); Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('a') - ->setFactory([Factory::class, 'createGeneric']); + ->setFactory([Factory::class, 'createUnion']); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'a': Class 'T' not found. -Check the return type of Factory::createGeneric()."); +}, Nette\DI\ServiceCreationException::class, "[Service 'a'] +Return type of Factory::createUnion() is not expected to be nullable/union/intersection/built-in, 'stdClass|array' given."); diff --git a/tests/DI/ContainerBuilder.selfdependency.phpt b/tests/DI/ContainerBuilder.selfdependency.phpt index 7230c1925..b23d6e9dc 100644 --- a/tests/DI/ContainerBuilder.selfdependency.phpt +++ b/tests/DI/ContainerBuilder.selfdependency.phpt @@ -23,8 +23,10 @@ class Foo $builder = new DI\ContainerBuilder; $builder->addDefinition(null) - ->setFactory(Foo::class); + ->setCreator(Foo::class); Assert::exception(function () use ($builder) { createContainer($builder); -}, Nette\DI\ServiceCreationException::class, 'Service of type Foo: Service of type Foo required by $foo in Foo::__construct() not found. Did you add it to configuration file?'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Foo] +Service of type Foo required by $foo in Foo::__construct() not found. +Did you add it to configuration file?'); diff --git a/tests/DI/ContainerLoader.basic.phpt b/tests/DI/ContainerLoader.basic.phpt index 7b1a92aa1..9f75a0b5f 100644 --- a/tests/DI/ContainerLoader.basic.phpt +++ b/tests/DI/ContainerLoader.basic.phpt @@ -19,9 +19,7 @@ $key = [1, 2]; $className = $cache->getClassName($key); Assert::match('Container%[\w]+%', $className); -$container = $cache->load(function () use ($className) { - return "class $className {}"; -}, $key); +$container = $cache->load(fn() => "class $className {}", $key); Assert::type($className, new $container); $container = $cache->load(function () {}, 'key2'); diff --git a/tests/DI/DIExtension.run.phpt b/tests/DI/DIExtension.run.phpt deleted file mode 100644 index 27526245d..000000000 --- a/tests/DI/DIExtension.run.phpt +++ /dev/null @@ -1,32 +0,0 @@ -addExtension('di', new DIExtension); -$loader = new DI\Config\Loader; -$config = $loader->load(Tester\FileMock::create(' -services: - std: {factory: stdClass, tags: [run]} - - {factory: stdClass, tags: [run]} -', 'neon')); - -@eval($compiler->addConfig($config)->setClassName(Container1::class)->compile()); // @ tag is deprecated - -$container = new Container1; -Assert::false($container->isCreated('std')); - -$container->initialize(); -Assert::true($container->isCreated('std')); diff --git a/tests/DI/DecoratorExtension.basic.phpt b/tests/DI/DecoratorExtension.basic.phpt index 8747145a9..08667d50e 100644 --- a/tests/DI/DecoratorExtension.basic.phpt +++ b/tests/DI/DecoratorExtension.basic.phpt @@ -78,7 +78,7 @@ $builder = $compiler->getContainerBuilder(); Assert::same( ['a' => true, 'tag' => 2, DI\Extensions\InjectExtension::TAG_INJECT => true, 'Iface' => true], - $builder->getDefinition('one')->getTags() + $builder->getDefinition('one')->getTags(), ); Assert::true($builder->getDefinition('one')->getTag(DI\Extensions\InjectExtension::TAG_INJECT)); diff --git a/tests/DI/DecoratorExtension.factories.accessor.phpt b/tests/DI/DecoratorExtension.factories.accessor.phpt index 35db040c6..9c5ceaeee 100644 --- a/tests/DI/DecoratorExtension.factories.accessor.phpt +++ b/tests/DI/DecoratorExtension.factories.accessor.phpt @@ -14,10 +14,7 @@ require __DIR__ . '/../bootstrap.php'; interface FooAccessor { - /** - * @return Foo - */ - public function get(); + public function get(): Foo; } class Foo diff --git a/tests/DI/DecoratorExtension.factories.phpt b/tests/DI/DecoratorExtension.factories.phpt index 7823aa89f..56c8a2c1a 100644 --- a/tests/DI/DecoratorExtension.factories.phpt +++ b/tests/DI/DecoratorExtension.factories.phpt @@ -14,10 +14,7 @@ require __DIR__ . '/../bootstrap.php'; interface FooFactory { - /** - * @return Foo - */ - public function create(); + public function create(): Foo; } class Foo diff --git a/tests/DI/DefinitionSchema.normalize.phpt b/tests/DI/DefinitionSchema.normalize.phpt index 733cca6a2..890072f83 100644 --- a/tests/DI/DefinitionSchema.normalize.phpt +++ b/tests/DI/DefinitionSchema.normalize.phpt @@ -6,8 +6,8 @@ declare(strict_types=1); -use Nette\DI\Config\DefinitionSchema; use Nette\DI\Definitions\Statement; +use Nette\DI\Extensions\DefinitionSchema; use Tester\Assert; @@ -26,17 +26,17 @@ Assert::with(DefinitionSchema::class, function () { Assert::same([], $schema->normalize(null, $context)); Assert::same([], $schema->normalize([], $context)); Assert::same([false], $schema->normalize(false, $context)); - Assert::same(['factory' => true], $schema->normalize(true, $context)); - Assert::same(['factory' => 'class'], $schema->normalize('class', $context)); + Assert::same(['create' => true], $schema->normalize(true, $context)); + Assert::same(['create' => 'class'], $schema->normalize('class', $context)); Assert::same(['implement' => Iface::class], $schema->normalize(Iface::class, $context)); - Assert::same(['factory' => ['class', 'method']], $schema->normalize(['class', 'method'], $context)); - Assert::same(['factory' => [Iface::class, 'method']], $schema->normalize([Iface::class, 'method'], $context)); + Assert::same(['create' => ['class', 'method']], $schema->normalize(['class', 'method'], $context)); + Assert::same(['create' => [Iface::class, 'method']], $schema->normalize([Iface::class, 'method'], $context)); $statement = new Statement(['class', 'method']); - Assert::same(['factory' => $statement], $schema->normalize($statement, $context)); + Assert::same(['create' => $statement], $schema->normalize($statement, $context)); $statement = new Statement(Iface::class, ['foo']); - Assert::same(['implement' => Iface::class, 'factory' => 'foo'], $schema->normalize($statement, $context)); + Assert::same(['implement' => Iface::class, 'create' => 'foo'], $schema->normalize($statement, $context)); $statement = new Statement(Iface::class, ['stdClass', 'stdClass']); Assert::same(['implement' => Iface::class, 'references' => ['stdClass', 'stdClass']], $schema->normalize($statement, $context)); @@ -45,7 +45,7 @@ Assert::with(DefinitionSchema::class, function () { Assert::same(['implement' => Iface::class, 'tagged' => 123], $schema->normalize($statement, $context)); // aliases - Assert::same(['factory' => 'val'], $schema->normalize(['class' => 'val'], $context)); + Assert::same(['create' => 'val'], $schema->normalize(['class' => 'val'], $context)); Assert::same(['imported' => 'val'], $schema->normalize(['dynamic' => 'val'], $context)); Assert::exception(function () use ($schema, $context) { diff --git a/tests/DI/Definitions.AccessorDefinition.api.phpt b/tests/DI/Definitions.AccessorDefinition.api.phpt index 7b6df72bf..1d0659ee9 100644 --- a/tests/DI/Definitions.AccessorDefinition.api.phpt +++ b/tests/DI/Definitions.AccessorDefinition.api.phpt @@ -40,11 +40,16 @@ interface Bad5 public function get($arg); } -interface Good1 +interface Bad6 { public function get(); } +interface Good1 +{ + public function get(): stdClass; +} + Assert::exception(function () { $def = new AccessorDefinition; @@ -55,43 +60,57 @@ Assert::exception(function () { Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad2 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad2 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad3 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad3 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad4 must have just one non-static method get()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad4 must have just one non-static method get().'); Assert::exception(function () { $def = new AccessorDefinition; $def->setImplement(Bad5::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad5::get() must have no parameters."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad5::get() must have no parameters.'); + + +Assert::exception(function () { + $def = new AccessorDefinition; + $def->setImplement(Bad6::class); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad6::get() is not declared.'); Assert::noError(function () { diff --git a/tests/DI/Definitions.AccessorDefinition.render.phpt b/tests/DI/Definitions.AccessorDefinition.render.phpt index 758e32613..e0f3e9884 100644 --- a/tests/DI/Definitions.AccessorDefinition.render.phpt +++ b/tests/DI/Definitions.AccessorDefinition.render.phpt @@ -36,26 +36,26 @@ test('', function () { Assert::match( <<<'XX' -public function createServiceAbc(): Good2 -{ - return new class ($this) implements Good2 { - private $container; + public function createServiceAbc(): Good2 + { + return new class ($this) implements Good2 { + private $container; - public function __construct($container) - { - $this->container = $container; - } + public function __construct($container) + { + $this->container = $container; + } - public function get(): stdClass - { - return $this->container->getService('a'); - } - }; -} -XX + public function get(): stdClass + { + return $this->container->getService('a'); + } + }; + } + XX , - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.AccessorDefinition.resolve.phpt b/tests/DI/Definitions.AccessorDefinition.resolve.phpt index c45c63e1c..d03e48290 100644 --- a/tests/DI/Definitions.AccessorDefinition.resolve.phpt +++ b/tests/DI/Definitions.AccessorDefinition.resolve.phpt @@ -13,12 +13,12 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -interface Good1 +interface Bad1 { public function get(); } -interface Good2 +interface Good1 { public function get(): stdClass; } @@ -28,16 +28,15 @@ Assert::exception(function () { $def = new AccessorDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); Assert::exception(function () { $def = new AccessorDefinition; - $def->setImplement(Good1::class); - $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); - $resolver->resolveDefinition($def); - $resolver->completeDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good1: Return type of Good1::get() is not declared.'); + $def->setImplement(Bad1::class); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad1::get() is not declared.'); Assert::noError(function () { @@ -52,7 +51,7 @@ Assert::noError(function () { Assert::noError(function () { $def = new AccessorDefinition; - $def->setImplement(Good2::class); + $def->setImplement(Good1::class); $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); @@ -61,9 +60,10 @@ Assert::noError(function () { Assert::exception(function () { $def = new AccessorDefinition; - $def->setImplement(Good2::class); + $def->setImplement(Good1::class); $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); $resolver->completeDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good2: Service of type stdClass not found. Did you add it to configuration file?'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Good1] +Service of type stdClass not found. Did you add it to configuration file?'); diff --git a/tests/DI/Definitions.FactoryDefinition.api.phpt b/tests/DI/Definitions.FactoryDefinition.api.phpt index 4b8e54275..46d936045 100644 --- a/tests/DI/Definitions.FactoryDefinition.api.phpt +++ b/tests/DI/Definitions.FactoryDefinition.api.phpt @@ -34,11 +34,16 @@ interface Bad4 public static function create(); } -interface Good1 +interface Bad5 { public function create(); } +interface Good1 +{ + public function create(): stdClass; +} + Assert::exception(function () { $def = new FactoryDefinition; @@ -49,53 +54,57 @@ Assert::exception(function () { Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad2 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad2 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad3 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad3 must have just one non-static method create().'); Assert::exception(function () { $def = new FactoryDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad4 must have just one non-static method create()."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad4 must have just one non-static method create().'); -Assert::noError(function () { +Assert::exception(function () { $def = new FactoryDefinition; - $def->setImplement(Good1::class); - Assert::same(Good1::class, $def->getImplement()); - Assert::same(Good1::class, $def->getType()); -}); + $def->setImplement(Bad5::class); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad5::create() is not declared.'); -test('', function () { +Assert::noError(function () { $def = new FactoryDefinition; $def->setImplement(Good1::class); - - $def->setParameters(['a' => 1]); - Assert::same(['a' => 1], $def->getParameters()); + Assert::same(Good1::class, $def->getImplement()); + Assert::same(Good1::class, $def->getType()); }); diff --git a/tests/DI/Definitions.FactoryDefinition.render.phpt b/tests/DI/Definitions.FactoryDefinition.render.phpt index 146da0eeb..b4b10e331 100644 --- a/tests/DI/Definitions.FactoryDefinition.render.phpt +++ b/tests/DI/Definitions.FactoryDefinition.render.phpt @@ -53,6 +53,6 @@ test('', function () { } }; }', - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.FactoryDefinition.resolve.phpt b/tests/DI/Definitions.FactoryDefinition.resolve.phpt index 582023168..79410b22a 100644 --- a/tests/DI/Definitions.FactoryDefinition.resolve.phpt +++ b/tests/DI/Definitions.FactoryDefinition.resolve.phpt @@ -13,12 +13,12 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -interface Good1 +interface Bad1 { public function create(); } -interface Good2 +interface Good1 { public function create(): stdClass; } @@ -28,15 +28,15 @@ Assert::exception(function () { $def = new FactoryDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type is missing in definition of service.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type is missing in definition of service.'); Assert::exception(function () { $def = new FactoryDefinition; - $def->setImplement(Good1::class); - $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); - $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good1: Return type of Good1::create() is not declared.'); + $def->setImplement(Bad1::class); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Return type of Bad1::create() is not declared.'); Assert::noError(function () { @@ -52,7 +52,7 @@ Assert::noError(function () { Assert::noError(function () { $def = new FactoryDefinition; - $def->setImplement(Good2::class); + $def->setImplement(Good1::class); $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); @@ -62,7 +62,7 @@ Assert::noError(function () { Assert::noError(function () { $def = new FactoryDefinition; - $def->setImplement(Good2::class); + $def->setImplement(Good1::class); $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); @@ -72,9 +72,10 @@ Assert::noError(function () { Assert::exception(function () { $def = new FactoryDefinition; - $def->setImplement(Good2::class); + $def->setImplement(Good1::class); $def->getResultDefinition()->setType(DateTime::class); $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Service of type Good2: Factory for stdClass cannot create incompatible DateTime type.'); +}, Nette\DI\ServiceCreationException::class, '[Service of type Good1] +Factory for stdClass cannot create incompatible DateTime type.'); diff --git a/tests/DI/Definitions.ImportedDefinition.phpt b/tests/DI/Definitions.ImportedDefinition.phpt index 1ff490e4e..e0600804a 100644 --- a/tests/DI/Definitions.ImportedDefinition.phpt +++ b/tests/DI/Definitions.ImportedDefinition.phpt @@ -16,14 +16,16 @@ require __DIR__ . '/../bootstrap.php'; Assert::exception(function () { $def = new ImportedDefinition; $def->setType('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Class or interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Class or interface 'Foo' not found."); Assert::exception(function () { $def = new ImportedDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); test('', function () { @@ -42,12 +44,12 @@ test('', function () { Assert::match( <<<'XX' -public function createServiceAbc(): void -{ - throw new Nette\DI\ServiceCreationException('Unable to create imported service \'abc\', it must be added using addService()'); -} -XX + public function createServiceAbc(): void + { + throw new Nette\DI\ServiceCreationException('Unable to create imported service \'abc\', it must be added using addService()'); + } + XX , - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.LocatorDefinition.api.phpt b/tests/DI/Definitions.LocatorDefinition.api.phpt index 84dbac9fa..488c0a016 100644 --- a/tests/DI/Definitions.LocatorDefinition.api.phpt +++ b/tests/DI/Definitions.LocatorDefinition.api.phpt @@ -57,9 +57,9 @@ interface Good2 interface Good3 { - public function createA(); + public function createA(): stdClass; - public function getB(); + public function getB(): stdClass; } @@ -72,49 +72,57 @@ Assert::exception(function () { Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'Foo' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'Foo' not found."); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(stdClass::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface 'stdClass' not found."); +}, Nette\InvalidArgumentException::class, "[Service ?] +Interface 'stdClass' not found."); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad1::class); -}, Nette\InvalidArgumentException::class, "Service '': Interface Bad1 must have at least one method."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Interface Bad1 must have at least one method.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad2::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad2::create() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad2::create() does not meet the requirements: is create($name), get($name), create*() or get*() and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad3::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad3::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad3::get() does not meet the requirements: is create($name), get($name), create*() or get*() and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad4::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad4::foo() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad4::foo() does not meet the requirements: is create($name), get($name), create*() or get*() and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad5::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad5::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad5::get() does not meet the requirements: is create($name), get($name), create*() or get*() and is non-static.'); Assert::exception(function () { $def = new LocatorDefinition; $def->setImplement(Bad6::class); -}, Nette\InvalidArgumentException::class, "Service '': Method Bad6::get() does not meet the requirements: is create(\$name), get(\$name), create*() or get*() and is non-static."); +}, Nette\InvalidArgumentException::class, '[Service ?] +Method Bad6::get() does not meet the requirements: is create($name), get($name), create*() or get*() and is non-static.'); Assert::noError(function () { diff --git a/tests/DI/Definitions.LocatorDefinition.render.create.phpt b/tests/DI/Definitions.LocatorDefinition.render.create.phpt index 2550d0611..f10b438b5 100644 --- a/tests/DI/Definitions.LocatorDefinition.render.create.phpt +++ b/tests/DI/Definitions.LocatorDefinition.render.create.phpt @@ -37,30 +37,30 @@ test('', function () { Assert::match( <<<'XX' -public function createServiceAbc(): Good -{ - return new class ($this) implements Good { - private $container;%A?% - private $mapping = ['first' => 'a', 'second' => 'a']; - - - public function __construct($container) - { - $this->container = $container; - } - - - public function create($name): stdClass - { - if (!isset($this->mapping[$name])) { - throw new Nette\DI\MissingServiceException("Service '$name' is not defined."); + public function createServiceAbc(): Good + { + return new class ($this) implements Good { + private $container;%A?% + private $mapping = ['first' => 'a', 'second' => 'a']; + + + public function __construct($container) + { + $this->container = $container; + } + + + public function create($name): stdClass + { + if (!isset($this->mapping[$name])) { + throw new Nette\DI\MissingServiceException("Service '$name' is not defined."); + } + return $this->container->createService($this->mapping[$name]); + } + }; } - return $this->container->createService($this->mapping[$name]); - } - }; -} -XX + XX , - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.LocatorDefinition.render.get.phpt b/tests/DI/Definitions.LocatorDefinition.render.get.phpt index e12b207f2..1ef788f3e 100644 --- a/tests/DI/Definitions.LocatorDefinition.render.get.phpt +++ b/tests/DI/Definitions.LocatorDefinition.render.get.phpt @@ -37,30 +37,30 @@ test('', function () { Assert::match( <<<'XX' -public function createServiceAbc(): Good -{ - return new class ($this) implements Good { - private $container;%A?% - private $mapping = ['first' => 'a', 'second' => 'a']; - - - public function __construct($container) - { - $this->container = $container; - } - - - public function get($name): stdClass - { - if (!isset($this->mapping[$name])) { - throw new Nette\DI\MissingServiceException("Service '$name' is not defined."); + public function createServiceAbc(): Good + { + return new class ($this) implements Good { + private $container;%A?% + private $mapping = ['first' => 'a', 'second' => 'a']; + + + public function __construct($container) + { + $this->container = $container; + } + + + public function get($name): stdClass + { + if (!isset($this->mapping[$name])) { + throw new Nette\DI\MissingServiceException("Service '$name' is not defined."); + } + return $this->container->getService($this->mapping[$name]); + } + }; } - return $this->container->getService($this->mapping[$name]); - } - }; -} -XX + XX , - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.LocatorDefinition.render.multi.phpt b/tests/DI/Definitions.LocatorDefinition.render.multi.phpt index 036048d66..5b24175a5 100644 --- a/tests/DI/Definitions.LocatorDefinition.render.multi.phpt +++ b/tests/DI/Definitions.LocatorDefinition.render.multi.phpt @@ -39,32 +39,32 @@ test('', function () { Assert::match( <<<'XX' -public function createServiceAbc(): Good -{ - return new class ($this) implements Good { - private $container; + public function createServiceAbc(): Good + { + return new class ($this) implements Good { + private $container; - public function __construct($container) - { - $this->container = $container; - } + public function __construct($container) + { + $this->container = $container; + } - public function createFirst(): stdClass - { - return $this->container->createServiceA(); - } + public function createFirst(): stdClass + { + return $this->container->createServiceA(); + } - public function getSecond(): ?stdClass - { - return $this->container->getService('a'); - } - }; -} -XX + public function getSecond(): ?stdClass + { + return $this->container->getService('a'); + } + }; + } + XX , - $method->__toString() + $method->__toString(), ); }); diff --git a/tests/DI/Definitions.LocatorDefinition.resolve.phpt b/tests/DI/Definitions.LocatorDefinition.resolve.phpt index 2a12fbf54..45714e3a8 100644 --- a/tests/DI/Definitions.LocatorDefinition.resolve.phpt +++ b/tests/DI/Definitions.LocatorDefinition.resolve.phpt @@ -33,7 +33,8 @@ Assert::exception(function () { $def = new LocatorDefinition; $resolver = new Nette\DI\Resolver(new Nette\DI\ContainerBuilder); $resolver->resolveDefinition($def); -}, Nette\DI\ServiceCreationException::class, 'Type of service is unknown.'); +}, Nette\DI\ServiceCreationException::class, '[Service ?] +Type of service is unknown.'); test('', function () { diff --git a/tests/DI/Definitions.ServiceDefinition.phpt b/tests/DI/Definitions.ServiceDefinition.phpt index 05e98f561..e0d26954c 100644 --- a/tests/DI/Definitions.ServiceDefinition.phpt +++ b/tests/DI/Definitions.ServiceDefinition.phpt @@ -17,12 +17,8 @@ require __DIR__ . '/../bootstrap.php'; Assert::exception(function () { $def = new ServiceDefinition; $def->setType('Foo'); -}, Nette\InvalidArgumentException::class, "Service '': Class or interface 'Foo' not found."); - -Assert::exception(function () { - $def = new ServiceDefinition; - $def->setImplement('Foo'); -}, Nette\DeprecatedException::class); +}, Nette\InvalidArgumentException::class, "[Service ?] +Class or interface 'Foo' not found."); test('', function () { $def = new ServiceDefinition; @@ -37,69 +33,51 @@ test('', function () { test('', function () { $def = new ServiceDefinition; - Assert::error(function () use ($def) { - $def->setClass(stdClass::class, []); - }, E_USER_DEPRECATED); - Assert::same(stdClass::class, $def->getType()); - Assert::null($def->getEntity()); -}); - -test('', function () { - $def = new ServiceDefinition; - Assert::error(function () use ($def) { - $def->setClass(stdClass::class, [1, 2]); - }, E_USER_DEPRECATED); - Assert::same(stdClass::class, $def->getType()); - Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getFactory()); -}); - -test('', function () { - $def = new ServiceDefinition; - $def->setFactory(stdClass::class); + $def->setCreator(stdClass::class); Assert::null($def->getType()); - Assert::equal(new Statement(stdClass::class, []), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, []), $def->getCreator()); $def->setArguments([1, 2]); Assert::null($def->getType()); - Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getCreator()); // Demonstrate that setArguments call will always replace arguments. $def->setArguments([1 => 200]); - Assert::equal(new Statement(stdClass::class, [1 => 200]), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, [1 => 200]), $def->getCreator()); }); test('Test with factory being previously set.', function () { $def1 = new ServiceDefinition; - $def1->setFactory(stdClass::class, ['foo', 'bar']); + $def1->setCreator(stdClass::class, ['foo', 'bar']); $def1->setArgument(1, 'new'); - Assert::equal(new Statement(stdClass::class, ['foo', 'new']), $def1->getFactory()); + Assert::equal(new Statement(stdClass::class, ['foo', 'new']), $def1->getCreator()); // Test with factory being set implicitly. $def2 = new ServiceDefinition; $def2->setArgument(1, 'new'); $def2->setArgument(2, 'bar'); - Assert::equal(new Statement(null, [1 => 'new', 2 => 'bar']), $def2->getFactory()); + Assert::equal(new Statement(null, [1 => 'new', 2 => 'bar']), $def2->getCreator()); }); test('', function () { $def = new ServiceDefinition; - $def->setFactory(stdClass::class, [1, 2]); + $def->setCreator(stdClass::class, [1, 2]); Assert::null($def->getType()); - Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getCreator()); }); test('', function () { $def = new ServiceDefinition; - $def->setFactory(new Statement(stdClass::class, [1, 2])); + $def->setCreator(new Statement(stdClass::class, [1, 2])); Assert::null($def->getType()); - Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getCreator()); }); test('', function () { $def = new ServiceDefinition; - $def->setFactory(new Statement(stdClass::class, [1, 2]), [99]); // 99 is ignored + $def->setCreator(new Statement(stdClass::class, [1, 2]), [99]); // 99 is ignored Assert::null($def->getType()); - Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getFactory()); + Assert::equal(new Statement(stdClass::class, [1, 2]), $def->getCreator()); }); test('', function () { @@ -130,12 +108,12 @@ test('', function () { test('deep clone', function () { $def = new ServiceDefinition; - $def->setFactory(new Statement(stdClass::class, [1, 2])); + $def->setCreator(new Statement(stdClass::class, [1, 2])); $def->addSetup(new Statement(stdClass::class, [1, 2])); $dolly = clone $def; - Assert::notSame($dolly->getFactory(), $def->getFactory()); - Assert::equal($dolly->getFactory(), $def->getFactory()); + Assert::notSame($dolly->getCreator(), $def->getCreator()); + Assert::equal($dolly->getCreator(), $def->getCreator()); Assert::notSame($dolly->getSetup(), $def->getSetup()); Assert::equal($dolly->getSetup(), $def->getSetup()); }); diff --git a/tests/DI/ExtensionsExtension.basic.phpt b/tests/DI/ExtensionsExtension.basic.phpt index ee5409fb6..16183b0b8 100644 --- a/tests/DI/ExtensionsExtension.basic.phpt +++ b/tests/DI/ExtensionsExtension.basic.phpt @@ -51,6 +51,13 @@ class FirstExtension extends DI\CompilerExtension } } +class CustomExtensionsExtension extends DI\CompilerExtension +{ + public function loadConfiguration() + { + $this->compiler->addExtension('first', new FirstExtension); + } +} $compiler = new DI\Compiler; $compiler->addExtension('first', new FirstExtension); @@ -67,7 +74,11 @@ foo: key: value '); - Assert::same('hello', $container->parameters['foo']); Assert::same('test', $container->parameters['bar']); Assert::same(['services', 'parameters', 'first', 'extensions', 'foo', 'bar'], $container->parameters['first']); + +$compiler = new DI\Compiler; +$compiler->addExtension('extensions', new CustomExtensionsExtension); +$container = createContainer($compiler); +Assert::same(['services', 'parameters', 'extensions', 'first'], $container->parameters['first']); diff --git a/tests/DI/Helpers.escape().phpt b/tests/DI/Helpers.escape().phpt index 522946581..86a92be96 100644 --- a/tests/DI/Helpers.escape().phpt +++ b/tests/DI/Helpers.escape().phpt @@ -19,5 +19,5 @@ Assert::same('@@', Helpers::escape('@')); Assert::same('x@', Helpers::escape('x@')); Assert::same( ['key1' => '%%', 'key2' => '@@', '%%a%%' => 123, '@' => 123], - Helpers::escape(['key1' => '%', 'key2' => '@', '%a%' => 123, '@' => 123]) + Helpers::escape(['key1' => '%', 'key2' => '@', '%a%' => 123, '@' => 123]), ); diff --git a/tests/DI/Helpers.expand().phpt b/tests/DI/Helpers.expand().phpt index a515d5719..90aef87cf 100644 --- a/tests/DI/Helpers.expand().phpt +++ b/tests/DI/Helpers.expand().phpt @@ -30,7 +30,7 @@ Assert::same( Helpers::expand('%keyA%', [ 'keyA' => ['key1' => 123, 'key2' => '%keyB%'], 'keyB' => 'abc', - ], true) + ], true), ); Assert::equal(new PhpLiteral('func()'), Helpers::expand('%key%', ['key' => new PhpLiteral('func()')])); diff --git a/tests/DI/Helpers.filterArguments.phpt b/tests/DI/Helpers.filterArguments.phpt index 35cdf7a39..44c0320cd 100644 --- a/tests/DI/Helpers.filterArguments.phpt +++ b/tests/DI/Helpers.filterArguments.phpt @@ -16,22 +16,17 @@ require __DIR__ . '/../bootstrap.php'; Assert::same([], Helpers::filterArguments([])); -Assert::same( - ['a', 'b', 3 => ['c'], [1 => 'd']], - Helpers::filterArguments(['a', 'b', '...', ['c', '...'], ['...', 'd']]) -); - Assert::same( ['a', 'b', Nette\DI\ContainerBuilder::THIS_CONTAINER], - Helpers::filterArguments(['a', 'b', 'Nette\DI\ContainerBuilder::THIS_CONTAINER']) + Helpers::filterArguments(['a', 'b', 'Nette\DI\ContainerBuilder::THIS_CONTAINER']), ); Assert::equal( ['a', 'b', new Nette\DI\Definitions\Reference('service')], - Helpers::filterArguments(['a', 'b', '@service']) + Helpers::filterArguments(['a', 'b', '@service']), ); Assert::equal( - [new Statement('class', ['a', 2 => Nette\DI\ContainerBuilder::THIS_CONTAINER])], - Helpers::filterArguments([new Statement('class', ['a', '...', 'Nette\DI\ContainerBuilder::THIS_CONTAINER'])]) + [new Statement('class', ['a', Nette\DI\ContainerBuilder::THIS_CONTAINER])], + Helpers::filterArguments([new Statement('class', ['a', 'Nette\DI\ContainerBuilder::THIS_CONTAINER'])]), ); diff --git a/tests/DI/Helpers.getReturnType.phpt b/tests/DI/Helpers.getReturnType.phpt deleted file mode 100644 index 9a0a47cbf..000000000 --- a/tests/DI/Helpers.getReturnType.phpt +++ /dev/null @@ -1,30 +0,0 @@ - A\AInjected::class, - 'varC' => A\AInjected::class, - ], InjectExtension::getInjectProperties(A\AClass::class)); -} diff --git a/tests/DI/InjectExtension.getInjectProperties().php80.phpt b/tests/DI/InjectExtension.getInjectProperties().php80.phpt deleted file mode 100644 index bc72b460f..000000000 --- a/tests/DI/InjectExtension.getInjectProperties().php80.phpt +++ /dev/null @@ -1,36 +0,0 @@ - 'stdClass', -], InjectExtension::getInjectProperties(EClass::class)); diff --git a/tests/DI/InjectExtension.getInjectProperties().phpt b/tests/DI/InjectExtension.getInjectProperties().phpt index 616c6a39a..110af62ba 100644 --- a/tests/DI/InjectExtension.getInjectProperties().phpt +++ b/tests/DI/InjectExtension.getInjectProperties().phpt @@ -6,94 +6,49 @@ declare(strict_types=1); -namespace A -{ - class AClass - { - /** @var AInjected @inject */ - public $varA; +use Nette\DI\Attributes\Inject; +use Nette\DI\Extensions\InjectExtension; +use Tester\Assert; + - /** @var B\BInjected @inject */ - public $varB; +class AClass +{ + /** @inject */ + public AInjected $varA; - /** @var AInjected @inject */ - public $varC; + /** @inject */ + public BInjected $varB; - /** @var AInjected */ - public $varD; - } + public $varD; - class AInjected - { - } + #[Inject] + public stdClass $varF; } -namespace A\B +class BadClass { - use A; - - class BClass extends A\AClass - { - /** @var BInjected @inject */ - public $varF; - } - - class BInjected - { - } + /** @inject */ + public AClass|stdClass $var; } -namespace C +class AInjected { - use A\AInjected; - use A\B; - use C\CInjected as CAlias; +} - class CClass - { - /** @var AInjected @inject */ - public $var1; +class BInjected +{ +} - /** @var B\BInjected @inject */ - public $var2; - /** @var CAlias @inject */ - public $var3; +require __DIR__ . '/../bootstrap.php'; - /** @var CInjected @inject */ - public $var4; - } - class CInjected - { - } -} +Assert::same([ + 'varA' => AInjected::class, + 'varB' => BInjected::class, + 'varF' => stdClass::class, +], InjectExtension::getInjectProperties(AClass::class)); -namespace -{ - use Nette\DI\Extensions\InjectExtension; - use Tester\Assert; - - require __DIR__ . '/../bootstrap.php'; - - - Assert::same([ - 'varA' => A\AInjected::class, - 'varB' => A\B\BInjected::class, - 'varC' => A\AInjected::class, - ], InjectExtension::getInjectProperties(A\AClass::class)); - - Assert::same([ - 'varA' => A\AInjected::class, - 'varB' => A\B\BInjected::class, - 'varC' => A\AInjected::class, - 'varF' => A\B\BInjected::class, - ], InjectExtension::getInjectProperties(A\B\BClass::class)); - - Assert::same([ - 'var1' => A\AInjected::class, - 'var2' => A\B\BInjected::class, - 'var3' => C\CInjected::class, - 'var4' => C\CInjected::class, - ], InjectExtension::getInjectProperties(C\CClass::class)); -} +Assert::exception(function () { + InjectExtension::getInjectProperties(BadClass::class); +}, Nette\InvalidStateException::class, "Type of property BadClass::\$var is not expected to be nullable/union/intersection/built-in, 'AClass|stdClass' given."); diff --git a/tests/DI/InjectExtension.getInjectProperties().traits.phpt b/tests/DI/InjectExtension.getInjectProperties().traits.phpt index 6eecf733b..73a9631b3 100644 --- a/tests/DI/InjectExtension.getInjectProperties().traits.phpt +++ b/tests/DI/InjectExtension.getInjectProperties().traits.phpt @@ -19,8 +19,8 @@ namespace B trait BTrait { - /** @var AInjected @inject */ - public $varA; + /** @inject */ + public AInjected $varA; } } diff --git a/tests/DI/NeonAdapter.basic.phpt b/tests/DI/NeonAdapter.basic.phpt index 18a2d67d2..92a8eb833 100644 --- a/tests/DI/NeonAdapter.basic.phpt +++ b/tests/DI/NeonAdapter.basic.phpt @@ -12,59 +12,58 @@ $adapter = new NeonAdapter; $data = $adapter->load('files/neonAdapter.neon'); Assert::match(<<<'EOD' -# generated by Nette - -parameters: - type: Ipsum - -services: - referencedService: @one - referencedServiceWithSetup: - factory: @one - setup: - - $x(10) - - serviceAsParam: Ipsum(@one) - calledService: @one() - calledServiceWithArgs: @one(1) - calledServiceAsParam: Ipsum(@one()) - calledServiceWithArgsAsParam: Ipsum(@one(1)) - one: - type: %class% - arguments: - - 1 - - two: - factory: %class%(1) - - three: - type: Lorem - factory: Factory::createLorem - arguments: - - 1 - - four: - factory: Factory::createLorem(1) - - five: - factory: Factory::createLorem(1) - - six: Factory::createLorem(1) - seven: @factory - eight: @factory() - nine: - - @three - - foo - - stdClass: stdClass - factory: Lorem - rich1: Lorem(1)::foo() - rich2: - factory: Lorem(Ipsum(@one))::foo(1) - - rich3: Factory::createLorem(1)::foo() - rich4: Factory()::createLorem(1)::foo() - - Lorem(1)::foo() - -EOD -, $adapter->dump($data)); + # generated by Nette + + parameters: + type: Ipsum + + services: + referencedService: @one + referencedServiceWithSetup: + factory: @one + setup: + - $x(10) + + serviceAsParam: Ipsum(@one) + calledService: @one() + calledServiceWithArgs: @one(1) + calledServiceAsParam: Ipsum(@one()) + calledServiceWithArgsAsParam: Ipsum(@one(1)) + one: + type: %class% + arguments: + - 1 + + two: + factory: %class%(1) + + three: + type: Lorem + factory: Factory::createLorem + arguments: + - 1 + + four: + factory: Factory::createLorem(1) + + five: + factory: Factory::createLorem(1) + + six: Factory::createLorem(1) + seven: @factory + eight: @factory() + nine: + - @three + - foo + + stdClass: stdClass + factory: Lorem + rich1: Lorem(1)::foo() + rich2: + factory: Lorem(Ipsum(@one))::foo(1) + + rich3: Factory::createLorem(1)::foo() + rich4: Factory()::createLorem(1)::foo() + - Lorem(1)::foo() + + EOD, $adapter->dump($data)); diff --git a/tests/DI/NeonAdapter.preprocess.phpt b/tests/DI/NeonAdapter.preprocess.phpt index 17d6e8b8a..a39209eff 100644 --- a/tests/DI/NeonAdapter.preprocess.phpt +++ b/tests/DI/NeonAdapter.preprocess.phpt @@ -25,25 +25,24 @@ Assert::equal([ new Statement('ent', [2]), 'inner', ], - [3, 4] + [3, 4], ), new Statement( [ new Statement('ent', [3]), 'inner', ], - [5] + [5], ), ], $data); Assert::match(<<<'EOD' -# generated by Nette + # generated by Nette -- ent(1) -- ent(2)::inner(3, 4) -- ent(3)::inner(5) -EOD -, $adapter->dump($data)); + - ent(1) + - ent(2)::inner(3, 4) + - ent(3)::inner(5) + EOD, $adapter->dump($data)); // references @@ -53,12 +52,11 @@ $data = [ ]; Assert::match(<<<'EOD' -# generated by Nette + # generated by Nette -a: @foo::method(@bar) -b: @foo() -EOD -, $adapter->dump($data)); + a: @foo::method(@bar) + b: @foo() + EOD, $adapter->dump($data)); // _ @@ -68,5 +66,24 @@ $data = $adapter->load(Tester\FileMock::create(' Assert::equal( [new Statement('Class', ['arg1', 2 => ['_']])], - $data + $data, +); + + +// @ escaping +$data = @$adapter->load(Tester\FileMock::create(' +- @@double +- "@@doublequoted" +- @simple +- "@simplequoted" +', 'neon')); + +Assert::equal( + [ + '@@double', + '@@doublequoted', + '@simple', + '@@simplequoted', // escaped + ], + $data, ); diff --git a/tests/DI/PhpAdapter.phpt b/tests/DI/PhpAdapter.phpt index 5e46af9b8..909d4c68d 100644 --- a/tests/DI/PhpAdapter.phpt +++ b/tests/DI/PhpAdapter.phpt @@ -31,20 +31,20 @@ Assert::same([ ], $data); -$config->save($data, TEMP_FILE); +@$config->save($data, TEMP_FILE); // deprecated Assert::match(<<<'EOD' - 'the example', - 'database' => [ - 'adapter' => 'pdo_mysql', - 'params' => [ - 'host' => 'db.example.com', - 'username' => 'dbuser', - 'password' => '*secret*', - 'dbname' => 'dbname', + 'the example', + 'database' => [ + 'adapter' => 'pdo_mysql', + 'params' => [ + 'host' => 'db.example.com', + 'username' => 'dbuser', + 'password' => '*secret*', + 'dbname' => 'dbname', + ], ], - ], -]; -EOD + ]; + EOD , file_get_contents(TEMP_FILE)); diff --git a/tests/DI/Resolver.autowireArguments.80.phpt b/tests/DI/Resolver.autowireArguments.80.phpt deleted file mode 100644 index 7ebf0b136..000000000 --- a/tests/DI/Resolver.autowireArguments.80.phpt +++ /dev/null @@ -1,58 +0,0 @@ - 1, 'b' => 2, 'c' => 3], - Resolver::autowireArguments( - new ReflectionFunction(function (...$args) {}), - ['a' => 1, 'b' => 2, 'c' => 3], - function () {} - ) -); diff --git a/tests/DI/Resolver.autowireArguments.81.phpt b/tests/DI/Resolver.autowireArguments.81.phpt index 721cb1383..241f611a3 100644 --- a/tests/DI/Resolver.autowireArguments.81.phpt +++ b/tests/DI/Resolver.autowireArguments.81.phpt @@ -30,7 +30,7 @@ Assert::exception(function () { [], function () {} ); -}, Nette\InvalidStateException::class, 'Parameter $x in {closure}%a?% has intersection type, so its value must be specified.'); +}, Nette\InvalidStateException::class, 'Parameter $x in {closure}() has intersection type, so its value must be specified.'); // object as default Assert::same( diff --git a/tests/DI/Resolver.autowireArguments.errors.phpt b/tests/DI/Resolver.autowireArguments.errors.phpt index 11c748bd3..fe219e1eb 100644 --- a/tests/DI/Resolver.autowireArguments.errors.phpt +++ b/tests/DI/Resolver.autowireArguments.errors.phpt @@ -18,9 +18,10 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function (stdClass $x) {}), [], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, 'Service of type stdClass required by $x in {closure}%a?% not found. Did you add it to configuration file?'); +}, Nette\DI\ServiceCreationException::class, 'Service of type stdClass required by $x in {closure}() not found. +Did you add it to configuration file?'); // not found @@ -28,9 +29,10 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function (Foo $x) {}), [], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, "Class 'Foo' required by \$x in {closure}%a?% not found. Check the parameter type and 'use' statements."); +}, Nette\DI\ServiceCreationException::class, "Class 'Foo' required by \$x in {closure}() not found. +Check the parameter type and 'use' statements."); // no typehint @@ -38,9 +40,9 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function ($x) {}), [], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}%a?% has no class type or default value, so its value must be specified.'); +}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}() has no class type or default value, so its value must be specified.'); // scalar @@ -48,9 +50,49 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function (int $x) {}), [], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}%a?% has no class type or default value, so its value must be specified.'); +}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}() has no class type or default value, so its value must be specified.'); + + +// nullable unknown class +Assert::error(function () { + Resolver::autowireArguments( + new ReflectionFunction(function (?stdClass $arg) {}), + [], + fn($type) => $type === Test::class ? new Test : null, + ); +}, E_USER_DEPRECATED, 'The parameter $arg in {closure}() should have a declared value in the configuration.'); + + +// nullable scalar +Assert::exception(function () { + Resolver::autowireArguments( + new ReflectionFunction(function (?int $arg) {}), + [], + fn($type) => $type === Test::class ? new Test : null, + ); +}, Nette\DI\ServiceCreationException::class, 'Parameter $arg in {closure}() has union type and no default value, so its value must be specified.'); + + +// union +Assert::exception(function () { + Resolver::autowireArguments( + new ReflectionFunction(function (stdClass|Test $x) {}), + [], + function () {}, + ); +}, Nette\InvalidStateException::class, 'Parameter $x in {closure}() has union type and no default value, so its value must be specified.'); + + +// nullable union +Assert::exception(function () { + Resolver::autowireArguments( + new ReflectionFunction(function (stdClass|Test|null $x) {}), + [], + function () {}, + ); +}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}() has union type and no default value, so its value must be specified.'); // bad variadics (this is actually what PHP allows) @@ -58,9 +100,9 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function (...$args) {}), [1, 'args' => []], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, 'Unable to pass specified arguments to {closure}%a?%.'); +}, Nette\DI\ServiceCreationException::class, 'Unable to pass specified arguments to {closure}().'); // bad variadics @@ -68,6 +110,6 @@ Assert::exception(function () { Resolver::autowireArguments( new ReflectionFunction(function (...$args) {}), ['args' => [], 1], - function () {} + function () {}, ); -}, Nette\DI\ServiceCreationException::class, 'Unable to pass specified arguments to {closure}%a?%.'); +}, Nette\DI\ServiceCreationException::class, 'Unable to pass specified arguments to {closure}().'); diff --git a/tests/DI/Resolver.autowireArguments.phpt b/tests/DI/Resolver.autowireArguments.phpt index 9735a165c..ceaea54df 100644 --- a/tests/DI/Resolver.autowireArguments.phpt +++ b/tests/DI/Resolver.autowireArguments.phpt @@ -24,8 +24,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (Test $arg) {}), [], - function ($type) { return $type === Test::class ? new Test : null; } - ) + fn($type) => $type === Test::class ? new Test : null, + ), ); // nullable class @@ -34,28 +34,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (?Test $arg) {}), [], - function ($type) { return $type === Test::class ? new Test : null; } - ) -); - -// nullable unknown class -Assert::equal( - [null], - Resolver::autowireArguments( - new ReflectionFunction(function (?stdClass $arg) {}), - [], - function ($type) { return $type === Test::class ? new Test : null; } - ) -); - -// nullable scalar -Assert::equal( - [null], - Resolver::autowireArguments( - new ReflectionFunction(function (?int $arg) {}), - [], - function ($type) { return $type === Test::class ? new Test : null; } - ) + fn($type) => $type === Test::class ? new Test : null, + ), ); // nullable optional class @@ -64,8 +44,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (?Test $arg = null) {}), [], - function ($type) { return $type === Test::class ? new Test : null; } - ) + fn($type) => $type === Test::class ? new Test : null, + ), ); // nullable optional scalar @@ -74,38 +54,38 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (?int $arg = null) {}), [], - function ($type) { return $type === Test::class ? new Test : null; } - ) + fn($type) => $type === Test::class ? new Test : null, + ), ); // optional arguments + positional Assert::equal( - PHP_VERSION_ID < 80000 ? [1, 'new'] : ['b' => 'new'], + ['b' => 'new'], Resolver::autowireArguments( new ReflectionFunction(function ($a = 1, $b = 2) {}), [1 => 'new'], - function () {} - ) + function () {}, + ), ); // optional arguments + named Assert::equal( - PHP_VERSION_ID < 80000 ? [1, 'new'] : ['b' => 'new'], + ['b' => 'new'], Resolver::autowireArguments( new ReflectionFunction(function ($a = 1, $b = 2) {}), ['b' => 'new'], - function () {} - ) + function () {}, + ), ); // optional arguments + variadics Assert::equal( - PHP_VERSION_ID < 80000 ? [1, 'new1', 'new2'] : ['args' => ['new1', 'new2']], + ['args' => ['new1', 'new2']], Resolver::autowireArguments( new ReflectionFunction(function ($a = 1, ...$args) {}), [1 => 'new1', 2 => 'new2'], - function () {} - ) + function () {}, + ), ); // optional arguments + variadics @@ -114,8 +94,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function ($a = 1, ...$args) {}), ['a' => 'new', 1 => 'new1', 2 => 'new2'], - function () {} - ) + function () {}, + ), ); // variadics as items @@ -124,8 +104,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (...$args) {}), [1, 2, 3], - function () {} - ) + function () {}, + ), ); // variadics as array @@ -134,8 +114,8 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function (...$args) {}), ['args' => [1, 2, 3]], - function () {} - ) + function () {}, + ), ); // named parameter intentionally overwrites the indexed one (due to overwriting in the configuration) @@ -144,6 +124,26 @@ Assert::equal( Resolver::autowireArguments( new ReflectionFunction(function ($a) {}), [1, 'a' => 2], - function () {} - ) + function () {}, + ), +); + +// optional union +Assert::same( + [], + Resolver::autowireArguments( + new ReflectionFunction(function (stdClass|int $x = 1) {}), + [], + function () {}, + ), +); + +// named variadics +Assert::equal( + ['a' => 1, 'b' => 2, 'c' => 3], + Resolver::autowireArguments( + new ReflectionFunction(function (...$args) {}), + ['a' => 1, 'b' => 2, 'c' => 3], + function () {}, + ), ); diff --git a/tests/DI/files/compiler.generatedFactory.neon b/tests/DI/files/compiler.generatedFactory.neon index c26a79b9c..0881fd3c2 100644 --- a/tests/DI/files/compiler.generatedFactory.neon +++ b/tests/DI/files/compiler.generatedFactory.neon @@ -5,12 +5,9 @@ services: lorem: \ILoremFactory(Lorem) - finder: IFinderFactory - article: - create: Article(%title%) + create: Article($title) implement: IArticleFactory - parameters: [title] setup: - method(@self::ABC) - $prop = @self::ABC @@ -18,12 +15,10 @@ services: article2: implement: IArticleFactory arguments: [$title] - parameters: [title] fooFactory1: - create: Foo(_, %baz%) + create: Foo(_, $baz) implement: IFooFactory - parameters: [Baz baz = null] fooFactory3: type: Foo diff --git a/tests/DI/fixtures/Helpers.getReturnType.php b/tests/DI/fixtures/Helpers.getReturnType.php deleted file mode 100644 index 93bb93e5b..000000000 --- a/tests/DI/fixtures/Helpers.getReturnType.php +++ /dev/null @@ -1,49 +0,0 @@ -