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

Walkthrough

Space play step click any line
Three takeaways
  1. 1A FormRequest bundles authorization and validation so controllers receive only clean, trusted input.
  2. 2Dot-and-wildcard notation like `items.*.product_id` validates each element of nested arrays declaratively.
  3. 3Custom messages and attribute names turn framework validation errors into language users actually understand.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Validating nested order payloads in Laravel — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code