Skip to content

Instantly share code, notes, and snippets.

@sebastiaanluca
Last active September 15, 2017 15:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebastiaanluca/4e834a24db7214ff3ae6 to your computer and use it in GitHub Desktop.
Save sebastiaanluca/4e834a24db7214ff3ae6 to your computer and use it in GitHub Desktop.
Simple example of returning a generic object in a repository using Laravel.
<?php namespace App\Repositories;
use App;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection;
use Illuminate\Support\Contracts\ArrayableInterface;
abstract class AbstractRepository
{
protected $model;
public function __construct($model)
{
$this->model = $model;
}
/**
* Parses a value in a nested way as deep as possible, in an
* effort to normalize itself and its contents.
*
* Mainly converts (Eloquent, etc) objects to standardized RespitoryObjects.
*
* @param mixed $value
*
* @return RepositoryObject|Collection|mixed
*/
protected function normalize($value)
{
$isCollection = false;
// TODO: extensively test with various values!
// If it's an array
if (is_array($value) || $value instanceof Collection) {
$isCollection = true;
if ($value instanceof Collection) {
$value = $value->toArray();
}
foreach ($value as &$item) {
// We're not there yet!
// Some nesting to get every object normalized
$item = $this->normalize($item);
}
// Some conversion because we want collections and not arrays
// (collections are way more powerful)
if (is_array($value)) {
$value = App::make('Illuminate\Support\Collection', [$value]);
}
}
// An object that implements ArrayableInterface (e.g. Eloquent)
// needs to be converted to array so its values represent
// whatever is visible or hidden
elseif (is_object($value) && $value instanceof ArrayableInterface) {
$value = $value->toArray();
}
// A regular object that we just cast
// to an array
elseif (is_object($value)) {
$value = (array)$value;
}
// Fill the custom repository object, but only
// if it's an array (otherwise making it a
// repository object would be too much normalization)
// Also don't do this for collections
if (is_array($value) && !$isCollection) {
$object = App::make('App\Repositories\RepositoryObject');
$object->fill($value);
}
// Return either the normalised object
// or the original value (not an array or object, or a nested call)
return isset($object) ? $object : $value;
}
/**
* Perform some content validation on the provided value.
*
* @param mixed $value
*
* @throws ModelNotFoundException
*/
protected function validate($value)
{
// Is it a Collection?
if ($value instanceof Collection) {
// Does it have any content?
if (count($value) <= 0) {
throw (new ModelNotFoundException())->setModel($this->model);
}
}
}
/**
* Wrapper to normalize and validate a result.
*
* @param mixed $result
*
* @return \App\Repositories\RepositoryObject|\Illuminate\Support\Collection|mixed
*/
protected function enhance($result)
{
$result = $this->normalize($result);
$this->validate($result);
return $result;
}
/**
* Handle every public call that's not overridden and reroute it to the model.
*
* @param $name
* @param $arguments
*
* @return \App\Repositories\RepositoryObject|\Illuminate\Support\Collection|mixed
*/
public function __call($name, $arguments)
{
// TODO: might need some more review and work
return $this->enhance(call_user_func_array([$this->model, $name], $arguments));
}
}
<?php namespace App\Repositories\Items;
use App;
use App\Models\Item;
use App\Repositories\AbstractRepository;
class ItemDBRepository extends AbstractRepository
{
public function __construct(Item $model)
{
parent::__construct($model);
}
public function findOrFail($id)
{
return $this->enhance($this->model->findOrFail($id));
}
}
<?php namespace App\Repositories;
use Illuminate\Support\Contracts\ArrayableInterface;
use Illuminate\Support\Contracts\JsonableInterface;
class RepositoryObject implements ArrayableInterface, JsonableInterface
{
public function fill(array $attributes)
{
foreach ($attributes as $key => $value) {
$this->$key = $value;
}
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return (array)$this;
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
*
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->toArray());
}
/**
* Convert the object to a JSON string.
*
* @return string
*/
public function __toString()
{
return $this->toJson();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment