如何在 Laravel 中灵活的使用 Trait

 Laravel3个月前/  1740 /  4 / 更新于 3个月前

 

@这是小豪的第九篇文章

好久没有更新文章了,说好了周更结果还是被自己对时间的安排打败了。。。。

今天给大家介绍的是在 Laravel 中如何灵活的使用 Trait,说起 Trait ,我一开始不知道是什么样的存在,有个模糊的印象是:复用。一直以来对复用的理解和使用就是:写在一个公共类中,哪里需要哪里调用,目的就是少写些代码,哈哈。

废话不多说,现在开始。

 

前言

大家可能经常看到以下几种情况:

class Post extends Model
{
protected static function boot()
{
parent::boot(); static::saving(function ($post){
$post->creator_id = $post->creator_id ?? \auth()->id();
});
}
} // 或者 class Video extends Model
{
protected static function boot()
{
parent::boot(); static::saving(function ($post){
$post->creator_id = $post->creator_id ?? \auth()->id();
});
}
} // 或者直接在控制器中指定 creator_id

可以看到,这些代码明显是重复的,可是到底怎么分离出去达到复用的效果呢。

这样?

public function hasCreator($model)
{
$model->creator_id = $model->creator_id ?? \auth()->id();
} // 封装一个上述公共方法,然后在模型中调用,或者在控制器中调用。

从上面的示例中发现这些操作都不是很好,不够优雅,哈哈。现在我们来看看 laravel 中 Trait 是如何定义和使用的:

// 定义

trait HasCreator
{
public static function bootHasCreator()
{
static::saving(function ($model) {
$model->creator_id = $model->creator_id ?? \auth()->id();
});
}
} // 调用
class Post extends Model
{
use HasCreator;
} // 可以了,哈哈,自动调用已经可以实现对 creator_id 的自动写入了,是不是很优雅,哈哈。

现在一步步的来解释一下是怎么写的。

 

开始

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

  1. 首先我们得知道如何定义一个 Trait, 使用的关键字是 trait 而不是 class

    namespace App\Traits;
    
    trait HasCreator
    {
    }
  2. 定义方法(我们先从简单的来)

    namespace App\Traits;
    
    trait HasCreator
    {
    public static function hasCreator()
    {
    static::saving(function ($model) {
    $model->creator_id = $model->creator_id ?? 1;
    });
    }
    }

    可以看到在 Trait 中声明了一个 setCreator 方法,里面里面依旧是对 creator 设置默认值

  3. 调用

    namespace App;
    
    use App\Traits\HasCreator;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\SoftDeletes; class Post extends Model
    {
    use HasCreator, SoftDeletes; protected $fillable = ['title', 'user_id']; protected static function boot()
    {
    parent::boot(); self::hasCreator();
    }
    }

    用我的理解来说就是将 Trait 中的方法合并到 模型中去了,要想使用就 use 一下,然后当自己声明的一样去调用就好了。

大家可以看到上面的例子中还 use 了 SoftDeletes , 我们来简单的看一下它的源码:

namespace Illuminate\Database\Eloquent;

trait SoftDeletes
{
/**
* Indicates if the model is currently force deleting.
*
* @var bool
*/
protected $forceDeleting = false; /**
* Boot the soft deleting trait for a model.
*
* @return void
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
} /**
* Force a hard delete on a soft deleted model.
*
* @return bool|null
*/
public function forceDelete()
{
$this->forceDeleting = true; return tap($this->delete(), function ($deleted) {
$this->forceDeleting = false; if ($deleted) {
$this->fireModelEvent('forceDeleted', false);
}
});
} ......
}

从展示的源码中我们可以看到,当前 Trait 定义了一个属性、两个方法,居然还可以定义属性,是不是很意外,哈哈。

大家可能会问,要是 Task 中也定义了 $forceDeleting 属性怎么办,哪个为主呢,这里面其实有个优先级的:调用类 >Trait > 父类,也就是说当 Trait 中出现于调用类重复的属性和方法的时候,默认是以调用类为主的。

接下来我们来看下面两个方法:

bootSoftDeletes:静态、前缀加了 boot, 这表示啥呢?表示默认执行的操作,哈哈。

既然可以定义为自动调用,我们是不是把上面的 HasCreator 改一下呢:

    namespace App\Traits;

    trait HasCreator
{
public static function hasCreator() // -> 改为 bootHasCreator
{
static::saving(function ($model) {
$model->creator_id = $model->creator_id ?? 1;
});
}
}

已经自动调用了,那么:

namespace App;

use App\Traits\HasCreator;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; class Post extends Model
{
use HasCreator, SoftDeletes; protected $fillable = ['title', 'user_id'];
}

这样就可以啦!

后面的那个方法和之前的 hasCreator 是一样的,当作自身的方法调用就好啦,是否声明为静态就看自己的需要了。

下面给大家推荐一些在项目中用得到的 Trait,都是从超哥那里摘下来的,哈哈。

 

小案例

 

HasCreator

指定创建者

namespace App\Traits;

use App\User;

/**
* Trait HasCreator.
*
* @property \App\User $creator
*/
trait HasCreator
{
public static function bootHasCreator()
{
static::saving(function ($model) {
$model->creator_id = $model->creator_id ?? \auth()->id();
});
} /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function creator()
{
return $this->belongsTo(User::class, 'creator_id')->withTrashed();
} /**
* @param \App\User|int $user
*
* @return bool
*/
public function isCreatedBy($user)
{
if ($user instanceof User) {
$user = $user->id;
} return $this->creator_id == \intval($user);
}
}

Trait 中定义了三个方法,现在给大家简单的解释一哈:

  1. bootHasCreator:默认给定当前认证用户。至于下面的 static::saving 不明白的,可以看之前的文章哒。
  2. creator:定义模型关联
  3. isCreatedBy:判断传入的用户是否为当前创建者
 

BelongsToUser

指定用户

namespace App\Traits;

use App\User;

/**
* Trait BelongsToUser.
*
* @property \App\User $user
*/
trait BelongsToUser
{
public static function bootBelongsToUser()
{
static::creating(function ($model) {
if (!$model->user_id) {
$model->user_id = \auth()->id();
}
});
} /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class)->withTrashed();
} /**
* @param \App\User|int $user
*
* @return bool
*/
public function isOwnedBy($user)
{
if ($user instanceof User) {
$user = $user->id;
} return $this->user_id == \intval($user);
}
}

我就不解释啦,和上面的是差不多的,大家看看就明白了。

 

结束语

就简单的给大家介绍一下 Trait 在 Laravel 中如何使用的,写的不对的地方和补充欢迎大家留言噢,哈哈。

相关链接: 《我所理解的 PHP Trait》 ( 对 Trait 更深层次的讲解 -- 超哥出品,哈哈)、 《掌握 PHP Trait 的概念和用法》

如何在 Laravel 中灵活的使用 Trait的更多相关文章

  1. 详解如何在Laravel中增加自定义全局函数

    http://www.php.cn/php-weizijiaocheng-383928.html 如何在Laravel中增加自定义全局函数?在我们的应用里经常会有一些全局都可能会用的函数,我们应该怎么 ...

  2. 【社交系统研发日记】如何在 Laravel 中 “规范” 的开发验证码发送功能

    顺便发个小通知:7月15日ThinkSNS+开源版发布,同时非开源的APP也走出内测阶段,体验二维码也全面发布体验. 什么是ThinkSNS ? ThinkSNS(简称TS),一款全平台综合性社交系统 ...

  3. 如何在 Laravel 中 “规范” 的开发验证码发送功能

    什么是ThinkSNS ? ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+(简称TS+).Thin ...

  4. 如何在 Laravel 中使用 SMTP 发送邮件(适用于 163、QQ、Gmail 等)

    Laravel  和 Laravel  的邮件发送使用方式完全一致.Laravel  的邮件发送中文文档在:http: 邮箱为例,展示如何用 Laravel 内置的邮件发送类来发送邮件. 配置 修改邮 ...

  5. 如何在 Laravel 中连接多个 MySQL 数据库

    第一步.定义数据库链接 config/database.php <?php return [ 'default' => 'mysql', 'connections' => [ # 主 ...

  6. Laravel 中使用支付宝、银联支付、微信支付进行支付

    Laravel Packages 为 Laravel 提供了强大的扩展功能,为从 1 到 n 提供无限可能,这其中就包括支付, Laravel 官方提供的 Cashier 包集成对 Stripe 的支 ...

  7. laravel中如何执行请求

    laravel中如何执行request请求?本篇文章给大家介绍关于laravel中执行请求的方法,需要的朋友可以参考一下,希望对你有所帮助. 我们先来看一下request是什么? 客户端(例如Web浏 ...

  8. Laravel 中使用 Repository 模式

    在本文中,我会向你展示如何在 Laravel 中从头开始实现 repository 设计模式.我将使用 Laravel 5.8.3 版,但 Laravel 版本不是最重要的.在开始写代码之前,你需要了 ...

  9. [Laravel-Swagger]如何在 Laravel 项目中使用 Swagger

    如何在 Laravel 项目中使用 Swagger http://swagger.io/getting-started/ 安装依赖 swagger-php composer require zirco ...

随机推荐

  1. 星舟平台的使用(GIT、spring Boot 的使用以及swagger组件的使用)

    一.介绍星舟平台     1.星舟简介     2.网关kong的介绍     3.客户端         1).服务注册:Eureka         2).客户端负载均衡:Ribbon     4 ...

  2. kubernetes kubeadm安装v1.14

    1.我们这里准备两台Centos7的主机用于安装,后续节点可以根究需要添加即可:master node01两台都得改:cat /etc/hosts192.168.71.134 master192.16 ...

  3. MySQL SELECT语法(四)UNION语法详解

    源自MySQL 5.7 官方手册:13.2.9.3 UNION Syntax 一.UNION语法 UNION用于将多个SELECT语句的结果合并到一个结果集中. SELECT ... UNION [A ...

  4. 怎样写一个 "Hello, World!"

    第一步: 打开浏览器, 按 F12 键或 Ctrl + Shift + J.   注意:  1. 打开的这个界面是浏览器的开发者工具界面. 2. 顶部有许多Tab栏, 如: Elements / Co ...

  5. JVM描述符标识字符含义

    标识字符 含义 B byte C char D double F float I int J long S short Z boolean V void L 对象类型,如Ljava/lang/Obje ...

  6. HTTP协议探究(一):缓存

    一 复习与目标 1 复习 序章主要用WrieShark抓包HTTP报文 复习了TCP协议 讲述了TCP协议与HTTP之间的关系 HTTP1.1更新原因:HTTP1.0一次TCP连接只能发送一次HTTP ...

  7. MQTT图形化客户端比较

    1 MQTT.fx (1)协议支持 TCP(tcp) TLS(tls) (2)特点 界面美观,操作便捷 不支持WebSocket协议 基于java开发 支持代理 通过Nashorn Engine的JS ...

  8. Visual Studio container tools require Docker to be running

    处理项目在生成时报错"Visual Studio container tools require Docker to be running" 最初win10上安装docker,项目 ...

  9. Install CUDA 6.0 on Ubuntu 14.04 LTS

    Ubuntu 14.04 LTS is out, loads of new features have been added. Here are some procedures I followed ...

  10. 最简单的一个win32程序

    #include <windows.h> HINSTANCE g_hInst = NULL; //2 窗口处理函数 LRESULT CALLBACK WndProc( HWND hWnd, ...