From b3b97e7979f399a559d2437e1dc16f2df4954a6d Mon Sep 17 00:00:00 2001 From: Sergii Date: Wed, 8 Jul 2020 15:37:46 +0200 Subject: [PATCH 1/4] setup --- install/class.Setup.php | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/install/class.Setup.php b/install/class.Setup.php index 5bf5b7093e1..514a156965a 100644 --- a/install/class.Setup.php +++ b/install/class.Setup.php @@ -225,6 +225,11 @@ public function __invoke($params) } foreach ($parameters['configuration'] as $extension => $configs) { + + $sortedConfigs = $this->sortConfigs($serviceManager, $configs); + + var_dump(array_keys($sortedConfigs)); + foreach ($configs as $key => $config) { if (isset($config['type']) && $config['type'] === 'configurableService') { $className = $config['class']; @@ -287,6 +292,64 @@ public function __invoke($params) $this->logNotice('Installation completed!'); } + private function getDependencies(string $className): array + { + $reflection = new ReflectionClass($className); + + $constructor = $reflection->getConstructor(); + + $result = []; + + foreach ($constructor->getParameters() as $parameter) { + if ($class = $parameter->getClass()) { + $result[] = $class->name; + } + } + + return $result; + } + + private function sortDependencies(ServiceManager $serviceManager, array $graph, string $key, array &$result): void + { + echo "> $key\n"; + echo ">> {$graph[$key]['class']}\n"; + +// if (!isset($graph[$key]) || !$serviceManager->get($graph[$key]['class'])) { +// throw new Exception("No '$key' in graph"); +// } + + if (isset($result[$key])) { + return; + } + + if (!isset($graph[$key]['class'])) { + return; + } + + $className = $graph[$key]['class']; + + $deps = $this->getDependencies($className); + + var_dump($deps); + + foreach ($deps as $depKey) { + $this->sortDependencies($serviceManager, $graph, $depKey, $result); + } + + $result[$key] = $graph[$key]; + } + + private function sortConfigs(ServiceManager $serviceManager, array $config): array + { + $result = []; + + foreach ($config as $key => $value) { + $this->sortDependencies($serviceManager, $config, $key, $result); + } + + return $result; + } + /** * @param string $class * @param array $parametersToSort From 2109a116f453153570e40dd43602905abed9fe56 Mon Sep 17 00:00:00 2001 From: Sergii Date: Sat, 22 Aug 2020 17:21:01 +0200 Subject: [PATCH 2/4] feat: automatic sorting services in seed file by dependencies --- install/class.Setup.php | 66 +------ models/classes/install/seed/SeedSorter.php | 120 ++++++++++++ .../install/seed/SeedSorterException.php | 29 +++ test/unit/install/seed/SeedSorterTest.php | 174 ++++++++++++++++++ 4 files changed, 327 insertions(+), 62 deletions(-) create mode 100644 models/classes/install/seed/SeedSorter.php create mode 100644 models/classes/install/seed/SeedSorterException.php create mode 100644 test/unit/install/seed/SeedSorterTest.php diff --git a/install/class.Setup.php b/install/class.Setup.php index 514a156965a..ff83c589208 100644 --- a/install/class.Setup.php +++ b/install/class.Setup.php @@ -26,6 +26,7 @@ use oat\oatbox\log\LoggerService; use oat\oatbox\service\ConfigurableService; use oat\oatbox\service\ServiceManager; +use oat\tao\model\install\seed\SeedSorter; use Zend\ServiceManager\ServiceLocatorAwareInterface; class tao_install_Setup implements Action @@ -52,6 +53,7 @@ class tao_install_Setup implements Action * @throws common_ext_ExtensionException When a presented parameter is invalid or malformed. * @throws InvalidArgumentException * @throws tao_install_utils_Exception + * @throws ReflectionException */ public function __invoke($params) { @@ -223,12 +225,10 @@ public function __invoke($params) } elseif (!isset($persistences['type'])) { throw new InvalidArgumentException('Your config should have a \'default\' key under \'persistences\''); } - + $seedSorter = new SeedSorter(); foreach ($parameters['configuration'] as $extension => $configs) { - $sortedConfigs = $this->sortConfigs($serviceManager, $configs); - - var_dump(array_keys($sortedConfigs)); + $configs = $seedSorter->sort($configs); foreach ($configs as $key => $config) { if (isset($config['type']) && $config['type'] === 'configurableService') { @@ -292,64 +292,6 @@ public function __invoke($params) $this->logNotice('Installation completed!'); } - private function getDependencies(string $className): array - { - $reflection = new ReflectionClass($className); - - $constructor = $reflection->getConstructor(); - - $result = []; - - foreach ($constructor->getParameters() as $parameter) { - if ($class = $parameter->getClass()) { - $result[] = $class->name; - } - } - - return $result; - } - - private function sortDependencies(ServiceManager $serviceManager, array $graph, string $key, array &$result): void - { - echo "> $key\n"; - echo ">> {$graph[$key]['class']}\n"; - -// if (!isset($graph[$key]) || !$serviceManager->get($graph[$key]['class'])) { -// throw new Exception("No '$key' in graph"); -// } - - if (isset($result[$key])) { - return; - } - - if (!isset($graph[$key]['class'])) { - return; - } - - $className = $graph[$key]['class']; - - $deps = $this->getDependencies($className); - - var_dump($deps); - - foreach ($deps as $depKey) { - $this->sortDependencies($serviceManager, $graph, $depKey, $result); - } - - $result[$key] = $graph[$key]; - } - - private function sortConfigs(ServiceManager $serviceManager, array $config): array - { - $result = []; - - foreach ($config as $key => $value) { - $this->sortDependencies($serviceManager, $config, $key, $result); - } - - return $result; - } - /** * @param string $class * @param array $parametersToSort diff --git a/models/classes/install/seed/SeedSorter.php b/models/classes/install/seed/SeedSorter.php new file mode 100644 index 00000000000..e089f1403f7 --- /dev/null +++ b/models/classes/install/seed/SeedSorter.php @@ -0,0 +1,120 @@ + $serviceConfig) { + $this->sortDependencies($config, $serviceKey, $sortedConfig); + } + + return $sortedConfig; + } + + /** + * @throws ReflectionException + */ + private function getDependencies(string $className): array + { + $reflection = new ReflectionClass($className); + + $constructor = $reflection->getConstructor(); + + if (null === $constructor) { + return []; + } + + $dependencies = []; + + foreach ($constructor->getParameters() as $parameter) { + if ($class = $parameter->getClass()) { + $dependencies[] = $class->name; + } + } + + return $dependencies; + } + + /** + * @throws ReflectionException + */ + private function sortDependencies(array $config, string $serviceKey, array &$result): void + { + if (isset($result[$serviceKey])) { + return; + } + + if (!isset($config[$serviceKey]['class'])) { + $result[$serviceKey] = $config[$serviceKey]; + + return; + } + + $serviceClassName = $config[$serviceKey]['class']; + + $dependencies = $this->getDependencies($serviceClassName); + + foreach ($dependencies as $dependencyClassName) { + try { + $dependencyKey = $this->findServiceKey($config, $dependencyClassName); + $this->sortDependencies($config, $dependencyKey, $result); + } catch (SeedSorterException $e) { + continue; + } + } + + $result[$serviceKey] = $config[$serviceKey]; + } + + private function findServiceKey(array $config, string $className) + { + foreach ($config as $serviceKey => $serviceConfig) { + if (empty($serviceConfig['class'])) { + throw new SeedSorterException( + sprintf('%s not a class', $className) + ); + } + + if ( + $serviceConfig['class'] === $className + || is_subclass_of($serviceConfig['class'], $className) + ) { + return $serviceKey; + } + } + + throw new SeedSorterException( + sprintf('Service key for class %s not found', $className) + ); + } +} diff --git a/models/classes/install/seed/SeedSorterException.php b/models/classes/install/seed/SeedSorterException.php new file mode 100644 index 00000000000..347454fbf86 --- /dev/null +++ b/models/classes/install/seed/SeedSorterException.php @@ -0,0 +1,29 @@ +sorter = new SeedSorter(); + } + + /** + * @throws ReflectionException + */ + public function testSortConfigs(): void + { + $configConfiguration = [ + 'DepFromInterfaceInConfigClass' => [ + 'class' => DepFromInterfaceInConfigClass::class, + ], + 'DoubleDepFromServiceInConfigAndNotInConfigClass' => [ + 'class' => DoubleDepFromServiceInConfigAndNotInConfigClass::class, + ], + 'DepFromServiceNotInConfigClass' => [ + 'class' => DepFromServiceNotInConfigClass::class, + ], + 'Dep2FromServiceInConfigClass' => [ + 'class' => Dep2FromServiceInConfigClass::class, + ], + 'DoubleDepFromServiceInConfigClass' => [ + 'class' => DoubleDepFromServiceInConfigClass::class, + ], + 'DepFromServiceInConfigClass' => [ + 'class' => DepFromServiceInConfigClass::class, + ], + 'NoDepArrayClass' => [ + 'class' => NoDepArrayClass::class, + ], + 'NoDepClass' => [ + 'class' => NoDepClass::class, + ], + 'NotAClass' => [ + 'some' => 'config', + ], + ]; + + $sortedConfigs = $this->sorter->sort($configConfiguration); + + $this->assertKeysAfter(['NoDepClass'], 'DepFromServiceInConfigClass', $sortedConfigs); + $this->assertKeysAfter(['NoDepClass'], 'DepFromInterfaceInConfigClass', $sortedConfigs); + $this->assertKeysAfter( + ['DoubleDepFromServiceInConfigClass'], + 'DoubleDepFromServiceInConfigAndNotInConfigClass', + $sortedConfigs + ); + $this->assertKeysAfter( + ['NoDepClass', 'DepFromServiceInConfigClass'], + 'DoubleDepFromServiceInConfigClass', + $sortedConfigs + ); + + self::assertArrayHasKey('NoDepClass', $sortedConfigs); + self::assertArrayHasKey('NoDepArrayClass', $sortedConfigs); + self::assertArrayHasKey('DepFromServiceNotInConfigClass', $sortedConfigs); + self::assertArrayHasKey('NotAClass', $sortedConfigs); + } + + private function assertKeysAfter(array $priorKeys, string $needleKey, array $array): void + { + $maxKeyIndex = 0; + + $arrayKeys = array_keys($array); + + foreach ($priorKeys as $priorKey) { + $keyIndex = array_search($priorKey, $arrayKeys, true); + + self::assertIsInt($keyIndex); + + if ($maxKeyIndex < $keyIndex) { + $maxKeyIndex = $keyIndex; + } + } + + self::assertTrue($maxKeyIndex < array_search($needleKey, $arrayKeys, true)); + } +} From 1ff3a22fcefd09f3c884dde2ce71d796d060afce Mon Sep 17 00:00:00 2001 From: Sergii Date: Sun, 23 Aug 2020 13:52:04 +0200 Subject: [PATCH 3/4] chore: version bump --- manifest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.php b/manifest.php index 8f297f02dd4..b6ba5b338eb 100755 --- a/manifest.php +++ b/manifest.php @@ -62,7 +62,7 @@ 'label' => 'TAO Base', 'description' => 'TAO meta-extension', 'license' => 'GPL-2.0', - 'version' => '45.7.0', + 'version' => '45.8.0', 'author' => 'Open Assessment Technologies, CRP Henri Tudor', 'requires' => [ 'generis' => '>=13.0.0', From 78ee75aaf49e7195eea499be9a9accac33f55567 Mon Sep 17 00:00:00 2001 From: Sergii Date: Sun, 23 Aug 2020 13:56:51 +0200 Subject: [PATCH 4/4] chore: code style --- models/classes/install/seed/SeedSorter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/models/classes/install/seed/SeedSorter.php b/models/classes/install/seed/SeedSorter.php index e089f1403f7..019a514b123 100644 --- a/models/classes/install/seed/SeedSorter.php +++ b/models/classes/install/seed/SeedSorter.php @@ -89,7 +89,6 @@ private function sortDependencies(array $config, string $serviceKey, array &$res $dependencyKey = $this->findServiceKey($config, $dependencyClassName); $this->sortDependencies($config, $dependencyKey, $result); } catch (SeedSorterException $e) { - continue; } }