/** * Affiches les disques de l'utilisateur */ public function indexAction() { //TODO 4.2 $controller = $this; $user = Auth::getUser($controller); $cloud = $this->config->cloud; $this->view->setVar("cloud", $cloud); $this->view->setVar("user", $user); $disques = Disque::find(array("idUser" => $user->getId(), "order" => "name")); $this->view->setVar("disques", $disques); $occupation = ModelUtils::getDisqueOccupation($disques); $this->view->setVar("occupation", $occupation); $this->jquery->compile($this->view); }
/** * Nombre de la tabla que almacena informacion sobre la relacion entre 2 instancias de PO. * El nombre de la tabla de la relacion es el nombre derivado de la instancia1 concatenado * al nombre del atributo que apunta a la instancia 2, concatenado al nombre derivador de * la instancia 2. * @param PersistentObject $ins1 Instancia duenia de la asociacion. * @param String Atributo de $ins1 que apunta a $ins2. * @param PersistentObject $ins2 Instancia hija en la asociacion. */ public static function relTableName(PersistentObject $ins1, $inst1Attr, PersistentObject $ins2) { // Problema: si el atributo pertenece a C1, y $ins1 es instancia de G1, // la tabla que se genera para hasMany a UnaClase es "gs_unaclase_" // y deberia ser "cs_unaclase_", esto es un problema porque si cargo // una instancia de C1 no tiene acceso a sus hasMany "UnaClase". // TODO: esta es una solucion rapida al problema, hay que mejorarla. // Esta solucion intenta buscar cual es la clase en la que se declara el atributo hasMany // para el que se quiere generar la tabla intermedia de referencias, si no la encuentra, // es que el atributo hasMany se declaro en $ins1. // Tambien hay un problema cuando hay composite> // Si ins1->hasMany[ins1Attr] es a una superclase de ins2, genera mal el nombre de la tabla de join. // El nombre se tiene que generar a la clase para la que se declara le hasMany, // no para el nombre de tabla de ins2 (porque ins2 puede guardarse en otra tabla // que no sea la que se guarda su superclase a la cual fue declarado el hasMany // ins1->hasMany[inst1Attr]). // Solucion: ver si la clase a la que se declara el hasMany no es la clase de ins2, // y verificar si ins2 se guarda en otra tabla que la clase a la que se // declara el hasMany en ins1. Si es distinta, el nombre debe apuntar al // de la clase declarada en el hasMany. (aunque en ambos casos es a esto, // asi que no es necesario verificar). $classes = ModelUtils::getAllAncestorsOf($ins1->getClass()); //Logger::struct( $classes, "Superclases de " . $ins1->getClass() ); $instConElAtributoHasMany = $ins1; // En ppio pienso que la instancia es la que tiene el atributo masMany. foreach ($classes as $aclass) { $ins = new $aclass(NULL, true); //if ( $ins->hasManyOfThis( $ins2->getClass() ) ) // la clase no es la que tenga el atributo, debe ser en la que se declara el atributo if ($ins->attributeDeclaredOnThisClass($inst1Attr)) { //Logger::getInstance()->log("TIENE MANY DE " . $ins2->getClass()); $instConElAtributoHasMany = $ins; break; } //Logger::struct( $ins, "Instancia de $aclass" ); } $tableName1 = self::tableName($instConElAtributoHasMany); //echo "=== " . $ins1->getAttributeType( $inst1Attr ) . " ==== <br/>"; // La tabla de join considera la tabla en la que se guardan las instancias del tipo // declarado en el hasMany, NO A LOS DE SUS SUBCLASES!!! (como podia ser ins2) $tableName2 = self::tableName($ins1->getAttributeType($inst1Attr)); // $tableName2 = self::tableName( $ins2 ); // TODO: Normalizar $inst1Attr ? // echo "Nombre tabla relTableName: ". $tableName1 . "_" . $inst1Attr . "_" . $tableName2 ."<br/>"; return $tableName1 . "_" . $inst1Attr . "_" . $tableName2; // owner_child }
/** * Obtiene la superclase de esta donde fue declarado el atributo. * Si no encuentra el atributo, devuelve null. */ public function getSuperClassWithDeclaredAttribute($attr) { $superClasses = ModelUtils::getAllAncestorsOf($this->getClass()); foreach ($superClasses as $superClass) { $superInstance = new $superClass(NULL, true); if ($superInstance->attributeDeclaredOnThisClass($attr)) { return $superClass; } } return NULL; // El atributo no fue declarado en ninguna superclase. }
<?php // Depende de clase FileSystem xq tiene que leer los archivos // de un directorio dado para levantar clases (include de esos archivos). // TODO: Una clase FileSystem que sepa hacer funciones sobre directorios // y archivos (ver la clase en SWP_CMS) /* * Created on 24/02/2008 * */ include_once 'core.utils.ModelUtils.class.php'; echo "<pre>"; print_r(ModelUtils::getModelClasses()); echo "</pre>";
/** * Dada una instancia de PO, devuelve una estructura con las clases que se deben guardar * en distintas tablas y los atrbibutos de cada una con sus respectivos valores. */ public static function getPartialInstancesToSave($po_ins) { Logger::getInstance()->dal_log("MTI::getPartialInstancesToSave " . $po_ins->getClass()); //Logger::struct( $po_ins, __FILE__ . ".getPartialInstancesToSave " . __LINE__ ); // TODO: (performance) si el objeto no representa un MTI no deberia hacerse todo el trabajo de copiar cada atributo del objeto, // eso deberia verificarse antes, y de no ser un MTI, devolver nomas un array con el objeto entrante. // Para simplificar y no tener que hacer aGet sobre po_ins $values = $po_ins->getAttributeValues(); //$superclasses = ModelUtils::getAllAncestorsOf( $po_ins->getClass() ); // puede ser en cualquier orden! $superclasses = ModelUtils::getAllAncestorsOf($values['class']); // puede ser en cualquier orden! /* // Quiero la clase de nivel 1 $level1Class = NULL; foreach ( $superclasses as $class ) { if ( get_parent_class( $class ) == 'PersistentObject' ) { $level1Class = $class; break; // salir del foreach } } $struct = self::getMultipleTableInheritanceStructureToGenerateModel( array($level1Class) ); */ // Lo anterior es lo mismo que hacer esto: // NO! SERIA LO MISMO SI LA INSTANCIA QUE ME PASAN ES DE LA ULTIMA CLASE DE LA ESTRUCTURA DE HERENCIA. // CORRECCION, esta bien porque hace getClass, y obtiene la clase real que es la ultima de la estructura!!!! //$superclasses[] = $po_ins->getClass(); $superclasses[] = $values['class']; // Mapa de clases y subclases que se mapean en la misma tabla. $struct = self::getMultipleTableInheritance($superclasses); //Logger::getInstance()->dal_log("getMultipleTableInheritance (son las subclases en la misma tabla) " . __FILE__ . " " . __LINE__ ); //Logger::struct( $struct ); // TODO: Partial Instances no considera valores, tengo que setear los valores a mano a partir de los valores de po_ins. $partialInstances = self::getPartialInstantes($struct); // Instancias de las clases en $superclasses que solo tienen los atributos que van en cada tabla. Cada clase de estas se mapea directamente con una tabla. foreach ($partialInstances as $partialInstance) { $attrs_values = $partialInstance->getAttributeTypes(); // El tipo no lo uso para nada, solo necesito la declaracion de atributos. foreach ($attrs_values as $attr => $type) { //echo $partialInstance->getClass() . " " . $po_ins->getClass() . " $attr<br />"; //if ( $partialInstance->getClass() === $po_ins->getClass() || // Seteo atributos inyectados tambien, xq son de esta instancia! if ($partialInstance->getClass() === $values['class'] || !PersistentObject::isInyectedAttribute($attr)) { // =============================================================================== // aGet tiene cierta complejidad pidiendo values directamente es mas rapido //$partialInstance->aSet($attr, $po_ins->aGet($attr)); $partialInstance->aSet($attr, $values[$attr]); // PO garantiza que vienen valores para todos los indices, aunque sean NULL, por eso no es necesario hacer un isset($values[$attr]) } } // El deleted, si la instancia a salvar esta deleted, todos los registros deben estarlo! //$partialInstance->setDeleted( $po_ins->getDeleted() ); $partialInstance->setDeleted($values['deleted']); } // getPartialInstancesToSave return $partialInstances; // derecho para salvar cada uno usando save_object!!! }
/** * 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 }
public function delete($persistentInstance, $id, $logical) { Logger::getInstance()->pm_log("PM::delete"); //Logger::add( Logger::LEVEL_PM, "PM::delete ". __FILE__."@". __LINE__ ); // Se asume que la instancia ya es la ultima porque esta cargada con "get" // o con "listAll" que garantiza que carga la instancia completa. // Borra el registro de la clase actual (no estaba incluida en los ancestors si es MTI) // Si no es MTI, este es el lunico delete que se hace $this->dal->delete($persistentInstance->getClass(), $id, $logical); // Soporte MTI if (MultipleTableInheritanceSupport::isMTISubclassInstance($persistentInstance)) { // Ahora tengo que pedir las superclases y para cada una, borrar la instancia parcial $superclasses = ModelUtils::getAllAncestorsOf($persistentInstance->getClass()); foreach ($superclasses as $mtiClass) { $this->dal->delete($mtiClass, $id, $logical); // Todas las instancias parciales tienen el mismo id } } }