Created
January 27, 2017 10:12
-
-
Save jarektkaczyk/1d38b3af8c3f60cbd6dec74c3be46371 to your computer and use it in GitHub Desktop.
presenter for eloquent
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\Presenters; | |
use ArrayAccess; | |
use Illuminate\Support\Collection; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Contracts\Pagination\Paginator; | |
class Decorator | |
{ | |
/** @var string[] Namepsaces checked for proprietary presenters */ | |
protected $proprietary_namespaces = ['App\\Presenters\\']; | |
/** @var string Generic presenter, that will be used if no proprietary presenter is found */ | |
protected $generic_presenter = Presenter::class; | |
/** | |
* Set generic presenter class. | |
* | |
* @param string $class | |
*/ | |
public function setGenericPresenter($class) | |
{ | |
$this->generic_presenter = $class; | |
} | |
/** | |
* Add namespace for proprietary presenter lookup. | |
* | |
* @param string $namespace | |
*/ | |
public function addNamespace($namespace) | |
{ | |
array_unshift($this->proprietary_namespaces, $namespace); | |
} | |
/** | |
* Decorate model with presenter class. | |
* | |
* @param \Illuminate\Database\Eloquent\Model $model | |
* @return \App\Presenters\Presenter | |
*/ | |
public function decorate($model) | |
{ | |
if ($model instanceof Collection || is_array($model) || $model instanceof Paginator) { | |
return $this->decorateMany($model); | |
} | |
if (!$model instanceof Presentable) { | |
return $model; | |
} | |
$presenter = $this->generic_presenter; | |
foreach ($this->proprietary_namespaces as $ns) { | |
if (class_exists($proprietary = $ns.class_basename($model))) { | |
$presenter = $proprietary; | |
break; | |
} | |
} | |
return new $presenter($model, $this); | |
} | |
public function decorateMany($models) | |
{ | |
foreach ($models as $key => $model) { | |
if ($model instanceof Presentable) { | |
$models[$key] = $this->decorate($model); | |
} | |
} | |
return $models; | |
} | |
} |
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\Presenters; | |
use Illuminate\Database\Eloquent\Model; | |
use App\Traits\TranslatableFields; | |
class LanguageAwarePresenter extends Presenter | |
{ | |
public function present($key) | |
{ | |
$value = in_array(TranslatableFields::class, class_uses_recursive(get_class($this->model))) | |
? $this->translate($key) | |
: $this->model->{$key}; | |
return ($method = $this->getMethod($key)) ? $this->{$method}($value) : $value; | |
} | |
protected function translate($key) | |
{ | |
return $this->model->getTranslation($key); | |
} | |
} |
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\Presenters; | |
interface Presentable | |
{ | |
// | |
} |
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\Presenters; | |
use Illuminate\Support\Str; | |
use Illuminate\Support\Collection; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Contracts\Routing\UrlRoutable; | |
class Presenter implements UrlRoutable | |
{ | |
protected $model; | |
protected $decorator; | |
public function __construct(Model $model, Decorator $decorator) | |
{ | |
$this->model = $model; | |
$this->decorator = $decorator; | |
} | |
public function getModel() | |
{ | |
return $this->model; | |
} | |
public function __get($key) | |
{ | |
$value = $this->model->{$key}; | |
if ($value instanceof Model || $value instanceof Collection || is_array($value)) { | |
return $this->decorator->decorate($this->model->{$key}); | |
} | |
return $this->present($key); | |
} | |
protected function present($key) | |
{ | |
return ($method = $this->getMethod($key)) | |
? $this->{$method}($this->model->{$key}) | |
: $this->model->{$key}; | |
} | |
protected function getMethod($key) | |
{ | |
if (method_exists($this, $method = $key) | |
|| method_exists($this, $method = Str::snake($key)) | |
|| method_exists($this, $method = Str::camel($key)) | |
) { | |
return $method; | |
} | |
} | |
public function __call($method, $params) | |
{ | |
return call_user_func_array([$this->model, $method], $params); | |
} | |
public function __isset($key) | |
{ | |
return $this->model->__isset($key); | |
} | |
public function toArray() | |
{ | |
$attributes = collect($this->model->toArray()); | |
return $attributes->map(function ($_, $key) { | |
return $this->present($key); | |
})->all(); | |
} | |
public function __toString() | |
{ | |
return json_encode($this->toArray()); | |
} | |
/** | |
* Get the value of the model's route key. | |
* | |
* @return mixed | |
*/ | |
public function getRouteKey() | |
{ | |
return $this->model->getRouteKey(); | |
} | |
/** | |
* Get the route key for the model. | |
* | |
* @return string | |
*/ | |
public function getRouteKeyName() | |
{ | |
return $this->model->getRouteKeyName(); | |
} | |
} |
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\Providers; | |
use App\Presenters\Decorator; | |
use App\Presenters\Presenter; | |
use Illuminate\Contracts\View\Factory; | |
use Illuminate\Support\ServiceProvider; | |
/** | |
* This Provider registers a View Composer that will automatically | |
* decorate Presentable models with appropriate Presenter class. | |
*/ | |
class PresentersServiceProvider extends ServiceProvider | |
{ | |
public function boot(Factory $view) | |
{ | |
$view->composer('*', function ($view) { | |
$data = array_merge($view->getFactory()->getShared(), $view->getData()); | |
foreach ($data as $var => $model) { | |
$view[$var] = $this->app['presenters']->decorate($model); | |
} | |
}, 999); | |
} | |
public function register() | |
{ | |
$this->app->singleton('presenters', function () { | |
return new Decorator; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment