From 0f0c24c69ed3a86754d2fe5f72af8baa3c52963b Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 11 Mar 2019 23:47:57 +0100 Subject: [PATCH] DI extensions: are using configuration Schema --- composer.json | 2 +- .../ApplicationDI/ApplicationExtension.php | 68 ++++++++++--------- src/Bridges/ApplicationDI/LatteExtension.php | 30 ++++---- .../ApplicationDI/RoutingExtension.php | 40 ++++++----- 4 files changed, 79 insertions(+), 61 deletions(-) diff --git a/composer.json b/composer.json index a6ce364be..dcfb2fbed 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "mockery/mockery": "^1.0" }, "conflict": { - "nette/di": "<2.4", + "nette/di": "<3.0", "nette/forms": "<3.0", "nette/latte": "<3.0" }, diff --git a/src/Bridges/ApplicationDI/ApplicationExtension.php b/src/Bridges/ApplicationDI/ApplicationExtension.php index dd414c9ee..f03b91610 100644 --- a/src/Bridges/ApplicationDI/ApplicationExtension.php +++ b/src/Bridges/ApplicationDI/ApplicationExtension.php @@ -12,6 +12,8 @@ use Composer\Autoload\ClassLoader; use Nette; use Nette\Application\UI; +use Nette\DI\Config\Expect; +use Nette\DI\Definitions; use Tracy; @@ -20,20 +22,12 @@ */ final class ApplicationExtension extends Nette\DI\CompilerExtension { - private $defaults = [ - 'debugger' => null, - 'errorPresenter' => 'Nette:Error', - 'catchExceptions' => null, - 'mapping' => null, - 'scanDirs' => [], - 'scanComposer' => null, - 'scanFilter' => 'Presenter', - 'silentLinks' => false, - ]; - /** @var bool */ private $debugMode; + /** @var array */ + private $scanDirs; + /** @var int */ private $invalidLinkMode; @@ -43,48 +37,60 @@ final class ApplicationExtension extends Nette\DI\CompilerExtension public function __construct(bool $debugMode = false, array $scanDirs = null, string $tempDir = null) { - $this->defaults['debugger'] = interface_exists(Tracy\IBarPanel::class); - $this->defaults['scanDirs'] = (array) $scanDirs; - $this->defaults['scanComposer'] = class_exists(ClassLoader::class); - $this->defaults['catchExceptions'] = !$debugMode; $this->debugMode = $debugMode; + $this->scanDirs = (array) $scanDirs; $this->tempDir = $tempDir; } + public function getConfigSchema(): Nette\DI\Config\Schema + { + return Expect::structure([ + 'debugger' => Expect::bool(interface_exists(Tracy\IBarPanel::class)), + 'errorPresenter' => Expect::string('Nette:Error')->dynamic(), + 'catchExceptions' => Expect::bool(!$this->debugMode)->dynamic(), + 'mapping' => Expect::arrayOf('string')->dynamic(), + 'scanDirs' => Expect::enum(Expect::arrayOf('string')->default($this->scanDirs), false), + 'scanComposer' => Expect::bool(class_exists(ClassLoader::class)), + 'scanFilter' => Expect::string('Presenter'), + 'silentLinks' => Expect::bool(), + ]); + } + + public function loadConfiguration() { - $config = $this->validateConfig($this->defaults); + $config = $this->config; $builder = $this->getContainerBuilder(); $builder->addExcludedClasses([UI\Presenter::class]); $this->invalidLinkMode = $this->debugMode - ? UI\Presenter::INVALID_LINK_TEXTUAL | ($config['silentLinks'] ? 0 : UI\Presenter::INVALID_LINK_WARNING) + ? UI\Presenter::INVALID_LINK_TEXTUAL | ($config->silentLinks ? 0 : UI\Presenter::INVALID_LINK_WARNING) : UI\Presenter::INVALID_LINK_WARNING; $application = $builder->addDefinition($this->prefix('application')) ->setFactory(Nette\Application\Application::class) - ->addSetup('$catchExceptions', [$config['catchExceptions']]) - ->addSetup('$errorPresenter', [$config['errorPresenter']]); + ->addSetup('$catchExceptions', [$config->catchExceptions]) + ->addSetup('$errorPresenter', [$config->errorPresenter]); - if ($config['debugger']) { + if ($config->debugger) { $application->addSetup([Nette\Bridges\ApplicationTracy\RoutingPanel::class, 'initializePanel']); } - $touch = $this->debugMode && $config['scanDirs'] && $this->tempDir ? $this->tempDir . '/touch' : null; + $touch = $this->debugMode && $config->scanDirs && $this->tempDir ? $this->tempDir . '/touch' : null; $presenterFactory = $builder->addDefinition($this->prefix('presenterFactory')) ->setType(Nette\Application\IPresenterFactory::class) - ->setFactory(Nette\Application\PresenterFactory::class, [new Nette\DI\Definitions\Statement( + ->setFactory(Nette\Application\PresenterFactory::class, [new Definitions\Statement( Nette\Bridges\ApplicationDI\PresenterFactoryCallback::class, [1 => $this->invalidLinkMode, $touch] )]); - if ($config['mapping']) { - $presenterFactory->addSetup('setMapping', [$config['mapping']]); + if ($config->mapping) { + $presenterFactory->addSetup('setMapping', [$config->mapping]); } $builder->addDefinition($this->prefix('linkGenerator')) ->setFactory(Nette\Application\LinkGenerator::class, [ - 1 => new Nette\DI\Definitions\Statement('@Nette\Http\IRequest::getUrl'), + 1 => new Definitions\Statement('@Nette\Http\IRequest::getUrl'), ]); if ($this->name === 'application') { @@ -115,7 +121,7 @@ public function beforeCompile() $def->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT) ->setAutowired(false); - if (is_subclass_of($def->getType(), UI\Presenter::class)) { + if (is_subclass_of($def->getType(), UI\Presenter::class) && $def instanceof Definitions\ServiceDefinition) { $def->addSetup('$invalidLinkMode', [$this->invalidLinkMode]); } } @@ -127,13 +133,13 @@ private function findPresenters(): array $config = $this->getConfig(); $classes = []; - if ($config['scanDirs']) { + if ($config->scanDirs) { if (!class_exists(Nette\Loaders\RobotLoader::class)) { throw new Nette\NotSupportedException("RobotLoader is required to find presenters, install package `nette/robot-loader` or disable option {$this->prefix('scanDirs')}: false"); } $robot = new Nette\Loaders\RobotLoader; - $robot->addDirectory(...$config['scanDirs']); - $robot->acceptFiles = ['*' . $config['scanFilter'] . '*.php']; + $robot->addDirectory(...$config->scanDirs); + $robot->acceptFiles = ['*' . $config->scanFilter . '*.php']; if ($this->tempDir) { $robot->setTempDirectory($this->tempDir); $robot->refresh(); @@ -144,7 +150,7 @@ private function findPresenters(): array $this->getContainerBuilder()->addDependency($this->tempDir . '/touch'); } - if ($config['scanComposer']) { + if ($config->scanComposer) { $rc = new \ReflectionClass(ClassLoader::class); $classFile = dirname($rc->getFileName()) . '/autoload_classmap.php'; if (is_file($classFile)) { @@ -158,7 +164,7 @@ private function findPresenters(): array $presenters = []; foreach (array_unique($classes) as $class) { if ( - strpos($class, $config['scanFilter']) !== false + strpos($class, $config->scanFilter) !== false && class_exists($class) && ($rc = new \ReflectionClass($class)) && $rc->implementsInterface(Nette\Application\IPresenter::class) diff --git a/src/Bridges/ApplicationDI/LatteExtension.php b/src/Bridges/ApplicationDI/LatteExtension.php index 66cfc4296..892d432a9 100644 --- a/src/Bridges/ApplicationDI/LatteExtension.php +++ b/src/Bridges/ApplicationDI/LatteExtension.php @@ -18,13 +18,6 @@ */ final class LatteExtension extends Nette\DI\CompilerExtension { - public $defaults = [ - 'xhtml' => false, - 'macros' => [], - 'templateClass' => null, - 'strictTypes' => false, - ]; - /** @var bool */ private $debugMode; @@ -36,6 +29,17 @@ public function __construct(string $tempDir, bool $debugMode = false) { $this->tempDir = $tempDir; $this->debugMode = $debugMode; + + $this->config = new class { + /** @var bool */ + public $xhtml = false; + /** @var string[] */ + public $macros = []; + /** @var ?string */ + public $templateClass; + /** @var bool */ + public $strictTypes = false; + }; } @@ -45,7 +49,7 @@ public function loadConfiguration() return; } - $config = $this->validateConfig($this->defaults); + $config = $this->config; $builder = $this->getContainerBuilder(); $latteFactory = $builder->addFactoryDefinition($this->prefix('latteFactory')) @@ -54,19 +58,19 @@ public function loadConfiguration() ->setFactory(Latte\Engine::class) ->addSetup('setTempDirectory', [$this->tempDir]) ->addSetup('setAutoRefresh', [$this->debugMode]) - ->addSetup('setContentType', [$config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML]) - ->addSetup('Nette\Utils\Html::$xhtml = ?', [(bool) $config['xhtml']]); + ->addSetup('setContentType', [$config->xhtml ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML]) + ->addSetup('Nette\Utils\Html::$xhtml = ?', [$config->xhtml]); - if ($config['strictTypes']) { + if ($config->strictTypes) { $latteFactory->addSetup('setStrictTypes', [true]); } $builder->addDefinition($this->prefix('templateFactory')) ->setType(Nette\Application\UI\ITemplateFactory::class) ->setFactory(Nette\Bridges\ApplicationLatte\TemplateFactory::class) - ->setArguments(['templateClass' => $config['templateClass']]); + ->setArguments(['templateClass' => $config->templateClass]); - foreach ($config['macros'] as $macro) { + foreach ($config->macros as $macro) { $this->addMacro($macro); } diff --git a/src/Bridges/ApplicationDI/RoutingExtension.php b/src/Bridges/ApplicationDI/RoutingExtension.php index 95f838be2..deae3c536 100644 --- a/src/Bridges/ApplicationDI/RoutingExtension.php +++ b/src/Bridges/ApplicationDI/RoutingExtension.php @@ -10,6 +10,7 @@ namespace Nette\Bridges\ApplicationDI; use Nette; +use Nette\DI\Definitions; use Tracy; @@ -18,36 +19,38 @@ */ final class RoutingExtension extends Nette\DI\CompilerExtension { - public $defaults = [ - 'debugger' => null, - 'routes' => [], // of [mask => action] - 'routeClass' => null, - 'cache' => false, - ]; - /** @var bool */ private $debugMode; public function __construct(bool $debugMode = false) { - $this->defaults['debugger'] = interface_exists(Tracy\IBarPanel::class); $this->debugMode = $debugMode; + + $this->config = new class { + /** @var bool */ + public $debugger; + /** @var string[] */ + public $routes = []; + /** @var ?string */ + public $routeClass = Nette\Application\Routers\Route::class; + /** @var bool */ + public $cache = false; + }; + $this->config->debugger = interface_exists(Tracy\IBarPanel::class); } public function loadConfiguration() { - $config = $this->validateConfig($this->defaults); $builder = $this->getContainerBuilder(); $router = $builder->addDefinition($this->prefix('router')) ->setType(Nette\Application\IRouter::class) ->setFactory(Nette\Application\Routers\RouteList::class); - $routeClass = $config['routeClass'] ?: Nette\Application\Routers\Route::class; - foreach ($config['routes'] as $mask => $action) { - $router->addSetup('$service[] = new ' . $routeClass . '(?, ?)', [$mask, $action]); + foreach ($this->config->routes as $mask => $action) { + $router->addSetup('$service[] = new ' . $this->config->routeClass . '(?, ?)', [$mask, $action]); } if ($this->name === 'routing') { @@ -60,9 +63,14 @@ public function beforeCompile() { $builder = $this->getContainerBuilder(); - if ($this->debugMode && $this->config['debugger'] && $application = $builder->getByType(Nette\Application\Application::class)) { - $builder->getDefinition($application)->addSetup('@Tracy\Bar::addPanel', [ - new Nette\DI\Definitions\Statement(Nette\Bridges\ApplicationTracy\RoutingPanel::class), + if ( + $this->debugMode && + $this->config->debugger && + ($name = $builder->getByType(Nette\Application\Application::class)) && + ($application = $builder->getDefinition($name)) instanceof Definitions\ServiceDefinition + ) { + $application->addSetup('@Tracy\Bar::addPanel', [ + new Definitions\Statement(Nette\Bridges\ApplicationTracy\RoutingPanel::class), ]); } } @@ -70,7 +78,7 @@ public function beforeCompile() public function afterCompile(Nette\PhpGenerator\ClassType $class) { - if (!empty($this->config['cache'])) { + if ($this->config->cache) { $method = $class->getMethod(Nette\DI\Container::getMethodName($this->prefix('router'))); try { $router = eval($method->getBody());