Passed
Push — master ( 813b52...b69cbb )
by Arthur
03:02
created

Json::unsetObject()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
c 0
b 0
f 0
rs 10
cc 3
nc 3
nop 2
1
<?php
2
3
namespace SoliDry\Helpers;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Http\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, SoliDry\Helpers\Request. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use League\Fractal\Manager;
8
use League\Fractal\Resource\Collection;
9
use League\Fractal\Resource\Item;
10
use League\Fractal\Resource\ResourceInterface;
11
use League\Fractal\Serializer\JsonApiSerializer;
12
use SoliDry\Types\ModelsInterface;
13
use SoliDry\Types\PhpInterface;
14
use SoliDry\Types\ApiInterface;
15
use SoliDry\Extension\BaseFormRequest;
16
use SoliDry\Extension\JSONApiInterface;
17
use SoliDry\Transformers\DefaultTransformer;
18
19
/**
20
 * Class Json
21
 * @package SoliDry\Helpers
22
 */
23
class Json
24
{
25
    /**
26
     * @param array $jsonApiArr
27
     *
28
     * @return array
29
     */
30
    public static function getAttributes(array $jsonApiArr) : array
31
    {
32
        return empty($jsonApiArr[ApiInterface::RAML_DATA][ApiInterface::RAML_ATTRS]) ? [] : $jsonApiArr[ApiInterface::RAML_DATA][ApiInterface::RAML_ATTRS];
33
    }
34
35
    /**
36
     * Returns an array of bulk attributes for each element
37
     *
38
     * @param array $jsonApiArr
39
     * @return array
40
     */
41
    public static function getBulkAttributes(array $jsonApiArr) : array
42
    {
43
        return empty($jsonApiArr[ApiInterface::RAML_DATA]) ? [] : $jsonApiArr[ApiInterface::RAML_DATA];
44
    }
45
46
    /**
47
     * @param array $jsonApiArr
48
     *
49
     * @return array
50
     */
51
    public static function getRelationships(array $jsonApiArr) : array
52
    {
53
        return empty($jsonApiArr[ApiInterface::RAML_DATA][ApiInterface::RAML_RELATIONSHIPS]) ? [] : $jsonApiArr[ApiInterface::RAML_DATA][ApiInterface::RAML_RELATIONSHIPS];
54
    }
55
56
    /**
57
     * @param array $jsonApiArr
58
     *
59
     * @return array
60
     */
61
    public static function getData(array $jsonApiArr) : array
62
    {
63
        return empty($jsonApiArr[ApiInterface::RAML_DATA]) ? [] : $jsonApiArr[ApiInterface::RAML_DATA];
64
    }
65
66
    /**
67
     * @param $relations      \Illuminate\Database\Eloquent\Collection
68
     * @param string $entity
69
     * @return array JSON API rels compatible array
70
     */
71
    public static function getRelations($relations, string $entity) : array
72
    {
73
        $jsonArr = [];
74
        if ($relations instanceof \Illuminate\Database\Eloquent\Collection) {
75
            $cnt = count($relations);
76
            if ($cnt > 1) {
77
                foreach ($relations as $v) {
78
                    $attrs     = $v->getAttributes();
79
                    $jsonArr[] = [ApiInterface::RAML_TYPE => $entity,
80
                                  ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
81
                }
82
            } else {
83
                foreach ($relations as $v) {
84
                    $attrs   = $v->getAttributes();
85
                    $jsonArr = [ApiInterface::RAML_TYPE => $entity,
86
                                ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
87
                }
88
            }
89
        } elseif ($relations instanceof Model) {
90
            $attrs   = $relations->getAttributes();
91
            $jsonArr = [ApiInterface::RAML_TYPE => $entity,
92
                        ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
93
        }
94
95
        return $jsonArr;
96
    }
97
98
    /**
99
     * Output errors in JSON API compatible format
100
     * @param array $errors
101
     * @param bool $return
102
     * @return string
103
     */
104
    public static function outputErrors(array $errors, bool $return = false)
105
    {
106
        $arr[JSONApiInterface::CONTENT_ERRORS] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$arr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $arr = array(); before regardless.
Loading history...
107
        if (empty($errors) === false) {
108
            $arr[JSONApiInterface::CONTENT_ERRORS] = $errors;
109
        }
110
        // errors and codes must be clear with readable json
111
        $encoded = self::encode($arr, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
112
        if (false === $return && env('APP_ENV') !== 'dev') {
113
            echo $encoded;
114
            exit(JSONApiInterface::EXIT_STATUS_ERROR);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
115
        }
116
        return $encoded;
117
    }
118
119
    /**
120
     *
121
     * @param array $errors
122
     * @return string
123
     */
124
    public function getErrors(array $errors) : string
125
    {
126
        $arr[JSONApiInterface::CONTENT_ERRORS] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$arr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $arr = array(); before regardless.
Loading history...
127
        if (empty($errors) === false) {
128
            $arr[JSONApiInterface::CONTENT_ERRORS] = $errors;
129
        }
130
131
        return self::encode($arr, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
132
    }
133
134
    /**
135
     * Returns composition of relations
136
     *
137
     * @param Request $request
138
     * @param array $data
139
     * @return string
140
     */
141
    public static function prepareSerializedRelations(Request $request, array $data) : string
142
    {
143
        $arr[JSONApiInterface::CONTENT_LINKS] = [
0 ignored issues
show
Comprehensibility Best Practice introduced by
$arr was never initialized. Although not strictly required by PHP, it is generally a good practice to add $arr = array(); before regardless.
Loading history...
144
            JSONApiInterface::CONTENT_SELF => $request->getUri(),
145
        ];
146
147
        $arr[JSONApiInterface::CONTENT_DATA] = $data;
148
149
        return self::encode($arr);
150
    }
151
152
    /**
153
     * @param BaseFormRequest $formRequest
154
     * @param                 $model
155
     * @param string $entity
156
     * @param bool $isCollection
157
     *
158
     * @param array $meta
159
     * @return Collection|Item
160
     */
161
    public static function getResource(BaseFormRequest $formRequest, $model, string $entity, bool $isCollection = false, array $meta = [])
162
    {
163
        $transformer = new DefaultTransformer($formRequest);
164
        if ($isCollection === true) {
165
            $collection = new Collection($model, $transformer, strtolower($entity));
166
            if (empty($meta) === false) {
167
                $collection->setMeta($meta);
168
            }
169
170
            return $collection;
171
        }
172
173
        $item = new Item($model, $transformer, strtolower($entity));
174
        $item->setMeta($meta);
175
176
        return $item;
177
    }
178
179
    /**
180
     * @param ResourceInterface $resource
181
     * @param array $data
182
     * @return string
183
     */
184
    public static function prepareSerializedData(ResourceInterface $resource, $data = ModelsInterface::DEFAULT_DATA) : string
185
    {
186
        if (empty($resource->getData())) { // preventing 3d party libs (League etc) from crash on empty data
187
            return self::encode([
188
                ModelsInterface::PARAM_DATA => []
189
            ]);
190
        }
191
192
        $host    = $_SERVER['HTTP_HOST'];
193
        $manager = new Manager();
194
195
        if (isset($_GET['include'])) {
196
            $manager->parseIncludes($_GET['include']);
197
        }
198
199
        $manager->setSerializer(new JsonApiSerializer($host));
200
        return self::getSelectedData($manager->createData($resource)->toJson(), $data);
201
    }
202
203
    /**
204
     * @param array $array
205
     * @param int $opts
206
     * @return string
207
     */
208
    public static function encode(array $array, int $opts = 0)
209
    {
210
        return json_encode($array, $opts);
211
    }
212
213
    /**
214
     * @param mixed $json
215
     * @return mixed
216
     */
217
    public static function decode(string $json): array
218
    {
219
        return json_decode($json, true);
220
    }
221
222
    /**
223
     * @param string $json
224
     * @return array
225
     */
226
    public static function parse(string $json): array
227
    {
228
        return self::decode($json);
229
    }
230
231
    /**
232
     * @param string $json
233
     * @param array $data
234
     * @return string
235
     */
236
    private static function getSelectedData(string $json, array $data) : string
237
    {
238
        if (current($data) === PhpInterface::ASTERISK) {// do nothing - grab all fields
239
            return $json;
240
        }
241
242
        $jsonArr = self::decode($json);
243
        $current = current($jsonArr[ApiInterface::RAML_DATA]);
244
245
        if (empty($current[JSONApiInterface::CONTENT_ATTRIBUTES]) === false) {// this is an array of values
246
            self::unsetArray($jsonArr, $data);
247
        } else {// this is just one element
248
            self::unsetObject($jsonArr, $data);
249
        }
250
251
        return self::encode($jsonArr);
252
    }
253
254
    /**
255
     *
256
     * @param array &$json
257
     * @param array $data
258
     */
259
    private static function unsetArray(array &$json, array $data) : void
260
    {
261
        foreach ($json as &$jsonObject) {
262
            foreach ($jsonObject as &$v) {
263
                foreach ($v[JSONApiInterface::CONTENT_ATTRIBUTES] as $key => $attr) {
264
                    if (in_array($key, $data) === false) {
265
                        unset($v[JSONApiInterface::CONTENT_ATTRIBUTES][$key]);
266
                    }
267
                }
268
            }
269
        }
270
    }
271
272
    /**
273
     * @param array $json
274
     * @param array $data
275
     */
276
    private static function unsetObject(array &$json, array $data) : void
277
    {
278
        foreach ($json[JSONApiInterface::CONTENT_DATA][JSONApiInterface::CONTENT_ATTRIBUTES] as $k => $v) {
279
            if (in_array($k, $data) === false) {
280
                unset($json[JSONApiInterface::CONTENT_DATA][JSONApiInterface::CONTENT_ATTRIBUTES][$k]);
281
            }
282
        }
283
    }
284
}