echo $attr; ?> </th> <?php } ?> </tr> <?php foreach ($list as $po) { ?> <tr> <?php foreach ($attrs as $attr => $type) { ?> <?php if ($attr === 'deleted' || DatabaseNormalization::isSimpleAssocName($attr)) { continue; } // No quiero mostrar la columna 'deleted' o hasone attr_id ?> <td> <?php if ($attr == "id") { ?> <?php // Si en la aplicacion actual existe el controlador para esta clase de dominio, // que vaya a la aplicacion actual y a ese controller. // Si no, va a la app y controller "core". if ($theApp->hasController($po->aGet('class'))) { ?> <?php
/** * 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); } } } }
public function nullable($attr) { // Atributos inyectados no son nullables. if (self::isInyectedAttribute($attr)) { return false; } if (DatabaseNormalization::isSimpleAssocName($attr)) { $attr = DatabaseNormalization::getSimpleAssocName($attr); } if (isset($this->constraints[$attr])) { foreach ($this->constraints[$attr] as $constraint) { if (get_class($constraint) === 'Nullable') { return $constraint->getValue(); } } } return true; // Por defecto es nullable. Es mas facil para generar las tablas, ahora se pone en not null solo si hay una restriccion que lo diga. }
/** * Devuelve HTML para edicion de un objeto como una tabla con 2 columnas, la primera de nombres de campos la segunda con campos con valores para modificar. */ private static function display_edit(PersistentObject $po) { $res = '<table>'; $attrs = $po->getAttributeTypes(); foreach ($attrs as $attr => $type) { // Los atributos inyectados no se deberian poder editar! $res .= '<tr><td>'; $res .= $attr; // TODO: Habria que ver si esto es i18n, deberia haber algun "display name" asociado al nombre del campo. $res .= '</td><td>'; if ($po->isInyectedAttribute($attr)) { //$res .= $po->aGet($attr); $res .= self::field_to_html_show($attr, $type, $po->aGet($attr)); } else { if (DatabaseNormalization::isSimpleAssocName($attr)) { // Si es un fk a un id de un hasOne, quiero mostrar una lista de los posibles ids // de la clase de la relacion HO que le puedo asignar, y como esto es create o edit, // si tiene un valor actual, deberia quedar seleccionado en el select. $currentValue = $po->aGet($attr); // Puede ser NULL $role = DatabaseNormalization::getSimpleAssocName($attr); // email_id -> email $relClass = $po->getAttributeType($role); // Clase de la relacion HO // Objetos que puedo tener relacionadoss // Se puede en PHP 5.3.0... //$list = $relClass::listAll(new ArrayObject()); // Objetos que podria tener asociados // ... pero por las dudas ... $list = call_user_func_array(array($relClass, 'listAll'), array(new ArrayObject())); $select = '<select name="' . $attr . '"><option value=""></option>'; foreach ($list as $relObj) { $sel = $currentValue == $relObj->getId() ? ' selected="true"' : ''; $select .= '<option value="' . $relObj->getId() . '"' . $sel . '>' . $relClass . '[' . $relObj->getId() . ']</option>'; // TODO: Si se tuviera un toString en la clase se mostraria mejor } $select .= '</select>'; $res .= $select; } else { $maxStringLength = NULL; if ($type === Datatypes::TEXT) { $maxLengthConstraint = $po->getConstraintOfClass($attr, 'MaxLengthConstraint'); if ($maxLengthConstraint !== NULL) { $maxStringLength = $maxLengthConstraint->getValue(); } } $res .= self::field_to_html_edit($attr, $type, $po->aGet($attr), $maxStringLength); // Si el campo tiene errores, los muestro if ($po->getErrors()->hasFieldErrors($attr)) { $res .= '<div class="errors">'; $res .= self::fieldErrors($po, $attr); $res .= '</div>'; } } } $res .= '</td></tr>'; } $res .= '</table>'; return $res; }