Issues (115)

src/Services/AliasesService.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace VGirol\JsonApi\Services;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Http\Request;
7
use Illuminate\Routing\Route;
8
use VGirol\JsonApi\Exceptions\JsonApiException;
9
use VGirol\JsonApi\Resources\ResourceIdentifier;
10
use VGirol\JsonApi\Resources\ResourceIdentifierCollection;
11
use VGirol\JsonApi\Resources\ResourceObject;
12
use VGirol\JsonApi\Resources\ResourceObjectCollection;
13
14
class AliasesService
15
{
16
    public const ERROR_PATH_DOES_NOT_EXIST =
17
    'Path does not exist (%s => %s).';
18
19
    public const ERROR_REF_NOT_VALID =
20
    'Reference "%s" is not valid : no such Model, resource type, route key or relationship alias.';
21
22
    public const ERROR_NO_ROUTE =
23
    'No route available !';
24
25
    /**
26
     * Undocumented variable
27
     *
28
     * @var array
29
     */
30
    protected $groups = [];
31
32
    /**
33
     * Undocumented variable
34
     *
35
     * @var array
36
     */
37
    private $models = [];
38
39
    /**
40
     * Undocumented variable
41
     *
42
     * @var array
43
     */
44
    private $routeKeys = [];
45
46
    /**
47
     * Undocumented variable
48
     *
49
     * @var array
50
     */
51
    private $resType = [];
52
53
    /**
54
     * Undocumented variable
55
     *
56
     * @var array
57
     */
58
    private $aliases = [];
59
60
    /**
61
     * Class constructor
62
     */
63
    public function __construct()
64
    {
65
        $this->init();
66
    }
67
68
    /**
69
     * Undocumented function
70
     *
71
     * @return void
72
     */
73
    public function init(): void
74
    {
75
        $this->groups = config('jsonapi-alias.groups', []);
76
        $this->createDictionaries();
77
    }
78
79
    public function getModelClassName($ref = null): string
80
    {
81
        return $this->getDictionaryValue($ref, 'model', true);
82
    }
83
84
    public function getParentClassName($ref = null): string
85
    {
86
        return $this->getDictionaryValue($ref, 'model', false);
87
    }
88
89
    public function getResourceClassName($ref = null): string
90
    {
91
        return $this->getDictionaryValue($ref, 'resource-ro', true);
92
    }
93
94
    public function getResourceIdentifierClassName($ref = null): string
95
    {
96
        return $this->getDictionaryValue($ref, 'resource-ri', true);
97
    }
98
99
    public function getResourceCollectionClassName($ref = null): string
100
    {
101
        return $this->getDictionaryValue($ref, 'resource-roc', true);
102
    }
103
104
    public function getResourceIdentifierCollectionClassName($ref = null): string
105
    {
106
        return $this->getDictionaryValue($ref, 'resource-ric', true);
107
    }
108
109
    public function getFormRequestClassName($ref = null): string
110
    {
111
        return $this->getDictionaryValue($ref, 'request', true);
112
    }
113
114
    public function getResourceType($ref = null): string
115
    {
116
        return $this->getDictionaryValue($ref, 'type', true);
117
    }
118
119
    public function getResourceRoute($ref = null): string
120
    {
121
        return $this->getDictionaryValue($ref, 'route', true);
122
    }
123
124
    public function getParentRoute($ref = null): string
125
    {
126
        return $this->getDictionaryValue($ref, 'route', false);
127
    }
128
129
    public function getModelKeyName($ref = null): string
130
    {
131
        return jsonapiModel()->getModelKeyName($this->getModelClassName($ref));
132
    }
133
134
    /**
135
     * Undocumented function
136
     *
137
     * @param string|null $ref
138
     *
139
     * @return int|null
140
     */
141
    protected function getIndex(?string $ref): ?int
142
    {
143
        if (isset($this->aliases[$ref])) {
144
            $ref = $this->aliases[$ref];
145
        }
146
147
        if (isset($this->routeKeys[$ref])) {
148
            return $this->routeKeys[$ref];
149
        }
150
        if (isset($this->models[$ref])) {
151
            return $this->models[$ref];
152
        }
153
        if (isset($this->resType[$ref])) {
154
            return $this->resType[$ref];
155
        }
156
157
        return null;
158
    }
159
160
    /**
161
     * Undocumented function
162
     *
163
     * @param Request|Route|Model|string|null $ref
164
     * @param string                          $query
165
     * @param bool                            $searchForRelated
166
     *
167
     * @return string
168
     * @throws JsonApiException
169
     */
170
    private function getDictionaryValue($ref, string $query, bool $searchForRelated): string
171
    {
172
        if (!\is_string($ref)) {
173
            $ref = $this->getKeyName($ref, $searchForRelated);
174
        }
175
        $index = $this->getIndex($ref);
176
        if ($index === null) {
177
            throw new JsonApiException(sprintf(self::ERROR_REF_NOT_VALID, $ref));
178
        }
179
180
        $value = $this->groups[$index];
181
        $keys = explode('.', $query);
182
        foreach ($keys as $key) {
183
            if (isset($value[$key])) {
184
                $value = $value[$key];
185
                break;
186
            }
187
188
            switch ($key) {
189
                case 'resource-ro':
190
                    $value = ResourceObject::class;
191
                    break;
192
                case 'resource-ri':
193
                    $value = ResourceIdentifier::class;
194
                    break;
195
                case 'resource-roc':
196
                    $value = ResourceObjectCollection::class;
197
                    break;
198
                case 'resource-ric':
199
                    $value = ResourceIdentifierCollection::class;
200
                    break;
201
                default:
202
                    throw new JsonApiException(sprintf(self::ERROR_PATH_DOES_NOT_EXIST, $ref, $query));
203
            }
204
        }
205
206
        return $value;
207
    }
208
209
    /**
210
     * Undocumented function
211
     *
212
     * @param bool                            $searchForRelated
213
     * @param Request|Route|Model|string|null $ref
214
     *
215
     * @return string
216
     * @throws JsonApiException
217
     */
218
    private function getKeyName($ref, $searchForRelated): string
219
    {
220
        if ($ref instanceof Model) {
221
            $ref = get_class($ref);
222
        }
223
224
        if (\is_string($ref)) {
225
            return $ref;
226
        }
227
228
        $route = $ref;
229
        if (\is_null($ref)) {
230
            $ref = request();
231
        }
232
        if ($ref instanceof Request) {
233
            $route = $ref->route();
0 ignored issues
show
The method route() does not exist on Illuminate\Http\Request. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

233
            /** @scrutinizer ignore-call */ 
234
            $route = $ref->route();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
234
        }
235
        if (!$route instanceof Route) {
236
            throw new JsonApiException(self::ERROR_NO_ROUTE);
237
        }
238
239
        $bRelated = $route->named(['*.related.*', '*.relationship.*']) && $searchForRelated;
240
        $segment = $bRelated ? $route->parameters['relationship'] : $this->getRootSegment($route);
241
242
        return $segment;
243
    }
244
245
    /**
246
     * Undocumented function
247
     *
248
     * @param Route $route
249
     *
250
     * @return string
251
     */
252
    private function getRootSegment($route): string
253
    {
254
        $path = array_values(array_diff(
255
            explode('/', $route->uri),
256
            explode('/', $route->getPrefix())
257
        ));
258
259
        return $path[0];
260
    }
261
262
    /**
263
     * Undocumented function
264
     *
265
     * @return void
266
     */
267
    private function createDictionaries(): void
268
    {
269
        $this->routeKeys = [];
270
        $this->models = [];
271
        $this->resType = [];
272
        $this->aliases = [];
273
274
        foreach ($this->groups as $key => $array) {
275
            if (isset($array['route'])) {
276
                $this->routeKeys[$array['route']] = $key;
277
            }
278
            if (isset($array['model'])) {
279
                $this->models[$array['model']] = $key;
280
            }
281
            if (isset($array['type'])) {
282
                $this->resType[$array['type']] = $key;
283
            }
284
            if (isset($array['relationships'])) {
285
                $this->aliases = array_merge($this->aliases, $array['relationships']);
286
            }
287
        }
288
    }
289
}
290