--- name: perfex-migrations description: Migrações e upgrades de módulos Perfex CRM — gestão de versões, ficheiros de migração e actualizações de base de dados. Baseado apenas na documentação oficial. --- # /perfex-migrations - Migrations Perfex CRM Sistema de migrações e upgrades de módulos. **Zero assumptions, zero hallucinations** - apenas documentação oficial. --- ## Documentação Base - [Preparing Module Upgrade](https://help.perfexcrm.com/preparing-module-upgrade/) - [Module Basics](https://help.perfexcrm.com/module-basics/) --- ## Como Funciona O Perfex CRM compara: - **Versão no init file** (header `Version:`) - **Versão na base de dados** (tabela `tblmodules`) Se forem diferentes → Sistema mostra "Database upgrade required". --- ## Estrutura de Migrations ``` modules/meu_modulo/ ├── meu_modulo.php # Init file com Version: X.Y.Z └── migrations/ ├── 001_version_100.php # v1.0.0 → v1.0.1 ├── 002_version_101.php # v1.0.1 → v1.0.2 ├── 100_version_100.php # v1.0.0 inicial (alternativa) ├── 110_version_110.php # v1.1.0 └── 200_version_200.php # v2.0.0 ``` --- ## Formato do Ficheiro ### Nomenclatura (CRÍTICO) O Perfex usa **Sequential Migration** (não Timestamp). ``` NNN_version_NNN.php │ │ │ │ │ └── Versão sem pontos (110 = 1.1.0) │ └── Literal "version" └── Número sequencial (3 dígitos, sem gaps) ``` **Exemplos:** | Versão | Ficheiro | |--------|----------| | 1.0.0 | `001_version_100.php` ou `100_version_100.php` | | 1.0.1 | `002_version_101.php` ou `101_version_101.php` | | 1.1.0 | `003_version_110.php` ou `110_version_110.php` | | 2.0.0 | `004_version_200.php` ou `200_version_200.php` | **Convenção recomendada:** Usar versão como prefixo (100, 110, 200...). --- ## Template Migration ```php db->field_exists('new_column', db_prefix() . 'meu_modulo')) { $CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo` ADD COLUMN `new_column` VARCHAR(255) DEFAULT NULL AFTER `name`'); } } } ``` ### Criar Nova Tabela ```php db->table_exists(db_prefix() . 'meu_modulo_items')) { $CI->db->query(' CREATE TABLE `' . db_prefix() . 'meu_modulo_items` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `parent_id` INT(11) UNSIGNED NOT NULL, `name` VARCHAR(255) NOT NULL, `quantity` INT(11) NOT NULL DEFAULT 1, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . '; '); } } } ``` ### Modificar Coluna ```php db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo` MODIFY COLUMN `amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00'); } } ``` ### Adicionar Índice ```php db->query('SHOW INDEX FROM `' . db_prefix() . 'meu_modulo` WHERE Key_name = "idx_status"')->result(); if (count($indexes) == 0) { $CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo` ADD INDEX `idx_status` (`status`)'); } } } ``` ### Migração de Dados ```php db->query('UPDATE `' . db_prefix() . 'meu_modulo` SET `status` = "active" WHERE `status` = "1"'); $CI->db->query('UPDATE `' . db_prefix() . 'meu_modulo` SET `status` = "inactive" WHERE `status` = "0"'); } } ``` ### Adicionar Opção ```php db->table_exists(db_prefix() . 'meu_modulo')) { $CI->db->query(' CREATE TABLE `' . db_prefix() . 'meu_modulo` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `client_id` INT(11) UNSIGNED NOT NULL, `name` VARCHAR(255) NOT NULL, `new_column` VARCHAR(255) DEFAULT NULL, -- Adicionado v1.1.0 `description` TEXT, `amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00, -- Modificado v1.3.0 `status` VARCHAR(50) NOT NULL DEFAULT "pending", `created_at` DATETIME NOT NULL, `updated_at` DATETIME DEFAULT NULL, PRIMARY KEY (`id`), KEY `client_id` (`client_id`), KEY `idx_status` (`status`) -- Adicionado v1.4.0 ) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . '; '); } // Tabela items (adicionada v1.2.0) if (!$CI->db->table_exists(db_prefix() . 'meu_modulo_items')) { $CI->db->query(' CREATE TABLE `' . db_prefix() . 'meu_modulo_items` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `parent_id` INT(11) UNSIGNED NOT NULL, `name` VARCHAR(255) NOT NULL, `quantity` INT(11) NOT NULL DEFAULT 1, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . '; '); } // Opções (versão mais recente) add_option('meu_modulo_version', '1.7.0'); add_option('meu_modulo_new_feature', '1'); // v1.6.0 add_option('meu_modulo_default_status', 'pending'); // v1.6.0 } ``` --- ## Workflow de Release ### 1. Desenvolver Alterações ```php // Exemplo: Adicionar campo "priority" na v1.8.0 ``` ### 2. Criar Migration ```php // migrations/180_version_180.php db->field_exists('priority', db_prefix() . 'meu_modulo')) { $CI->db->query('ALTER TABLE `' . db_prefix() . 'meu_modulo` ADD COLUMN `priority` TINYINT(1) NOT NULL DEFAULT 0 AFTER `status`'); } } } ``` ### 3. Actualizar Activation Hook ```php // Adicionar campo ao CREATE TABLE no activation hook `priority` TINYINT(1) NOT NULL DEFAULT 0, ``` ### 4. Actualizar Versão no Header ```php /* Module Name: Meu Módulo Version: 1.8.0 Requires at least: 2.3.* */ ``` ### 5. Testar 1. Instalação limpa (activation hook) 2. Upgrade de versão anterior (migration) --- ## Verificações de Segurança em Migrations ```php public function up() { $CI = &get_instance(); // Verificar se tabela existe antes de ALTER if (!$CI->db->table_exists(db_prefix() . 'meu_modulo')) { return; // Tabela não existe, nada a fazer } // Verificar se coluna existe antes de ADD if ($CI->db->field_exists('new_column', db_prefix() . 'meu_modulo')) { return; // Coluna já existe } // Seguro para executar $CI->db->query('ALTER TABLE ...'); } ``` --- ## Anti-Patterns (NUNCA FAZER) | Anti-Pattern | Risco | Alternativa | |--------------|-------|-------------| | Gaps na sequência (001, 003) | Migrations saltadas | Sequência contínua | | Não actualizar activation hook | Instalações novas incompletas | Sincronizar sempre | | ALTER sem verificar existência | Erro se já existe | `field_exists()` | | DROP sem backup | Dados perdidos | Backup ou soft delete | | Hardcode prefix "tbl" | Falha em instalações custom | `db_prefix()` | --- ## Checklist Migrations ``` 1. [ ] Ficheiro com nome correcto (NNN_version_NNN.php) 2. [ ] Classe com nome correcto (Migration_Version_NNN) 3. [ ] Extends App_module_migration 4. [ ] Verificações de existência antes de ALTER 5. [ ] db_prefix() em todas as queries 6. [ ] Activation hook actualizado com schema completo 7. [ ] Header Version actualizado 8. [ ] Testado: instalação limpa 9. [ ] Testado: upgrade de versão anterior 10. [ ] Sem gaps na sequência de migrations ``` --- **Versão:** 1.0.0 | **Autor:** Descomplicar® **Fonte:** help.perfexcrm.com/preparing-module-upgrade