Development
#api
laravel-patterns
Patrones de arquitectura Laravel, routing/controladores, Eloquent ORM, capas de servicio, colas, eventos, caché y API resources para aplicaciones en producción.
DeepseekModel
Curated skill
Quality Excellent · 90
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-laravel-patterns-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name laravel-patterns description Patrones de arquitectura Laravel, routing/controladores, Eloquent ORM, capas de servicio, colas, eventos, caché y API resources para aplicaciones en producción. origin ECC Patrones de Desarrollo Laravel Patrones de arquitectura Laravel de nivel producción para aplicaciones escalables y mantenibles. Cuándo Usar Construir aplicaciones web o APIs con Laravel Estructurar controladores, servicios y lógica de dominio Trabajar con modelos Eloquent y relaciones Diseñar APIs con resources y paginación Agregar colas, eventos, caché y jobs en segundo plano Cómo Funciona Estructurar la app con límites claros (controladores -> servicios/actions -> modelos). Usar bindings explícitos y bindings con scope para mantener el routing predecible; aplicar autorización para el control de acceso. Favorecer modelos tipados, casts y scopes para mantener la lógica de dominio consistente. Mantener el trabajo intensivo de IO en colas y cachear lecturas costosas. Centralizar la configuración en config/* y mantener los entornos explícitos. Ejemplos Estructura del Proyecto Usar un layout convencional de Laravel con límites de capa claros (HTTP, servicios/actions, modelos). Layout Recomendado app/ ├── Actions/ # Casos de uso de un solo propósito ├── Console/ ├── Events/ ├── Exceptions/ ├── Http/ │ ├── Controllers/ │ ├── Middleware/ │ ├── Requests/ # Validación con Form Requests │ └── Resources/ # API resources ├── Jobs/ ├── Models/ ├── Policies/ ├── Providers/ ├── Services/ # Servicios de dominio coordinadores └── Support/ config/ database/ ├── factories/ ├── migrations/ └── seeders/ resources/ ├── views/ └── lang/ routes/ ├── api.php ├── web.php └── console.php Controladores -> Servicios -> Actions Mantener los controladores delgados. Poner la orquestación en servicios y la lógica de un solo propósito en actions. final class CreateOrderAction { public function __construct ( private OrderRepository $orders ) {} public function handle ( CreateOrderData $data ): Order { return $this ->orders-> create ( $data ); } } final class OrdersController extends Controller { public function __construct ( private CreateOrderAction $createOrder ) {} public function store ( StoreOrderRequest $request ): JsonResponse { $order = $this ->createOrder-> handle ( $request -> toDto ()); return response ()-> json ([ 'success' => true , 'data' => OrderResource :: make ( $order ), 'error' => null , 'meta' => null , ], 201 ); } } Routing y Controladores Preferir route-model binding y controladores de recursos para mayor claridad. use Illuminate \ Support \ Facades \ Route ; Route :: middleware ( 'auth:sanctum' )-> group (function () { Route :: apiResource ( 'projects' , ProjectController :: class ); }); Route Model Binding con Scope Usar bindings con scope para prevenir acceso entre tenants. Route :: scopeBindings ()-> group (function () { Route :: get ( '/accounts/{account}/projects/{project}' , [ ProjectController :: class , 'show' ]); }); Rutas Anidadas y Nombres de Binding Mantener prefijos y rutas consistentes para evitar doble anidamiento (ej. conversation vs conversations ). Usar un único nombre de parámetro que coincida con el modelo vinculado (ej. {conversation} para Conversation ). Preferir bindings con scope al anidar para aplicar relaciones padre-hijo. use App \ Http \ Controllers \ Api \ ConversationController ; use App \ Http \ Controllers \ Api \ MessageController ; use Illuminate \ Support \ Facades \ Route ; Route :: middleware ( 'auth:sanctum' )-> prefix ( 'conversations' )-> group (function () { Route :: post ( '/' , [ ConversationController :: class , 'store' ])-> name ( 'conversations.store' ); Route :: scopeBindings ()-> group (function () { Route :: get ( '/{conversation}' , [ ConversationController :: class , 'show' ]) -> name ( 'conversations.show' ); Route :: post ( '/{conversation}/messages' , [ MessageController :: class , 'store' ]) -> name ( 'conversation-messages.store' ); Route :: get ( '/{conversation}/messages/{message}' , [ MessageController :: class , 'show' ]) -> name ( 'conversation-messages.show' ); }); }); Si deseas que un parámetro resuelva a una clase de modelo diferente, definir un binding explícito. Para lógica de binding personalizada, usar Route::bind() o implementar resolveRouteBinding() en el modelo. use App \ Models \ AiConversation ; use Illuminate \ Support \ Facades \ Route ; Route :: model ( 'conversation' , AiConversation :: class ); Bindings del Contenedor de Servicios Vincular interfaces a implementaciones en un service provider para una inyección de dependencias clara. use App \ Repositories \ EloquentOrderRepository ; use App \ Repositories \ OrderRepository ; use Illuminate \ Support \ ServiceProvider ; final class AppServiceProvider extends ServiceProvider { public function register ( ): void { $this ->app-> bind ( OrderRepository :: class , EloquentOrderRepository :: class ); } } Patrones de Modelos Eloquent Configuración del Modelo final class Project extends Model { use HasFactory ; protected $fillable = [ 'name' , 'owner_id' , 'status' ]; protected $casts = [ 'status' => ProjectStatus :: class , 'archived_at' => 'datetime' , ]; public function owner ( ): BelongsTo { return $this -> belongsTo ( User :: class , 'owner_id' ); } public function scopeActive ( Builder $query ): Builder { return $query -> whereNull ( 'archived_at' ); } } Casts Personalizados y Objetos de Valor Usar enums u objetos de valor para tipado estricto. use Illuminate \ Database \ Eloquent \ Casts \ Attribute ; protected $casts = [ 'status' => ProjectStatus :: class , ]; protected function budgetCents ( ): Attribute { return Attribute :: make ( get : fn ( int $value ) => Money :: fromCents ( $value ), set: fn ( Money $money ) => $money -> toCents (), ); } Eager Loading para Evitar N+1 $orders = Order :: query () -> with ([ 'customer' , 'items.product' ]) -> latest () -> paginate ( 25 ); Query Objects para Filtros Complejos final class ProjectQuery { public function __construct ( private Builder $query ) {} public function ownedBy ( int $userId ): self { $query = clone $this ->query; return new self ( $query -> where ( 'owner_id' , $userId )); } public function active ( ): self { $query = clone $this ->query; return new self ( $query -> whereNull ( 'archived_at' )); } public function builder ( ): Builder { return $this ->query; } } Global Scopes y Soft Deletes Usar global scopes para filtrado por defecto y SoftDeletes para registros recuperables. Usar ya sea un global scope o un named scope para el mismo filtro, no ambos, a menos que se desee comportamiento en capas. use Illuminate \ Database \ Eloquent \ SoftDeletes ; use Illuminate \ Database \ Eloquent \ Builder ; final class Project extends Model { use SoftDeletes ; protected static function booted ( ): void { static :: addGlobalScope ( 'active' , function (Builder $builder ): void { $builder -> whereNull ( 'archived_at' ); }); } } Query Scopes para Filtros Reutilizables use Illuminate \ Database \ Eloquent \ Builder ; final class Project extends Model { public function scopeOwnedBy ( Builder $query , int $userId ): Builder { return $query -> where ( 'owner_id' , $userId ); } } // En servicio, repositorio, etc. $projects = Project :: ownedBy ( $user ->id)-> get (); Transacciones para Actualizaciones Multi-Paso use Illuminate \ Support \ Facades \ DB ; DB:: transaction (function (): void { $order -> update ([ 'status' => 'paid' ]); $order -> items ()-> update ([ 'paid_at' => now ()]); }); Migraciones Convención de Nomenclatura Los nombres de archivo usan timestamps: YYYY_MM_DD_HHMMSS_create_users_table.php Las migraciones usan clases anónimas (sin clase con nombre); el nombre del archivo comunica la intención Los nombres de tablas son snake_case y plurales por defecto Ejemplo de Migración use Illuminate \ Database \ Migrations \ Migration ; use Illuminate \ Database \ Schema \ Blueprint ; use Illuminate \ Support \ Facades \ Schema ; return new class extends Migration { public function up ( ): void { Schema :: create ( 'orders' , function (Blueprint $table ): void { $table -> id (); $table -> foreignId ( 'customer_id' )-> constrained ()-> cascadeOnDelete (); $table -> string ( 'status' , 32 )-> index (); $table -> unsignedInteger ( 'total_cents' ); $table -> timestamps (); }); } public function down ( ): void { Schema :: dropIfExists ( 'orders' ); } }; Form Requests y Validación Mantener la validación en Form Requests y transformar las entradas a DTOs. use App \ Models \ Order ; final class StoreOrderRequest extends FormRequest { public function authorize ( ): bool { return $this -> user ()?-> can ( 'create' , Order :: class ) ?? false ; } public function rules ( ): array { return [ 'customer_id' => [ 'required' , 'integer' , 'exists:customers,id' ], 'items' => [ 'required' , 'array' , 'min:1' ], 'items.*.sku' => [ 'required' , 'string' ], 'items.*.quantity' => [ 'required' , 'integer' , 'min:1' ], ]; } public function toDto ( ): CreateOrderData { return new CreateOrderData ( customerId: ( int ) $this -> validated ( 'customer_id' ), items: $this -> validated ( 'items' ), ); } } API Resources Mantener respuestas de API consistentes con resources y paginación. $projects = Project :: query ()-> active ()-> paginate ( 25 ); return response ()-> json ([ 'success' => true , 'data' => ProjectResource :: collection ( $projects -> items ()), 'error' => null , 'meta' => [ 'page' => $projects -> currentPage (), 'per_page' => $projects -> perPage (), 'total' => $projects -> total (), ], ]); Eventos, Jobs y Colas Emitir eventos de dominio para efectos secundarios (emails, analíticas) Usar jobs en cola para trabajo lento (reportes, exportaciones, webhooks) Preferir handlers idempotentes con reintentos y backoff Caché Cachear endpoints y consultas costosas con muchas lecturas Invalidar cachés en eventos del modelo (created/updated/deleted) Usar tags al cachear datos relacionados para facilitar la invalidación Configuración y Entornos Mantener secretos en .env y configuración en config/*.php Usar sobreescrituras de configuración por entorno y config:cache en producción
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.