php
50 lines · 8 steps
Validating nested order payloads in Laravel
A FormRequest that authorizes, validates, and humanizes errors for a deeply nested order-creation request.
Explained by
highlit
1<?php
2
3namespace App\Http\Requests;
4
5use Illuminate\Foundation\Http\FormRequest;
6use Illuminate\Validation\Rule;
7
8class StoreOrderRequest extends FormRequest
9{
10 public function authorize(): bool
11 {
12 return $this->user()->can('create', \App\Models\Order::class);
13 }
14
15 public function rules(): array
16 {
17 return [
18 'customer_id' => ['required', 'integer', 'exists:customers,id'],
19 'currency' => ['required', 'string', 'size:3'],
20 'items' => ['required', 'array', 'min:1', 'max:50'],
21 'items.*.product_id' => ['required', 'integer', 'distinct', 'exists:products,id'],
22 'items.*.sku' => ['required', 'string', 'max:64'],
23 'items.*.quantity' => ['required', 'integer', 'min:1', 'max:999'],
24 'items.*.unit_price' => ['required', 'numeric', 'min:0'],
25 'items.*.discount' => ['nullable', 'numeric', 'min:0', 'lte:items.*.unit_price'],
26 'items.*.options' => ['sometimes', 'array'],
27 'items.*.options.*' => ['string', 'max:100'],
28 'shipping.method' => ['required', Rule::in(['standard', 'express', 'pickup'])],
29 'shipping.address_id' => ['required_unless:shipping.method,pickup', 'integer', 'exists:addresses,id'],
30 ];
31 }
32
33 public function messages(): array
34 {
35 return [
36 'items.*.product_id.distinct' => 'The same product appears more than once in this order.',
37 'items.*.quantity.max' => 'You cannot order more than 999 units of a single item.',
38 'items.*.discount.lte' => 'A line item discount cannot exceed its unit price.',
39 ];
40 }
41
42 public function attributes(): array
43 {
44 return [
45 'items.*.product_id' => 'product',
46 'items.*.quantity' => 'quantity',
47 'items.*.unit_price' => 'unit price',
48 ];
49 }
50}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A FormRequest bundles authorization and validation so controllers receive only clean, trusted input.
- 2Dot-and-wildcard notation like `items.*.product_id` validates each element of nested arrays declaratively.
- 3Custom messages and attribute names turn framework validation errors into language users actually understand.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
php
<?php final class RotatingFileLogger {
How a rotating file logger works in PHP
logging
file-rotation
io
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/validating-nested-order-payloads-in-laravel-explained-php-c1eb/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.