Completed
Push — master ( bb645e...4d0389 )
by Jaap
11:40 queued 08:50
created

ProjectDescriptorBuilder::shouldIncludeSource()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of phpDocumentor.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @link https://phpdoc.org
12
 */
13
14
namespace phpDocumentor\Descriptor;
15
16
use InvalidArgumentException;
17
use phpDocumentor\Configuration\ApiSpecification;
18
use phpDocumentor\Descriptor\Builder\AssemblerFactory;
19
use phpDocumentor\Descriptor\Builder\AssemblerInterface;
20
use phpDocumentor\Descriptor\Filter\Filter;
21
use phpDocumentor\Descriptor\Filter\Filterable;
22
use phpDocumentor\Descriptor\ProjectDescriptor\WithCustomSettings;
23
use phpDocumentor\Reflection\Php\Project;
24
use function array_merge;
25
use function get_class;
26
27
/**
28
 * Builds a Project Descriptor and underlying tree.
29
 */
30
class ProjectDescriptorBuilder
31
{
32
    /** @var string */
33
    public const DEFAULT_PROJECT_NAME = 'Untitled project';
34
35
    /** @var AssemblerFactory $assemblerFactory */
36
    protected $assemblerFactory;
37
38
    /** @var Filter $filter */
39
    protected $filter;
40
41
    /** @var ProjectDescriptor $project */
42
    protected $project;
43
44
    /** @var string */
45
    private $defaultPackage = '';
46
47
    /** @var iterable<WithCustomSettings> */
48
    private $servicesWithCustomSettings;
49
50
    /** @var ApiSpecification */
51
    private $apiSpecification;
52
53
    /**
54
     * @param iterable<WithCustomSettings> $servicesWithCustomSettings
0 ignored issues
show
Documentation introduced by
The doc-type iterable<WithCustomSettings> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
55
     */
56 1
    public function __construct(
57
        AssemblerFactory $assemblerFactory,
58
        Filter $filterManager,
59
        iterable $servicesWithCustomSettings = []
60
    ) {
61 1
        $this->assemblerFactory = $assemblerFactory;
62 1
        $this->filter = $filterManager;
63 1
        $this->servicesWithCustomSettings = $servicesWithCustomSettings;
64 1
    }
65
66 2
    public function createProjectDescriptor() : void
67
    {
68 2
        $this->project = new ProjectDescriptor(self::DEFAULT_PROJECT_NAME);
69 2
    }
70
71
    /**
72
     * Returns the project descriptor that is being built.
73
     */
74 2
    public function getProjectDescriptor() : ProjectDescriptor
75
    {
76 2
        return $this->project;
77
    }
78
79
    /**
80
     * Takes the given data and attempts to build a Descriptor from it.
81
     *
82
     * @param class-string<TDescriptor> $type
0 ignored issues
show
Documentation introduced by
The doc-type class-string<TDescriptor> could not be parsed: Unknown type name "class-string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
83
     *
84
     * @return TDescriptor|null
85
     *
86
     * @throws InvalidArgumentException If no Assembler could be found that matches the given data.
87
     *
88
     * @template TDescriptor of Descriptor
89
     */
90
    public function buildDescriptor(object $data, string $type) : ?Descriptor
91
    {
92
        $assembler = $this->getAssembler($data, $type);
93
        if (!$assembler) {
94
            throw new InvalidArgumentException(
95
                'Unable to build a Descriptor; the provided data did not match any Assembler ' .
96
                get_class($data)
97
            );
98
        }
99
100
        if ($assembler instanceof Builder\AssemblerAbstract) {
101
            $assembler->setBuilder($this);
102
        }
103
104
        // create Descriptor and populate with the provided data
105
        return $this->filterDescriptor($assembler->create($data));
0 ignored issues
show
Bug introduced by
It seems like $assembler->create($data) targeting phpDocumentor\Descriptor...blerInterface::create() can also be of type null; however, phpDocumentor\Descriptor...der::filterDescriptor() does only seem to accept object<phpDocumentor\Descriptor\Descriptor>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
106
    }
107
108
    /**
109
     * Attempts to find an assembler matching the given data.
110
     *
111
     * @param TInput $data
112
     * @param class-string<TDescriptor> $type
0 ignored issues
show
Documentation introduced by
The doc-type class-string<TDescriptor> could not be parsed: Unknown type name "class-string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
113
     *
114
     * @return AssemblerInterface<TDescriptor, TInput>|null
0 ignored issues
show
Documentation introduced by
The doc-type AssemblerInterface<TDescriptor, could not be parsed: Expected "|" or "end of type", but got "<" at position 18. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
115
     *
116
     * @template TInput as object
117
     * @template TDescriptor as Descriptor
118
     */
119
    public function getAssembler(object $data, string $type) : ?AssemblerInterface
120
    {
121
        return $this->assemblerFactory->get($data, $type);
122
    }
123
124
    /**
125
     * Analyzes a Descriptor and alters its state based on its state or even removes the descriptor.
126
     *
127
     * @param TDescriptor $descriptor
128
     *
129
     * @return TDescriptor|null
130
     *
131
     * @template TDescriptor as Filterable
132
     */
133
    public function filter(Filterable $descriptor) : ?Filterable
134
    {
135
        return $this->filter->filter($descriptor, $this->apiSpecification);
136
    }
137
138
    /**
139
     * Filters a descriptor, validates it, stores the validation results and returns the transmuted object or null
140
     * if it is supposed to be removed.
141
     *
142
     * @param TDescriptor $descriptor
143
     *
144
     * @return TDescriptor|null
145
     *
146
     * @template TDescriptor as Descriptor
147
     */
148
    protected function filterDescriptor(Descriptor $descriptor) : ?Descriptor
149
    {
150
        if (!$descriptor instanceof Filterable) {
151
            return $descriptor;
152
        }
153
154
        // filter the descriptor; this may result in the descriptor being removed!
155
        $descriptor = $this->filter($descriptor);
156
157
        return $descriptor;
158
    }
159
160
    public function setApiSpecification(ApiSpecification $apiSpecification) : void
161
    {
162
        $this->apiSpecification = $apiSpecification;
163
    }
164
165
    public function createApiDocumentationSet(Project $project) : void
166
    {
167
        $packageName = $project->getRootNamespace()->getFqsen()->getName();
168
        $this->defaultPackage = $packageName;
169
170
        $customSettings = $this->getProjectDescriptor()->getSettings()->getCustom();
171
        foreach ($this->servicesWithCustomSettings as $service) {
172
            // We assume that the custom settings have the non-default settings and we should not override those;
173
            // that is why we merge the custom settings on top of the default settings; this will cause the overrides
174
            // to remain in place.
175
            $customSettings = array_merge($service->getDefaultSettings(), $customSettings);
176
        }
177
178
        $this->getProjectDescriptor()->getSettings()->setCustom($customSettings);
179
180
        foreach ($project->getFiles() as $file) {
181
            $descriptor = $this->buildDescriptor($file, FileDescriptor::class);
0 ignored issues
show
Documentation introduced by
$file is of type object<phpDocumentor\Reflection\Php\File>, but the function expects a object<phpDocumentor\Descriptor\object>.

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...
182
            if ($descriptor === null) {
183
                continue;
184
            }
185
186
            $this->getProjectDescriptor()->getFiles()->set($descriptor->getPath(), $descriptor);
0 ignored issues
show
Bug introduced by
It seems like $descriptor defined by $this->buildDescriptor($...\FileDescriptor::class) on line 181 can also be of type object<phpDocumentor\Descriptor\Descriptor>; however, phpDocumentor\Descriptor\Collection::set() does only seem to accept object<phpDocumentor\Descriptor\T>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
187
        }
188
189
        $namespaces = $this->getProjectDescriptor()->getIndexes()->fetch('namespaces', new Collection());
190
191
        foreach ($project->getNamespaces() as $namespace) {
192
            $namespaces->set(
193
                (string) $namespace->getFqsen(),
194
                $this->buildDescriptor($namespace, NamespaceDescriptor::class)
0 ignored issues
show
Documentation introduced by
$namespace is of type object<phpDocumentor\Reflection\Php\Namespace_>, but the function expects a object<phpDocumentor\Descriptor\object>.

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...
195
            );
196
        }
197
    }
198
199
    public function getDefaultPackage() : string
200
    {
201
        return $this->defaultPackage;
202
    }
203
204 1
    public function setVisibility(int $visibility) : void
205
    {
206 1
        $this->project->getSettings()->setVisibility($visibility);
207 1
    }
208
209
    public function shouldIncludeSource() : bool
210
    {
211
        return $this->apiSpecification['include-source'];
212
    }
213
214
    public function setName(string $title) : void
215
    {
216
        $this->project->setName($title);
217
    }
218
219
    /**
220
     * @param Collection<string> $partials
0 ignored issues
show
Documentation introduced by
The doc-type Collection<string> could not be parsed: Expected "|" or "end of type", but got "<" at position 10. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
221
     */
222
    public function setPartials(Collection $partials) : void
223
    {
224
        $this->project->setPartials($partials);
225
    }
226
227
    /**
228
     * @param array<string, string> $customSettings
229
     */
230
    public function setCustomSettings(array $customSettings) : void
231
    {
232
        $this->project->getSettings()->setCustom($customSettings);
233
    }
234
235
    public function addVersion(VersionDescriptor $version) : void
236
    {
237
        $this->project->getVersions()->add($version);
0 ignored issues
show
Documentation introduced by
$version is of type object<phpDocumentor\Des...ptor\VersionDescriptor>, but the function expects a object<phpDocumentor\Descriptor\T>.

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...
238
    }
239
}
240