Completed
Push — master ( 6f6a8a...c98c64 )
by Greg
14:01
created

SiteAliasFileLoader::getRequestedEnvData()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
namespace Consolidation\SiteAlias;
3
4
use Consolidation\Config\Loader\ConfigProcessor;
5
use Dflydev\DotAccessData\Util as DotAccessDataUtil;
6
7
/**
8
 * Discover alias files:
9
 *
10
 * - sitename.site.yml: contains multiple aliases, one for each of the
11
 *     environments of 'sitename'.
12
 */
13
class SiteAliasFileLoader
14
{
15
    /**
16
     * @var SiteAliasFileDiscovery
17
     */
18
    protected $discovery;
19
20
    /**
21
     * @var array
22
     */
23
    protected $referenceData;
24
25
    /**
26
     * @var array
27
     */
28
    protected $loader;
29
30
    /**
31
     * SiteAliasFileLoader constructor
32
     *
33
     * @param SiteAliasFileDiscovery|null $discovery
34
     */
35
    public function __construct($discovery = null)
36
    {
37
        $this->discovery = $discovery ?: new SiteAliasFileDiscovery();
38
        $this->referenceData = [];
39
        $this->loader = [];
40
    }
41
42
    /**
43
     * Allow configuration data to be used in replacements in the alias file.
44
     */
45
    public function setReferenceData($data)
46
    {
47
        $this->referenceData = $data;
48
    }
49
50
    /**
51
     * Add a search location to our discovery object.
52
     *
53
     * @param string $path
54
     *
55
     * @return $this
56
     */
57
    public function addSearchLocation($path)
58
    {
59
        $this->discovery()->addSearchLocation($path);
60
        return $this;
61
    }
62
63
    /**
64
     * Return our discovery object.
65
     *
66
     * @return SiteAliasFileDiscovery
67
     */
68
    public function discovery()
69
    {
70
        return $this->discovery;
71
    }
72
73
    /**
74
     * Load the file containing the specified alias name.
75
     *
76
     * @param SiteAliasName $aliasName
77
     *
78
     * @return AliasRecord|false
79
     */
80
    public function load(SiteAliasName $aliasName)
81
    {
82
        // First attempt to load a sitename.site.yml file for the alias.
83
        $aliasRecord = $this->loadSingleAliasFile($aliasName);
84
        if ($aliasRecord) {
85
            return $aliasRecord;
86
        }
87
88
        // If aliasname was provides as @site.env and we did not find it,
89
        // then we are done.
90
        if ($aliasName->hasSitename()) {
91
            return false;
92
        }
93
94
        // If $aliasName was provided as `@foo` (`hasSitename()` returned `false`
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
95
        // above), then this was interpreted as `@self.foo` when we searched
96
        // above. If we could not find an alias record for `@self.foo`, then we
97
        // will try to search again, this time with the assumption that `@foo`
98
        // might be `@foo.<default>`, where `<default>` is the default
99
        // environment for the specified site. Note that in this instance, the
100
        // sitename will be found in $aliasName->env().
101
        $sitename = $aliasName->env();
102
        return $this->loadDefaultEnvFromSitename($sitename);
103
    }
104
105
    /**
106
     * Given only a site name, load the default environment from it.
107
     */
108
    protected function loadDefaultEnvFromSitename($sitename)
109
    {
110
        $path = $this->discovery()->findSingleSiteAliasFile($sitename);
111
        if (!$path) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
112
            return false;
113
        }
114
        $data = $this->loadSiteDataFromPath($path);
115
        if (!$data) {
116
            return false;
117
        }
118
        $env = $this->getDefaultEnvironmentName($data);
119
120
        $aliasName = new SiteAliasName($sitename, $env);
121
        $processor = new ConfigProcessor();
122
        return $this->fetchAliasRecordFromSiteAliasData($aliasName, $processor, $data);
123
    }
124
125
    /**
126
     * Return a list of all site aliases loadable from any findable path.
127
     *
128
     * @return AliasRecord[]
129
     */
130
    public function loadAll()
131
    {
132
        $result = [];
133
        $paths = $this->discovery()->findAllSingleAliasFiles();
134
        foreach ($paths as $path) {
135
            $aliasRecords = $this->loadSingleSiteAliasFileAtPath($path);
136
            if ($aliasRecords) {
137
                foreach ($aliasRecords as $aliasRecord) {
138
                    $this->storeAliasRecordInResut($result, $aliasRecord);
139
                }
140
            }
141
        }
142
        ksort($result);
143
        return $result;
144
    }
145
146
    /**
147
     * Return a list of all available alias files. Does not include
148
     * legacy files.
149
     *
150
     * @param string $location Only consider alias files in the specified location.
151
     * @return string[]
152
     */
153
    public function listAll($location = '')
154
    {
155
        return $this->discovery()->filterByLocation($location)->findAllSingleAliasFiles();
156
    }
157
158
    /**
159
     * Given an alias name that might represent multiple sites,
160
     * return a list of all matching alias records. If nothing was found,
161
     * or the name represents a single site + env, then we take
162
     * no action and return `false`.
163
     *
164
     * @param string $sitename The site name to return all environments for.
165
     * @return AliasRecord[]|false
166
     */
167 View Code Duplication
    public function loadMultiple($sitename)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
168
    {
169
        $result = [];
170
        foreach ($this->discovery()->find($sitename) as $path) {
171
            if ($siteData = $this->loadSiteDataFromPath($path)) {
172
                $location = SiteAliasName::locationFromPath($path);
0 ignored issues
show
Documentation introduced by
$path is of type string, but the function expects a object<Consolidation\SiteAlias\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
173
                // Convert the raw array into a list of alias records.
174
                $result = array_merge(
175
                    $result,
176
                    $this->createAliasRecordsFromSiteData($sitename, $siteData, $location)
177
                );
178
            }
179
        }
180
        return $result;
181
    }
182
183
184
    /**
185
     * Given a location, return all alias files located there.
186
     *
187
     * @param string $location The location to filter.
188
     * @return AliasRecord[]
189
     */
190 View Code Duplication
    public function loadLocation($location)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
191
    {
192
        $result = [];
193
        foreach ($this->listAll($location) as $path) {
194
            if ($siteData = $this->loadSiteDataFromPath($path)) {
195
                $location = SiteAliasName::locationFromPath($path);
0 ignored issues
show
Documentation introduced by
$path is of type string, but the function expects a object<Consolidation\SiteAlias\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
196
                $sitename = $this->siteNameFromPath($path);
197
                // Convert the raw array into a list of alias records.
198
                $result = array_merge(
199
                    $result,
200
                    $this->createAliasRecordsFromSiteData($sitename, $siteData, $location)
201
                );
202
            }
203
        }
204
        return $result;
205
    }
206
207
    /**
208
     * @param array $siteData list of sites with its respective data
209
     *
210
     * @param SiteAliasName $aliasName The name of the record being created
0 ignored issues
show
Bug introduced by
There is no parameter named $aliasName. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
211
     * @param $siteData An associative array of envrionment => site data
212
     * @return AliasRecord[]
213
     */
214
    protected function createAliasRecordsFromSiteData($sitename, $siteData, $location = '')
215
    {
216
        $result = [];
217
        if (!is_array($siteData) || empty($siteData)) {
218
            return $result;
219
        }
220
        foreach ($siteData as $envName => $data) {
221
            if (is_array($data)) {
222
                $aliasName = new SiteAliasName($sitename, $envName, $location);
223
224
                $processor = new ConfigProcessor();
225
                $oneRecord = $this->fetchAliasRecordFromSiteAliasData($aliasName, $processor, $siteData);
226
                $this->storeAliasRecordInResut($result, $oneRecord);
0 ignored issues
show
Security Bug introduced by
It seems like $oneRecord defined by $this->fetchAliasRecordF... $processor, $siteData) on line 225 can also be of type false; however, Consolidation\SiteAlias\...oreAliasRecordInResut() does only seem to accept object<Consolidation\SiteAlias\AliasRecord>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
227
            }
228
        }
229
        return $result;
230
    }
231
232
    /**
233
     * Store an alias record in a list. If the alias record has
234
     * a known name, then the key of the list will be the record's name.
235
     * Otherwise, append the record to the end of the list with
236
     * a numeric index.
237
     *
238
     * @param &AliasRecord[] $result list of alias records
0 ignored issues
show
Documentation introduced by
The doc-type &AliasRecord[] could not be parsed: Unknown type name "&AliasRecord" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
239
     * @param AliasRecord $aliasRecord one more alias to store in the result
240
     */
241
    protected function storeAliasRecordInResut(&$result, AliasRecord $aliasRecord)
242
    {
243
        if (!$aliasRecord) {
244
            return;
245
        }
246
        $key = $aliasRecord->name();
247
        if (empty($key)) {
248
            $result[] = $aliasRecord;
249
            return;
250
        }
251
        $result[$key] = $aliasRecord;
252
    }
253
254
    /**
255
     * If the alias name is '@sitename', or if it is '@sitename.env', then
256
     * look for a sitename.site.yml file that contains it. We also handle
257
     * '@location.sitename.env' here as well.
258
     *
259
     * @param SiteAliasName $aliasName
260
     *
261
     * @return AliasRecord|false
262
     */
263
    protected function loadSingleAliasFile(SiteAliasName $aliasName)
264
    {
265
        // Check to see if the appropriate sitename.alias.yml file can be
266
        // found. Return if it cannot.
267
        $path = $this->discovery()
268
            ->filterByLocation($aliasName->location())
269
            ->findSingleSiteAliasFile($aliasName->sitename());
270
        if (!$path) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
271
            return false;
272
        }
273
        return $this->loadSingleAliasFileWithNameAtPath($aliasName, $path);
274
    }
275
276
    /**
277
     * Given only the path to an alias file `site.alias.yml`, return all
278
     * of the alias records for every environment stored in that file.
279
     *
280
     * @param string $path
281
     * @return AliasRecord[]
282
     */
283
    protected function loadSingleSiteAliasFileAtPath($path)
284
    {
285
        $sitename = $this->siteNameFromPath($path);
286
        $location = SiteAliasName::locationFromPath($path);
0 ignored issues
show
Documentation introduced by
$path is of type string, but the function expects a object<Consolidation\SiteAlias\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
287
        if ($siteData = $this->loadSiteDataFromPath($path)) {
288
            return $this->createAliasRecordsFromSiteData($sitename, $siteData, $location);
289
        }
290
        return false;
291
    }
292
293
    /**
294
     * Given the path to a single site alias file `site.alias.yml`,
295
     * return the `site` part.
296
     *
297
     * @param string $path
298
     */
299
    protected function siteNameFromPath($path)
300
    {
301
        return $this->basenameWithoutExtension($path, '.site.yml');
302
303
// OR:
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
304
//        $filename = basename($path);
305
//        return preg_replace('#\..*##', '', $filename);
306
    }
307
308
    /**
309
     * Chop off the `aliases.yml` or `alias.yml` part of a path. This works
310
     * just like `basename`, except it will throw if the provided path
311
     * does not end in the specified extension.
312
     *
313
     * @param string $path
314
     * @param string $extension
315
     * @return string
316
     * @throws \Exception
317
     */
318
    protected function basenameWithoutExtension($path, $extension)
319
    {
320
        $result = basename($path, $extension);
321
        // It is an error if $path does not end with site.yml
322
        if ($result == basename($path)) {
323
            throw new \Exception("$path must end with '$extension'");
324
        }
325
        return $result;
326
    }
327
328
    /**
329
     * Given an alias name and a path, load the data from the path
330
     * and process it as needed to generate the alias record.
331
     *
332
     * @param SiteAliasName $aliasName
333
     * @param string $path
334
     * @return AliasRecord|false
335
     */
336
    protected function loadSingleAliasFileWithNameAtPath(SiteAliasName $aliasName, $path)
337
    {
338
        $data = $this->loadSiteDataFromPath($path);
339
        if (!$data) {
340
            return false;
341
        }
342
        $processor = new ConfigProcessor();
343
        return $this->fetchAliasRecordFromSiteAliasData($aliasName, $processor, $data);
344
    }
345
346
    /**
347
     * Load the yml from the given path
348
     *
349
     * @param string $path
350
     * @return array|bool
351
     */
352
    protected function loadSiteDataFromPath($path)
353
    {
354
        $data = $this->loadData($path);
355
        if (!$data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data 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...
356
            return false;
357
        }
358
        $selfSiteAliases = $this->findSelfSiteAliases($data);
359
        $data = array_merge($data, $selfSiteAliases);
360
        return $data;
361
    }
362
363
    /**
364
     * Given an array of site aliases, find the first one that is
365
     * local (has no 'host' item) and also contains a 'self.site.yml' file.
366
     * @param array $data
0 ignored issues
show
Bug introduced by
There is no parameter named $data. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
367
     * @return array
368
     */
369
    protected function findSelfSiteAliases($site_aliases)
370
    {
371
        foreach ($site_aliases as $site => $data) {
372
            if (!isset($data['host']) && isset($data['root'])) {
373
                foreach (['.', '..'] as $relative_path) {
374
                    $candidate = $data['root'] . '/' . $relative_path . '/drush/sites/self.site.yml';
375
                    if (file_exists($candidate)) {
376
                        return $this->loadData($candidate);
377
                    }
378
                }
379
            }
380
        }
381
        return [];
382
    }
383
384
    /**
385
     * Load the contents of the specified file.
386
     *
387
     * @param string $path Path to file to load
388
     * @return array
389
     */
390
    protected function loadData($path)
391
    {
392
        if (empty($path) || !file_exists($path)) {
393
            return [];
394
        }
395
        $loader = $this->getLoader(pathinfo($path, PATHINFO_EXTENSION));
396
        if (!$loader) {
397
            return [];
398
        }
399
        return $loader->load($path);
400
    }
401
402
    /**
403
     * @return DataFileLoaderInterface
404
     */
405
    public function getLoader($extension)
406
    {
407
        if (!isset($this->loader[$extension])) {
408
            return null;
409
        }
410
        return $this->loader[$extension];
411
    }
412
413
    public function addLoader($extension, DataFileLoaderInterface $loader)
414
    {
415
        $this->loader[$extension] = $loader;
416
    }
417
418
    /**
419
     * Given an array containing site alias data, return an alias record
420
     * containing the data for the requested record. If there is a 'common'
421
     * section, then merge that in as well.
422
     *
423
     * @param SiteAliasName $aliasName the alias we are loading
424
     * @param array $data
425
     *
426
     * @return AliasRecord|false
427
     */
428
    protected function fetchAliasRecordFromSiteAliasData(SiteAliasName $aliasName, ConfigProcessor $processor, array $data)
429
    {
430
        $data = $this->adjustIfSingleAlias($data);
431
        $env = $this->getEnvironmentName($aliasName, $data);
432
        $env_data = $this->getRequestedEnvData($data, $env);
433
        if (!$env_data) {
434
            return false;
435
        }
436
437
        // Add the 'common' section if it exists.
438
        if ($this->siteEnvExists($data, 'common')) {
439
            $processor->add($data['common']);
440
        }
441
442
        // Then add the data from the desired environment.
443
        $processor->add($env_data);
444
445
        // Export the combined data and create an AliasRecord object to manage it.
446
        return new AliasRecord($processor->export($this->referenceData + ['env-name' => $env]), '@' . $aliasName->sitenameWithLocation(), $env);
447
    }
448
449
    /**
450
     * getRequestedEnvData fetches the data for the specified environment
451
     * from the provided site record data.
452
     *
453
     * @param array $data The site alias data
454
     * @param string $env The name of the environment desired
455
     * @return array|false
456
     */
457
    protected function getRequestedEnvData(array $data, $env)
458
    {
459
        // If the requested environment exists, we will use it.
460
        if ($this->siteEnvExists($data, $env)) {
461
            return $data[$env];
462
        }
463
464
        // If there is a wildcard environment, then return that instead.
465
        if ($this->siteEnvExists($data, '*')) {
466
            return $data['*'];
467
        }
468
469
        return false;
470
    }
471
472
    /**
473
     * Determine whether there is a valid-looking environment '$env' in the
474
     * provided site alias data.
475
     *
476
     * @param array $data
477
     * @param string $env
478
     * @return bool
479
     */
480
    protected function siteEnvExists(array $data, $env)
481
    {
482
        return (
483
            is_array($data) &&
484
            isset($data[$env]) &&
485
            is_array($data[$env])
486
        );
487
    }
488
489
    /**
490
     * Adjust the alias data for a single-site alias. Usually, a .yml alias
491
     * file will contain multiple entries, one for each of the environments
492
     * of an alias. If there are no environments
493
     *
494
     * @param array $data
495
     * @return array
496
     */
497
    protected function adjustIfSingleAlias($data)
498
    {
499
        if (!$this->detectSingleAlias($data)) {
500
            return $data;
501
        }
502
503
        $result = [
504
            'default' => $data,
505
        ];
506
507
        return $result;
508
    }
509
510
    /**
511
     * A single-environment alias looks something like this:
512
     *
513
     *   ---
514
     *   root: /path/to/drupal
515
     *   uri: https://mysite.org
516
     *
517
     * A multiple-environment alias looks something like this:
518
     *
519
     *   ---
520
     *   default: dev
521
     *   dev:
522
     *     root: /path/to/dev
523
     *     uri: https://dev.mysite.org
524
     *   stage:
525
     *     root: /path/to/stage
526
     *     uri: https://stage.mysite.org
527
     *
528
     * The differentiator between these two is that the multi-environment
529
     * alias always has top-level elements that are associative arrays, and
530
     * the single-environment alias never does.
531
     *
532
     * @param array $data
533
     * @return bool
534
     */
535
    protected function detectSingleAlias($data)
536
    {
537
        foreach ($data as $key => $value) {
538
            if (is_array($value) && DotAccessDataUtil::isAssoc($value)) {
539
                return false;
540
            }
541
        }
542
        return true;
543
    }
544
545
    /**
546
     * Return the name of the environment requested.
547
     *
548
     * @param SiteAliasName $aliasName the alias we are loading
549
     * @param array $data
550
     *
551
     * @return string
552
     */
553
    protected function getEnvironmentName(SiteAliasName $aliasName, array $data)
554
    {
555
        // If the alias name specifically mentions the environment
556
        // to use, then return it.
557
        if ($aliasName->hasEnv()) {
558
            return $aliasName->env();
559
        }
560
        return $this->getDefaultEnvironmentName($data);
561
    }
562
563
    /**
564
     * Given a data array containing site alias environments, determine which
565
     * envirionmnet should be used as the default environment.
566
     *
567
     * @param array $data
568
     * @return string
569
     */
570
    protected function getDefaultEnvironmentName(array $data)
571
    {
572
        // If there is an entry named 'default', it will either contain the
573
        // name of the environment to use by default, or it will itself be
574
        // the default environment.
575
        if (isset($data['default'])) {
576
            return is_array($data['default']) ? 'default' : $data['default'];
577
        }
578
        // If there is an environment named 'dev', it will be our default.
579
        if (isset($data['dev'])) {
580
            return 'dev';
581
        }
582
        // If we don't know which environment to use, just take the first one.
583
        $keys = array_keys($data);
584
        return reset($keys);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression reset($keys); of type string|false adds false to the return on line 584 which is incompatible with the return type documented by Consolidation\SiteAlias\...tDefaultEnvironmentName of type string. It seems like you forgot to handle an error condition.
Loading history...
585
    }
586
}
587