Security update for permissions_by_term
[yaffs-website] / vendor / behat / behat / src / Behat / Behat / Context / Suite / Setup / SuiteWithContextsSetup.php
1 <?php
2
3 /*
4  * This file is part of the Behat.
5  * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 namespace Behat\Behat\Context\Suite\Setup;
12
13 use Behat\Behat\Context\ContextClass\ClassGenerator;
14 use Behat\Behat\Context\Exception\ContextNotFoundException;
15 use Behat\Testwork\Filesystem\FilesystemLogger;
16 use Behat\Testwork\Suite\Exception\SuiteConfigurationException;
17 use Behat\Testwork\Suite\Setup\SuiteSetup;
18 use Behat\Testwork\Suite\Suite;
19 use Symfony\Component\ClassLoader\ClassLoader;
20
21 /**
22  * Generates classes for all contexts in the suite using autoloader.
23  *
24  * @author Konstantin Kudryashov <ever.zet@gmail.com>
25  */
26 final class SuiteWithContextsSetup implements SuiteSetup
27 {
28     /**
29      * @var ClassLoader
30      */
31     private $autoloader;
32     /**
33      * @var null|FilesystemLogger
34      */
35     private $logger;
36     /**
37      * @var ClassGenerator[]
38      */
39     private $classGenerators = array();
40
41     /**
42      * Initializes setup.
43      *
44      * @param ClassLoader           $autoloader
45      * @param null|FilesystemLogger $logger
46      */
47     public function __construct(ClassLoader $autoloader, FilesystemLogger $logger = null)
48     {
49         $this->autoloader = $autoloader;
50         $this->logger = $logger;
51     }
52
53     /**
54      * Registers class generator.
55      *
56      * @param ClassGenerator $generator
57      */
58     public function registerClassGenerator(ClassGenerator $generator)
59     {
60         $this->classGenerators[] = $generator;
61     }
62
63     /**
64      * {@inheritdoc}
65      */
66     public function supportsSuite(Suite $suite)
67     {
68         return $suite->hasSetting('contexts');
69     }
70
71     /**
72      * {@inheritdoc}
73      */
74     public function setupSuite(Suite $suite)
75     {
76         foreach ($this->getNormalizedContextClasses($suite) as $class) {
77             if (class_exists($class)) {
78                 continue;
79             }
80
81             $this->ensureContextDirectory($path = $this->findClassFile($class));
82
83             if ($content = $this->generateClass($suite, $class)) {
84                 $this->createContextFile($path, $content);
85             }
86         }
87     }
88
89     /**
90      * Returns normalized context classes.
91      *
92      * @param Suite $suite
93      *
94      * @return string[]
95      */
96     private function getNormalizedContextClasses(Suite $suite)
97     {
98         return array_map(
99             function ($context) {
100                 return is_array($context) ? current(array_keys($context)) : $context;
101             },
102             $this->getSuiteContexts($suite)
103         );
104     }
105
106     /**
107      * Returns array of context classes configured for the provided suite.
108      *
109      * @param Suite $suite
110      *
111      * @return string[]
112      *
113      * @throws SuiteConfigurationException If `contexts` setting is not an array
114      */
115     private function getSuiteContexts(Suite $suite)
116     {
117         $contexts = $suite->getSetting('contexts');
118
119         if (!is_array($contexts)) {
120             throw new SuiteConfigurationException(
121                 sprintf('`contexts` setting of the "%s" suite is expected to be an array, `%s` given.',
122                     $suite->getName(),
123                     gettype($contexts)
124                 ),
125                 $suite->getName()
126             );
127         }
128
129         return $contexts;
130     }
131
132     /**
133      * Creates context directory in the filesystem.
134      *
135      * @param string $path
136      */
137     private function createContextDirectory($path)
138     {
139         mkdir($path, 0777, true);
140
141         if ($this->logger) {
142             $this->logger->directoryCreated($path, 'place your context classes here');
143         }
144     }
145
146     /**
147      * Creates context class file in the filesystem.
148      *
149      * @param string $path
150      * @param string $content
151      */
152     private function createContextFile($path, $content)
153     {
154         file_put_contents($path, $content);
155
156         if ($this->logger) {
157             $this->logger->fileCreated($path, 'place your definitions, transformations and hooks here');
158         }
159     }
160
161     /**
162      * Finds file to store a class.
163      *
164      * @param string $class
165      *
166      * @return string
167      *
168      * @throws ContextNotFoundException If class file could not be determined
169      */
170     private function findClassFile($class)
171     {
172         list($classpath, $classname) = $this->findClasspathAndClass($class);
173         $classpath .= str_replace('_', DIRECTORY_SEPARATOR, $classname) . '.php';
174
175         foreach ($this->autoloader->getPrefixes() as $prefix => $dirs) {
176             if (0 === strpos($class, $prefix)) {
177                 return current($dirs) . DIRECTORY_SEPARATOR . $classpath;
178             }
179         }
180
181         if ($dirs = $this->autoloader->getFallbackDirs()) {
182             return current($dirs) . DIRECTORY_SEPARATOR . $classpath;
183         }
184
185         throw new ContextNotFoundException(sprintf(
186             'Could not find where to put "%s" class. Have you configured autoloader properly?',
187             $class
188         ), $class);
189     }
190
191     /**
192      * Generates class using registered class generators.
193      *
194      * @param Suite  $suite
195      * @param string $class
196      *
197      * @return null|string
198      */
199     private function generateClass(Suite $suite, $class)
200     {
201         $content = null;
202         foreach ($this->classGenerators as $generator) {
203             if ($generator->supportsSuiteAndClass($suite, $class)) {
204                 $content = $generator->generateClass($suite, $class);
205             }
206         }
207
208         return $content;
209     }
210
211     /**
212      * Ensures that directory for a classpath exists.
213      *
214      * @param string $classpath
215      */
216     private function ensureContextDirectory($classpath)
217     {
218         if (!is_dir(dirname($classpath))) {
219             $this->createContextDirectory(dirname($classpath));
220         }
221     }
222
223     /**
224      * Finds classpath and classname from class.
225      *
226      * @param string $class
227      *
228      * @return array
229      */
230     private function findClasspathAndClass($class)
231     {
232         if (false !== $pos = strrpos($class, '\\')) {
233             // namespaced class name
234             $classpath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
235             $classname = substr($class, $pos + 1);
236
237             return array($classpath, $classname);
238         }
239
240         // PEAR-like class name
241         $classpath = null;
242         $classname = $class;
243
244         return array($classpath, $classname);
245     }
246 }