zoukankan      html  css  js  c++  java
  • Laravel 在哪些地方使用了 trait ?

    laravel 框架大量使用了traits. 简单举几个例子:

    在Eloquent中使用了trait 。然后在model初始化的时候,有个boot方法,会自动判断当前的类用了哪些trait。然后得到一个数组。程序会遍历这个数组,寻找有没有符合 "bootTraitName"的方法(在trait中定义),如果有就执行。

    /**
     * Boot all of the bootable traits on the model.
     *
     * @return void
     */
    protected static function bootTraits()
    {
        foreach (class_uses_recursive(get_called_class()) as $trait) {
            if (method_exists(get_called_class(), $method = 'boot'.class_basename($trait))) {
                forward_static_call([get_called_class(), $method]);
            }
        }
    }

    Eloquent用这种方法,在初始化一个model的时候,就可以做许多自动加载. laravel自带的功能中,softDelete就是通过trait来实现的。简单来说,use了softDelete的model,会在boot的时候自动执行bootSoftDelete,然后该方法在model所有的查询都默认加入一个判断deleted_at 字段的环节,以只调取未被删除的数据。

    /**
     * Boot the soft deleting trait for a model.
     *
     * @return void
     */
    public static function bootSoftDeletes()
    {
        static::addGlobalScope(new SoftDeletingScope);
    }

    这种做法提供了很多便利,也提供了trait的使用示范。

    举个简单的例子: 我们可以用这种方法 , 给model加载一个自动清除缓存的trait . 在每一个模型每次saved之后,自动刷新它的缓存:

    trait ModelCache {
    
        public static function bootModelCache(){
            static::saved(function($model){
                $cacheKey = get_class($model).'_'.$model->id;
                Cache::forget($cacheKey);
            });
        }
    
    }

    trait在laravel的其它场景中也经常使用。例如User模型,是Laravel用来做身份验证的驱动。与身份验证的相关方法就是用一个trait来加载的。

    <?php
    
    namespace IlluminateAuth;
    
    trait Authenticatable
    {
        /**
         * Get the unique identifier for the user.
         *
         * @return mixed
         */
        public function getAuthIdentifier()
        {
            return $this->getKey();
        }
    
        .................
    
        /**
         * Get the token value for the "remember me" session.
         *
         * @return string
         */
        public function getRememberToken()
        {
            return $this->{$this->getRememberTokenName()};
        }
    
    }

    这样当我们需要换别的模型,别的控制器做验证驱动,只要写一行use 代码,就自动得到了相关方法。

    laravel使用trait还有一个比较典型的,就是dispatch。主要在laravel的controller中调用了这个trait。这样laravel的控制器就可以用$this->dispatch() 直接来调度任务。

    trait DispatchesJobs
    {
        /**
         * Dispatch a job to its appropriate handler.
         *
         * @param  mixed  $job
         * @return mixed
         */
        protected function dispatch($job)
        {
            return app('IlluminateContractsBusDispatcher')->dispatch($job);
        }
    
        ...........
    }

    任何一个类只要use了这个DispatchJob的trait,都能用同样的调度方法(其实就是用app()得到了一个dispatch的单例)。

    灵活使用trait , 还是能创造各种魔法 . 我有一个设想就是通过模仿laravel的trait机制实现的 .

    简单来说 , 在做一个复杂的资讯站时 , 可能要创建许多种model . 然而每个model 总有一部分模块是一样的,例如:

    • 文章(标题,作者,正文)
    • 图片组(图片,简介)
    • 视频(标题,来源,源码,简介)
    • 添加到tag
    • 相关专题
    • 等等

    创建model时,重复添加这些字段是一个很头疼的工作. 而现在,我们可以用trait:

    abstract class Installer {
    
        //引用文章,图片,视频相关字段的构造trait
        use ArticleTrait,ImageTrait,VideoTrait;
    
        /**
         *  创建数据表
         */
        protected function CreateTable()
        {
    
            //用Schema创建数据表
            Schema::Create($this->table,function(Blueprint $table){
    
                //生成默认字段
                $table = $this->makeDefaultFields($table);
    
                //生成trait中的字段
                $table = $this->makeTraitFields($table);
    
            });
    
        }
    
        /**
         *   生成默认字段
         */
        protected function makeDefaultFields(Blueprint $table)
        {
            $table->increaments('id');
            $table->timestamps();
            return $table;
        }
    
        /**
         *   按照trait内的方法,生成模块的字段
         */
        protected function makeTraitFields(Blueprint $table)
        {
            foreach (class_uses_recursive(get_called_class()) as $trait) {
    
                //如果trait内有 makeTraitNameFields方法, 就用该方法生成字段
                if (method_exists($this, $method = 'make'.class_basename($trait).'Fields')) {
                    $table = $this->{$method}($table);
                }
    
            }
    
            return $table;
        }
    
    }

    这样 , 建完几个标准的trait后, 要建其它复杂的模型,代码上就非常简单了

  • 相关阅读:
    Python3网络学习案例三:编写web server
    struct.pack()和struct.unpack() 详解(转载)
    Python3网络学习案例二:traceroute详解
    Redis 配置
    vue之this.$route.params和this.$route.query的区别
    解决bugs: mybatisPlus 分页不能生效
    解决bug :"status":400,"error":"Bad Request","message":"Required request body is missing:
    vue,ElementUI中Switch 开关,switch 打开时的值为数字,该如何设置
    解决bug:vue项目中点击修改按钮,不能显示要修改的分类名字
    The 'Access-Control-Allow-Origin' header contains multiple values'*, *', but only one is allowed.
  • 原文地址:https://www.cnblogs.com/mouseleo/p/8674601.html
Copyright © 2011-2022 走看看