How to Log Model Changes with Spatie Laravel Activitylog
When a Laravel Eloquent model changes, Spatie Laravel Activitylog can save a record of that event in the activity_log database table. An…
When a Laravel request submits a list of records, such as the products in an order, validate the list’s structure and each value in every record. Laravel’s * wildcard applies rules to each array item, while dot notation names a field inside an item. Add rules to the parent field too, so Laravel checks that it is an array and, when required, that it has enough items.
An order can contain a products array with a name and price for each product. A Form Request is a Laravel class that organizes request validation, so you can define these rules in one place. Validate the parent array and each nested field separately.
Add a rule to the parent field to check that it is an array, then use wildcard paths to check its contents. Here, products must be an array with at least one item. Each item must be an array, and each product must have a name and a numeric price.
use Illuminate\Foundation\Http\FormRequest;
class StoreOrderRequest extends FormRequest
{
public function rules(): array
{
return [
'products' => ['required', 'array', 'min:1'],
'products.*' => ['required', 'array'],
'products.*.name' => ['required', 'string'],
'products.*.price' => ['required', 'numeric', 'min:0'],
];
}
}
The wildcard in products.*.name tells Laravel to check the name field on every product. It does not check whether products itself is an array; the rule on products handles that. This distinction is central to Laravel array validation.
After Laravel validates the request, a controller can use the validated values:
public function store(StoreOrderRequest $request)
{
$data = $request->validated();
// Use the validated product data.
}
For deeper structures, add a wildcard at each array level. A path such as teams.*.members.*.name applies to the name field of every member in every team. Add rules for the parent arrays, such as teams and teams.*.members, as well as for the nested fields. Dot notation supports nested array paths.
Laravel uses a field’s path in the input to identify a failing value. If the first product has no name, the error key is products.0.name. The 0 identifies the first product, so a client or form can show the message beside the correct field.
A Form Request can replace a generic validation message with wording that makes sense to the person submitting the form:
public function messages(): array
{
return [
'products.*.name.required' => 'Each product needs a name.',
'products.*.price.numeric' => 'Each product price must be a number.',
];
}
Messages with wildcard paths apply to matching nested fields. Laravel’s form-array validation example also discusses custom messages for submitted arrays. If a form shows errors beside individual rows, use the error path to match each message to its field.
A rule for one field can depend on another field in the same product. For example, a product’s serial_number might be required only when its type is physical. One approach is to add rules for each submitted index in the Form Request, so each rule applies to the product at that index. Check that the input is an array before looping over it, because a malformed request might submit a different type.
use Illuminate\Validation\Rule;
public function rules(): array
{
$rules = [
'products' => ['required', 'array', 'min:1'],
'products.*' => ['required', 'array'],
'products.*.type' => ['required', 'string'],
'products.*.serial_number' => ['nullable', 'string'],
];
$products = $this->input('products', []);
if (is_array($products)) {
foreach ($products as $index => $product) {
if (! is_array($product)) {
continue;
}
$rules["products.$index.serial_number"] = [
Rule::requiredIf(($product['type'] ?? null) === 'physical'),
'nullable',
'string',
];
}
}
return $rules;
}
To compare multiple array items, such as when rejecting duplicate combinations of fields, write a custom validation rule that checks the full input. Laravel’s DataAwareRule interface gives a rule access to the complete submitted data array; a nested-validation example discusses this approach. Keep the comparison logic explicit and test it with the input shapes your request accepts. Code that gets an array index from an attribute string depends on the exact path format, so avoid fragile string parsing.
Laravel also provides Rule::forEach to apply rules to array items. The available patterns depend on your Laravel version, so check the documentation for the version installed in your project before using a version-specific API.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com