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);
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);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% 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...
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