Completed
Pull Request — develop (#1)
by Tom
13:24 queued 06:18
created

ConfigurationLoader   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 386
Duplicated Lines 3.63 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 48
c 1
b 0
f 0
lcom 1
cbo 7
dl 14
loc 386
rs 8.4865

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getPartialConfig() 0 11 2
A loadStageTwo() 0 12 2
A toArray() 0 8 2
A loadDistConfig() 0 12 3
B loadSystemConfig() 0 22 6
C loadPluginConfig() 0 59 10
A applyVariables() 0 9 2
B loadUserConfig() 6 23 5
B loadProjectConfig() 8 22 6
B registerPluginConfigFile() 0 26 5
A getVendorDir() 0 16 3
A getConfigurationLoaderDir() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ConfigurationLoader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ConfigurationLoader, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace N98\Magento\Application;
4
5
use N98\Util\BinaryString;
6
use N98\Util\OperatingSystem;
7
use Symfony\Component\Console\Output\OutputInterface;
8
use Symfony\Component\Finder\Finder;
9
use Symfony\Component\Finder\SplFileInfo;
10
use Symfony\Component\Yaml\Yaml;
11
use N98\Util\ArrayFunctions;
12
13
/**
14
 * Config consists of several parts which are merged.
15
 * The configuration which is global (not Magento project specific) is loaded
16
 * during construction.
17
 *
18
 * As soon as the Magento folder is known, loadStageTwo should be called.
19
 *
20
 * The toArray method only works if the Magento folder specific configuration is already loaded.
21
 *
22
 * Class ConfigurationLoader
23
 * @package N98\Magento\Command
24
 */
25
class ConfigurationLoader
26
{
27
    /**
28
     * Config passed in the constructor
29
     *
30
     * @var array
31
     */
32
    protected $_initialConfig;
33
34
    /**
35
     * @var array
36
     */
37
    protected $_configArray = null;
38
39
    /**
40
     * Cache
41
     *
42
     * @var array
43
     */
44
    protected $_distConfig;
45
46
    /**
47
     * Cache
48
     *
49
     * @var array
50
     */
51
    protected $_pluginConfig;
52
53
    /**
54
     * Cache
55
     *
56
     * @var array
57
     */
58
    protected $_systemConfig;
59
60
    /**
61
     * Cache
62
     *
63
     * @var array
64
     */
65
    protected $_userConfig;
66
67
    /**
68
     * Cache
69
     *
70
     * @var array
71
     */
72
    protected $_projectConfig;
73
74
    /**
75
     * @var string
76
     */
77
    protected $_customConfigFilename = 'n98-magerun2.yaml';
78
79
    /**
80
     * @var bool
81
     */
82
    protected $_isPharMode = true;
83
84
    /**
85
     * @var OutputInterface
86
     */
87
    protected $_output;
88
89
    /**
90
     * Load config
91
     * If $magentoRootFolder is null, only non-project config is loaded
92
     *
93
     * @param array $config
94
     * @param bool $isPharMode
95
     * @param OutputInterface $output
96
     */
97
    public function __construct($config, $isPharMode, OutputInterface $output)
98
    {
99
        $this->_initialConfig = $config;
100
        $this->_isPharMode = $isPharMode;
101
        $this->_output = $output;
102
    }
103
104
    /**
105
     * @param bool $loadExternalConfig
106
     * @return array
107
     */
108
    public function getPartialConfig($loadExternalConfig = true)
109
    {
110
        $config = $this->_initialConfig;
111
        $config = $this->loadDistConfig($config);
112
        if ($loadExternalConfig) {
113
            $config = $this->loadSystemConfig($config);
114
            $config = $this->loadUserConfig($config);
115
        }
116
117
        return $config;
118
    }
119
120
    /**
121
     * @param string $magentoRootFolder
122
     * @param bool   $loadExternalConfig
123
     * @param string $magerunStopFileFolder
124
     */
125
    public function loadStageTwo($magentoRootFolder, $loadExternalConfig = true, $magerunStopFileFolder = '')
126
    {
127
        $config = $this->_initialConfig;
128
        $config = $this->loadDistConfig($config);
129
        if ($loadExternalConfig) {
130
            $config = $this->loadPluginConfig($config, $magentoRootFolder);
131
            $config = $this->loadSystemConfig($config);
132
            $config = $this->loadUserConfig($config, $magentoRootFolder);
133
            $config = $this->loadProjectConfig($magentoRootFolder, $magerunStopFileFolder, $config);
134
        }
135
        $this->_configArray = $config;
136
    }
137
138
    /**
139
     * @throws \ErrorException
140
     *
141
     * @return array
142
     */
143
    public function toArray()
144
    {
145
        if ($this->_configArray == null) {
146
            throw new \ErrorException('Configuration not yet fully loaded');
147
        }
148
149
        return $this->_configArray;
150
    }
151
152
    /**
153
     * @param array $initConfig
154
     *
155
     * @return array
156
     */
157
    protected function loadDistConfig($initConfig)
158
    {
159
        if ($this->_distConfig == null) {
160
            $this->_distConfig = Yaml::parse(__DIR__ . '/../../../../config.yaml');
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Yaml\.../../../../config.yaml') can also be of type string. However, the property $_distConfig is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
161
        }
162
        if (OutputInterface::VERBOSITY_DEBUG <= $this->_output->getVerbosity()) {
163
            $this->_output->writeln('<debug>Load dist config</debug>');
164
        }
165
        $config = ArrayFunctions::mergeArrays($this->_distConfig, $initConfig);
0 ignored issues
show
Bug introduced by
It seems like $this->_distConfig can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
166
167
        return $config;
168
    }
169
170
    /**
171
     * Check if there is a global config file in /etc folder
172
     *
173
     * @param array $config
174
     *
175
     * @return array
176
     */
177
    public function loadSystemConfig($config)
178
    {
179
        if ($this->_systemConfig == null) {
180
            if (OperatingSystem::isWindows()) {
181
                $systemWideConfigFile = getenv('WINDIR') . DIRECTORY_SEPARATOR . $this->_customConfigFilename;
182
            } else {
183
                $systemWideConfigFile = '/etc/' . $this->_customConfigFilename;
184
            }
185
186
            if ($systemWideConfigFile && file_exists($systemWideConfigFile)) {
187
                if (OutputInterface::VERBOSITY_DEBUG <= $this->_output->getVerbosity()) {
188
                    $this->_output->writeln('<debug>Load system config <comment>' . $systemWideConfigFile . '</comment></debug>');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
189
                }
190
                $this->_systemConfig = Yaml::parse($systemWideConfigFile);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Yaml\...($systemWideConfigFile) can also be of type string. However, the property $_systemConfig is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
191
            } else {
192
                $this->_systemConfig = array();
193
            }
194
        }
195
196
        $config = ArrayFunctions::mergeArrays($config, $this->_systemConfig);
0 ignored issues
show
Bug introduced by
It seems like $this->_systemConfig can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
197
        return $config;
198
    }
199
200
    /**
201
     * Load config from all installed bundles
202
     *
203
     * @param array  $config
204
     * @param string $magentoRootFolder
205
     *
206
     * @return array
207
     */
208
    public function loadPluginConfig($config, $magentoRootFolder)
209
    {
210
        if ($this->_pluginConfig == null) {
211
            $this->_pluginConfig = array();
212
            $moduleBaseFolders = array();
213
            if (OperatingSystem::isWindows()) {
214
                $config['plugin']['folders'][] = getenv('WINDIR') . '/n98-magerun2/modules';
215
                $config['plugin']['folders'][] = OperatingSystem::getHomeDir() . '/n98-magerun2/modules';
216
            } else {
217
                $config['plugin']['folders'][] = OperatingSystem::getHomeDir() . '/.n98-magerun2/modules';
218
            }
219
            $config['plugin']['folders'][] = $magentoRootFolder . '/lib/n98-magerun2/modules';
220
            foreach ($config['plugin']['folders'] as $folder) {
221
                if (is_dir($folder)) {
222
                    $moduleBaseFolders[] = $folder;
223
                }
224
            }
225
226
            /**
227
             * Allow modules to be placed vendor folder if not in phar mode
228
             */
229
            if (!$this->_isPharMode) {
230
                if (is_dir($this->getVendorDir())) {
231
                    $finder = Finder::create();
232
                    $finder
233
                        ->files()
234
                        ->depth(2)
235
                        ->followLinks()
236
                        ->ignoreUnreadableDirs(true)
237
                        ->name($this->_customConfigFilename)
238
                        ->in($this->getVendorDir());
239
240
                    foreach ($finder as $file) { /* @var $file \Symfony\Component\Finder\SplFileInfo */
241
                        $this->registerPluginConfigFile($magentoRootFolder, $file);
242
                    }
243
                }
244
            }
245
246
            if (count($moduleBaseFolders) > 0) {
247
                // Glob plugin folders
248
                $finder = Finder::create();
249
                $finder
250
                    ->files()
251
                    ->depth(1)
252
                    ->followLinks()
253
                    ->ignoreUnreadableDirs(true)
254
                    ->name($this->_customConfigFilename)
255
                    ->in($moduleBaseFolders);
256
257
                foreach ($finder as $file) { /* @var $file \Symfony\Component\Finder\SplFileInfo */
258
                    $this->registerPluginConfigFile($magentoRootFolder, $file);
259
                }
260
            }
261
        }
262
263
        $config = ArrayFunctions::mergeArrays($config, $this->_pluginConfig);
264
265
        return $config;
266
    }
267
268
    /**
269
     * @param string                                $rawConfig
270
     * @param string                                $magentoRootFolder
271
     * @param \Symfony\Component\Finder\SplFileInfo $file
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file not be SplFileInfo|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
272
     *
273
     * @return string
274
     */
275
    protected function applyVariables($rawConfig, $magentoRootFolder, $file = null)
276
    {
277
        $replace = array(
278
            '%module%' => $file ? $file->getPath() : '',
279
            '%root%'   => $magentoRootFolder,
280
        );
281
282
        return str_replace(array_keys($replace), $replace, $rawConfig);
283
    }
284
285
286
    /**
287
     * Check if there is a user config file. ~/.n98-magerun.yaml
288
     *
289
     * @param array  $config
290
     * @param string $magentoRootFolder
1 ignored issue
show
Documentation introduced by
Should the type for parameter $magentoRootFolder not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
291
     *
292
     * @return array
293
     */
294
    public function loadUserConfig($config, $magentoRootFolder = null)
295
    {
296
        if ($this->_userConfig == null) {
297
            $this->_userConfig = array();
298
            $homeDirectory =  OperatingSystem::getHomeDir();
299
            if (OperatingSystem::isWindows()) {
300
                $personalConfigFile = $homeDirectory . DIRECTORY_SEPARATOR . $this->_customConfigFilename;
301
            } else {
302
                $personalConfigFile = $homeDirectory . DIRECTORY_SEPARATOR . '.' . $this->_customConfigFilename;
303
            }
304
305 View Code Duplication
            if ($homeDirectory && file_exists($personalConfigFile)) {
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...
306
                $userConfig = $this->applyVariables(\file_get_contents($personalConfigFile), $magentoRootFolder, null);
307
                $this->_userConfig = Yaml::parse($userConfig);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Yaml\Yaml::parse($userConfig) can also be of type string. However, the property $_userConfig is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
308
309
                return $config;
310
            }
311
        }
312
313
        $config = ArrayFunctions::mergeArrays($config, $this->_userConfig);
314
315
        return $config;
316
    }
317
318
    /**
319
     * MAGENTO_ROOT/app/etc/n98-magerun.yaml
320
     *
321
     * @param string $magentoRootFolder
322
     * @param string $magerunStopFileFolder
323
     * @param array $config
324
     *
325
     * @return array
326
     */
327
    public function loadProjectConfig($magentoRootFolder, $magerunStopFileFolder, $config)
328
    {
329
        if ($this->_projectConfig == null) {
330
            $this->_projectConfig = array();
331
332
            $projectConfigFile = $magentoRootFolder . DIRECTORY_SEPARATOR . 'app/etc/' . $this->_customConfigFilename;
333 View Code Duplication
            if ($projectConfigFile && file_exists($projectConfigFile)) {
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...
334
                $projectConfig = $this->applyVariables(\file_get_contents($projectConfigFile), $magentoRootFolder, null);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
335
                $this->_projectConfig = Yaml::parse($projectConfig);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Yaml\...::parse($projectConfig) can also be of type string. However, the property $_projectConfig is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
336
            }
337
338
            $stopFileConfigFile = $magerunStopFileFolder . DIRECTORY_SEPARATOR . '.' . $this->_customConfigFilename;
339 View Code Duplication
            if (!empty($magerunStopFileFolder) && file_exists($stopFileConfigFile)) {
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...
340
                $projectConfig = $this->applyVariables(\file_get_contents($stopFileConfigFile), $magentoRootFolder, null);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
341
                $this->_projectConfig = ArrayFunctions::mergeArrays($this->_projectConfig, Yaml::parse($projectConfig));
0 ignored issues
show
Bug introduced by
It seems like $this->_projectConfig can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like \Symfony\Component\Yaml\...::parse($projectConfig) targeting Symfony\Component\Yaml\Yaml::parse() can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
342
            }
343
344
            $config = ArrayFunctions::mergeArrays($config, $this->_projectConfig);
0 ignored issues
show
Bug introduced by
It seems like $this->_projectConfig can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
345
        }
346
347
        return $config;
348
    }
349
350
    /**
351
     * Loads a plugin config file and merges it to plugin config
352
     *
353
     * @param string       $magentoRootFolder
354
     * @param SplFileInfo $file
355
     */
356
    protected function registerPluginConfigFile($magentoRootFolder, $file)
357
    {
358
        if (BinaryString::startsWith($file->getPathname(), 'vfs://')) {
359
            $path = $file->getPathname();
360
        } else {
361
            $path = $file->getRealPath();
362
363
            if ($path === "") {
364
                throw new \UnexpectedValueException(sprintf("Realpath for '%s' did return an empty string.", $file));
365
            }
366
367
            if ($path === false) {
368
                $this->_output->writeln(sprintf("<error>Plugin config file broken link '%s'</error>", $file));
369
                return;
370
            }
371
        }
372
373
        if (OutputInterface::VERBOSITY_DEBUG <= $this->_output->getVerbosity()) {
374
            $this->_output->writeln('<debug>Load plugin config <comment>' . $path . '</comment></debug>');
375
        }
376
377
        $localPluginConfig = \file_get_contents($path);
378
        $localPluginConfig = Yaml::parse($this->applyVariables($localPluginConfig, $magentoRootFolder, $file));
379
380
        $this->_pluginConfig = ArrayFunctions::mergeArrays($this->_pluginConfig, $localPluginConfig);
0 ignored issues
show
Bug introduced by
It seems like $localPluginConfig defined by \Symfony\Component\Yaml\...entoRootFolder, $file)) on line 378 can also be of type string; however, N98\Util\ArrayFunctions::mergeArrays() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
381
    }
382
383
    /**
384
     * @return string
385
     */
386
    public function getVendorDir()
387
    {
388
        /* old vendor folder to give backward compatibility */
389
        $vendorFolder = $this->getConfigurationLoaderDir() . '/../../../../vendor';
390
        if (is_dir($vendorFolder)) {
391
            return $vendorFolder;
392
        }
393
394
        /* correct vendor folder for composer installations */
395
        $vendorFolder = $this->getConfigurationLoaderDir() . '/../../../../../../../vendor';
396
        if (is_dir($vendorFolder)) {
397
            return $vendorFolder;
398
        }
399
400
        return '';
401
    }
402
403
    /**
404
     * @return string
405
     */
406
    public function getConfigurationLoaderDir()
407
    {
408
        return __DIR__;
409
    }
410
}
411