4 * This file is part of the Behat Testwork.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
11 namespace Behat\Testwork\ServiceContainer;
13 use Behat\Testwork\ServiceContainer\Exception\ExtensionInitializationException;
16 * Manages both default and 3rd-party extensions.
18 * @author Konstantin Kudryashov <ever.zet@gmail.com>
20 final class ExtensionManager
25 private $extensionsPath;
29 private $extensions = array();
31 * @var Extension[string]
33 private $locatedExtensions = array();
34 private $debugInformation = array(
35 'extensions_list' => array()
39 * Initializes manager.
41 * @param Extension[] $extensions List of default extensions
42 * @param null|string $extensionsPath Base path where to search custom extension files
44 public function __construct(array $extensions, $extensionsPath = null)
46 foreach ($extensions as $extension) {
47 $this->extensions[$extension->getConfigKey()] = $extension;
50 $this->extensionsPath = $extensionsPath;
54 * Sets path to directory in which manager will try to find extension files.
56 * @param null|string $path
58 public function setExtensionsPath($path)
60 $this->extensionsPath = $path;
64 * Activate extension by its locator.
66 * @param string $locator phar file name, php file name, class name
70 public function activateExtension($locator)
72 $extension = $this->initialize($locator);
74 $this->debugInformation['extensions_list'][] = $extension->getConfigKey();
76 return $this->extensions[$extension->getConfigKey()] = $extension;
80 * Returns specific extension by its name.
86 public function getExtension($key)
88 return isset($this->extensions[$key]) ? $this->extensions[$key] : null;
92 * Returns all available extensions.
96 public function getExtensions()
98 return $this->extensions;
102 * Returns activated extension names.
106 public function getExtensionClasses()
108 return array_map('get_class', array_values($this->extensions));
112 * Initializes all activated and predefined extensions.
114 public function initializeExtensions()
116 foreach ($this->extensions as $extension) {
117 $extension->initialize($this);
122 * Returns array with extensions debug information.
126 public function debugInformation()
128 return $this->debugInformation;
132 * Attempts to guess full extension class from relative.
134 * @param string $locator
138 private function getFullExtensionClass($locator)
140 $parts = explode('\\', $locator);
141 $name = preg_replace('/Extension$/', '', end($parts)) . 'Extension';
143 return $locator . '\\ServiceContainer\\' . $name;
147 * Initializes extension by id.
149 * @param string $locator
153 * @throws ExtensionInitializationException
155 private function initialize($locator)
157 if (isset($this->locatedExtensions[$locator])) {
158 return $this->locatedExtensions[$locator];
161 $extension = $this->instantiateExtension($locator);
162 $this->validateExtensionInstance($extension, $locator);
164 return $this->locatedExtensions[$locator] = $extension;
168 * Instantiates extension from its locator.
170 * @param string $locator
174 * @throws ExtensionInitializationException
176 private function instantiateExtension($locator)
178 if (class_exists($class = $locator)) {
182 if (class_exists($class = $this->getFullExtensionClass($locator))) {
186 if (file_exists($locator)) {
187 return require($locator);
190 if (file_exists($path = $this->extensionsPath . DIRECTORY_SEPARATOR . $locator)) {
191 return require($path);
194 throw new ExtensionInitializationException(sprintf(
195 '`%s` extension file or class could not be located.',
201 * Validates extension instance.
203 * @param Extension $extension
204 * @param string $locator
206 * @throws ExtensionInitializationException
208 private function validateExtensionInstance($extension, $locator)
210 if (null === $extension) {
211 throw new ExtensionInitializationException(sprintf(
212 '`%s` extension could not be found.',
217 if (!is_object($extension)) {
218 throw new ExtensionInitializationException(sprintf(
219 '`%s` extension could not be initialized.',
224 if (!$extension instanceof Extension) {
225 throw new ExtensionInitializationException(sprintf(
226 '`%s` extension class should implement Testwork Extension interface.',
227 get_class($extension)