使用 View Presenter 模式管理自定义属性
在 Laravel 视图中,经常要使用到一些格式化的属性,例如将姓名的首字母大写后显示
{{ ucwords($user->name) }}
解决方案就是使用 Laravel 提供的访问器来自定义属性格式
<?php
public function getNameAttribute($value){
return ucwords($value);
}
这样做有两个不足之处,一个是会覆盖原始属性,如果要获取原有属性,就需要使用专门的方法
$user->getOriginal('name');
另外一个不足之处在于,将姓名的首字母格式化只是对外显示的时候使用,并不是在所有场景中都需要用到。
我们从单一职责的角度出发,可以将需要格式化显示的属性用专门的类来管理,我们称之为 Presenter
类。
定义专门的 UserPresenter
类
<?php
namespace App\Presenter;
use Illuminate\Database\Eloquent\Model;
class UserPresenter
{
protected $model;
/**
* PostPresenter constructor.
*
* @param $model
*/
public function __construct(Model $model)
{
$this->model = $model;
}
public function createdAt()
{
return $this->model->created_at->format('Y-m-d');
}
public function name()
{
return ucwords($this->model->name)
}
public function __get($property)
{
if(method_exists($this, $property)){
return $this->$property();
}
return $this->model->getAttribute($property);
}
}
将 UserPresenter
绑定到对应的模型中
<?php
class User {
protected $presenterInstance;
protected $presenter = UserPresenter::class;
public function presenter()
{
if(! $this->presenterInstance){
$this->presenterInstance = new $this->presenter($this);
}
return $this->presenterInstance;
}
}
使用
<?php
$user->presenter->name();
// 使用动态属性访问
$user->presenter->name;
$user->presenter->created_at;
// 当对应方法不存在时,自动获取对应模型的属性
$user->presenter->email;
最后,封装代码,让所有 Presenter 类继承一个基类
<?php
namespace App\Presenter;
use Illuminate\Database\Eloquent\Model;
abstract class AbstractPresenter
{
protected $model;
/**
* PostPresenter constructor.
*
* @param $model
*/
public function __construct(Model $model)
{
$this->model = $model;
}
public function __get($property)
{
if(method_exists($this, $property)){
return $this->$property();
}
return $this->model->getAttribute($property);
}
}
定义对应模型使用的 Trait
<?php
namespace App\Presenter;
trait Presenterable
{
protected $presenterInstance;
public function presenter()
{
if(! $this->presenterInstance){
$this->presenterInstance = new $this->presenter($this);
}
return $this->presenterInstance;
}
}
使用
<?php
namespace App\Presenter;
class UserPresenter extends AbstractPresenter
{
public function createdAt()
{
return $this->model->created_at->format('Y-m-d');
}
public function name()
{
return ucwords($this->model->name);
}
}
<?php
use App\Presenter\Presenterable;
use App\Presenter\UserPresenter;
class User {
use Presenterable;
protected $presenter = UserPresenter::class;
}