SiteCommand::locateWebroots()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 3
nop 1
dl 0
loc 11
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace Buttress\Concrete\Console\Command;
4
5
use Buttress\Concrete\Console\Command\Manager\CommandManager;
6
use Buttress\Concrete\Locator\Locator;
7
use Buttress\Concrete\Locator\Site;
8
use Buttress\Concrete\Route\RouteCollector;
9
use FilesystemIterator as FS;
10
use League\CLImate\CLImate;
11
12
class SiteCommand implements Command
13
{
14
15
    /** @var \Buttress\Concrete\Locator\Locator */
16
    private $locator;
17
    /**
18
     * @var \League\CLImate\CLImate
19
     */
20
    private $cli;
21
22
    public function __construct(Locator $locator, CLImate $cli)
23
    {
24
        $this->locator = $locator;
25
        $this->cli = $cli;
26
    }
27
28
    /**
29
     * Get the command definitions this command provides
30
     *
31
     * @param \Buttress\Concrete\Locator\Site|null $site
32
     * @return \Buttress\Concrete\Console\Command\Manager\CommandManager[]
33
     * @throws \Exception
34
     */
35
    public function getCommands(Site $site)
36
    {
37
        $locate = new CommandManager('site:locate');
38
        $locate->add('path', [
39
            'required' => true,
40
            'castTo' => 'string',
41
            'description' => 'The package handle to install',
42
            'defaultValue' => getcwd()
43
        ]);
44
45
        return [
46
            'site:locate' => $locate
47
        ];
48
    }
49
50
    /**
51
     * Register routes onto the route collector
52
     *
53
     * @param \Buttress\Concrete\Route\RouteCollector $collector
54
     * @param \Buttress\Concrete\Locator\Site|null $site Null is passed when a concrete5 site wasn't located
55
     * @return void
56
     */
57
    public function registerRoutes(RouteCollector $collector, Site $site = null)
58
    {
59
        $collector->addGroup(['site', 'sites'], function (RouteCollector $collector) use ($site) {
0 ignored issues
show
Documentation introduced by
array('site', 'sites') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

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...
60
            $collector->addRoute(['locate', 'find'], function () use ($site) {
0 ignored issues
show
Documentation introduced by
array('locate', 'find') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

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...
61
                $command = array_get($this->getCommands($site), 'site:locate');
0 ignored issues
show
Bug introduced by
It seems like $site defined by parameter $site on line 57 can be null; however, Buttress\Concrete\Consol...eCommand::getCommands() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
62
                $command->parse();
63
                $path = realpath($command->get('path'));
64
                foreach ($this->locateWebroots($path) as $webroot) {
65
                    $this->outputWebroot($webroot);
66
                }
67
            });
68
        });
69
    }
70
71
    private function locateWebroots($path)
72
    {
73
        $flags = FS::CURRENT_AS_PATHNAME | FS::SKIP_DOTS;
74
        $files = new \RecursiveDirectoryIterator($path, $flags);
75
76
        foreach ($this->directoryGenerator($files) as $path) {
77
            if (($root = $this->locator->getLocation($path, false)) && $root->getPath() === $path) {
78
                yield $root;
79
            }
80
        }
81
    }
82
83
    /**
84
     * @param \RecursiveDirectoryIterator $iterator
85
     * @return \RecursiveDirectoryIterator[]
86
     */
87
    private function directoryGenerator(\RecursiveDirectoryIterator $iterator)
88
    {
89
        $children = [];
90
        foreach ($this->visibleChildren($iterator) as $directory) {
91
            $children[] = $directory;
92
            yield $directory->getPath();
93
        }
94
95
        // One level deeper
96
        foreach ($children as $child) {
97
            foreach ($this->directoryGenerator($child) as $item) {
98
                yield $item;
99
            }
100
        }
101
102
    }
103
    /**
104
     * @param \RecursiveDirectoryIterator $iterator
105
     * @return \RecursiveDirectoryIterator[]
106
     */
107
    private function visibleChildren(\RecursiveDirectoryIterator $iterator)
108
    {
109
        /** @var \RecursiveDirectoryIterator $child */
110
        foreach ($iterator as $child) {
111
            if ($iterator->hasChildren() && basename($child)[0] !== '.') {
112
                yield $iterator->getChildren();
113
            }
114
        }
115
    }
116
117
    private function outputWebroot(Site $webroot)
118
    {
119
        $version = $stringVersion = $webroot->getVersion();
120
        $spaces = str_repeat(' ', max(0, 9 - strlen($version)));
121
        $suffix = '     ';
122
123
        if ($remainder = trim(preg_replace('/^[\d\.]+/', '', $version))) {
124
            $stringVersion = substr($version, 0, -strlen($remainder));
125
            $stringVersion .= "<error>{$remainder}</error>";
126
        }
127
128
        // Latest major version
129
        if (version_compare($version, '8.0.0', '>=')) {
130
            $stringVersion = "<green>{$stringVersion}</green>";
131
        } elseif (version_compare($version, '5.7.0', '<')) {
132
            $stringVersion = "<error>{$stringVersion}</error>";
133
            $suffix = ' <bold><background_light_red>[!]</background_light_red></bold> ';
134
        }
135
136
        $this->cli
137
            ->inline(
138
                sprintf(
139
                    '<bold>%s</bold>%s%s ',
140
                    $stringVersion,
141
                    $spaces,
142
                    $suffix
143
                )
144
            )
145
            ->out($webroot->getPath());
146
    }
147
}
148