Skip to content

Instantly share code, notes, and snippets.

@Ellrion
Last active September 23, 2021 00:02
Show Gist options
  • Save Ellrion/02ca1afe1ea45f1177a47260dac5621d to your computer and use it in GitHub Desktop.
Save Ellrion/02ca1afe1ea45f1177a47260dac5621d to your computer and use it in GitHub Desktop.
Презентеры в Laravel.
<?php
namespace App\Presenters;
abstract class AbstractPresenter
{
/**
* The resource that is the object that was decorated.
*
* @var mixed
*/
protected $entity;
/**
* @param $entity
*/
public function __construct($entity)
{
$this->entity = $entity;
}
/**
* Allow for property-style retrieval
*
* @param $property
* @return mixed
*/
public function __get($property)
{
if ($this->presentationMethodExists($property)) {
$method = $this->getPresentationMethod($property);
return $this->{$method}();
}
return $this->entity->{$property};
}
/**
* Detect if property exists.
*
* @param $property
* @return bool
*/
public function __isset($property)
{
return $this->presentationMethodExists($property) || isset($this->entity->{$property});
}
/**
* Allow for methods-style retrieval
*
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
if ($this->presentationMethodExists($name)) {
$method = $this->getPresentationMethod($name);
return $this->{$method}(...$arguments);
}
return call_user_func_array([$this->entity, $name], $arguments);
}
/**
* Determines presentation method exists.
*
* @param $property
* @return bool
*/
protected function presentationMethodExists($property)
{
return method_exists($this, $this->getPresentationMethod($property));
}
/**
* Getter for name of presentation method for property.
*
* @param $property
* @return string
*/
protected function getPresentationMethod($property)
{
return 'present' . studly_case($property);
}
}
<?php
namespace App\Presenters;
use App\Exceptions\PresenterNotFoundException;
trait Presentable
{
/**
* View presenter instance
*
* @var AbstractPresenter
*/
protected $presenterInstance;
/**
* Default presenters namespace.
*
* @var string
*/
protected $presentersNamespace = 'App\\Presenters\\';
/**
* Prepare a new or cached presenter instance
*
* @throws PresenterNotFoundException
* @return AbstractPresenter
*/
public function present()
{
$presenter_class_name = $this->presenter ?? $this->presentersNamespace . class_basename($this) . 'Presenter';
if (!class_exists($presenter_class_name, true)) {
throw new PresenterNotFoundException($presenter_class_name);
}
if (!$this->presenterInstance) {
$this->presenterInstance = new $presenter_class_name($this);
}
return $this->presenterInstance;
}
}
<?php
namespace App\Exceptions;
use Exception;
class PresenterNotFoundException extends Exception
{
/**
* Create a new presenter not found exception.
*
* @param string $class
* @param string|null $message
* @param int $code
* @param Exception $previous
*/
public function __construct($class, $message = null, $code = 0, Exception $previous = null)
{
if (!$message) {
$message = $class.' not found. Please set the $presenter property to your presenter path.';
}
parent::__construct($message, $code, $previous);
}
}
@Ellrion
Copy link
Author

Ellrion commented Sep 14, 2016

Использование

Теперь представим что у нас есть модель app/Models/User.php

<?php

namespace App\Models;

use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Model;

class User extend Mode implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContractl
{
    use Presentable;
    // Тут еще много всего еще трейты, всякие $fillable\$casts и т. п. скоупы, связи, методы бизнесслогики...
}

и есть презентер app/Presenters/UserPresenter.php (кусок почти реального презентора)

<?php

namespace App\Presenters;

use Illuminate\Support\HtmlString;

class UserPresenter extends AbstractPresenter
{
    public function presentName()
    {
        return empty($this->entity->name) ? $this->entity->login : $this->entity->name;
    }

    public function presentStatus()
    {
        return $this->entity->is_active ? 'активен' : 'заблокирован';
    }

    public function presentLang()
    {
        $lang_labels = ['en' => 'English', 'ru' => 'Русский'];

        return array_get($lang_labels, $this->entity->lang, $this->entity->lang);
    }

    public function presentAvatarBaseUrl()
    {
        return 'https://www.gravatar.com/avatar/' . md5($this->entity->email);
    }

    public function presentAvatarMin()
    {
        $size = 48;
        $html = <<<HTML
<img src="{$this->avatar_base_url}?s={$size}&d=mm" alt="" class="uk-border-circle" height="{$size}" width="{$size}">
HTML;
        return new HtmlString($html);
    }
}

ну и где то во вьюхе (наверняка в очень многих разных местах а можно и не во вьюхе)

{{ $user->present()->avatar_min }} {{ $user->present()->name }}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment