From 378dc91e9d72bc4608015b04267d9db029e5da5b Mon Sep 17 00:00:00 2001 From: Tibor Kotosz Date: Sun, 8 Nov 2015 13:51:49 +0100 Subject: [PATCH] Initial commit of the extenstion driver locator component --- .gitignore | 5 + composer.json | 31 ++++ .../DriverClassNameResolver.php | 45 ++++++ .../DriverClassValidator.php | 44 ++++++ .../DriverInterface.php | 24 ++++ .../ExtensionDriverLocator/DriverLocator.php | 133 ++++++++++++++++++ .../DriverNodeBuilder.php | 99 +++++++++++++ 7 files changed, 381 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 src/Bex/Behat/ExtensionDriverLocator/DriverClassNameResolver.php create mode 100644 src/Bex/Behat/ExtensionDriverLocator/DriverClassValidator.php create mode 100644 src/Bex/Behat/ExtensionDriverLocator/DriverInterface.php create mode 100644 src/Bex/Behat/ExtensionDriverLocator/DriverLocator.php create mode 100644 src/Bex/Behat/ExtensionDriverLocator/DriverNodeBuilder.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83a980 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Composer packages directory +/vendor + +# Composer executable files directory +/bin diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4522caa --- /dev/null +++ b/composer.json @@ -0,0 +1,31 @@ +{ + "name": "bex/behat-extension-driver-locator", + "type": "library", + "description": "Driver locator tool for behat extensions", + "keywords": ["tdd","bdd","behat"], + "homepage": "https://github.com/tkotosz/behat-extension-driver-locator", + "license": "MIT", + "authors": [ + { + "name": "Tibor Kotosz", + "email": "kotosy@gmail.com", + "homepage": "https://github.com/tkotosz", + "role": "Developer" + } + ], + "require": { + "php" : "^5.4", + "behat/behat" : "^3.0.0" + }, + "require-dev": { + "phpspec/phpspec" : "^2.3.0" + }, + "config": { + "bin-dir": "bin" + }, + "autoload": { + "psr-0": { + "": "src" + } + } +} diff --git a/src/Bex/Behat/ExtensionDriverLocator/DriverClassNameResolver.php b/src/Bex/Behat/ExtensionDriverLocator/DriverClassNameResolver.php new file mode 100644 index 0000000..1562eac --- /dev/null +++ b/src/Bex/Behat/ExtensionDriverLocator/DriverClassNameResolver.php @@ -0,0 +1,45 @@ +namespace = $namespace; + $this->classValidator = $classValidator; + } + + /** + * @param string $driverKey + * + * @return string + */ + public function getClassNameByDriverKey($driverKey) + { + $driverClass = $this->namespace . '\\' . ucfirst(DIContainer::camelize($driverKey)); + + if (!$this->classValidator->isValidDriverClass($driverClass)) { + throw new \Exception(sprintf('Driver %s was not found in %s', $driverKey, $driverClass)); + } + + return $driverClass; + } +} \ No newline at end of file diff --git a/src/Bex/Behat/ExtensionDriverLocator/DriverClassValidator.php b/src/Bex/Behat/ExtensionDriverLocator/DriverClassValidator.php new file mode 100644 index 0000000..24d8983 --- /dev/null +++ b/src/Bex/Behat/ExtensionDriverLocator/DriverClassValidator.php @@ -0,0 +1,44 @@ +parent = $parent; + } + + /** + * @param string $className + * + * @return boolean + */ + public function isValidDriverClass($className) + { + if (!class_exists($className)) { + return false; + } + + if (!is_subclass_of($className, DriverInterface::class)) { + return false; + } + + if (!empty($this->parent) && !is_subclass_of($className, $this->parent)) { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/src/Bex/Behat/ExtensionDriverLocator/DriverInterface.php b/src/Bex/Behat/ExtensionDriverLocator/DriverInterface.php new file mode 100644 index 0000000..836dfb2 --- /dev/null +++ b/src/Bex/Behat/ExtensionDriverLocator/DriverInterface.php @@ -0,0 +1,24 @@ +classNameResolver = $classNameResolver; + } + + /** + * @param string $namespace + * @param string $parent + * + * @return Locator + */ + public static function getInstance($namespace, $parent = '') + { + return new self(new ClassNameResolver($namespace, new ClassValidator($parent))); + } + + /** + * @param ContainerBuilder $container + * @param array $configs + * + * @return DriverInterface[] + */ + public function findDrivers(ContainerBuilder $container, array $activeDrivers, array $driverConfigs) + { + $this->createDrivers($activeDrivers); + $configTree = $this->configureDrivers($driverConfigs); + $driverConfigs = $this->processDriverConfiguration($configTree, $driverConfigs); + $this->loadDrivers($container, $driverConfigs); + + return $this->drivers; + } + + /** + * @return DriverInterface[] + */ + public function getDrivers() + { + return $this->drivers; + } + + /** + * @param array $driverKeys + * + * @return DriverInterface[] + */ + private function createDrivers($driverKeys) + { + $this->drivers = []; + + foreach ($driverKeys as $driverKey) { + $driverClass = $this->classNameResolver->getClassNameByDriverKey($driverKey); + $this->drivers[$driverKey] = new $driverClass(); + } + + return $this->drivers; + } + + /** + * @param array $driverConfigs + * + * @return NodeInterface + */ + private function configureDrivers($driverConfigs) + { + $tree = new TreeBuilder(); + $root = $tree->root('drivers'); + + foreach ($this->drivers as $driverKey => $driver) { + $driver->configure($root->children()->arrayNode($driverKey)); + } + + return $tree->buildTree(); + } + + /** + * @param NodeInterface $configTree + * @param array $configs + * + * @return array The processed configuration + */ + private function processDriverConfiguration(NodeInterface $configTree, array $configs) + { + $configProcessor = new Processor(); + + foreach ($this->drivers as $driverKey => $driver) { + $configs[$driverKey] = isset($configs[$driverKey]) ? $configs[$driverKey] : []; + } + + return $configProcessor->process($configTree, ['drivers' => $configs]); + } + + /** + * @param ContainerBuilder $container + * @param array $driverConfigs + * + * @return DriverInterface[] + */ + private function loadDrivers(ContainerBuilder $container, array $driverConfigs) + { + foreach ($this->drivers as $driverKey => $driver) { + $driver->load($container, $driverConfigs[$driverKey]); + } + + return $this->drivers; + } +} \ No newline at end of file diff --git a/src/Bex/Behat/ExtensionDriverLocator/DriverNodeBuilder.php b/src/Bex/Behat/ExtensionDriverLocator/DriverNodeBuilder.php new file mode 100644 index 0000000..f72bf41 --- /dev/null +++ b/src/Bex/Behat/ExtensionDriverLocator/DriverNodeBuilder.php @@ -0,0 +1,99 @@ +driverClassNameResolver = $driverClassNameResolver; + } + + /** + * @param string $namespace + * @param string $parent + * + * @return NodeBuilder + */ + public static function getInstance($namespace, $parent = '') + { + return new self(new ClassNameResolver($namespace, new ClassValidator($parent))); + } + + /** + * @param ArrayNodeDefinition $builder + * @param string $activeDriversNodeName + * @param string $driversNodeName + * @param array $defaultActiveDrivers + * + * @return void + */ + public function buildDriverNodes( + ArrayNodeDefinition $builder, + $activeDriversNodeName, + $driversNodeName, + $defaultActiveDrivers + ) { + $builder + ->children() + ->arrayNode($activeDriversNodeName) + ->defaultValue($defaultActiveDrivers) + ->beforeNormalization() + ->ifString() + ->then($this->getDefaultValueInitializer()) + ->end() + ->validate() + ->ifTrue($this->getDriverKeyValidator()) + ->thenInvalid('%s') + ->end() + ->prototype('scalar')->end() + ->end() + ->end() + ->fixXmlConfig($driversNodeName . '_child', $driversNodeName) + ->children() + ->arrayNode($driversNodeName) + ->prototype('array') + ->prototype('scalar')->end() + ->end() + ->end() + ->end(); + } + + /** + * @return \Closure + */ + private function getDefaultValueInitializer() + { + return function ($value) { + return [$value]; + }; + } + + /** + * @return \Closure + */ + private function getDriverKeyValidator() + { + $classNameResolver = $this->driverClassNameResolver; + + return function ($driverKeys) use ($classNameResolver) { + foreach ($driverKeys as $driverKey) { + $classNameResolver->getClassNameByDriverKey($driverKey); + } + + return false; + }; + } +} \ No newline at end of file