Download the PHP package innodite/laravel-module-maker without Composer

On this page you can find all versions of the php package innodite/laravel-module-maker. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-module-maker

🏗️ Innodite Laravel Module Maker

Tests Coverage Latest Version PHP Laravel

v5.2 — Generador de módulos Laravel para proyectos de una aplicación o multiinquilino. Genera el backend completo, sus rutas con el permiso de cada una y sus vistas Vue 3, con un solo comando. Un módulo agrupa varias subfuncionalidades, y cada una es autocontenida: Modules/<Módulo>/<SubFuncionalidad>/<Capa>/<Contexto>/.

👉 La versión que se instala es la 5.2.0

Y cambia la forma de todo lo que el paquete escribe. Un módulo generado con una 4.x no coincide con lo que genera esta —ni en carpetas ni en namespaces—, así que actualizar sin mover nada deja el proyecto con dos formas dentro. Qué cambió exactamente, y en qué orden se mueve un módulo existente, está en el CHANGELOG.

El primer comando después de actualizar es el diagnóstico, que dice qué le falta al proyecto y con qué línea se arregla cada cosa:


⚠️ Versiones Deprecadas

Se consideran deprecados los tags históricos con referencias heredadas a software/proyecto externo. Para uso nuevo, instala la 5.1 (arriba) — esto es solo un registro de qué tags antiguos evitar si tienes que instalar contra una versión previa a la reescritura de la v5.

Tags deprecados:

Nota: la deprecación es de soporte/uso recomendado. No se reescribe el historial Git publicado.


📋 Tabla de Contenidos

Nuevos en la v4:


✅ Requisitos

Dependencia Versión mínima
PHP 8.2+
Laravel 11.0+
illuminate/support ^11.0|^12.0
illuminate/console ^11.0|^12.0
illuminate/filesystem ^11.0|^12.0
illuminate/routing ^11.0|^12.0
@inertiajs/vue3 ^1.0 (frontend)
Vue ^3.0 (frontend)

Compatible opcionalmente con stancl/tenancy y spatie/laravel-permission.


🚀 Instalación

Al instalar por primera vez, el paquete detecta la ausencia de configuración y sugiere el setup en consola.

Inicializar el proyecto (requerido)

Crea module-maker-config/ en la raíz del proyecto con:

Publicar assets manualmente

⚠️ Publicar las plantillas tiene un coste que conviene saber antes: una copia publicada se queda congelada en tu proyecto y deja de actualizarse con el paquete, así que sigue generando la forma antigua sin decir nada. Por eso el instalador ya no las publica y existe innodite:publish-stubs, que te deja pedir solo las que vas a tocar y sin argumentos se limita a listarlas.


🗺️ Los dos contextos

En multiinquilino hay dos contextos y solo dos. Un proyecto que necesite otro lo declara en su module-maker-config/contexts.json; el paquete no trae ninguno más de fábrica.

Contexto Prefijo de clase Carpeta Archivo de rutas Prefijo de URL Nombre de ruta Conexión del modelo
central Central …/Central/ Routes/web.php central-users central.users.index $connection = 'central'
tenant Tenant …/Tenant/ Routes/tenant.php tenant-users tenant.users.index ninguna — la conmuta la tenencia

⛔ Ningún archivo lleva el nombre de un cliente. Una carpeta y una conexión por cliente producen una copia por cliente de lógica idéntica, permisos que hay que sembrar y renombrar uno a uno, y rutas servidas bajo el prefijo de un cliente concreto.

⛔ Y el modelo del inquilino no declara conexión, nunca. La conmuta el paquete de tenencia al identificar la ruta; nombrarla ata el modelo a un cliente. Si el proyecto declara tenancy.package = none, el modelo sale con una nota que dice quién tiene que conmutarla.


🖥️ Arquitectura Frontend

Regla fundamental — No negociable en este paquete.

Responsabilidad Tecnología
Navegación entre páginas Inertia.js (router.visit(), router.get())
Carga y mutación de datos axios (GET, POST, PUT, DELETE)
Contexto activo y permisos Props de Inertia — compartidos por InnoditeContextBridge

Los controladores utilizan el trait RendersInertiaModule y el método renderModule() para devolver la vista Inertia correcta según el contexto. Nunca pasan datos de negocio por props de Inertia.

Las vistas Vue son shells que se autocargan al montarse vía axios. Inertia nunca transporta datos de negocio; solo gestiona la navegación SPA.


🛠️ Guía de comandos

innodite:make-module — Generador principal

Genera backend completo + vistas Vue en un solo comando.

Flags de componentes:

Flag Componente generado
-M / --model Modelo Eloquent con $table definida
-C / --controller Controlador con RendersInertiaModule + inyección de rutas CRUD
-S / --service Servicio + Interface en Services/Contracts/
-R / --repository Repositorio + Interface en Repositories/Contracts/
-G / --migration Migración anónima contextualizada
-Q / --request Form Request validado — el de alta y el de edición

Validaciones de seguridad:


innodite:add-entity — Agregar entidad a módulo existente

Agrega una nueva entidad a un módulo ya existente, generando sus componentes dentro de la subcarpeta de entidad correspondiente. Diseñado para módulos multi-entidad como UserManagement (con User, Role, Permission, Module).

Firma:

Argumento Descripción
module Nombre del módulo existente (ej: UserManagement)
entity Nombre de la entidad nueva (ej: Role, Permission)
--context= Contexto destino: central o tenant. En aplicación única no se pasa
-M a -Q Mismos flags que make-module (sin flags = genera todos los componentes)

Ejemplo de archivos generados — add-entity UserManagement Role --context=central:

La capa va dentro de la subfuncionalidad, y el contexto es la hoja. En aplicación única el último tramo no existe (Role/Services/RoleService.php) y el resto es idéntico: los dos modos comparten estructura en vez de parecerse.

Diferencia con make-module:

make-module add-entity
Crea módulo nuevo ✅ ❌
Agrega a módulo existente ❌ ✅
Valida que el módulo exista primero — ✅
Sin flags = genera todos los componentes ✅ ✅
Naming convention intacta ✅ ✅

innodite:module-setup — Configuración inicial

Crea la estructura de configuración del paquete en la raíz del proyecto. Debe ejecutarse una sola vez al inicializar un nuevo proyecto que use este paquete.


innodite:doctor — Diagnóstico, en cascada

Recorre tres etapas, y cada fallo trae en su propia línea qué hacer.

Etapa 1 · El entorno del generador

  1. El modo del proyecto — sin él, los comandos no generan
  2. contexts.json — validez, estructura y el catálogo que exige ese modo
  3. Permisos de escritura en Modules/ y storage/logs/
  4. Colisiones de nombres entre módulos, y comandos del proyecto que tapen a los del paquete
  5. config/make-module.php publicada — el orden de despliegue vive ahí
  6. Stubs publicados — detecta los que siguen en el formato de la v3
  7. Últimas entradas del log de eventos

Etapa 2 · El contrato del proyecto anfitrión

Verifica el bridge Inertia y, si algo falta, imprime el bloque de código exacto a copiar:

  1. Modelo User — HasRoles (Spatie) o InnoditeUserPermissions
  2. HandleInertiaRequests — auth.permissions compartido
  3. InnoditeContextBridge — registrado en el grupo web

Etapa 3 · Lo que dice el criterio

Consulta al proveedor de reglas configurado y lista sus hallazgos.

⭐ Desde la 5.1.0, además recorre cada módulo buscando la estructura de pruebas compartida ya retirada (Tests/Feature/Shared/, o una pieza de Central/Tenant que todavía incorpora un trait con use <Trait> en vez de llevar el código inline). Si encuentra un caso, lo lista con la ruta exacta y el arreglo: inlinear el cuerpo del trait en cada contexto y borrar la carpeta compartida. Es detección pura — ningún comando mueve el código por su cuenta.

Viene de innodite:module-check y de innodite:check-env, que ya no existen. Eran dos comandos útiles cuyos nombres no decían lo que hacían, y que había que acordarse de lanzar por separado: uno miraba el entorno y el otro el contrato, cuando lo que se quiere saber es una sola cosa —si este proyecto puede generar y si lo generado va a encontrar su sitio—.


innodite:publish-frontend — ⛔ RETIRADO

El paquete no configura el frontend de tu proyecto: no publica composables ni componentes, y no toca app.js ni el middleware de Inertia. Solo genera las vistas de cada subfuncionalidad, y lo hace sin depender de ninguna biblioteca — el can() va escrito en la propia pantalla.

Contra qué se generan lo decide --frontend=default|innodite en el instalador.


innodite:migrate-plan — ⛔ RETIRADO

Aplicaba las migraciones del proyecto recorriendo el árbol. Usa innodite:deploy, que aplica el esquema, los datos y los permisos juntos y en el orden que declaras tú:

El comando sigue registrado para decir esto mismo si lo ejecutas, y devuelve error —no éxito—, de modo que un script que lo tuviera escrito no lo dé por hecho.

Por qué se retiró. Ordenaba las subfuncionalidades por el nombre de sus carpetas, ignorando el orden que el proyecto declara en deploy. Con Cart, Customer y Order en un módulo de ventas, carts se migraba antes que las dos tablas a las que apunta. Y era el único sitio del paquete que ejecutaba migraciones fuera del seeder, contra la regla que el propio paquete escribe en cada trait que genera: el vehículo del despliegue es el seeder.

Dónde vive ahora cada mitad del orden, que es lo único que hay que recordar:

Quién Qué decide
deploy, en config/make-module.php El orden entre subfuncionalidades — lo declaras tú
El trait MigrationsList de cada una El orden dentro de una subfuncionalidad — lo genera el paquete

Para una migración suelta sigue estando innodite:migrate-one.


innodite:migrate-one — Ejecutar una migración específica

Ejecuta una sola migración, nombrada por su coordenada Modulo:Contexto/archivo.php. La base de datos sale de la propia coordenada, que ya lleva encima su carpeta de contexto.

Opción Descripción
--context= Fuerza el contexto de ejecución en vez de derivarlo de la coordenada
--yes Omite la confirmación
--dry-run Muestra lo que haría sin ejecutar

innodite:deploy — Levanta el proyecto entero

Esquema, datos y permisos, en el orden declarado en deploy (config/make-module.php), más el webmaster al cerrar. Es el comando que sustituye a innodite:seed-one y a innodite:migration-sync.

Argumento / opción Descripción
entorno Obligatorio. stage o production. Nada por defecto: stage puede reconstruir desde cero
--context= Obligatorio en multitenant: central o tenant
--force No pedir confirmación aunque SEEDER_DESTRUCTIVE esté activo

El seeder que invoca lo escribe el instalador en database/seeders/, y es donde se lee y se amplía la secuencia de pasos del despliegue.

Retirados en la v4: innodite:seed-one y innodite:migration-sync. Los dos existían para mantener los manifiestos *.order.json, que ya no lee nadie: el orden de las migraciones lo declaran los traits MigrationsList y el de los seeders el array deploy. Si tu proyecto todavía tiene esa carpeta, los comandos de migración te lo dirán al ejecutarse; puedes borrarla.


innodite:test — Ejecutar el contrato de una subfuncionalidad

Se ejecuta por subfuncionalidad, no por módulo, porque el contrato es de ella: son sus nueve temas, su manifiesto y sus seis piezas. Un módulo con cuatro subfuncionalidades no tiene un contrato, tiene cuatro — y ejecutarlos juntos mezcla el resultado de cosas que se despliegan y fallan por separado.

En cascada, y con corte temprano:

El orden es de dependencia: cada pieza da por supuesto lo que comprobó la anterior. Si el andamiaje no está, el esquema falla por lo mismo; si el esquema no está, los permisos fallan por lo mismo; y el comportamiento por HTTP falla de treinta formas distintas por la misma causa única.

Treinta fallos rojos de un solo problema no informan treinta veces mejor: informan peor, porque hay que leerlos todos para descubrir que eran el mismo. Por eso al primer fallo se para, y dice qué falló, qué cubría y qué queda sin ejecutar.

Antes de lanzar nada comprueba que el grupo esté entero. Faltar el manifiesto no es «una prueba menos»: sin él ninguna de las otras puede derivar rutas ni permisos, y lo que saldría serían fallos que describen el síntoma y esconden la causa.

⭐ Y desde la 5.1.0, comprueba también que la subfuncionalidad no tenga la estructura de pruebas compartida ya retirada (Tests/Feature/Shared/, o un trait incorporado con use <Trait> en vez de inline). Si la encuentra, el comando se niega a correr y dice el arreglo — el mismo chequeo que hace innodite:doctor en cascada sobre todo el proyecto.

El tema 6 se nombra siempre, también cuando todo pasa. Un contrato «en verde» que se saltó un tema sin decirlo es la peor clase de silencio.

Qué tiene que traer tu proyecto para que el grupo corra

El grupo generado se escribe contra las tablas y contra el router, no contra las clases de un paquete concreto — así sobrevive a que cambies de versión, o de paquete de permisos. A cambio da por supuestas cinco cosas, y las cinco las pone el proyecto, no el módulo:

Lo que hace falta Por qué
Tests\TestCase La base del grupo la extiende. Es la de Laravel de toda la vida
Modules\ en el autoload PSR-4 de Composer Sin él las piezas no se cargan
users y las tablas de permisos permissions (con description y module_id), modules, roles, model_has_permissions y role_has_permissions. El seeder generado llena description y module_id si existen
El alias del middleware de permiso, registrado El que use tu proyecto: permission, central-permission, tenant-permission… El grupo lo lee de la propia ruta, así que reconoce cualquiera que termine en permission
APP_KEY El grupo web cifra la sesión: sin clave, la petición revienta antes de llegar al middleware de permiso, y el fallo no se parece en nada a su causa

Y una consecuencia del diseño de las migraciones: el trait MigrationsList declara sus rutas relativas a la raíz del proyecto, porque así las recibe migrate --path. El módulo tiene que vivir bajo esa raíz para que el seeder las encuentre.

Tres pruebas nacen saltadas, y es a propósito. Las de validación —entrada inválida, edición inválida, y la de crear y volver a leer— se saltan mientras el FormRequest generado no declare reglas: sin rules() no hay nada que pueda fallar la validación, y una prueba que pasa porque no comprueba nada es peor que una que dice que no corrió. Escribe tus reglas y corren solas.

Viene de innodite:test-module, que ya no existe. El comando anterior trabajaba por módulo y contexto leyendo Modules/{Modulo}/Tests/test-config.json. Ese archivo era el último manifiesto JSON del paquete y se retiró junto con innodite:test-sync, que lo generaba: el contexto lo dice ahora el comando (--context) y la forma del módulo la dice el modo. Un proyecto que aún tenga esos archivos recibe un aviso al ejecutar innodite:test — no un error: el proyecto funciona sin ellos, y puedes borrarlos cuando hayas comprobado que no te falta nada de ellos.

📁 La forma de lo generado

La subfuncionalidad manda, la capa va dentro de ella y el contexto es la hoja. En aplicación única ese último tramo no existe y el resto es idéntico: los dos modos comparten estructura en vez de parecerse.

Qué vive dónde: si la pieza recorre todas las subfuncionalidades —Docs/, Routes/, Providers/ y los tres maestros—, vive al nivel del módulo. Todo lo demás baja a la suya.

Las cuentas, medidas generando de verdad:

Módulo User con 2 subfuncionalidades × 2 contextos 129 archivos + 16 carpetas
El mismo en aplicación única 66 archivos + 8 carpetas
Una subfuncionalidad en un solo contexto 29 archivos

🔄 El ciclo, de principio a fin

⛔ add-entity deja exactamente lo mismo que make-module: las cuatro capas, la migración, las seis piezas de seeder, la factory, las pantallas, las rutas, el provider de su contexto y el grupo de pruebas. Las dos puertas por las que aparece una subfuncionalidad emiten lo mismo.


🧩 Composables Vue 3

⛔ El paquete ya no publica composables. Se retiraron en la 4.x junto con innodite:publish-frontend: montar el andamiaje del frontend es del proyecto, o de la biblioteca de interfaz que use. Lo que sigue describe el contrato que la vista generada espera de tu proyecto, por si prefieres implementarlo con composables propios; la pantalla que genera el paquete no importa ninguno — lleva su can() de dos líneas escrito dentro.

El contexto activo, y cómo lo lee la pantalla

Lee auth.context.route_prefix desde las props de Inertia compartidas por InnoditeContextBridge y antepone automáticamente el prefijo correcto a cualquier clave de ruta.

⛔ El paquete no publica ningún composable para esto. Lo hizo hasta la 4.x, con useModuleContext; se retiró junto con el resto del andamiaje de frontend, porque montar el frontend es del proyecto o de la biblioteca que lo instale, no del generador.

⭐ Y el nombre de la ruta ya no hay que resolverlo en cada petición: el generador lo escribe en la pantalla con el prefijo de su contexto ya puesto, porque lo que se sabe al generar no se calcula mil veces después. El contexto compartido sigue sirviendo para lo que sí depende de la sesión.


usePermissions — Verificación de permisos del usuario

Lee auth.permissions desde las props de Inertia y permite verificar permisos de forma declarativa en las plantillas Vue.

Estrategia dual: verifica {prefix}.{perm} y {perm} plano simultáneamente. El mismo componente funciona en cualquier contexto sin cambios.


Flujo de datos en las vistas Vue generadas

Ejemplo — CentralUserIndex.vue

Ejemplo — CentralUserCreate.vue

Ejemplo — CentralUserEdit.vue


🔧 Stubs contextuales

El paquete trae un solo juego de plantillas, en una carpeta plana. Tú decides cuáles personalizar, y puedes hacerlo para todo el proyecto o solo para un contexto.

Estructura de stubs

⚠️ El paquete ya NO envía copias por contexto. Llegó a llevar cuatro —Central, Shared, TenantShared, TenantName—, idénticas byte a byte a la plantilla base y con prioridad sobre ella: corregir la base sin tocar sus cuatro copias no cambiaba nada, porque ganaba la copia vieja. La carpeta por contexto sigue existiendo en tu proyecto, que es donde puede diferir de verdad.

Publicar stubs para personalización

Copia las plantillas a module-maker-config/stubs/contextual/. A partir de ahí ganan a las del paquete, y puedes borrar las que no vayas a tocar: lo que no esté ahí se sigue leyendo del paquete.

⚠️ Publicarlas tiene un coste: una plantilla copiada no se actualiza con el paquete. Si publicaste las 38 «por si acaso», borra las que no personalizaste — si no, seguirás generando con las de la versión en que las copiaste.

Stubs aportados por otro paquete instalado

Un paquete instalado puede aportar sus propios stubs, y el generador los usará sin que haya que configurar nada. El contrato es una ruta: cualquier paquete que traiga

participa en la resolución. Sirve para generar contra una biblioteca de interfaz concreta —su tabla, sus formularios— en vez de contra las plantillas genéricas del paquete.

Orden de resolución, de lo más específico a lo más genérico:

# Dónde Quién manda
1 module-maker-config/stubs/contextual/{Contexto}/ El proyecto, para un contexto
2 module-maker-config/stubs/contextual/ El proyecto
3 vendor/*/*/stubs/module-maker/contextual/ Un paquete instalado
4 Los del propio laravel-module-maker El paquete

El proyecto siempre gana: es el único que puede tener la última palabra sobre su propio código. Si dos paquetes aportan el mismo stub, gana el primero por orden alfabético y make-module lo dice al terminar, junto con el nombre de quién aportó qué.

provider-boot.stub — el punto de enganche del módulo

Es un stub opcional: no existe en el paquete y solo se usa si el proyecto o un paquete instalado lo aportan. Su contenido se escribe dentro del boot() del ServiceProvider del módulo generado, y sin él ese boot() sale vacío.

Está pensado para enganchar el módulo en el menú de la aplicación, que es lo que el generador no puede escribir por su cuenta: la línea que lo hace depende de cómo se declare un menú en cada proyecto. Recibe dos variables:

Variable Qué trae Ejemplo
{{{ moduleName }}} El nombre del módulo Invoice
{{{ functionality }}} La funcionalidad, como la nombran sus rutas invoices

texts-trait.stub — la séptima pieza del seeder: los textos de la subfuncionalidad

También opcional, y por el mismo motivo: el paquete no sabe sembrar un texto —en qué tabla se guarda, qué archivo se sirve después— porque eso lo decide la biblioteca que lo lee. Si el proyecto o un paquete instalado lo aportan, make-module y add-entity escriben {Prefijo}{Módulo}{SubFunc}Texts.php junto a las otras seis piezas de Database/Seeders/, los seeders de stage y de producción la incorporan con use …Texts; y la llaman al final de run() —$this->safe('seedTexts', fn () => $this->seedTexts()), después de los permisos y antes del reporte—, y el módulo nace con resources/lang/.gitkeep: sin esa carpeta el proveedor no registra el espacio de nombres de traducción del módulo y el texto sembrado no llega a ninguna pantalla.

Sin nadie que lo aporte, los seeders salen exactamente como siempre. Y como las otras seis, la pieza no se sobrescribe si ya existe. Recibe:

Variable Qué trae Ejemplo
{{{ namespace }}} El de las piezas de seeder de esa subfuncionalidad y contexto Modules\Invoice\Invoice\Database\Seeders\Central
{{{ traitName }}} El nombre de la pieza CentralInvoiceInvoiceTexts
{{{ moduleName }}} · {{{ subFeature }}} El módulo y la subfuncionalidad Invoice · Invoice
{{{ textsGroup }}} El grupo de traducción, compuesto como el proveedor registra resources/lang: snake_case del módulo y del archivo invoice::invoice · person_catalog::person_catalog

⚠️ stage-seeder.stub y production-seeder.stub llevan desde la 5.2.0 los placeholders {{{ textsTraitUse }}} y {{{ textsStep }}}. Si los tienes publicados de una versión anterior, tu copia gana y el seeder generado no incorpora la pieza: republícalos o añádeselos.

Variables disponibles en los stubs

⛔ Se escriben con TRIPLE llave: {{{ nombre }}}, no {{ nombre }}. No es capricho: los stubs generan código que a su vez lleva llaves —Blade, Vue, arrays de PHP—, y con doble llave el sustituidor se comía trozos que no eran suyos. Un stub personalizado con doble llave no se sustituye y sale literal en el archivo generado; el doctor lo detecta y lo dice.

Las que verás en casi todos:

Variable Descripción Ejemplo
{{{ moduleName }}} Nombre del módulo Invoice
{{{ modelName }}} Nombre del modelo Invoice
{{{ namespace }}} Namespace de la clase que se genera Modules\Invoice\Http\Controllers
{{{ className }}} Nombre de la clase generada InvoiceController
{{{ tableName }}} Nombre de la tabla invoices
{{{ subFeature }}} Subfuncionalidad Payment
{{{ subFeatureLabel }}} Etiqueta legible de la subfuncionalidad Payment
{{{ routeBase }}} La funcionalidad, como la nombran las rutas invoices
{{{ routePrefix }}} Prefijo de ruta del contexto central
{{{ connection }}} Conexión declarada, cuando el modo la lleva tenant_one

Y en las cuatro vistas Vue, además:

Variable Descripción Ejemplo
{{{ vueComponentName }}} Componente de esta vista InvoiceIndex
{{{ vueComponentBase }}} Nombre sin el sufijo de vista Invoice
{{{ permViewStore }}} · {{{ permViewShow }}} · {{{ permViewUpdate }}} · {{{ permViewDestroy }}} · {{{ permViewRestore }}} El permiso que decide si se muestra cada elemento
{{{ textsGroup }}} El grupo de traducción de la subfuncionalidad, el mismo que recibe texts-trait.stub invoice::invoice

⭐ La lista completa la tiene cada stub: abre el que vayas a personalizar y mira qué variables usa. Son las que su generador le entrega, y no todas están en todos.


🌉 Bridge Frontend-Backend

Middleware InnoditeContextBridge

Intercepta cada request e inyecta vía Inertia::share():

Prop Valor ejemplo
auth.context.route_prefix central, tenant — null en aplicación única
auth.context.permission_prefix central, tenant — null en aplicación única
auth.permissions ['central.users.edit', 'users.view', ...]

Cadena de resolución de permisos:

  1. Spatie Permission → $user->getAllPermissions()->pluck('name')
  2. InnoditeUserPermissions → $user->getInnoditePermissions()
  3. Fail-safe → [] + Warning en log

Registrar en bootstrap/app.php (Laravel 11+):

Alias para rutas específicas:


Interfaz InnoditeUserPermissions


⚙️ El catálogo de contextos (contexts.json)

Lo publica el instalador en module-maker-config/contexts.json, y en multiinquilino trae dos:

⛔ El inquilino no declara connection_key, y no es un olvido: la conmuta el paquete de tenencia al identificar la ruta. Nombrarla ataría cada modelo a un cliente.

Un contexto propio —una segunda central, un almacén aparte— se declara aquí con su carpeta, su prefijo y su archivo de rutas, y el generador lo acepta. Ese sí tiene que declarar su conexión: no la conmuta nadie.


📐 Convenciones de nomenclatura

Contexto Prefijo de clase Ejemplo Vue Ejemplo PHP
central Central CentralUserIndex.vue CentralUserController.php
tenant Tenant TenantUserIndex.vue TenantUserController.php
aplicación única — UserIndex.vue UserController.php

Reglas adicionales:


🔀 Flujo de inyección de rutas

Marcadores en routes/web.php

Marcadores en routes/tenant.php

Lo decide el ARCHIVO, no el contexto. Cada archivo de rutas sirve a un contexto y solo a uno, así que dentro hay una sección y un solo sitio donde crece: ahí entra la siguiente subfuncionalidad, dentro del grupo que le da dominio y middleware.

Proceso interno de inyección

Un contexto por archivo de rutas

Contexto Archivo destino Prefijo URL Nombre de ruta
central routes/web.php central-{funcionalidad} central.
tenant routes/tenant.php tenant-{funcionalidad} tenant.

El archivo declara las rutas de su contexto y de ninguno más. Hasta la 4.x un archivo podía recibir un bloque por cada inquilino del catálogo, importando controladores que nadie había escrito: el módulo salía sin una sola ruta utilizable y el fallo no se veía leyendo el código.


📋 Resumen de todos los comandos

Comando Descripción
innodite:make-module {Name} Genera módulo completo con backend, vistas Vue y rutas
innodite:add-entity {Module} {Entity} Agrega una entidad a un módulo existente
innodite:module-setup Inicializa configuración del paquete en el proyecto
innodite:doctor Diagnóstico en cascada: el entorno del generador y el contrato del proyecto
innodite:crear-bd-test Clona el esquema real en la base _test, sin una sola fila
innodite:publish-stubs Exporta las plantillas que quieras personalizar
innodite:migrate-plan Retirado — el esquema lo aplica innodite:deploy, a través de los seeders
innodite:migrate-one Ejecuta una migración puntual por coordenada
innodite:deploy {stage\|production} Levanta el proyecto: esquema, datos, permisos y webmaster
innodite:test Ejecuta el contrato de una subfuncionalidad, en cascada y con corte temprano
vendor:publish --tag=module-maker-config Publica make-module.php
vendor:publish --tag=module-maker-stubs Publica stubs contextuales personalizables
vendor:publish --tag=module-maker-contexts Publica contexts.json de ejemplo

Son tres los tags publicables, y son los que el proveedor de servicios declara. El de module-maker-frontend que esta tabla listaba no existe: se fue con el andamiaje de frontend.


📊 Auditoría

storage/logs/module_maker.log — formato NDJSON (una entrada JSON por línea):

Evento Cuándo se registra
module.created Módulo completo generado correctamente
module.components Componentes individuales añadidos a módulo existente
routes.injected Rutas inyectadas exitosamente en el proyecto
module.rollback Rollback ejecutado tras error durante la generación

🧪 Pruebas

Los tests generados se ubican todos en Modules/{Name}/Tests/Feature/{Context}/{SubFuncionalidad}/, como un grupo por subfuncionalidad: un manifiesto ({SubFunc}Contract.php), su base ({SubFunc}TestCase.php) y las piezas de los nueve temas —ScaffoldTest, SchemaTest, PermissionsTest, DeploymentTest y HttpTest—. La del tema 6 la ejecuta Vitest y vive con el JavaScript, en resources/js/__tests__/{Context}/{SubFuncionalidad}/.

Los emiten por igual make-module y add-entity: una subfuncionalidad nace con su grupo entero venga por donde venga.


📏 Estándares de código

El paquete incluye configuración de PHP CS Fixer compatible con PSR-12. Todos los archivos PHP generados incluyen declare(strict_types=1) por defecto.


📦 Publicar en Packagist / repositorio privado

Repositorio público (Packagist)

Luego registrar el repositorio en packagist.org con la URL del repositorio.

⚠️ La etiqueta se empuja sola, por su referencia completa. --tags arrastra todas las que tengas en local, incluidas las de pruebas que no querías publicar — y una etiqueta publicada no se corrige: hay que retirarla y rehacerla, cuando Packagist ya la ha servido.

⭐ Y etiqueta después de cerrar el CHANGELOG.md, no antes: lo que se publica es el árbol tal y como está en ese commit, así que una versión etiquetada con su changelog aún en «sin publicar» sale diciendo que no publica nada de lo que trae.

Repositorio privado (VCS)

Agregar en el composer.json del proyecto consumidor:


📚 Documentación

El manual de uso vive en docs/, dentro del propio paquete, y se declara en el composer.json con extra.innodite-docs:

👉 Leerlo aquí — instalación, modificaciones manuales del proyecto anfitrión, y una ficha por comando con pestañas: qué hace, qué parámetros recibe, qué archivos o cambios genera, personalización de stubs (en los generadores) y ejemplos.

⭐ Vive aquí a propósito: quien cambia un comando actualiza su ficha en el mismo commit. Una documentación que se escribe en otro sitio se actualiza «después», y «después» es como se llega a un manual que anuncia comandos que ya no existen.

La página publicada se genera, no se edita

manual.html sale de las fichas, así que no se toca a mano: se cambia el .md y se vuelve a armar. index.html es la portada gerencial (aparte, no generada) — es lo primero que ve quien entra al sitio. Los dos, junto con assets/, viven en la raíz del repositorio —no en docs/— a propósito: así el hosting del subdominio los sirve directo, sin ninguna subcarpeta.

Así la fuente sigue siendo una sola —los .md, que son también lo que consume el portal por extra.innodite-docs— y la página publicada no puede decir algo distinto de lo que dice el manual.


📝 Changelog

Ver CHANGELOG.md para el historial completo de versiones.


📄 Licencia

MIT — Anthony Filgueira


All versions of laravel-module-maker with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/support Version ^11.0|^12.0|^13.0
illuminate/console Version ^11.0|^12.0|^13.0
illuminate/filesystem Version ^11.0|^12.0|^13.0
illuminate/routing Version ^11.0|^12.0|^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package innodite/laravel-module-maker contains the following files

Loading the files please wait ...