allyson / arch-laravel
CRUD architecture for laravel projects.
Installs: 573
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/allyson/arch-laravel
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.2
- laravel/framework: ^10.10
- laravel/sanctum: ^2.14.1|^3.0
- laravel/tinker: ^2.7
Requires (Dev)
- fakerphp/faker: ^1.9.1
- laravel/sail: ^1.0.1
- mockery/mockery: ^1.4.4
- nunomaduro/collision: ^6.1
- phpunit/phpunit: ^9.5.10
- spatie/laravel-ignition: ^1.0
This package is auto-updated.
Last update: 2025-10-06 03:54:41 UTC
README
Allyson Arch-Laravel é um pacote PHP que fornece uma maneira simples e elegante de organizar a arquitetura do seu aplicativo Laravel. Tem como objetivo promover a modularidade e escalabilidade, fornecendo um conjunto de ferramentas e convenções que facilitam a estruturação da base de código do seu aplicativo em módulos independentes.
Installation
Você pode instalar o pacote via composer:
composer require allyson/arch-laravel
Como usar
BaseRequest
- File:
./Example/ExampleRequest.php
<?php namespace App\Http\Requests\Example; use ArchCrudLaravel\App\Http\Requests\BaseRequest; use App\Models\Example; abstract class ExampleRequest extends BaseRequest { protected $model = Example::class; protected function hasGroupPermission(): bool { // Code... } protected function isOwner(string $method): bool { // Code... } }
A classe abstrata BaseRequest fornece os métodos: indexRules(), updateRules() e destroyRules(), eles retornam um array com regras que permitem o funcionamento adequado do BaseService para os métodos index(), update(), destroy(), respectivamente. Podendo ser concatenados com suas próprias regras de negócios. Também é necessário implementar os métodos hasGroupPermission() e isOwner(), que podem ser implementados de acordo com as necessidades do aplicativo e regras de negócio para autorizar o acesso e uso do recurso.
- File:
./Example/IndexRequest.php
<?php namespace App\Http\Requests\Example; class IndexRequest extends ExampleRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize(): bool { return $this->hasGroupPermission(); } /** * Get the validation rules that apply to the request. * * @return array */ public function rules(): array { return $this->indexRules(); } }
O método indexRules() permite navegação através de paginação, definindo o número de itens por página e estabelecendo os critérios de ordenação e filtragem para a consulta.
JSON Request Example
{
"perPage": 15,
"page": 1,
"orderBy": {
"id": "asc"
},
"wheres": [
{
"column": "name",
"condition": "like",
"search": "%zeck%"
},
{
"column": "years",
"condition": ">",
"search": "18"
}
],
"orWheres": [
{
"column": "id",
"condition": "=",
"search": "50"
}
]
}
Detalhes:
page(integer): Este parâmetro é usado para especificar o número da página dos resultados a serem recuperados. Deve ser um valor inteiro.perPage(integer): Este parâmetro é usado para especificar o número de itens por página a serem recuperados. Deve ser um valor inteiro.orderBy(array): Este parâmetro é usado para especificar os critérios de ordenação para a consulta. Deve ser uma matriz contendo um ou mais critérios de ordenação. Cada critério de ordenação é uma matriz contendo dois elementos: a coluna pela qual ordenar e a direção da ordenação (ascendente ou descendente). O nome da coluna é validado para garantir que existe na tabela especificada pela variável$table, e a direção da ordenação é validada para garantir que seja 'asc' ou 'desc'.wheres(array): Este parâmetro é usado para especificar os critérios de filtragem para a consulta. Deve ser uma matriz contendo um ou mais critérios de filtragem. Cada critério de filtragem é uma matriz contendo três elementos: a coluna pela qual filtrar, a condição de filtragem (por exemplo, '=', '<', '>=', 'like', etc.) e o valor a ser procurado. O nome da coluna é validado para garantir que existe na tabela especificada pela variável$table, e a condição de filtragem é validada para garantir que seja uma das condições permitidas especificadas pelos$conditionsOperators.wheres.*.column(string): Este parâmetro é o nome da coluna pela qual filtrar. É um valor de string obrigatório que deve existir no array$searchabledo modelo e deve existir na tabela especificada pela variável$table.wheres.*.condition(string): Este parâmetro é a condição de filtragem a ser usada para a coluna especificada. É um valor de string obrigatório que deve ser uma das condições permitidas especificadas pela constante$conditionsOperators.wheres.*.search(string): Este parâmetro é o valor a ser procurado na coluna especificada. É um valor de string obrigatório.- orWheres (array): Este parâmetro é usado para especificar critérios de filtragem adicionais para a consulta. Funciona da mesma forma que o parâmetro wheres, mas as condições de filtragem são combinadas usando o
operador ORem vez dooperador AND. orWheres.*.column(string): Este parâmetro é o nome da coluna pela qual filtrar. É um valor de string obrigatório que deve existir no array$searchabledo modelo e deve existir na tabela especificada pela variável$table.orWheres.*.condition(string): Este parâmetro é a condição de filtragem a ser usada para a coluna especificada. É um valor de string obrigatório que deve ser uma das condições permitidas especificadas pela constante$conditionsOperators.orWheres.*.search(string): Este parâmetro é o valor a ser procurado na coluna especificada. É um valor de string obrigatório.
public array $conditionsOperators = ['=', '!=', '<>', '<', '>', '<=', '>=', 'LIKE', 'NOT LIKE', 'IS NULL', 'IS NOT NULL'];
- File:
./Example/DestroyRequest.php
<?php namespace App\Http\Requests\Example; class DestroyRequest extends ExampleRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize(): bool { return $this->hasGroupPermission(); } /** * Get the validation rules that apply to the request. * * @return array */ public function rules(): array { return $this->destroyRules(); } }
O método destroyRules() tem como propósito possibilitar que o BaseService elimine um recurso de forma permanente, juntamente com seus registros dependentes, ou realize uma exclusão suave. Ao aplicar o método destroyRules(), basta fornecer o parâmetro force: true na solicitação para que a estrutura remova o recurso de modo definitivo, junto aos seus vínculos, de maneira recursiva. Caso o parâmetro force não seja fornecido na requisição ou seja igual a false, o comportamento padrão do método delete() será remover o recurso de forma permanente apenas se não estiver em uso. Se estiver em uso, será executada uma exclusão suave. Tanto a exclusão permanente (hard delete) quanto a suave (soft delete) ocorrem de forma recursiva.
JSON Request Example
{
"force": true
}
- File:
./Example/UpdateRequest.php
<?php namespace App\Http\Requests\Example; class UpdateRequest extends ExampleRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize(): bool { return $this->hasGroupPermission(); } /** * Get the validation rules that apply to the request. * * @return array */ public function rules(): array { return [ ...$this->updateRules() 'field' => 'bail|required|integer', 'field2' => 'bail|nullable|string' ]; } }
O método updateRules() possui um conjunto de validações que possibilitará que o BaseService restaure o registro, juntamente com seus vínculos. Para isso basta fornecer o parâmetro $model::DELETED_AT como nulo na solicitação para que a estrutura reabilite o registro de maneira recursiva.
JSON Request Example
{
"deleted_at": null
}
BaseModel
A classe BaseModel é uma classe abstrata que pode ser estendida para criar modelos na sua aplicação Laravel. Abaixo está um exemplo de como usar a classe BaseModel para criar um modelo Paises.
- File:
./Example/Paises.php
<?php namespace App\Models; use ArchCrudLaravel\App\Models\BaseModel; use Illuminate\Database\Eloquent\Relations\{ HasMany }; class Paises extends BaseModel { public $table = 'paises'; protected $fillable = [ 'nome', self::DELETED_AT ]; public array $searchable = [ 'nome', self::DELETED_AT ]; public function estados(): HasMany { return $this->hasMany(Estados::class, 'paisId'); } }
No exemplo acima, a propriedade $searchable permite que você especifique quais campos podem ser pesquisados ao usar o método index() da classe BaseService. Isso é útil ao implementar a funcionalidade de pesquisa na sua aplicação.
Além disso, a classe BaseModel fornece as constantes DELETED_AT, UPDATED_AT e CREATED_AT para permitir fácil referenciamento dos timestamps padrão do Laravel. No entanto, você também pode sobrescrever essas constantes fornecendo uma string contendo o nome da coluna na tabela.
Para o correto funcionamento do método $service->destroy(), os relacionamentos DEVEM ser tipados.
BaseCollection
BaseResource
BaseService
O BaseService é uma classe fornecida pelo Arch-Laravel que pode ser usada para simplificar a criação de serviços no Laravel. Aqui está um exemplo de como utilizá-lo:
- File:
./Example/BaseService.php
<?php namespace App\Services\Api; use App\Http\Resources\Tratamentos\ExampleCollection; use App\Http\Resources\Tratamentos\ExampleResource; use App\Models\Tratamentos\Example; use ArchCrudLaravel\App\Services\BaseService; class ExampleService extends BaseService { protected $nameModel = Example::class; protected $nameCollection = ExampleCollection::class; protected $nameResource = ExampleResource::class; }
Neste exemplo, criamos um novo serviço chamado ExampleService que estende a classe BaseService.
Propriedades
$nameModel: O nome da classe do modelo que o serviço utiliza, se o seu serviço não usar um modelo, não é necessário informar essa propriedade.$nameCollection: O nome da classe de recurso de coleção que o serviço retorna quando várias instâncias do modelo são solicitadas, o uso desta propriedade é opcional.$nameResource: O nome da classe de recurso do item que o serviço retorna quando uma única instância do modelo é solicitada, o uso desta propriedade é opcional.$onTransaction: Controla se os rollbacks de banco de dados serão realizados se ocorrer uma exceção. O valor padrão étrue.$onCache: Controla se os resultados dos métodosshow()eindex()serão armazenados em cache. O métodoupdate()cria e atualiza os valores do cache. O valor padrão étrue.$relationships: Você pode inserir um array com os relacionamentos que deseja exibir. É possível usar o métodogetRelationshipNames()para obter todos os relacionamentos. O padrão é[](um array vazio).$ignoreRelationships: Você pode inserir um array com os nomes dos relacionamentos que deseja ignorar no métodohardDelete(). É possível usar o métodogetRelationshipNames()para obter todos os relacionamentos. O padrão é[](um array vazio).$ignoreTypesOfRelationships: Você pode inserir um array com os tipos de relacionamentos que deseja ignorar no métodohardDelete(). O padrão é[](um array vazio).
Todas essas propriedades podem ser definidas no método __constructor() ou nos métodos CRUD, da forma que fizer mais sentido em sua aplicação.
Metódos
O BaseService conta com os métodos que podem ser empregados para adaptar o fluxo de processos conforme as exigências dos seus aplicativos:
beforeInsert(): executado antes da inserção de dados.afterInsert(): executado após a inserção de dados.beforeList(): executado antes da listagem de dados.afterList(): executado após a listagem de dados.beforeSelect(): executado antes da seleção de um registro.afterSelect(): executado após a seleção de um registro.beforeModify(): executado antes da modificação de um registro.afterModify(): executado após a modificação de um registro.beforeDelete(): executado antes da exclusão de um registro.afterDelete(): executado após a exclusão de um registro.
Além disso, há métodos de controle que podem ser úteis nos cases de seu serviço. Esses métodos incluem:
hasRelationships(): retorna umtruese o modelo tiver relacionamentos definidos.getRelationshipNames(): retorna os nomes dos relacionamentos do modelo.setCustomExceptionMappings(): permite personalizar os tratamentos exceções, padronizando as respostas da API. Cada item do parâmetro$mappingsdeve ser uma instância deCustomExceptionMapping.
Vantagens
A utilização da classe BaseService traz consigo inúmeras vantagens, como:
- Operações CRUD padrão: O
BaseServiceoferece um conjunto padrão de operações CRUD (create, read, update e delete), facilitando a implementação destas funcionalidades nos serviços derivados. - Respostas consistentes: A classe fornece um conjunto padrão de códigos de resposta, garantindo respostas consistentes e padronizadas em toda a aplicação.
- Gerenciamento de relacionamentos: Quando a propriedade
$nameModelé informada, o métododestroy()doBaseServiceverifica se o recurso está sendo utilizado por outras entidades no banco de dados, utilizando os relacionamentos declarados na model. Um soft delete será executado por padrão caso existam vínculos, mas é possível forçar a remoção permanente do recurso, juntamente com a desanexação das entidades relacionadas, utilizando o parâmetroforce: true. - Recuperação de soft deletes: É possível reverter os soft deletes ao atualizar o campo
$model::DELETED_ATdo registro, sendo a restauração executada de maneira recursiva.
Ao estender a classe BaseService, você garante uma base sólida e consistente para os serviços de sua aplicação, agilizando o desenvolvimento e facilitando a manutenção.
Controller
Aqui está um exemplo de como usar o BaseController fornecido pelo Arch-Laravel em conjunto com o ExampleService criado anteriormente:
- File:
./Example/BaseController.php
<?php namespace App\Http\Controllers\Api; use ArchCrudLaravel\App\Http\Controllers\BaseController; use App\Http\Requests\Example\{ DeleteRequest, indexRules, StoreRequest, ShowRequest, UpdateRequest }; use App\Services\Api\ExampleService; use Illuminate\Http\Response; class ExampleController extends BaseController { protected $nameService = ExampleService::class; // These methods are optional and correspond to standard CRUD actions public function store(StoreRequest $request): Response { return $this->service->store($request->validated()); } public function index(IndexRequest $request): Response { return $this->service->index($request->validated()); } public function show(ShowRequest $request, int $id): Response { return $this->service->show($request->validated(), $id); } public function update(UpdateRequest $request, int $id): Response { return $this->service->update($request->validated(), $id); } public function destroy(DeleteRequest $request, int $id): Response { return $this->service->destroy($request->validated(), $id); } // Additional methods for custom actions or endpoints can be defined as needed public function customAction(Request $request): Response { // ... } }
Neste exemplo, criamos um novo controlador chamado ExampleController, que estende a classe BaseController. Também definimos uma propriedade $nameService para indicar qual serviço este controlador utiliza. O serviço ExampleService é usado para lidar com as operações CRUD subjacentes e retorna a resposta correta com base no resultado da operação.
Cada método no controlador corresponde a uma ação padrão CRUD. O método store() lida com a criação de um novo recurso, o método index() lida com a listagem de recursos, o método show() lida com a exibição de um recurso específico, o método update() lida com a atualização de um recurso existente e o método destroy() lida com a exclusão de um recurso existente, eles retornam uma instância da classe Response do Laravel, que representa a resposta HTTP retornada pelo controlador.
Todos os métodos do CRUD recebem uma instância de uma classe de Request (por exemplo, StoreRequest ou UpdateRequest), que é usada para validar e recuperar os dados enviados pelo cliente. O método $request->validated() é DEVE sempre ser usado para recuperar os dados validados da solicitação.
Credits
License
The MIT License (MIT). Please see License File for more information.