public function aSet($attribute, $value)
 {
     Logger::getInstance()->po_log("PO:aSet {$attribute}=" . print_r($value, true) . " PHP Type: " . gettype($value));
     // Chekeo is_scalar para seteo de atributos simples.
     // Se agregaron returns para los casos de seteo correcto.
     // Chekeo de is_null para hasOne.
     // Consideracion de valor null para hasOne.
     // ====================================================================
     // Si es una tributo simple
     // VERIFY: CUal es la joda de discutir en que lista esta si al final hago lo mismo ???
     // SIRVE PARA VERIFICAR QUE LO QUE ESTOY SETEANDO ES VALIDO.
     // CHECK 1: El atributo esta en la lista de atributos?
     if (isset($this->attributeTypes[$attribute]) || array_key_exists($attribute, $this->attributeTypes)) {
         // https://code.google.com/p/yupp/issues/detail?id=172
         // Para DATES, SQLServer devuelve un DateTime object, por lo que no es escalar (integer, float, string, boolean) y tira excepcion.
         // DateTime > PHP 5.2
         if (Datatypes::isDateTime($this->attributeTypes[$attribute]) && $value instanceof DateTime) {
             $value = $value->format('Y-m-d H:i:s');
             // Saca el string de la fecha
         }
         if (Datatypes::isText($this->attributeTypes[$attribute]) && is_string($value)) {
             $value = trim($value);
         }
         // Si el valor es null o es un tipo simple (no una clase)
         //  - Dejo tambien setear NULL xq al setear email_id puede ser NULL
         //    y un valor simple tambien puede ser NULL si se lo desea.
         if ($value !== NULL && !is_scalar($value)) {
             throw new Exception("El valor para el atributo simple {$attribute} no es simple, es un " . gettype($value));
         }
         // TICKET: http://code.google.com/p/yupp/issues/detail?id=35
         // Resuelve el problema de que si es un booleano y carga de la base,
         // el tipo del valor pasa a ser string y debe mantener el tipo boolean de PHP.
         if ($this->attributeTypes[$attribute] == Datatypes::BOOLEAN && !is_bool($value)) {
             // TODO: otro valor posible podria ser "true" o "false" como strings.
             // TODO: ademas depende del DBMS
             //  - "0"/"1" para MySQL funciona
             //  - "f"/"t" para Postgres funciona
             $boolFalseValues = array(0, "0", "f", "F", "false", "FALSE");
             $boolTrueValues = array(1, "1", "t", "T", "true", "TRUE");
             // Si es $value=null y attr es booleano, la validez del valor depende de que sea nullable(true)
             if (!is_null($value)) {
                 // Si esta en trueValues es true, si esta en falseValues es false, otro caso no es soportado.
                 if ($value === "") {
                     $value = null;
                 } else {
                     if (in_array($value, $boolTrueValues, true)) {
                         $value = true;
                     } else {
                         if (in_array($value, $boolFalseValues, true)) {
                             $value = false;
                         } else {
                             throw new Exception("El valor '{$value}' para '{$attribute}' no es un valor booleano valido");
                         }
                     }
                 }
                 // Si es otro valor, no es soportado
             }
         }
         // TODO: verificar que el tipo del dato corresponde con el tipo del campo.
         $this->attributeValues[$attribute] = $value;
         $this->dirty = true;
         // Marca como modificada
         return;
     } else {
         // Esto es para buscar atributos generados ej. hoattr_id
         // Pruebo si el attribute no es el nombre de la columna que
         // corresponde con algun atributo de esta clase en el ORM.
         foreach ($this->attributeTypes as $classAttr => $type) {
             if (DatabaseNormalization::col($classAttr) == $attribute) {
                 if ($value !== NULL && !is_scalar($value)) {
                     throw new Exception("El valor para el atributo simple {$attribute} no es simple, es un " . gettype($value));
                 }
                 $this->attributeValues[$classAttr] = $value;
                 $this->dirty = true;
                 // Marca como modificada
                 return;
             }
         }
     }
     // ======================================================================
     // Es hasMany o hasOne
     // si no esta en la lista de atributos, me fijo si no encuentro un atributo con
     // nombre "similar" a $attribute, esto pasa porque si el atributo es normalizedName
     // en la tabla guarda 'normalizedname' todo en minusculas (por YuppConventions).
     // Se debe hacer idem para hasOne y hasMany
     // Si el rol tiene el nombre de la assoc declarado, necesito ver cual es el nombre
     // completo de la key en hasOne o hasMany porque usa attribute__assocName.
     $attribute = $this->getRoleWithAssocName($attribute);
     if (isset($this->hasOne[$attribute]) || array_key_exists($attribute, $this->hasOne)) {
         if ($value !== NULL && !is_subclass_of($value, 'PersistentObject')) {
             throw new Exception("El valor para el atributo hasOne {$full_attribute} no es persistente, es un " . gettype($value));
         }
         $this->attributeValues[$attribute] = $value;
         // email
         // Si seteo NULL no puedo preguntarle el id!!!
         $refAttrName = DatabaseNormalization::simpleAssoc($attribute);
         // "email_id"
         if ($value) {
             $this->attributeValues[$refAttrName] = $value->getId();
         } else {
             $this->attributeValues[$refAttrName] = NULL;
         }
         // Seteo tambien "email_id", puede ser NULL !!!
         $this->dirtyOne = true;
         // Marca como modificada
         return;
     } else {
         // Pruebo si el attribute no es el nombre de la columna que
         // corresponde con algun atributo de esta clase en el ORM.
         foreach ($this->hasOne as $classHOAttr) {
             if (DatabaseNormalization::col($classHOAttr) == $attribute) {
                 if ($value !== NULL && !is_subclass_of($value, 'PersistentObject')) {
                     throw new Exception("El valor para el atributo hasOne {$full_attribute} no es persistente, es un " . gettype($value));
                 }
                 $this->attributeValues[$attribute] = $value;
                 // email
                 // Si seteo NULL no puedo preguntarle el id!!!
                 $refAttrName = DatabaseNormalization::simpleAssoc($attribute);
                 // "email_id"
                 if ($value) {
                     $this->attributeValues[$refAttrName] = $value->getId();
                 } else {
                     $this->attributeValues[$refAttrName] = NULL;
                 }
                 // Seteo tambien "email_id", puede ser NULL !!!
                 $this->dirtyOne = true;
                 // Marca como modificada
                 return;
             }
         }
     }
     if (isset($this->hasMany[$attribute]) || array_key_exists($attribute, $this->hasMany)) {
         // TODO: ademas deberia ser de objetos persistentes.
         // TODO: NULL es un valor valido para una lista de objetos ?
         if (!is_array($value)) {
             throw new Exception("El valor para el atributo " . $attribute . " debe ser un array.");
         }
         $this->attributeValues[$attribute] = $value;
         $this->dirtyMany = true;
         // Marca como modificada
         return;
     } else {
         // Pruebo si el attribute no es el nombre de la columna
         // que corresponde con algun atributo de esta clase en el ORM.
         foreach ($this->hasMany as $classHMAttr) {
             if (DatabaseNormalization::col($classHMAttr) == $attribute) {
                 if (!is_array($value)) {
                     throw new Exception("El valor para el atributo " . $attribute . " debe ser un array.");
                 }
                 $this->attributeValues[$attribute] = $value;
                 // Si seteo NULL no puedo preguntarle el id!!!
                 $refAttrName = DatabaseNormalization::simpleAssoc($attribute);
                 // "email_id"
                 if ($value) {
                     $this->attributeValues[$refAttrName] = $value->getId();
                 } else {
                     $this->attributeValues[$refAttrName] = NULL;
                 }
                 // Seteo tambien "email_id", puede ser NULL !!!
                 $this->dirtyMany = true;
                 // Marca como modificada
                 return;
             }
         }
     }
     throw new Exception("PO.aSet: El atributo '{$attribute}' no existe en la clase (" . get_class($this) . ")");
 }
 public function getDBType($type, $constraints)
 {
     $dbms_type = NULL;
     if (Datatypes::isText($type)) {
         $maxLength = NULL;
         // TODO: Falta ver si tengo restricciones de maxlength!!!
         $maxLengthConstraint = NULL;
         if ($constraints !== NULL) {
             foreach ($constraints as $constraint) {
                 if (get_class($constraint) === 'MaxLengthConstraint') {
                     $maxLengthConstraint = $constraint;
                     break;
                     // rompe for
                 }
             }
         }
         //$maxLengthConstraint = $obj->getConstraintOfClass( $attr, MaxLengthConstraint );
         if ($maxLengthConstraint !== NULL) {
             $maxLength = $maxLengthConstraint->getValue();
         }
         $dbms_type = $this->getTextType($type, $maxLength);
         // Devuelve VARCHAR, TEXT, o el tipo correcto dependiendo del maxlength.
     } else {
         if (Datatypes::isNumber($type)) {
             $dbms_type = $this->getNumericType($type);
         } else {
             if (Datatypes::isDateTime($type)) {
                 $dbms_type = $this->getDateTimeType($type);
             } else {
                 throw new Exception("DatabasePosgreSQL.getDBType: el tipo ({$type}) no esta definido.");
             }
         }
     }
     return $dbms_type;
 }
 public function getDBType($type, $constraints)
 {
     $dbms_type = NULL;
     if (Datatypes::isText($type)) {
         $maxLength = NULL;
         $maxLengthConstraint = NULL;
         if ($constraints !== NULL) {
             foreach ($constraints as $constraint) {
                 if (get_class($constraint) === 'MaxLengthConstraint') {
                     $maxLengthConstraint = $constraint;
                     break;
                     // rompe for
                 }
             }
         }
         // FIXME: no tengo este metodo? para que se hace la busqueda aca? En MySQL debe estar igual...
         //$maxLengthConstraint = $obj->getConstraintOfClass( $attr, MaxLengthConstraint );
         if ($maxLengthConstraint !== NULL) {
             $maxLength = $maxLengthConstraint->getValue();
         }
         $dbms_type = $this->getTextType($type, $maxLength);
         // Devuelve VARCHAR, TEXT, o el tipo correcto dependiendo del maxlength.
     } else {
         if (Datatypes::isNumber($type)) {
             $dbms_type = $this->getNumericType($type);
         } else {
             if (Datatypes::isDateTime($type)) {
                 $dbms_type = $this->getDateTimeType($type);
             } else {
                 throw new Exception("DatabaseMySQL.getDBType: el tipo ({$type}) no esta definido.");
             }
         }
     }
     return $dbms_type;
 }