Exemple of register: public function register() { $this->app->bind('App\Product\Repository', function() { $eloquent = new \App\Repositories\Product\Eloquent(new App\Model\Product); if ($this->useCache) { return new \App\Repositories\Product\Cache($eloquent); } return $eloquent; }); } /*********************************************************************** * Eloquent class used for all repositories of the project */ <?php namespace App\Repositories; use \RuntimeException; use \InvalidArgumentException; use Illuminate\Support\Collection; use Illuminate\Support\Str; abstract class Eloquent implements Repository { /** * Model/Mapper to use to map to the data * * @var object */ protected $model; /** * Constructor * * @param object $model * @throws InvalidArgumentException */ public function __construct($model=null) { if (is_null($model) || empty($model)) { throw new InvalidArgumentException('Invalid Mapper'); } $this->model = $model; } /** * Get an item by its ID * * @param $id * @param array $columns * @return mixed */ public function getById($id, $columns = ['*']) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid id'); } return $this->model->notDeleted()->find($id, $columns); } /** * Get an item identified a given attribute * * @param $attribute * @param $value * @param array $columns * @return mixed */ public function getBy($attribute=null, $value=null, $columns=['*']) { if (is_null($attribute) || empty($attribute)) { throw new InvalidArgumentException('Invalid attribute: '.$attribute); } return $this->model->notDeleted()->where($attribute, '=', $value)->first($columns); } /** * Return a collection of all saved items * * @param array $columns */ public function getAll($columns=['*']) { return $this->model->notDeleted()->get($columns); } /** * Get all items identified a given attribute * * @param $attribute * @param $value * @param array $columns * @return mixed */ public function getAllBy($attribute=null, $value=null, $columns=['*']) { if (is_null($attribute) || empty($attribute)) { throw new InvalidArgumentException('Invalid attribute: '.$attribute); } return $this->model->notDeleted()->where($attribute, '=', $value)->get($columns); } /** * Get all paginated items * * @param int $perPage * @param array $columns * @return mixed */ public function getPaginate($perPage=15, $columns=['*']) { $perPage = intval($perPage); if ($perPage==0) { throw new InvalidArgumentException('Invalid value per page'); } return $this->model->notDeleted()->paginate($perPage, $columns); } /** * Create a new item * * @param array $data * @throws InvalidArgumentException * @return Authentication\Mappers\Eloquent saved object */ public function create(array $data=[]) { return $this->model->create($data); } /** * Update an existing item * * @param array $data * @param integer $id * @param string $attribute * @throws RuntimeException * @throws InvalidArgumentException * @return Eloquent saved object */ public function update(array $data=[], $id=null, $attribute="id") { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $model = $this->model->where('id', $id)->first(); if (is_null($model) || !$model->exists) { throw new InvalidArgumentException('Item not found'); } try { $update = $model->where($attribute, '=', $id)->update($data); } catch(Exception $e) { throw new RuntimeException($e->getMessage(), $e); } if ($update===false) { throw new RuntimeException('Could not save the item'); } return $update; } /** * Delete an item identified by a given id * * @param integer $id * @throws RuntimeException * @throws InvalidArgumentException * @throws RuntimeException */ public function delete($id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $model = $this->model->where('id', $id)->first(); if (is_null($model) || !$model->exists) { throw new InvalidArgumentException('Item not found'); } try { $delete = $model->delete(); } catch(Exception $e) { throw new RuntimeException($e->getMessage(), $e); } if (!$delete) { throw new RuntimeException('Could not delete the item'); } return $model; } /** * Restore an item identified by a given id * * @param integer $id * @throws InvalidArgumentException * @throws RuntimeException */ public function restore($id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $model = $this->model->withTrashed()->where('id', $id)->first(); if (is_null($model) || !$model->exists) { throw new InvalidArgumentException('Item not found'); } try { $restore = $model->restore(); } catch(Exception $e) { throw new RuntimeException($e->getMessage(), $e); } if (!$restore) { throw new RuntimeException('Could not restore the item'); } return $restore; } /** * Handle dynamic getBy call * * @param string $method * @param array $parameters * @return mixed * @throws \BadMethodCallException */ public function __call($method, $parameters) { if (Str::startsWith($method, 'getBy')) { $attribute = str_replace('getBy', '', $method); $model = $this->model; if ($model::$snakeAttributes) { $attribute = Str::snake($attribute); } array_unshift($parameters, $attribute); return call_user_func_array([$this, 'getBy'], $parameters); } elseif (Str::startsWith($method, 'getAllBy')) { $attribute = str_replace('getAllBy', '', $method); $model = $this->model; if ($model::$snakeAttributes) { $attribute = Str::snake($attribute); } array_unshift($parameters, $attribute); return call_user_func_array([$this, 'getAllBy'], $parameters); } throw new \BadMethodCallException('Invalid method: '.$method); } } /*********************************************************************** * Using the decorator pattern whe can make a cached implementation of this */ <?php namespace App\Repositories; use \RuntimeException; use \InvalidArgumentException; use App\CacheRepository; use Illuminate\Support\Facades\App; abstract class Cache implements Repository { /** * Repository * * @var $repository */ protected $repository; /** * Cache interface * * @var Cache */ protected $cache; /** * Constructor * * @param Repository Repository * @param Cache $cache * @throws InvalidArgumentException */ public function __construct(Repository $repository=null, CacheRepository $cache=null) { if (is_null($repository) || empty($repository)) { throw new InvalidArgumentException('Invalid repository'); } $this->repository = $repository; $this->cache = $cache; } /** * Get an item by its ID * * @param string $id * @throws InvalidArgumentException * @return mixed Eloquent object found or null if not found */ public function getById($id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid id'); } $this->cache->setKey($this, __FUNCTION__, func_get_args()); return $this->cache->get(function() use ($id) { return $this->repository->getById($id); }); } /** * Get an item identified a given attribute * * @param $attribute * @param $value * @param array $columns * @return mixed */ public function getBy($attribute=null, $value=null, $columns=['*']) { if (is_null($attribute) || empty($attribute)) { throw new InvalidArgumentException('Invalid attribute: '.$attribute); } $this->cache->setKey($this, __FUNCTION__, func_get_args()); return $this->cache->get(function() use ($attribute, $value, $columns) { return $this->repository->getBy($attribute, $value, $columns); }); } /** * Return a collection of all saved items * * @return Illuminate\Support\Collection */ public function getAll() { $this->cache->setKey($this, __FUNCTION__, func_get_args()); return $this->cache->get(function() { return $this->repository->getAll(); }); } /** * Get all items identified a given attribute * * @param $attribute * @param $value * @param array $columns * @return mixed */ public function getAllBy($attribute=null, $value=null, $columns=['*']) { if (is_null($attribute) || empty($attribute)) { throw new InvalidArgumentException('Invalid attribute: '.$attribute); } $this->cache->setKey($this, __FUNCTION__, func_get_args()); return $this->cache->get(function() use ($attribute, $value, $columns) { return $this->repository->getAllBy($attribute, $value, $columns); }); } /** * Create a new item * * @param array $data * @throws InvalidArgumentException * @return Eloquent saved object */ public function create(array $data=Array()) { $this->cache->flush(); return $this->repository->create($data); } /** * Update an existing item * * @param array $data * @param integer $id * @throws RuntimeException * @throws InvalidArgumentException * @return Authentication\Mappers\Eloquent saved object */ public function update(array $data=Array(), $id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $update = $this->repository->update($data, $id); $this->cache->flush(); return $update; } /** * Delete an item identified by a given id * * @param integer $id * @throws RuntimeException * @throws InvalidArgumentException * @throws RuntimeException */ public function delete($id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $delete = $this->repository->delete($id); $this->cache->flush(); return $delete; } /** * Restore an item identified by a given id * * @param integer $id * @throws InvalidArgumentException * @throws RuntimeException */ public function restore($id=null) { if (is_null($id) || empty($id)) { throw new InvalidArgumentException('Invalid ID'); } $restore = $this->repository->restore($id); $this->cache->flush(); } } /*********************************************************************** * Cache for repository */ <?php namespace App\Repositories; use \RuntimeException; use \InvalidArgumentException; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Config; use Illuminate\Support\Str; class CacheRepository { private $minutes = 10; private $key; private $enable = true; public function __construct() { if (Config::get('app.debug')) { $this->disable(); } } public function isEnable() { return $this->enable; } /** * Enable cache */ public function enable() { $this->enable = true; } /** * Disable cache */ public function disable() { $this->enable = false; } /** * Cache expiration * * @param integer $minutes * @throws InvalidArgumentException */ public function setExpire($minutes=null) { $minutes = intval($minutes); if (is_null($minutes) || $minutes<=0) throw new InvalidArgumentException('Invalid expiration delay'); $this->minutes = $minutes; } /** * Set the current key based on arguments * * @param object $object * @param string $method * @param array $arguments * @throws InvalidArgumentException */ public function setKey($object=null, $method=null, $arguments=Array()) { if (is_null($object) || is_null($method)) throw new InvalidArgumentException('Invalid class/method name'); if (!is_object($object)) throw new InvalidArgumentException('Invalid class'); if (!is_array($arguments)) $arguments = Array(); $this->key = Str::slug(str_replace('\\', '-', get_class($object)).' '.$method.' '.implode(' ', $arguments)); return $this->key; } public function has($key=null) { if (is_null($key)) throw new RuntimeException('Wrong cache key'); return (Cache::has($key))?true:false; } public function getByKey($key=null) { if (is_null($key)) throw new RuntimeException('Wrong cache key'); if ($this->has($this->key)) return Cache::get($this->key); return null; } public function putByKey($key=null, $data=null) { Cache::put($key, $data, $this->minutes); } /** * Get the cached values or generate it using the callback * * @param Closure $callback * @throws RuntimeException * @throws InvalidArgumentException * @return mixed */ public function get($callback) { if (is_null($this->key)) throw new RuntimeException('Wrong cache key'); if (!$this->enable) { if (!is_callable($callback)) throw new InvalidArgumentException('The callback must be callable'); return call_user_func($callback); } if ($this->has($this->key)) return $this->getByKey($this->key); if (!is_callable($callback)) throw new InvalidArgumentException('The callback must be callable'); $result = call_user_func($callback); $this->putByKey($this->key, $result); $this->key = null; return $result; } /** * Flush all the cached item */ public function flush() { if (!$this->enable) return; Cache::flush(); } }