Completed
Push — master ( da521e...2646ae )
by Richan
01:12
created

Command::startWebServer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Suitmedia\LighthouseAudit;
4
5
use LogicException;
6
use Suitmedia\LighthouseAudit\Audit\AuditManager;
7
use Suitmedia\LighthouseAudit\Concerns\SanitizeInput;
8
use Symfony\Component\Console\Command\Command as AbstractCommand;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
14
final class Command extends AbstractCommand
15
{
16
    use SanitizeInput;
17
18
    public const DEFAULT_SERVER = 'localhost:8000';
19
    public const DEFAULT_MODE = 'mobile';
20
    public const DEFAULT_PERFORMANCE = '80';
21
    public const DEFAULT_BEST_PRACTICES = '80';
22
    public const DEFAULT_ACCESSIBILITY = '80';
23
    public const DEFAULT_SEO = '80';
24
    public const DEFAULT_PWA = '0';
25
26
    /**
27
     * Current web server instance.
28
     *
29
     * @var WebServer
30
     */
31
    protected $webServer;
32
33
    /**
34
     * Configures the lighthouse-audit command.
35
     *
36
     * @return void
37
     */
38
    protected function configure() :void
39
    {
40
        $this->setName('lighthouse-audit')
41
            ->setDefinition([new InputArgument(
42
                'path',
43
                InputArgument::REQUIRED,
44
                'Specify the path of a directory to analyse.'
45
            )])
46
            ->addOption(
47
                'server',
48
                'S',
49
                InputOption::VALUE_OPTIONAL,
50
                'Define the address and port that PHP web-server should serve. <address>:<port>',
51
                self::DEFAULT_SERVER
52
            )
53
            ->addOption(
54
                'mode',
55
                null,
56
                InputOption::VALUE_OPTIONAL,
57
                'Define the mode to run Lighthouse audit. Option: mobile,desktop',
58
                self::DEFAULT_MODE
59
            )
60
            ->addOption(
61
                'performance',
62
                null,
63
                InputOption::VALUE_OPTIONAL,
64
                'Define the minimal performance score for audit to pass',
65
                self::DEFAULT_PERFORMANCE
66
            )
67
            ->addOption(
68
                'best-practices',
69
                null,
70
                InputOption::VALUE_OPTIONAL,
71
                'Define the minimal best-practices score for audit to pass',
72
                self::DEFAULT_BEST_PRACTICES
73
            )
74
            ->addOption(
75
                'accessibility',
76
                null,
77
                InputOption::VALUE_OPTIONAL,
78
                'Define the minimal accessibility score for audit to pass',
79
                self::DEFAULT_ACCESSIBILITY
80
            )
81
            ->addOption(
82
                'seo',
83
                null,
84
                InputOption::VALUE_OPTIONAL,
85
                'Define the minimal seo score for audit to pass',
86
                self::DEFAULT_SEO
87
            )
88
            ->addOption(
89
                'pwa',
90
                null,
91
                InputOption::VALUE_OPTIONAL,
92
                'Define the minimal pwa score for audit to pass',
93
                self::DEFAULT_PWA
94
            )
95
            ->addOption(
96
                'except',
97
                null,
98
                InputOption::VALUE_OPTIONAL,
99
                'Provide a list of filenames that you wish to exclude, separated by commas.'.PHP_EOL
100
            )
101
            ->addOption(
102
                'chrome-flags',
103
                null,
104
                InputOption::VALUE_OPTIONAL,
105
                'Custom flags to pass to Chrome (space-delimited). For a full list of flags, '.PHP_EOL.'see http://peter.sh/experiments/chromium-command-line-switches/.'.PHP_EOL
106
            );
107
    }
108
109
    /**
110
     * Executes the current command.
111
     *
112
     * This method is not abstract because you can use this class
113
     * as a concrete class. In this case, instead of defining the
114
     * execute() method, you set the code to execute by passing
115
     * a Closure to the setCode() method.
116
     *
117
     * @param InputInterface  $input
118
     * @param OutputInterface $output
119
     *
120
     * @throws LogicException|\Exception
121
     *
122
     * @return int
123
     */
124
    protected function execute(InputInterface $input, OutputInterface $output) :int
125
    {
126
        $this->startWebServer($input);
127
        $app = $this->getApplication();
128
        $excludedFiles = $this->getExcludedFiles($input);
129
130
        $output->writeln($app->getLongVersion());
131
        $output->writeln('');
132
133
        $finder = new HtmlFileFinder($input->getArgument('path'));
134
        $files = $finder->getFiles();
135
136
        foreach ($files as $file) {
137
            if (in_array($file, $excludedFiles, true)) {
138
                continue;
139
            }
140
141
            $audit = new AuditManager(
142
                $this->getApplication()->getProcessBuilder(),
143
                $input,
144
                $output,
145
                $file
146
            );
147
            $audit->run();
0 ignored issues
show
Documentation Bug introduced by
The method run does not exist on object<Suitmedia\Lightho...dit\Audit\AuditManager>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
148
        }
149
150
        $output->writeln('');
151
        $output->writeln('<info>All audits have completed without any issue.</info>');
152
        $output->writeln('');
153
154
        $this->webServer->stop();
155
156
        return 0;
157
    }
158
159
    /**
160
     * Get the list of files that should be excluded from analysis.
161
     *
162
     * @param InputInterface $input
163
     *
164
     * @return array
165
     */
166
    public function getExcludedFiles(InputInterface $input) :array
167
    {
168
        $except = $input->getOption('except');
169
170
        $files = is_string($except) ? explode(',', $this->trimDoubleQuotes($except)) : [];
171
172
        return array_filter(array_map('trim', $files));
173
    }
174
175
    /**
176
     * Create and start a new web server instance.
177
     *
178
     * @param InputInterface $input
179
     */
180
    protected function startWebServer(InputInterface $input) :void
181
    {
182
        $this->webServer = new WebServer($input, $this->getApplication()->getProcessBuilder());
183
        $this->webServer->run();
184
    }
185
}
186