如何在 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. (一)使用 mybatis 的缘由

    目录 传统代码操作数据库的存在的问题 mybatis 的解决之道 传统代码操作数据库的存在的问题 数据库连接,在使用数据库时,创建数据库连接,在不用的时候,就会立即释放掉连接:这样当下次使用的又会创建 ...

  2. hdu 1029 求出现次数过半的数

    题目传送门//res tp hdu 已知必定存在一个元素出现次数超过一半,考虑用栈 若当前元素等于栈顶元素,入栈,反之出栈,并将当前元素入栈 最终的栈顶元素即是所求 #include<iostr ...

  3. springcloud注解

    @EnableEurekaServer:启动一个服务注册中心提供给其他应用进行对话 @EnableZuulProxy:开启网关; @FeignClient:发现服务 @EnableFeignClien ...

  4. go语言操作kafka

    go语言操作kafka Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据,具有高性能.持久化.多副本备份.横向扩展等特点.本文介绍了如何使用Go语言发送和 ...

  5. MySQL 聚合函数(四)检测功能依赖

    源自MySQL 5.7 官方手册:12.20.4 Detection of Functional Dependence 本节提供了MySQL检测功能依赖的方式的几个示例.这些示例使用此表示法: {X} ...

  6. oracle_多表查询02

    多表查询 select * from BONUS; select * from DEPT; select * from EMP; select * from SALGRADE; BONUS表 ENAM ...

  7. java方法可变参数研究

    1 问题引出 (1)缘由 最近在研究如何在项目中引入Redis缓存,于是遇到可变参数这个疑惑点,之前没有好好研究过,为了避免项目后期出现问题. (2)项目相关技术 SpringBoot Redis K ...

  8. C#picturebox控件图片以json格式上传java后台保存

    关于winform上传图片到Java后端,保存到数据库,有多种方法,本文主要介绍利用picturebox控件,点击按钮上传图片,将图片转化为base64格式,以json格式上传到Java后台,再从ja ...

  9. ThreadPoolExecutor的runState和workCount变量怎么存储?

    在阅读Java线程池ThreadPoolExecutor源码的时候,发现它很巧妙地把线程池状态runState和线程数workCount两个变量存放在了一个int型变量里面. 我们先看一个数值,如下是 ...

  10. Objective-C 之Extension

    Objective-C 之Extension class extension:类扩展 类扩展与 category 有相似性,但在编译时它只能被添加到已有源代码的一类中(该类扩展和该类同时被编译). 在 ...