/** * Dada una estructura de herencia multiple (dada por getMultipleTableInheritanceStructureToGenerateModel) */ public static function getPartialInstantes($struct) { $sol = array(); foreach ($struct as $class => $subclassesOnSameTable) { $c_ins = new $class(); // FIXME: supongo que ya tiene withTable, luego veo el caso que no se le ponga WT a la superclase... // FIXME: como tambien tiene los atributos de las superclases y como van en otra tabla, hay que sacarlos. foreach ($subclassesOnSameTable as $subclass) { $sc_ins = new $subclass(); // Para setear los atributos. $props = $sc_ins->getAttributeTypes(); $hone = $sc_ins->getHasOne(); $hmany = $sc_ins->getHasMany(); $constraints = $sc_ins->getConstraints(); foreach ($props as $name => $type) { $c_ins->addAttribute($name, $type); } foreach ($hone as $name => $type) { $c_ins->addHasOne($name, $type); } foreach ($hmany as $name => $type) { $c_ins->addHasMany($name, $type); } foreach ($constraints as $attr => $constraintList) { $c_ins->addConstraints($attr, $constraintList); } } $parent_class = get_parent_class($c_ins); if ($parent_class !== 'PersistentObject') { // La superclase de c_ins se mapea en otra tabla, saco esos atributos... $suc_ins = new $parent_class(); $c_ins = PersistentObject::less($c_ins, $suc_ins); // Saco los atributos de la superclase } $sol[] = $c_ins; } return $sol; }
/** * generateAll * Genera todas las tablas correspondientes al modelo previamente cargado. * * @pre Deberia haber cargado, antes de llamar, todas las clases persistentes. */ public static function generateAll() { Logger::getInstance()->pm_log("TableGen::generateAll ======"); $yupp = new Yupp(); $appNames = $yupp->getAppNames(); foreach ($appNames as $appName) { $dalForApp = new DAL($appName); // No puedo usar this->dal porque esta configurada para 'core' // Todas las clases del primer nivel del modelo. $A = ModelUtils::getSubclassesOf('PersistentObject', $appName); // FIXME> no es recursiva! // Se utiliza luego para generar FKs. $generatedPOs = array(); foreach ($A as $clazz) { $struct = MultipleTableInheritanceSupport::getMultipleTableInheritanceStructureToGenerateModel($clazz); // struct es un mapeo por clave las clases que generan una tabla y valor las clases que se mapean a esa tabla. foreach ($struct as $class => $subclassesOnSameTable) { // Instancia que genera tabla $c_ins = new $class(); // FIXME: supongo que ya tiene withTable, luego veo el caso que no se le ponga WT a la superclase... // FIXME: como tambien tiene los atributos de las superclases y como van en otra tabla, hay que sacarlos. // Para cara subclase que se mapea en la misma tabla foreach ($subclassesOnSameTable as $subclass) { $sc_ins = new $subclass(); // Para setear los atributos. $props = $sc_ins->getAttributeTypes(); $hone = $sc_ins->getHasOne(); $hmany = $sc_ins->getHasMany(); // FIXME: si el artibuto no es de una subclase parece que tambien pone nullable true... // Agrega constraint nullable true, para que los atributos de las subclases // puedan ser nulos en la tabla, para que funcione bien el mapeo de herencia de una tabla. //Logger::getInstance()->pm_log( "Para cada attr de: $subclass " . __FILE__ . " " . __LINE__); foreach ($props as $attr => $type) { // FIXME: esta parte seria mas facil si simplemente cuando la clase tiene la constraint // y le seteo otra del mismo tipo para el mismo atributo, sobreescriba la anterior. $constraint = $sc_ins->getConstraintOfClass($attr, 'Nullable'); if ($constraint !== NULL) { //Logger::getInstance()->log( "CONTRAINT NULLABLE EXISTE!"); // Si hay, setea en true $constraint->setValue(true); } else { // Si no hay, agrega nueva //Logger::getInstance()->log( "CONTRAINT NULLABLE NO EXISTE!, LA AGREGA"); $sc_ins->addConstraints($attr, array(Constraint::nullable(true))); } } //Logger::getInstance()->pm_log( "Termina con las constraints ======= " . __FILE__ . " " . __LINE__); // Se toma luego de modificar las restricciones $constraints = $sc_ins->getConstraints(); foreach ($props as $name => $type) { $c_ins->addAttribute($name, $type); } foreach ($hone as $name => $type) { $c_ins->addHasOne($name, $type); } foreach ($hmany as $name => $type) { $c_ins->addHasMany($name, $type); } // Agrego las constraints al final porque puedo referenciar atributos que todavia no fueron agregados. foreach ($constraints as $attr => $constraintList) { $c_ins->addConstraints($attr, $constraintList); } } $parent_class = get_parent_class($c_ins); if ($parent_class !== 'PersistentObject') { // La superclase de c_ins se mapea en otra tabla, saco esos atributos... $suc_ins = new $parent_class(); $c_ins = PersistentObject::less($c_ins, $suc_ins); // Saco los atributos de la superclase } $tableName = YuppConventions::tableName($c_ins); // FIXME: esta operacion necesita instanciar una DAL por cada aplicacion. // La implementacion esta orientada a la clase, no a la aplicacion, hay que modificarla. // Si la tabla ya existe, no la crea. if (!$dalForApp->tableExists($tableName)) { // FIXME: c_ins no tiene las restricciones sobre los atributos inyectados. self::generate($c_ins, $dalForApp); // Para luego generar FKs. $generatedPOs[] = $c_ins; } } // foreach ($struct as $class => $subclassesOnSameTable) } // foreach( $A as $clazz ) // ====================================================================== // Crear FKs en la base. //Logger::struct( $generatedPOs, "GENERATED OBJS" ); foreach ($generatedPOs as $ins) { $tableName = YuppConventions::tableName($ins); $fks = array(); // FKs hasOne $ho_attrs = $ins->getHasOne(); foreach ($ho_attrs as $attr => $refClass) { // Problema: pasa lo mismo que pasaba en YuppConventions.relTableName, esta tratando // de inyectar la FK en la tabla incorrecta porque la instancia es de una superclase // de la clase donde se declara la relacion HasOne, entonces hay que verificar si una // subclase no tiene ya el atributo hasOne declarado, para asegurarse que es de la // instancia actual y no intentar generar la FK si no lo es. $instConElAtributoHasOne = NULL; $subclasses = ModelUtils::getAllAncestorsOf($ins->getClass()); foreach ($subclasses as $aclass) { $ains = new $aclass(); if ($ains->hasOneOfThis($refClass)) { //Logger::getInstance()->log( $ains->getClass() . " TIENE UNO DE: $refClass" ); $instConElAtributoHasOne = $ains; // EL ATRIBUTO ES DE OTRA INSTANCIA! break; } } // Si el atributo de FK hasOne es de la instancia actual, se genera: if ($instConElAtributoHasOne === NULL) { // Para ChasOne esta generando "chasOne", y el nombre de la tabla que aparece en la tabla es "chasone". $refTableName = YuppConventions::tableName($refClass); $fks[] = array('name' => DatabaseNormalization::simpleAssoc($attr), 'table' => $refTableName, 'refName' => 'id'); } } // FKs tablas intermedias HasMany $hasMany = $ins->getHasMany(); foreach ($hasMany as $attr => $assocClassName) { //Logger::getInstance()->pm_log("AssocClassName: $assocClassName, attr: $attr"); if ($ins->isOwnerOf($attr)) { $hm_fks = array(); $hasManyTableName = YuppConventions::relTableName($ins, $attr, new $assocClassName()); // "owner_id", "ref_id" son FKs. // =============================================================================== // El nombre de la tabla owner para la FK debe ser el de la clase // donde se declara el attr hasMany, // no para el ultimo de la estructura de MTI (como pasaba antes). $classes = ModelUtils::getAllAncestorsOf($ins->getClass()); //Logger::struct( $classes, "Superclases de " . $ins1->getClass() ); $instConElAtributoHasMany = $ins; // En ppio pienso que la instancia es la que tiene el atributo masMany. foreach ($classes as $aclass) { $_ins = new $aclass(); if ($_ins->hasManyOfThis($assocClassName)) { //Logger::getInstance()->log("TIENE MANY DE " . $ins2->getClass()); $instConElAtributoHasMany = $_ins; break; } //Logger::struct( $ins, "Instancia de $aclass" ); } // =============================================================================== $hm_fks[] = array('name' => 'owner_id', 'table' => YuppConventions::tableName($instConElAtributoHasMany->getClass()), 'refName' => 'id'); $hm_fks[] = array('name' => 'ref_id', 'table' => YuppConventions::tableName($assocClassName), 'refName' => 'id'); // Genera FKs $dalForApp->addForeignKeys($hasManyTableName, $hm_fks); } } // foreach hasMany // Genera FKs $dalForApp->addForeignKeys($tableName, $fks, false); } // foreach PO } // foreach app }