Sintetizadores
Dado que los componentes Livewire se deshidratan (serializan) en JSON y luego se rehidratan (deserializan) de nuevo en componentes PHP entre solicitudes, sus propiedades deben ser serializables en JSON.
De forma nativa, PHP serializa fácilmente la mayoría de los valores primitivos en JSON. Sin embargo, para que los componentes Livewire admitan tipos de propiedades más sofisticados (como modelos, colecciones, instancias de carbono y stringables), se necesita un sistema más robusto.
Por lo tanto, Livewire proporciona un punto de extensión llamado «Sintetizadores» que permite a los usuarios admitir cualquier tipo de propiedad personalizada que deseen.
Comprender los sintetizadores
Antes de explorar la creación de sintetizadores personalizados, veamos primero el sintetizador interno que Livewire utiliza para admitir Laravel Stringables.
Supongamos que su aplicación contiene el siguiente componente CreatePost:
class CreatePost extends Component{ public $title = '';}Entre solicitudes, Livewire podría serializar el estado de este componente en un objeto JSON como el siguiente:
state: { title: '' },Ahora, consideremos un ejemplo más avanzado en el que el valor de la propiedad $title es una cadena convertible en cadena en lugar de una cadena simple:
class CreatePost extends Component{ public $title = '';
public function mount() { $this->title = str($this->title); }}El JSON deshidratado que representa el estado de este componente ahora contiene una tupla de metadatos en lugar de una cadena vacía simple:
state: { title: ['', { s: 'str' }] },Livewire ahora puede usar esta tupla para rehidratar la propiedad $title en una cadena en la siguiente solicitud.
Ahora que has visto los efectos externos de los sintetizadores, aquí tienes el código fuente real del sintetizador de cadenas interno de 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); }}Analicemos esto pieza por pieza.
Primero está la propiedad $key:
public static $key = 'str';Cada sintetizador debe contener una propiedad estática $key que Livewire utiliza para convertir una tupla de metadatos como [“”, { s: “str” }] de nuevo en una cadena. Como se puede observar, cada tupla de metadatos tiene una clave s que hace referencia a esta clave.
A la inversa, cuando Livewire deshidrata una propiedad, utiliza la función estática match() del sintetizador para identificar si este sintetizador en particular es un buen candidato para deshidratar la propiedad actual ($target es el valor actual de la propiedad):
public static function match($target){ return $target instanceof Stringable;}Si match() devuelve true, se utilizará el método dehydrate() para tomar el valor PHP de la propiedad como entrada y devolver la tupla de metadatos JSONable:
public function dehydrate($target){ return [$target->__toString(), []];}Ahora, al comienzo de la siguiente solicitud, después de que este sintetizador haya sido emparejado con la clave { s: “str” } en la tupla, se llamará al método hydrate() y se le pasará la representación JSON sin procesar de la propiedad con la expectativa de que devuelva el valor completo compatible con PHP para asignarlo a la propiedad.
public function hydrate($value){ return str($value);}Registro de un sintetizador personalizado
Para mostrar cómo se puede crear un sintetizador propio que admita una propiedad personalizada, utilizaremos el siguiente componente UpdateProperty como ejemplo:
class UpdateProperty extends Component{ public Address $address;
public function mount() { $this->address = new Address(); }}Aquí está el código fuente de la clase Address:
namespace App\Dtos\Address;
class Address{ public $street = ''; public $city = ''; public $state = ''; public $zip = '';}Para admitir propiedades de tipo Address, podemos utilizar el siguiente sintetizador:
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; }}Para que esté disponible globalmente en su aplicación, puede utilizar el método propertySynthesizer de Livewire para registrar el sintetizador desde el método de arranque de su proveedor de servicios:
class AppServiceProvider extends ServiceProvider{ /** * Bootstrap any application services. */ public function boot(): void { Livewire::propertySynthesizer(AddressSynth::class); }}Compatibilidad con el Data Binding
Utilizando el ejemplo UpdateProperty anterior, es probable que desee admitir el enlace wire:model directamente a las propiedades del objeto Address. Los sintetizadores le permiten admitir esto utilizando los métodos get() y 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; }}