美文网首页PHP开发
Laravel ORM Model 的预定义属性

Laravel ORM Model 的预定义属性

作者: patiencing | 来源:发表于2017-04-30 19:11 被阅读585次

    缘起

    后端开发的基本操作就是处理数据 -- "增删改查 / CURD", 而 Laravel 框架的"对象关系映射 (ORM = Object Relationship Mapping)" 为解决数据操作中的痛点和痒点提供了便捷的解决方案.


    属性

    $table 属性 -- 自定义关联的数据表

    既然叫"对象关系映射", 则意味着有明确的对应关系和约定.

    Laravel 约定数据表的表名是 Model 名的复数, 比如 User Model 对应的是 users 表, Order Model 对应的是 orders 表.
    如果需要自定义, 可以通过覆写 $table 属性来指定表名:

    protected $table = 'yourTableName';
    

    $primaryKey 属性 -- 自定义主键

    Laravel 约定每张表都有整型的 id 字段做为自增主键.

    如果想设置其他字段做为主键,可以通过覆写 $primaryKey 属性来自定义.

    protected $primaryKey = 'uid';
    

    $timestamp 属性 -- 数据的时间戳属性

    数据的可追溯性是非常重要的. 所以 Laravel 迁移文件默认带时间戳:

    $table->timestamps();
    

    所以通过迁移文件生成的数据表默认带 create_atupdated_at 字段, 在添加数据和更新数据时会分别自动更新这两个字段.

    这两个字段是 MySQL 的 datetime 类型, 即这种样式: 2015-08-05 07:27:09.
    但是个人觉得从 MySQL 检索优化的角度来说, int 型的 Unix 时间戳比 datetime 类型速度要快, 所以这样设置:

    use Illuminate\Database\Eloquent\Model;
    
    class PosterSubScribeModel extends Model
    {
        protected $table = 'subscriber';
        protected $guarded = [''];
    
        /**
         * 获取当前Unix时间戳
         * @return int
         */
        public function freshTimestamp()
        {
            return time();
        }
    
        /**
         * 避免转换Unix时间戳为时间字符串
         *
         * @param \DateTime|int $value
         * @return \DateTime|int
         */
        public function fromDateTime($value)
        {
            return $value;
        }
    }
    

    PS. 如果不想使用 timestamp, 可以将其关闭:

    protected $timestamps = FALSE;
    

    $casts 属性 -- 转化数据类型

    PHP 擅长处理数组, 而前后端交互通常用 JSON, 所以常见的场景是我们希望用"数组"处理数据和存储数据, 但是希望读取出来的是 JSON 格式.

    这种场景下就可以使用 $casts 属性, 实现取出数据时自动转化为 JSON 数据:

    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model
    {
        protected $casts = [
            'my_array_data' => 'json',
        ];
    }
    

    还有一种使用场景, 是把存储的 1 和 0, 在取出时自动转化为 true 和 false:

    class User extends Model
    {
        protected $casts = [
            'options' => 'json',
            'status' => 'bool',
        ];
    }
    

    **注意: **
    $cast 并没有真的改变存储的数据类型,而是取出数据时暂时转换成设定的数据类型;


    $attributes 属性 -- 默认值

    给数据库里的一个字段设置默认值.

    protected $attributes = [
        'goods_ids' => '[]', //可以配合 $casts, 取出数据时自动转化为 JSON
        'category_ids' => '[]',
        'display_order' => 0,
    ];
    

    注意:
    不能写成 'goods_ids' => []. 而必须给[]加上引号; 上次因为没有加引号, 存储数据时莫名出现多个空数据(暂时还未弄清楚原因).


    $dates 属性 - 强大的时间类

    时间数据经常面临"格式化"的问题, 比如"Unix时间戳"和"可读时间格式"的转化.

    $date 属性可以解决这个问题.
    设置成这个属性的时间数据可以自动转化为 Carbon 类的对象, 从而使用 Carbon 的方法来处理时间.

    Carbon 类的方法很强大, 大家可以深入研究一下Carbon源码 或者是查看 Laravel 中的 Carbon 类 (/vendor/nesbot/carbon/src/Carbon/Carbon.php).
    比如, 把"可读时间格式"(比如 2017-04-30 12:00) 转化为 "Unix 时间戳":

    $model->deleted_at->timestamp
    

    $guarded 和 $fillable 属性 -- 限制写入数据库的数据

    因为 Eloquent 模型默认对批量赋值(Mass Assignment)进行保护. 这规则要求使用 create() 或者 update() 方法批量插入或者更新属性时, 需要先设置 $guarded$fillable 属性.

    设置后, 在批量写入数据库时, 不光会筛掉数据表没有的字段, 也会筛选掉 $guarded$fillable 中限制的字段.

    • $guarded 是"黑名单", 写入这里的字段, 表示不可以被赋值; 如果所有字段都可以写入数据库, 可以这样写 protected $guarded = [''], 表示没有需要被 "guarded/保护" 的字段.
    • $fillable 是"白名单", 写入这里的字段, 表示只有在这些声明的字段可以被写入数据库;

    注意:
    一个 model 只能使用其中一个属性, 而不是一起使用.
    一般来说, 因为这两个属性的适用场景是剔除非法赋值的数据, 所以$guarded 使用的频率高一些。


    $hidden 和 $visible 属性 -- 设置数据的可见性

    比如像 password 这种字段,是不希望在读取后呈现给用户看到的,那么可以把它隐藏:

    • 黑名单 $hidden 的写法
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model
    {
        protected $hidden = ['password'];
    }
    
    • 白名单 $visible 的写法
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model
    {
        protected $visible = ['first_name', 'last_name']; //排除 password 字段
    }
    

    注意:

    • $guarded & $fillable 属性一样, 一个 model 只能使用 $hidden$visible 其中一个属性, 而不是同时使用.
      一般来说, 由于这两个属性的适用场景是"隐藏数据", 所以 $hidden 使用的频率高一些。
    • 对于"关联查询"
      • 如果要隐藏整张关联表的字段,需要在 $hidden 中填写"表间关系的方法"(比如 hasManyPost)
      • 如果要隐藏关联表里的部分字段,则需要到关联表的 model 里去设置 $hidden / $visible 属性.

    $appends 属性 -- 添加属性

    开发 API 接口时, 前端经常会要求提供一些数据表没有的字段, 这时候, 就需要使用 $appends 属性了. 在查询数据库返回的数据中, 手动增加新的数据:

    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model
    {
        public function getIsAdminAttribute()
        {
             return 'yes';
        }
         protected $appends = ['is_admin'];
    }
    

    这时, 查询 users 表的数据时, 就多了一个 is_admin 的数据.


    $deleted_at 属性 -- 软删除

    数据是宝贵的, 而硬盘存储的成本非常低廉, 所以删除数据时一般只是添加删除标识而并不真的删除数据.

    Laravel 提供了"软删除"方案, 使用 deleted_at 字段保存数据的删除时间. 查询数据时, 被软删除的数据将会自动从查询结果中排除.

    想要使用"软删除", 需要这样设置:

    • 1.创建数据表时在"迁移文件"中加入 deleted_at 字段:
    public function up()
    {
        Schema::table('flights', function ($table) {
            $table->softDeletes();
        });
    }
    

    或者是创建迁移文件在已有的数据表中添加 deleted_at 字段:

    public function up()
    {
        Schema::table('poster', function (Blueprint $table) {
            $table->integer('deleted_at')->nullable()->comment('删除时间');
        });
    }
    
    public function down()
    {
        Schema::table('poster', function (Blueprint $table) {
            $table->dropColumn('deleted_at');
        });
    }
    
    • 2.引入 SoftDeletes 的 trait, 并声明 deleted_at 字段是 $dates 属性:
    namespace App;
    
    use app\common\models\BaseModel;
    use Illuminate\Database\Eloquent\SoftDeletes;
    
    class Poster extends BaseModel
    {
        use SoftDeletes;
    
        protected $dates = ['deleted_at'];
    }
    

    如果想要查询出这些被删除的数据时, 只要加上 withTrashed() 方法即可.


    参考文章


    文章历史

    • 2017/04/30 (第一次发布)
    • 2017/05/03 润色
    • 2017/06/03 润色
    • 2017/06/14 润色

    如果我的文章对你有用, 希望给些改进的建议, 或者打个"喜欢" _

    相关文章

      网友评论

        本文标题:Laravel ORM Model 的预定义属性

        本文链接:https://www.haomeiwen.com/subject/jwpxtxtx.html