使用 tinker CLI 时,Laravel 如何在 Eloquent 模型上查找和显示动态属性?
How does Laravel find and display the dynamic attributes on Eloquent models when using the tinker CLI?
当我们使用 artisan tinker
并引用 Eloquent 模型对象时,REPL 会自动打印模型的属性,就像它打印任何标准对象的 public 属性一样参考:
>>> (object) ['hello' => 'world']
=> {
+"hello": "world",
}
>>> App\User::first()
=> App\User {
id: 1,
name: "...",
}
对我来说不太明显的是如何这些虚拟属性可以出现在这里,就好像它们已经定义为[=31]的public属性一样=].我知道模型的大部分属性分配都是由 HasAttributes
特征在内部处理的,但即使查看那里,我仍然看不出 Laravel 作者是如何实现这种行为的。
我试过像这样构建 class:
class Bunch implements Arrayable, ArrayAccess, Jsonable, JsonSerializable { ... }
但即使使用工作数组访问和 toArray
方法,当我直接从 artisan tinker
:
引用它时
>>> $b = new Bunch()
=> Bunch {}
>>> $b->one = 1
=> 1
>>> $b['one']
=> 1
>>> $b
=> Bunch {}
我们如何更改 REPL 在打印这样的对象时使用的表示形式?
Eloquent 使用数据库连接设置自动填充模型属性。
决定如何在 Tinker 中显示模型属性的代码在 Tinker 代码中,而不在模型中:
脚轮是 Symfony VarDumper component which is used by PsySH 显示 class 的一部分。 Tinker 建立在 PsySH 之上。
Tinker 在其控制台命令中将脚轮映射到 classes class:
这个 returns classes 到他们施法者的映射:
/**
* 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'];
}
当我们使用 artisan tinker
并引用 Eloquent 模型对象时,REPL 会自动打印模型的属性,就像它打印任何标准对象的 public 属性一样参考:
>>> (object) ['hello' => 'world']
=> {
+"hello": "world",
}
>>> App\User::first()
=> App\User {
id: 1,
name: "...",
}
对我来说不太明显的是如何这些虚拟属性可以出现在这里,就好像它们已经定义为[=31]的public属性一样=].我知道模型的大部分属性分配都是由 HasAttributes
特征在内部处理的,但即使查看那里,我仍然看不出 Laravel 作者是如何实现这种行为的。
我试过像这样构建 class:
class Bunch implements Arrayable, ArrayAccess, Jsonable, JsonSerializable { ... }
但即使使用工作数组访问和 toArray
方法,当我直接从 artisan tinker
:
>>> $b = new Bunch()
=> Bunch {}
>>> $b->one = 1
=> 1
>>> $b['one']
=> 1
>>> $b
=> Bunch {}
我们如何更改 REPL 在打印这样的对象时使用的表示形式?
Eloquent 使用数据库连接设置自动填充模型属性。
决定如何在 Tinker 中显示模型属性的代码在 Tinker 代码中,而不在模型中:
脚轮是 Symfony VarDumper component which is used by PsySH 显示 class 的一部分。 Tinker 建立在 PsySH 之上。
Tinker 在其控制台命令中将脚轮映射到 classes class:
这个 returns classes 到他们施法者的映射:
/**
* 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'];
}