/** * Devuelve la superclase de $class que genera la tabla donde se guarda $class. * Si $class es de nivel 1, se retorna $class. */ public static function superclassThatGenerateMyTable($class) { $parent = get_parent_class($class); if ($parent === 'PersistentObject') { return $class; } $classTable = YuppConventions::tableName($class); // Tengo que ir para arriba y ver quien es el ultimo que tiene la tabla // igual a la mia, antes de llegar a PO o llegar a otro con distinta tabla. // Chekeo si ya la primer superclase se mapea en una tabla distinta, devuelvo $class. $superclassTable = YuppConventions::tableName($parent); if ($classTable != $superclassTable) { return $class; } // $class y $parent se mapean en la misma tabla. $prevClassToIterate = $parent; $classToIterate = get_parent_class($parent); // Puede ser PO. $found = false; while (!$found && $classToIterate !== 'PersistentObject') { $superclassTable = YuppConventions::tableName($classToIterate); if ($classTable != $superclassTable) { $found = true; // Quiero la clase que genera la tabla anterior. } else { $prevClassToIterate = $classToIterate; $classToIterate = get_parent_class($classToIterate); } } return $prevClassToIterate; }
public function test1() { PersistentManager::getInstance()->generateAll(); echo YuppConventions::tableName('Pagina') . "<br/>"; /** * Resultado> * * CREATE TABLE test_a004_pagina (id INT(11) DEFAULT 1 PRIMARY KEY, titulo VARCHAR(255) NULL, contenido MEDIUMTEXT NULL, class TEXT NOT NULL, deleted BOOL NOT NULL, owner_id INT(11) NULL); * * CREATE TABLE test_a004_pagina_subpages_test_a004_pagina (id INT(11) DEFAULT 1 PRIMARY KEY, owner_id INT(11) NOT NULL, ref_id INT(11) NOT NULL, type INT(11) NOT NULL, deleted BOOL NOT NULL, class TEXT NOT NULL, ord INT(11) NULL); * * ALTER TABLE test_a004_pagina_subpages_test_a004_pagina ADD FOREIGN KEY (owner_id) REFERENCES test_a004_pagina(id); * * ALTER TABLE test_a004_pagina_subpages_test_a004_pagina ADD FOREIGN KEY (ref_id) REFERENCES test_a004_pagina(id); * * ALTER TABLE test_a004_pagina ADD FOREIGN KEY (owner_id) REFERENCES test_a004_pagina(id); * */ // TODO: verificar si la tabla para Nariz y Cara fue creada. //$dal = DAL::getInstance(); $dal = new DAL('tests'); $this->assert($dal->tableExists(YuppConventions::tableName('Pagina')), 'TestCaseA004: Test generar tabla'); }
/** * Se recibe un objecto a la que ya se ha verificado que debe insertarse en la base de datos. * @param $object POs a salvar. */ private function insert_query($object, $tableName = NULL) { Logger::getInstance()->dal_log("DAL:insert_query " . __FILE__ . " " . __LINE__); // INSERT INTO hello_world_persona ( nombre ,edad ,class ,id ,deleted ) VALUES ('pepe' ,'12' ,'Persona' ,'6' ,'' ); if (!$tableName) { $tableName = YuppConventions::tableName($object); } $q = "INSERT INTO " . $tableName . " ( "; // DBSTD $attrs = $object->getAttributeTypes(); // Recorro todos los atributos simples... $tableAttrs = ""; foreach ($attrs as $attr => $type) { $tableAttrs .= DatabaseNormalization::col($attr) . " ,"; // DBSTD } $tableAttrs = substr($tableAttrs, 0, sizeof($tableAttrs) - 2); $q .= $tableAttrs; $q .= ") VALUES ("; // El codigo es distinto al de update porque la forma de la consulta es distinta. // TODO: Si el valor es null tengo que poner null en la tabla, no el string vacio. // TODO: Verificar atributos no nullables en null en la instancia de la clase, esto falta agregar cosas a la clase persistente, "las restricciones" $tableVals = ""; foreach ($attrs as $attr => $type) { $value = $object->aGet($attr); // Valor del atributo simple. if ($value === NULL) { $tableVals .= "NULL ,"; } else { if (is_string($value)) { $tableVals .= "'" . addslashes($value) . "' ,"; } else { if (is_bool($value)) { $tableVals .= "'" . ($value === true ? "1" : "0") . "' ,"; } else { $tableVals .= "'" . $value . "' ,"; } } } // FIXME: OJO, si no es literal no deberia poner comillas !!!! y si es null deberia guardar null //echo $attr . " tiene tipo: " . gettype($value) . " y valor '" . $value . "'<br/>"; } $tableVals = substr($tableVals, 0, sizeof($tableVals) - 2); $q .= $tableVals; $q .= ");"; // Si hay una excepcion, llega hasta la capa superior. $this->db->execute($q); }
private function test1() { PersistentManager::getInstance()->generateAll(); echo YuppConventions::tableName('M010_Persona') . "<br/>"; /** * Resultado> * * CREATE TABLE test_m010_persona ( * id INT(11) DEFAULT 1 PRIMARY KEY, * nombre TEXT NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL * ); * * CREATE TABLE test_m010_persona_hijos_test_m010_persona ( * id INT(11) DEFAULT 1 PRIMARY KEY, * owner_id INT(11) NOT NULL, * ref_id INT(11) NOT NULL, * type INT(11) NOT NULL, * deleted BOOL NOT NULL, * class TEXT NOT NULL, * ord INT(11) NULL * ); * */ // TODO: verificar si la tabla para Nariz y Cara fue creada. //$dal = DAL::getInstance(); $dal = new DAL('tests'); if ($dal->tableExists(YuppConventions::tableName('M010_Persona'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } }
private function test1() { PersistentManager::getInstance()->generateAll(); echo YuppConventions::tableName('Contenido1') . "<br/>"; echo YuppConventions::tableName('Recipiente1') . "<br/>"; echo YuppConventions::tableName('Vaso1') . "<br/>"; /** * Resultado> * * CREATE TABLE test_i006_contenido1 (id INT(11) DEFAULT 1 PRIMARY KEY, elemento VARCHAR(30) NULL, volumen FLOAT NULL, class TEXT NOT NULL, deleted BOOL NOT NULL); * * CREATE TABLE test_i005_contenido ( * id INT(11) DEFAULT 1 PRIMARY KEY, * elemento VARCHAR(30) NULL, * volumen FLOAT NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL * ); * * CREATE TABLE test_i006_vaso1 (id INT(11) DEFAULT 1 PRIMARY KEY, marca TEXT NULL, class TEXT NOT NULL, deleted BOOL NOT NULL, contenido_id INT(11) NULL, super_id_recipiente1 INT(11) NOT NULL); * * CREATE TABLE test_i005_vaso ( * id INT(11) DEFAULT 1 PRIMARY KEY, * marca TEXT NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL, * contenido_id INT(11) NULL, * super_id_recipiente INT(11) NOT NULL * ); * * CREATE TABLE test_i006_recipiente1 (id INT(11) DEFAULT 1 PRIMARY KEY, material VARCHAR(30) NULL, capacidad FLOAT NULL, tieneTapa BOOL NULL, class TEXT NOT NULL, deleted BOOL NOT NULL); * * CREATE TABLE test_i005_recipiente ( * id INT(11) DEFAULT 1 PRIMARY KEY, * material VARCHAR(30) NULL, * capacidad FLOAT NULL, * tieneTapa BOOL NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL * ); * * ALTER TABLE test_i006_vaso1 ADD FOREIGN KEY (super_id_recipiente1) REFERENCES test_i006_recipiente1(id); * * ALTER TABLE test_i005_vaso * ADD FOREIGN KEY (super_id_recipiente) * REFERENCES test_i005_recipiente(id); * * ALTER TABLE test_i006_vaso1 ADD FOREIGN KEY (contenido_id) REFERENCES test_i005_contenido(id); * * ALTER TABLE test_i005_vaso * ADD FOREIGN KEY (contenido_id) * REFERENCES test_i005_contenido(id); */ // TODO: verificar si la tabla para Nariz y Cara fue creada. //$dal = DAL::getInstance(); $dal = new DAL('tests'); if ($dal->tableExists(YuppConventions::tableName('Contenido1'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } if ($dal->tableExists(YuppConventions::tableName('Recipiente1'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } if ($dal->tableExists(YuppConventions::tableName('Vaso1'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } }
public function dbStatusAction() { $yupp = new Yupp(); $appNames = $yupp->getAppNames(); $appModelClasses = array(); // [appName][class][tablename,creada o no] // Incluye todas las clases del modelo de todas las apps YuppLoader::loadModel(); // Para saber si se crearon las tablas para todas las // clases del modelo de todas las aplicaciones. $allTablesCreated = true; $fn = new FileNames(); // http://code.google.com/p/yupp/issues/detail?id=123 $createDatabaseForApps = array(); // Aplicaciones a las que se sugiere que se cree su base de datos foreach ($appNames as $appName) { $app = new App($appName); $modelClassFileNames = $app->getModel(); // no incluye las clases, solo obtiene los nombres //print_r($modelClassFileNames); // Necesito que sea plano el array, si no, tengo que hacer recorrida recursiva. // Esto no seria necesario si modifico la recorrida en la vista, para mostrar // la estructura interna de paquetes del modelo de la aplicacion. $modelClassFileNames = $this->array_flatten($modelClassFileNames); //print_r($modelClassFileNames); // Toda la informacion de las clases y tablas creadas para esta app $appModelClasses[$appName] = array(); // http://code.google.com/p/yupp/issues/detail?id=123 try { $dal = new DAL($appName); // Falla sino existe la base para la app $appName } catch (Exception $e) { if ($e->getCode() == 666) { $createDatabaseForApps[] = $appName; } continue; // Para el for appNames } foreach ($modelClassFileNames as $classFileName) { $fileInfo = $fn->getFileNameInfo($classFileName); $className = $fileInfo['name']; // Para incluir las clases (por si no estan incluidas) // Ticket: http://code.google.com/p/yupp/issues/detail?id=71 YuppLoader::load($fileInfo['package'], $className); $tableName = YuppConventions::tableName($className); if ($dal->tableExists($tableName)) { $appModelClasses[$appName][$className] = array('tableName' => $tableName, 'created' => "CREADA"); } else { $appModelClasses[$appName][$className] = array('tableName' => $tableName, 'created' => "NO CREADA"); $allTablesCreated = false; } } } $this->params['allTablesCreated'] = $allTablesCreated; $this->params['appModelClasses'] = $appModelClasses; $this->params['createDatabaseForApps'] = $createDatabaseForApps; return $this->render("dbStatus"); }
public function test1() { $dal = new DAL('tests'); $this->assert($dal->tableExists(YuppConventions::tableName('Entidad')), 'Test 003.1.1 existe tabla'); $this->assert($dal->tableExists(YuppConventions::tableName('TestPersona')), 'Test 003.1.2 existe tabla'); }
private function test1() { PersistentManager::getInstance()->generateAll(); echo YuppConventions::tableName('Dedo') . "<br/>"; echo YuppConventions::tableName('Mano') . "<br/>"; /** * Resultado> * * CREATE TABLE test_m003_dedo ( * id INT(11) DEFAULT 1 PRIMARY KEY, * uniaLarga BOOL NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL * ); * * CREATE TABLE test_m003_mano ( * id INT(11) DEFAULT 1 PRIMARY KEY, * tamanio TEXT NULL, * class TEXT NOT NULL, * deleted BOOL NOT NULL * ); * * CREATE TABLE test_m003_mano_dedos_test_m003_dedo ( * id INT(11) DEFAULT 1 PRIMARY KEY, * owner_id INT(11) NOT NULL, * ref_id INT(11) NOT NULL, * type INT(11) NOT NULL, * deleted BOOL NOT NULL, * class TEXT NOT NULL, * ord INT(11) NULL * ); * * ALTER TABLE test_m003_mano_dedos_test_m003_dedo * ADD FOREIGN KEY (owner_id) * REFERENCES test_m003_mano(id); * * ALTER TABLE test_m003_mano_dedos_test_m003_dedo * ADD FOREIGN KEY (ref_id) * REFERENCES test_m003_dedo(id); * */ // TODO: verificar si la tabla para Nariz y Cara fue creada. //$dal = DAL::getInstance(); $dal = new DAL('tests'); if ($dal->tableExists(YuppConventions::tableName('Dedo'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } if ($dal->tableExists(YuppConventions::tableName('Mano'))) { echo "Test 1 correcto"; } else { echo "Test 1 Incorrecto"; } }
/** * generate * Genera la tabla para una clase y todas las tablas intermedias * para sus relaciones hasMany de la que son suyas. * * Si dalForApp es NULL se usa this->dal, de lo contrario se usa esa DAL. */ private static function generate($ins, $dalForApp = NULL) { Logger::getInstance()->pm_log("TableGen::generate"); // La DAL que se va a usar //$dal = $this->dal; //if ($dalForApp !== NULL) $dal = $dalForApp; $dal = $dalForApp; // FIXME: creo que siempre se pasa dalForApp, no hay porque setear null por defecto. // TODO: Si la tabla existe deberia hacer un respaldo y borrarla y generarla de nuevo. //DROP TABLE IF EXISTS `acceso`; // Si la clase tiene un nombre de tabla, uso ese, si no el nombre de la clase. $tableName = YuppConventions::tableName($ins); // Ya se sabe que id es el identificador de la tabla, es un atributo inyectado por PO. $pks = array(array('name' => 'id', 'type' => Datatypes::INT_NUMBER, 'default' => 1)); /* EJEMPLO de la estructura que se debe crear. $cols = array( array('name' => 'name', 'type' => Datatypes :: TEXT, 'nullable' => false), // FK array('name' => 'ent_id', 'type' => Datatypes :: INT_NUMBER, 'nullable' => true) ); */ // ===================================================================================================== // $nullable = NULL; // Hay que determinar si el atributo es nullable. // Si es una clase de nivel 2 o superior y esta mapeado en la misma tabla que su superclase, // todos sus atributos (declarados en ella) deben ser nullables. // TODO: ahora no tengo una funcionalidad que me diga que atributos estan declarados en que // clase, por ahora le pongo que todos sus atributos sean nullables. // ===================================================================================================== // FIXME: no sirve chekear por la clase porque la instancia que me pasan es un merge de todas las // subclases que se mapean en la misma tabla, asi que puede ser que parent_class sea POe igual // tenga que declarar nullables. // >> Solucion rapida <<, para los atributos de las subclases, en generateAll inyectarles // contraints nullables true. // Son iguales, no se sobreescribe el valor de "class" por el de la instancia real porque no interesa, // solo son instancias de merges de POs para una tabla. //Logger::getInstance()->log( "getClass: " . $ins->getClass() ); //Logger::getInstance()->log( "GET_CLASS: " . get_class($ins) ); // if ( get_parent_class($ins) != PersistentObject && // self::isMappedOnSameTable($ins->getClass(), get_parent_class($ins)) ) // { // $nullable = true; // } // ===================================================================================================== $cols = array(); $attrs = $ins->getAttributeTypes(); // Ya tiene los MTI attrs! foreach ($attrs as $attr => $type) { if ($attr !== 'id') { $cols[] = array('name' => $attr, 'type' => $type, 'nullable' => DatabaseNormalization::isSimpleAssocName($attr) ? true : $ins->nullable($attr)); } } // ==================================================================================================== // Sigue fallando, genera esto: (el vacio en nullable es el false) // [5] => Array // ( // [name] => entrada_id // [type] => type_int32 // [nullable] => // ) // Mientras que tengo esto en el objeto: (o sea la constraint nullable esta en true) // [entrada_id] => Array // ( // [0] => Nullable Object // ( // [nullable:private] => 1 // ) // ) // El problema es que PO.nullable cuando es un atributo de referencia hasOne, // se va a fijar si el atributo hasOne es nullable, y en este caso el atributo // NO es nullable, lo que hace a la referencia no nullable. // SOLUCION!: Lo resuelvo fijandome si es un atributo de referencia, lo hago // nullable, si no me fijo en si es nullable en el PO. // ========================================================= //Logger::struct( $cols, "=== COLS ===" ); $dal->createTable2($tableName, $pks, $cols, $ins->getConstraints()); // Crea tablas intermedias para las relaciones hasMany. // Estas tablas deberan ser creadas por las partes que no tienen el belongsTo, o sea la clase duenia de la relacion. // FIXME: si la relacion hasMany esta declarada en una superClase, la clase actual tiene la // relacion pero no deberia generar la tabla de JOIN a partir de ella, si no de la // tabla en la que se declara la relacion. $hasMany = $ins->getHasMany(); foreach ($hasMany as $attr => $assocClassName) { //Logger::getInstance()->pm_log("AssocClassName: $assocClassName, attr: $attr"); //if ($ins->isOwnerOf( $attr )) Logger::show("isOwner: $attr", "h3"); //if ($ins->attributeDeclaredOnThisClass( $attr )) Logger::show("attributeDeclaredOnThisClass: $attr", "h3"); // VERIFY, FIXME, TODO: Toma la asuncion de que el belongsTo es por clase. // Podria generar un problema si tengo dos atributos de la misma clase pero // pertenezco a uno y no al otro porque el modelo es asi. // Para casos donde no es n-n el hasMany, lo que importa es donde se declara la relacion, // no que lado es el owner. Para la n-n si es importante el owner. // Verifico si la relacion es hasMany n-n if ($ins->getClass() !== $assocClassName) { $hmRelObj = new $assocClassName(NULL, true); if ($hmRelObj->hasManyOfThis($ins->getClass())) { if ($ins->isOwnerOf($attr)) { self::generateHasManyJoinTable($ins, $attr, $assocClassName, $dal); } } else { if ($ins->attributeDeclaredOnThisClass($attr)) { self::generateHasManyJoinTable($ins, $attr, $assocClassName, $dal); } } } else { if ($ins->attributeDeclaredOnThisClass($attr)) { self::generateHasManyJoinTable($ins, $attr, $assocClassName, $dal); } } } }
/** FIXME: no deberia ser de PO? o de MTISup? no deberia estar en PM deberia ser algo del model utils o mti support. * Devuelve true si ambas clases se mapean en la misma tabla, las clases podrian ser * superclase y subclase, ser clases primas, hermanas o no tener relacion alguna. * Este metodo es mas general que isMappedOnSameTableSubclass. */ public static function isMappedOnSameTable($class1, $class2) { Logger::getInstance()->pm_log("PM::isMappedOnSameTable {$class1}, {$class2}"); // TODO // el caso superclase subclase lo handlea isMappedOnSameTableSubclass. $table1 = YuppConventions::tableName($class1); $table2 = YuppConventions::tableName($class2); //Logger::getInstance()->log( "isMappedOnSameTable: table1 $table1" ); //Logger::getInstance()->log( "isMappedOnSameTable: table2 $table2" ); return $table1 === $table2; }