1 | <?php |
||
16 | abstract class AbstractResource extends Operator implements ResourceInterface |
||
17 | { |
||
18 | const DEFAULT_MARKER_KEY = 'id'; |
||
19 | |||
20 | /** |
||
21 | * The JSON key that indicates how the API nests singular resources. For example, when |
||
22 | * performing a GET, it could respond with ``{"server": {"id": "12345"}}``. In this case, |
||
23 | * "server" is the resource key, since the essential state of the server is nested inside. |
||
24 | * |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $resourceKey; |
||
28 | |||
29 | /** |
||
30 | * The key that indicates how the API nests resource collections. For example, when |
||
31 | * performing a GET, it could respond with ``{"servers": [{}, {}]}``. In this case, "servers" |
||
32 | * is the resources key, since the array of servers is nested inside. |
||
33 | * |
||
34 | * @var string |
||
35 | */ |
||
36 | protected $resourcesKey; |
||
37 | |||
38 | /** |
||
39 | * Indicates which attribute of the current resource should be used for pagination markers. |
||
40 | * |
||
41 | * @var string |
||
42 | */ |
||
43 | protected $markerKey; |
||
44 | |||
45 | /** |
||
46 | * An array of aliases that will be checked when the resource is being populated. For example, |
||
47 | * |
||
48 | * 'FOO_BAR' => 'fooBar' |
||
49 | * |
||
50 | * will extract FOO_BAR from the response, and save it as 'fooBar' in the resource. |
||
51 | * |
||
52 | * @var array |
||
53 | */ |
||
54 | protected $aliases = []; |
||
55 | |||
56 | /** |
||
57 | * Populates the current resource from a response object. |
||
58 | * |
||
59 | * @param ResponseInterface $response |
||
60 | * |
||
61 | * @return $this|ResourceInterface |
||
62 | */ |
||
63 | 74 | public function populateFromResponse(ResponseInterface $response) |
|
64 | { |
||
65 | 74 | if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) { |
|
66 | 61 | $json = Utils::jsonDecode($response); |
|
67 | 61 | if (!empty($json)) { |
|
68 | 61 | $this->populateFromArray(Utils::flattenJson($json, $this->resourceKey)); |
|
69 | 61 | } |
|
70 | 61 | } |
|
71 | |||
72 | 74 | return $this; |
|
73 | } |
||
74 | |||
75 | /** |
||
76 | * Populates the current resource from a data array. |
||
77 | * |
||
78 | * @param array $array |
||
79 | * |
||
80 | * @return mixed|void |
||
81 | */ |
||
82 | 133 | public function populateFromArray(array $array) |
|
83 | { |
||
84 | 133 | $reflClass = new \ReflectionClass($this); |
|
85 | |||
86 | 133 | foreach ($array as $key => $val) { |
|
87 | 133 | $propertyName = isset($this->aliases[$key]) ? $this->aliases[$key] : $key; |
|
88 | |||
89 | 133 | if (property_exists($this, $propertyName)) { |
|
90 | 131 | if ($type = $this->extractTypeFromDocBlock($reflClass, $propertyName)) { |
|
91 | 128 | $val = $this->parseDocBlockValue($type, $val); |
|
92 | 128 | } |
|
93 | |||
94 | 131 | $this->$propertyName = $val; |
|
95 | 131 | } |
|
96 | 133 | } |
|
97 | 133 | } |
|
98 | |||
99 | 128 | private function parseDocBlockValue($type, $val) |
|
100 | 2 | { |
|
101 | 128 | if (strpos($type, '[]') === 0 && is_array($val)) { |
|
102 | 6 | $array = []; |
|
103 | 6 | foreach ($val as $subVal) { |
|
104 | 6 | $array[] = $this->model($this->normalizeModelClass(substr($type, 2)), $subVal); |
|
105 | 6 | } |
|
106 | 6 | $val = $array; |
|
107 | 128 | } elseif (strcasecmp($type, '\datetimeimmutable') === 0) { |
|
108 | 28 | $val = new \DateTimeImmutable($val); |
|
109 | 127 | } elseif ($this->isNotNativeType($type)) { |
|
110 | 11 | $val = $this->model($this->normalizeModelClass($type), $val); |
|
111 | 11 | } |
|
112 | |||
113 | 128 | return $val; |
|
114 | } |
||
115 | |||
116 | 124 | private function isNotNativeType($type) |
|
117 | { |
||
118 | 124 | return !in_array($type, [ |
|
119 | 124 | 'string', 'bool', 'boolean', 'null', 'array', 'object', 'int', 'integer', 'float', 'numeric', 'mixed' |
|
120 | 124 | ]); |
|
121 | } |
||
122 | |||
123 | 12 | private function normalizeModelClass($class) |
|
124 | { |
||
125 | 12 | if (strpos($class, '\\') === false) { |
|
126 | 12 | $currentNamespace = (new \ReflectionClass($this))->getNamespaceName(); |
|
127 | 12 | $class = sprintf("%s\\%s", $currentNamespace, $class); |
|
128 | 12 | } |
|
129 | |||
130 | 12 | return $class; |
|
131 | } |
||
132 | |||
133 | 131 | private function extractTypeFromDocBlock(\ReflectionClass $reflClass, $propertyName) |
|
134 | { |
||
135 | 131 | $docComment = $reflClass->getProperty($propertyName)->getDocComment(); |
|
136 | |||
137 | 131 | if (!$docComment) { |
|
138 | 3 | return false; |
|
139 | } |
||
140 | |||
141 | 128 | $matches = []; |
|
142 | 128 | preg_match('#@var ((\[\])?[\w|\\\]+)#', $docComment, $matches); |
|
143 | 128 | return isset($matches[1]) ? $matches[1] : null; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * Internal method which retrieves the values of provided keys. |
||
148 | * |
||
149 | * @param array $keys |
||
150 | * |
||
151 | * @return array |
||
152 | */ |
||
153 | 65 | protected function getAttrs(array $keys) |
|
154 | { |
||
155 | 65 | $output = []; |
|
156 | |||
157 | 65 | foreach ($keys as $key) { |
|
158 | 65 | if (property_exists($this, $key) && $this->$key !== null) { |
|
159 | 65 | $output[$key] = $this->$key; |
|
160 | 65 | } |
|
161 | 65 | } |
|
162 | |||
163 | 65 | return $output; |
|
164 | } |
||
165 | |||
166 | /** |
||
167 | * @param array $definition |
||
168 | * |
||
169 | * @return mixed |
||
170 | */ |
||
171 | 60 | public function executeWithState(array $definition) |
|
175 | |||
176 | 38 | private function getResourcesKey() |
|
177 | { |
||
178 | 38 | $resourcesKey = $this->resourcesKey; |
|
179 | |||
180 | 38 | if (!$resourcesKey) { |
|
181 | 9 | $class = substr(static::class, strrpos(static::class, '\\') + 1); |
|
182 | 9 | $resourcesKey = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class)) . 's'; |
|
187 | |||
188 | /** |
||
189 | * {@inheritDoc} |
||
190 | */ |
||
191 | 33 | public function enumerate(array $def, array $userVals = [], callable $mapFn = null) |
|
218 | |||
219 | 5 | public function extractMultipleInstances(ResponseInterface $response, $key = null) |
|
234 | |||
235 | 1 | protected function getService() |
|
242 | } |
||
243 |