Skip to content

Commit

Permalink
Merge pull request #15 from Napp/feature/transformaware
Browse files Browse the repository at this point in the history
Feature/transformaware
  • Loading branch information
Mads Møller authored Jul 28, 2018
2 parents eab647b + 9e6e243 commit b4731bd
Show file tree
Hide file tree
Showing 16 changed files with 815 additions and 30 deletions.
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html

# Ignore all test and documentation with "export-ignore".
/docs export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.travis.yml export-ignore
/phpunit.xml export-ignore
/.scrutinizer.yml export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.coverage.xml export-ignore
/coverage export-ignore
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.7",
"mockery/mockery": "^0.9.5",
"phpunit/phpunit" : "^6.1",
"phpunit/phpcov": "^4.0",
"mockery/mockery": "^1.0",
"phpunit/phpunit" : "^7.0",
"phpunit/phpcov": "^5.0",
"squizlabs/php_codesniffer": "^3.1",
"orchestra/testbench": "~3.0",
"orchestra/testbench": "^3.6",
"orchestra/database": "^3.6",
"fzaninotto/faker": "^1.7"
},
"extra": {
Expand Down
4 changes: 1 addition & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
verbose="true">
<testsuites>
<testsuite name="Unit">
Expand All @@ -28,9 +27,8 @@
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="test" />
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="DB_CONNECTION" value="sqlite" />
<env name="DB_DATABASE" value=":memory:" />
</php>
</phpunit>
224 changes: 206 additions & 18 deletions src/Transformers/ApiTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

/**
* Class ApiTransformer
* @package Napp\Core\Api\Transformers
*/
class ApiTransformer implements TransformerInterface
{
/**
* @var array
*/
protected $apiMapping = [];
public $apiMapping = [];

/**
* Strict mode removes keys that are
Expand Down Expand Up @@ -67,16 +72,65 @@ public function transformOutput($data): array
}

if (true === $data instanceof Collection) {
foreach ($data as $item) {
$output[] = $this->transformOutput($item);
}
$output = $this->transformCollection($output, $data);
} else if (true === $data instanceof Model) {
$output = $this->transformAttributes($output, $data->getAttributes());
$output = $this->transformRelationships($output, $data);
} else {
$data = (true === \is_array($data)) ? $data : $data->toArray();
foreach ($data as $key => $value) {
if (true === $this->strict && false === array_key_exists($key, $this->apiMapping)) {
$output = $this->transformAttributes($output, $data);
}

return $output;
}


/**
* @param array $output
* @param array $data
* @return array
*/
protected function transformAttributes(array $output, array $data): array
{
foreach ($data as $key => $value) {
if (true === $this->strict && false === array_key_exists($key, $this->apiMapping)) {
continue;
}

$output[$this->findNewKey($key)] = $this->convertValueType($key, $value);
}

return $output;
}

/**
* @param array $output
* @param Model $data
* @return array
*/
protected function transformRelationships(array $output, Model $data): array
{
/** @var Model $data */
$relationships = $data->getRelations();
foreach ($relationships as $relationshipName => $relationship) {
if (true === $relationship instanceof Collection) {
// do not transform empty relationships
if($relationship->isEmpty()) {
continue;
}
$output[$this->findNewKey($key)] = $this->convertValueType($key, $value);

if ($this->isTransformAware($relationship->first())) {
$output[$relationshipName] = $relationship->first()->getTransformer()->transformOutput($relationship);
} else {
$output[$relationshipName] = $relationship->toArray();
}
} else {
// model
if ($this->isTransformAware($relationship)) {
$output[$relationshipName] = $relationship->getTransformer()->transformOutput($relationship);
} else {
$output[$relationshipName] = $relationship->getAttributes();
}
}
}

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

/**
* @param array $output
* @param Collection $data
* @return array
*/
protected function transformCollection(array $output, Collection $data): array
{
foreach ($data as $item) {
$output[] = $this->transformOutput($item);
}

return $output;
}

/**
* @param string $newKey
* @return string
Expand Down Expand Up @@ -123,6 +191,7 @@ protected function findNewKey(string $originalKey): string
/**
* @param string $key
* @param mixed $value
* @param string $newKey
* @return mixed
*/
protected function convertValueType(string $key, $value)
Expand All @@ -131,21 +200,140 @@ protected function convertValueType(string $key, $value)
? $this->apiMapping[$key]['dataType']
: 'string';

foreach (static::normalizeType($type) as list($method, $parameters)) {
if (true === empty($method)) {
return $value;
}

if ('Nullable' === $method) {
if (true === empty($value) && false === \is_numeric($value)) {
return null;
}

continue;
}

$method = "convert{$method}";

if (false === method_exists(TransformerMethods::class, $method)) {
return $value;
}

return TransformerMethods::$method($value, $parameters);
}
}

/**
* @param $type
* @return array
*/
protected static function parseStringDataType($type): array
{
$parameters = [];

// The format for transforming data-types and parameters follows an
// easy {data-type}:{parameters} formatting convention. For instance the
// data-type "float:3" states that the value will be converted to a float with 3 decimals.
if (mb_strpos($type, ':') !== false) {
list($dataType, $parameter) = explode(':', $type, 2);

$parameters = static::parseParameters($parameter);
}

$dataType = static::normalizeDataType(trim($dataType ?? $type));

return [Str::studly($dataType), $parameters ?? []];
}

/**
* Parse a parameter list.
*
* @param string $parameter
* @return array
*/
protected static function parseParameters($parameter): array
{
return str_getcsv($parameter);
}

/**
* @param $type
* @return array
*/
protected static function parseManyDataTypes($type): array
{
$parsed = [];

$dataTypes = explode('|', $type);

foreach ($dataTypes as $dataType) {
$parsed[] = static::parseStringDataType(trim($dataType));
}

return $parsed;
}

/**
* @param $type
* @return array
*/
protected static function normalizeType($type): array
{
if (false !== mb_strpos($type, '|')) {
return self::normalizeNullable(
static::parseManyDataTypes($type)
);
}

return [static::parseStringDataType(trim($type))];
}

/**
* @param $type
* @return bool
*/
protected static function hasParameters($type): bool
{
return false !== mb_strpos($type, ':');
}

/**
* @param $dataTypes
* @return array
*/
protected static function normalizeNullable($dataTypes): array
{
if (isset($dataTypes[1][0]) && $dataTypes[1][0] === 'Nullable') {
return array_reverse($dataTypes);
}

return $dataTypes;
}

/**
* @param $type
* @return string
*/
protected static function normalizeDataType($type): string
{
switch ($type) {
case 'datetime':
return strtotime($value) > 0 ? date("c", strtotime($value)) : '';
case 'int':
return (int) $value;
return 'integer';
case 'bool':
return (bool) $value;
case 'array':
return (array) $value;
case 'json':
return json_decode($value);
case 'float':
return (float) $value;
return 'boolean';
case 'date':
return 'datetime';
default:
return $value;
return $type;
}
}

/**
* @param $model
* @return bool
*/
protected function isTransformAware($model): bool
{
return array_key_exists(TransformerAware::class, class_uses($model));
}
}
8 changes: 8 additions & 0 deletions src/Transformers/TransformerAware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Napp\Core\Api\Transformers;

trait TransformerAware
{
abstract public function getTransformer(): ApiTransformer;
}
Loading

0 comments on commit b4731bd

Please sign in to comment.