主题
Synthesizers
由于 Livewire 组件在请求之间被脱水(序列化)为 JSON,然后水合(反序列化)回 PHP 组件,它们的属性需要是 JSON 可序列化的。
原生情况下,PHP 可以轻松地将大多数原始值序列化为 JSON。但是,为了让 Livewire 组件支持更复杂的属性类型(如模型、集合、carbon 实例和 stringables),需要一个更强大的系统。
因此,Livewire 提供了一个名为"Synthesizers"的扩展点,允许用户支持任何他们希望的自定义属性类型。
首先确保您了解 hydration
在使用 Synthesizers 之前,完全了解 Livewire 的 hydration 系统会很有帮助。您可以通过阅读 hydration 文档 了解更多。
理解 Synthesizers
在探索创建自定义 Synthesizers 之前,让我们先看看 Livewire 用来支持 Laravel Stringables 的内部 Synthesizer。
假设您的应用程序包含以下 CreatePost 组件:
php
class CreatePost extends Component
{
public $title = '';
}在请求之间,Livewire 可能会将此组件的状态序列化为如下 JSON 对象:
js
state: { title: '' },现在,考虑一个更高级的示例,其中 $title 属性值是 stringable 而不是普通字符串:
php
class CreatePost extends Component
{
public $title = '';
public function mount()
{
$this->title = str($this->title);
}
}表示此组件状态的脱水 JSON 现在包含一个元数据元组而不是普通的空字符串:
js
state: { title: ['', { s: 'str' }] },Livewire 现在可以使用此元组在下一次请求时将 $title 属性水合回 stringable。
现在您已经看到了 Synthesizers 的外部效果,以下是 Livewire 内部 stringable synth 的实际源代码:
php
use Illuminate\Support\Stringable;
class StringableSynth extends Synth
{
public static $key = 'str';
public static function match($target)
{
return $target instanceof Stringable;
}
public function dehydrate($target)
{
return [$target->__toString(), []];
}
public function hydrate($value)
{
return str($value);
}
}让我们逐一分析这些部分。
首先是 $key 属性:
php
public static $key = 'str';每个 synth 必须包含一个静态 $key 属性,Livewire 使用它将像 ['', { s: 'str' }] 这样的元数据元组转换回 stringable。您可能注意到,每个元数据元组都有一个引用此 key 的 s 键。
相反,当 Livewire 脱水一个属性时,它将使用 synth 的静态 match() 函数来识别这个特定的 Synthesizer 是否是脱水当前属性的好候选($target 是属性的当前值):
php
public static function match($target)
{
return $target instanceof Stringable;
}如果 match() 返回 true,dehydrate() 方法将用于接收属性的 PHP 值作为输入并返回 JSON 可序列化的元数据元组:
php
public function dehydrate($target)
{
return [$target->__toString(), []];
}现在,在下一次请求开始时,在此 Synthesizer 通过元组中的 { s: 'str' } key 被匹配后,hydrate() 方法将被调用并传递属性的原始 JSON 表示,期望它返回完整的 PHP 兼容值以分配给属性。
php
public function hydrate($value)
{
return str($value);
}注册自定义 Synthesizer
为了演示您如何编写自己的 Synthesizer 来支持自定义属性,我们将使用以下 UpdateProperty 组件作为示例:
php
class UpdateProperty extends Component
{
public Address $address;
public function mount()
{
$this->address = new Address();
}
}以下是 Address 类的源代码:
php
namespace App\Dtos\Address;
class Address
{
public $street = '';
public $city = '';
public $state = '';
public $zip = '';
}为了支持 Address 类型的属性,我们可以使用以下 Synthesizer:
php
use App\Dtos\Address;
class AddressSynth extends Synth
{
public static $key = 'address';
public static function match($target)
{
return $target instanceof Address;
}
public function dehydrate($target)
{
return [[
'street' => $target->street,
'city' => $target->city,
'state' => $target->state,
'zip' => $target->zip,
], []];
}
public function hydrate($value)
{
$instance = new Address;
$instance->street = $value['street'];
$instance->city = $value['city'];
$instance->state = $value['state'];
$instance->zip = $value['zip'];
return $instance;
}
}要使其在您的应用程序中全局可用,您可以使用 Livewire 的 propertySynthesizer 方法从您的 service provider boot 方法中注册 synthesizer:
php
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Livewire::propertySynthesizer(AddressSynth::class);
}
}支持数据绑定
使用上面的 UpdateProperty 示例,您可能希望支持直接将 wire:model 绑定到 Address 对象的属性。Synthesizers 允许您使用 get() 和 set() 方法来支持此功能:
php
use App\Dtos\Address;
class AddressSynth extends Synth
{
public static $key = 'address';
public static function match($target)
{
return $target instanceof Address;
}
public function dehydrate($target)
{
return [[
'street' => $target->street,
'city' => $target->city,
'state' => $target->state,
'zip' => $target->zip,
], []];
}
public function hydrate($value)
{
$instance = new Address;
$instance->street = $value['street'];
$instance->city = $value['city'];
$instance->state = $value['state'];
$instance->zip = $value['zip'];
return $instance;
}
public function get(&$target, $key) // [tl! highlight:8]
{
return $target->{$key};
}
public function set(&$target, $key, $value)
{
$target->{$key} = $value;
}
}