Controllers
Controllers are tasked with two primary responsibilities: serving the requested data and constructing the corresponding response.
To generate new controllers
you may use the apiato:generate:controller
interactive command:
php artisan apiato:generate:controller
Definition & Principles
Read Porto SAP Documentation (#Controllers).
Rules
- All API Controllers:
- MUST be placed in the
app/Containers/{Section}/{Container}/UI/API/Controllers
directory. - MUST extend the
App\Ship\Parents\Controllers\ApiController
class. - MUST format their responses via a Transformer.
- MUST be placed in the
- All Web Controllers:
- MUST be placed in the
app/Containers/{Section}/{Container}/UI/WEB/Controllers
directory. - MUST extend the
App\Ship\Parents\Controllers\WebController
class.
- MUST be placed in the
- Controllers:
- MUST only call the
run
ortransactionalRun
method of Actions. - SHOULD pass the Request object to the Action instead of passing data from the request.
- MUST only call the
Folder Structure
app
└── Containers
└── Section
└── Container
└── UI
├── API
│ └── Controllers
│ ├── ControllerA.php
│ ├── ControllerB.php
│ └── ...
└── WEB
└── Controllers
├── ControllerA.php
├── ControllerB.php
└── ...
Code Example
API Controller
use App\Ship\Parents\Controllers\ApiController;
class Controller extends ApiController
{
public function __construct(
private readonly SampleAction $sampleAction,
) {
}
public function __invoke(SampleRequest $request): array
{
$sample = $this->sampleAction->run($request);
return $this->transform($sample, SampleTransformer::class);
}
}
Web Controller
use App\Ship\Parents\Controllers\WebController;
class Controller extends WebController
{
public function show(): Factory|View|Application
{
return view('sectionName@containerName::view-name');
}
}
In case you want to handle the same Action differently based on the UI type (e.g., API, Web, CLI), you can set the
UI on Action with setUI
method.
$action = app(Action::class);
$action->setUI('web');
and get the UI in your Action with getUI
method.
$action->getUI(); // will return 'web'
Response Helpers Methods
transform
This method is incredibly useful and will be used in most cases.
- The first required parameter accepts data as an object or a Collection of objects.
- The second required parameter is the transformer class.
- The third optional parameter allows you to specify the includes that should be returned in the response.
- The fourth optional parameter lets you include metadata in the response. This metadata will be returned under the
meta
key in thecustom
key.
// With Includes
$this->transform($resource, ResourceTransformer::class, ['foo', 'bar']);
// With Meta
$this->transform($resource, ResourceTransformer::class, meta: ['foo' => 'bar', 'baz' => 1]);
// Response
{
"data": {},
"meta": {
"include": [...],
"custom": {
"foo": "bar",
"baz": 1
},
"pagination": {}
}
}
withMeta
This method enables you to add metadata to the response,
and it MUST be used in conjunction with the transform
method.
This is different from the meta
parameter in the transform
method.
This metadata will be returned directly under the meta
key.
You can use this method in conjunction with the meta
parameter in the transform
method.
$metaData = ['foo' => 999, 'bar'];
$this->withMeta($metaData)->transform($sample, SampleTransformer::class, meta: ['foo' => 'bar', 'baz' => 1]);
// Response
{
"data": {},
"meta": {
"foo": 999,
"0": "bar",
"include": [...],
"custom": {
"foo": "bar",
"baz": 1
},
"pagination": {}
}
}
json
This method allows you to pass an array of data that will be represented as JSON.
$this->json($data)
created
This method allows you to return a response with a 201
status code.
$this->created($data)
deleted
This method allows you to return a response with a 202
status code.
$this->deleted($deletedModel)
// Response
{
"message": "Model (1) Deleted Successfully."
}
accepted
This method allows you to return a response with a 202
status code.
$this->accepted($data)
noContent
This method allows you to return a response with a 204
status code.
$this->noContent()