Search by

modularize / laravel-modules

Thrive-utils

Modular architecture for Laravel applications with automatic scaffolding for Web and API

Package info

bitbucket.org/thrive_agency/modularize

pkg:composer/modularize/laravel-modules

Statistics

Installs: 191

Dependents: 0

Suggesters: 0

v1.2.0 2026-09-17 20:38 UTC

This package is not auto-updated.

Last update: 2026-09-17 23:48:15 UTC


README

Laravel Modularize es un paquete independiente (framework-agnostic) que permite crear arquitecturas modulares, limpias y altamente desacopladas dentro de aplicaciones Laravel 11 y 12+. Diseñado específicamente para proyectos Enterprise y Domain-Driven Design (DDD), se aleja del monolito MVC tradicional para organizar la lógica de forma funcional (por Módulos).

Proporciona generadores CLI inteligentes para inicializar ciclos CRUD completos, incluyendo rutas anidadas, inyección de tareas programadas y variantes de scaffolding específicas para APIs o Web tradicional.

🚀 Características

  • Arquitectura Desacoplada: La lógica se estructura funcionalmente en Módulos que encapsulan sus propios Modelos, Controladores, Requests, Vistas, Migraciones, etc.
  • Auto-Bootstrapping: Cada Módulo actúa como su propio Service Provider—cargando automáticamente Rutas, Archivos de Configuración, Migraciones, Vistas y Comandos de Consola sin esfuerzo.
  • Scaffolding Profundo (Web y API): Con un solo comando, puedes generar un Módulo entero, sus Módulos Hijos anidados, o una estructura completa que incluye métodos de Controlador, Modelos, Resources y rutas, afinados específicamente para endpoints API o portales Web clásicos.
  • Abstracción de Namespaces: Se integra de forma nativa en cualquier aplicación sin depender de reglas rígidas basadas en la carpeta app/.
  • 100% Testeado: Cobertura respaldada explícitamente por una rigurosa suite de pruebas montada sobre Orchestra Testbench y verificando los analizadores del árbol de sintaxis abstracta (AST) y generadores de archivos.

📦 Instalación (Local vía Path Repository)

Requisitos del Sistema

  • PHP: 8.2, 8.3, 8.4, 8.5+
  • Laravel: 11.x, 12.x
  • nette/php-generator: ^4.1 (Requerido obligatoriamente para soporte AST en PHP 8.4/8.5)

Hasta que el paquete sea registrado formalmente en Packagist, puedes instalarlo fácilmente de manera manual en cualquier proyecto de Laravel configurando un repositorio de ruta local.

Estos son los pasos para agregarlo a tu aplicación Laravel local:

  1. Clona este paquete en un directorio junto a tu aplicación Laravel para que la estructura de carpetas se vea así:

    /tu-workspace
      /mi-app-laravel      <-- Tu proyecto real
      /modularize          <-- Este paquete
    
  2. En tu proyecto de Laravel (mi-app-laravel), abre composer.json y añade un repositorio local:

    "repositories": [
        {
            "type": "path",
            "url": "../modularize",
            "options": {
                "symlink": true
            }
        }
    ]
    
  3. Requiere el paquete ejecutando:

    composer require modularize/laravel-modules @dev
    php artisan vendor:publish --tag=modularize-init
    
  4. (Opcional pero recomendado): Publica la configuración del módulo y los stubs personalizados si necesitas cambiar la clase base o los namespaces. El proveedor ModulesServiceProvider sincronizará los archivos necesarios (ej: AppModulo.stub) hacia tu carpeta de stubs de la aplicación.

     php artisan vendor:publish --provider="Modularize\ModulesServiceProvider"
    

🛠 Uso y Comandos

Todos los comandos de Laravel Modularize están diseñados para ser amigables tanto para automatización como para humanos.

[!TIP] Modo Interactivo: Si ejecutas cualquier comando de terminal enumerado abajo y omites parcialmente (o enteramente) los parámetros (por ejemplo, si simplemente ejecutas php artisan modularize:make:scaffold), la consola entrará en modo interactivo y te guiará paso a paso preguntándote los valores que faltan (nombre del módulo, modelo a usar, etc) presentándote menús desplegables para elegir.

1. El poder de make:scaffold

Genera un ecosistema de andamiaje (scaffolding) completo para un concepto específico en un solo paso. Creará el archivo del Módulo Principal, el Modelo, el Resource, las clases Request para validación, el Controlador (alojado en la raíz matemática del módulo), la nueva capa lógica Business, y acoplará sus rutas al árbol de ejecución automáticamente.

A) Para Backends de API (RESTful) Añade el flag --api. Esto omitirá el código pensado para vistas visuales (como los métodos create y edit) y automáticamente generará código listo para devolver respuestas JSON utilizando los API Resources.

php artisan modularize:make:scaffold --module=app --name=Blog --modelName=Post --api

B) Para Portales Web Clásicos (Blade / Vistas)

php artisan modularize:make:scaffold --module=app --name=Blog --modelName=Post

2. Scaffolding de Campos Interactivo (Estilo Rails)

Al generar andamiajes (make:scaffold) o modelos independientes (make:model, make:migration, etc.), puedes definir la estructura de la base de datos directamente desde la consola usando una sintaxis inspirada en Ruby on Rails, pasándola mediante la opción --fields:

php artisan modularize:make:scaffold --module=app --name=Store --modelName=Product \
  --fields="name:string:unique,description:text:nullable,price:integer,category_id:foreignId"

El paquete utiliza manipulación del Árbol de Sintaxis Abstracta (AST) mediante nikic/php-parser para inspeccionar y recodificar tus archivos en tiempo real, inyectando exactamente lo que necesitas.

Tipos Soportados y Modificadores

Soporta estructuralmente todos los tipos nativos de Blueprint de Laravel (string, text, integer, boolean, uuid, etc). También soporta modificadores separados por otro ::

  • nullable: Marca la migración con ->nullable() y cambia las reglas de Form Request a ['nullable'] en lugar de ['required'].
  • unique: Añade la restricción ->unique() en la base de datos.

Generación Automática de Relaciones y Casos Límite (Edge Cases)

El paquete es lo suficientemente inteligente para inyectar métodos de relaciones de Eloquent directamente en tus Modelos. Si declaras un campo de tipo foreignId o usas un nombre que termine en _id (ej. user_id:integer), el AST escribirá tu modelo así:

1. Modelos Simples (user_id / category_id) Se abstrae y traduce directamente a:

public function user()
{
    return $this->belongsTo(User::class);
}

Además, en la capa de base de datos apendizará automáticamente ->constrained().

2. Relaciones Multipalabra (android_device_id / assigned_user_id) Al seguir un diseño de convenciones estrictas (PSR), el paquete parseará cualquier llave relacional compleja y generará la relación aplicando camelCase para el método, y StudlyCase para la clase. Por ejemplo, assigned_user_id:foreignId genera:

public function assignedUser()
{
    return $this->belongsTo(AssignedUser::class);
}

3. Modificadores de Relación Avanzados y Cascada Puedes inyectar métodos de relaciones adicionales directamente especificando el tipo de relación de Eloquent (hasOne, hasMany, belongsToMany, hasManyThrough, hasOneThrough).

Para las llaves foráneas (foreignId), el paquete aplica ->onDelete('cascade') por defecto para mantener la integridad relacional. Sin embargo, puedes sobreescribir este comportamiento delegándole distintas restricciones a la base de datos de esta forma:

  • user_id:foreignId:set null -> ->onDelete('set null') en la Migración.
  • user_id:foreignId:restrict -> ->onDelete('restrict') en la Migración.
  • user_id:foreignId:no action -> ->onDelete('no action') en la Migración.

Para las relaciones del Eloquent Model:

  • profile:hasOne -> method profile() con $this->hasOne(Profile::class) en el Modelo.
  • roles:belongsToMany -> method roles() con $this->belongsToMany(Role::class) en el Modelo.
  • deployments:hasManyThrough:Environment -> Usa el tercer parámetro como modelo intermedio.

[!NOTE] Autocompletado Interactivo: Si olvidas pasar el parámetro --fields, Laravel Modularize te presentará un "wizard" o asistente en la consola preguntándote si deseas escribir estos campos manualmente antes de continuar.

3. Generadores Artisan Disponibles

En lugar de usar los comandos generadores monolíticos de Laravel (make:controller), utiliza el prefijo modularize: para garantizar que los archivos se creen dentro del límite lógico y el namespace correcto de tu módulo.

[!TIP] Modo Interactivo por Defecto: ¡Puedes simplemente ejecutar php artisan modularize:make:model (sin ningún argumento) y la consola te preguntará todo paso a paso, incluyendo los campos de la base de datos fields dinámicamente!

A continuación, la estructura detallada de cada generador. (Recuerda que todos los argumentos son opcionales y el asistente te los preguntará interactiva y escalonadamente si los omites).

make:module

Crea un archivo de clase Module principal o anidado que se auto-registra en su módulo padre. Ejemplo:

php artisan modularize:make:module --module=app --name=Store
ArgumentoDescripción
--moduleLa llave de registro del módulo padre (ej: app o app.blog).
--nameEl nombre del nuevo Módulo (ej: Store).

make:scaffold

Genera un ecosistema CRUD completo (Controlador, Modelo, Migración, Request, Resource, Rutas integradas). Si no provees los campos, el asistente promptForFields() tomará el control. Ejemplo:

php artisan modularize:make:scaffold --module=app --name=Blog --modelName=Post --api --fields="title:string:unique,body:text"
ArgumentoDescripción
--moduleLa llave de registro del módulo padre donde se anidará el scaffolding.
--nameEl nombre del submódulo (ej: Blog).
--modelNameEl nombre de la entidad/Modelo principal (ej: Post).
--api(Flag) Si se provee, construye Controladores y Rutas estrictamente API (omite Vistas web create/edit).
--fieldsCuerda (String) continua de campos interactivos estilo Rails.
--cssFramework CSS a utilizar para Vistas Web (bootstrap, tailwind, plain). Si se omite, el asistente te lo preguntará.
--confirm(Flag) Si se provee, sobreescribe archivos existentes sin lanzar advertencias (ideal para automatización CI/CD).

make:model

Genera un Modelo Eloquent alterando el AST para inyectar relaciones en el vuelo basándose en reglas sintácticas (_id / foreignId). Nota: Este comando ahora maneja centralmente y de forma segura la integración de la Migración, previniendo duplicados cuando se invoca a través del scaffold. Ejemplo:

php artisan modularize:make:model --module=app --name=Order --fields="amount:integer,user_id:foreignId" --migration
ArgumentoDescripción
--moduleMódulo padre de destino.
--nameNombre del Modelo (ej: Order).
--fieldsString de campos procesados por el ModelCodeGenerator para deducir relaciones belongsTo y reglas $fillable.
--migration / -m(Flag) Si se indica, además del modelo creará su respectivo archivo de Migración basándose en los mismos campos y lo guardará en el Migrations/ del módulo.

make:migration

Genera un archivo de base de datos inyectando los esquemas directamente mediante AST, insertando constrained(), nullable() y más, inteligentemente. Ejemplo:

php artisan modularize:make:migration --module=app --name=create_orders_table --create=orders --fields="amount:integer,user_id:foreignId"
ArgumentoDescripción
--moduleMódulo objetivo para guardar el Schema.
--nameNombre final del archivo PHP de migración.
--createEl nombre formal de la tabla en base de datos.
--fieldsCampos para generar la estructura Blueprint.
--path(Opcional) Ruta personalizada explícita para generar el archivo.

make:request

Genera FormRequests mapeando automáticamente las definiciones de atributos de Rails a validaciones de Laravel clásicas (required, nullable, integer, etc). Ejemplo:

php artisan modularize:make:request --module=app --name=StoreOrderRequest --fields="amount:integer:nullable"
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre del Request Validator.
--fieldsUtilizado para inyectar automáticamente el arreglo (array) nativo de reglas de validación en el método rules().

make:resource

Genera un API JsonResource exponiendo las propiedades serializadas extraídas del schema. Ejemplo:

php artisan modularize:make:resource --module=app --name=OrderResource --fields="amount:integer"
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre del Resource.
--fieldsAtributos mapeados para construir el array predeterminado de toArray().

make:view

Genera las cuatro plantillas Blade principales (index, create, edit, show) y el layout base para un modelo, integrando automáticamente los formularios HTML interactivos y clases CSS dinámicas. Soporta nativamente la inyección de alertas de validación (@error). Ejemplo:

php artisan modularize:make:view --module=app --name=Product --fields="title:string,price:integer" --css=bootstrap
ArgumentoDescripción
--moduleMódulo objetivo donde residirán las vistas (Views/).
--nameNombre del Modelo asociado (ej: Product).
--fieldsLos campos utilizados para generar dinámicamente las columnas de tablas (index) y etiquetas <input>/<select> de formularios (create/edit).
--cssEl motor CSS deseado. Opciones: bootstrap, tailwind, plain. Por defecto, si omites esto en modo interactivo, la consola te desplegará un menú para elegir.

make:business

Genera una clase de capa intermedia (Business Logic) a nivel raíz del módulo, pre-configurada con un método estático listar() que abstrae paginación, filtros y ordenamiento. Ejemplo:

php artisan modularize:make:business --module=app --name=Order
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre para la clase Business (ej: Order). El archivo resultante será OrderBusiness.

make:controller

Genera un archivo de Controlador estándar vacío pero perfectamente enlazado y namespacesado (Namespaced) en la raíz del módulo objetivo (sin subcarpeta interna Controllers/). Ejemplo:

php artisan modularize:make:controller --module=app --name=OrderController
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre final de la clase Controller.

make:command

Acopla un comando custom de consola en el ecosistema particular de un Módulo. Ejemplo:

php artisan modularize:make:command --module=app --name=SyncOrdersCommand
ArgumentoDescripción
--moduleMódulo contenedor para el comando.
--nameNombre de la clase (terminará extendiendo de \Illuminate\Console\Command).

make:factory

Genera un Database Factory pre-configurado para Faker. Capaz de leer el Modelo vía AST (ModelParser) si omites los campos. Ejemplo:

php artisan modularize:make:factory --module=app --name=OrderFactory --modelName=Order
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre de la clase Factory.
--modelNameNombre del Modelo a asociar. Si se omite, se preguntará interactivamente.
--fieldsString de campos a falsificar. Si se omite, se extraerán directamente del código de la clase del Modelo indicado.

make:seeder

Genera un Database Seeder invocativo. Automatiza la instanciación de un Factory si le indicas un Modelo. Ejemplo:

php artisan modularize:make:seeder --module=app --name=OrderSeeder --modelName=Order
ArgumentoDescripción
--moduleMódulo objetivo.
--nameNombre de la clase Seeder.
--modelName(Opcional) Si se especifica, el Seeder autogenerado vendrá con Order::factory()->count(10)->create() listo.

Manejadores AST Directos (add:route y add:schedule)

Inyectan nodos directamente en la sintaxis de clases ya provistas globalmente por un Módulo utilizando php-parser.

ComandoArgumentosDescripción / Objetivo
add:route--verb, --uri, --method-nameAcopla una nueva ruta REST en routes.php / api.php.
add:schedule--command-nameSe inyecta al final del registro crond/scheduler del Module.php.

🧪 Testing

El paquete depende exclusivamente de Docker y PCOV para garantizar un entorno de pruebas y nativo sin afectar las configuraciones de sistema operativo de tu máquina local.

Para correr toda la suite de pruebas (tests de features e integración), simplemente usa docker-compose:

# Correr tests de forma limpia
docker compose up test

Para ver el reporte gráfico completo de cobertura de código (HTML Coverage):

# Generará el reporte HTML dentro de la carpeta `./coverage/` local
docker compose run --rm coverage

📋 Auditable Models

modularize/laravel-modules expone un trait opt-in que cualquier modelo del usuario puede use-ar para registrar todas sus mutaciones en una tabla de auditoría (auditoria por default). Cada evento se persiste como un JSON con los datos de antes, después y los cambios, más traza de stack y contexto de request/usuario.

1. Publicar migración y config

php artisan vendor:publish --tag=modularize-audit-migrations
php artisan vendor:publish --tag=modularize-audit-config
php artisan migrate

2. Opt-in en cada modelo

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Modularize\Auditable\Auditable;

class Producto extends Model
{
    use Auditable;

    protected $table = 'productos';
    protected $fillable = ['nombre', 'precio'];
}

A partir de ese momento, cualquier create, update, delete y (si usás SoftDeletes) restore deja una fila en auditoria con la siguiente forma:

ColumnaDescripción
modelo_clase, modelo_tabla, modelo_idIdentidad del registro afectado
accioncreated / updated / deleted / restored
datos_antes, datos_despues, cambiosSnapshots JSON del estado del modelo
errorMensaje si la mutación del modelo lanzó una excepción (no rompe la operación)
traceFrames de stack (sin argumentos) hasta el punto donde se gatilló la mutación
usuario_id, ruta, ip, ocurrio_enContexto de request

3. Comando de purga

# Borrar lo anterior a 90 días (default configurable)
php artisan modularize:audit:prune

# Dry-run + override de días + lista blanca inline
php artisan modularize:audit:prune --dias=30 --whitelist=lotes --dry-run

Opciones:

FlagEfecto
--dias=NSobrescribe modularize.audit.prune.dias_retencion
--whitelist=tabla1,tabla2Tablas a preservar siempre (también en config)
--blacklist=tabla1,tabla2Tablas a purgar siempre, ignorando whitelist
--dry-runMuestra conteo, no borra

Reglas de resolución:

  1. Si blacklist no está vacía → purga solo las tablas en blacklist (ignora whitelist).
  2. Si blacklist está vacía y whitelist no está vacía → purga todas excepto whitelist.
  3. Si ambas están vacías → purga por edad, sin filtro de tabla.

4. Schedule sugerido

Desde el AppModule del consumidor (o cualquier Module):

public function bootSchedule()
{
    \Modularize\Auditable\AuditLog::schedulePrune($this->scheduler(), 'dailyAt("03:00")');
}

5. Configuración (config/modularize.php)

return [
    'audit' => [
        'habilitado'   => env('AUDIT_HABILITADO', true),
        'tabla'        => env('AUDIT_TABLA', 'auditoria'),
        'log_errores'  => env('AUDIT_LOG_ERRORES', true),
        'prune' => [
            'dias_retencion' => 90,
            'lotes'          => 1000,    // tamaño de chunk
        ],
        'whitelist' => ['lotes' => true],   // se preservan siempre
        'blacklist' => [],                  // override de whitelist
    ],
];

Notas operativas

  • El trace se captura con debug_backtrace(IGNORE_ARGS, 15): descarta valores (no captura PII ni passwords), pero quedan nombres de archivo y función.
  • Si la tabla auditoria no existe, el trait sigue funcionando: el save() del modelo del usuario no se rompe. Ver tests Feature para confirmación.
  • El trait no está aplicado a AuditLog (la tabla de auditoría). No hay riesgo de recursion infinita.

🇪🇸 Convenciones del equipo (--team)

make:scaffold (y los sub-comandos que dispara) aceptan un flag --team para alinearse con las convenciones internas del equipo:

  • Métodos en español: listar, crear, obtener, actualizar, borrar.
  • Variables en español: $datos en lugar de $data o request()->all().
  • Single Request: CreateRequest + UpdateRequest se colapsan en un único OrderRequest.
  • Resource con claves camelCase: assigned_user_idassignedUserId.
  • Rutas con {id}: ya no usa el nombre del recurso como placeholder.
  • Business con 5 métodos: listar, crear, actualizar, borrar, obtenerPorId.
  • register() vacío listo para provide()s, si el módulo se genera nuevo.
  • jwt.verify middleware: si existe App\Modules\Auth\AuthModule, las rutas CRUD se insertan dentro del ->group() existente para heredar auth.
php artisan modularize:make:scaffold --module=app --name=Tienda --modelName=Order \
  --api --fields="total:decimal,cliente_id:foreignId" --team=true

El default es false (compatibilidad con código existente). Para activarlo por proyecto publicá config/modularize.php con:

return [
    'team_mode'      => true,                       // métodos ES, $datos, single Request
    'plural'         => ['locale' => 'es'],         // reglas de pluralización
];

🇪🇸 Plural en español (SpanishInflector)

make:model infiere el nombre de la tabla pluralizando el nombre del modelo. Por default usa reglas inglesas (Postposts); si la config modularize.plural.locale = 'es' está activa, usa reglas españolas:

SingularPlural ES
OperacionOperaciones
LoteLotes
CategoríaCategorías
PostPosts

Para forzar el nombre de la tabla manualmente (ignora locale):

php artisan modularize:make:model --module=app --name=Operacion \
  --fields=... --table=operaciones_especificas

💀 Soft-deletes (--soft-deletes)

Activa SoftDeletes tanto en el modelo como en la migración:

php artisan modularize:make:scaffold --module=app --name=Tienda \
  --modelName=Pedido --soft-deletes --fields="cliente_id:foreignId,monto:decimal"

Esto agrega al modelo:

use Illuminate\Database\Eloquent\SoftDeletes;

class Pedido extends Repositorio
{
    use SoftDeletes;
    protected $casts = ['deleted_at' => 'datetime'];
}

Y a la migración:

$table->softDeletes();
$table->timestamps();

🧪 Test generator (modularize:make:test)

Genera un Feature test mínimo con RefreshDatabase y un test de listado:

php artisan modularize:make:test --module=app --name=Producto --api=true

Resultado: tests/Feature/Productos/ProductoTest.php con test_listar_devuelve_una_coleccion() que pega GET /api/productos y verifica código 200 + colección vacía. Si pasás --api=false, usa get() en vez de getJson().

📦 BaseRequest compartido (modularize:make:base-request)

Genera un FormRequest base en app/Modules/Base/Requests/ para acumular reglas reutilizables (ej: NombreRequest, IdRequest):

php artisan modularize:make:base-request Nombre

Resultado: app/Modules/Base/Requests/NombreRequest.php con authorize() = true (la auth la hace el middleware) y rules() = [] para que las clases hijas extiendan y sobreescriban.

⚖️ Licencia

El paquete Laravel Modularize es software de código abierto licenciado bajo los términos de la licencia MIT.