Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

normykinz's avatar

Livewire 3 attribute validation

Loving Livewire 3 but this is more of a PHP limitation,

This won't work because the attribute contains invalid operations.

#[Rule(['required', 'email', Rule::unique('users')->ignore($this->user)])]
public string $email;

Is there a way aroud this or should I bite the bullet in this case and just use the V2 rules array?

0 likes
3 replies
LaryAI's avatar
Level 58

In Livewire 3, you can't use $this in attribute validation because PHP attributes are evaluated at compile time, not at runtime. This means that $this is not available when the attribute is being evaluated.

However, you can use a closure in the Rule::unique() method to achieve the same result. Here's how you can do it:

#[Rule(['required', 'email'])]
public string $email;

public function rules()
{
    return [
        'email' => [
            ...$this->email->rules,
            Rule::unique('users')->ignore($this->user),
        ],
    ];
}

In this code, the rules method is overriding the email attribute's rules and adding the unique rule with the user to ignore. This way, you can still use the attribute validation and also have the unique rule ignore the current user.

Snapey's avatar

bear in mind what the docs say

As more properties and validation rules are added to a Livewire component, it can begin to feel too crowded. To alleviate this pain and also provide a helpful abstraction for code reuse, you can use Livewire's Form Objects to store your properties and validation rules.

HigorCh's avatar

Livewire Form

<?php

namespace App\Livewire\Forms;

use Livewire\Form;
use App\Models\User;
use Illuminate\Validation\Rule;

class UserForm extends Form
{
    public $user = '';
    public $name = '';
    public $email = '';
    public $password = '';
    public $role = '';
    public $status = '';

    public function rules()
    {
        $rules = [
            'name' => 'required',
            'email' => [
                'required',
                'email',
                Rule::unique('users', 'email')->ignore($this->user, 'uuid'),
            ],
            'password' => [
                'string',
                'min:8',              // must be at least 8 characters in length
                'regex:/[a-z]/',      // must contain at least one lowercase letter
                'regex:/[A-Z]/',      // must contain at least one uppercase letter
                'regex:/[0-9]/',      // must contain at least one digit
                'regex:/[@$!%*#?&]/', // must contain a special character
            ],
            'role' => 'required',
            'status' => 'required',
        ];

        if (empty($this->user)) {
            array_unshift($rules['password'], 'required');
        } else {
            array_unshift($rules['password'], 'nullable');
        }

        return $rules;
    }

    public function stored()
    {
        User::create([
            'name' => $this->name,
            'email' => $this->email,
            'password' => bcrypt($this->password),
            'role' => $this->role,
            'status' => $this->status,
        ]);
    }
}

Livewire Component

<?php

namespace App\Livewire\Panel\User;

use Livewire\Component;
use App\Livewire\Forms\UserForm;

class ModalStored extends Component
{
    public UserForm $form;

    public function render()
    {
        return view('livewire.panel.user.modal-stored');
    }

    public function submit()
    {
        $this->createOrUpdate();
    }

    public function createOrUpdate()
    {
        $this->validate();

        try {
            $this->form->stored();
            $this->dispatch('close-modal', ref: "modal-stored");
            $this->dispatch('notify', msg: "Executado com sucesso!", type: "success");
        } catch (\Exception $e) {
            $this->dispatch('notify', msg: "Não foi possível salvar.", type: "error");
        }
    }
}

1 like

Please or to participate in this conversation.