Configuration::config()   F
last analyzed

Complexity

Conditions 26
Paths 4630

Size

Total Lines 121

Duplication

Lines 6
Ratio 4.96 %

Importance

Changes 0
Metric Value
cc 26
nc 4630
nop 1
dl 6
loc 121
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Codeception;
4
5
use Codeception\Exception\ConfigurationException;
6
use Codeception\Lib\ParamsLoader;
7
use Codeception\Util\Autoload;
8
use Codeception\Util\Template;
9
use Symfony\Component\Finder\Finder;
10
use Symfony\Component\Finder\SplFileInfo;
11
use Symfony\Component\Yaml\Exception\ParseException;
12
use Symfony\Component\Yaml\Yaml;
13
14
class Configuration
15
{
16
    protected static $suites = [];
17
18
    /**
19
     * @var array Current configuration
20
     */
21
    protected static $config = null;
22
23
    /**
24
     * @var array environmental files configuration cache
25
     */
26
    protected static $envConfig = [];
27
28
    /**
29
     * @var string Directory containing main configuration file.
30
     * @see self::projectDir()
31
     */
32
    protected static $dir = null;
33
34
    /**
35
     * @var string Current project output directory.
36
     */
37
    protected static $outputDir = null;
38
39
    /**
40
     * @var string Current project data directory. This directory is used to hold
41
     * sql dumps and other things needed for current project tests.
42
     */
43
    protected static $dataDir = null;
44
45
    /**
46
     * @var string Directory with test support files like Actors, Helpers, PageObjects, etc
47
     */
48
    protected static $supportDir = null;
49
50
    /**
51
     * @var string Directory containing environment configuration files.
52
     */
53
    protected static $envsDir = null;
54
55
    /**
56
     * @var string Directory containing tests and suites of the current project.
57
     */
58
    protected static $testsDir = null;
59
60
    public static $lock = false;
61
62
    protected static $di;
63
64
    /**
65
     * @var array Default config
66
     */
67
    public static $defaultConfig = [
68
        'actor_suffix'=> 'Tester',
69
        'namespace'  => '',
70
        'include'    => [],
71
        'paths'      => [],
72
        'extends'    => null,
73
        'suites'     => [],
74
        'modules'    => [],
75
        'extensions' => [
76
            'enabled'  => [],
77
            'config'   => [],
78
            'commands' => [],
79
        ],
80
        'reporters'  => [
81
            'xml'    => 'Codeception\PHPUnit\Log\JUnit',
82
            'html'   => 'Codeception\PHPUnit\ResultPrinter\HTML',
83
            'report' => 'Codeception\PHPUnit\ResultPrinter\Report',
84
            'tap'    => 'PHPUnit\Util\Log\TAP',
85
            'json'   => 'PHPUnit\Util\Log\JSON',
86
        ],
87
        'groups'     => [],
88
        'settings'   => [
89
            'colors'                    => true,
90
            'bootstrap'                 => false,
91
            'strict_xml'                => false,
92
            'lint'                      => true,
93
            'backup_globals'            => true,
94
            'log_incomplete_skipped'    => false,
95
            'report_useless_tests'      => false,
96
            'disallow_test_output'      => false,
97
            'be_strict_about_changes_to_global_state' => false
98
        ],
99
        'coverage'   => [],
100
        'params'     => [],
101
        'gherkin'    => []
102
    ];
103
104
    public static $defaultSuiteSettings = [
105
        'actor'       => null,
106
        'class_name'  => null, // Codeception <2.3 compatibility
107
        'modules'     => [
108
            'enabled' => [],
109
            'config'  => [],
110
            'depends' => []
111
        ],
112
        'path'        => null,
113
        'extends'     => null,
114
        'namespace'   => null,
115
        'groups'      => [],
116
        'formats'     => [],
117
        'shuffle'     => false,
118
        'extensions'  => [ // suite extensions
119
            'enabled' => [],
120
            'config' => [],
121
        ],
122
        'error_level' => 'E_ALL & ~E_STRICT & ~E_DEPRECATED',
123
    ];
124
125
    protected static $params;
126
127
    /**
128
     * Loads global config file which is `codeception.yml` by default.
129
     * When config is already loaded - returns it.
130
     *
131
     * @param null $configFile
132
     * @return array
133
     * @throws Exception\ConfigurationException
134
     */
135
    public static function config($configFile = null)
136
    {
137
        if (!$configFile && self::$config) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$config of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
138
            return self::$config;
139
        }
140
141
        if (self::$config && self::$lock) {
0 ignored issues
show
Bug Best Practice introduced by
The expression self::$config of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
142
            return self::$config;
143
        }
144
145
        if ($configFile === null) {
146
            $configFile = getcwd() . DIRECTORY_SEPARATOR . 'codeception.yml';
147
        }
148
149
        if (is_dir($configFile)) {
150
            $configFile = $configFile . DIRECTORY_SEPARATOR . 'codeception.yml';
151
        }
152
153
        $dir = realpath(dirname($configFile));
154
        self::$dir = $dir;
155
156
        $configDistFile = $dir . DIRECTORY_SEPARATOR . 'codeception.dist.yml';
157
158
        if (!(file_exists($configDistFile) || file_exists($configFile))) {
159
            throw new ConfigurationException("Configuration file could not be found.\nRun `bootstrap` to initialize Codeception.", 404);
160
        }
161
162
        // Preload config to retrieve params such that they are applied to codeception config file below
163
        $tempConfig = self::$defaultConfig;
164
165
        $distConfigContents = "";
166
        if (file_exists($configDistFile)) {
167
            $distConfigContents = file_get_contents($configDistFile);
168
            $tempConfig = self::mergeConfigs($tempConfig, self::getConfFromContents($distConfigContents, $configDistFile));
169
        }
170
171
        $configContents = "";
172
        if (file_exists($configFile)) {
173
            $configContents = file_get_contents($configFile);
174
            $tempConfig = self::mergeConfigs($tempConfig, self::getConfFromContents($configContents, $configFile));
175
        }
176
        self::prepareParams($tempConfig);
177
178
        // load config using params
179
        $config = self::mergeConfigs(self::$defaultConfig, self::getConfFromContents($distConfigContents, $configDistFile));
180
        $config = self::mergeConfigs($config, self::getConfFromContents($configContents, $configFile));
181
182
        if ($config == self::$defaultConfig) {
183
            throw new ConfigurationException("Configuration file is invalid");
184
        }
185
186
        // we check for the "extends" key in the yml file
187
        if (isset($config['extends'])) {
188
            // and now we search for the file
189
            $presetFilePath = codecept_absolute_path($config['extends']);
190
            if (file_exists($presetFilePath)) {
191
                // and merge it with our configuration file
192
                $config = self::mergeConfigs(self::getConfFromFile($presetFilePath), $config);
193
            }
194
        }
195
196
        self::$config = $config;
197
198
        // compatibility with suites created by Codeception < 2.3.0
199 View Code Duplication
        if (!isset($config['paths']['output']) and isset($config['paths']['log'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
            $config['paths']['output'] = $config['paths']['log'];
201
        }
202
203
        if (isset(self::$config['actor'])) {
204
            self::$config['actor_suffix'] = self::$config['actor']; // old compatibility
205
        }
206
207 View Code Duplication
        if (!isset($config['paths']['support']) and isset($config['paths']['helpers'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
            $config['paths']['support'] = $config['paths']['helpers'];
209
        }
210
211
        if (!isset($config['paths']['output'])) {
212
            throw new ConfigurationException('Output path is not defined by key "paths: output"');
213
        }
214
215
        self::$outputDir = $config['paths']['output'];
216
217
        // fill up includes with wildcard expansions
218
        $config['include'] = self::expandWildcardedIncludes($config['include']);
219
220
        // config without tests, for inclusion of other configs
221
        if (count($config['include'])) {
222
            self::$config = $config;
223
            if (!isset($config['paths']['tests'])) {
224
                 return $config;
225
            }
226
        }
227
228
        if (!isset($config['paths']['tests'])) {
229
            throw new ConfigurationException(
230
                'Tests directory is not defined in Codeception config by key "paths: tests:"'
231
            );
232
        }
233
234
        if (!isset($config['paths']['data'])) {
235
            throw new ConfigurationException('Data path is not defined Codeception config by key "paths: data"');
236
        }
237
238
        if (!isset($config['paths']['support'])) {
239
            throw new ConfigurationException('Helpers path is not defined by key "paths: support"');
240
        }
241
242
        self::$dataDir = $config['paths']['data'];
243
        self::$supportDir = $config['paths']['support'];
244
        self::$testsDir = $config['paths']['tests'];
245
246
        if (isset($config['paths']['envs'])) {
247
            self::$envsDir = $config['paths']['envs'];
248
        }
249
250
        Autoload::addNamespace(self::$config['namespace'], self::supportDir());
251
        self::loadBootstrap($config['settings']['bootstrap']);
252
        self::loadSuites();
253
254
        return $config;
255
    }
256
257
    protected static function loadBootstrap($bootstrap)
258
    {
259
        if (!$bootstrap) {
260
            return;
261
        }
262
        $bootstrap = self::$dir . DIRECTORY_SEPARATOR . self::$testsDir . DIRECTORY_SEPARATOR . $bootstrap;
263
        if (file_exists($bootstrap)) {
264
            include_once $bootstrap;
265
        }
266
    }
267
268
    protected static function loadSuites()
269
    {
270
        $suites = Finder::create()
271
            ->files()
272
            ->name('*.{suite,suite.dist}.yml')
273
            ->in(self::$dir . DIRECTORY_SEPARATOR . self::$testsDir)
274
            ->depth('< 1')
275
            ->sortByName();
276
277
        self::$suites = [];
278
279
        foreach (array_keys(self::$config['suites']) as $suite) {
280
            self::$suites[$suite] = $suite;
281
        }
282
283
        /** @var SplFileInfo $suite */
284
        foreach ($suites as $suite) {
285
            preg_match('~(.*?)(\.suite|\.suite\.dist)\.yml~', $suite->getFilename(), $matches);
286
            self::$suites[$matches[1]] = $matches[1];
287
        }
288
    }
289
290
    /**
291
     * Returns suite configuration. Requires suite name and global config used (Configuration::config)
292
     *
293
     * @param string $suite
294
     * @param array $config
295
     * @return array
296
     * @throws \Exception
297
     */
298
    public static function suiteSettings($suite, $config)
299
    {
300
        // cut namespace name from suite name
301
        if ($suite != $config['namespace'] && substr($suite, 0, strlen($config['namespace'])) == $config['namespace']) {
302
            $suite = substr($suite, strlen($config['namespace']));
303
        }
304
305
        if (!in_array($suite, self::$suites)) {
306
            throw new ConfigurationException("Suite $suite was not loaded");
307
        }
308
309
        // load global config
310
        $globalConf = $config['settings'];
311
        foreach (['modules', 'coverage', 'namespace', 'groups', 'env', 'gherkin', 'extensions'] as $key) {
312
            if (isset($config[$key])) {
313
                $globalConf[$key] = $config[$key];
314
            }
315
        }
316
        $settings = self::mergeConfigs(self::$defaultSuiteSettings, $globalConf);
317
318
        // load suite config
319
        $settings = self::loadSuiteConfig($suite, $config['paths']['tests'], $settings);
320
        // load from environment configs
321
        if (isset($config['paths']['envs'])) {
322
            $envConf = self::loadEnvConfigs(self::$dir . DIRECTORY_SEPARATOR . $config['paths']['envs']);
323
            $settings = self::mergeConfigs($settings, $envConf);
324
        }
325
326
        if (!$settings['actor']) {
327
            // Codeception 2.2 compatibility
328
            $settings['actor'] = $settings['class_name'];
329
        }
330
331
        if (!$settings['path']) {
332
            // take a suite path from its name
333
            $settings['path'] = $suite;
334
        }
335
336
        $config['paths']['tests'] = str_replace('/', DIRECTORY_SEPARATOR, $config['paths']['tests']);
337
338
        $settings['path'] = self::$dir . DIRECTORY_SEPARATOR . $config['paths']['tests']
339
            . DIRECTORY_SEPARATOR . $settings['path'] . DIRECTORY_SEPARATOR;
340
341
342
343
        return $settings;
344
    }
345
346
    /**
347
     * Loads environments configuration from set directory
348
     *
349
     * @param string $path path to the directory
350
     * @return array
351
     */
352
    protected static function loadEnvConfigs($path)
353
    {
354
        if (isset(self::$envConfig[$path])) {
355
            return self::$envConfig[$path];
356
        }
357
        if (!is_dir($path)) {
358
            self::$envConfig[$path] = [];
359
            return self::$envConfig[$path];
360
        }
361
362
        $envFiles = Finder::create()
363
            ->files()
364
            ->name('*.yml')
365
            ->in($path)
366
            ->depth('< 2');
367
368
        $envConfig = [];
369
        /** @var SplFileInfo $envFile */
370
        foreach ($envFiles as $envFile) {
371
            $env = str_replace(['.dist.yml', '.yml'], '', $envFile->getFilename());
372
            $envConfig[$env] = [];
373
            $envPath = $path;
374
            if ($envFile->getRelativePath()) {
375
                $envPath .= DIRECTORY_SEPARATOR . $envFile->getRelativePath();
376
            }
377
            foreach (['.dist.yml', '.yml'] as $suffix) {
378
                $envConf = self::getConfFromFile($envPath . DIRECTORY_SEPARATOR . $env . $suffix, null);
379
                if ($envConf === null) {
380
                    continue;
381
                }
382
                $envConfig[$env] = self::mergeConfigs($envConfig[$env], $envConf);
383
            }
384
        }
385
386
        self::$envConfig[$path] = ['env' => $envConfig];
387
        return self::$envConfig[$path];
388
    }
389
390
    /**
391
     * Loads configuration from Yaml data
392
     *
393
     * @param string $contents Yaml config file contents
394
     * @param string $filename which is supposed to be loaded
395
     * @return array
396
     * @throws ConfigurationException
397
     */
398
    protected static function getConfFromContents($contents, $filename = '(.yml)')
399
    {
400
        if (self::$params) {
401
            $template = new Template($contents, '%', '%');
402
            $template->setVars(self::$params);
403
            $contents = $template->produce();
404
        }
405
406
        try {
407
            return Yaml::parse($contents);
408
        } catch (ParseException $exception) {
409
            throw new ConfigurationException(
410
                sprintf(
411
                    "Error loading Yaml config from `%s`\n \n%s\nRead more about Yaml format https://goo.gl/9UPuEC",
412
                    $filename,
413
                    $exception->getMessage()
414
                )
415
            );
416
        }
417
    }
418
419
    /**
420
     * Loads configuration from Yaml file or returns given value if the file doesn't exist
421
     *
422
     * @param string $filename filename
423
     * @param mixed $nonExistentValue value used if filename is not found
424
     * @return array
425
     */
426
    protected static function getConfFromFile($filename, $nonExistentValue = [])
427
    {
428
        if (file_exists($filename)) {
429
            $yaml = file_get_contents($filename);
430
            return self::getConfFromContents($yaml, $filename);
431
        }
432
        return $nonExistentValue;
433
    }
434
435
    /**
436
     * Returns all possible suite configurations according environment rules.
437
     * Suite configurations will contain `current_environment` key which specifies what environment used.
438
     *
439
     * @param $suite
440
     * @return array
441
     */
442
    public static function suiteEnvironments($suite)
443
    {
444
        $settings = self::suiteSettings($suite, self::config());
445
446
        if (!isset($settings['env']) || !is_array($settings['env'])) {
447
            return [];
448
        }
449
450
        $environments = [];
451
452
        foreach ($settings['env'] as $env => $envConfig) {
453
            $environments[$env] = $envConfig ? self::mergeConfigs($settings, $envConfig) : $settings;
454
            $environments[$env]['current_environment'] = $env;
455
        }
456
457
        return $environments;
458
    }
459
460
    public static function suites()
461
    {
462
        return self::$suites;
463
    }
464
465
    /**
466
     * Return list of enabled modules according suite config.
467
     *
468
     * @param array $settings suite settings
469
     * @return array
470
     */
471
    public static function modules($settings)
472
    {
473
        return array_filter(
474
            array_map(
475
                function ($m) {
476
                    return is_array($m) ? key($m) : $m;
477
                },
478
                $settings['modules']['enabled'],
479
                array_keys($settings['modules']['enabled'])
480
            ),
481
            function ($m) use ($settings) {
482
                if (!isset($settings['modules']['disabled'])) {
483
                    return true;
484
                }
485
                return !in_array($m, $settings['modules']['disabled']);
486
            }
487
        );
488
    }
489
490
    public static function isExtensionEnabled($extensionName)
491
    {
492
        return isset(self::$config['extensions'], self::$config['extensions']['enabled'])
493
        && in_array($extensionName, self::$config['extensions']['enabled']);
494
    }
495
496
    /**
497
     * Returns current path to `_data` dir.
498
     * Use it to store database fixtures, sql dumps, or other files required by your tests.
499
     *
500
     * @return string
501
     */
502
    public static function dataDir()
503
    {
504
        return self::$dir . DIRECTORY_SEPARATOR . self::$dataDir . DIRECTORY_SEPARATOR;
505
    }
506
507
    /**
508
     * Return current path to `_helpers` dir.
509
     * Helpers are custom modules.
510
     *
511
     * @return string
512
     */
513
    public static function supportDir()
514
    {
515
        return self::$dir . DIRECTORY_SEPARATOR . self::$supportDir . DIRECTORY_SEPARATOR;
516
    }
517
518
    /**
519
     * Returns actual path to current `_output` dir.
520
     * Use it in Helpers or Groups to save result or temporary files.
521
     *
522
     * @return string
523
     * @throws Exception\ConfigurationException
524
     */
525
    public static function outputDir()
526
    {
527
        if (!self::$outputDir) {
528
            throw new ConfigurationException("Path for output not specified. Please, set output path in global config");
529
        }
530
531
        $dir = self::$outputDir . DIRECTORY_SEPARATOR;
532
        if (strcmp(self::$outputDir[0], "/") !== 0) {
533
            $dir = self::$dir . DIRECTORY_SEPARATOR . $dir;
534
        }
535
536
        if (!file_exists($dir)) {
537
            @mkdir($dir, 0777, true);
538
        }
539
540
        if (!is_writable($dir)) {
541
            @chmod($dir, 0777);
542
        }
543
544
        if (!is_writable($dir)) {
545
            throw new ConfigurationException(
546
                "Path for output is not writable. Please, set appropriate access mode for output path."
547
            );
548
        }
549
550
        return $dir;
551
    }
552
553
    /**
554
     * Compatibility alias to `Configuration::logDir()`
555
     * @return string
556
     */
557
    public static function logDir()
558
    {
559
        return self::outputDir();
560
    }
561
562
    /**
563
     * Returns path to the root of your project.
564
     * Basically returns path to current `codeception.yml` loaded.
565
     * Use this method instead of `__DIR__`, `getcwd()` or anything else.
566
     * @return string
567
     */
568
    public static function projectDir()
569
    {
570
        return self::$dir . DIRECTORY_SEPARATOR;
571
    }
572
573
574
    /**
575
     * Returns path to tests directory
576
     *
577
     * @return string
578
     */
579
    public static function testsDir()
580
    {
581
        return self::$dir . DIRECTORY_SEPARATOR . self::$testsDir . DIRECTORY_SEPARATOR;
582
    }
583
584
    /**
585
     * Return current path to `_envs` dir.
586
     * Use it to store environment specific configuration.
587
     *
588
     * @return string
589
     */
590
    public static function envsDir()
591
    {
592
        if (!self::$envsDir) {
593
            return null;
594
        }
595
        return self::$dir . DIRECTORY_SEPARATOR . self::$envsDir . DIRECTORY_SEPARATOR;
596
    }
597
598
    /**
599
     * Is this a meta-configuration file that just points to other `codeception.yml`?
600
     * If so, it may have no tests by itself.
601
     *
602
     * @return bool
603
     */
604
    public static function isEmpty()
605
    {
606
        return !(bool)self::$testsDir;
607
    }
608
609
    /**
610
     * Adds parameters to config
611
     *
612
     * @param array $config
613
     * @return array
614
     */
615
    public static function append(array $config = [])
616
    {
617
        self::$config = self::mergeConfigs(self::$config, $config);
618
619
        if (isset(self::$config['paths']['output'])) {
620
            self::$outputDir = self::$config['paths']['output'];
621
        }
622
        if (isset(self::$config['paths']['data'])) {
623
            self::$dataDir = self::$config['paths']['data'];
624
        }
625
        if (isset(self::$config['paths']['support'])) {
626
            self::$supportDir = self::$config['paths']['support'];
627
        }
628
        if (isset(self::$config['paths']['tests'])) {
629
            self::$testsDir = self::$config['paths']['tests'];
630
        }
631
632
        return self::$config;
633
    }
634
635
    public static function mergeConfigs($a1, $a2)
636
    {
637
        if (!is_array($a1)) {
638
            return $a2;
639
        }
640
641
        if (!is_array($a2)) {
642
            return $a1;
643
        }
644
645
        $res = [];
646
647
        // for sequential arrays
648
        if (isset($a1[0], $a2[0])) {
649
            return array_merge_recursive($a2, $a1);
650
        }
651
652
        // for associative arrays
653
        foreach ($a2 as $k2 => $v2) {
654
            if (!isset($a1[$k2])) { // if no such key
655
                $res[$k2] = $v2;
656
                unset($a1[$k2]);
657
                continue;
658
            }
659
660
            $res[$k2] = self::mergeConfigs($a1[$k2], $v2);
661
            unset($a1[$k2]);
662
        }
663
664
        foreach ($a1 as $k1 => $v1) { // only single elements here left
665
            $res[$k1] = $v1;
666
        }
667
668
        return $res;
669
    }
670
671
    /**
672
     * Loads config from *.dist.suite.yml and *.suite.yml
673
     *
674
     * @param $suite
675
     * @param $path
676
     * @param $settings
677
     * @return array
678
     */
679
    protected static function loadSuiteConfig($suite, $path, $settings)
680
    {
681
        if (isset(self::$config['suites'][$suite])) {
682
            // bundled config
683
            return self::mergeConfigs($settings, self::$config['suites'][$suite]);
684
        }
685
686
        $suiteDir = self::$dir . DIRECTORY_SEPARATOR . $path;
687
688
        $suiteDistConf = self::getConfFromFile($suiteDir . DIRECTORY_SEPARATOR . "$suite.suite.dist.yml");
689
        $suiteConf = self::getConfFromFile($suiteDir . DIRECTORY_SEPARATOR . "$suite.suite.yml");
690
691
        // now we check the suite config file, if a extends key is defined
692
        if (isset($suiteConf['extends'])) {
693
            $presetFilePath = codecept_is_path_absolute($suiteConf['extends'])
694
                ? $suiteConf['extends'] // If path is absolute – use it
695
                : realpath($suiteDir . DIRECTORY_SEPARATOR . $suiteConf['extends']); // Otherwise try to locate it in the suite dir
696
697
            if (file_exists($presetFilePath)) {
698
                $settings = self::mergeConfigs(self::getConfFromFile($presetFilePath), $settings);
699
            }
700
        }
701
702
        $settings = self::mergeConfigs($settings, $suiteDistConf);
703
        $settings = self::mergeConfigs($settings, $suiteConf);
704
705
        return $settings;
706
    }
707
708
    /**
709
     * Replaces wildcarded items in include array with real paths.
710
     *
711
     * @param $includes
712
     * @return array
713
     */
714
    protected static function expandWildcardedIncludes(array $includes)
715
    {
716
        if (empty($includes)) {
717
            return $includes;
718
        }
719
        $expandedIncludes = [];
720
        foreach ($includes as $include) {
721
            $expandedIncludes = array_merge($expandedIncludes, self::expandWildcardsFor($include));
722
        }
723
        return $expandedIncludes;
724
    }
725
726
    /**
727
     * Finds config files in given wildcarded include path.
728
     * Returns the expanded paths or the original if not a wildcard.
729
     *
730
     * @param $include
731
     * @return array
732
     * @throws ConfigurationException
733
     */
734
    protected static function expandWildcardsFor($include)
735
    {
736
        if (1 !== preg_match('/[\?\.\*]/', $include)) {
737
            return [$include,];
738
        }
739
740
        try {
741
            $configFiles = Finder::create()->files()
742
                ->name('/codeception(\.dist\.yml|\.yml)/')
743
                ->in(self::$dir . DIRECTORY_SEPARATOR . $include);
744
        } catch (\InvalidArgumentException $e) {
745
            throw new ConfigurationException(
746
                "Configuration file(s) could not be found in \"$include\"."
747
            );
748
        }
749
750
        $paths = [];
751
        foreach ($configFiles as $file) {
752
            $paths[] = codecept_relative_path($file->getPath());
753
        }
754
755
        return $paths;
756
    }
757
758
    private static function prepareParams($settings)
759
    {
760
        self::$params = [];
761
        $paramsLoader = new ParamsLoader();
762
763
        foreach ($settings['params'] as $paramStorage) {
764
            static::$params = array_merge(self::$params, $paramsLoader->load($paramStorage));
765
        }
766
    }
767
}
768