Download the PHP package boring-o11y/wirestan without Composer
On this page you can find all versions of the php package boring-o11y/wirestan. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download boring-o11y/wirestan
More information about boring-o11y/wirestan
Files in boring-o11y/wirestan
Package wirestan
Short Description PHPStan rule for Livewire components: public properties that are never reassigned outside lifecycle methods must be marked #[Locked], so the client cannot tamper with them via $wire.set.
License MIT
Homepage https://github.com/boring-o11y/wirestan
Informations about the package wirestan
wirestan
PHPStan / Larastan rules for Livewire components.
Every public property on a Livewire component is part of the client-editable
state: the browser can set any of them with $wire.set('prop', value), and
Livewire will happily hydrate the new value on the next request. That is exactly
what you want for a wire:model-bound input — and exactly what you don't want
for $bookingId, $tenantId, $role, or anything else the server seeded in
mount() and then trusted.
Livewire's answer is the #[Locked] attribute, which makes the property
server-only. The failure mode of forgetting it is silent: nothing throws, the
component works in the browser, and the IDOR only shows up when someone goes
looking for it.
wirestan catches the omission in CI.
Requirements
- PHP
^8.2 - PHPStan
^2.0(works great alongside Larastan) - Livewire 3 or 4 in the analysed project
Installation
Registering the rules
If you use phpstan/extension-installer
(recommended), there is nothing else to do — the rule registers
automatically.
Otherwise, include the bundled extension.neon from your phpstan.neon
(or phpstan.neon.dist):
That's it — the rule now runs as part of your normal analysis:
Rules
| Rule | Identifier | In one line |
|---|---|---|
| LockedPublicPropertyRule | boringO11yWirestan.lockedPublicProperty |
Never-reassigned public properties must be #[Locked] |
LockedPublicPropertyRule
Reports public properties of Livewire\Component subclasses that are never
reassigned outside the lifecycle seed methods and are missing
#[Livewire\Attributes\Locked].
The fix is one attribute:
What counts as a mutation
Writes inside the seed methods — mount, __construct, boot, booted,
hydrate, dehydrate — are server-controlled initialisation, not user-driven
mutation, so they do not exempt a property. A write anywhere else does.
Recognised as a mutation: plain assignment, compound assignment (.=, +=, …),
reference assignment, ++/--, array-element writes ($this->rows[] = …),
list destructuring ([$this->a, $this->b] = …), and $this->reset('name')
with literal property names.
What the rule deliberately skips
- Properties already marked
#[Locked], obviously. staticandreadonlyproperties — not client-editable state.Livewire\Formproperties. A Form is mutated through nested fields (wire:model="form.email") and never reassigned wholesale, so it reads as immutable — but locking the root breaks every nested update at runtime withCannotUpdateLockedPropertyException. Livewire de/hydrates Forms natively, so they are not a$wire.setvector.- Framework-reserved properties:
$listeners,$rules,$messages,$validationAttributes,$queryString,$paginationTheme. Configurable, see below. - The entire component, when a non-seed method performs an opaque
mass-assignment that could touch any public property:
$this->fill(),fillData(),mergeData(),resetExcept(), a no-argument or non-literal-argument$this->reset(), or a dynamic write$this->{$name} = …. Immutability can no longer be proven statically, so the rule stays quiet rather than emit false positives.
Configuration
Override the reserved-property list from your phpstan.neon:
Adopting on an existing codebase
The rule will light up on any Livewire codebase that predates it. Generate a baseline so it only fails on new violations, then burn the entries down:
Each baselined entry is a real decision: add #[Locked] where the property is
server-controlled, or confirm it is genuinely a wire:model-bound input and
remove it from the baseline once the rule stops matching.
To silence an individual finding, use the error identifier:
Development
Tests use PHPStan's RuleTestCase against fixtures in tests/Fixtures, with
minimal Livewire\* stubs in tests/Stubs so the package has no runtime
dependency on Livewire itself.
License
MIT — see LICENSE.