Regenerate Boost guidelines and skills
Generated by boost:update for Boost 2.8, which replaces the pest-testing skill with testing-best-practices and adds infer-conventions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017XYnWFt9pJEwvAmNFN38XD
This commit is contained in:
co-authored by
Claude Opus 5
parent
3638455167
commit
92b3b3de56
@@ -1,75 +1,89 @@
|
||||
# Validation & Forms Best Practices
|
||||
# Validation and Forms Best Practices
|
||||
|
||||
## Use Form Request Classes
|
||||
## Extract Validation When It Improves the Boundary
|
||||
|
||||
Extract validation from controllers into dedicated Form Request classes.
|
||||
Use a form request when validation or authorization is substantial, reused, or clearer outside the controller. Inline `$request->validate()` remains appropriate for a small, endpoint-specific rule set.
|
||||
|
||||
Incorrect:
|
||||
```php
|
||||
public function store(Request $request)
|
||||
public function store(StorePostRequest $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'title' => 'required|max:255',
|
||||
'body' => 'required',
|
||||
]);
|
||||
$post = Post::create($request->validated());
|
||||
|
||||
return redirect()->route('posts.show', $post);
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
```php
|
||||
public function store(StorePostRequest $request)
|
||||
{
|
||||
Post::create($request->validated());
|
||||
}
|
||||
```
|
||||
A form request's `authorize()` method can enforce access to the operation. Validation establishes the shape and values of input; it does not itself authorize the user.
|
||||
|
||||
## Array vs. String Notation for Rules
|
||||
## Prefer Readable Rule Syntax
|
||||
|
||||
Array syntax is more readable and composes cleanly with `Rule::` objects. Prefer it in new code, but check existing Form Requests first and match whatever notation the project already uses.
|
||||
Array syntax composes cleanly with rule objects and avoids delimiter issues. Prefer it in new code when it improves readability, while following a consistent local style.
|
||||
|
||||
```php
|
||||
// Preferred for new code
|
||||
'email' => ['required', 'email', Rule::unique('users')],
|
||||
```
|
||||
|
||||
// Follow existing convention if the project uses string notation
|
||||
String syntax remains valid for simple rules:
|
||||
|
||||
```php
|
||||
'email' => 'required|email|unique:users',
|
||||
```
|
||||
|
||||
## Always Use `validated()`
|
||||
## Use Only Intended Validated Data
|
||||
|
||||
Get only validated data. Never use `$request->all()` for mass operations.
|
||||
Use `validated()` or `safe()` instead of `$request->all()` when passing request data onward. Then select the fields intended for the operation when the validation rules also cover control fields or nested data.
|
||||
|
||||
Unsafe:
|
||||
|
||||
Incorrect:
|
||||
```php
|
||||
Post::create($request->all());
|
||||
```
|
||||
|
||||
Correct:
|
||||
Preferred:
|
||||
|
||||
```php
|
||||
Post::create($request->validated());
|
||||
$post = Post::create($request->safe()->only(['title', 'body']));
|
||||
```
|
||||
|
||||
## Use `Rule::when()` for Conditional Validation
|
||||
Validated data is not automatically safe for mass assignment. Keep model `$fillable` or `$guarded` rules aligned with the operation, and never add a sensitive attribute to validation merely to make mass assignment convenient.
|
||||
|
||||
## Express Conditional Rules Clearly
|
||||
|
||||
Use conditional rules such as `Rule::when()`, `required_if`, or `exclude_unless` when they make the condition explicit. Choose the simplest form that remains easy to test.
|
||||
|
||||
```php
|
||||
'company_name' => [
|
||||
Rule::when($this->account_type === 'business', ['required', 'string', 'max:255']),
|
||||
'string',
|
||||
'max:255',
|
||||
Rule::when(
|
||||
$this->input('account_type') === 'business',
|
||||
['required'],
|
||||
['nullable'],
|
||||
),
|
||||
],
|
||||
```
|
||||
|
||||
## Use the `after()` Method for Custom Validation
|
||||
## Add Cross-Field Validation After Base Rules
|
||||
|
||||
Use `after()` instead of `withValidator()` for custom validation logic that depends on multiple fields.
|
||||
Use a form request's `after()` method for validation that depends on multiple fields or application state. Avoid expensive queries when prerequisite fields have already failed validation.
|
||||
|
||||
```php
|
||||
public function after(): array
|
||||
{
|
||||
return [
|
||||
function (Validator $validator) {
|
||||
if ($this->quantity > Product::find($this->product_id)?->stock) {
|
||||
if ($validator->errors()->hasAny(['product_id', 'quantity'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stock = Product::find($this->integer('product_id'))?->stock;
|
||||
|
||||
if ($stock !== null && $this->integer('quantity') > $stock) {
|
||||
$validator->errors()->add('quantity', 'Not enough stock.');
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Validation against mutable state does not prevent a race between validation and persistence. Enforce inventory, uniqueness, and similar invariants with database constraints, atomic updates, or a database transaction as appropriate.
|
||||
|
||||
Reference in New Issue
Block a user