Document   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 218
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 67.12%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 25
c 10
b 0
f 0
lcom 1
cbo 4
dl 0
loc 218
ccs 49
cts 73
cp 0.6712
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
D getIncluded() 0 44 10
A mergeResource() 0 13 2
A setData() 0 6 1
A setErrors() 0 6 1
A setJsonapi() 0 6 1
C toArray() 0 34 7
A __toString() 0 4 1
A jsonSerialize() 0 4 1
1
<?php
2
3
/*
4
 * This file is part of JSON-API.
5
 *
6
 * (c) Toby Zerner <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tobscure\JsonApi;
13
14
use JsonSerializable;
15
16
class Document implements JsonSerializable
17
{
18
    use LinksTrait;
19
    use MetaTrait;
20
21
    const MEDIA_TYPE = 'application/vnd.api+json';
22
23
    /**
24
     * The included array.
25
     *
26
     * @var array
27
     */
28
    protected $included = [];
29
30
    /**
31
     * The errors array.
32
     *
33
     * @var array
34
     */
35
    protected $errors;
36
37
    /**
38
     * The jsonapi array.
39
     *
40
     * @var array
41
     */
42
    protected $jsonapi;
43
44
    /**
45
     * The data object.
46
     *
47
     * @var ElementInterface
48
     */
49
    protected $data;
50
51
    /**
52 12
     * @param ElementInterface $data
0 ignored issues
show
Documentation introduced by
Should the type for parameter $data not be null|ElementInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
53
     */
54 12
    public function __construct(ElementInterface $data = null)
55 12
    {
56
        $this->data = $data;
57
    }
58
59
    /**
60
     * Get included resources.
61
     *
62
     * @param \Tobscure\JsonApi\ElementInterface $element
63
     * @param bool $includeParent
64
     *
65 9
     * @return \Tobscure\JsonApi\Resource[]
66
     */
67 9
    protected function getIncluded(ElementInterface $element, $includeParent = false)
68
    {
69 9
        $included = [];
70 9
71
        foreach ($element->getResources() as $resource) {
72
            if ($resource->isIdentifier()) {
73
                continue;
74 9
            }
75 3
76 3
            if ($includeParent) {
77 9
                $included = $this->mergeResource($included, $resource);
78 9
            } else {
79
                $type = $resource->getType();
80
                $id = $resource->getId();
81 9
            }
82 3
83
            foreach ($resource->getUnfilteredRelationships() as $relationship) {
84 3
                $includedElement = $relationship->getData();
85
86
                if (! $includedElement instanceof ElementInterface) {
87
                    continue;
88 3
                }
89
90
                foreach ($this->getIncluded($includedElement, true) as $child) {
91
                    // If this resource is the same as the top-level "data"
92 3
                    // resource, then we don't want it to show up again in the
93
                    // "included" array.
94
                    if (! $includeParent && $child->getType() === $type && $child->getId() === $id) {
0 ignored issues
show
Bug introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
95
                        continue;
96 3
                    }
97 3
98 9
                    $included = $this->mergeResource($included, $child);
99 9
                }
100
            }
101 9
        }
102
103
        $flattened = [];
104 3
105 9
        array_walk_recursive($included, function ($a) use (&$flattened) {
106
            $flattened[] = $a;
107 9
        });
108
109
        return $flattened;
110
    }
111
112
    /**
113
     * @param \Tobscure\JsonApi\Resource[] $resources
114
     * @param \Tobscure\JsonApi\Resource $newResource
115
     *
116 3
     * @return \Tobscure\JsonApi\Resource[]
117
     */
118 3
    protected function mergeResource(array $resources, Resource $newResource)
119 3
    {
120
        $type = $newResource->getType();
121 3
        $id = $newResource->getId();
122
123
        if (isset($resources[$type][$id])) {
124 3
            $resources[$type][$id]->merge($newResource);
125
        } else {
126
            $resources[$type][$id] = $newResource;
127 3
        }
128
129
        return $resources;
130
    }
131
132
    /**
133
     * Set the data object.
134
     *
135
     * @param \Tobscure\JsonApi\ElementInterface $element
136
     *
137
     * @return $this
138
     */
139
    public function setData(ElementInterface $element)
140
    {
141
        $this->data = $element;
142
143
        return $this;
144
    }
145
146
    /**
147
     * Set the errors array.
148
     *
149
     * @param array $errors
150
     *
151
     * @return $this
152
     */
153
    public function setErrors($errors)
154
    {
155
        $this->errors = $errors;
156
157
        return $this;
158
    }
159
160
    /**
161
     * Set the jsonapi array.
162
     *
163
     * @param array $jsonapi
164
     *
165
     * @return $this
166
     */
167
    public function setJsonapi($jsonapi)
168
    {
169
        $this->jsonapi = $jsonapi;
170
171
        return $this;
172
    }
173
174
    /**
175
     * Map everything to arrays.
176
     *
177 12
     * @return array
178
     */
179 12
    public function toArray()
180
    {
181 12
        $document = [];
182
183
        if (! empty($this->links)) {
184
            $document['links'] = $this->links;
185 12
        }
186 9
187
        if (! empty($this->data)) {
188 9
            $document['data'] = $this->data->toArray();
189
190 9
            $resources = $this->getIncluded($this->data);
191 3
192 3
            if (count($resources)) {
193 3
                $document['included'] = array_map(function (Resource $resource) {
194 3
                    return $resource->toArray();
195 9
                }, $resources);
196
            }
197 12
        }
198
199
        if (! empty($this->meta)) {
200
            $document['meta'] = $this->meta;
201 12
        }
202
203
        if (! empty($this->errors)) {
204
            $document['errors'] = $this->errors;
205 12
        }
206
207
        if (! empty($this->jsonapi)) {
208
            $document['jsonapi'] = $this->jsonapi;
209 12
        }
210
211
        return $document;
212
    }
213
214
    /**
215
     * Map to string.
216
     *
217 6
     * @return string
218
     */
219 6
    public function __toString()
220
    {
221
        return json_encode($this->toArray());
222
    }
223
224
    /**
225
     * Serialize for JSON usage.
226
     *
227
     * @return array
228
     */
229
    public function jsonSerialize()
230
    {
231
        return $this->toArray();
232
    }
233
}
234