Completed
Push — develop ( 9193e7...62056c )
by Jaap
12:45 queued 02:43
created

ProjectDescriptorBuilder::build()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 5
nop 1
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Descriptor;
13
14
use phpDocumentor\Descriptor\Builder\AssemblerFactory;
15
use phpDocumentor\Descriptor\Builder\Reflector\AssemblerAbstract;
16
use phpDocumentor\Descriptor\Filter\Filter;
17
use phpDocumentor\Descriptor\Filter\Filterable;
18
use phpDocumentor\Descriptor\ProjectDescriptor\Settings;
19
use phpDocumentor\Descriptor\Validator\Error;
20
use phpDocumentor\Reflection\Fqsen;
21
use phpDocumentor\Reflection\Php\Project;
22
use phpDocumentor\Translator\Translator;
23
use Psr\Log\LogLevel;
24
use Symfony\Component\Validator\ConstraintViolation;
25
use Symfony\Component\Validator\Validator;
26
27
/**
28
 * Builds a Project Descriptor and underlying tree.
29
 */
30
class ProjectDescriptorBuilder
0 ignored issues
show
Complexity introduced by
The class ProjectDescriptorBuilder has a coupling between objects value of 21. Consider to reduce the number of dependencies under 13.
Loading history...
31
{
32
    /** @var string */
33
    const DEFAULT_PROJECT_NAME = 'Untitled project';
34
35
    /** @var AssemblerFactory $assemblerFactory */
36
    protected $assemblerFactory;
37
38
    /** @var Validator $validator */
39
    protected $validator;
40
41
    /** @var Filter $filter */
42
    protected $filter;
43
44
    /** @var ProjectDescriptor $project */
45
    protected $project;
46
47
    /** @var Translator $translator */
48
    protected $translator;
49
    private $defaultPackage;
50
51
    public function __construct(AssemblerFactory $assemblerFactory, Filter $filterManager, Validator $validator)
52
    {
53
        $this->assemblerFactory = $assemblerFactory;
54
        $this->validator        = $validator;
55
        $this->filter           = $filterManager;
56
    }
57
58
    public function createProjectDescriptor()
59
    {
60
        $this->project = new ProjectDescriptor(self::DEFAULT_PROJECT_NAME);
61
    }
62
63
    public function setProjectDescriptor(ProjectDescriptor $projectDescriptor)
64
    {
65
        $this->project = $projectDescriptor;
66
    }
67
68
    /**
69
     * Returns the project descriptor that is being built.
70
     *
71
     * @return ProjectDescriptor
72
     */
73
    public function getProjectDescriptor()
74
    {
75
        return $this->project;
76
    }
77
78
    /**
79
     * Verifies whether the given visibility is allowed to be included in the Descriptors.
80
     *
81
     * This method is used anytime a Descriptor is added to a collection (for example, when adding a Method to a Class)
82
     * to determine whether the visibility of that element is matches what the user has specified when it ran
83
     * phpDocumentor.
84
     *
85
     * @param string|integer $visibility One of the visibility constants of the ProjectDescriptor class or the words
86
     *     'public', 'protected', 'private' or 'internal'.
87
     *
88
     * @see ProjectDescriptor where the visibility is stored and that declares the constants to use.
89
     *
90
     * @return boolean
91
     */
92
    public function isVisibilityAllowed($visibility)
93
    {
94
        switch ($visibility) {
95
            case 'public':
96
                $visibility = Settings::VISIBILITY_PUBLIC;
97
                break;
98
            case 'protected':
99
                $visibility = Settings::VISIBILITY_PROTECTED;
100
                break;
101
            case 'private':
102
                $visibility = Settings::VISIBILITY_PRIVATE;
103
                break;
104
            case 'internal':
105
                $visibility = Settings::VISIBILITY_INTERNAL;
106
                break;
107
        }
108
109
        return $this->getProjectDescriptor()->isVisibilityAllowed($visibility);
110
    }
111
112
    /**
113
     * Takes the given data and attempts to build a Descriptor from it.
114
     *
115
     * @param mixed $data
116
     *
117
     * @throws \InvalidArgumentException if no Assembler could be found that matches the given data.
118
     *
119
     * @return DescriptorAbstract|Collection|null
120
     */
121
    public function buildDescriptor($data)
122
    {
123
        $assembler = $this->getAssembler($data);
124
        if (!$assembler) {
125
            throw new \InvalidArgumentException(
126
                'Unable to build a Descriptor; the provided data did not match any Assembler '. get_class($data)
127
            );
128
        }
129
130
        if ($assembler instanceof Builder\AssemblerAbstract) {
131
            $assembler->setBuilder($this);
132
        }
133
134
        // create Descriptor and populate with the provided data
135
        $descriptor = $assembler->create($data);
136
        if (!$descriptor) {
137
            return null;
138
        }
139
140
        $descriptor = (!is_array($descriptor) && (!$descriptor instanceof Collection))
141
            ? $this->filterAndValidateDescriptor($descriptor)
142
            : $this->filterAndValidateEachDescriptor($descriptor);
0 ignored issues
show
Documentation introduced by
$descriptor is of type array|object<phpDocumentor\Descriptor\Collection>, but the function expects a array<integer,object<php...or\DescriptorAbstract>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
143
144
        return $descriptor;
145
    }
146
147
    /**
148
     * Attempts to find an assembler matching the given data.
149
     *
150
     * @param mixed $data
151
     *
152
     * @return AssemblerAbstract
153
     */
154
    public function getAssembler($data)
155
    {
156
        return $this->assemblerFactory->get($data);
157
    }
158
159
    /**
160
     * Analyzes a Descriptor and alters its state based on its state or even removes the descriptor.
161
     *
162
     * @param Filterable $descriptor
163
     *
164
     * @return Filterable
165
     */
166
    public function filter(Filterable $descriptor)
167
    {
168
        return $this->filter->filter($descriptor);
169
    }
170
171
    /**
172
     * Validates the contents of the Descriptor and outputs warnings and error if something is amiss.
173
     *
174
     * @param DescriptorAbstract $descriptor
175
     *
176
     * @return Collection
177
     */
178
    public function validate($descriptor)
179
    {
180
        $violations = $this->validator->validate($descriptor);
181
        $errors = new Collection();
182
183
        /** @var ConstraintViolation $violation */
184
        foreach ($violations as $violation) {
185
            $errors->add(
186
                new Error(
187
                    $this->mapCodeToSeverity($violation->getCode()),
188
                    $violation->getMessageTemplate(),
189
                    $descriptor->getLine(),
190
                    $violation->getMessageParameters() + array($descriptor->getFullyQualifiedStructuralElementName())
191
                )
192
            );
193
        }
194
195
        return $errors;
196
    }
197
198
    /**
199
     * Filters each descriptor, validates them, stores the validation results and returns a collection of transmuted
200
     * objects.
201
     *
202
     * @param DescriptorAbstract[] $descriptor
203
     *
204
     * @return Collection
205
     */
206
    private function filterAndValidateEachDescriptor($descriptor)
207
    {
208
        $descriptors = new Collection();
209
        foreach ($descriptor as $key => $item) {
210
            $item = $this->filterAndValidateDescriptor($item);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $item is correct as $this->filterAndValidateDescriptor($item) (which targets phpDocumentor\Descriptor...AndValidateDescriptor()) 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...
211
            if (!$item) {
212
                continue;
213
            }
214
215
            $descriptors[$key] = $item;
216
        }
217
218
        return $descriptors;
219
    }
220
221
    /**
222
     * Filters a descriptor, validates it, stores the validation results and returns the transmuted object or null
223
     * if it is supposed to be removed.
224
     *
225
     * @param DescriptorAbstract $descriptor
226
     *
227
     * @return DescriptorAbstract|null
228
     */
229
    protected function filterAndValidateDescriptor($descriptor)
230
    {
231
        if (!$descriptor instanceof Filterable) {
232
            return $descriptor;
233
        }
234
235
        // filter the descriptor; this may result in the descriptor being removed!
236
        $descriptor = $this->filter($descriptor);
237
        if (!$descriptor) {
238
            return null;
239
        }
240
241
        // Validate the descriptor and store any errors
242
        $descriptor->setErrors($this->validate($descriptor));
0 ignored issues
show
Compatibility introduced by
$descriptor of type object<phpDocumentor\Des...ptor\Filter\Filterable> is not a sub-type of object<phpDocumentor\Des...tor\DescriptorAbstract>. It seems like you assume a concrete implementation of the interface phpDocumentor\Descriptor\Filter\Filterable to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
243
244
        return $descriptor;
245
	}
246
247
    /**
248
     * Map error code to severity.
249
     *
250
     * @param int $code
251
     *
252
     * @return string
253
     */
254
    protected function mapCodeToSeverity($code)
255
    {
256
        if (is_int($code) && $this->translator->translate('VAL:ERRLVL-'.$code)) {
257
            $severity = $this->translator->translate('VAL:ERRLVL-'.$code);
258
        } else {
259
             $severity = LogLevel::ERROR;
260
        }
261
262
        return $severity;
263
    }
264
265
    /**
266
     * @param Translator $translator
267
     *
268
     * @return void
269
     */
270
    public function setTranslator(Translator $translator)
271
    {
272
        $this->translator = $translator;
273
    }
274
275
    public function build(Project $project)
276
    {
277
        $packageName = $project->getRootNamespace()->getFqsen()->getName();
278
        $this->defaultPackage = new PackageDescriptor();
279
        $this->defaultPackage->setFullyQualifiedStructuralElementName((string)$project->getRootNamespace()->getFqsen());
280
        $this->defaultPackage->setName($packageName);
281
        $this->defaultPackage->setNamespace(substr((string)$project->getRootNamespace()->getFqsen(), 0, -strlen($packageName)-1));
282
283
        foreach ($project->getFiles() as $file) {
284
            $descriptor = $this->buildDescriptor($file);
285
            if (!$descriptor) {
286
                return;
287
            }
288
289
            $this->getProjectDescriptor()->getFiles()->set($descriptor->getPath(), $descriptor);
290
        }
291
292
        $namespaces = $this->getProjectDescriptor()->getIndexes()->get('namespaces', new Collection());
293
//        $namespaces->add($this->defaultPackage);
294
295
        foreach ($project->getNamespaces() as $namespace) {
296
            $namespaces->set((string)$namespace->getFqsen(), $this->buildDescriptor($namespace));
297
        }
298
    }
299
300
    /**
301
     * @return string
302
     */
303
    public function getDefaultPackage()
304
    {
305
        return $this->defaultPackage;
306
    }
307
}
308