Introducción
Crear módulos en Perfex CRM es la forma más potente de extender las funcionalidades del sistema sin modificar el código base. En este tutorial completo, aprenderás a crear un módulo profesional desde cero, siguiendo las mejores prácticas de la industria.
💡 ¿Por qué crear módulos?
Los módulos te permiten añadir funcionalidades que se mantienen separadas del core, facilitando las actualizaciones de Perfex CRM y permitiendo reutilizar tu código en otros proyectos.
Estructura Obligatoria del Módulo
Todo módulo en Perfex CRM debe seguir una estructura específica. Aquí tienes la estructura mínima requerida:
1. El Archivo Principal del Módulo
El archivo principal (mi_modulo.php) es el corazón de tu módulo. Define la información básica y registra los hooks necesarios:
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/*
* Module Name: Mi Módulo
* Description: Descripción de lo que hace el módulo
* Version: 1.0.0
* Author: Tu Nombre
* Author URI: https://tudominio.com
* Requires at least: 3.0
*/
define('MI_MODULO_VERSION', '1.0.0');
// Registrar activación del módulo
register_activation_hook(MI_MODULO_MODULE_NAME, 'mi_modulo_activation_hook');
function mi_modulo_activation_hook()
{
$CI = &get_instance();
$CI->load->library('App_module_installer');
// Instalar base de datos
require_once(__DIR__ . '/install.php');
}
// Registrar menú de administración
hooks()->add_action('admin_init', 'mi_modulo_init');
hooks()->add_action('app_admin_head', 'mi_modulo_add_head');
function mi_modulo_init()
{
// Registrar permisos
$capabilities = [];
$capabilities['capabilities'] = [
'view' => _l('permission_view'),
'create' => _l('permission_create'),
'edit' => _l('permission_edit'),
'delete' => _l('permission_delete'),
];
register_staff_capabilities('mi_modulo', $capabilities, _l('mi_modulo_title'));
}
function mi_modulo_add_head()
{
echo '<link rel="stylesheet" href="' . module_dir_url('mi_modulo', 'assets/css/styles.css') . '">';
}
// Registrar ítem de menú
hooks()->add_action('admin_init', 'mi_modulo_menu');
function mi_modulo_menu()
{
$CI = &get_instance();
if (has_permission('mi_modulo', '', 'view')) {
$CI->app_menu->add_sidebar_menu_item('mi_modulo', [
'name' => _l('mi_modulo_title'),
'href' => admin_url('mi_modulo'),
'icon' => 'fa fa-puzzle-piece',
'position' => 50,
]);
}
}
2. Crear el Controlador
El controlador maneja las peticiones HTTP y conecta la lógica con las vistas. Debe extender AdminController:
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Mi_modulo extends AdminController
{
public function __construct()
{
parent::__construct();
// Verificar permisos
if (!has_permission('mi_modulo', '', 'view')) {
access_denied('mi_modulo');
}
// Cargar modelo
$this->load->model('mi_modulo_model');
}
public function index()
{
// Preparar datos para la vista
$data['title'] = _l('mi_modulo_title');
$data['items'] = $this->mi_modulo_model->get_all();
// Renderizar vista
$this->load->view('dashboard', $data);
}
public function create()
{
if (!has_permission('mi_modulo', '', 'create')) {
access_denied('mi_modulo');
}
if ($this->input->post()) {
$data = $this->input->post();
$id = $this->mi_modulo_model->add($data);
if ($id) {
set_alert('success', _l('added_successfully', _l('mi_modulo_item')));
}
redirect(admin_url('mi_modulo'));
}
$this->load->view('create');
}
}
⚠️ Importante: Singleton Pattern
Fuera de controladores, siempre usa $CI = &get_instance(); para acceder a las funciones de CodeIgniter. Nunca uses $this en helpers o librerías.
3. Crear el Modelo
El modelo gestiona todas las operaciones con la base de datos. Recuerda usar siempre db_prefix():
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Mi_modulo_model extends App_Model
{
private $table;
public function __construct()
{
parent::__construct();
$this->table = db_prefix() . 'mi_modulo_items';
}
public function get_all()
{
return $this->db->get($this->table)->result_array();
}
public function get($id)
{
$this->db->where('id', $id);
return $this->db->get($this->table)->row();
}
public function add($data)
{
$data['datecreated'] = date('Y-m-d H:i:s');
$this->db->insert($this->table, $data);
return $this->db->insert_id();
}
public function update($id, $data)
{
$this->db->where('id', $id);
return $this->db->update($this->table, $data);
}
public function delete($id)
{
$this->db->where('id', $id);
return $this->db->delete($this->table);
}
}
4. Archivo de Instalación
El archivo install.php crea las tablas necesarias cuando se activa el módulo:
<?php
defined('BASEPATH') or exit('No direct script access allowed');
$CI = &get_instance();
// Crear tabla principal
if (!$CI->db->table_exists(db_prefix() . 'mi_modulo_items')) {
$CI->db->query("
CREATE TABLE `" . db_prefix() . "mi_modulo_items` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`nombre` VARCHAR(255) NOT NULL,
`descripcion` TEXT,
`activo` TINYINT(1) DEFAULT 1,
`datecreated` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
}
5. Traducciones (i18n)
Siempre incluye traducciones para español e inglés:
// language/spanish/mi_modulo_lang.php
<?php
$lang['mi_modulo_title'] = 'Mi Módulo';
$lang['mi_modulo_item'] = 'Elemento';
$lang['mi_modulo_add_new'] = 'Añadir Nuevo';
$lang['mi_modulo_name'] = 'Nombre';
$lang['mi_modulo_description'] = 'Descripción';
// language/english/mi_modulo_lang.php
<?php
$lang['mi_modulo_title'] = 'My Module';
$lang['mi_modulo_item'] = 'Item';
$lang['mi_modulo_add_new'] = 'Add New';
$lang['mi_modulo_name'] = 'Name';
$lang['mi_modulo_description'] = 'Description';
✅ Checklist Pre-Publicación
Antes de publicar tu módulo, verifica: ✓ Permisos de archivos (644) y carpetas (755) ✓ Todas las cadenas traducidas ✓ README.md incluido ✓ CHANGELOG.md actualizado ✓ Sin errores PHP (php -l archivo.php)
Conclusión
Ahora tienes los conocimientos básicos para crear módulos en Perfex CRM. Recuerda siempre seguir las convenciones del framework, usar los helpers nativos y mantener tu código limpio y documentado.
En próximos artículos exploraremos temas más avanzados como DataTables server-side, APIs REST y el sistema de migraciones.