From a0f372dca36ca0b0a2dc105e6b741d0f10b484d7 Mon Sep 17 00:00:00 2001 From: Andrii Vasyliev Date: Thu, 11 May 2017 13:29:46 +0000 Subject: [PATCH] added proper resolving of config dependencies with `Resolver` class --- src/Builder.php | 2 + src/Plugin.php | 8 +- src/Resolver.php | 100 ++++++++++++++++++ .../CircularDependencyException.php | 19 ++++ 4 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 src/Resolver.php create mode 100644 src/exceptions/CircularDependencyException.php diff --git a/src/Builder.php b/src/Builder.php index 4b920bc..ae1bad1 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -125,6 +125,8 @@ public function buildConfigs($files = null) if (is_null($files)) { $files = $this->files; } + $resolver = new Resolver($files); + $files = $resolver->get(); foreach ($files as $name => $paths) { $olddefs = get_defined_constants(); $configs = $this->loadConfigs($paths); diff --git a/src/Plugin.php b/src/Plugin.php index 6c685a1..9c08bc1 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -263,15 +263,15 @@ protected function prepareAliases(PackageInterface $package, $psr, $dev = false) */ public function preparePath(PackageInterface $package, $path) { + if (strncmp($path, '$', 1) === 0) { + return $path; + } + $skippable = strncmp($path, '?', 1) === 0 ? '?' : ''; if ($skippable) { $path = substr($path, 1); } - if (strncmp($path, '$', 1) === 0) { - $path = Builder::path(substr($path, 1)); - } - if (!$this->getFilesystem()->isAbsolutePath($path)) { $prefix = $package instanceof RootPackageInterface ? $this->getBaseDir() diff --git a/src/Resolver.php b/src/Resolver.php new file mode 100644 index 0000000..e8fd961 --- /dev/null +++ b/src/Resolver.php @@ -0,0 +1,100 @@ + + */ +class Resolver +{ + protected $order = []; + + protected $deps = []; + + protected $following = []; + + public function __construct(array $files) + { + $this->files = $files; + + $this->collectDeps(); + foreach (array_keys($this->files) as $name) { + $this->followDeps($name); + } + + } + + public function get() + { + $result = []; + foreach ($this->order as $name) { + $result[$name] = $this->resolveDeps($this->files[$name]); + } + + return $result; + } + + protected function resolveDeps(array $paths) + { + foreach ($paths as &$path) { + $dep = $this->isDep($path); + if ($dep) { + $path = Builder::path($dep); + } + } + + return $paths; + } + + protected function followDeps($name) + { + if (isset($this->order[$name])) { + return; + } + if (isset($this->following[$name])) { + throw new CircularDependencyException($name . ' ' . implode(',', $this->following)); + } + $this->following[$name] = $name; + if (isset($this->deps[$name])) { + foreach ($this->deps[$name] as $dep) { + $this->followDeps($dep); + } + } + $this->order[$name] = $name; + unset($this->following[$name]); + } + + protected function collectDeps() + { + foreach ($this->files as $name => $paths) { + foreach ($paths as $path) { + $dep = $this->isDep($path); + if ($dep) { + if (!isset($this->deps[$name])) { + $this->deps[$name] = []; + } + $this->deps[$name][$dep] = $dep; + } + } + } + } + + protected function isDep($path) + { + return strncmp($path, '$', 1) === 0 ? substr($path, 1) : false; + } + +} diff --git a/src/exceptions/CircularDependencyException.php b/src/exceptions/CircularDependencyException.php new file mode 100644 index 0000000..259c2f5 --- /dev/null +++ b/src/exceptions/CircularDependencyException.php @@ -0,0 +1,19 @@ + + */ +class CircularDependencyException extends Exception +{ +}