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/Controllersdirectory. - MUST extend the
App\Ship\Parents\Controllers\ApiControllerclass. - 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/Controllersdirectory. - MUST extend the
App\Ship\Parents\Controllers\WebControllerclass.
- MUST be placed in the
- Controllers:
- MUST only call the
runortransactionalRunmethod 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
metakey in thecustomkey.
// 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()