Completed
Branch master (85eed3)
by
unknown
06:32
created

Factory::createError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 12
ccs 2
cts 2
cp 1
rs 9.4285
cc 1
eloc 10
nc 1
nop 8
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php namespace Neomerx\JsonApi\Factories;
2
3
/**
4
 * Copyright 2015 [email protected] (www.neomerx.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use \Closure;
20
use \Psr\Log\LoggerInterface;
21
use \Neomerx\JsonApi\Schema\Link;
22
use \Neomerx\JsonApi\Document\Error;
23
use \Neomerx\JsonApi\Encoder\Encoder;
24
use \Neomerx\JsonApi\Schema\Container;
25
use \Neomerx\JsonApi\Document\Document;
26
use \Neomerx\JsonApi\Codec\CodecMatcher;
27
use \Neomerx\JsonApi\Encoder\Stack\Stack;
28
use \Neomerx\JsonApi\Encoder\Parser\Parser;
29
use \Neomerx\JsonApi\Schema\IdentitySchema;
30
use \Neomerx\JsonApi\Schema\ResourceObject;
31
use \Neomerx\JsonApi\Encoder\EncoderOptions;
32
use \Neomerx\JsonApi\Http\Headers\MediaType;
33
use \Neomerx\JsonApi\Encoder\Stack\StackFrame;
34
use \Neomerx\JsonApi\Http\Headers\AcceptHeader;
35
use \Neomerx\JsonApi\Schema\RelationshipObject;
36
use \Neomerx\JsonApi\Encoder\Parser\ParserReply;
37
use \Neomerx\JsonApi\Http\Parameters\Parameters;
38
use \Neomerx\JsonApi\Encoder\Parser\ParserManager;
39
use \Neomerx\JsonApi\Http\Headers\AcceptMediaType;
40
use \Neomerx\JsonApi\Http\Parameters\SortParameter;
41
use \Neomerx\JsonApi\Contracts\Schema\LinkInterface;
42
use \Neomerx\JsonApi\Encoder\Parser\ParserEmptyReply;
43
use \Neomerx\JsonApi\Http\Parameters\ParametersParser;
44
use \Neomerx\JsonApi\Encoder\Handlers\ReplyInterpreter;
45
use \Neomerx\JsonApi\Http\Parameters\EncodingParameters;
46
use \Neomerx\JsonApi\Contracts\Schema\ContainerInterface;
47
use \Neomerx\JsonApi\Http\Parameters\SupportedExtensions;
48
use \Neomerx\JsonApi\Contracts\Document\DocumentInterface;
49
use \Neomerx\JsonApi\Contracts\Factories\FactoryInterface;
50
use \Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface;
51
use \Neomerx\JsonApi\Encoder\Parameters\ParametersAnalyzer;
52
use \Neomerx\JsonApi\Schema\ResourceIdentifierSchemaAdapter;
53
use \Neomerx\JsonApi\Contracts\Http\Headers\HeaderInterface;
54
use \Neomerx\JsonApi\Http\Parameters\RestrictiveQueryChecker;
55
use \Neomerx\JsonApi\Contracts\Schema\SchemaProviderInterface;
56
use \Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface;
57
use \Neomerx\JsonApi\Http\Parameters\RestrictiveHeadersChecker;
58
use \Neomerx\JsonApi\Schema\ResourceIdentifierContainerAdapter;
59
use \Neomerx\JsonApi\Http\Parameters\RestrictiveParametersChecker;
60
use \Neomerx\JsonApi\Contracts\Http\Headers\AcceptHeaderInterface;
61
use \Neomerx\JsonApi\Contracts\Encoder\Stack\StackReadOnlyInterface;
62
use \Neomerx\JsonApi\Contracts\Encoder\Parser\ParserManagerInterface;
63
use \Neomerx\JsonApi\Contracts\Encoder\Stack\StackFrameReadOnlyInterface;
64
use \Neomerx\JsonApi\Contracts\Http\Parameters\EncodingParametersInterface;
65
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\ParametersAnalyzerInterface;
66
67
/**
68
 * @package Neomerx\JsonApi
69
 */
70
class Factory implements FactoryInterface
71
{
72
    /**
73
     * @var LoggerInterface
74
     */
75
    protected $logger;
76
77
    /**
78
     * Constructor.
79
     */
80 167
    public function __construct()
81
    {
82 167
        $this->logger = new ProxyLogger();
83 167
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88 2
    public function setLogger(LoggerInterface $logger)
89
    {
90 2
        $this->logger->setLogger($logger);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Log\LoggerInterface as the method setLogger() does only exist in the following implementations of said interface: Neomerx\JsonApi\Factories\ProxyLogger.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
91 2
    }
92
93
    /**
94
     * @inheritdoc
95
     */
96 61
    public function createEncoder(ContainerInterface $container, EncoderOptions $encoderOptions = null)
97
    {
98 61
        $encoder = new Encoder($this, $container, $encoderOptions);
99
100 61
        $encoder->setLogger($this->logger);
101
102 61
        return $encoder;
103
    }
104
105
    /**
106
     * @inheritdoc
107
     */
108 89
    public function createDocument()
109
    {
110 89
        $document = new Document();
111
112 89
        $document->setLogger($this->logger);
113
114 89
        return $document;
115
    }
116
117
    /**
118
     * @inheritdoc
119
     */
120 3
    public function createError(
121
        $idx = null,
122
        LinkInterface $aboutLink = null,
123
        $status = null,
124
        $code = null,
125
        $title = null,
126
        $detail = null,
127
        $source = null,
128
        array $meta = null
129
    ) {
130 3
        return new Error($idx, $aboutLink, $status, $code, $title, $detail, $source, $meta);
131
    }
132
    /**
133
     * @inheritdoc
134
     */
135 51
    public function createReply($replyType, StackReadOnlyInterface $stack)
136
    {
137 51
        return new ParserReply($replyType, $stack);
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143 19
    public function createEmptyReply(
144
        $replyType,
145
        StackReadOnlyInterface $stack
146
    ) {
147 19
        return new ParserEmptyReply($replyType, $stack);
148
    }
149
150
    /**
151
     * @inheritdoc
152
     */
153 57
    public function createParser(ContainerInterface $container, ParserManagerInterface $manager)
154
    {
155 57
        $parser = new Parser($this, $this, $this, $container, $manager);
156
157 57
        $parser->setLogger($this->logger);
158
159 57
        return $parser;
160
    }
161
162
    /**
163
     * @inheritdoc
164
     */
165 55
    public function createManager(ParametersAnalyzerInterface $parameterAnalyzer)
166
    {
167 55
        $manager = new ParserManager($parameterAnalyzer);
168
169 55
        $manager->setLogger($this->logger);
170
171 55
        return $manager;
172
    }
173
174
    /**
175
     * @inheritdoc
176
     */
177 60
    public function createFrame(StackFrameReadOnlyInterface $previous = null)
178
    {
179 60
        return new StackFrame($previous);
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185 61
    public function createStack()
186
    {
187 61
        return new Stack($this);
188
    }
189
190
    /**
191
     * @inheritdoc
192
     */
193 55
    public function createReplyInterpreter(DocumentInterface $document, ParametersAnalyzerInterface $parameterAnalyzer)
194
    {
195 55
        $interpreter = new ReplyInterpreter($document, $parameterAnalyzer);
196
197 55
        $interpreter->setLogger($this->logger);
198
199 55
        return $interpreter;
200
    }
201
202
    /**
203
     * @inheritdoc
204
     */
205 40
    public function createEncodingParameters($includePaths = null, array $fieldSets = null)
206
    {
207 40
        return new EncodingParameters($includePaths, $fieldSets);
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213 58
    public function createParametersAnalyzer(EncodingParametersInterface $parameters, ContainerInterface $container)
214
    {
215 58
        $analyzer = new ParametersAnalyzer($parameters, $container);
216
217 58
        $analyzer->setLogger($this->logger);
218
219 58
        return $analyzer;
220
    }
221
222
    /**
223
     * @inheritdoc
224
     */
225 1
    public function createMediaType($type, $subType, $parameters = null)
226
    {
227 1
        return new MediaType($type, $subType, $parameters);
228
    }
229
230
    /**
231
     * @inheritdoc
232
     */
233 25
    public function createParameters(
234
        HeaderInterface $contentType,
235
        AcceptHeaderInterface $accept,
236
        $includePaths = null,
237
        array $fieldSets = null,
238
        $sortParameters = null,
239
        array $pagingParameters = null,
240
        array $filteringParameters = null,
241
        array $unrecognizedParams = null
242
    ) {
243 25
        return new Parameters(
244 25
            $contentType,
245 25
            $accept,
246 25
            $includePaths,
247 25
            $fieldSets,
248 25
            $sortParameters,
249 25
            $pagingParameters,
250 25
            $filteringParameters,
251
            $unrecognizedParams
252 25
        );
253
    }
254
255
    /**
256
     * @inheritdoc
257
     */
258 33
    public function createParametersParser()
259
    {
260 33
        $parser = new ParametersParser($this);
261
262 33
        $parser->setLogger($this->logger);
263
264 33
        return $parser;
265
    }
266
267
    /**
268
     * @inheritdoc
269
     */
270 18
    public function createSortParam($sortField, $isAscending)
271
    {
272 18
        return new SortParameter($sortField, $isAscending);
273
    }
274
275
    /**
276
     * @inheritdoc
277
     */
278 1
    public function createSupportedExtensions($extensions = MediaTypeInterface::NO_EXT)
279
    {
280 1
        return new SupportedExtensions($extensions);
281
    }
282
283
    /**
284
     * @inheritdoc
285
     */
286 2
    public function createAcceptMediaType(
287
        $position,
288
        $type,
289
        $subType,
290
        $parameters = null,
291
        $quality = 1.0,
292
        $extensions = null
293
    ) {
294 2
        return new AcceptMediaType($position, $type, $subType, $parameters, $quality, $extensions);
295
    }
296
297
    /**
298
     * @inheritdoc
299
     */
300 2
    public function createAcceptHeader($unsortedMediaTypes)
301
    {
302 2
        return new AcceptHeader($unsortedMediaTypes);
303
    }
304
305
    /**
306
     * @inheritdoc
307
     */
308 16
    public function createHeadersChecker(CodecMatcherInterface $codecMatcher)
309
    {
310 16
        return new RestrictiveHeadersChecker($codecMatcher);
311
    }
312
313
    /**
314
     * @inheritdoc
315
     */
316 16
    public function createQueryChecker(
317
        $allowUnrecognized = true,
318
        array $includePaths = null,
319
        array $fieldSetTypes = null,
320
        array $sortParameters = null,
321
        array $pagingParameters = null,
322
        array $filteringParameters = null
323
    ) {
324 16
        return new RestrictiveQueryChecker(
325 16
            $allowUnrecognized,
326 16
            $includePaths,
327 16
            $fieldSetTypes,
328 16
            $sortParameters,
329 16
            $pagingParameters,
330
            $filteringParameters
331 16
        );
332
    }
333
334
    /**
335
     * @inheritdoc
336
     */
337 16
    public function createParametersChecker(
338
        CodecMatcherInterface $codecMatcher,
339
        $allowUnrecognized = false,
340
        array $includePaths = null,
341
        array $fieldSetTypes = null,
342
        array $sortParameters = null,
343
        array $pagingParameters = null,
344
        array $filteringParameters = null
345
    ) {
346 16
        $headersChecker = $this->createHeadersChecker($codecMatcher);
347 16
        $queryChecker   = $this->createQueryChecker(
348 16
            $allowUnrecognized,
349 16
            $includePaths,
350 16
            $fieldSetTypes,
351 16
            $sortParameters,
352 16
            $pagingParameters,
353
            $filteringParameters
354 16
        );
355
356 16
        return new RestrictiveParametersChecker($headersChecker, $queryChecker);
357
    }
358
359
    /**
360
     * @inheritdoc
361
     */
362 73
    public function createContainer(array $providers = [])
363
    {
364 73
        $container = new Container($this, $providers);
365
366 71
        $container->setLogger($this->logger);
367
368 71
        return $container;
369
    }
370
371
    /**
372
     * @inheritdoc
373
     */
374 72
    public function createResourceObject(
375
        SchemaProviderInterface $schema,
376
        $resource,
377
        $isInArray,
378
        $attributeKeysFilter = null
379
    ) {
380 72
        return new ResourceObject($schema, $resource, $isInArray, $attributeKeysFilter);
381
    }
382
383
    /**
384
     * @inheritdoc
385
     */
386 72
    public function createRelationshipObject($name, $data, $links, $meta, $isShowData, $isRoot)
387
    {
388 72
        return new RelationshipObject($name, $data, $links, $meta, $isShowData, $isRoot);
389
    }
390
391
    /**
392
     * @inheritdoc
393
     */
394 7
    public function createLink($subHref, $meta = null, $treatAsHref = false)
395
    {
396 7
        return new Link($subHref, $meta, $treatAsHref);
397
    }
398
399
    /**
400
     * @inheritdoc
401
     */
402 2
    public function createResourceIdentifierSchemaAdapter(SchemaProviderInterface $schema)
403
    {
404 2
        return new ResourceIdentifierSchemaAdapter($this, $schema);
405
    }
406
407
    /**
408
     * @inheritdoc
409
     */
410 2
    public function createResourceIdentifierContainerAdapter(ContainerInterface $container)
411
    {
412 2
        return new ResourceIdentifierContainerAdapter($this, $container);
413
    }
414
415
    /**
416
     * @inheritdoc
417
     */
418 1
    public function createIdentitySchema(ContainerInterface $container, $classType, Closure $identityClosure)
419
    {
420 1
        return new IdentitySchema($this, $container, $classType, $identityClosure);
421
    }
422
423
    /**
424
     * @inheritdoc
425
     */
426 28
    public function createCodecMatcher()
427
    {
428 28
        return new CodecMatcher();
429
    }
430
}
431