Completed
Branch master (c2a41b)
by
unknown
06:28
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 0
Metric Value
dl 0
loc 12
ccs 2
cts 2
cp 1
rs 9.4285
c 0
b 0
f 0
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-2017 [email protected]
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\Document\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\Encoder\Parser\ParserManager;
38
use \Neomerx\JsonApi\Http\Headers\AcceptMediaType;
39
use \Neomerx\JsonApi\Http\Headers\HeaderParameters;
40
use \Neomerx\JsonApi\Encoder\Parser\ParserEmptyReply;
41
use \Neomerx\JsonApi\Contracts\Document\LinkInterface;
42
use \Neomerx\JsonApi\Encoder\Parameters\SortParameter;
43
use \Neomerx\JsonApi\Http\Headers\SupportedExtensions;
44
use \Neomerx\JsonApi\Http\Query\QueryParametersParser;
45
use \Neomerx\JsonApi\Encoder\Handlers\ReplyInterpreter;
46
use \Neomerx\JsonApi\Http\Query\RestrictiveQueryChecker;
47
use \Neomerx\JsonApi\Contracts\Schema\ContainerInterface;
48
use \Neomerx\JsonApi\Http\Headers\HeaderParametersParser;
49
use \Neomerx\JsonApi\Contracts\Document\DocumentInterface;
50
use \Neomerx\JsonApi\Contracts\Factories\FactoryInterface;
51
use \Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface;
52
use \Neomerx\JsonApi\Encoder\Parameters\EncodingParameters;
53
use \Neomerx\JsonApi\Encoder\Parameters\ParametersAnalyzer;
54
use \Neomerx\JsonApi\Http\Headers\RestrictiveHeadersChecker;
55
use \Neomerx\JsonApi\Schema\ResourceIdentifierSchemaAdapter;
56
use \Neomerx\JsonApi\Contracts\Http\Headers\HeaderInterface;
57
use \Neomerx\JsonApi\Contracts\Schema\SchemaProviderInterface;
58
use \Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface;
59
use \Neomerx\JsonApi\Schema\ResourceIdentifierContainerAdapter;
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\Encoder\Parameters\EncodingParametersInterface;
65
use \Neomerx\JsonApi\Contracts\Encoder\Parameters\ParametersAnalyzerInterface;
66
67
/**
68
 * @package Neomerx\JsonApi
69
 *
70
 * @SuppressWarnings(PHPMD.TooManyMethods)
71
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
72
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
73
 */
74
class Factory implements FactoryInterface
75
{
76
    /**
77
     * @var LoggerInterface
78
     */
79
    protected $logger;
80
81
    /**
82
     * Constructor.
83
     */
84 193
    public function __construct()
85
    {
86 193
        $this->logger = new ProxyLogger();
87 193
    }
88
89
    /**
90
     * @inheritdoc
91
     */
92 2
    public function setLogger(LoggerInterface $logger)
93
    {
94 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...
95 2
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100 71
    public function createEncoder(ContainerInterface $container, EncoderOptions $encoderOptions = null)
101
    {
102 71
        $encoder = new Encoder($this, $container, $encoderOptions);
103
104 71
        $encoder->setLogger($this->logger);
105
106 71
        return $encoder;
107
    }
108
109
    /**
110
     * @inheritdoc
111
     */
112 104
    public function createDocument()
113
    {
114 104
        $document = new Document();
115
116 104
        $document->setLogger($this->logger);
117
118 104
        return $document;
119
    }
120
121
    /**
122
     * @inheritdoc
123
     */
124 3
    public function createError(
125
        $idx = null,
126
        LinkInterface $aboutLink = null,
127
        $status = null,
128
        $code = null,
129
        $title = null,
130
        $detail = null,
131
        $source = null,
132
        array $meta = null
133
    ) {
134 3
        return new Error($idx, $aboutLink, $status, $code, $title, $detail, $source, $meta);
135
    }
136
    /**
137
     * @inheritdoc
138
     */
139 62
    public function createReply($replyType, StackReadOnlyInterface $stack)
140
    {
141 62
        return new ParserReply($replyType, $stack);
142
    }
143
144
    /**
145
     * @inheritdoc
146
     */
147 24
    public function createEmptyReply(
148
        $replyType,
149
        StackReadOnlyInterface $stack
150
    ) {
151 24
        return new ParserEmptyReply($replyType, $stack);
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157 68
    public function createParser(ContainerInterface $container, ParserManagerInterface $manager)
158
    {
159 68
        $parser = new Parser($this, $this, $this, $container, $manager);
160
161 68
        $parser->setLogger($this->logger);
162
163 68
        return $parser;
164
    }
165
166
    /**
167
     * @inheritdoc
168
     */
169 66
    public function createManager(ParametersAnalyzerInterface $parameterAnalyzer)
170
    {
171 66
        $manager = new ParserManager($parameterAnalyzer);
172
173 66
        $manager->setLogger($this->logger);
174
175 66
        return $manager;
176
    }
177
178
    /**
179
     * @inheritdoc
180
     */
181 71
    public function createFrame(StackFrameReadOnlyInterface $previous = null)
182
    {
183 71
        return new StackFrame($previous);
184
    }
185
186
    /**
187
     * @inheritdoc
188
     */
189 72
    public function createStack()
190
    {
191 72
        return new Stack($this);
192
    }
193
194
    /**
195
     * @inheritdoc
196
     */
197 66
    public function createReplyInterpreter(DocumentInterface $document, ParametersAnalyzerInterface $parameterAnalyzer)
198
    {
199 66
        $interpreter = new ReplyInterpreter($document, $parameterAnalyzer);
200
201 66
        $interpreter->setLogger($this->logger);
202
203 66
        return $interpreter;
204
    }
205
206
    /**
207
     * @inheritdoc
208
     */
209 69
    public function createParametersAnalyzer(EncodingParametersInterface $parameters, ContainerInterface $container)
210
    {
211 69
        $analyzer = new ParametersAnalyzer($parameters, $container);
212
213 69
        $analyzer->setLogger($this->logger);
214
215 69
        return $analyzer;
216
    }
217
218
    /**
219
     * @inheritdoc
220
     */
221 1
    public function createMediaType($type, $subType, $parameters = null)
222
    {
223 1
        return new MediaType($type, $subType, $parameters);
224
    }
225
226
    /**
227
     * @inheritdoc
228
     */
229 70
    public function createQueryParameters(
230
        $includePaths = null,
231
        array $fieldSets = null,
232
        $sortParameters = null,
233
        array $pagingParameters = null,
234
        array $filteringParameters = null,
235
        array $unrecognizedParams = null
236
    ) {
237 70
        return new EncodingParameters(
238 70
            $includePaths,
239 70
            $fieldSets,
240 70
            $sortParameters,
241 70
            $pagingParameters,
242 70
            $filteringParameters,
243
            $unrecognizedParams
244 70
        );
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250 12
    public function createHeaderParameters($method, AcceptHeaderInterface $accept, HeaderInterface $contentType)
251
    {
252 12
        return new HeaderParameters($method, $accept, $contentType);
253
    }
254
255
    /**
256
     * @inheritdoc
257
     */
258 1
    public function createNoContentHeaderParameters($method, AcceptHeaderInterface $accept)
259
    {
260 1
        return new HeaderParameters($method, $accept, null);
261
    }
262
263
    /**
264
     * @inheritdoc
265
     */
266 26
    public function createQueryParametersParser()
267
    {
268 26
        $parser = new QueryParametersParser($this);
269
270 26
        $parser->setLogger($this->logger);
271
272 26
        return $parser;
273
    }
274
275
    /**
276
     * @inheritdoc
277
     */
278 15
    public function createHeaderParametersParser()
279
    {
280 15
        $parser = new HeaderParametersParser($this);
281
282 15
        $parser->setLogger($this->logger);
283
284 15
        return $parser;
285
    }
286
287
    /**
288
     * @inheritdoc
289
     */
290 17
    public function createSortParam($sortField, $isAscending)
291
    {
292 17
        return new SortParameter($sortField, $isAscending);
293
    }
294
295
    /**
296
     * @inheritdoc
297
     */
298 1
    public function createSupportedExtensions($extensions = MediaTypeInterface::NO_EXT)
299
    {
300 1
        return new SupportedExtensions($extensions);
301
    }
302
303
    /**
304
     * @inheritdoc
305
     */
306 1
    public function createAcceptMediaType(
307
        $position,
308
        $type,
309
        $subType,
310
        $parameters = null,
311
        $quality = 1.0,
312
        $extensions = null
313
    ) {
314 1
        return new AcceptMediaType($position, $type, $subType, $parameters, $quality, $extensions);
315
    }
316
317
    /**
318
     * @inheritdoc
319
     */
320 1
    public function createAcceptHeader($unsortedMediaTypes)
321
    {
322 1
        return new AcceptHeader($unsortedMediaTypes);
323
    }
324
325
    /**
326
     * @inheritdoc
327
     */
328 8
    public function createHeadersChecker(CodecMatcherInterface $codecMatcher)
329
    {
330 8
        return new RestrictiveHeadersChecker($codecMatcher);
331
    }
332
333
    /**
334
     * @inheritdoc
335
     *
336
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
337
     */
338 14
    public function createQueryChecker(
339
        $allowUnrecognized = true,
340
        array $includePaths = null,
341
        array $fieldSetTypes = null,
342
        array $sortParameters = null,
343
        array $pagingParameters = null,
344
        array $filteringParameters = null
345
    ) {
346 14
        return new RestrictiveQueryChecker(
347 14
            $allowUnrecognized,
348 14
            $includePaths,
349 14
            $fieldSetTypes,
350 14
            $sortParameters,
351 14
            $pagingParameters,
352
            $filteringParameters
353 14
        );
354
    }
355
356
    /**
357
     * @inheritdoc
358
     */
359 83
    public function createContainer(array $providers = [])
360
    {
361 83
        $container = new Container($this, $providers);
362
363 81
        $container->setLogger($this->logger);
364
365 81
        return $container;
366
    }
367
368
    /**
369
     * @inheritdoc
370
     */
371 83
    public function createResourceObject(
372
        SchemaProviderInterface $schema,
373
        $resource,
374
        $isInArray,
375
        $attributeKeysFilter = null
376
    ) {
377 83
        return new ResourceObject($schema, $resource, $isInArray, $attributeKeysFilter);
378
    }
379
380
    /**
381
     * @inheritdoc
382
     */
383 83
    public function createRelationshipObject($name, $data, $links, $meta, $isShowData, $isRoot)
384
    {
385 83
        return new RelationshipObject($name, $data, $links, $meta, $isShowData, $isRoot);
386
    }
387
388
    /**
389
     * @inheritdoc
390
     *
391
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
392
     */
393 58
    public function createLink($subHref, $meta = null, $treatAsHref = false)
394
    {
395 58
        return new Link($subHref, $meta, $treatAsHref);
396
    }
397
398
    /**
399
     * @inheritdoc
400
     */
401 3
    public function createResourceIdentifierSchemaAdapter(SchemaProviderInterface $schema)
402
    {
403 3
        return new ResourceIdentifierSchemaAdapter($this, $schema);
404
    }
405
406
    /**
407
     * @inheritdoc
408
     */
409 3
    public function createResourceIdentifierContainerAdapter(ContainerInterface $container)
410
    {
411 3
        return new ResourceIdentifierContainerAdapter($this, $container);
412
    }
413
414
    /**
415
     * @inheritdoc
416
     */
417 1
    public function createIdentitySchema(ContainerInterface $container, $classType, Closure $identityClosure)
418
    {
419 1
        return new IdentitySchema($this, $container, $classType, $identityClosure);
420
    }
421
422
    /**
423
     * @inheritdoc
424
     */
425 20
    public function createCodecMatcher()
426
    {
427 20
        return new CodecMatcher();
428
    }
429
}
430