Skip to content

Instantly share code, notes, and snippets.

@pepijnolivier
Last active November 26, 2019 14:57
Show Gist options
  • Save pepijnolivier/576dd44558cd0e146ee9dd634fa9d40d to your computer and use it in GitHub Desktop.
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`.
<?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