Escaped text and raw output
To display a comment as text inside an HTML element, use normal escaping through {{ $comment }}. The {!! $comment !!}
form emits the value without that escaping; trim or storage in a database does not make user content safe. Define the contract before choosing output: ordinary text does not need to interpret author-supplied markup. Escaping is context-dependent and does not authorize publishing arbitrary data; private fields still require an access decision.
Component data and defaults
In a component declaring message, message="$notice" passes a literal string, while :message="$notice" evaluates the PHP variable. Also inspect additional attributes: merge(["type"=>"button"]) supplies a default, but type="submit" at the invocation overrides it.
The class behavior that combines values must not be generalized to type. When reviewing a button unintentionally submitting a form, start with the effective invocation and resulting attribute rather than assuming the default was mandatory.
Method and token are distinct fields
An HTML POST form can target a PATCH route through @method("PATCH"), which creates _method. @csrf supplies the token field used in the corresponding protection flow. Neither directive substitutes for the other: method identifies the route contract, while the token participates in request protection.
Retain server-side validation and authorization as well. Hiding the form with @can improves the interface for users lacking permission, but does not prevent a directly constructed request to the same endpoint.
Data in a JavaScript expression
When a view receives an array to initialize JavaScript, avoid manually constructing quotes and separators. Js::from($settings) prepares an escaped representation for HTML inclusion and produces the JavaScript expression reconstructing the value.
Documentation recommends supplying an existing variable rather than a complex expression in the template. Do not confuse this script context with an API’s JSON body or raw HTML output. The consumer and insertion location determine the required serialization contract.
Project fields and defer conditional computation
A JsonResource toArray defines the data representation; returning only id and display_name is an explicit field choice. when removes a key when its condition fails, but PHP evaluates arguments before the call: when(false, buildSummary()) still calls buildSummary.
Pass a closure when calculation should occur only with permission. Final omission and earlier execution are distinct evidence. The condition must come from the appropriate access rule, and the endpoint remains responsible for authorizing the base resource.
Missing relationships, empty collections and counts
whenLoaded receives the relationship name to avoid reading and unnecessarily loading it. If it was not loaded, the key is omitted in an ordinary resource; if it was loaded and has no elements, it can be an empty collection. These states are not equivalent for the consumer. whenCounted applies the distinction to aggregates: tickets_count loaded as zero is a known count and can be included, while an absent aggregate is omitted. Neither helper automatically loads all models to establish absence.
Pagination is part of the representation
A paginated collection returned through ordinary resources retains the data, links and meta envelope even when withoutWrapping was called. A client expecting a root array can fail despite correct models. Document response shape and states, including page navigation, rather than relying solely on global wrapping configuration.
Any custom transformation must be agreed and observed in consumers; it does not follow from loading more relationships or changing the data query.
{{-- Blade fragments for reading; surrounding application omitted. --}}
<p>{{ $comment }}</p>
<x-alert :message="$notice" />
<form method="POST" action="{{ route('invoices.update', $invoice) }}">
@csrf
@method('PATCH')
{{-- Authorized input fields would be defined here. --}}
</form>
<script>
const pageSettings = {{ Js::from($settings) }};
</script>
<?php
// Separate JsonResource::toArray excerpt; route already authorized the model.
return [
'id' => $this->id,
'tickets' => TicketResource::collection($this->whenLoaded('tickets')),
'tickets_count' => $this->whenCounted('tickets'),
'internal_summary' => $this->when(
$request->user()->can('viewInternal', $this->resource),
fn () => $this->buildInternalSummary()
),
];
The Blade fragments show escaped text, a variable passed to a component, PATCH over POST and data prepared for JavaScript. The PHP fragment belongs separately to a JsonResource: it includes already loaded relationships and counts and defers the internal summary until permission passes.
It assumes an authenticated user, policy, summary method, ticket resource and view context supplied by the application. It is neither a complete file nor an execution task.
Common pitfalls
Using raw output for text comments; confusing literal attributes with PHP expressions; treating merge type=button as mandatory; expecting when to undo argument evaluation; interpreting unloaded relationships as empty; expecting withoutWrapping to remove the paginated envelope.
Related topics: Validation and request contracts · Eloquent, relationships and query cost · Authentication, authorization and sessions
Representation is an explicit contract of fields, context and conditions. Choose appropriate escaping and serialization, defer computation with closures when required, and document absence states. The view and resource complement endpoint authorization; they do not replace it.
Reference: Resource response projection · Laravel 13.x; PHP 8.3+