Completed
Push — develop ( 8fda15...dbbcf5 )
by Jaap
14s
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
/**
3
 * This file is part of phpDocumentor.
4
 *
5
 *  For the full copyright and license information, please view the LICENSE
6
 *  file that was distributed with this source code.
7
 *
8
 *  @copyright 2010-2017 Mike van Riel<[email protected]>
9
 *  @license   http://www.opensource.org/licenses/mit-license.php MIT
10
 *  @link      http://phpdoc.org
11
 */
12
13
namespace phpDocumentor\Application\Stage;
14
15
use phpDocumentor\Descriptor\Cache\ProjectDescriptorMapper;
16
use phpDocumentor\Descriptor\ProjectDescriptor;
17
use phpDocumentor\Descriptor\ProjectDescriptorBuilder;
18
use phpDocumentor\DomainModel\Parser\FileCollector;
19
use phpDocumentor\Event\LogEvent;
20
use phpDocumentor\Parser\Parser as DocParser;
21
use phpDocumentor\Partials\Collection as PartialsCollection;
22
use phpDocumentor\Reflection\DocBlock\ExampleFinder;
23
use Psr\Log\LogLevel;
24
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
25
use Symfony\Component\Filesystem\Filesystem;
26
use Zend\Cache\Storage\StorageInterface;
27
28
/**
29
 * Parses the given source code and creates a structure file.
30
 *
31
 * The parse task uses the source files defined either by -f or -d options and
32
 * generates a structure file (structure.xml) at the target location (which is
33
 * the folder 'output' unless the option -t is provided).
34
 */
35
final class Parser
36
{
37
    /** @var ProjectDescriptorBuilder $builder */
38
    private $builder;
39
40
    /** @var DocParser $parser */
41
    private $parser;
42
43
    /** @var StorageInterface */
44
    private $cache;
45
46
    /**
47
     * @var ExampleFinder
48
     */
49
    private $exampleFinder;
50
51
    /**
52
     * @var PartialsCollection
53
     */
54
    private $partials;
55
56
    /**
57
     * @var FileCollector
58
     */
59
    private $fileCollector;
60
61
    /**
62
     * @var EventDispatcherInterface
63
     */
64
    private $eventDispatcher;
65
66
    /**
67
     * ParseCommand constructor.
68
     */
69
    public function __construct(
70
        ProjectDescriptorBuilder $builder,
71
        DocParser $parser,
72
        FileCollector $fileCollector,
73
        StorageInterface $cache,
74
        ExampleFinder $exampleFinder,
75
        PartialsCollection $partials,
76
        EventDispatcherInterface $eventDispatcher
77
    ) {
78
        $this->builder = $builder;
79
        $this->parser = $parser;
80
        $this->cache = $cache;
81
        $this->exampleFinder = $exampleFinder;
82
        $this->partials = $partials;
83
        $this->fileCollector = $fileCollector;
84
        $this->eventDispatcher = $eventDispatcher;
85
    }
86
87
    private function getBuilder(): ProjectDescriptorBuilder
88
    {
89
        return $this->builder;
90
    }
91
92
    private function getParser(): DocParser
93
    {
94
        return $this->parser;
95
    }
96
97
    /**
98
     * Returns the Cache.
99
     *
100
     * @throws \InvalidArgumentException
101
     */
102
    private function getCache(): StorageInterface
103
    {
104
        return $this->cache;
105
    }
106
107
    /**
108
     * Executes the business logic involved with this command.
109
     *
110
     * @return array
111
     * @throws \Exception if the target location is not a folder.
112
     */
113
    public function __invoke(array $configuration)
114
    {
115
        $target = $configuration['phpdocumentor']['paths']['cache'];
116
117
        //Grep only the first version for now. Multi version support will be added later
118
        $version = current($configuration['phpdocumentor']['versions']);
119
120
        //We are currently in the parser stage so grep the api config.
121
        //And for now we support a single api definition. Could be more in the future.
122
        $apiConfig = $version['api'][0];
123
124
        //Process cache setup
125
        $fileSystem = new Filesystem();
126
        if (!$fileSystem->isAbsolutePath($target)) {
127
            $target = getcwd() . DIRECTORY_SEPARATOR . $target;
128
        }
129
        if (!file_exists($target)) {
130
            if (!mkdir($target) && !is_dir($target)) {
131
                throw new \RuntimeException('PPCPP:EXC-BADTARGET');
132
            }
133
        }
134
135
        $this->getCache()->getOptions()->setCacheDir($target);
136
137
        $parser = $this->getParser();
138
        $parser->setForced(!$configuration['phpdocumentor']['use-cache']);
139
        $parser->setEncoding($apiConfig['encoding']);
140
        $parser->setMarkers($apiConfig['markers']);
141
        $parser->setIgnoredTags($apiConfig['ignore-tags']);
142
        $parser->setValidate($apiConfig['validate']);
143
        $parser->setDefaultPackageName($apiConfig['default-package-name']);
144
145
        $builder = $this->getBuilder();
146
        $builder->createProjectDescriptor();
147
        $projectDescriptor = $builder->getProjectDescriptor();
148
        $projectDescriptor->setName($configuration['phpdocumentor']['title']);
149
        $projectDescriptor->setPartials($this->partials);
150
151
        $visibility = $this->getVisibility($apiConfig);
152
        $projectDescriptor->getSettings()->setVisibility($visibility);
153
154
        $mapper = new ProjectDescriptorMapper($this->getCache());
155
156
        if ($configuration['phpdocumentor']['use-cache']) {
157
            //TODO: Re-enable garbage collection here.
158
            //$mapper->garbageCollect($files);
159
            $mapper->populate($projectDescriptor);
160
        }
161
162
        //TODO: Should determine root based on filesystems. Could be an issue for multiple.
163
        // Need some config update here.
164
        $this->exampleFinder->setSourceDirectory(getcwd());
165
        $this->exampleFinder->setExampleDirectories(['.']);
166
167
        $this->log('PPCPP:LOG-COLLECTING');
168
        $files = $this->getFileCollection($apiConfig);
169
        $this->log('PPCPP:LOG-OK');
170
        $this->log('PPCPP:LOG-INITIALIZING');
171
172
        $this->log('PPCPP:LOG-OK');
173
        $this->log('PPCPP:LOG-PARSING');
174
175
        $parser->parse($builder, $files);
176
177
        $this->log('PPCPP:LOG-STORECACHE', LogLevel::INFO, ['cacheDir' => $target]);
178
        $projectDescriptor->getSettings()->clearModifiedFlag();
179
        $mapper->save($projectDescriptor);
180
        $this->log('PPCPP:LOG-OK');
181
182
        return $configuration;
183
    }
184
185
    /**
186
     * Returns the collection of files based on the input and configuration.
187
     */
188
    private function getFileCollection(array $apiConfig): array
189
    {
190
        $ignorePaths = array_map(
191
            function ($value) {
192
                if (substr($value, -1) === '*') {
193
                    return substr($value, 0, -1);
194
                }
195
196
                return $value;
197
            },
198
            $apiConfig['ignore']['paths']
199
        );
200
201
        return $this->fileCollector->getFiles(
202
            $apiConfig['source']['dsn'],
203
            $apiConfig['source']['paths'],
204
            [
205
                'paths' => $ignorePaths,
206
                'hidden' => $apiConfig['ignore']['hidden'],
207
            ],
208
            $apiConfig['extensions']
209
        );
210
    }
211
212
    private function getVisibility(array $apiConfig): ?int
213
    {
214
        $visibilities = $apiConfig['visibility'];
215
        $visibility = null;
216
        foreach ($visibilities as $item) {
217
            switch ($item) {
218
                case 'public':
0 ignored issues
show
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
219
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PUBLIC;
220
                    break;
221
                case 'protected':
222
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PROTECTED;
223
                    break;
224
                case 'private':
225
                    $visibility |= ProjectDescriptor\Settings::VISIBILITY_PRIVATE;
226
                    break;
227
            }
228
        }
229
        return $visibility;
230
    }
231
232
    /**
233
     * Dispatches a logging request.
234
     *
235
     * @param string   $message  The message to log.
236
     * @param string   $priority The logging priority as declared in the LogLevel PSR-3 class.
237
     * @param string[] $parameters
238
     */
239
    private function log($message, $priority = LogLevel::INFO, $parameters = [])
240
    {
241
        $this->eventDispatcher->dispatch(
242
            'system.log',
243
            LogEvent::createInstance($this)
244
                ->setContext($parameters)
245
                ->setMessage($message)
246
                ->setPriority($priority)
247
        );
248
    }
249
}
250