在使用 tinker CLI 时,Laravel 如何在 Eloquent 模型上查找和显示动态属性?

Posted

技术标签:

【中文标题】在使用 tinker CLI 时,Laravel 如何在 Eloquent 模型上查找和显示动态属性?【英文标题】:How does Laravel find and display the dynamic attributes on Eloquent models when using the tinker CLI? 【发布时间】:2020-11-19 18:13:25 【问题描述】:

当我们使用 artisan tinker 并引用 Eloquent 模型对象时,REPL 会自动打印模型的属性,就像它打印我们引用的任何标准对象的公共属性一样:

>>> (object) ['hello' => 'world']
 => 
      +"hello": "world",
    

>>> App\User::first()
 => App\User 
      id: 1,
      name: "...",
   

对我来说不太明显的是如何这些虚拟属性可以出现在这里,就好像它们已经被定义为类的公共属性一样。我知道模型的大部分属性分配是由HasAttributes trait 在内部处理的,但是即使看那里,我仍然看不到 Laravel 的作者是如何实现这种行为的。

我尝试过构建这样的类:

class Bunch implements Arrayable, ArrayAccess, Jsonable, JsonSerializable  ... 

但即使使用有效的数组访问和toArray 方法,当我直接从artisan tinker 引用它时:

>>> $b = new Bunch()
 => Bunch 
>>> $b->one = 1
 => 1
>>> $b['one']
 => 1
>>> $b
 => Bunch 

我们如何改变 REPL 在打印这样的对象时使用的表示形式?

【问题讨论】:

【参考方案1】:

确定如何在 Tinker 中显示模型属性的代码在 Tinker 代码中,而不是在模型中:

https://github.com/laravel/tinker/blob/2.x/src/TinkerCaster.php

脚轮是Symfony VarDumper component 的一部分,PsySH 使用它来显示类。 Tinker 建立在 PsySH 之上。

Tinker 将施法者映射到其控制台命令类中的类:

https://github.com/laravel/tinker/blob/2.x/src/Console/TinkerCommand.php

这会返回类到它们的施法者的映射:

/**
     * Get an array of Laravel tailored casters.
     *
     * @return array
     */
    protected function getCasters()
    
        $casters = [
            'Illuminate\Support\Collection' => 'Laravel\Tinker\TinkerCaster::castCollection',
            'Illuminate\Support\htmlString' => 'Laravel\Tinker\TinkerCaster::castHtmlString',
            'Illuminate\Support\Stringable' => 'Laravel\Tinker\TinkerCaster::castStringable',
        ];

        if (class_exists('Illuminate\Database\Eloquent\Model')) 
            $casters['Illuminate\Database\Eloquent\Model'] = 'Laravel\Tinker\TinkerCaster::castModel';
        

        if (class_exists('Illuminate\Foundation\Application')) 
            $casters['Illuminate\Foundation\Application'] = 'Laravel\Tinker\TinkerCaster::castApplication';
        

        return $casters;
    

这会设置 VarDumper 上的脚轮:

        $config->getPresenter()->addCasters(
            $this->getCasters()
        );

如果您想从模型中添加其他属性以在 Tinker 中显示,您可以在模型上使用 $appends 属性:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['is_admin'];

【讨论】:

是的!这完全是我想要的。添加$casters['App\Bunch'] = 'App\Bunch::castBunch'; 允许我定义一个自定义方法来处理我的自定义类的REPL 表示。非常感谢!【参考方案2】:

Eloquent 使用数据库连接设置自动填充模型属性。

【讨论】:

以上是关于在使用 tinker CLI 时,Laravel 如何在 Eloquent 模型上查找和显示动态属性?的主要内容,如果未能解决你的问题,请参考以下文章

php 7.2.19 上的 Laravel Tinker

laravel 5.5:php artisan tinker:ErrorException:目录不为空[重复]

带有消息“未定义变量”的 Laravel Tinker ErrorException

Laravel 8 + Tinker:如何创建虚拟数据

Laravel Tinker 的使用

如何使用 Laravel 8 中的工厂在 tinker 中创建虚拟表数据并连接它们?