Passed
Push — master ( 107a58...f1f480 )
by Arthur
05:43 queued 02:45
created

Json::setIsCollection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace SoliDry\Helpers;
4
5
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
6
use Illuminate\Database\Eloquent\Model;
7
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...
8
use League\Fractal\Manager;
9
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
10
use League\Fractal\Resource\Collection;
11
use League\Fractal\Resource\Item;
12
use League\Fractal\Resource\ResourceInterface;
13
use League\Fractal\Serializer\JsonApiSerializer;
14
use SoliDry\Types\ModelsInterface;
15
use SoliDry\Types\PhpInterface;
16
use SoliDry\Types\ApiInterface;
17
use SoliDry\Extension\BaseFormRequest;
18
use SoliDry\Extension\JSONApiInterface;
19
use SoliDry\Transformers\DefaultTransformer;
20
use SoliDry\Helpers\Request as Req;
21
22
/**
23
 * Class Json
24
 * @package SoliDry\Helpers
25
 */
26
class Json extends JsonAbstract
27
{
28
    private $isCollection = false;
29
    private $meta = [];
30
31
    /**
32
     * @param $relations      \Illuminate\Database\Eloquent\Collection
33
     * @param string $entity
34
     * @return array JSON API rels compatible array
35
     */
36
    public static function getRelations($relations, string $entity) : array
37
    {
38
        $jsonArr = [];
39
        if ($relations instanceof \Illuminate\Database\Eloquent\Collection) {
40
            $cnt = \count($relations);
41
            if ($cnt > 1) {
42
                foreach ($relations as $v) {
43
                    $attrs     = $v->getAttributes();
44
                    $jsonArr[] = [ApiInterface::RAML_TYPE => $entity,
45
                                  ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
46
                }
47
            } else {
48
                foreach ($relations as $v) {
49
                    $attrs   = $v->getAttributes();
50
                    $jsonArr = [ApiInterface::RAML_TYPE => $entity,
51
                                ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
52
                }
53
            }
54
        } elseif ($relations instanceof Model) {
55
            $attrs   = $relations->getAttributes();
56
            $jsonArr = [ApiInterface::RAML_TYPE => $entity,
57
                        ApiInterface::RAML_ID   => $attrs[ApiInterface::RAML_ID]];
58
        }
59
60
        return $jsonArr;
61
    }
62
63
    /**
64
     * Output errors in JSON API compatible format
65
     * @param array $errors
66
     * @param bool $return
67
     * @return string
68
     */
69
    public static function outputErrors(array $errors, bool $return = false)
70
    {
71
        $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...
72
        if (empty($errors) === false) {
73
            $arr[JSONApiInterface::CONTENT_ERRORS] = $errors;
74
        }
75
        // errors and codes must be clear with readable json
76
        $encoded = self::encode($arr, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
77
        if ($return === false && env('APP_ENV') !== 'dev') {
78
            echo $encoded;
79
            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...
80
        }
81
        return $encoded;
82
    }
83
84
    /**
85
     *
86
     * @param array $errors
87
     * @return string
88
     */
89
    public function getErrors(array $errors) : string
90
    {
91
        $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...
92
        if (empty($errors) === false) {
93
            $arr[JSONApiInterface::CONTENT_ERRORS] = $errors;
94
        }
95
96
        return self::encode($arr, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT);
97
    }
98
99
    /**
100
     * Returns composition of relations
101
     *
102
     * @param Request $request
103
     * @param array $data
104
     * @return string
105
     */
106
    public static function prepareSerializedRelations(Request $request, array $data) : string
107
    {
108
        $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...
109
            JSONApiInterface::CONTENT_SELF => $request->getUri(),
110
        ];
111
112
        $arr[JSONApiInterface::CONTENT_DATA] = $data;
113
114
        return self::encode($arr);
115
    }
116
117
    /**
118
     * @param BaseFormRequest $formRequest
119
     * @param                 $model
120
     * @param string $entity
121
     *
122
     * @return Collection|Item
123
     */
124
    public function getResource(BaseFormRequest $formRequest, $model, string $entity)
125
    {
126
        $transformer = new DefaultTransformer($formRequest);
127
        if ($this->isCollection === true) {
128
            $collection = new Collection($model, $transformer, strtolower($entity));
129
            if (empty($this->meta) === false) {
130
                $collection->setMeta($this->meta);
131
            }
132
133
            if ($model instanceof LengthAwarePaginator) { // only for paginator
134
                $collection->setPaginator(new IlluminatePaginatorAdapter($model));
135
            }
136
137
            return $collection;
138
        }
139
140
        $item = new Item($model, $transformer, strtolower($entity));
141
        $item->setMeta($this->meta);
142
143
        return $item;
144
    }
145
146
    /**
147
     * Prepares data to output in json-api format
148
     *
149
     * @param ResourceInterface $resource
150
     * @param array $data
151
     * @return string
152
     */
153
    public static function prepareSerializedData(ResourceInterface $resource, $data = ModelsInterface::DEFAULT_DATA) : string
154
    {
155
        if (empty($resource->getData())) { // preventing 3d party libs (League etc) from crash on empty data
156
            return self::encode([
157
                ModelsInterface::PARAM_DATA => []
158
            ]);
159
        }
160
161
        $manager = new Manager();
162
        if (isset($_GET['include'])) {
163
            $manager->parseIncludes($_GET['include']);
164
        }
165
166
        $manager->setSerializer(new JsonApiSerializer((new Req())->getBasePath()));
167
        return self::getSelectedData($manager->createData($resource)->toJson(), $data);
168
    }
169
170
    /**
171
     * Gets data only with those elements of object/array that should be provided as output
172
     *
173
     * @param string $json
174
     * @param array $data
175
     * @return string
176
     */
177
    private static function getSelectedData(string $json, array $data) : string
178
    {
179
        if (current($data) === PhpInterface::ASTERISK) {// do nothing - grab all fields
180
            return $json;
181
        }
182
183
        $jsonArr = self::decode($json);
184
        $current = current($jsonArr[ApiInterface::RAML_DATA]);
185
186
        if (empty($current[JSONApiInterface::CONTENT_ATTRIBUTES]) === false) {// this is an array of values
187
            self::unsetArray($jsonArr, $data);
188
        } else {// this is just one element
189
            self::unsetObject($jsonArr, $data);
190
        }
191
192
        return self::encode($jsonArr);
193
    }
194
195
    /**
196
     * Unsets objects from array that shouldn't be provided as output
197
     *
198
     * @param array &$json
199
     * @param array $data
200
     */
201
    private static function unsetArray(array &$json, array $data) : void
202
    {
203
        foreach ($json as $type => &$jsonObject) {
204
205
            if ($type === ApiInterface::RAML_DATA) { // unset only data->attributes fields
206
                foreach ($jsonObject as &$v) {
207
208
                    if (empty($v[JSONApiInterface::CONTENT_ATTRIBUTES]) === false) { // can be any of meta/link
209
                        foreach ($v[JSONApiInterface::CONTENT_ATTRIBUTES] as $key => $attr) {
210
211
                            if (\in_array($key, $data, true) === false) {
212
                                unset($v[JSONApiInterface::CONTENT_ATTRIBUTES][$key]);
213
                            }
214
                        }
215
                    }
216
                }
217
            }
218
        }
219
    }
220
221
    /**
222
     * Unsets objects that shouldn't be provided as output
223
     *
224
     * @param array $json
225
     * @param array $data
226
     */
227
    private static function unsetObject(array &$json, array $data) : void
228
    {
229
        if (empty($json[JSONApiInterface::CONTENT_DATA]) === false
230
            && empty($json[JSONApiInterface::CONTENT_DATA][JSONApiInterface::CONTENT_ATTRIBUTES]) === false) {
231
232
            foreach ($json[JSONApiInterface::CONTENT_DATA][JSONApiInterface::CONTENT_ATTRIBUTES] as $k => $v) {
233
                if (\in_array($k, $data, true) === false) {
234
                    unset($json[JSONApiInterface::CONTENT_DATA][JSONApiInterface::CONTENT_ATTRIBUTES][$k]);
235
                }
236
            }
237
        }
238
    }
239
240
    /**
241
     * @param bool $isCollection
242
     * @return Json
243
     */
244
    public function setIsCollection(bool $isCollection): Json
245
    {
246
        $this->isCollection = $isCollection;
247
248
        return $this;
249
    }
250
251
    /**
252
     * @param array $meta
253
     * @return Json
254
     */
255
    public function setMeta(array $meta): Json
256
    {
257
        $this->meta = $meta;
258
259
        return $this;
260
    }
261
}