Completed
Push — master ( afc521...1cce3a )
by Vincent
03:19
created

AssertStructure::getAllResourceIdentifierObjects()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 8.0189

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 7
nop 1
dl 0
loc 25
ccs 14
cts 15
cp 0.9333
crap 8.0189
rs 8.4444
c 0
b 0
f 0
1
<?php
2
namespace VGirol\JsonApiAssert\Asserts;
3
4
use PHPUnit\Framework\Assert as PHPUnit;
5
use VGirol\JsonApiAssert\Messages;
6
use PHPUnit\Framework\ExpectationFailedException;
7
8
trait AssertStructure
9
{
10
    /**
11
     * Asserts that a json document has valid structure.
12
     *
13
     * @param array     $json
14
     * @param boolean   $strict     If true, unsafe characters are not allowed when checking members name.
15
     *
16
     * @throws PHPUnit\Framework\ExpectationFailedException
17
     */
18 9
    public static function assertHasValidStructure($json, $strict)
19
    {
20 9
        static::assertHasValidTopLevelMembers($json);
21
22 8
        if (isset($json['data'])) {
23 6
            static::assertIsValidPrimaryData($json['data'], $strict);
24
        }
25
26 7
        if (isset($json['errors'])) {
27 2
            static::assertIsValidErrorsObject($json['errors'], $strict);
28
        }
29
30 6
        if (isset($json['meta'])) {
31 2
            static::assertIsValidMetaObject($json['meta'], $strict);
32
        }
33
34 5
        if (isset($json['jsonapi'])) {
35 2
            static::assertIsValidJsonapiObject($json['jsonapi'], $strict);
36
        }
37
38 4
        if (isset($json['links'])) {
39 2
            static::assertIsValidTopLevelLinksMember($json['links'], $strict);
40
        }
41
42 3
        if (isset($json['included'])) {
43 2
            static::assertIsValidIncludedCollection($json['included'], $json['data'], $strict);
44
        }
45 2
    }
46
47
    /**
48
     * Asserts that a json document has valid top-level structure.
49
     *
50
     * @param array $json
51
     *
52
     * @throws PHPUnit\Framework\ExpectationFailedException
53
     */
54 14
    public static function assertHasValidTopLevelMembers($json)
55
    {
56 14
        $expected = ['data', 'errors', 'meta'];
57 14
        static::assertContainsAtLeastOneMember(
58 14
            $expected,
59 14
            $json,
60 14
            \sprintf(Messages::TOP_LEVEL_MEMBERS, implode('", "', $expected))
61
        );
62
63 13
        PHPUnit::assertFalse(
64 13
            isset($json['data']) && isset($json['errors']),
65 13
            Messages::TOP_LEVEL_DATA_AND_ERROR
66
        );
67
68 12
        $allowed = ['data', 'errors', 'meta', 'jsonapi', 'links', 'included'];
69 12
        static::assertContainsOnlyAllowedMembers(
70 12
            $allowed,
71 12
            $json
72
        );
73
74 10
        PHPUnit::assertFALSE(
75 10
            !isset($json['data']) && isset($json['included']),
76 10
            Messages::TOP_LEVEL_DATA_AND_INCLUDED
77
        );
78 9
    }
79
80
    /**
81
     * Asserts that a json fragment is a valid top-level links member.
82
     *
83
     * @param array     $json
84
     * @param boolean   $strict     If true, unsafe characters are not allowed when checking members name.
85
     *
86
     * @throws PHPUnit\Framework\ExpectationFailedException
87
     */
88 4
    public static function assertIsValidTopLevelLinksMember($json, $strict)
89
    {
90 4
        $allowed = ['self', 'related', 'first', 'last', 'next', 'prev'];
91 4
        static::assertIsValidLinksObject($json, $allowed, $strict);
92 2
    }
93
94
    /**
95
     * Asserts a json fragment is a valid primary data object.
96
     *
97
     * @param array     $data
98
     * @param boolean   $strict     If true, unsafe characters are not allowed when checking members name.
99
     *
100
     * @throws PHPUnit\Framework\ExpectationFailedException
101
     */
102 13
    public static function assertIsValidPrimaryData($data, $strict)
103
    {
104
        try {
105 13
            PHPUnit::assertIsArray(
106 13
                $data,
107 13
                Messages::PRIMARY_DATA_NOT_ARRAY
108
            );
109 11
            if (empty($data)) {
110 11
                return;
111
            }
112 2
        } catch (ExpectationFailedException $e) {
113 2
            PHPUnit::assertNull(
114 2
                $data,
115 2
                Messages::PRIMARY_DATA_NOT_ARRAY
116
            );
117 1
            return;
118
        }
119
120 10
        if (static::isArrayOfObjects($data)) {
121
            // Resource collection (Resource Objects or Resource Identifier Objects)
122 3
            static::assertIsValidPrimaryCollection($data, true, $strict);
123
        } else {
124
            // Single Resource (Resource Object or Resource Identifier Object)
125 7
            static::assertIsValidPrimarySingle($data, $strict);
126
        }
127 7
    }
128
129
    /**
130
     * Asserts that a collection of resource object is valid.
131
     *
132
     * @param array     $list
133
     * @param boolean   $checkType      If true, asserts that all resources of the collection are of same type.
134
     * @param boolean   $strict         If true, excludes not safe characters when checking members name
135
     *
136
     * @throws PHPUnit\Framework\ExpectationFailedException
137
     */
138 18
    private static function assertIsValidPrimaryCollection($list, $checkType, $strict)
139
    {
140 18
        $isResourceObjectCollection = null;
141
        foreach ($list as $index => $resource) {
142 14
            if ($checkType) {
143 14
                // Assert that all resources of the collection are of same type.
144 13
                if ($index == 0) {
145
                    $isResourceObjectCollection = static::dataIsResourceObject($resource);
146 8
                } else {
147 8
                    PHPUnit::assertEquals(
148
                        $isResourceObjectCollection,
149 6
                        static::dataIsResourceObject($resource),
150 6
                        Messages::PRIMARY_DATA_SAME_TYPE
151 6
                    );
152 6
                }
153
            }
154
155
            // Check the resource
156
            static::assertIsValidPrimarySingle($resource, $strict);
157
        }
158 13
    }
159
160 11
    /**
161
     * Assert that a single resource object is valid.
162
     *
163
     * @param array     $resource
164
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
165
     *
166
     * @throws PHPUnit\Framework\ExpectationFailedException
167
     */
168
    private static function assertIsValidPrimarySingle($resource, $strict)
169
    {
170 26
        if (static::dataIsResourceObject($resource)) {
171
            static::assertIsValidResourceObject($resource, $strict);
172 26
        } else {
173
            static::assertIsValidResourceIdentifierObject($resource, $strict);
174 25
        }
175 16
    }
176
177 10
    /**
178
     * Asserts that a collection of included resources is valid.
179 19
     *
180
     * @param array     $included   The included top-level member of a json document.
181
     * @param array     $data       The primary data of a json document.
182
     * @param boolean   $strict     If true, unsafe characters are not allowed when checking members name.
183
     *
184
     * @throws PHPUnit\Framework\ExpectationFailedException
185
     */
186
    public static function assertIsValidIncludedCollection($included, $data, $strict)
187
    {
188
        static::assertIsArrayOfObjects($included);
189
        foreach ($included as $resource) {
190 9
            static::assertIsValidResourceObject($resource, $strict);
191
        }
192 9
193
        $resIdentifiers = array_merge(
194 6
            static::getAllResourceIdentifierObjects($data),
195 6
            static::getAllResourceIdentifierObjects($included)
196 6
        );
197
198
        $present = [];
199 6
        foreach ($included as $inc) {
200 6
            PHPUnit::assertTrue(
201 6
                self::existsInArray($inc, $resIdentifiers),
202 6
                Messages::INCLUDED_RESOURCE_NOT_LINKED
203 6
            );
204
205
            if (!isset($present[$inc['type']])) {
206 5
                $present[$inc['type']] = [];
207 5
            }
208
            PHPUnit::assertNotContains(
209 5
                $inc['id'],
210 5
                $present[$inc['type']],
211 5
                Messages::COMPOUND_DOCUMENT_ONLY_ONE_RESOURCE
212 5
            );
213
            array_push($present[$inc['type']], $inc['id']);
214 5
        }
215
    }
216 3
217
    private static function dataIsResourceObject($resource)
218 25
    {
219
        $expected = ['attributes', 'relationships', 'links'];
220 25
221
        return static::containsAtLeastOneMember($expected, $resource);
222 25
    }
223
224
    private static function getAllResourceIdentifierObjects($data)
225 6
    {
226
        $arr = [];
227 6
        if (empty($data)) {
228 6
            return $arr;
229
        }
230
        if (!static::isArrayOfObjects($data)) {
231 6
            $data = [$data];
232 4
        }
233
        foreach ($data as $obj) {
234 6
            if (!isset($obj['relationships'])) {
235 6
                continue;
236 6
            }
237
            foreach ($obj['relationships'] as $key => $relationship) {
238 6
                if (!isset($relationship['data'])) {
239 6
                    continue;
240 1
                }
241
                $arr = array_merge(
242 6
                    $arr,
243 6
                    static::isArrayOfObjects($relationship['data']) ? $relationship['data'] : [$relationship['data']]
244 6
                );
245
            }
246
        }
247
248
        return $arr;
249 6
    }
250
251
    private static function existsInArray($needle, $arr)
252 6
    {
253
        foreach ($arr as $resIdentifier) {
254 6
            if (($resIdentifier['type'] === $needle['type']) && ($resIdentifier['id'] === $needle['id'])) {
255 6
                return true;
256 5
            }
257
        }
258
259
        return false;
260 2
    }
261
}
262