Completed
Push — master ( 198b3f...28f717 )
by Nate
02:18
created

Scope::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
/**
4
 * @package   Transform
5
 * @author    Flipbox Transform
6
 * @copyright Copyright (c) 2017, Flipbox Digital
7
 * @link      https://github.com/flipbox/transform/releases/latest
8
 * @license   https://github.com/flipbox/transform/blob/master/LICENSE
9
 */
10
11
namespace flipbox\transform;
12
13
use flipbox\transform\transformers\TransformerInterface;
14
15
/**
16
 * @package flipbox\transform
17
 * @author Flipbox Transform <[email protected]>
18
 * @since 1.0.0
19
 */
20
class Scope
21
{
22
23
    /**
24
     * @var string
25
     */
26
    protected $scopeIdentifier;
27
28
    /**
29
     * @var Transform
30
     */
31
    protected $transform;
32
33
    /**
34
     * @var array
35
     */
36
    protected $parentScopes = [];
37
38
    /**
39
     * Scope constructor.
40
     * @param Transform $transform
41
     * @param string|null $scopeIdentifier
42
     * @param array $parentScopes
43
     */
44
    public function __construct(Transform $transform, string $scopeIdentifier = null, array $parentScopes = [])
45
    {
46
        $this->transform = $transform;
47
        $this->scopeIdentifier = $scopeIdentifier;
48
        $this->parentScopes = $parentScopes;
49
    }
50
51
    /**
52
     * @return Transform
53
     */
54
    public function getTransform(): Transform
55
    {
56
        return $this->transform;
57
    }
58
59
    /**
60
     * @param $key
61
     * @return ParamBag
62
     */
63
    public function getParams(string $key = null): ParamBag
64
    {
65
        return $this->getTransform()->getParams(
66
            $this->getIdentifier($key)
67
        );
68
    }
69
70
    /**
71
     * Get the current identifier.
72
     *
73
     * @return string|null
74
     */
75
    public function getScopeIdentifier()
76
    {
77
        return $this->scopeIdentifier;
78
    }
79
80
    /**
81
     * Get the unique identifier for this scope.
82
     *
83
     * @param string $appendIdentifier
84
     *
85
     * @return string
86
     */
87
    public function getIdentifier(string $appendIdentifier = null): string
88
    {
89
        return implode(
90
            '.',
91
            array_filter(array_merge(
92
                $this->parentScopes,
93
                [
94
                    $this->scopeIdentifier,
95
                    $appendIdentifier
96
                ]
97
            ))
98
        );
99
    }
100
101
    /**
102
     * Getter for parentScopes.
103
     *
104
     * @return array
105
     */
106
    public function getParentScopes(): array
107
    {
108
        return $this->parentScopes;
109
    }
110
111
    /**
112
     * Is Requested.
113
     *
114
     * Check if - in relation to the current scope - this specific segment is allowed.
115
     * That means, if a.b.c is requested and the current scope is a.b, then c is allowed. If the current
116
     * scope is a then c is not allowed, even if it is there and potentially transformable.
117
     *
118
     * @internal
119
     *
120
     * @param string $checkScopeSegment
121
     *
122
     * @return bool Returns the new number of elements in the array.
123
     */
124
    public function isRequested($checkScopeSegment): bool
125
    {
126
        return in_array(
127
            $this->_scopeString($checkScopeSegment),
128
            $this->transform->getIncludes()
129
        );
130
    }
131
132
    /**
133
     * Is Excluded.
134
     *
135
     * Check if - in relation to the current scope - this specific segment should
136
     * be excluded. That means, if a.b.c is excluded and the current scope is a.b,
137
     * then c will not be allowed in the transformation whether it appears in
138
     * the list of default or available, requested includes.
139
     *
140
     * @internal
141
     *
142
     * @param string $checkScopeSegment
143
     *
144
     * @return bool
145
     */
146
    public function isExcluded($checkScopeSegment): bool
147
    {
148
        return in_array(
149
            $this->_scopeString($checkScopeSegment),
150
            $this->transform->getExcludes()
151
        );
152
    }
153
154
    /**
155
     * @param TransformerInterface|callable $transformer
156
     * @param mixed $data
157
     * @return array
158
     */
159
    public function transform(callable $transformer, $data): array
160
    {
161
162
        $includedData = [];
163
164
        // Transform data
165
        $transformedData = $this->parseValue($transformer, $data);
166
167
        // Bail now
168
        if (null === $transformedData) {
169
            return $includedData;
170
        }
171
172
        // Conform to array
173
        if (!is_array($transformedData)) {
174
            $transformedData = [$transformedData];
175
        }
176
177
        foreach ($transformedData as $key => $val) {
178
179
            if (!$this->includeValue($transformer, $key)) {
180
                continue;
181
            }
182
183
            $includedData[$key] = $this->parseValue($val, $data, $key);
184
185
        }
186
187
        // Return only the requested fields
188
        $includedData = $this->filterFields($includedData);
189
190
        return $includedData;
191
192
    }
193
194
    /**
195
     * @param callable $transformer
196
     * @param string $key
197
     * @return bool
198
     */
199
    protected function includeValue(callable $transformer, string $key): bool
200
    {
201
202
        // Ignore optional (that have not been explicitly requested)
203
        if ($transformer instanceof TransformerInterface && in_array($key, $transformer->getIncludes(), true) && !$this->isRequested($key)) {
204
            return false;
205
        }
206
207
        // Ignore excludes
208
        if ($this->isExcluded($key)) {
209
            return false;
210
        }
211
212
        return true;
213
214
    }
215
216
    /**
217
     * @param $val
218
     * @param $data
219
     * @param string|null $key
220
     * @return array|string|null
221
     */
222
    protected function parseValue($val, $data, string $key = null)
223
    {
224
225
226
        if (is_callable($val)) {
227
228
            return call_user_func_array($val, [$data, $this, $key]);
229
230
        }
231
232
        return $val;
233
234
    }
235
236
    /**
237
     * @param string $identifier
238
     * @return Scope
239
     */
240
    public function childScope(string $identifier): Scope
241
    {
242
243
        $parentScopes = $this->getParentScopes();
244
        $parentScopes[] = $this->getScopeIdentifier();
245
246
        return new Scope(
247
            $this->getTransform(),
248
            $identifier,
249
            array_filter($parentScopes)
250
        );
251
252
    }
253
254
    /**
255
     * Check, if this is the root scope.
256
     *
257
     * @return bool
258
     */
259
    protected function isRootScope(): bool
260
    {
261
        return empty($this->parentScopes);
262
    }
263
264
    /**
265
     * Filter the provided data with the requested filter fields for
266
     * the scope resource
267
     *
268
     * @internal
269
     *
270
     * @param array $data
271
     *
272
     * @return array
273
     */
274
    protected function filterFields(array $data): array
275
    {
276
277
        $fields = $this->getFilterFields();
278
279
        if ($fields === null) {
280
            return $data;
281
        }
282
283
        return array_intersect_key(
284
            $data,
285
            array_flip(
286
                iterator_to_array($fields)
287
            )
288
        );
289
290
    }
291
292
    /**
293
     * Return the requested filter fields for the scope resource
294
     *
295
     * @internal
296
     *
297
     * @return ParamBag|null
298
     */
299
    protected function getFilterFields()
300
    {
301
        return $this->transform->getField(
302
            $this->getScopeIdentifier()
303
        );
304
    }
305
306
    /**
307
     * @param string $checkScopeSegment
308
     * @return string
309
     */
310
    private function _scopeString(string $checkScopeSegment): string
311
    {
312
313
        if ($this->parentScopes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->parentScopes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
314
            $scopeArray = array_slice($this->parentScopes, 1);
315
            array_push($scopeArray, $this->scopeIdentifier, $checkScopeSegment);
316
        } else {
317
            $scopeArray = [$checkScopeSegment];
318
        }
319
320
        return implode('.', (array)$scopeArray);
321
322
    }
323
324
}
325