Last active
November 26, 2019 14:57
-
-
Save pepijnolivier/576dd44558cd0e146ee9dd634fa9d40d to your computer and use it in GitHub Desktop.
Useful trait when quickly scaffolding an API using Laravel Fractal transformers. PHP 7.0 compatible. Can be used with `astrotomic/laravel-translatable`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Support\Collection; | |
trait GenericTransformerTrait | |
{ | |
/** | |
* @param $modelOrCollection | |
* @param bool $recurse | |
* @param array $propsToIgnore | |
* | |
* @return array | |
*/ | |
public function genericTransform( | |
$modelOrCollection, bool $recurse = true, array $propsToIgnore=null | |
) { | |
$propsToIgnore = $propsToIgnore ?? $this->getDefaultPropsToIgnore(); | |
$propsToIgnore = $this->assocPropsArray($propsToIgnore); | |
return $this->prepareProps($modelOrCollection, $propsToIgnore, $recurse); | |
} | |
/** | |
* @return array | |
*/ | |
protected function getDefaultPropsToIgnore() | |
{ | |
return [ | |
'created_at', | |
'created_by_id', | |
'updated_at', | |
'updated_by_id', | |
'deleted_at', | |
'deleted_by_id', | |
]; | |
} | |
/** | |
* 1. Casts any collection and model to an array | |
* 2. recursively runs through all properties, | |
* Removes given properties (eg. timestamps) | |
* Also keys translations by locale | |
* | |
* @param $items | |
* @param array $propsToIgnore | |
* @param bool $recurse | |
* @return array | |
*/ | |
protected function prepareProps(&$items, array &$propsToIgnore, bool $recurse) | |
{ | |
// 1. cast to array | |
$wasCollection = false; | |
if (is_a($items, Collection::class)) { | |
/** @var Collection $items */ | |
$items = $items->toArray(); | |
$wasCollection = true; | |
} elseif (is_a($items, Model::class)) { | |
/** @var Model $items */ | |
$items = $items->toArray(); | |
} elseif(!is_array($items)) { | |
// bail, this was not a collection, a model or an array. | |
return []; | |
} | |
// 2. recursively loop over properties | |
foreach ($items as $key => &$item) { | |
// 2. bail early when we're detecting an array while not recursing | |
if (is_array($item) && !$recurse) { | |
unset($items[$key]); | |
continue; | |
} | |
// 2a. recurse | |
if (is_array($item) && $recurse) { | |
$this->prepareProps($item, $propsToIgnore, $recurse); | |
} | |
// 2b. remove properties to ignore | |
if (!$wasCollection && $this->shouldIgnoreProp($propsToIgnore, $key)) { | |
unset($items[$key]); | |
continue; | |
} | |
// 2c. key translations by locale, and cast to array | |
if ($key === 'translations') { | |
$item = collect($item)->keyBy('locale')->toArray(); | |
} | |
} | |
/** @var array $items */ | |
$items = $wasCollection ? array_values($items) : $items; | |
// 3. return array | |
return $items; | |
} | |
/** | |
* @param $arr | |
* @return array | |
*/ | |
protected function assocPropsArray(array $arr) | |
{ | |
$mapped = []; | |
foreach ($arr as $prop) { | |
if(is_string($prop)) { | |
$mapped[$prop] = true; | |
} | |
} | |
return $mapped; | |
} | |
protected function shouldIgnoreProp(array $propsToIgnore, string $prop) | |
{ | |
return isset($propsToIgnore[$prop]) && $propsToIgnore[$prop] === true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment