Repository navigation
Resource
Viames Marino edited this page Oct 19, 2026
·
3 revisions
Pair\Api\Resource is the base transformer for API output.
It decouples domain/ActiveRecord objects from JSON response format.
In Pair v4, it remains a compatibility bridge. Prefer ReadModel and the readModel configuration key for new API contracts.
Stores the underlying object/data instance.
Must be implemented in each resource class.
Returns toArray() so resources are directly serializable with json_encode().
Transforms many items into an array of resource arrays.
<?php
namespace App\Api\Resources;
use Pair\Api\Resource;
class UserResource extends Resource {
public function toArray(): array
{
$u = $this->data;
return [
'id' => (int)$u->id,
'name' => (string)$u->name,
'email' => (string)$u->email,
'active' => (bool)$u->active,
];
}
}Single item:
$data = (new UserResource($user))->toArray();
ApiResponse::respond($data);Collection:
$data = UserResource::collection($users);
ApiResponse::respond($data);In model API config:
$config = [
'resource' => App\Api\Resources\UserResource::class,
];Then CrudController automatically uses your transformer.
class UserResource extends \Pair\Api\Resource {
public function toArray(): array
{
$u = $this->data;
return [
'id' => (int)$u->id,
'email' => (string)$u->email,
'group' => $u->groupId ? [
'id' => (int)$u->groupId
] : null,
];
}
}class OrderResource extends \Pair\Api\Resource {
public function toArray(): array
{
$o = $this->data;
return [
'id' => (int)$o->id,
'total' => (float)$o->total,
'paid' => (bool)$o->paid,
'createdAt' => $o->formatDateTime('createdAt', 'Y-m-d H:i:s'),
'note' => $o->note ? (string)$o->note : null,
];
}
}$orders = \App\Orm\Order::latest()->limit(50)->get();
$data = \App\Api\Resources\OrderResource::collection($orders);
\Pair\Api\ApiResponse::respond($data);- Leaking internal model fields by returning raw
toArray()everywhere. - Inconsistent types across endpoints (string vs int/bool).
- Heavy N+1 relation calls inside
toArray()without caching strategy.
See also: CrudController, ApiExposable, ApiResponse.
Home · Setup · Configuration
Build with Pair 4
- Generator
- Controllers and responses
- Read models
- ActiveRecord and queries
- Forms and validation
- PairUI.js and HTML fragments
APIs and authentication
- API guide and CRUD
- Middleware and rate limits
- Users, sessions, and ACL
- Passkeys and social login
- Native mobile setup
Integrate and operate
- Integrations
- Runtime extensions and adapter keys
- Cache and cache stores
- Logs and observability
- PWA and push
- Packages and distribution
- Upgrade to v4