Unite al grupo

Grupos de Google
Suscribirte a webandbeer
Correo electrónico:
Consultar este grupo

lunes, 30 de junio de 2008

Oracle/PHP for starters: Ponele bindings a esa query!

¿Qué son los bindings?

Oracle tiene una facilidad de fundamental importancia que a veces suele llamarse variable binding, pero que es más comunmente conocido (también en otros DBMS como MySQL, SQL Server o Postgre) como prepared statements o "sentencias preparadas", por la forma en que se utiliza esto a nivel código.

Lo explicaré desde el punto de vista de Oracle, que por lo que conozco es bastante más completo (y me es más familiar) y luego comentaré brevemente cómo se puede implementar en otros sistemas como MySQL.

¿A qué llamamos prepared statements?
Un prepared statement es básicamente una consulta SQL que se define en forma genérica con el fin de ser reutilizado varias veces a lo largo de la ejecusión de un mismo programa. Como generalmente una query suele tener filtros por determinados campos, donde comparamos el valor de uno o más campos contra uno o más valores variables, lo que utilizamos al definir el prepared statement es definir variables dentro de la query.

Optimización de consultas

Veamos esto con un ejemplo.

Supongamos que tenemos una consulta para obtener los datos de un usuario a partir de su ID:

$sSql = "SELECT user_name, user_password, user_birthdate FROM user WHERE user_id = " . $iUserId;

Dejaremos de lado por un momento los problemas de seguridad de esta query para ver qué sucede cuando se ejecuta en Oracle. Al ejecutarse esa query, por ejemplo cuando la variable $iUserId es igual a 5, se enviará a Oracle la siguiente consulta:

SELECT user_name, user_password, user_birthdate FROM user WHERE user_id = 5

Oracle tomará la consulta, elaborará un plan de ejecusión (dependiendo de muchas variables como índices, claves primarias y foráneas, estadísticas específicas de la base de datos, etc.), ejecutará la query y devolverá los resultados. Adicionalmente, esta query será almacenada en una suerte de cache que tiene Oracle con las últimas queries ejecutadas (no recuerdo el número exacto de consultas que se cachean, pero por decir algo digamos que son 100), junto con su plan de ejecusión. De esta manera, cuando una misma query se ejecuta varias veces seguidas, Oracle no debe estar armando el plan de ejecusión cada vez.

Supongamos que, seguidamente, ingresa otro usuario al sistema y se ejecuta la query para obtener los datos del usuario con ID = 6. Se ejecutaría la siguiente consulta:

SELECT user_name, user_password, user_birthdate FROM user WHERE user_id = 6

Oracle repetiría los pasos que describimos recién: plan de ejecusión, ejecusión, devolución de los resultados. ¿Por qué no utiliza el cache del que hablabamos?, porque evidentemente para Oracle las dos queries son diferentes: una tiene un 5 y la otra un 6. El query string, digamos, es diferente por lo tanto Oracle no tiene por qué pensar que el plan de ejecusión va a ser el mismo.

¿Cómo hacemos para que Oracle sepa que la query es la misma? Definimos ese $iUserId que usamos en PHP como una variable que pueda reconocer Oracle. Para ello, de la misma forma que en cualquier lenguaje, deberemos definir un nombre para la variable, ubicarla dentro de la query y luego asignarle un valor a esa variable. Dentro de la consulta SQL, las variables se identifican porque comienzan con dos puntos ":". La consulta que teníamos quedaría así:

$sSql = "SELECT user_name, user_password, user_birthdate FROM user WHERE user_id = :iUserId";

Luego, asignamos el valor a la variable en un array.

$aBindings = array ("iUserId" => $iUserId);

Por último, ejecutamos la query con nuestra clase de base de datos:

$aResult = $oDB->sql_query($sSql, $aBindings);

En pruebas en producción, con queries sobre tablas con cientos de miles de registros, creanmé que las diferencias de preformance son notables.

Consultas más seguras

Pero esto tiene otra ventaja adicional, en relación a un problema cotidiano de cualquier desarrollador, y sobre todo de cualquier desarrollador web: el escapado de las variables. Muchos freaks recordarán la famosa viñeta de xkcd al respecto.

El iUserId (o cualquier otra variable que usemos para filtrar), en muchos casos vendrá de un dato introducido por el usuario y debemos asegurarnos de validar esa información correctamente para evitar riesgos de SQL Inyection, es decir que en esa variable se introduzca código SQL que pueda modificar (en algunos casos muy perjudicialmente, HolaCine, cof, cof) el comportamiento esperado de la consulta. Ahora bien, yendo a la lógica más naif: ¿Si $iUserId es una variable que utilizo para filtrar, por qué le voy a meter SQL? Claro, hasta hace un rato Oracle no tenía ni idea que iUserId era una variable porque a él le llegaba el string de SQL entero y el ejecutaba.

Con los bindings Oracle sabe que :iUserId es una variable (de hecho, al momento de bindear con el statement se le puede indicar de qué tipo de dato es esa variable), por lo tanto no hay ninguna razón para evaluarlo como SQL. Nosotros podríamos tener:

$sSql = "SELECT user_name, user_password, user_birthdate FROM user WHERE user_id = :iUserId";
$aBindings = array ("iUserId" => '"" OR 1 = 1; DROP TABLE user;');
$aResult = $oDB->sql_query($sSql, $aBindings);

Y no vamos a tener ningún problema de inyection. Ojo, en ese caso en particular lo que sí vamos a tener es un error de Oracle diciendo que el valor que le pusimos a iUserId no es del tipo de dato adecuado (a menos que seamos tan nardos de poner un ID en un campo char/varchar).

Además, con los bindings no necesitamos preocuparnos por andar escapando comillas, porque el SQL statement y los valores viajan por canales separados y no como un string concatenado.

Cómo implementar prepared statements

Hasta ahora, a lo largo del artículo, utilicé siempre una ficticia clase de base de datos pero no dije cómo funcionaba internamente. Creo que no tiene sentido que reproduzca aquí la clase que uso, porque no es mía, tiene algunos problemas y seguramente ustedes podrán hacer alguna mejor. Voy a reproducir un pequeño ejemplo de cómo hacer una query con bindings usando la librería Oci8. Luego también está la alternativa con PDO que en todo caso veré para la próxima si armo algún ejemplo.


// Este sería el valor con el que vamos a filtrar
$mValue = 'some value';

// El prefetch define la cantidad de registros para la cual la librería alocará
// memoria inicialmente, en cada "ida" a buscar información.
// 200 suele ser un número recomendable cuando la query retornará varios
// registros.
$iPreFetch = 200;

// El array donde guardaremos la respuesta
$aResponse = array();

// Nos conectamos
$rConn = ocilogon($sDbUsername, $sDbPassword, $sDbName);

if ($rConn) {
    // Armamos la query
    $sSql = "SELECT field_1, field_2 FROM table WHERE field_3 = :value";

    // Definimos el array de bindings
    $aBindings = array (
                   'value' => $mValue
                 );

    // Generamos el statement
    $oStmt = ociparse($rConn, $sSql);

    // Asociamos los bindings
    foreach ($aBindings as $sWildcard => $sValue) {
       
@ocibindbyname($oStmt, ":" . $sWildcard, $sValue, -1);
    }
   
      // Vemos si hubo algun error al generar el statement
    $err = ocierror($oStmt);
    if(!$err) {
        // Seteamos el prefetch
        ocisetprefetch($oStmt, $iPreFetch);

        // Ejecutamos el statement
        $bOk = ociexecute($oStmt, OCI_DEFAULT);

        // Vemos si hubo algún error en la ejecusión
        $err = ocierror($oStmt);

        // Si estuvo todo bien armamos el record set
        if ($bOk) {
            while(ocifetchinto($oStmt, $aRow, OCI_ASSOC+OCI_RETURN_NULLS+OCI

_RETURN_LOBS+OCI_NUM)) {
                $aResponse[] = $aRow;
            }
            print_r($aResponse);
        } else {
            die("SQL error");
        }
       
        // Liberamos la memoria del statement
        ocifreestatement($oStmt);
    }
}
?>

En otros DBMS

Otros DBMS como MySQL o SQL Server también soportan queries con bindings. Actualmente, la mejor forma que he visto es con PDO porque lo maneja de la misma forma que con Oracle. Para MySQL desde PHP también puede hacerse con la clase Mysqli, el problema es que en vez de poner nombres de variables en la query uno debe usar signos de pregunta "?", lo cual trae varios problemas: si una variable se usa más de una vez en una query se debe enviar repetidas veces; los valores de las variables deben ser enviados en orden; la comprensibilidad de la query en sí resulta más complicada.

Al implementarlo de la misma forma que en Oracle, con PDO se resuelve este problema.

Estructuras de datos en C y manejo de memoria I

Nota: Este texto supone que se sabe que es una estructura de datos recursivas (nodos de listas, colas, pilas, árboles, etc.) y como se la programa en C e intenta darle una vuelta de rosca a ese conocimiento.

El lenguaje C es uno de los lenguajes de más bajo nivel (relativo) que existe. En este lenguaje la memoria se estructura de manera plana, que es en definitiva lo que es la memoria, un espacio plano de almacenamiento temporal.

Así entonces un nodo de estructura dinámica como el siguiente:

struct empleado{
int idEmpleado;
char* nombre;
char codigoPostal[6];
int idDepto;
struct empleado* sgte;
}

No es una estructura dimensional, sino un manojo de bytes ordenados:

(
Suponiendo arquitectura intel x86 32bits
int = >4 bytes
Dirección de memoria => 4bytes
char x 6 => 6 bytes
)

id nombre Codigo depto siguiente
[][][][] [][][][] [][][][][][] [][][][] [][][][]

Los cuales son interpretados cada uno como entero, puntero a caracter, entero, entero, entero.
En otras palabras, puede ser claramente un vector de bytes, donde a cada subconjunto de bytes se los interpreta como un tipo de datos nativo según la información de la definición de la estructura.

Bien, ahora supongamos que tenemos esta otra estructura bastante distinta:

struct empresa{
char* idEmpresa;
char* razonSocial;
long int cuit;
char* direccion;
char codigoPostal[6];
struct empresa* sgte;
};

Cuando hacemos funciones de acceso a cola (por ejemplo) siempre tenemos la maldita sensación de estar haciendo las mismas cosas miles de veces, puesto que si bien no es lo mismo un empleado y una empresa,
¡¡Las colas son todas iguales!!
¡¡El mecanismo si es el mismo, agrego al final, saco del principio!!

¿Cómo hacer para separar el “¿Qué?” del “¿Cómo?”?

Con el conocimiento que tenemos ahora de la memoria y la estructuración en memoria de las estructuras, existe al menos una forma de hacerlo.

¿Qué tienen en común todos los nodos de una estructura de datos dinámica / recursiva?
Rta.: El puntero al siguiente nodo.

¿Qué tienen en común todos los punteros en una misma arquitectura hardware / sistema operativo?
Rta.: El puntero es un tipo de datos, no importa lo que apunte, siempre pesa lo mismo.

Si planteamos la siguiente estructura:

Struct Nodo {
Struct Nodo* sgte;
};

Tenemos una estructura que el primer valor es un puntero un siguiente nodo, no tenemos variable “contenedor”, y no la necesitamos, puesto que ahora no nos importa el contenido de información, sino el puntero siguiente.

Un programa hecho en C, interpreta los datos según el tipo del mismo en el instante de ejecución dado.

Si yo modificase las estructuras anteriores y pusiese el elemento siguiente primero en la lista, quedaría esto:

struct empleado{
struct empleado* sgte;
int idEmpleado;
char* nombre;
char codigoPostal[6];
int idDepto;
}

struct empresa{
struct empresa* sgte;
char* idEmpresa;
char* razonSocial;
long int cuit;
char* direccion;
char codigoPostal[6];
};

Ahora, la última pregunta a hacernos es:
¿Qué tienen en común nuestras tres estructuras?
Rta.: Las tres empiezan con un puntero conceptualmente igual, el puntero al siguiente elemento.

Como se dan todas estas relaciones, entonces, gracias a la existencia del “casteo”, que hace que el programa interprete un dato como otro, sin afectarlo en el proceso, entonces, podemos definir todas las funciones para manejo de Colas para la estructura mas chica.

#define null NULL
#include
#include

typedef struct Nodo {
struct Nodo* sgte;
}Nodo;

typedef struct Cola {
Nodo* head;
Nodo* tail;
}Cola;

typedef struct Empleado{
struct Empleado* sgte;
int idEmpleado;
char* nombre;
char codigoPostal[6];
int idDepto;
} Empleado;

void inicializarCola (Cola* unaCola) {
unaCola->head = null;
unaCola->tail = null;
}

void agregarNodo (Cola* unaCola, Nodo* unNodo){
unNodo->sgte = null;

if ( unaCola->tail != null) {
unaCola->tail->sgte = unNodo;
}
unaCola->tail = unNodo;

if (unaCola->head == null) {
unaCola->head = unNodo;
}

}

Nodo* obtenerNodo (Cola* unaCola) {
Nodo* retorno;
retorno = unaCola->head;
if ( unaCola->head != null ) {
unaCola->head = unaCola->head->sgte;
}
return retorno;
}

int main (void) {

Cola unaCola;
Empleado* unEmpleado;
int i;
inicializarCola(&unaCola);

for (i = 0; i codigoPostal), ”, 6);
unEmpleado->idDepto = i;
unEmpleado->idEmpleado = i * 2;
unEmpleado->nombre = null;
agregarNodo(&unaCola, (Nodo*)unEmpleado);

}

while ((unEmpleado = (Empleado*) obtenerNodo(&unaCola)) != null) {
printf (” Id Empleado: %d \tId Depto: %d \n”, unEmpleado->idEmpleado, unEmpleado->idDepto);
}

return 0;
}

/*
Nota: Ejemplo probado con GCC y MinGW. No incluye el manejo de cadenas y la creación de empleados por una función dedicada por cuestiones de tiempo.
*/

Y con esto, tenemos el algoritmo de inserción y obtención de colas para cualquier nodo que tenga como primer dato de estructura el puntero al siguiente valor.

Como se puede ver a simple vista, esto de poder usar la misma función para distintos tipos de datos en los parámetros tiene cierto potencial.
Esta posibilidad de, por medio de casteo a estructuras menores de igual forma es una forma de emular el llamado Polimorfismo paramétrico (que no es el polimorfismo de objetos, sino, el de funcional)

Este articulo fue escrito por el flameante editor de Zend Hispano Santiago Bragagnolo en su blog

Artituculo original

domingo, 29 de junio de 2008

Entrevista a Richard Stallman

La gente de tecnologicas libres consiguio una entrevista con Richard Stallman.

Este es la version publicada por ellos.


richardstallmanvu1.jpg

¿Hola, como estás :)?

Tengo un calor insoportable aquí.

¿Cuando viajaras de nuevo a Chile?

No tengo un plan de volver a Chile, pero me gustaría ir, cuando haya
una invitación con fondos para los costes, y un hueco en mi agenda.

Como lo prefieres ¿”Free Software” o “Software Libre”?

“Software libre” es más claro, porque no se toma por “software
gratuito”. El software libre es el software que respeta la libertad
del usuario y la solidaridad social de su comunidad. No es asunto de
precio. Por lo tanto, en español no digas nunca “free software”, sino
siempre “software libre”. Incluso en inglés digo a veces “libre”.

Peor aun es decir “open source”. Ese término fue inventado para hacer
caso omiso de los asuntos éticos. Si comparas la palabra de los
activistas de software libre, como yo, y los promovidores de open
source, verás una gran diferencia al nivel el más profundo, el de
los valores.

¿Que Sistema Operativo estas usando?

Uso el sistema GNU con Linux. Básicamente es el sistema operativo
GNU, cuyo desarrollo lanc é en 1984, combinado con el kernel Linux,
lanzado en 1991 por el Sr. Torvalds.

Pero no uso su versión de Linux, porque contiene programas privativos.
Son los “blobs” de firmware que son presientes en los archivos
“fuente” de varias pilotas, en la forma de largas listas de números.
Es decir, estos archivos no realmente son de código fuente; no
obstante, los desarrolladores de Linux los ponen en sus archivos.

Ahora tenemos que mantener otra versión de Linux, llamada Linux Libre,
para usar en las versiones libres del sistema GNU/Linux.

Esto nos demuestra que ser libres hoy no garantiza que seremos libres
en un año. Mantener la libertad exige defenderla, en todos los
aspectos de la vida, incluso la informática.

Cuentanos ¿Como es un día promedio de Richard Stallman, desde que te levantas hasta que te duermes?

No me gusta tener rutinas, por lo tanto cada día es diferente en los
detalles. Lo que puedo decir es que paso mucho tiempo leyendo y
contestando mis correos. Mi trabajo se hace usualmente en
comunicación, y usualmente por correo. A parte esto, leo mucho
excepto el trabajo no me deja tiempo.

¿Estas desarrollando algún proyecto que nos puedas contar?

Mi trabajo de hoy en día no es programar, es difundir la filosofía
ética de software libre. Por lo tanto, mayormente no tiene la forma
de proyectos.

¿Has pensado en tener hijos?

La idea de unirse con otro en amor para crear una mezcla es muy
romántica, pero las consecuencias son muchas molestias. Por ejemplo,
las peleas arruinan el mismo amor, y hay que dedicar la vida al ganar
dinero.

El crecimiento de población es también muy malo para el mundo. La
población actual parece más que la tierra puede soportar. Estamos
estropeando nuestro mundo. El no tener hijos es un acto muy importante
para protegerlo.

¿Deseas agregar algo más?

La libertad no se defiende sola; tú tienes que defenderla.

Si aprecias el trabajo del movimiento de software libre, y del
Proyecto GNU, la mejor manera de agradecernos es contribuir.
Programar no es la única manera de contribuir: gnu.org/help sugiere
muchas más.

Para defender tu libertad, tienes que organizar. Si tu país propone
firmar un tratado de comercio con los EEUU, casi seguro que es
injusto. Organiza para que no se firme, o si ya se firmó, para
anularlo. (El Presidente Correa de Ecuador ha rechazado firmar un
tratado; es un muy buen ejemplo.)

Últimamente tienes que resistir la tentación de ceder tu libertad.
Por lo tanto, nunca compres ningún producto que implemente la Gestión
Digital de Restricciones (es decir, DRM) sin tener acceso personal a
las medidas necesarias para superarla.

Esto fue la entrevista que le realice al señor Stallman, por favor si quieres incluirla en tu website
asegúrese de que también incluya estos 3 links:

http://gnu.org/help
http://www.tecnologiaslibres.net
http://www.tecnologiaslibres.net/2008/06/29/entrevista-a-richard-stallman-desde-chile/

Oracle/PHP for starters: Introducción y asteriscos

Antes que nada, una pequeña presentación. Mi nombre es Andrés, actualmente trabajo en Intraway, y Cesar me pidió que escribiera algunas cositas sobre Oracle.

Debo decir, para empezar que no soy ningún especialista en el tema, y que seguramente cualquier otro compañero podría decirles muchas más cosas sobre este enorme y complejo DBMS. Por lo tanto, me pareció que una buena aproximación para escribir al respecto podría ser comentar las cosas más importantes que fui aprendiendo en el último año y medio que vengo trabajando con Oracle (particularmente Oracle 10g). No son necesariamente cuestiones específicas de Oracle, sino que yo las aprendí trabajando sobre ese entorno y frecuentemente son cosas que los desarrolladores web no tomamos en cuenta. Así doy comienzo a esta pequeña serie de posts llamada "Oracle/PHP for starters".

Antes que nada, un pequeño comentario sobre cómo trabjar con Oracle desde PHP (que es lo que yo uso).  Actualmente, PHP incluye dos librerías para trabajar con Oracle (en realidad hay más, pero estas son las más importantes): Oci8 y PDO. La primera es una librería en C específica para conectarse a Oracle y la segunda son los PHP Data Objects que sirven de interfaz para conectarse a múltiples sistemas de bases de datos. Si bien yo diriamente trabajo con Oci8, al día de hoy me parece que lo más adecuado es incorporar PDO para obtener una aproximación uniforme a múltiples DBMS.

Adicionalmente, es muy recomendable este PDF de Oracle, llamado "The Underground PHP and Oracle Manual", que se actualiza regularmente y explica todo lo que uno debería saber sobre cómo trabajar con Oracle desde PHP. De hecho, abunda más en las distintas formas de conectarse a Oracle desde PHP con Oci8, PDO, ADOdb, PEAR DB, PEAR MDB2, y Zend Core for Oracle.

Voy a empezar con un tema muy (quizás demasiado) sencillo, pero que a la hora de la verdad, hace la diferencia en términos de rendimiento y seguridad.

Olvidate de los asteriscos

Empecemos por el más sencillo de todos. Evitar a toda costa los asteriscos (*) en las consultas. Este detalle, que para muchos será absolutamente básico (casi me avergüenza tener que mencionarlo), no lo es tanto para la mayoría de los desarrolladores. ¿Cuántas sencillas aplicaciones de ABM en PHP con MySQL hemos visto que hacen queries del estilo de esta?:

SELECT * FROM tabla;

Pero, ¿por qué debemos evitar este tipo de prácticas?. Muy sencillo: con el * le estamos diciendo al DBMS que traiga todos los campos de la/s tabla/s seleccionadas, con lo cual el motor pierde una cantidad preciosa de tiempo en el plan de ejecusión buscando la estructura de cada tabla para poder devolvérnosla. Ahora bien, si nosotros ya conocemos la estructura de la tabla, ¿por qué no se la adelantamos al motor para que se ahorre ese paso?. Es un detalle básico, que puede demorarnos unos segundos extra al momento de armar la query y nos puede llegar a ahorrar mucho tiempo después en la performance de la query. Solamente basta reescribir la query para dejar algo como esto:

SELECT campo1, campo2, campo3 FROM tabla;

Adicionalmente, deberíamos agregar que el orden de los campos incide en la performance de la query, por lo que es importante siempre procurar escribirlos en el orden en que se encuentran en la tabla. De la misma forma, si la consulta incluye joins con otras tablas, los campos deberán ser solicitados en el orden en que se consultan las tablas.

La misma idea sería aplicable al caso de los COUNT(*). ¡He llegado a encontrarme casos de gente que hace un 'SELECT *' y luego un count() en PHP para saber cuántos registros hay en una tabla!. Más allá de esos casos extremos, sería bueno reemplazar queries como la siguiente:

SELECT COUNT(*) FROM tabla;

Por alguna de estas otras:

SELECT COUNT(tabla_id) AS qty FROM tabla;

SELECT COUNT(1) AS qty FROM tabla;

sábado, 28 de junio de 2008

El incentivo alcoholico para cada lenguaje

El delirio de la lista de web and beer no tiene limites, esta semana estuvimos armando un listado con la bebida alcoholica que corresponde para trabajar con cada lenguaje dependieno de sus caracteristicas. Obviamente como siempre para estas cosas, se engancharon enseguida y el resultado fue este.

C con whisky añejado y bueno
C++ con un etiqueta negra va como piña
JavaScript con fernet
Java con fernet o cafe re cargado.
Python con tekila a morir
Ruby con Ron seco nomas
RoR Speed con Vodka
.NET new age o vino espumante muy fashion.
Basic con coca obvio, estas aprendiendo de la vida con basic
PHP con cerveza
PHP sobre framework cerveza con fanta
ASP con gaseosa plin plin
Cobol con moscato (dos cosas viejas que no les gustan a nadie).
Perl me suena Mariposa.
ActionScript es Dr. Lemon
Bash es Tia Maria

jueves, 26 de junio de 2008

Consulta a db en varios lenguajes.

Por Francisco Rosales

C#

using System;
using System.Data;
using System.Data.OleDb;
namespace proyecto.Logic
{
public class GetLista
{
private OleDbConnection conn;
private OleDbCommand comm;
public GetLista()
{
conn = new OleDbConnection();
conn.ConnectionString = "oracleString";
conn.Open();
comm = new OleDbCommand();
comm.Connection = conn;
string sql = "SELECT * FROM list";
comm.CommandText = sql;
int registro = comm.ExecuteNonQuery();
}
}
}
ActionScript 3
package {
import pl.mooska.asql.*;
public class ASQLTest extends Sprite
{
private var conn:Asql = new Asql();
public function ASQLTest()
{
conn.addEventListener(SQLEvent.CONNECT, handleConnect);
conn.addEventListener(SQLEvent.SQL_DATA, getList);
conn.connect("urldb","user","pass","schema",3306);
}
private function handleConnect ( evt:SQLEvent ) :void
{
conn.query("SELECT * FROM list");
}
private function getList ( evt:SQLEvent ) :void
{
trace("data > " + evt.data.toString());
conn.disconnect();
}
}
}


Pablo Morales

hacer una conexion a un mysql y devolver un array con los registros con Zend Framework (php)

$db = new Zend_Db_Adapter_Pdo_Mysql
(array('host' => 'localhost' , 'username' => 'desarrollo' , 'password' => 'testinpass' , 'dbname' => 'sistemas'));
$query = $db->select()->from('personal')->where('personal_id="' . $request['idPersonal'] . '"');
$rows = $db->fetchAll($query);
?>

Hugo Arregui

Java + Hibernate (HQL)
getSession().createQuery("FROM User user WHERE id =
:id").setInteger("id", 1).uniqueResult();


Cesar Casas

Bien groncho en java

Connection conexion = DriverManager.getConnection ("jdbc:mysql://localhost
/usuarios","userdb", "passdb");
Statement s = conexion.createStatement();
ResultSet rs = s.executeQuery ("select * from Users where username='"+user+"' and password='"+pass+"');

new User(rs.next());





Zend_Layout, tener mas de un layout en nuestro sistema.

Generalmente para los sistemas web tenemos dos partes, frontend (la parte del usuario), y un backend. Es probable que compartan el diseño, pero el backend tiende a ser mas simple que el frontend, para diferenciarlo, y que no sea tan molesto el trabajo diario, debido al exceso de contenido.

Si leyeron la guia de implementación de Zend_Layout, de zsamer en su blog. Solo nos muestra un solo layout.

Pero si nosotros queremos tener mas de un layout lo podemos configurar muy facilmente.

Primero en el bootstrap configuramos los layout que va a usar nuestro sistema, y en que ruta vamos a tenerlo. En mi caso los guardo en /html/scripts/layout, pero eso es relativo a cada uno.

Agregamos el siguiente código.

$options = array(
'layout' => 'Frontend',
'layout' => 'Backend',
'layoutPath' => 'html/scripts/layout/'
);
Zend_Layout::startMvc($options);


Con esto ya tenemos configurado nuestro Bootstrap con los dos layout Frontend, y Backend, tengan en cuenta que Frontend va a quedar como layout default. Dentro de la carpeta html/scripts/layout, debe haber un frontend.phtml, y un backend.phtml con la estructura de nuestra web.

Una vez creado nuestros archivos desde el controller que vamos a ejecutar backend o un layout que no sea el default, antes de ejecutar el render, seteamos el layout que queremos que se muestre
en nuestro caso backend.

La linea que debemos agregar es la siguiente
$this->_helper->layout->setLayout('backend');

Y listo, si ejecutamos nuestra aplicacion vamos a poder ver como conviven pacíficamente varios layouts. ;)


Mas info:
Manual Oficial
Entrada en el blog de zsamer
Wikibook

Utilizando Zend_Feed

Estoy haciendo el desarrollo de un portal de noticias, que dentro de poco voy a liberar una primer version. Hoy me tocaba la tarea de hacer la suscripcion Atom de las noticias del portal para lo cual use Zend_Feed.

Voy a mostrar como quedo mi ejemplo.

En un primer paso arme el controller para el modulo Rss.

1
<?php
2
class Rss_IndexController extends Me_Generic_Controller
3
{
4 public function
indexAction ()
5 {
6
Zend_Loader::loadClass('Zend_Feed');
7
Zend_feed::importArray(Rss::getArray(), 'atom')->send();
8
$this->_helper->viewRenderer->setNoRender();
9 }
10 }
11
?>


Tenemos por ahora solo un metodo index, desde ese index cargamos Zend_Feed con Zend_loader, despues vamos a obtener del modelo Rss un array con el contenido que va a tener nuestro Atom. Para procesar ese Array vamos a usar Zend_Feed::importArray, el cual convierte el array en un xml valido. Lo otro que vamos a hacer es evitar que cargue la vista del modulo.

Por ahora va muy simple. Ahora vamos al modelo.

1
<?php
2
class Rss extends Zend_Db_Table
3
{
4 const
CANT_NOTICIAS = '20';
5 const
CHARSET = 'utf-8';
6 public static function
getArray ()
7 {
8
$noticias = Noticias::getXCantidad(self::CANT_NOTICIAS);
9
$datos['title'] = 'Portal de noticias';
10
$datos['link'] = 'http://localhost/diario/rss/';
11
$datos['lastUpdate'] = Fechas::getMkFromFechaHora(Noticias::getLastDate());
12
$datos['charset'] = self::CHARSET;
13
$i = 0;
14 foreach (
$noticias as $noticia) {
15
$datos['entries'][$i]['title'] = utf8_encode($noticia->titulo);
16
$datos['entries'][$i]['link'] = 'http://localhost/diario/noticias/?noticia=' . $noticia->id_noticia;
17
$datos['entries'][$i]['description'] = utf8_encode($noticia->texto_portada);
18
$datos['entries'][$i]['content'] = utf8_encode($noticia->texto);
19
$datos['entries'][$i]['lastUpdate'] = Fechas::getMkFromFechaHora($noticia->aud_fecha_hora_ingreso);
20 ++
$i;
21 }
22 return
$datos;
23 }
24 }
25
?>




Por ahora tambien va a tener un metodo solo, getArray en la primeras lineas traemos desde el modelo de Noticias las ultimas 20 noticias cargadas y activas. Declaramos un titulo a nuestro feed, que va a ser el titulo del portal de noticias, agregamos el link al feed, la fecha de la ultima actualizacion que va a estar con formato mktime y el charset, en nuestro ejemplo sera utf-8.

Con el objeto con las ultimas veinte noticias, vamos a iterarlos, para conseguir el detalle de cada noticia. Y vamos a completar los datos correspondientes, y por ultimo vamos a devolver el array generado.

Cuando le devolvemos al controller el array, este lo transforma en un Atom valido.

Cuando ejecutamos.

http://www.dominio.com/rss


nos va mostrar el Atom de las ultimas 20 noticias ;)




Pero falta algo, como hacer que desde el home nos aparezca el icono de rss y nos permita agregar en nuestro feed con la url http://www.dominio.com/ como hacemos con cualquier blog.

Muy facil
Dentro del head de nuestro html, agregamos la siguiente linea

1

2 <link rel="alternate" type="application/rss+xml" title="RSS" href="<?php echo $this->baseUrl;?>/rss/" />



en href ponemos la url a nuestro feed.



asi nos quedaria

Facil, no?

Otros links

Syndicate content with Zend Framework Zend_Feed classes

miércoles, 18 de junio de 2008

Encondig... la dura lucha

Bueno, basicamente este post sale de las discuciones por e-mail, como la mayoria.


Se que algunos suelen tener quilombos de encoding, es por ello que vamos a dar una explicacion super express que sera ampliada en el futuro.


Primero que nada, todo debe ser utf-8. Cuando digo todo, es TODO, el archivo, las bases de datos, las tablas, los campos, etc etc etc. Todas las conf deben estar en utf-8, y muy importante, el editor que usen debe estar en UTF 8.

Uno de los errores tipicos, es importar bases que han sido exportadas con el phpmyadmin (odio esta app con toda mi alma) y claro, al restaurarlas quedan como el orto.

Aca es facil, basta con abrir el el archivo sql y agregarle un :

set charset utf8

y ya, con eso mas o menos la vamos piloteando.

Recuerden, todo el trayecto debe ser utf-8, el trayecto es desde el campo en la tabla, pasando ese dato a PHP, que sera servida por el servidor web, y el tipo de encoding especificado en el meta.


Bueno gente, saludetes.

miércoles, 4 de junio de 2008

Al fin, llego el gran dia!

Estimado, finalmente llego el dia del segundo Web And Beer.

Recuerde completar su registro en:
http://www.eventioz.com/events/web-and-beer-20/registrations/new

La cita es en Santa Maria de Oro 2476, esquina Santa Fe, a las 19:30 hs.

Hay 60 cervezas confirmadas :D, se entregaran 2 x cada asistente (que este registrado, claro esta).

Los esperamos!.

martes, 3 de junio de 2008

SEGUNDO EVENTO WEB AND BEER - CAMBIO DE FECHA!

Estimados amigos, les informamos que el segundo evento de Web And Beer se ha cambiado de fecha.
No se realizara el dia miercoles 4 de junio, sino que se paso al dia jueves 5 de junio.

Les pedimos disculpas por el cambio tan sobre la fecha, pero es debido a los partidos de Boca y Argentina (nuestros usuarios son muy futboleros, que se le va a hacer).

Nuevamente disculpas.

Los esperamos!.

lunes, 2 de junio de 2008

Web And Beer 2.0 - Miercoles 4 de Junio

Estimados, ya tiene fecha la próxima Web and Beer.

El evento se realizara en el bar Wherever, Sta. Meria de Oro 2476 Esq. Santa Fe, a las 19:30 hs, Barrio de PALERMO, CAPITAL FEDERAL, BUENOS AIRES, el día miércoles 4 de junio.

Están todos invitados a participar del segundo evento, para el cual ya estamos diseñado un cronograma de charlas y debates.

Esta vez, les tenemos una buena noticia, el grupo Wixi.com podrá ser el posible Sponsor del evento, lo que significa cerveza gratis.

Entre las cosas confirmadas, tenemos la charla de lighthttpd y Web semántica a dictar por el señor Martín Sarsale, un poco de WOE (nuevos casos de implementación), y vamos a ver un modelo de desarrollo con ProxyAJAX (algo loco que les explicaremos en el evento, muy interesante).

También vamos a cumplir nuestra promesa de la charla sobre Sphinx, y haremos un gran esfuerzo por armar un poco de documentación impresa para todos los que asistan al evento.

Para asistir, solo deben completar el registro en el evento:

http://www.eventioz.com/events/web-and-beer-20/registrations/new

Espero su participación en este evento.