Modelos dinámicos en CakePHP

Últimamente estoy experimentando mucho con CakePHP y una de las cosas que he necesitado es crear unos modelos en los que pudiera cambiar en tiempo de ejecución la base de datos con la que están enlazados.

Básicamente estoy construyendo un portal en el que se aglutinan una serie de utilidades, y alguna de estas utilidades atacan a otras bases de datos independientes de portal.

Lo que se me ha ocurrido es crear en la base de datos del portal una tabla en la que almaceno la configuración de las bases de datos a las que quiero acceder (algunas de ellas comparten modelo). De esta manera puedo crear de manera dinámica las conexiones necesarias y enlazarlas con los modelos que necesite en ese momento.

La tabla es la siguiente:

CREATE TABLE databases (
  id int(11) unsigned NOT NULL AUTO_INCREMENT, 
  name varchar(20) NOT NULL DEFAULT '', 
  datasource varchar(255) NOT NULL DEFAULT 'Database/Mysql', 
  persistent tinyint(1) DEFAULT NULL, 
  host varchar(255) DEFAULT NULL, 
  login varchar(255) DEFAULT NULL, 
  password varchar(255) DEFAULT NULL, 
  database varchar(255) DEFAULT NULL, 
  prefix varchar(255) DEFAULT NULL, 
  encoding varchar(255) NOT NULL DEFAULT 'utf8', 
  PRIMARY KEY (id), 
  UNIQUE KEY name_UNIQUE (name) 
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

Y este sería uno de los modelos:

<?php
  App::uses('Model', 'Model');
  App::uses('ConnectionManager', 'Model');

  class EjemploUnoModel extends Model {
    public $useDbConfig = 'default';
    public $useTable = 'uno';
    public $primaryKey = 'clave';
    public $name = 'uno';
    public $hasMany = [
      'dos' => [
        'foreignKey' => 'clave',
        'associationForeignKey' => 'claveuno',
      ],
    ];

    public function __construct($id = false, $table = null, $ds = null) {
      if (isset($id['Database'])) {
        ConnectionManager::create($id['Database']['name'], $id['Database']);
        $this->useDbConfig = $id['Database']['name'];
        $id = false;
      }

      $this->dos->useDbConfig = $this->useDbConfig;
      $this->dos->useTable = 'dos';
      $this->dos->primaryKey = 'clavedos';
      $this->dos->name = 'dos';

      parent::__construct();
    }
  }

El ejemplo tiene también un enlace con otra tabla, en este caso llamada “dos”. En la documentación del CakePHP se explica que foreingKey es el campo de la tabla “uno” que realiza en enlace, y el associationForeignKey es el campo de la tabla “dos”. Para definir las propiedades relativas a la tabla “dos”, como el origen de datos (useDbConfig) lo hacemos en el constructor.

Y así es cómo lo utilizo:

App::uses('EjemploUnoModel', 'Model');
$database['Database'] = $this->Database->find('first', ['conditions' => ['name' => 'baseuno'], 'recursive' => -1]);
$uno = new EjemploUnoModel($database);
$lista = $uno->find('list', ['fields' => ['nombre'], 'recursive' => -1]);

El ejemplo hace una cosa un poco extraña

$database['Database'] = ...

esto es porque al ser un ejemplo he simplificado el esquema real de trabajo ya que tengo una tabla donde guardo los sistemas a los que voy a acceder y que está enlazada con la tabla databases que es donde se guardan las conexiones de las bases de datos… pero creo que se entiende.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *