1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @author Flipbox Factory |
5
|
|
|
* @copyright Copyright (c) 2017, Flipbox Digital |
6
|
|
|
* @link https://github.com/flipbox/transform/releases/latest |
7
|
|
|
* @license https://github.com/flipbox/transform/blob/master/LICENSE |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace Flipbox\Transform\Scope; |
11
|
|
|
|
12
|
|
|
use Flipbox\Transform\Transformers\TransformerInterface; |
13
|
|
|
use Flipbox\Transform\Transform\ArrayTransform as ConfigurableTransform; |
14
|
|
|
use Flipbox\Transform\ParamBag; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @author Flipbox Factory <[email protected]> |
18
|
|
|
* @since 1.0.0 |
19
|
|
|
* |
20
|
|
|
* @property ConfigurableTransform $transform |
21
|
|
|
*/ |
22
|
|
|
class ArrayScope extends AbstractScope |
23
|
|
|
{ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Scope constructor. |
27
|
|
|
* @param ConfigurableTransform $transform |
28
|
|
|
* @param string|null $scopeIdentifier |
29
|
|
|
* @param array $parentScopes |
30
|
|
|
*/ |
31
|
|
|
public function __construct( |
32
|
|
|
ConfigurableTransform $transform, |
33
|
|
|
string $scopeIdentifier = null, |
34
|
|
|
array $parentScopes = [] |
35
|
|
|
) { |
36
|
|
|
parent::__construct($transform, $scopeIdentifier, $parentScopes); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Is Requested. |
41
|
|
|
* |
42
|
|
|
* Check if - in relation to the current scope - this specific segment is allowed. |
43
|
|
|
* That means, if a.b.c is requested and the current scope is a.b, then c is allowed. If the current |
44
|
|
|
* scope is a then c is not allowed, even if it is there and potentially transformable. |
45
|
|
|
* |
46
|
|
|
* @internal |
47
|
|
|
* |
48
|
|
|
* @param string $checkScopeSegment |
49
|
|
|
* |
50
|
|
|
* @return bool Returns the new number of elements in the array. |
51
|
|
|
*/ |
52
|
|
|
protected function isRequested($checkScopeSegment): bool |
53
|
|
|
{ |
54
|
|
|
return in_array( |
55
|
|
|
$this->scopeString($checkScopeSegment), |
56
|
|
|
$this->transform->getIncludes() |
57
|
|
|
); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Is Excluded. |
62
|
|
|
* |
63
|
|
|
* Check if - in relation to the current scope - this specific segment should |
64
|
|
|
* be excluded. That means, if a.b.c is excluded and the current scope is a.b, |
65
|
|
|
* then c will not be allowed in the transformation whether it appears in |
66
|
|
|
* the list of default or available, requested includes. |
67
|
|
|
* |
68
|
|
|
* @internal |
69
|
|
|
* |
70
|
|
|
* @param string $checkScopeSegment |
71
|
|
|
* |
72
|
|
|
* @return bool |
73
|
|
|
*/ |
74
|
|
|
protected function isExcluded($checkScopeSegment): bool |
75
|
|
|
{ |
76
|
|
|
return in_array( |
77
|
|
|
$this->scopeString($checkScopeSegment), |
78
|
|
|
$this->transform->getExcludes() |
79
|
|
|
); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param TransformerInterface|callable $transformer |
84
|
|
|
* @param mixed $data |
85
|
|
|
* @return array |
86
|
|
|
*/ |
87
|
|
|
public function transform(callable $transformer, $data): array |
88
|
|
|
{ |
89
|
|
|
$includedData = []; |
90
|
|
|
|
91
|
|
|
// Transform data |
92
|
|
|
$transformedData = parent::transform($transformer, $data); |
93
|
|
|
|
94
|
|
|
// Bail now |
95
|
|
|
if (null === $transformedData) { |
96
|
|
|
return $includedData; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
if (is_string($transformedData)) { |
100
|
|
|
$transformedData = [$transformedData]; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
foreach ($transformedData as $key => $val) { |
104
|
|
|
if (!$this->includeValue($transformer, $key)) { |
105
|
|
|
continue; |
106
|
|
|
} |
107
|
|
|
$includedData[$key] = $this->parseValue($val, $data, $key); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
// Return only the requested fields |
111
|
|
|
$includedData = $this->filterFields($includedData); |
112
|
|
|
|
113
|
|
|
return $includedData; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* @param callable $transformer |
118
|
|
|
* @param string $key |
119
|
|
|
* @return bool |
120
|
|
|
*/ |
121
|
|
|
protected function includeValue(callable $transformer, string $key): bool |
122
|
|
|
{ |
123
|
|
|
// Ignore optional (that have not been explicitly requested) |
124
|
|
|
if ($transformer instanceof TransformerInterface && |
125
|
|
|
in_array($key, $transformer->getIncludes(), true) && |
126
|
|
|
!$this->isRequested($key) |
127
|
|
|
) { |
128
|
|
|
return false; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
// Ignore excludes |
132
|
|
|
if ($this->isExcluded($key)) { |
133
|
|
|
return false; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
return true; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Filter the provided data with the requested filter fields for |
141
|
|
|
* the scope resource |
142
|
|
|
* |
143
|
|
|
* @internal |
144
|
|
|
* |
145
|
|
|
* @param array $data |
146
|
|
|
* |
147
|
|
|
* @return array |
148
|
|
|
*/ |
149
|
|
|
protected function filterFields(array $data): array |
150
|
|
|
{ |
151
|
|
|
$fields = $this->getFilterFields(); |
152
|
|
|
|
153
|
|
|
if ($fields === null) { |
154
|
|
|
return $data; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
return array_intersect_key( |
158
|
|
|
$data, |
159
|
|
|
array_flip( |
160
|
|
|
iterator_to_array($fields) |
161
|
|
|
) |
162
|
|
|
); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Return the requested filter fields for the scope resource |
167
|
|
|
* |
168
|
|
|
* @internal |
169
|
|
|
* |
170
|
|
|
* @return ParamBag|null |
171
|
|
|
*/ |
172
|
|
|
protected function getFilterFields() |
173
|
|
|
{ |
174
|
|
|
return $this->transform->getField( |
175
|
|
|
$this->getScopeIdentifier() |
176
|
|
|
); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @param string $checkScopeSegment |
181
|
|
|
* @return string |
182
|
|
|
*/ |
183
|
|
|
private function scopeString(string $checkScopeSegment): string |
184
|
|
|
{ |
185
|
|
|
if ($this->parentScopes) { |
|
|
|
|
186
|
|
|
$scopeArray = array_slice($this->parentScopes, 1); |
187
|
|
|
array_push($scopeArray, $this->scopeIdentifier, $checkScopeSegment); |
188
|
|
|
} else { |
189
|
|
|
$scopeArray = [$checkScopeSegment]; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return implode('.', (array)$scopeArray); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
|
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.