dvarilek/livewire-closure-synthesizer
Installation:
Run composer require dvarilek/livewire-closure-synthesizer in your Laravel project. No additional configuration is required—this is a drop-in package.
First Use Case:
Closure type (e.g., public ?Closure $modifyComponentUsing = null;).<livewire:component :modifyComponentUsing="fn($value) => $value * 2" />
if ($modifyComponentUsing) $result = $modifyComponentUsing($input);).Where to Look First:
Dynamic Component Behavior: Use closures to inject logic into components without modifying their class definitions. For example:
// Blade
<livewire:user-table :sortClosure="fn($column) => 'asc' === $column ? 'desc' : 'asc'" />
// Component
public ?Closure $sortClosure = null;
public function sort($column) {
$direction = $this->sortClosure ? $this->sortClosure($column) : 'asc';
// Apply sorting...
}
Conditional Rendering: Pass closures to control visibility or rendering logic:
// Blade
<livewire:modal :isVisible="fn() => auth()->check()" />
// Component
public ?Closure $isVisible = null;
public function shouldRender() {
return $this->isVisible ? $this->isVisible() : false;
}
Data Transformation: Use closures to transform data before/after Livewire operations (e.g., form validation, API responses):
// Blade
<livewire:form :transformResponse="fn($data) => collect($data)->map(fn($v) => strtoupper($v))" />
// Component
public ?Closure $transformResponse = null;
public function submit() {
$data = $this->transformResponse ? $this->transformResponse($this->data) : $this->data;
// Process $data...
}
Closure Persistence: The package automatically serializes and encrypts closures, ensuring they persist across requests. Leverage this for:
Integration with Livewire Hooks:
Combine with Livewire’s lifecycle hooks (e.g., mount, hydrate) to initialize closures dynamically:
public function mount() {
$this->modifyComponentUsing = fn($x) => $x + $this->user->preference;
}
Testing: Mock closures in tests by passing simple anonymous functions:
$this->component->modifyComponentUsing = fn($x) => $x * 2;
$this->assertEquals(4, $this->component->modifyComponentUsing(2));
?Closure) to avoid runtime errors when undefined.var_dump($this->closureProperty) to inspect serialized closures (output will be encrypted).Serialization Limits:
// Anti-pattern: Capturing a large dataset
$bigArray = range(1, 10000);
$this->closureProperty = fn() => $bigArray;
Encryption Overhead:
Closure Scope:
public function someMethod() {
$temp = "value";
$this->closureProperty = fn() => $temp; // $temp may be out of scope later!
}
Blade Syntax Quirks:
use statements:
<!-- Works -->
:closure="fn($x) => $x + 1"
<!-- May fail (syntax ambiguity) -->
:closure="fn($x) => { return $x + 1; }"
now() or app() helpers to test syntax:
{{ fn($x) => $x + 1 }}
Livewire 3 Migration:
Inspect Serialized Closures: Add this to a component to log closure state:
public function hydrate() {
if ($this->closureProperty) {
\Log::debug('Closure serialized:', [
'is_callable' => is_callable($this->closureProperty),
'serialized' => serialize($this->closureProperty),
]);
}
}
Common Errors:
Closure could not be serialized.
Cause: The closure captures non-serializable data (e.g., resources, closures).
Fix: Simplify the closure or use component properties.Call to undefined function in closure.
Cause: The closure references a function/class not autoloaded or available in the Livewire context.
Fix: Use fully qualified names (e.g., \App\Helpers\myFunction).Storage Bloat:
livewire table size if storing many closures. Large serialized closures can inflate storage.Custom Serialization:
Override the default serialization by publishing the package’s config and extending the ClosureSynthesizer:
// config/livewire-closure-synthesizer.php
'serializer' => \App\CustomClosureSerializer::class,
Implement SynthesizesClosures interface to define custom logic.
Encryption Key Rotation: The package uses Laravel’s default encryption. To rotate keys:
APP_KEY in .env.livewire table.Fallback Logic: Provide default behavior when closures fail to serialize:
public ?Closure $fallbackClosure = null;
public function safeExecute(?Closure $closure, $arg) {
try {
return $closure ? $closure($arg) : $this->fallbackClosure($arg);
} catch (\Throwable $e) {
return $this->fallbackClosure($arg);
}
}
Closure Validation:
Validate closures in rules() or validate() to ensure they meet expectations:
protected $rules = [
'closureProperty' => ['required', function ($attribute, $value, $fail) {
if ($value && !is_callable($value)) {
$fail('The closure must be callable.');
}
}],
];
How can I help you explore Laravel packages today?