Skip to content

Commit b4731bd

Browse files
author
Mads Møller
authored
Merge pull request #15 from Napp/feature/transformaware
Feature/transformaware
2 parents eab647b + 9e6e243 commit b4731bd

16 files changed

+815
-30
lines changed

.gitattributes

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Path-based git attributes
2+
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
3+
4+
# Ignore all test and documentation with "export-ignore".
5+
/docs export-ignore
6+
/.gitattributes export-ignore
7+
/.gitignore export-ignore
8+
/.travis.yml export-ignore
9+
/phpunit.xml export-ignore
10+
/.scrutinizer.yml export-ignore
11+
/tests export-ignore
12+
/.editorconfig export-ignore
13+
/.coverage.xml export-ignore
14+
/coverage export-ignore

composer.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@
3535
},
3636
"require-dev": {
3737
"friendsofphp/php-cs-fixer": "^2.7",
38-
"mockery/mockery": "^0.9.5",
39-
"phpunit/phpunit" : "^6.1",
40-
"phpunit/phpcov": "^4.0",
38+
"mockery/mockery": "^1.0",
39+
"phpunit/phpunit" : "^7.0",
40+
"phpunit/phpcov": "^5.0",
4141
"squizlabs/php_codesniffer": "^3.1",
42-
"orchestra/testbench": "~3.0",
42+
"orchestra/testbench": "^3.6",
43+
"orchestra/database": "^3.6",
4344
"fzaninotto/faker": "^1.7"
4445
},
4546
"extra": {

phpunit.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
convertWarningsToExceptions="true"
99
processIsolation="false"
1010
stopOnFailure="false"
11-
syntaxCheck="true"
1211
verbose="true">
1312
<testsuites>
1413
<testsuite name="Unit">
@@ -28,9 +27,8 @@
2827
<php>
2928
<env name="APP_ENV" value="testing"/>
3029
<env name="CACHE_DRIVER" value="array"/>
30+
<env name="DB_CONNECTION" value="test" />
3131
<env name="SESSION_DRIVER" value="array"/>
3232
<env name="QUEUE_DRIVER" value="sync"/>
33-
<env name="DB_CONNECTION" value="sqlite" />
34-
<env name="DB_DATABASE" value=":memory:" />
3533
</php>
3634
</phpunit>

src/Transformers/ApiTransformer.php

Lines changed: 206 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
use Illuminate\Pagination\LengthAwarePaginator;
88
use Illuminate\Pagination\Paginator;
99
use Illuminate\Support\Collection;
10+
use Illuminate\Support\Str;
1011

12+
/**
13+
* Class ApiTransformer
14+
* @package Napp\Core\Api\Transformers
15+
*/
1116
class ApiTransformer implements TransformerInterface
1217
{
1318
/**
1419
* @var array
1520
*/
16-
protected $apiMapping = [];
21+
public $apiMapping = [];
1722

1823
/**
1924
* Strict mode removes keys that are
@@ -67,16 +72,65 @@ public function transformOutput($data): array
6772
}
6873

6974
if (true === $data instanceof Collection) {
70-
foreach ($data as $item) {
71-
$output[] = $this->transformOutput($item);
72-
}
75+
$output = $this->transformCollection($output, $data);
76+
} else if (true === $data instanceof Model) {
77+
$output = $this->transformAttributes($output, $data->getAttributes());
78+
$output = $this->transformRelationships($output, $data);
7379
} else {
7480
$data = (true === \is_array($data)) ? $data : $data->toArray();
75-
foreach ($data as $key => $value) {
76-
if (true === $this->strict && false === array_key_exists($key, $this->apiMapping)) {
81+
$output = $this->transformAttributes($output, $data);
82+
}
83+
84+
return $output;
85+
}
86+
87+
88+
/**
89+
* @param array $output
90+
* @param array $data
91+
* @return array
92+
*/
93+
protected function transformAttributes(array $output, array $data): array
94+
{
95+
foreach ($data as $key => $value) {
96+
if (true === $this->strict && false === array_key_exists($key, $this->apiMapping)) {
97+
continue;
98+
}
99+
100+
$output[$this->findNewKey($key)] = $this->convertValueType($key, $value);
101+
}
102+
103+
return $output;
104+
}
105+
106+
/**
107+
* @param array $output
108+
* @param Model $data
109+
* @return array
110+
*/
111+
protected function transformRelationships(array $output, Model $data): array
112+
{
113+
/** @var Model $data */
114+
$relationships = $data->getRelations();
115+
foreach ($relationships as $relationshipName => $relationship) {
116+
if (true === $relationship instanceof Collection) {
117+
// do not transform empty relationships
118+
if($relationship->isEmpty()) {
77119
continue;
78120
}
79-
$output[$this->findNewKey($key)] = $this->convertValueType($key, $value);
121+
122+
if ($this->isTransformAware($relationship->first())) {
123+
$output[$relationshipName] = $relationship->first()->getTransformer()->transformOutput($relationship);
124+
} else {
125+
$output[$relationshipName] = $relationship->toArray();
126+
}
127+
} else {
128+
// model
129+
if ($this->isTransformAware($relationship)) {
130+
$output[$relationshipName] = $relationship->getTransformer()->transformOutput($relationship);
131+
} else {
132+
$output[$relationshipName] = $relationship->getAttributes();
133+
}
80134
}
81135
}
82136

@@ -92,6 +146,20 @@ protected function transformPaginatedOutput($data): array
92146
return $result;
93147
}
94148

149+
/**
150+
* @param array $output
151+
* @param Collection $data
152+
* @return array
153+
*/
154+
protected function transformCollection(array $output, Collection $data): array
155+
{
156+
foreach ($data as $item) {
157+
$output[] = $this->transformOutput($item);
158+
}
159+
160+
return $output;
161+
}
162+
95163
/**
96164
* @param string $newKey
97165
* @return string
@@ -123,6 +191,7 @@ protected function findNewKey(string $originalKey): string
123191
/**
124192
* @param string $key
125193
* @param mixed $value
194+
* @param string $newKey
126195
* @return mixed
127196
*/
128197
protected function convertValueType(string $key, $value)
@@ -131,21 +200,140 @@ protected function convertValueType(string $key, $value)
131200
? $this->apiMapping[$key]['dataType']
132201
: 'string';
133202

203+
foreach (static::normalizeType($type) as list($method, $parameters)) {
204+
if (true === empty($method)) {
205+
return $value;
206+
}
207+
208+
if ('Nullable' === $method) {
209+
if (true === empty($value) && false === \is_numeric($value)) {
210+
return null;
211+
}
212+
213+
continue;
214+
}
215+
216+
$method = "convert{$method}";
217+
218+
if (false === method_exists(TransformerMethods::class, $method)) {
219+
return $value;
220+
}
221+
222+
return TransformerMethods::$method($value, $parameters);
223+
}
224+
}
225+
226+
/**
227+
* @param $type
228+
* @return array
229+
*/
230+
protected static function parseStringDataType($type): array
231+
{
232+
$parameters = [];
233+
234+
// The format for transforming data-types and parameters follows an
235+
// easy {data-type}:{parameters} formatting convention. For instance the
236+
// data-type "float:3" states that the value will be converted to a float with 3 decimals.
237+
if (mb_strpos($type, ':') !== false) {
238+
list($dataType, $parameter) = explode(':', $type, 2);
239+
240+
$parameters = static::parseParameters($parameter);
241+
}
242+
243+
$dataType = static::normalizeDataType(trim($dataType ?? $type));
244+
245+
return [Str::studly($dataType), $parameters ?? []];
246+
}
247+
248+
/**
249+
* Parse a parameter list.
250+
*
251+
* @param string $parameter
252+
* @return array
253+
*/
254+
protected static function parseParameters($parameter): array
255+
{
256+
return str_getcsv($parameter);
257+
}
258+
259+
/**
260+
* @param $type
261+
* @return array
262+
*/
263+
protected static function parseManyDataTypes($type): array
264+
{
265+
$parsed = [];
266+
267+
$dataTypes = explode('|', $type);
268+
269+
foreach ($dataTypes as $dataType) {
270+
$parsed[] = static::parseStringDataType(trim($dataType));
271+
}
272+
273+
return $parsed;
274+
}
275+
276+
/**
277+
* @param $type
278+
* @return array
279+
*/
280+
protected static function normalizeType($type): array
281+
{
282+
if (false !== mb_strpos($type, '|')) {
283+
return self::normalizeNullable(
284+
static::parseManyDataTypes($type)
285+
);
286+
}
287+
288+
return [static::parseStringDataType(trim($type))];
289+
}
290+
291+
/**
292+
* @param $type
293+
* @return bool
294+
*/
295+
protected static function hasParameters($type): bool
296+
{
297+
return false !== mb_strpos($type, ':');
298+
}
299+
300+
/**
301+
* @param $dataTypes
302+
* @return array
303+
*/
304+
protected static function normalizeNullable($dataTypes): array
305+
{
306+
if (isset($dataTypes[1][0]) && $dataTypes[1][0] === 'Nullable') {
307+
return array_reverse($dataTypes);
308+
}
309+
310+
return $dataTypes;
311+
}
312+
313+
/**
314+
* @param $type
315+
* @return string
316+
*/
317+
protected static function normalizeDataType($type): string
318+
{
134319
switch ($type) {
135-
case 'datetime':
136-
return strtotime($value) > 0 ? date("c", strtotime($value)) : '';
137320
case 'int':
138-
return (int) $value;
321+
return 'integer';
139322
case 'bool':
140-
return (bool) $value;
141-
case 'array':
142-
return (array) $value;
143-
case 'json':
144-
return json_decode($value);
145-
case 'float':
146-
return (float) $value;
323+
return 'boolean';
324+
case 'date':
325+
return 'datetime';
147326
default:
148-
return $value;
327+
return $type;
149328
}
150329
}
330+
331+
/**
332+
* @param $model
333+
* @return bool
334+
*/
335+
protected function isTransformAware($model): bool
336+
{
337+
return array_key_exists(TransformerAware::class, class_uses($model));
338+
}
151339
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Napp\Core\Api\Transformers;
4+
5+
trait TransformerAware
6+
{
7+
abstract public function getTransformer(): ApiTransformer;
8+
}

0 commit comments

Comments
 (0)