CodeIgniter no permite el uso de variables GET por defecto, para permitir las "URLs amigables". Sin embargo, todavía se pueden pasar parámetros.
Supongamos un foro, y queremos pasar el número de tema para mostrar los comentarios. En PHP clásico haríamos una URL ver_tema.php?tema_id=1234 pero en CI, en cambio, podemos hacer tema/ver/1234. Entonces el controller es tema, el método ver y un parámetro adicional es 1234.
¿Cómo recuperamos el valor de este parámetro?
Tenemos dos opciones. Podemos definirlo como parámetro del método ver o a través de la clase URI.
La primer alternativa sería algo así
function ver($id = 0)
{
// y ya está definida $id
}
La segunda opción es
function ver()
{
$id = $this->uri->segment(3);
// y ya está definida $id
}
La primera parece más linda, ¿no? Quizás a alguien le llame la atención el = 0 en el parámetro... cómo el usuario define la URL que visita puede no enviar el parámetro y esto generaría un error fatal de PHP, irrecuperable. De esta forma podemos hacer que si el id es vacío, el usuario sea redirigido a una página de error o a la lista de temas... Básicamente, fallar con gracia.
Este caso es simple. Sin embargo se complica más cuando los parámetros son múltiples. Por ejemplo, para paginar el tema que estamos mostrando, podemos agregar un cuarto parámetro, quedando
function ver($id = 0, $pagina = 1)
{
}
Pero las cosas se pueden complicar todavía más, cuando hay múltiples parámetros y no necesariamente un orden de importancia (en el caso anterior, siempre se necesita un ID, pero no siempre un número de página).
Supongamos un formulario de búsqueda avanzado, dentro del mismo foro. Además de palabras clave, podemos seleccionar un rango de fecha y un usuario en particular. Si tratamos de aplicar el mismo criterio, llegaríamos a algo tan confuso como
function buscar($palabras_clave = '', $desde_fecha = '', $hasta_fecha = '', $usuario = 0)
{
// ...
}
Lo que parece más molesto que amigable. Hay varias posibles soluciones.
Sesiones
Una posible variante es envíar el formulario a una página que lo guarde en la sesión y luego poder navegar sabiendo que buscó a través de los datos de sesión. Contra: si un usuario hace dos búsquedas no las puede "navegar" (entrar a temas y volver, o utilizar la paginación) en forma simultanea. Contra II: no se puede compartir o guardar como favoritos la página de resultados de la búsqueda.
Uri Assoc
Si bien no podemos hacer resultados_busqueda.php?palabras_clave=...&desde_fecha=...&hasta_fecha=... podemos hacer una URI asociativa y utilizar busqueda/resultados/palabras_clave/.../desde_fecha/.../hasta_fecha/... y luego aprovechar el método uri_to_assoc de la clase URI para lograr un array asociativo simple.
Hash
Por último, podemos utilizar la URI para mandar un identificador de la búsqueda. Por ejemplo busqueda/resultados/bda90d48eda6d07d961b3ec26216fe05 y guardar en nuestra base de datos que criterios significan "bda90d48eda6d07d961b3ec26216fe05".
domingo, 24 de febrero de 2008
sábado, 16 de febrero de 2008
Lo primero que hay que saber
El objeto que se instancia como controlador, tiene referencias a todas las instancias de librerías y modelos que hayan cargadas como un atributo del mismo nombre de la clase.
Así, si cargamos la librería Email, tenemos que $this->email es una instancia de la clase Email.
El tema no termina ahí. Cada modelo, también, tiene esos mismos atributos cargados, entonces el código que tenemos en el controlador y en el módelo es similar, ya que accedemos a los mismos atributos. Entonces, si hacemos cierto código en el controlador y nos parece que es muy general y lo podemos necesitar en otro, es fácil pasarlo a un modelo.
Pero... ¿Qué pasa si estamos en una librería?
A las librerías no se les cargan los atributos, pero pueden necesitar acceso a otra librería, o a un modelo. Para eso, podemos acceder a la instancia del controlador a través de la función "get_instance".
Por ejemplo, dentro de la clase Email queremos validar el mail con el método valid_email de la clase de Validación. Entonces:
function valid_email($address)
{
// (El & es importante para no crear una copia en PHP 4)
$CI =& get_instance();
// Si no está cargada la librería, la cargamos nosotros
if (!isset($CI->validation))
{
$CI->load->library('validation');
}
// Llamamos al método
return $CI->validation->valid_email($address);
}
Simple, no?
Igualmente, esto sigue...
¿Qué pasa si en la vista, queremos acceder a una librería o modelo, por ejemplo, a la de validación para recuperar los mensajes?
Las views también pueden acceder como $this->validation al mismo objeto que el controlador o los modelos.
Internamente, esto se logra asignandole estas instancias a la clase Loader, donde se cargan las vistas.
Así, si cargamos la librería Email, tenemos que $this->email es una instancia de la clase Email.
El tema no termina ahí. Cada modelo, también, tiene esos mismos atributos cargados, entonces el código que tenemos en el controlador y en el módelo es similar, ya que accedemos a los mismos atributos. Entonces, si hacemos cierto código en el controlador y nos parece que es muy general y lo podemos necesitar en otro, es fácil pasarlo a un modelo.
Pero... ¿Qué pasa si estamos en una librería?
A las librerías no se les cargan los atributos, pero pueden necesitar acceso a otra librería, o a un modelo. Para eso, podemos acceder a la instancia del controlador a través de la función "get_instance".
Por ejemplo, dentro de la clase Email queremos validar el mail con el método valid_email de la clase de Validación. Entonces:
function valid_email($address)
{
// (El & es importante para no crear una copia en PHP 4)
$CI =& get_instance();
// Si no está cargada la librería, la cargamos nosotros
if (!isset($CI->validation))
{
$CI->load->library('validation');
}
// Llamamos al método
return $CI->validation->valid_email($address);
}
Simple, no?
Igualmente, esto sigue...
¿Qué pasa si en la vista, queremos acceder a una librería o modelo, por ejemplo, a la de validación para recuperar los mensajes?
Las views también pueden acceder como $this->validation al mismo objeto que el controlador o los modelos.
Internamente, esto se logra asignandole estas instancias a la clase Loader, donde se cargan las vistas.
Dos largos meses
Desde mi cambio de trabajo, mis tiempos libres se acortaron y el blog cayó al olvido.
Últimamente le dedico mis ratos PHPeros a CodeIgniter, así que voy a empezar a postear al respecto.
Lo básico. CodeIgniter es un Framework que funciona en PHP 4.3.2 en adelante. Es muy liviano y muy flexible. Inspirado en Ruby on rails. Utiliza el patrón MVC. Promueve las URLs amigables. La documentación es muy buena (sólo en inglés).
Últimamente le dedico mis ratos PHPeros a CodeIgniter, así que voy a empezar a postear al respecto.
Lo básico. CodeIgniter es un Framework que funciona en PHP 4.3.2 en adelante. Es muy liviano y muy flexible. Inspirado en Ruby on rails. Utiliza el patrón MVC. Promueve las URLs amigables. La documentación es muy buena (sólo en inglés).
domingo, 16 de diciembre de 2007
Reflection Class
Desde PHP 5 se cuenta con un conjunto de clases e interfaces que nos permiten obtener información sobre las clases, funciones, métodos, atributos y objetos. Este conjunto nos permite, por ejemplo, saber cuantos parámetros recibe una función, y cuantos son requeridos... Un ejemplo de cómo usar esto.
/**
* Esta funcion repite
*
* @param string $texto
* @param integer $veces
*/
function repeat($texto, $veces = 2) {
return str_repeat($texto, $veces);
}
$reflection = new ReflectionFunction('repeat');
echo 'Definida por el usuario: ' , $reflection->isUserDefined() , "\r\n";
echo 'Documentacion: ' , $reflection->getDocComment() , "\r\n";
echo 'Cantidad de Parametros: ' , $reflection->getNumberOfParameters() , "\r\n";
foreach ($reflection->getParameters() as $parametro)
{
echo 'Parametro "' , $parametro->getName() , '" ' , ($parametro->isOptional() ? '' : 'no ') , 'es opcional' , "\n";
echo 'Por default: ' , ($parametro->isDefaultValueAvailable() ? $parametro->getDefaultValue() : 'no tiene') , "\n";
}
?>
/**
* Esta funcion repite
*
* @param string $texto
* @param integer $veces
*/
function repeat($texto, $veces = 2) {
return str_repeat($texto, $veces);
}
$reflection = new ReflectionFunction('repeat');
echo 'Definida por el usuario: ' , $reflection->isUserDefined() , "\r\n";
echo 'Documentacion: ' , $reflection->getDocComment() , "\r\n";
echo 'Cantidad de Parametros: ' , $reflection->getNumberOfParameters() , "\r\n";
foreach ($reflection->getParameters() as $parametro)
{
echo 'Parametro "' , $parametro->getName() , '" ' , ($parametro->isOptional() ? '' : 'no ') , 'es opcional' , "\n";
echo 'Por default: ' , ($parametro->isDefaultValueAvailable() ? $parametro->getDefaultValue() : 'no tiene') , "\n";
}
?>
domingo, 9 de diciembre de 2007
JSON
JSON es un formato de transmisión de datos muy útil para pasar de un código a otro.
El ejemplo más común es pasar un objeto o un array de PHP a JavaScript y viceversa. Para esto PHP 5 ofrece dos funciones que hacen el transpaso: json_encode y json_decode. Existen clases que ofrecen un funcionamiento similar para PHP 4.
La ventaja de esta notacion es la transparencia y facilidad con la que se transmiten los datos. XML es una alternativa que también presenta sus ventajas. Es preferible para una serie de datos, si se quieren hacer consultas con XQuery, pero para la transmisión de un dato en particular la sintaxis de JavaScript se presenta como más simple.
El ejemplo más común es pasar un objeto o un array de PHP a JavaScript y viceversa. Para esto PHP 5 ofrece dos funciones que hacen el transpaso: json_encode y json_decode. Existen clases que ofrecen un funcionamiento similar para PHP 4.
La ventaja de esta notacion es la transparencia y facilidad con la que se transmiten los datos. XML es una alternativa que también presenta sus ventajas. Es preferible para una serie de datos, si se quieren hacer consultas con XQuery, pero para la transmisión de un dato en particular la sintaxis de JavaScript se presenta como más simple.
Suscribirse a:
Entradas (Atom)