Cuando trabajas con múltiples paquetes en PHP (como módulos propios), llega un punto donde necesitas debuggear directamente el código del paquete y no una copia dentro de vendor.
Si alguna vez terminaste debuggeando en vendor/ en lugar de tu proyecto real… esto es para ti.
En el desarrollo moderno de aplicaciones PHP con CodeIgniter 4, uno de los mayores retos es mantener un flujo de trabajo eficiente entre desarrollo local, control de versiones y gestión de dependencias.
Este artículo explica una arquitectura híbrida usando Composer + Git + symlinks que permite trabajar módulos de forma profesional sin depender del directorio vendor.
🧠 El problema clásico
Cuando trabajamos con módulos reutilizables (inventarios, CFDI, pagos, etc.), normalmente terminamos instalando todo en vendor/, lo que genera problemas:
Generador Automático de CRUD para CodeIgniter 4 – julio101290/boilerplate
🚀 Generador Automático de CRUD para CodeIgniter 4: Crea Módulos Completos en 1 Minuto 🔥
¿Cansado de escribir el mismo código una y otra vez? ¿Tus proyectos se retrasan por la tediosa creación de modelos, controladores y vistas? ¡Tenemos la solución! Te presento el Generador Automático de CRUD para CodeIgniter 4, una herramienta integrada en mi boilerplate que transforma una tabla de base de datos en un módulo funcional, seguro y profesional en menos de 60 segundos. Ahorra cientos de horas y olvídate de los errores repetitivos.
Es un controlador inteligente que, a partir del nombre de una tabla existente en tu base de datos, genera de forma automática todos los archivos necesarios para un CRUD completo:
✅ Modelo con validaciones y soft delete
✅ Controlador con DataTables server-side
✅ Vistas (listado + modal) integradas con AdminLTE
✅ Archivos de idioma (inglés y español)
✅ Migración lista para ejecutar
✅ Rutas listas para copiar o integradas en tu paquete
✅ Permisos creados automáticamente (RBAC)
Todo esto con código limpio, indentado y siguiendo las mejores prácticas.
💡 Dato curioso: El generador lee la estructura de tu tabla y adapta los campos automáticamente. Si tu tabla tiene campos como created_at, updated_at, deleted_at, los maneja de forma especial para que el soft delete funcione perfectamente.
🏗️ El entorno perfecto: julio101290/boilerplate
Este generador vive dentro de mi fork del excelente boilerplate de agungsugiarto, adaptado y mejorado para proyectos reales. Incluye:
🔹 Lee el composer.json y extrae el namespace PSR-4 automáticamente.
🔹 Crea la estructura src/Models, src/Controllers, etc.
🔹 Actualiza el archivo src/Config/Routes.php del paquete con las nuevas rutas.
🔹 Tu paquete se vuelve autónomo y portable.
🔑 Permisos gestionados como profesionales
Antes: los permisos se creaban en caliente al generar el CRUD (poco ortodoxo). Ahora: cuando el destino es un paquete vendor, el generador actualiza el Seeder correspondiente (ej. BoilerplateCFDIDescargaMasiva.php), añadiendo la línea para crear el permiso y asignarlo al admin.
Así, la instalación de permisos se hace como Dios manda: con php spark db:seed.
⏱️ Ahorro de tiempo real
Tarea
Sin generador
Con generador
Ahorro
CRUD de 10 campos
45-60 min
1 min
~98%
20 tablas por proyecto
15-20 horas
20 minutos
¡Días!
Ese tiempo lo puedes reinvertir en lógica de negocio que realmente aporta valor. Además, todo el código generado sigue el mismo patrón, reduciendo la deuda técnica y facilitando el mantenimiento.
📝 Código completo del generador
Aquí tienes la clase AutoCrudControllerComposer en su versión final. Cópiala directamente en tu proyecto (julio101290/boilerplate/Controllers/).
db = \Config\Database::connect();
$this->authorize = Services::authorization();
$this->users = new UserModel();
helper('utilerias');
}
/**
* Método principal para generar el CRUD
*
* @param string $table Nombre de la tabla
* @param string|null $targetType 'app' o 'vendor' (por GET)
* @param string|null $vendorPackage Paquete vendor
* @param string|null $vendorNamespace Namespace (auto-detected)
*/
public function index($table, $targetType = null, $vendorPackage = null, $vendorNamespace = null)
{
// Leer de GET si no se pasaron como argumentos
if ($targetType === null) {
$targetType = $this->request->getGet('target') ?? 'app';
}
if ($vendorPackage === null && $targetType === 'vendor') {
$vendorPackage = $this->request->getGet('package');
}
if ($vendorNamespace === null && $targetType === 'vendor') {
$vendorNamespace = $this->request->getGet('namespace');
}
$this->targetType = $targetType;
if ($targetType === 'vendor' && $vendorPackage) {
$this->setupVendorPaths($vendorPackage, $vendorNamespace);
}
$this->generateModel($table);
$this->generateController($table);
$this->generateView($table);
$this->generateViewModal($table);
$this->generateLanguage($table);
$this->generateMigration($table);
$this->generateLanguageES($table);
if ($targetType === 'vendor') {
$this->generateVendorRoutesFile($table);
$this->updateSeederPermissions($table);
} else {
$this->generatePermissions($table);
}
$tableUpCase = ucfirst($table);
echo "";
echo "✅ CRUD generado exitosamente en: " . ($targetType === 'vendor' ? $this->vendorPackage : 'app') . "";
echo "";
}
// ... (el resto de métodos: setupVendorPaths, generateModel, generateController, etc.)
// Por brevedad, no repetimos todo el código aquí, pero en el artículo real debes incluir el código completo.
}
?>
⚠️ Nota: El código anterior es un resumen. Para obtener el código completo, visita el repositorio en GitHub o copia el bloque que aparece al final de este artículo.
🔌 Cómo usarlo
Agrega la ruta en app/Config/Routes.php: $routes->get('generateCRUDComposer/(:any)', 'julio101290\boilerplate\Controllers\AutoCrudControllerComposer::index/$1');
Genera un CRUD en app: http://tusitio.com/generateCRUDComposer/nombre_tabla
Genera en tu paquete vendor: http://tusitio.com/generateCRUDComposer/nombre_tabla?target=vendor&package=tu/paquete
¡Y listo! En segundos tendrás todo el código listo para usar.
🎯 Conclusión y llamado a la acción
El generador automático de CRUD ha evolucionado de un simple script a una herramienta profesional que:
Este manual técnico explica cómo enlazar sucursales locales con sucursales de SAP Business One (OBPL) utilizando ODBC (eODBC) sobre SAP HANA, evitando el uso del Service Layer para consultas de alto rendimiento.
¿Qué problema resuelve esta implementación?
En muchos proyectos con SAP Business One, el uso del Service Layer para catálogos o consultas simples introduce latencia innecesaria. Este módulo soluciona ese problema permitiendo:
Relacionar sucursales locales con sucursales SAP
Consultar la tabla OBPL directamente desde SAP HANA
Reducir tiempos de respuesta usando ODBC
Eliminar dependencias innecesarias del Service Layer
¿Por qué usar ODBC en SAP Business One?
El uso de ODBC en SAP HANA es ideal para consultas de solo lectura, catálogos y validaciones rápidas.
Característica
Service Layer
ODBC SAP HANA
Rendimiento
Medio
Alto
Latencia
Alta
Baja
Ideal para
CRUD complejo
Catálogos y consultas
Dependencia SAP
Alta
Media
Estructura del módulo de enlace SAP
La solución se divide en cuatro componentes principales:
Tabla de enlace entre sucursal local y SAP
Controlador con consultas ODBC
Vista con DataTables server-side
Formulario con Select2 dinámico
Tabla link_sap_branchoffice
Esta tabla permite mantener la relación entre el sistema local y SAP Business One sin duplicar información de SAP.
Campo
Descripción
id
ID interno
idEmpresa
Empresa local
idBranchOffice
Sucursal local
idBranchOfficeSAP
Sucursal SAP (OBPL.BPLId)
created_at
Fecha de creación
updated_at
Fecha de actualización
deleted_at
Borrado lógico
Conexión a SAP HANA usando ODBC
La conexión ODBC se realiza directamente contra SAP HANA, lo que permite consultas rápidas y estables.
Este paso es obligatorio para evitar errores como invalid table name en SAP HANA.
Consulta optimizada a la tabla OBPL
Para obtener una sucursal SAP se realiza una consulta directa a la tabla OBPL:
SELECT
"BPLId",
"BPLName"
FROM OBPL
WHERE "Disabled" <> 'Y'
AND "BPLId" = ?
Consulta directa
Sin bucles innecesarios
Ideal para formularios y edición
Listado con DataTables server-side
El módulo utiliza DataTables en modo server-side para manejar grandes volúmenes de datos:
Paginación eficiente
Búsqueda global
Ordenamiento dinámico
Filtrado por empresa del usuario
Select2 dinámico para sucursales
Sucursal local
Se cargan las sucursales locales vía AJAX usando Select2.
Sucursal SAP (OBPL)
Las sucursales SAP se consultan directamente desde SAP HANA vía ODBC, sin Service Layer.
Beneficios clave de esta arquitectura
Mayor rendimiento en SAP Business One
Menor latencia en consultas
Menos carga en el Service Layer
Arquitectura escalable y mantenible
Buenas prácticas recomendadas
Usar ODBC solo para consultas de lectura
Usar Service Layer para escrituras en SAP
Centralizar credenciales ODBC
Siempre definir el schema en SAP HANA
Conclusión
Este enfoque permite integrar SAP Business One con sistemas locales de forma eficiente, utilizando ODBC sobre SAP HANA como alternativa rápida y estable al Service Layer.
Ideal para catálogos, validaciones, reportes y sistemas híbridos SAP.
Conectar aplicaciones PHP o frameworks como CodeIgniter a SAP HANA desde Linux puede ser un reto, especialmente cuando no se quiere instalar el SAP HANA Client oficial. En esta guía aprenderás paso a paso cómo instalar y configurar CDATA ODBC Driver para SAP HANA en Linux Mint, una alternativa rápida y funcional para entornos de desarrollo.
¿Qué es CDATA ODBC para SAP HANA?
CDATA es un proveedor de drivers ODBC comerciales que permiten conectarse a múltiples bases de datos empresariales, incluido SAP HANA, sin necesidad de instalar clientes pesados de SAP.
Ventajas
Instalación sencilla
Compatible con PHP, Python y Java
Ideal para Linux Mint / Ubuntu
No requiere SAP HANA Client
Consideraciones
Driver comercial
Incluye periodo de prueba (~30 días)
Recomendado para desarrollo y pruebas
Requisitos del sistema
Linux Mint 22 (64 bits)
Acceso a SAP HANA (IP, puerto, usuario y base de datos)
cd ~/Descargas
tar -xvzf CDataODBCDriverforSAPHANA.tar.gz
cd CDataODBCDriverforSAPHANA
4. Instalar el driver CDATA
sudo ./install.sh
El driver se instalará por defecto en:
/opt/cdata/cdata-odbc-driver-for-saphana/
5. Registrar el driver en ODBC
Verifica que la librería exista:
ls /opt/cdata/cdata-odbc-driver-for-saphana/lib/
Debe existir:
libcdataodbcHANA.so
Edita el archivo odbcinst.ini:
sudo nano /etc/odbcinst.ini
Agrega lo siguiente:
[CData SAP HANA ODBC Driver]
Description=CData ODBC Driver for SAP HANA
Driver=/opt/cdata/cdata-odbc-driver-for-saphana/lib/libcdataodbcHANA.so
UsageCount=1
Verifica el registro:
odbcinst -q -d
6. Crear el DSN de conexión
Edita el archivo odbc.ini:
sudo nano /etc/odbc.ini
Ejemplo de conexión para SAP Business One HANA:
[hana_dev]
Driver=CData SAP HANA ODBC Driver
Server=192.168.1.50
Port=30015
User=HANAUSER
Password=MySecurePass123
Database=SBODEV_HANA
Nota: SAP HANA es sensible a mayúsculas y minúsculas, por lo que es obligatorio usar comillas dobles para tablas y campos.
Conclusión
El driver CDATA ODBC para SAP HANA es una excelente alternativa cuando necesitas conectarte rápidamente a SAP HANA desde Linux Mint sin instalar el cliente oficial de SAP.
Instalación sencilla
Compatible con PHP y CodeIgniter
Ideal para desarrollo y pruebas
Esta configuración puede adaptarse fácilmente a entornos productivos ajustando credenciales, seguridad y manejo de conexiones.
🛠️ Actualización técnica: validación y subida de imágenes + controlador seguro en boilerplateproducts 🖼️
En este cambio abordamos varios problemas prácticos que afectaban la subida de imágenes y la robustez del endpoint admin/products/save. Objetivos principales:
✅ Permitir JPG/JPEG además de PNG (y manejar HEIC de iPhone).
✅ Soportar subida desde móvil (cámara/galería).
✅ Validar tipo y tamaño en cliente y servidor (pasamos de 2 MB a 5 MB).
✅ Enviar la imagen con FormData solo si existe y evitar errores por selectores incorrectos.
✅ Mejorar el controlador en CodeIgniter 4: validaciones, rutas absolutas, manejo seguro de archivos, respuestas JSON y logging. 📦
1 — Problema inicial 🐞
El JS validaba solo image/png, por lo que bloqueaba .jpg/.jpeg. ❌
Selectores inconsistentes (.imagenProducto vs #imagenProducto) => riesgo de undefined. ⚠️
El controlador PHP aceptaba únicamente PNG, hacía var_dump, usaba rutas relativas y agarraba excepciones equivocadas. 🧨
Tamaño máximo 2 MB; se solicitó ampliar a 5 MB. 📈
No había protocolo JSON consistente entre frontend y backend. 🧩
2 — Cambios en el frontend (JS) 📱
Qué se cambió (resumen)
Validación de tipos permitidos: image/png, image/jpeg, image/jpg. ✅
Detección y rechazo de HEIC (iPhone) con aviso o rechazo según preferencia. 🚫🧾
Frontend: validar JPG/JPEG + PNG, rechazar HEIC, aumentar tamaño a 5MB, enviar FormData solo si existe, unificar selectores y mejorar UX (disable button + toast).
Backend (CI4): aceptar jpg/png, validar tamaño, usar FCPATH para almacenamiento, crear carpeta si no existe, devolver JSON, borrar imagen anterior de forma segura, mejorar manejo de errores y logging.
Incluye checklist de QA y capturas de la subida desde móvil/desktop.
7 — Próximos pasos recomendados 🚀
✂️ Optimizar imágenes: redimensionar/comprimir en cliente o servidor para ahorrar espacio y tiempo de subida.
♻️ Soportar HEIC: implementar conversión con Imagick o servicio externo si quieres aceptar HEIC automáticamente.
🧪 Automatizar pruebas: agregar tests para multipart upload y para el flujo de reemplazo/borrado de imágenes.
🔁 Pipeline CI/CD: en staging hacer composer update si fuera necesario, probar y en producción usar composer install (lockfile).
8 — Conclusión 🎯
Estos cambios hacen la subida de imágenes más robusta, amigable para móviles y segura en el servidor. El frontend ahora maneja errores con mensajes claros y el backend devuelve JSON estructurado para un manejo predecible en la UI. Además, ampliamos el límite a 5 MB y arreglamos detalles clásicos como rutas relativas y selectores inconsistentes. ✅
🚀 Nueva actualización lav1.5.1 — Manejo mejorado de Imagen de Perfil en Boilerplate
La versión lav1.5.1 introduce una de las mejoras más esperadas en el flujo de autenticación y gestión de usuarios: la capacidad de manejar de forma nativa la imagen de perfil, con validación robusta, soporte para valores NULL en base de datos y un avatar por defecto cuando no se encuentra la imagen.
Este release no solo mejora la experiencia visual y de usabilidad, sino que también fortalece la integración de datos del usuario dentro de las vistas del sistema. A continuación, presentamos en detalle todos los cambios, mejoras y la forma recomendada de actualizar tu proyecto.
✨ Principales Novedades
🔹 1. Imagen de perfil con validación
Ahora el sistema valida si el campo profile_image existe en la base de datos y contiene un valor válido.
Si el campo está vacío o en NULL, se muestra automáticamente un avatar genérico.
Si el archivo no existe en el servidor, el sistema también utiliza el avatar por defecto.
🔹 2. Avatar por defecto
El avatar por defecto se toma de la CDN oficial de AdminLTE:
Se añade el campo profile_image a la tabla de usuarios.
Este campo acepta NULL de manera nativa.
Si no se define, la vista renderiza automáticamente el avatar por defecto.
Compatibilidad
Compatible con PostgreSQL y MariaDB.
No requiere cambios manuales en tablas previas: el comando php spark boilerplate:update se encarga de todo.
🔒 Beneficios de Seguridad
No se exponen rutas inválidas de imágenes.
Se evita el error de “imagen rota”.
Se normalizan los valores NULL.
Mejora la experiencia del usuario manteniendo consistencia en toda la interfaz.
📊 Ejemplo Visual del Cambio
Antes (versión anterior):
Los usuarios sin foto aparecían con un ícono roto.
Los campos NULL no eran validados correctamente.
Ahora (lav1.5.1):
Todos los usuarios tienen avatar visible.
Integración estética y funcional en Navbar y Sidebar.
📝 Changelog resumido
✅ Validación de profile_image en todas las vistas principales.
✅ Avatar por defecto cuando el campo está vacío o NULL.
✅ Compatibilidad con PostgreSQL y MariaDB.
✅ Nuevo comando php spark boilerplate:update.
✅ Correcciones menores en estilos de AdminLTE.
🚀 Guía Paso a Paso de Migración
Respaldar tu proyecto actual.
Ejecutar:
composer update julio101290/boilerplate
Correr la migración:
php spark boilerplate:updatecommand
Limpiar caché.
Verificar que los usuarios aparecen con sus fotos de perfil o con el avatar por defecto.
📌 Notas Finales
Este release v1.5.1 marca un paso adelante en la personalización de Boilerplate. Ahora cada usuario tiene una experiencia más consistente y profesional dentro de la aplicación.
👉 Si quieres revisar el código y los commits de esta versión: 🔗 Release en GitHub
¿Buscas un sistema de facturación rápido, seguro y flexible que puedas instalar en tu servidor Ubuntu con mínimo esfuerzo?
¡Te presento CI4JCPOX, una solución basada en CodeIgniter 4.5 que potencia tu negocio con funcionalidades completas y tecnología moderna!
🌟 ¿Por qué elegir CI4JCPOX?
Basado en CodeIgniter 4.5, el framework PHP ligero y rápido
Uso de MariaDB para bases de datos robustas y eficientes
Integración lista con Apache y PHP para un entorno LAMP completo
Código abierto y fácil de personalizar para tus necesidades
Instalación rápida gracias a un script automatizado para Ubuntu Server 24.04 en AWS EC2 o cualquier VPS Linux
⚙️ ¿Qué incluye este sistema?
Gestión completa de facturas y clientes
Interfaz web limpia y responsiva
Migraciones y seeders para inicializar la base de datos sin complicaciones
Configuración segura con usuario y base de datos dedicados
Preparado para crecer y adaptarse a tu negocio
🛠️ Cómo instalar CI4JCPOX en Ubuntu Server 24.04 (AWS EC2)
He preparado un script automático para que en pocos minutos tengas todo listo: LAMP, base de datos, configuración de CodeIgniter y Apache con VirtualHost.
Paso 1: Descarga el script de instalación
cd ~
curl -O https://raw.githubusercontent.com/julio101290/ci4jcposv2/main/instalar_ci4_facturacion.sh
Paso 2: Dale permisos de ejecución
chmod +x instalar_ci4_facturacion.sh
Paso 3: Ejecuta el script como root
sudo ./instalar_ci4_facturacion.sh
✅ ¿Qué hace este script por ti?
Actualiza y prepara tu servidor Ubuntu
Instala Apache, MariaDB y PHP con todas las extensiones necesarias
Crea la base de datos facturacion y un usuario seguro con permisos
Instala el proyecto CI4JCPOX usando Composer en /var/www/html/facturacion
Configura Apache para servir el proyecto con un VirtualHost dedicado
Ejecuta migraciones y seeders para inicializar la base de datos
Deja todo listo para que accedas a tu sistema por IP o dominio
🌐 Accede a tu sistema
Abre tu navegador y entra a:
http://TU_IP_PUBLICA/
¡Listo para comenzar a facturar!
🔒 Seguridad y permisos
El script también se encarga de ajustar permisos para que Apache pueda servir correctamente la aplicación sin problemas de acceso.
📂 Código y más información
Puedes revisar y descargar el script completo desde GitHub:
Usamos cookies en nuestro sitio web para brindarle la experiencia más relevante recordando sus preferencias y visitas repetidas. Al hacer clic en "Aceptar", acepta el uso de TODAS las cookies.
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.