【问题标题】:How does Laravel find and display the dynamic attributes on Eloquent models when using the tinker CLI?在使用 tinker CLI 时,Laravel 如何在 Eloquent 模型上查找和显示动态属性?
【发布时间】: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 在打印这样的对象时使用的表示形式?

【问题讨论】:

    标签: php laravel formatting laravel-artisan tinker


    【解决方案1】:

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

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

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

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

    /**
         * 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 使用数据库连接设置自动填充模型属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-17
      • 2018-07-17
      • 2015-01-26
      • 2019-03-04
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      相关资源
      最近更新 更多