/**
  * 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
         }
     }
 }