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);
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...
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':
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