Completed
Push — develop ( 8eb671...133594 )
by Mike
19:30 queued 09:24
created

src/phpDocumentor/Application/Stage/Parser.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * This file is part of phpDocumentor.
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @author    Mike van Riel <[email protected]>
11
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
12
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
13
 * @link      http://phpdoc.org
14
 */
15
16
namespace phpDocumentor\Application\Stage;
17
18
use Exception;
19
use InvalidArgumentException;
20
use phpDocumentor\Descriptor\Cache\ProjectDescriptorMapper;
21
use phpDocumentor\Descriptor\Collection as PartialsCollection;
22
use phpDocumentor\Descriptor\ProjectDescriptor;
23
use phpDocumentor\Descriptor\ProjectDescriptorBuilder;
24
use phpDocumentor\DomainModel\Parser\FileCollector;
25
use phpDocumentor\Parser\Parser as DocParser;
26
use phpDocumentor\Reflection\DocBlock\ExampleFinder;
27
use Psr\Log\LoggerInterface;
28
use Psr\Log\LogLevel;
29
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
30
use Zend\Cache\Storage\StorageInterface;
31
32
/**
33
 * Parses the given source code and creates a structure file.
34
 *
35
 * The parse task uses the source files defined either by -f or -d options and
36
 * generates a structure file (structure.xml) at the target location (which is
37
 * the folder 'output' unless the option -t is provided).
38
 */
39
final class Parser
40
{
41
    /** @var ProjectDescriptorBuilder $builder */
42
    private $builder;
43
44
    /** @var DocParser $parser */
45
    private $parser;
46
47
    /** @var StorageInterface */
48
    private $cache;
49
50
    /**
51
     * @var ExampleFinder
52
     */
53
    private $exampleFinder;
54
55
    /**
56
     * @var PartialsCollection
57
     */
58
    private $partials;
59
60
    /**
61
     * @var FileCollector
62
     */
63
    private $fileCollector;
64
65
    /**
66
     * @var EventDispatcherInterface
67
     */
68
    private $eventDispatcher;
69
70
    private $logger;
71
72
    /**
73
     * ParseCommand constructor.
74
     */
75
    public function __construct(
76
        ProjectDescriptorBuilder $builder,
77
        DocParser $parser,
78
        FileCollector $fileCollector,
79
        StorageInterface $cache,
80
        ExampleFinder $exampleFinder,
81
        PartialsCollection $partials,
82
        EventDispatcherInterface $eventDispatcher,
83
        LoggerInterface $logger
84
    ) {
85
        $this->builder = $builder;
86
        $this->parser = $parser;
87
        $this->cache = $cache;
88
        $this->exampleFinder = $exampleFinder;
89
        $this->partials = $partials;
90
        $this->fileCollector = $fileCollector;
91
        $this->eventDispatcher = $eventDispatcher;
92
        $this->logger = $logger;
93
    }
94
95
    private function getBuilder(): ProjectDescriptorBuilder
96
    {
97
        return $this->builder;
98
    }
99
100
    private function getParser(): DocParser
101
    {
102
        return $this->parser;
103
    }
104
105
    /**
106
     * Returns the Cache.
107
     *
108
     * @throws InvalidArgumentException
109
     */
110
    private function getCache(): StorageInterface
111
    {
112
        return $this->cache;
113
    }
114
115
    /**
116
     * Executes the business logic involved with this command.
117
     *
118
     * @throws Exception if the target location is not a folder.
119
     */
120
    public function __invoke(array $configuration): array
121
    {
122
        //Grep only the first version for now. Multi version support will be added later
123
        $version = current($configuration['phpdocumentor']['versions']);
124
125
        //We are currently in the parser stage so grep the api config.
126
        //And for now we support a single api definition. Could be more in the future.
127
        $apiConfig = $version['api'][0];
128
129
        $parser = $this->getParser();
130
        $parser->setForced(!$configuration['phpdocumentor']['use-cache']);
131
        $parser->setEncoding($apiConfig['encoding']);
132
        $parser->setMarkers($apiConfig['markers']);
133
        $parser->setIgnoredTags($apiConfig['ignore-tags']);
134
        $parser->setValidate($apiConfig['validate']);
135
        $parser->setDefaultPackageName($apiConfig['default-package-name']);
136
137
        $builder = $this->getBuilder();
138
        $builder->createProjectDescriptor();
139
        $projectDescriptor = $builder->getProjectDescriptor();
140
        $projectDescriptor->setName($configuration['phpdocumentor']['title']);
141
        $projectDescriptor->setPartials($this->partials);
142
143
        $visibility = $this->getVisibility($apiConfig);
0 ignored issues
show
Are you sure the assignment to $visibility is correct as $this->getVisibility($apiConfig) (which targets phpDocumentor\Applicatio...Parser::getVisibility()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
144
        $projectDescriptor->getSettings()->setVisibility($visibility);
145
        $projectDescriptor->getSettings()->setMarkers($apiConfig['markers']);
146
        $projectDescriptor->getSettings()->includeSource();
147
148
        $mapper = new ProjectDescriptorMapper($this->getCache());
149
150
        if ($configuration['phpdocumentor']['use-cache']) {
151
            //TODO: Re-enable garbage collection here.
152
            //$mapper->garbageCollect($files);
153
            $mapper->populate($projectDescriptor);
154
        }
155
156
        //TODO: Should determine root based on filesystems. Could be an issue for multiple.
157
        // Need some config update here.
158
        $this->exampleFinder->setSourceDirectory(getcwd());
159
        $this->exampleFinder->setExampleDirectories(['.']);
160
161
        $this->log('Collecting files .. ');
162
        $files = $this->getFileCollection($apiConfig);
163
        $this->log('OK');
164
        $this->log('Parsing files', LogLevel::NOTICE);
165
166
        $parser->parse($builder, $files);
167
168
        $this->log('Storing cache .. ', LogLevel::NOTICE);
169
        $projectDescriptor->getSettings()->clearModifiedFlag();
170
        $mapper->save($projectDescriptor);
171
        $this->log('OK');
172
173
        return $configuration;
174
    }
175
176
    /**
177
     * Returns the collection of files based on the input and configuration.
178
     */
179
    private function getFileCollection(array $apiConfig): array
180
    {
181
        $ignorePaths = array_map(
182
            function ($value) {
183
                if (substr((string) $value, -1) === '*') {
184
                    return substr($value, 0, -1);
185
                }
186
187
                return $value;
188
            },
189
            $apiConfig['ignore']['paths']
190
        );
191
192
        return $this->fileCollector->getFiles(
193
            $apiConfig['source']['dsn'],
194
            $apiConfig['source']['paths'],
195
            [
196
                'paths' => $ignorePaths,
197
                'hidden' => $apiConfig['ignore']['hidden'],
198
            ],
199
            $apiConfig['extensions']
200
        );
201
    }
202
203
    private function getVisibility(array $apiConfig): ?int
204
    {
205
        $visibilities = $apiConfig['visibility'];
206
        $visibility = null;
207
        foreach ($visibilities as $item) {
208
            switch ($item) {
209
                case 'public':
210
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PUBLIC;
211
                    break;
212
                case 'protected':
213
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PROTECTED;
214
                    break;
215
                case 'private':
216
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PRIVATE;
217
                    break;
218
            }
219
        }
220
        return $visibility;
221
    }
222
223
    /**
224
     * Dispatches a logging request.
225
     *
226
     * @param string   $priority The logging priority as declared in the LogLevel PSR-3 class.
227
     * @param string[] $parameters
228
     */
229
    private function log(string $message, string $priority = LogLevel::INFO, array $parameters = []): void
230
    {
231
        $this->logger->log($priority, $message, $parameters);
232
    }
233
}
234