jueves, 3 de marzo de 2011

Relaciones Muchos a Muchos (M:N) en symfony 1.4 y Doctrine

Este es mi primer post de Symfony, mas adelante publicare muchos mas tips relacionados a este excelente framework de desarrollo en PHP.

Probando algunas cosas en symfony necesite hacer relaciones M:N en sf 1.4 con doctrine.. propel en la verison df 1.2 resolvia el asunto el solo, aparentemente 1.4 no lo hace asi... bien, supongamos que necesitamos realizar este tipo de relacion en nuestro projecto M:N, autor y libro, un autor tieme muchos libros y un libro tiene muchos autores necesariamente necesitamos una tabla intermedia parar representar este tipo de relacion..
En la vista de autor o de libro necesitamos tener un listado de libros o autores dependiendo del caso, una lista multiple, o un listado con checkboxes,

para realizar este ejemplo necesitamos la estructura (PostgreSQL):

CREATE TABLE autor
(
  id serial NOT NULL,
  descripcion text NOT NULL,
  CONSTRAINT autor_pkey PRIMARY KEY (id)
);

CREATE TABLE libro
(
  id serial NOT NULL,
  descripcion text NOT NULL,
  CONSTRAINT libro_pkey PRIMARY KEY (id)
);

CREATE TABLE autor_libro
(
  autor_id integer NOT NULL,
  libro_id integer NOT NULL,
  CONSTRAINT autor_libro_pkey PRIMARY KEY (autor_id, libro_id),
  CONSTRAINT autor_libro_autor_id_fkey FOREIGN KEY (autor_id)
      REFERENCES autor (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT autor_libro_libro_id_fkey FOREIGN KEY (libro_id)
      REFERENCES libro (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);
creamos nuestro proyecto, aplicacion, realizamos la conexion a BD y generamos el modelo, filtros y formularios, notamos que efectivamente en la vista de autor y de libro no existe referencia a la tabla intermedia...
symfony generate:project proy
symfony generate:app app
symfony configure:database "pgsql:host=localhost;dbname=proy_db" u_test 123456
symfony doctrine:build-schema
symfony doctrine:build --model
symfony doctrine:build --filters
symfony doctrine:build --forms
symfony doctrine:generate-module --with-show  app libro Libro
symfony doctrine:generate-module --with-show  app autor Autor
symfony cc
como solucionamos esto.. bien.. el schema original de la primera corrida es algo asi...

lo q tenemos q mejorar es lo referente a la relacion que representa el schema de la siguiente manera...
Autor:
  connection: doctrine
  tableName: autor
  columns:
    id:
      ....
    descripcion:
      ....
  relations:
    AutorLibro:
      local: id
      foreign: autor_id
      type: many

si lo que queremos es que en la vista de autor nos muestre un listado de libros para hacer una seleccion multiple tenemos que modificar la parte de la relacion de la tabla autor.
ahora quedara asi
Autor:
  connection: doctrine
  tableName: autor
  columns:
    id:
      ....
    descripcion:
      ....
  relations:
    Libro:
      class: Libro
      refClass: AutorLibro
      local: autor_id
      foreign: libro_id

posterior a esto lo q debemos hacer es ejecutar modelo, filtros, formulario y regenerar el modulo autor
symfony doctrine:build --model
symfony doctrine:build --filters
symfony doctrine:build --forms
symfony doctrine:generate-module --with-show  app autor Autor
symfony cc
Chequea nuevamente la vista y observamos una lista multiple donde se listaran todos los libros..
OJO, si modificas la estructura de datos y necesitas generar nuevamente el schema se perderan los cambios realizados en la tabla autor... algo malo a mi parecer.. debe haber algun plugin que realice algo de esto.. pero bueee...

si necesitas cambiar esa lista multiple solo deberas cambiar el widget y listo...

si tienes el plugin sfFormExtraPlugin instalado, solo agrega en /lib/form/doctrine/AutorForm.class.php:
$this->widgetSchema['libro_list']->setOption('renderer_class', 'sfWidgetFormSelectDoubleList');

tambien puedes cambiar lo que muestra en la lista agregando algunas validaciones de la consulta o mostrar checkboxes.. pero eso lo veremos luego en otro articulo..
la referencia de todo esto q explico lo puedes conseguir Aqui

jueves, 24 de febrero de 2011

host virtuales para tus proyectos PHP

Para crear host virtuales para tus proyectos PHP..
# cd /etc/apache2/sites-available/
aqui dentro encontraras varios archivos, necesitamos default, copiamos este archivo y lo editamos
# cp default sitios
# vim sitios
encontraremos un contenido similar al siguiente
< VirtualHost *:80>
 ServerAdmin webmaster@localhost

 DocumentRoot /var/www
 < Directory />
  Options FollowSymLinks
  AllowOverride All
 < /Directory>
 < Directory /var/www/>
  Options Indexes FollowSymLinks MultiViews
  AllowOverride None
  Order allow,deny
  allow from all
 < /Directory>

 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
 < Directory "/usr/lib/cgi-bin">
  AllowOverride None
  Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
  Order allow,deny
  Allow from all
 < /Directory>

 ErrorLog /var/log/apache2/error.log

 # Possible values include: debug, info, notice, warn, error, crit,
 # alert, emerg.
 LogLevel warn

 CustomLog /var/log/apache2/access.log combined

    Alias /doc/ "/usr/share/doc/"
    < Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    < /Directory>

< /VirtualHost>
lo editamos y terminamos con un archivo similar a este
< VirtualHost *:80>
 ServerAdmin webmaster@localhost
        ServerName  ingreso.localhost
 DocumentRoot /var/www/ingreso/web/
 < Directory />
  Options FollowSymLinks
  AllowOverride All
 < /Directory>
 < Directory /var/www/ingreso/web/>
  Options Indexes FollowSymLinks MultiViews
  AllowOverride None
  Order allow,deny
  allow from all
 < /Directory>

 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
 < Directory "/usr/lib/cgi-bin">
  AllowOverride None
  Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
  Order allow,deny
  Allow from all
 < /Directory>

 ErrorLog /var/log/apache2/error.log

 # Possible values include: debug, info, notice, warn, error, crit,
 # alert, emerg.
 LogLevel warn

 CustomLog /var/log/apache2/access.log combined

    Alias /doc/ "/usr/share/doc/"
    < Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    < /Directory>

< /VirtualHost>
al inicio agregamos el ServerName, modificamos el Documentroot y cambiamos tambien el 2do < Directory ...>
< VirtualHost *:80>
 ServerAdmin webmaster@localhost
        ServerName  ingreso.localhost
 DocumentRoot /var/www/ingreso/web/
 < Directory />
  Options FollowSymLinks
  AllowOverride All
 < /Directory>
 < Directory /var/www/ingreso/web/>
  ....
  ....
  .... 
en este archivo tambien podemos definir la ruta hacia donde se almacenaran los logs este proyecto
si necesitas hacer mas de 1 virtual host modifica este mismo archivo # vim /etc/apache2/sites-available/sitios
y agrega un nuevo tag < VirtualHost *:80> con la misma caracteristica y solo modificas las rutas y el nombre del ServerName

luego de realizar tus modificaciones debes habilitar el virtualhost creado y releer la confuiguracion del apache
# a2ensite sitios
# /etc/init.d/apache2 reload
No olvides agregar la linea correspondiente el /etc/hosts
# vim /etc/hosts
127.0.0.1       localhost
127.0.1.1       fmnh-d550
127.0.0.1       ingreso.localhost
192.168.1.14    desarrollo
192.168.1.11    intranet
y probar en tu navegador

http://ingreso.localhost/

y listo...!

lunes, 25 de octubre de 2010

JavaScript: validacion de campos de texto

En internet se puede conseguir un monton de controles para validar cajas de texto.. pero para que buscar en la web si puedo buscar en mi blog.. jejeje.. aqui publico 3 validaciones simples.. solo numeros enteros, numeros con 2 decimales y solo caracteres... copy paste y listo.. a probar



Use el separador de decimales punto "." // usa la funcion js decimales y dosDecimales

Use solo numeros enteros

Use solo caracteres

jueves, 30 de septiembre de 2010

PostgreSQL: Para otorgar privilegios a un usuario

PosgreSQL permite crear provilegios por tabla en la base de datos de manera que un usuario en particular pueda crear consultas SELECT pero no pueda ejecutar el resto UPDATE, DELETE, INSERT.. el problema de esto es que pasa si tienes una BD con muchas tablas, tendrias q generar la sentencia grant por cada tabla GRANT SELECT ON TABLE public.table to u_read; para solucionar esto dejo aqui una consulta que genera todas las sentencias GRANT para cada tabla dentro de la BD

select 'GRANT SELECT ON TABLE '||schemaname||'.'||tablename||' TO u_read;' 
from pg_tables 
where schemaname in ('public') order by schemaname, tablename;


Para ver la Referencia.
Referencia de Postgresql Aqui!

martes, 7 de septiembre de 2010

PostgreSQL: funcion para dividir cadenas a partir de expresiones regulares

la funcion regexp_split_to_table y regexp_split_to_array Dividide una cadena usando expresiones regulares POSIX como el delimitador.

El sigueinte ejemplo divide una cadena de texto utilizando como delimitador 'espacio' para separar las palabras y devolver un arreglo de postgres.
select regexp_split_to_array('hola mundo! que tal!',E'\\s+') as x
y el resultado
{hola,mundo!,que,tal!}

El sigueinte ejemplo divide una cadena de texto utilizando como delimitador 'espacio' para separar las palabras y devolver un recorset que contiene una fila para cada palabra
select regexp_split_to_table('hola mundo como estas',E'\\s+') as x
y el resultado es:
"hola"
"mundo"
"como"
"estas"
puedes cambiar la expresion regular E'\\s+' (que por lo q entiendo son espacios en blanco) por estas otras '[^0-9]+' '[^A-Z]+' '[^A-Z]*' '[^a-z]*' o cualquier otra que utilices, pruebalo y observa los resultados.
Utilidad: imagina que quieres crear usuarios con el primer caracter del nombre y el apellido concatenado a partir de tu tabla de personal de tu sistema administrativo entonces usas esto:
select cedula,nombre,apellido,substring(nombre from 1 for 1) ||
(select regexp_split_to_table(apellido,E'\\s+') as x limit 1) as login,
md5('123456'),1 as status from personal where status = 1 order by cedula
Luego toca verificar la unicidad de los login's de la tabla... y listo...

CSS: Vinculos con texto e imagenes

En muchas ocaciones he tenido que crear vinculos con imagenes/iconos y texto representativos de la accion que realizan, ej. agregar,modificar, eliminar y cada vez q pongo la imagen en la etiqueta <a> la imagen no queda centrada con el texto.. quizas para muchos es una cuestion muy sencilla, pero para mi que no se mucho o nada de CSS es importante.. aqui va el .css para realizar esto:
a
{
  color: #524F46;
  outline: none;
  text-decoration: none;
}

a:hover
{
  text-decoration: underline;
}

a.salir {
    background: transparent url(../images/imgForm/salir.png) no-repeat scroll left center;
    padding: 2px 0 2px 25px;
}

a.listado {
    background: transparent url(../images/imgForm/list.png) no-repeat scroll left center;
    padding: 2px 0 1px 20px;
}

a.agregar {
    background: transparent url(../images/imgForm/add.png) no-repeat scroll left center;
    padding: 2px 0 1px 20px;
}

a.modificar {
    background: transparent url(../images/imgForm/edit.png) no-repeat scroll left center;
    padding: 2px 0 1px 20px;
}

a.eliminar {
    background: transparent url(../images/imgForm/delete.png) no-repeat scroll left center;
    padding: 2px 0 1px 20px;
}

Y en los vinculos donde se implemtentan la hoja de estilos:

Salir

Volver al listado de personal

lunes, 6 de septiembre de 2010

HTML: incrustar los ultimos twits en tu pagina web

Buscando una manera de incrustar los twits mas recientes en una pagina web, me consegui con el siguiente codigo que esta disponible en Twitter y un amigo esta probando para la intranet.. es facil de implementar, solo quizas le falta algo de diseño pero es lo q te da twitter.. aqui va el codigo, solo copialo, cambia la direccion del twitter y listo..
<div  style = "margin-top:0px; margin-bottom:0px; position:relative;left:0px;overflow:hidden;padding-left:0px; 
padding-right:0px; padding-top:0px; padding-bottom:0px;  background-color:;width:100%; ">
<h3 style="overflow:hidden"></h3>
<br/><br/>
<script src="http://widgets.twimg.com/j/2/widget.js"></script>
<script>
new TWTR.Widget({
  version: 2,
  type: 'profile',
  rpp: 10,
  interval: 6000,
  width: 250,
  height: 300,
  theme: {
    shell: {
      background: '#000000',
      color: '#ffffff'
    },
    tweets: {
      background: '#f5edf5',
      color: '#0a0a0a',
      links: '#c73261'
    }
  },
  features: {
    scrollbar: true,
    loop: false,
    live: true,
    hashtags: true,
    timestamp: true,
    avatars: false,
    behavior: 'all'
  }
}).render().setUser('LuisChataing').start();
</script></div>