使用 PHP Traits 来封装 Laravel Eloquent 关联关系

file

我最近在重构某个项目的代码,然后我发现自己在 Eloquent 模型上为了定义 Account 类的关联关系而在写同样的方法。另外仅供参考,我更偏向于使用 getters 和 setters 而不是直接访问魔术属性。

所以接下来我用一个 Post 模型来做演示,它看起来如下:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

/**
 * Class Post
 *
 * @package App
 */
class Post extends Model
{
    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->getAttribute('title');
    }

    /**
     * @param string $title
     * @return $this
     */
    public function setTitle(string $title)
    {
        $this->setAttribute('title', $title);

        return $this;
    }

    /**
     * @return string
     */
    public function getPost()
    {
        return $this->getAttribute('post');
    }

    /**
     * @param string $post
     * @return $this
     */
    public function setPost(string $post)
    {
        $this->setAttribute('post', $post);

        return $this;
    }

    /**
     * @param Account $account
     * @return $this
     */
    public function setAccount(Account $account)
    {
        $this->account()->associate($account);

        return $this;
    }

    /**
     * @return Account|null;
     */
    public function getAccount()
    {
        return $this->getAttribute('account');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function account()
    {
        return $this->belongsTo(Account::class, 'account_id', 'id');
    }
}

我们定义了一些方法,一部分是为了 Post 属性,另一部分是为了关联关系。

现在,当我们再添加一个与 Account 有关联关系的模型时,我们又要添加同样的关联方法。这很费时间,而且如果你想修改这些方法,你还需要在所有有关联关系的模型上修改相应方法。

使用 Traits

Trait 的定义:

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

这就是使用 traits 的完美理由。我们创建一个名为 HasAccountTrait 的 Trait,它将保存所有属于一个 account 的关系的所有方法:

<?php

namespace App;

/**
 * Class HasAccountTrait
 *
 * @package App
 */
trait HasAccountTrait
{
    /**
     * @param Account $account
     * @return $this
     */
    public function setAccount(Account $account)
    {
        $this->account()->associate($account);

        return $this;
    }

    /**
     * @return Account|null;
     */
    public function getAccount()
    {
        return $this->getAttribute('account');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function account()
    {
        return $this->belongsTo(Account::class, 'account_id', 'id');
    }
}

然后我们使用 Trait 来重新整理一下上面的 Post 模型代码,所以它看起来像下面这样:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

/**
 * Class Post
 *
 * @package App
 */
class Post extends Model
{
    use HasAccountTrait;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->getAttribute('title');
    }

    /**
     * @param string $title
     * @return $this
     */
    public function setTitle(string $title)
    {
        $this->setAttribute('title', $title);

        return $this;
    }

    /**
     * @return string
     */
    public function getPost()
    {
        return $this->getAttribute('post');
    }

    /**
     * @param string $post
     * @return $this
     */
    public function setPost(string $post)
    {
        $this->setAttribute('post', $post);

        return $this;
    }
}

总结

使用 traits 意味着在定义同一个模型的关联关系时写出不重复的代码。它还可以加速开发,这取决于应用程序中有多少关联关系。


Practice makes perfect.

原文地址:https://medium.com/@tomgrohl/using-php-t...

译文地址:https://learnku.com/laravel/t/22682

本帖已被设为精华帖!
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 3

父类和当前类 trait 重名的时候,嘿嘿

4个月前 评论

@HI 那就给当前类的trait取一个别名,搞定

4个月前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

社区文档:

将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
GitHub Laravel 扩展包 TOP 250
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
浓缩过后的精华
Laravel Nova 后台管理面板文档的中文翻译
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会