合成器

您是视觉学习者吗?
通过我们深入的屏幕录制掌握 Livewire
立即观看

由于 Livewire 组件被脱水(序列化)为 JSON,然后在请求之间重新水化(反序列化)为 PHP 组件,因此它们的属性需要可 JSON 序列化。

PHP 本机可轻松将大多数基本值序列化为 JSON。但是,为了让 Livewire 组件支持更复杂属性类型(如模型、集合、carbon 实例和字符串),需要一个更健壮的系统。

因此,Livewire 提供了一个称为“合成器”的扩展点,允许用户支持他们希望的任何自定义属性类型。

确保您首先了解水化

在使用合成器之前,全面了解 Livewire 的水化系统会很有帮助。您可以通过阅读水化文档了解更多信息。

了解合成器

在探索创建自定义合成器之前,我们首先来看看 Livewire 用于支持Laravel 字符串的内部合成器。

假设您的应用程序包含以下 CreatePost 组件

class CreatePost extends Component
{
public $title = '';
}

在请求之间,Livewire 可能会将此组件的状态序列化为以下 JSON 对象

state: { title: '' },

现在,考虑一个更高级的示例,其中 $title 属性值是一个字符串,而不是一个普通字符串

class CreatePost extends Component
{
public $title = '';
 
public function mount()
{
$this->title = str($this->title);
}
}

表示此组件状态的脱水 JSON 现在包含一个元数据元组,而不是一个普通的空字符串

state: { title: ['', { s: 'str' }] },

Livewire 现在可以使用此元组在下一次请求中将 $title 属性重新水化为一个字符串。

现在你已经看到了合成器的外部效果,下面是 Livewire 内部可字符串化合成器的实际源代码

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 属性

public static $key = 'str';

每个合成器都必须包含一个静态 $key 属性,Livewire 使用它将元数据元组(如 ['', { s: 'str' }])转换回可字符串化对象。正如你可能注意到的,每个元数据元组都有一个引用此键的 s 键。

相反,当 Livewire 对属性进行脱水时,它将使用合成器的静态 match() 函数来识别此特定合成器是否是脱水当前属性的良好候选者($target 是属性的当前值)

public static function match($target)
{
return $target instanceof Stringable;
}

如果 match() 返回 true,则 dehydrate() 方法将用于将属性的 PHP 值作为输入并返回可 JSON 化的 元数据 元组

public function dehydrate($target)
{
return [$target->__toString(), []];
}

现在,在下一个请求的开始,在元组中的 { s: 'str' } 键匹配此合成器后,将调用 hydrate() 方法并传递属性的原始 JSON 表示,期望它返回要分配给属性的完全 PHP 兼容值。

public function hydrate($value)
{
return str($value);
}

注册自定义合成器

为了演示如何编写自己的合成器来支持自定义属性,我们将使用以下 UpdateProperty 组件作为示例

class UpdateProperty extends Component
{
public Address $address;
 
public function mount()
{
$this->address = new Address();
}
}

以下是 Address 类的源代码

namespace App\Dtos\Address;
 
class Address
{
public $street = '';
public $city = '';
public $state = '';
public $zip = '';
}

为了支持 Address 类型的属性,我们可以使用以下合成器

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 方法从服务提供程序引导方法注册合成器

class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Livewire::propertySynthesizer(AddressSynth::class);
}
}

支持数据绑定

使用上述 UpdateProperty 示例,您可能希望直接支持将 wire:model 绑定到 Address 对象的属性。合成器允许您使用 get()set() 方法支持此功能

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)
{
return $target->{$key};
}
 
public function set(&$target, $key, $value)
{
$target->{$key} = $value;
}
}