diff --git a/src/CompilerExtension.php b/src/CompilerExtension.php index 103a508..6295ca8 100644 --- a/src/CompilerExtension.php +++ b/src/CompilerExtension.php @@ -18,11 +18,9 @@ namespace BiuradPHP\DependencyInjection; use Nette; -use Nette\DI\Compiler; use BiuradPHP\DependencyInjection\Config; use Nette\DI\CompilerExtension as NetteCompilerExtension; use BiuradPHP\DependencyInjection\Concerns\ExtensionDefinitionsHelper; -use BiuradPHP\DependencyInjection\Interfaces\PassCompilerAwareInterface; /** * Configurator compiling extension. @@ -34,7 +32,7 @@ abstract class CompilerExtension extends NetteCompilerExtension { /** @var ExtensionDefinitionsHelper|null */ private $helper; - + /** * @internal do not use this function */ @@ -43,18 +41,6 @@ public function getName() return $this->name; } - /** @return static */ - public function setCompiler(Compiler $compiler, string $name) - { - $compiler = parent::setCompiler($compiler, $name); - - if ($this instanceof PassCompilerAwareInterface) { - $this->addCompilerPasses($this->compiler); - } - - return $compiler; - } - /** * ContainerBuilder is a DI container that provides an API to easily describe services. * @@ -70,7 +56,7 @@ public function getContainerBuilder(): Nette\DI\ContainerBuilder * * @return array An array of configuration or false if not found */ - public function getExtensionConfig(string $name) + protected function getExtensionConfig(string $name) { try { $extensionConfigs = $this->compiler->getExtension($name); @@ -91,12 +77,12 @@ public function getExtensionConfig(string $name) protected function getHelper(): ExtensionDefinitionsHelper { - if ($this->helper === null) { - $this->helper = new ExtensionDefinitionsHelper($this->compiler); - } + if ($this->helper === null) { + $this->helper = new ExtensionDefinitionsHelper($this->compiler); + } - return $this->helper; - } + return $this->helper; + } /** * Processes configuration data. Intended to be overridden by descendant. diff --git a/src/Concerns/Compiler.php b/src/Concerns/Compiler.php index 3291af2..00f1cca 100644 --- a/src/Concerns/Compiler.php +++ b/src/Concerns/Compiler.php @@ -24,6 +24,7 @@ use Nette\DI\CompilerExtension, Nette\DI\DependencyChecker; use BiuradPHP\DependencyInjection\Exceptions\InvalidConfigurationException; use BiuradPHP\DependencyInjection\Interfaces\CompilerPassInterface; +use BiuradPHP\DependencyInjection\Interfaces\PassCompilerAwareInterface; /** * DI container compiler. @@ -149,6 +150,12 @@ public function hasExtension(string $name) */ public function getCompilerPasses(): array { + // Backward compatability for Nette + foreach ($this->extensions as $name => $extension) { + if ($extension instanceof PassCompilerAwareInterface) { + $extension->addCompilerPasses($this); + } + } return $this->passConfig->getPasses(); } diff --git a/src/Concerns/ImportsLocator.php b/src/Concerns/ImportsLocator.php new file mode 100644 index 0000000..c6fcada --- /dev/null +++ b/src/Concerns/ImportsLocator.php @@ -0,0 +1,114 @@ + + * @copyright 2019 Biurad Group (https://biurad.com/) + * @license https://opensource.org/licenses/BSD-3-Clause License + * + * @link https://www.biurad.com/projects/dependencyinjection + * @since Version 0.1 + */ + +namespace BiuradPHP\DependencyInjection\Concerns; + +use Composer\Autoload\ClassLoader; +use InvalidArgumentException; +use Nette\DI\CompilerExtension; +use Nette\NotSupportedException; +use Nette\Utils\Strings; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use ReflectionClass; +use ReflectionObject; +use RuntimeException; +use SplFileInfo; + +class ImportsLocator +{ + /** + * Returns the file path for a given compiler extension resource. + * + * A Resource can be a file or a directory. + * + * The resource name must follow the following pattern: + * + * "@CompilerExtension/path/to/a/file.something" + * + * where CompilerExtension is the name of the nette-di extension + * and the remaining part is the relative path in the class. + * + * @param CompilerExtension $extension + * @param string $name + * @param bool $throw + * + * @return string The absolute path of the resource + * + * @throws InvalidArgumentException if the file cannot be found or the name is not valid + * @throws RuntimeException if the name contains invalid/unsafe characters + * @throws NotSupportedException if the $name doesn't match in $extension + */ + public static function getLocation(CompilerExtension $extension, string $name, bool $throw = true) + { + if ('@' !== $name[0] && true === $throw) { + throw new InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name)); + } + + if (false !== strpos($name, '..')) { + throw new RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name)); + } + + $path = ''; + if (false !== strpos($bundleName = substr($name, 1), '/')) { + [$bundleName, $path] = explode('/', $bundleName, 2); + } + + if (false === strpos(get_class($extension), $bundleName)) { + throw new NotSupportedException(sprintf('Resource path is not supported for %s', $bundleName)); + } + + /** @var RecursiveIteratorIterator|SplFileInfo[] $iterator */ + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($bundlePath = self::findComposerDirectory($extension)), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + if (strlen($file->getPathname()) === strlen($bundlePath.$path) && file_exists($bundlePath.$path)) { + return strtr($file->getPathname(), ['\\' => '/']); + } + } + + throw new InvalidArgumentException(sprintf('Unable to find file "%s".', $name)); + } + + /** + * @param CompilerExtension $extension + * + * @return string + */ + private static function findComposerDirectory(CompilerExtension $extension): string + { + $path = dirname((new ReflectionClass(ClassLoader::class))->getFileName()); + $directory = dirname((new ReflectionObject($extension))->getFileName()); + + $packagist = json_decode(file_get_contents($path.'/installed.json'), true); + + foreach ($packagist as $package) { + $packagePath = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, dirname($path, 1) .'/'. $package['name']); + if (!Strings::startsWith($directory, $packagePath)) { + continue; + } + $pathPrefix = current($package['autoload']['psr-4'] ?? $package['autoload']['psr-0'] ?? $package['autoload']['classmap']); + + return sprintf('%s/%s/', $packagePath, rtrim($pathPrefix, '/')); + } + + return dirname($directory, 1).'/'; + } +} diff --git a/src/Config/Adapter/IniAdapter.php b/src/Config/Adapter/IniAdapter.php index aac2b00..53248b1 100644 --- a/src/Config/Adapter/IniAdapter.php +++ b/src/Config/Adapter/IniAdapter.php @@ -17,7 +17,7 @@ namespace BiuradPHP\DependencyInjection\Config\Adapter; -use BiuradPHP\Loader\Files\Adapters\IniAdapter as BiuradPHPIniAdapter; +use BiuradPHP\Loader\Files\Adapters\IniFileAdapter as BiuradPHPIniAdapter; use Nette; /**