{"id":311,"date":"2026-07-14T16:15:07","date_gmt":"2026-07-14T23:15:07","guid":{"rendered":"https:\/\/www.mariatech.com.mx\/blog\/?p=311"},"modified":"2026-07-14T16:15:07","modified_gmt":"2026-07-14T23:15:07","slug":"arquitectura-de-un-proyecto-de-laravel","status":"publish","type":"post","link":"https:\/\/www.mariatech.com.mx\/blog\/laravel-php\/arquitectura-de-un-proyecto-de-laravel\/","title":{"rendered":"Arquitectura de un proyecto de Laravel"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Cuando un proyecto Laravel empieza a crecer, una de las primeras se\u00f1ales de desorden aparece en los controladores: m\u00e9todos cada vez m\u00e1s largos, validaciones mezcladas con consultas, reglas de negocio dentro del mismo archivo y operaciones repetidas en varias partes del sistema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Al inicio puede parecer pr\u00e1ctico resolver todo dentro del controller, pero con el tiempo esa decisi\u00f3n vuelve m\u00e1s dif\u00edcil mantener, probar y escalar el proyecto. Por eso conviene separar responsabilidades entre <strong>Controllers<\/strong>, <strong>Form Requests<\/strong>, <strong>Services<\/strong> y <strong>Models<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La idea no es complicar la arquitectura, sino poner cada pieza en el lugar correcto.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Resumen r\u00e1pido<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Una forma sencilla de entenderlo es esta:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Elemento<\/th><th>Responsabilidad principal<\/th><\/tr><\/thead><tbody><tr><td>Controller<\/td><td>Controla el flujo HTTP: recibe la petici\u00f3n, llama lo necesario y responde.<\/td><\/tr><tr><td>Form Request<\/td><td>Valida y prepara los datos antes de llegar al controller.<\/td><\/tr><tr><td>Service<\/td><td>Ejecuta la l\u00f3gica de negocio o procesos importantes del sistema.<\/td><\/tr><tr><td>Model<\/td><td>Representa una tabla, relaciones, atributos, scopes y comportamiento simple de la entidad.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">En otras palabras:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Request\n  \u2193\nForm Request\n  \u2193\nController\n  \u2193\nService\n  \u2193\nModel \/ Base de datos\n  \u2193\nResponse<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 es un Controller en Laravel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un controller agrupa la l\u00f3gica que responde a peticiones HTTP relacionadas con un recurso. Laravel recomienda usarlos para organizar el manejo de solicitudes que, de otra forma, terminar\u00edan como closures dentro de las rutas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El controller debe actuar como coordinador. No deber\u00eda cargar toda la l\u00f3gica de negocio del sistema.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Responsabilidades recomendadas de un controller<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Recibir la petici\u00f3n.<\/li>\n\n\n\n<li>Usar un Form Request para validar.<\/li>\n\n\n\n<li>Buscar un modelo cuando sea algo simple.<\/li>\n\n\n\n<li>Llamar un Service cuando haya l\u00f3gica de negocio.<\/li>\n\n\n\n<li>Regresar una vista, redirect o respuesta JSON.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Ejemplo de controller limpio<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>public function update(UpdateProductRequest $request, string $product)\n{\n    $product = Product::find($product);\n\n    $product = $this-&gt;productService-&gt;update(\n        $product,\n        $request-&gt;validated()\n    );\n\n    return response()-&gt;json(&#91;\n        'success' =&gt; true,\n        'message' =&gt; 'Producto actualizado correctamente.',\n        'product' =&gt; &#91;\n            'id' =&gt; $product-&gt;id,\n            'name' =&gt; $product-&gt;name,\n        ],\n    ]);\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Este controller no sabe todos los detalles de c\u00f3mo se actualiza el producto. Solo controla el flujo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eso lo hace m\u00e1s f\u00e1cil de leer, mantener y modificar.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 es un Form Request<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un Form Request es una clase especializada para validar y autorizar datos de entrada. Laravel permite crear estos archivos para encapsular validaci\u00f3n y autorizaci\u00f3n en un lugar separado del controller.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esto evita que el controller se llene de reglas como <code>required<\/code>, <code>exists<\/code>, <code>max<\/code>, <code>email<\/code>, validaciones condicionales o preparaci\u00f3n de datos.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Responsabilidades recomendadas de un Form Request<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Validar campos requeridos.<\/li>\n\n\n\n<li>Validar formatos.<\/li>\n\n\n\n<li>Validar existencia de registros en base de datos.<\/li>\n\n\n\n<li>Preparar datos antes de validar.<\/li>\n\n\n\n<li>Autorizar si el usuario puede ejecutar la acci\u00f3n.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Ejemplo de Form Request<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class UpdateProductRequest extends FormRequest\n{\n    public function rules(): array\n    {\n        return &#91;\n            'product_id' =&gt; &#91;'required', 'integer', 'exists:products,id'],\n            'name' =&gt; &#91;'required', 'string', 'max:255'],\n            'price' =&gt; &#91;'required', 'numeric', 'min:0'],\n        ];\n    }\n\n    public function authorize(): bool\n    {\n        return true;\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">El controller ya no necesita preocuparse por esa preparaci\u00f3n.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 es un Service<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un Service es una clase donde se concentra la l\u00f3gica de negocio o los procesos importantes del sistema. Aunque Laravel no obliga a crear una carpeta <code>Services<\/code>, el framework s\u00ed facilita este patr\u00f3n gracias a su Service Container y a la inyecci\u00f3n de dependencias.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La pregunta clave para decidir si algo va a un Service es:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">\u00bfEsto solo controla una petici\u00f3n HTTP o representa una operaci\u00f3n importante del negocio?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Si representa una operaci\u00f3n del negocio, normalmente conviene moverlo a un Service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Responsabilidades recomendadas de un Service<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Crear registros.<\/li>\n\n\n\n<li>Actualizar registros.<\/li>\n\n\n\n<li>Eliminar registros.<\/li>\n\n\n\n<li>Ejecutar transacciones.<\/li>\n\n\n\n<li>Aplicar reglas de negocio.<\/li>\n\n\n\n<li>Coordinar varias tablas.<\/li>\n\n\n\n<li>Calcular importes, descuentos, comisiones o estados.<\/li>\n\n\n\n<li>Consumir APIs externas.<\/li>\n\n\n\n<li>Disparar notificaciones, eventos o procesos relacionados.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Ejemplo de Service<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class ProductService\n{\n    public function create(array $data): Product\n    {\n        return DB::transaction(function () use ($data) {\n            return Product::create(&#91;\n                'name' =&gt; $data&#91;'name'],\n                'description' =&gt; $data&#91;'description'] ?? null,\n                'price' =&gt; $data&#91;'price'],\n                'enabled' =&gt; $data&#91;'enabled'] ?? true,\n            ]);\n        });\n    }\n\n    public function update(Product $product, array $data): Product\n    {\n        return DB::transaction(function () use ($product, $data) {\n            $product-&gt;name = $data&#91;'name'];\n            $product-&gt;description = $data&#91;'description'] ?? null;\n            $product-&gt;price = $data&#91;'price'];\n            $product-&gt;enabled = $data&#91;'enabled'] ?? $product-&gt;enabled;\n            $product-&gt;save();\n\n            return $product-&gt;fresh();\n        });\n    }\n\n    public function delete(Product $product): void\n    {\n        DB::transaction(function () use ($product) {\n            $product-&gt;delete();\n        });\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Aunque algunos m\u00e9todos parezcan simples al inicio, tenerlos en un Service permite que crezcan ordenadamente. Hoy un <code>delete()<\/code> puede borrar un registro; ma\u00f1ana puede validar permisos internos, eliminar relaciones, registrar historial y disparar una notificaci\u00f3n.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 es un Model en Laravel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Un Model representa una tabla de base de datos dentro de Eloquent. Laravel indica que cada tabla suele tener un modelo correspondiente, y que estos modelos permiten consultar, insertar, actualizar y eliminar registros.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pero eso no significa que toda la l\u00f3gica de negocio deba vivir dentro del Model.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Responsabilidades recomendadas de un Model<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Definir la tabla si no sigue la convenci\u00f3n.<\/li>\n\n\n\n<li>Definir campos <code>fillable<\/code> o <code>guarded<\/code>.<\/li>\n\n\n\n<li>Definir relaciones.<\/li>\n\n\n\n<li>Definir casts.<\/li>\n\n\n\n<li>Crear accessors y mutators.<\/li>\n\n\n\n<li>Crear scopes reutilizables.<\/li>\n\n\n\n<li>Agregar m\u00e9todos simples propios de la entidad.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Ejemplo de Model<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class Product extends Model\n{\n    protected $fillable = &#91;\n        'name',\n        'description',\n        'price',\n        'enabled',\n    ];\n\n    protected function casts(): array\n    {\n        return &#91;\n            'price' =&gt; 'decimal:2',\n            'enabled' =&gt; 'boolean',\n        ];\n    }\n\n    public function scopeEnabled($query)\n    {\n        return $query-&gt;where('enabled', true);\n    }\n\n    public function isAvailable(): bool\n    {\n        return $this-&gt;enabled === true;\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Este tipo de l\u00f3gica s\u00ed pertenece al modelo porque describe el comportamiento directo de la entidad <code>Product<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En cambio, si el proceso implica cobrar, registrar historial, enviar notificaciones y actualizar varias tablas, eso ya deber\u00eda ir a un Service.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Cu\u00e1ndo usar cada uno<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Usa Controller cuando&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Necesitas recibir una petici\u00f3n HTTP.<\/li>\n\n\n\n<li>Necesitas devolver una vista.<\/li>\n\n\n\n<li>Necesitas devolver JSON.<\/li>\n\n\n\n<li>Necesitas redireccionar.<\/li>\n\n\n\n<li>La acci\u00f3n solo coordina otras piezas.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>public function index()\n{\n    $products = Product::enabled()\n        -&gt;orderBy('name')\n        -&gt;paginate(20);\n\n    return view('products.index', compact('products'));\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Una consulta sencilla para mostrar datos puede quedarse en el controller.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Usa Form Request cuando&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Hay reglas de validaci\u00f3n.<\/li>\n\n\n\n<li>Hay autorizaci\u00f3n de la acci\u00f3n.<\/li>\n\n\n\n<li>Necesitas preparar datos antes de validarlos.<\/li>\n\n\n\n<li>Quieres evitar que el controller se llene de reglas.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>public function rules(): array\n{\n    return &#91;\n        'name' =&gt; &#91;'required', 'string', 'max:255'],\n        'email' =&gt; &#91;'required', 'email'],\n    ];\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Usa Service cuando&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>La acci\u00f3n crea, actualiza o elimina informaci\u00f3n importante.<\/li>\n\n\n\n<li>La acci\u00f3n toca varias tablas.<\/li>\n\n\n\n<li>La l\u00f3gica se reutilizar\u00e1 desde varios lugares.<\/li>\n\n\n\n<li>Hay transacciones.<\/li>\n\n\n\n<li>Hay integraci\u00f3n con APIs externas.<\/li>\n\n\n\n<li>Hay reglas de negocio.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$order = $this-&gt;orderService-&gt;create($request-&gt;validated());<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Usa Model cuando&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Necesitas definir relaciones.<\/li>\n\n\n\n<li>Necesitas casts.<\/li>\n\n\n\n<li>Necesitas scopes.<\/li>\n\n\n\n<li>Necesitas accessors o mutators.<\/li>\n\n\n\n<li>Necesitas m\u00e9todos simples de la entidad.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>public function scopeEnabled($query)\n{\n    return $query-&gt;where('enabled', true);\n}<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Ejemplo completo: creaci\u00f3n de una orden<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supongamos que tenemos un sistema donde un cliente puede crear una orden. La orden debe guardar productos, calcular total, registrar pagos pendientes y devolver una respuesta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Si todo se mete en el controller, el m\u00e9todo puede volverse enorme. Una mejor separaci\u00f3n ser\u00eda:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ruta<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>Route::post('\/orders', &#91;OrderController::class, 'store'])\n    -&gt;name('orders.store');<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Controller<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class OrderController extends Controller\n{\n    public function __construct(\n        private readonly OrderService $orderService\n    ) {}\n\n    public function store(StoreOrderRequest $request)\n    {\n        $order = $this-&gt;orderService-&gt;create($request-&gt;validated());\n\n        return response()-&gt;json(&#91;\n            'success' =&gt; true,\n            'message' =&gt; 'Orden creada correctamente.',\n            'order' =&gt; &#91;\n                'id' =&gt; $order-&gt;id,\n                'total' =&gt; $order-&gt;total,\n            ],\n        ]);\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Form Request<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class StoreOrderRequest extends FormRequest\n{\n    public function rules(): array\n    {\n        return &#91;\n            'customer_name' =&gt; &#91;'required', 'string', 'max:255'],\n            'items' =&gt; &#91;'required', 'array', 'min:1'],\n            'items.*.product_id' =&gt; &#91;'required', 'integer', 'exists:products,id'],\n            'items.*.quantity' =&gt; &#91;'required', 'integer', 'min:1'],\n        ];\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Service<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class OrderService\n{\n    public function create(array $data): Order\n    {\n        return DB::transaction(function () use ($data) {\n            $order = Order::create(&#91;\n                'customer_name' =&gt; $data&#91;'customer_name'],\n                'total' =&gt; 0,\n                'status' =&gt; 'pending',\n            ]);\n\n            $total = 0;\n\n            foreach ($data&#91;'items'] as $item) {\n                $product = Product::findOrFail($item&#91;'product_id']);\n                $subtotal = $product-&gt;price * $item&#91;'quantity'];\n\n                $order-&gt;items()-&gt;create(&#91;\n                    'product_id' =&gt; $product-&gt;id,\n                    'quantity' =&gt; $item&#91;'quantity'],\n                    'unit_price' =&gt; $product-&gt;price,\n                    'subtotal' =&gt; $subtotal,\n                ]);\n\n                $total += $subtotal;\n            }\n\n            $order-&gt;update(&#91;\n                'total' =&gt; $total,\n            ]);\n\n            return $order-&gt;fresh();\n        });\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Model<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>class Order extends Model\n{\n    protected $fillable = &#91;\n        'customer_name',\n        'total',\n        'status',\n    ];\n\n    protected function casts(): array\n    {\n        return &#91;\n            'total' =&gt; 'decimal:2',\n        ];\n    }\n\n    public function items()\n    {\n        return $this-&gt;hasMany(OrderItem::class);\n    }\n\n    public function isPending(): bool\n    {\n        return $this-&gt;status === 'pending';\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Con esta estructura, cada clase tiene una responsabilidad clara.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El controller no calcula totales. El Form Request no guarda datos. El Service no genera respuestas HTTP. El Model no se encarga de coordinar todo el proceso.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Errores comunes al separar responsabilidades<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Crear Services para todo<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No todas las acciones necesitan un Service. Si solo vas a mostrar una vista con una consulta sencilla, el controller puede hacerlo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Meter validaciones en el Service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">La validaci\u00f3n de entrada normalmente debe vivir en un Form Request. El Service debe recibir datos ya validados y ejecutar el proceso.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Regresar respuestas HTTP desde el Service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El Service no deber\u00eda regresar <code>response()-&gt;json()<\/code> ni redirects. Eso le corresponde al controller.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Convertir el Model en una clase gigante<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El Model debe representar la entidad, pero no coordinar procesos completos del sistema. Si una operaci\u00f3n toca varias entidades o APIs externas, probablemente debe vivir en un Service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5. No usar transacciones en procesos cr\u00edticos<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Cuando una operaci\u00f3n crea o actualiza varios registros relacionados, conviene usar transacciones para evitar datos incompletos si algo falla a mitad del proceso.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Regla pr\u00e1ctica para proyectos Laravel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Una convenci\u00f3n sencilla para mantener el orden es esta:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Si una acci\u00f3n crea, actualiza o elimina informaci\u00f3n importante de la base de datos, o representa un proceso del negocio, la l\u00f3gica principal debe ir en un Service.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Esto no significa que el controller nunca pueda consultar modelos. Para listados simples, vistas de edici\u00f3n o pantallas informativas, puede ser totalmente v\u00e1lido.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pero cuando el m\u00e9todo empieza a tener transacciones, ciclos, c\u00e1lculos, integraciones, actualizaciones en varias tablas o condiciones del negocio, es momento de mover esa l\u00f3gica a un Service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Gu\u00eda r\u00e1pida<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Situaci\u00f3n<\/th><th>D\u00f3nde colocarlo<\/th><\/tr><\/thead><tbody><tr><td>Mostrar una lista simple<\/td><td>Controller<\/td><\/tr><tr><td>Validar campos de formulario<\/td><td>Form Request<\/td><\/tr><tr><td>Crear un registro con reglas internas<\/td><td>Service<\/td><\/tr><tr><td>Actualizar varias tablas<\/td><td>Service<\/td><\/tr><tr><td>Consumir una API externa<\/td><td>Service<\/td><\/tr><tr><td>Definir relaci\u00f3n belongsTo<\/td><td>Model<\/td><\/tr><tr><td>Crear accessor o cast<\/td><td>Model<\/td><\/tr><tr><td>Regresar JSON<\/td><td>Controller<\/td><\/tr><tr><td>Redireccionar a otra ruta<\/td><td>Controller<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusi\u00f3n<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Separar Controllers, Form Requests, Services y Models no es solo una cuesti\u00f3n de estilo. Es una forma de mantener proyectos Laravel m\u00e1s claros, escalables y f\u00e1ciles de modificar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Un controller debe controlar el flujo de la petici\u00f3n. Un Form Request debe validar y preparar datos. Un Service debe ejecutar la l\u00f3gica de negocio. Un Model debe representar la entidad y su relaci\u00f3n con la base de datos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La meta no es crear m\u00e1s archivos sin raz\u00f3n, sino evitar que una sola clase tenga demasiadas responsabilidades.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cuando cada pieza cumple su funci\u00f3n, el c\u00f3digo se vuelve m\u00e1s f\u00e1cil de leer, probar y mantener.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fuentes consultadas<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/laravel.com\/docs\/13.x\/controllers\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Documentation: Controllers<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/laravel.com\/docs\/13.x\/validation#form-request-validation\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Documentation: Form Request Validation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/laravel.com\/docs\/13.x\/validation#preparing-input-for-validation\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Documentation: Preparing Input for Validation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/laravel.com\/docs\/13.x\/container\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Documentation: Service Container<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/laravel.com\/docs\/13.x\/eloquent\" target=\"_blank\" rel=\"noreferrer noopener\">Laravel Documentation: Eloquent ORM<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Conoce una buena pr\u00e1ctica para separar tu c\u00f3digo en proyectos de Laravel&#8230;<\/p>\n","protected":false},"author":1,"featured_media":312,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-311","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel-php"],"_links":{"self":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts\/311","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/comments?post=311"}],"version-history":[{"count":0,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/posts\/311\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/media\/312"}],"wp:attachment":[{"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/media?parent=311"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/categories?post=311"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mariatech.com.mx\/blog\/wp-json\/wp\/v2\/tags?post=311"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}