Instalar Symfony 2.8 con Xampp y NetBeans 8.1 en Windows 7

Esta entrada fue escrita en su versión original, hace mucho tiempo. Hoy Symfony anda por su versión 5. Igualmente, Symfony 2.8 sigue siendo una versión muy buena  potente y eficiente que puede y conviene usarse con PHP 7.1 o superior. Además, para los lectores de habla hispana, tenemos disponible un excelente libro para conocer casi todo sobre este framework en su versión 2.8, mientras que no hay casi nada escrito sobre como aprender a programar con las versiones más nuevas Me refiero al libro de Javier Eguiluz, que se menciona más abajo. Hoy, 18 de julio de 2020, he actualizado algunos detalles, pero lo esencial sigue vigente. (Desde hace poco, en 2020, salió el libro de Fabien Potencier: «Symfony 5: La vía rápida», que tiene una versión en castellano y puede comprarse por 30 euros en formato PDF).

Configurar el servidor Apache Xampp

Antes que nada debemos tener instalado y corriendo algún servidor Apache.

En mi caso utilizo Xampp.  Puede descargar Xampp desde varios lugares en la Web. Asegúrese de que sea una versión que contenga al menos PHP 5.5, en mi caso utilizo la versión de Xampp 5.6.24 (no funciona en Windows XP). Atención: solo instalo Apache y MySQL.

Iniciamos Xampp y si todo está correcto, veremos que se abre una ventana como la siguiente, donde puede verse que los servicios Apache y MySQL (los que elegí instalar) están funcionando adecuadamente ya que sus nombres se encuentran en fondo verde.

xampp1

Para que Xampp funcione de la manera adecuada para nuestro proyecto, debemos cambiar la configuración de Apache, haciendo clic en el botón Config  del módulo de Apache y abriendo el archivo httpd.conf
xampp2

Vamos al final del archivo y agregamos las siguientes líneas:

Listen 127.0.0.1:8080

<VirtualHost 127.0.0.1:8080>
           ServerName localhost
           DocumentRoot «D:\Datos\proyectos\cursospieromaster2017\html«
               <Directory «D:\Datos\proyectos\cursospieromaster2017\html«>
                   AllowOverride All
                     Allow from All
                    Require all granted
            </Directory>

</VirtualHost>

En el código de arriba podemos ver que debemos decirle a Xampp donde está ubicado nuestro directorio de trabajo: También definimos la IP del localhost con el puerto «8080» (en mi caso para distinguirlo de otros proyectos con los que uso diferente puertos).

Además de este cambio en el archivo httpd.conf debemos cambiar el puerto en la configuración general de Xampp, para ello:
  • Abrimos el Panel de Control de Xampp
  • Hacemos clic en Config (ver en la figura siguiente, el botón que está en el extremo superior derecho del Panel, encerrado en una elipse en color rojo).
  • Hacemos clic en Service and Port Settings
  • Aparece una nueva ventana que se llama Service Settings
  • Para nuestro propósito, solo elegimos la solapa Apache y reemplazamos el valor por defecto de 80 a 8080
  • Gravamos los cambios, haciendo click en Save
  • Y de nuevo  Save para actualizar la Configuración general de Xampp
  • Detenemos y volvemos a arrancar Apache en el panel principal, para que corra con los nuevos cambios.
configuracion general de Xampp

Recuerda que tendremos que introducir el dominio en nuestro fichero hosts del sistema operativo:

C:\Windows\System32\drivers\etc\hosts

127.0.0.1:8080       localhost

Luego probamos que todo está funcionando bien, cargando la página en nuestro localhost:

xampp4

Descargando e instalando Symfony 2.8

Aclaración: La explicación que sigue supone que Usted quiere desarrollar un proyecto nuevo. No que está tratando de importar un proyecto ya existente y en desarrollo.

Hay varios sitios en la web donde se explica como instalar Symfony 2. Incluso el sitio oficial de Symfony, también lo detalla. Sin embargo la tarea se puede complicar si además queremos usar como interface de programación a la IDE (integrated development environment) NetBeans para desarrollar nuestro proyecto. Es que desde la versión 2.6 Symfony no ofrece más el paquete en formato comprimido. Si Usted como yo, prefiere trabajar con  NetBeans, hay un par tareas extras, muy sencillas, para lograrlo.

Siguiendo los pasos que se detallan en este link:
https://symfony.com/doc/2.8/setup.html instalamos Symfony 2.8 en nuestra PC con Windows 7. Vemos que el sitio oficial de Symfony, ofrece varias alternativas. En mi caso prefiero usar Composer.

Una vez descargada en instalada la versión de Symfony 2.8, y  alojada en una carpeta que podemos denominar «c:\mi_proyecto», el paso siguiente es recurrir a algún de los software de compresión como Winzip o WinRar para comprimir esta carpeta con todas sus subcarpetas. Con ayuda del explorador de Windows, nos posicionamos en la carpeta «C:\mi_proyecto» y veremos algo similar a lo siguiente:

paso3

En el explorador de Windows, hacemos clic con el botón derecho del mouse (en mi caso uso Winzip) elijo: «Añadir a mi_proyecto.zip», y queda generado el archivo: «mi_proyecto.zip» en el directorio raíz C:\.

Instalando Symfony 2.8 en NetBeans 8.1

Ahora ingresamos a NetBeans (yo utilizo la versión 8.1) y seleccionamos en el menú principal: «Archivo, Import Proyect.., From Zip…», seleccionamos el archivo comprimido, «mi_proyecto.zip», y le decimos a NetBeans, donde queremos alojar nuestro proyecto. En mi caso, en la carpeta: «C:\proyectos». Hacemos clic en el botón «Import».

paso9

NetBeans, se encargará de importar y configurar el proyecto en la carpeta de destino elegida. Una vez terminada la importación, elegimos: «Archivo, Close All Proyects…», y luego, «Archivo, Open Proyect…» y seleccionamos de la lista nuestro proyecto recién importado (ver imagen siguiente)
paso7

Luego, elegimos en NetBeans: «Archivo|Project properties..» y en «Sources» nos aseguramos que las dos carpetas: «Sources folder» y «Project folder» sean iguales. En mi caso: «C:\proyectos\mi_proyecto»

Recordemos decirle a NetBeans, donde buscar el archivo de PHP. Para ello, en el menú principal, elegimos, «Herramientas, Opciones,» luego la solapa «PHP», y escribimos la ruta.  En mi caso, como utilizo Xampp, el archivo se aloja en «C:\xampp\php\php.exe», y luego hacemos clic en el botón «Aceptar», como muestra la imagen siguiente:

paso8

Así el proyecto quedará instalado, configurado (en modo automático) y listo para ser manejado desde NetBeans.

Ahora solo queda empezar a programar con Symfony. Un libro estupendo para aprender Symfony 2.8, se titula «Desarrollo web ágil con Symfony2» y está escrito por Javier Eguiluz, una de las personas que más sabe de Symfony en el mundo (puedes leer una reseña del libro aquí). En este libro se desarrolla un ejemplo muy completo y realista de una tienda on-line totalmente programada con Symfony2.

Symfony 1.4 y el uso de Doctrine Data Hydrators: un ejemplo

Cuando se necesita realizar una consulta y posterior listado, que involucre a varias tablas de una base de datos, puede resultar de utilidad, para ganar en velocidad de procesamiento, utilizar la opción de cargar todos los datos de la consulta en un array multidimensional y luego descargarlo en un archivo CSV o imprimirlo.

Para conocer todas las opciones disponibles de Doctrine y los Data Hydrators, se puede consultar (en inglés), aquí

Yo he necesitado incluir en una consulta el contenido de gran número de tablas (21 en total) de una base de datos, y luego generar un archivo CSV.

Veamos mi ejemplo:

La consulta que necesité hacer, incluida en el archivo actions.class.php tenía la siguiente forma:


public function executeConsultagral(sfWebRequest $request)
{
$records = Doctrine_Core::getTable('AccionConflictiva2')
->createQuery('a')
->leftJoin('a.ActoresAccionConflict3y4 y')
->leftJoin('a.ActoresTa1 at')
->leftJoin('a.FormatosProtestasHasAccionConflictivaT6 h')
->leftJoin('a.FormatosProtestasTa14 f')
->leftJoin('a.DemandasHasAccionConflictivaT5 k')
->leftJoin('a.DemandasTa2 dt')
->leftJoin('a.Conflictos1 c')
->leftJoin('y.TipoOrganizacionTa10 tot')
->leftJoin('y.OrganizacionTa11')
->leftJoin('c.SectorActividadCiuTa7 sac')
->leftJoin('c.SubsectorActividadTa8 sat')
->leftJoin('c.Conflictos1HasActoresTa1 cha')
->leftJoin('c.RelacionConflictualPrincipalTa9 rcp')
->leftJoin('a.FuentePrimariaTa3 p')
->leftJoin('a.FuenteSecundariaTa4 s')
->leftJoin('a.AlcanceTa5 l')
->leftJoin('a.LugaresTa6 u')
->leftJoin('a.RespuestaEstadoTa13 r')
->leftJoin('a.ParticipacionBasesTa12 t')
->leftJoin('a.NivelAgregadoTa15 n')
->where('y.Convocante=2')
->andWhere('a.Marca_patronal<>1')
->andWhere('c.Marca_patronal<>1')
->orderBy('c.Id, a.Id');

$chorizo = $records->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
$this->getUser()->setAttribute('databis', $chorizo);
}

Prestemos atención a las dos últimas líneas de la consulta anterior:


$chorizo = $records->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
$this->getUser()->setAttribute('databis', $chorizo);

Todos los datos de la consulta son cargados en la variable $chorizo que es un array multidimensional. El aspecto del array generado (solo para el primer elemento), se muestra a continuación:


Array
(
[0] => Array
(
[id] => 285
[idconflictos] => 133
[idparticipacion] => 5
[idalcance] => 3
[idlugar] => 2
[fuente_primaria] =>
[fuente_secundaria] => 1
[idnivel_agregado] => 1
[id_respuesta_estado] => 8
[tipo_fuente] => 2. Secundaria
[fecha_fuente] => 2013-01-03
[titulo_nota] => El municipio redujo adicionales de policía
[descripcion_situacion] => El gremio denunció falta de servicio por deudas. El Ejecutivo aclaró que el recorte obedece a la menor actividad estival.
[link_diario] => http://www.lavoz.com.ar/politica/el-municipio-redujo-adicionales-de-policia
[descripcion_alcance] => Municipalidad de Córdoba
[marca_patronal] => 0
[ActoresAccionConflict3y4] => Array
(
[0] => Array
(
[actores_ta1_id] => 10
[accion_conflictiva_2_id] => 285
[tipo_organizacion_ta10_id] => 1
[organizacion_ta11_id] => 120
[tipo_actor] => Trabajador
[actor_explicado] =>
[descripcion_organ] =>
[convocante] => 2
[TipoOrganizacionTa10] => Array
(
[id] => 1
[descripcion] => Sindicato
)

[OrganizacionTa11] => Array
(
[id] => 120
[organizacion] => SUOEM (Sind Ú. Obr y Empl Munic) Capital
[protagonista] => 0
[antagonista] => 0
)

)

[1] => Array
(
[actores_ta1_id] => 32
[accion_conflictiva_2_id] => 285
[tipo_organizacion_ta10_id] => 11
[organizacion_ta11_id] => 75
[tipo_actor] => Estado
[actor_explicado] =>
[descripcion_organ] =>
[convocante] => 5
[TipoOrganizacionTa10] => Array
(
[id] => 11
[descripcion] => Estado
)

[OrganizacionTa11] => Array
(
[id] => 75
[organizacion] => Poder Ejecutivo Municipal
[protagonista] => 0
[antagonista] => 0
)

)

)

[ActoresTa1] => Array
(
[0] => Array
(
[id] => 10
[actor] => Trabajadores estatales
)

[1] => Array
(
[id] => 32
[actor] => Estado municipal como empleador
)

)

[FormatosProtestasHasAccionConflictivaT6] => Array
(
[0] => Array
(
[formatos_protestas_ta14_id] => 9
[accion_conflictiva_2_id] => 285
[descripcion] =>
[principal] => 1
)

)

[FormatosProtestasTa14] => Array
(
[0] => Array
(
[id] => 9
[tipo_de_acciones] => Difusión y comunicación
[descripcion] =>
[tipo] => 5
)

)

[DemandasHasAccionConflictivaT5] => Array
(
[0] => Array
(
[demandas_ta2_id] => 7
[accion_conflictiva_2_id] => 285
[descripcion_demanda] => falta de adicionales policiales
[principal] => 1
)

)

[DemandasTa2] => Array
(
[0] => Array
(
[id] => 7
[motivos_o_demandas] => CYMAT no salarial (cond. y medio amb.)
[descripcion] =>
[tipo] => 0
)

)

[Conflictos1] => Array
(
[id] => 133
[id_relacion_conflictual_principal] => 5
[id_sector_actividad] => 12
[demandas_id] => 7
[id_subsector_actividad] => 33
[descripcion_general] => Trabajadores municipales de Córdoba agrupados en Suoem contra municipio por reducción de adicionales de policía
[descripcion_protagonista] => Trabajadores municipales
[descripcion_antagonista] => Municipio
[descripcion_demandaprinc] => suspension de contratacion de adicionales
[nivel_estado] => 3. Municipal
[fecha_comienzo] => 2013-01-03
[descripcion_sector] => Municipales
[fecha_final] =>
[marca_patronal] => 0
[SectorActividadCiuTa7] => Array
(
[id] => 12
[sector_actividad] => L. Administración publica y defensa planes de seguridad social de afiliación obligatoria
)

[SubsectorActividadTa8] => Array
(
[id] => 33
[id_sector] => 12
[descripcion] => L75. Otros
)

[Conflictos1HasActoresTa1] => Array
(
[0] => Array
(
[conflictos_1_id] => 133
[actores_ta1_id] => 10
)

)

[RelacionConflictualPrincipalTa9] => Array
(
[id] => 5
[descripcion] => A311. Trabajadores estatales // nivel municipal // capital // general
[privado_publico] => 1
[nivel_estado_o_sector] => A311
)

)

[FuentePrimariaTa3] =>
[FuenteSecundariaTa4] => Array
(
[id] => 1
[descripcion] => La Voz del Interior
)

[AlcanceTa5] => Array
(
[id] => 3
[descripcion] => Local/municipal
)

[LugaresTa6] => Array
(
[id] => 2
[depto_provincia] => Capital
)

[RespuestaEstadoTa13] => Array
(
[id] => 8
[descripcion] => Comunicación / niega
)

[ParticipacionBasesTa12] => Array
(
[id] => 5
[descripcion] => Sólo conducción
)

[NivelAgregadoTa15] => Array
(
[id] => 1
[nivel_agregacion] => Empresa o lugar de trabajo
[descripcion] =>
)

)

)

Luego, para poder listar los datos o pasarlos a un archivo CSV, en una vista de Symfony 1.4, procedo a utilizar la función setAttribute.
Luego, en la vista, será posible recorrer el array y volcar los datos en pantalla o en un archivo, sin necesidad de acceder al disco duro del servidor, ya que el array permanece en la memoria, generando un aumento notable de velocidad en las consultas complejas como esta.

Symfony 1.4 y TCPDF

Como obtener datos desde una base de datos y mostrarlos en un archivo .pdf

Quiero explicar como hacer posible la recuperación de datos desde una tabla o conjunto de tablas relacionadas de una base de datos, accedida con Symfony 1.4 y luego transformar la información en un archivo de formato PDF usando la libreria TCPDF.

Aquí no explicaré la instalación y uso de la librería TCPDF. Yo recurrí al plugin que está disponible en el sitio oficial de Symfony, pero hay que tener mucho cuidado porque existe un error en el link que aparece en este plugin sobre los archivos a instalar de la librería TCPDF. Pueden ver la naturaleza del problema y la solución que he encontrado consultando aquí:

http://stackoverflow.com/questions/19753485/how-to-use-the-plugin-sftcpdfplugin

Yo he separado el problema en dos partes.
Primero que nada procedo a escribir la consulta, en el archivo que contiene las «actions», que en mi caso toma la forma que se muestra a continuación:

public function executeTest()
{ 
     $this->conflictos1s = Doctrine_Core::getTable('Conflictos1')
      ->createQuery('a') 
      ->leftJoin('a.SectorActividadCiuTa7')     
      ->leftJoin('a.RelacionConflictualPrincipalTa9') 
      ->leftJoin('a.SubsectorActividadTa8')       
       ->leftJoin('a.DemandasTa2')      
       ->leftJoin('a.ActoresTa1')     
       ->leftJoin('a.Conflictos1HasActoresTa1')    
      ->orderBy('a.Id')
      ->execute();  
} 

Luego, yo construyo un template llamado testSuccess.php Hasta aquí nada nuevo en Symfony 1.4. Pero en el template, yo agrego las siguientes líneas de código:
Al comienzo:

<?php ob_start(); ?>

Al final de todo:

<?php $posts = ob_get_contents(); ?>

<?php ob_end_clean(); ?>

El contenido de la vista, queda grabado en la variable $posts
El contendio completo del código del archivo testSuccess.php, se muestra a continuación:

//testSuccess.php

<?php ob_start(); ?>


<h2>Listado de Conflictos</h2>
<table cellspacing="1" border="1">       
  <thead>
    <tr>
      <th width="2%">Id</th>
       <th width="6%">Fecha comienzo</th>
      <th>Relacion conflictual principal</th>
      <th>Sector actividad</th>
      <th>Subsector actividad</th>
      <th>Demandas</th>      
      <th width="20%">Descripcion-general</th>
      <th>Descripcion protagonista</th>
      <th>Descripcion antagonista</th>
      <th>Descripcion demandaprinc</th>
      <th>Nivel estado</th>
      <th>Descripcion sector</th>
</tr>
</thead>
<tbody>
  <?php foreach ($conflictos1s as $conflictos1): ?>
    <tr>
      <td width="2%"><?php echo $conflictos1->getId() ?></td>
      <td width="6%"><?php echo date('d/m/Y', strtotime($conflictos1->getFechaComienzo())) ?></td>
      <td><?php echo $conflictos1->getRelacionConflictualPrincipalTa9() ?></td>
      <td><?php echo $conflictos1->getSectorActividadCiuTa7() ?></td>
      <td><?php echo $conflictos1->getSubsectorActividadTa8() ?></td>
      <td><?php echo $conflictos1->getDemandasTa2() ?></td>
       <td width="20%"><?php echo substr($conflictos1->getDescripcionGeneral(),0,60).'...' ?></td> 
      <td><?php echo $conflictos1->getDescripcionProtagonista() ?></td>
      <td><?php echo $conflictos1->getDescripcionAntagonista() ?></td>
      <td><?php echo $conflictos1->getDescripcionDemandaprinc() ?></td>
      <td><?php echo $conflictos1->getNivelEstado() ?></td>
      <td><?php echo $conflictos1->getDescripcionSector() ?></td>   
    </tr>
    <?php endforeach; ?>      
  </tbody>
</table>
<?php $posts = ob_get_contents();
ob_end_clean(); ?>
<?php $sf_user->setAttribute('para_pdf', $posts); ?>
 <a href="<?php echo url_for('conflictos/testpdf') ?>">Generar Pdf</a>

En el template generamos la vista y capturamos todo lo que el browser «escribe». Agregué al final un link para generar ahora sí el archivo PDF

<a href="<?php echo url_for('conflictos/testpdf') ?>">Generar Pdf</a>

Esto pasa el contenido de la variable $posts a una nueva actions denominada: testpdf de la forma usual:

<?php $sf_user->setAttribute('para_pdf', $posts); ?>

En la nueva actions executeTestpdf, pongamos atención a la siguiente línea de código:

$ html = $ this-> getUser () -> getAttribute ('para_pdf');

La función completa se muestra a continuación:

public function executeTestpdf()
{       
  $config = sfTCPDFPluginConfigHandler::loadConfig();

  // pdf object
  $pdf = new sfTCPDF();

  // set document information
  $pdf->SetCreator(PDF_CREATOR);
  $pdf->SetAuthor('J. H.');
  $pdf->SetTitle('TCPDF Example 001');
  $pdf->SetSubject('TCPDF Tutorial');
  $pdf->SetKeywords('TCPDF, PDF, example, test, guide');

  // set default header data
 $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 001', PDF_HEADER_STRING);

  // set header and footer fonts
  $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
  $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));

  // set default monospaced font
  $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

  //set margins
  $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
  $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
  $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

  //set auto page breaks
  $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

  //set image scale factor
  $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

  // ---------------------------------------------------------
 $pdf->setPageOrientation("L");


  // set default font subsetting mode
  $pdf->setFontSubsetting(true);

  // Set font
  $pdf->SetFont('helvetica', '', 6);

  // Add a page
  // This method has several options, check the source code documentation for more information.

$pdf->AddPage();

$pdf->Write(0, '', '', 0, 'L', true, 0, false, false, 0);


  // Set some content to print


 $html = $this->getUser()->getAttribute('para_pdf');


  $pdf->writeHTML($html, true, false, false, false, '');

  // ---------------------------------------------------------

  // Close and output PDF document
  // This method has several options, check the source code documentation for more information.
  $pdf->Output('example_conflictos.pdf', 'I');

  // Stop symfony process
  throw new sfStopException();
}

Luego, ¡finalmente yo obtengo el archivo en formato PDF con todos los datos correctamente mostrados!

Como usar select dependientes en Symfony 1.4 con tres tablas

La mayoría de los ejemplos que aparecen en Internet sobre como codificar las funciones javascript y JQuery para select dependientes, suponen el caso de dos tablas. La tabla «padre», donde se selecciona un elemento de la lista desplegable, y luego que se elige este, aparecen las opciones disponibles de la tabla «hijo» en la segunda lista desplegable.
Pero que pasa cuando tengo tres tablas. La tabla 1, contiene campos que la relacionan con las tablas 2 y 3, en una relación «uno a muchos». A su vez, la tabla 2 sería la tabla «padre» de la tabla 3, que pasaría a ser la tabla «hijo».
Veamos la siguiente imagen que ilustra la relación:

symfony

Cuando creo un registro nuevo para la tabla 1, los valores de las tablas 2 y 3, aún no existen, y si se usan las funciones disponibles en la web, estas funcionan bien.
Pero, si quiero editar un registro existente de la tabla 1, el formulario _form.php en Symfony, debe mostrar los valores correctos de las tablas 2 y 3. En estos casos, los ejemplos de la web para dos tablas no funcionan.
Veamos mi caso, y la forma en que modifique una función JQuery, para que trabaje bien, tanto para los registros nuevos como para la edición de un registro existente.

A continuación les presento las tres tablas y sus relaciones:
Tabla 1 (simplificada):

Conflictos1:
 connection: doctrine
 tableName: conflictos_1
 columns:
 id:
 type: integer(4)
 fixed: false
 unsigned: false
 primary: true
 autoincrement: true

 id_sector_actividad:
 type: integer(4)
 fixed: false
 unsigned: false
 primary: false
 notnull: true
 autoincrement: false

 id_subsector_actividad:
 type: integer(4)
 fixed: false
 unsigned: false
 primary: false
 notnull: false
 autoincrement: false

 relations:

 SectorActividadCiuTa7:
 local: id_sector_actividad
 foreign: id
 type: one
 SubsectorActividadTa8:
 local: id_subsector_actividad
 foreign: id
 type: one

Tablas 2 y 3:


SectorActividadCiuTa7:
  connection: doctrine
  tableName: sector_actividad_ciu_ta7
  columns:
    id:
      type: integer(4)
      fixed: false
      unsigned: false
      primary: true
      autoincrement: true
    sector_actividad:
      type: string(255)
      fixed: false
      unsigned: false
      primary: false
      notnull: true
      autoincrement: false
  relations:
    Conflictos1:
      local: id
      foreign: id_sector_actividad
      type: many
    SubsectorActividadTa8:
      local: id
      foreign: id_sector
      type: many
SubsectorActividadTa8:
  connection: doctrine
  tableName: subsector_actividad_ta8
  columns:
    id:
      type: integer(4)
      fixed: false
      unsigned: false
      primary: true
      autoincrement: true
    id_sector:
      type: integer(4)
      fixed: false
      unsigned: false
      primary: false
      notnull: true
      autoincrement: false
    descripcion:
      type: string(255)
      fixed: false
      unsigned: false
      primary: false
      notnull: true
      autoincrement: false
  relations:
    SectorActividadCiuTa7:
      local: id_sector
      foreign: id
      type: one
    Conflictos1:
      local: id
      foreign: id_subsector_actividad
      type: many

La función AJAX – JQuery, en el partial _form.php en el módulo conflictos1, quedaría así:

<script type="text/javascript">
$(document).ready(function()
{
    $("#conflictos1_id_sector_actividad").change(function()
    {
        var id_sub = $(this).val();
        if(id_sub != '')
        {
            $.ajax
            ({
                type: "POST",
                url: '<?php echo url_for('conflictos/subsector'); ?>'+ '?id=' + id_sub,
                cache: false,
                data: "id_sub="+ id_sub,
                success: function(data)
                {
                    $("#conflictos1_id_subsector_actividad").html(data); // but it does not select the value of dropdown list.
                }
            });
        }
        else
        {
            $("#conflictos1_id_subsector_actividad").html("
<option value=''>-- No se ha seleccionado subsector --</option>

");
        }
        return false;
    });
});
</script>

En el formulario del partial _form.php en el módulo conflictos1, la parte correspondiente al campo id_subsector_actividad, quedaría así:

<?php if (!$form->getObject()->isNew()): ?>
         <?php echo $form['id_subsector_actividad'] ?>
    <?php endif; ?>
 <?php if ($form->getObject()->isNew()): ?>
             <select name="conflictos1[id_subsector_actividad]" id="conflictos1_id_subsector_actividad">

              <option value="" selected="selected">Seleccione sub-sector</option>
  <?php endif; ?>

La función que se llama desde la url: conflictos/subsector sería como sigue:

  public function executeSubsector()

    {
        $id_sub = $_POST['id_sub'];

       $this->subsec= Doctrine_Core::getTable('SubsectorActividadTa8')
                ->createQuery('a')
                ->where('a.id_sector = ?', $id_sub)
                ->execute();
    }

Luego, para los casos de edición de un registro existente, necesitamos algo de código adicional. Agregamos para el campo 'id_subsector_actividad'en el widget de conflictos1 la propiedad 'table_method'=>'Subsector' asociada a la función  public function Subsector()para ello creamos en el archivo SubsectorActividadTa8Table.class.php la siguiente función:

public function Subsector()

    {
         global $elsector;

         if (!is_null($elsector)){
       $id_sub=$elsector;
       $query= Doctrine_Query::create()
            ->select('a.id')
            ->from('SubsectorActividadTa8 a')
         ->innerJoin('a.Conflictos1 c')

           ->where('a.id_sector = ?', $id_sub);
               return $query->execute();
    }
    }

En la función executeEdit del archivo actions.class.php del módulo conflictos1 quedaría así:

public function executeEdit(sfWebRequest $request)
  {
 global $elsector;
    $this->forward404Unless($conflictos1 = Doctrine_Core::getTable('Conflictos1')->find(array($request->getParameter('id'))), sprintf('Object conflictos1 does not exist (%s).', $request->getParameter('id')));

    $elsector= $conflictos1->getIdSectorActividad();

    $this->form = new Conflictos1Form($conflictos1);

  }

Aquí capturamos en la variable $elsector el valor del campo id_sector_actividad que luego utilizamos en la función Subsector()

Instalar Symfony 1.4 en Windows XP

Obviamente que el primer paso para poder utilizar Symfony 1.4, es instalarlo en nuestra PC. Explicaré, paso a paso, como lo hice yo. Utilizo los siguientes programas, como herramientas complementarias (todos son gratuitos y se encuentran en la Web):

  1. NetBeans 7.2 (es suficiente para Symfony descargar la versión para PHP solo)
  2. MySQL Workbench
  3. Wamp
Detalle del proceso de instalación:

Primero que nada, instalemos Wamp (o cualquier otro servidor Apache que corra en Windows XP). Una vez que Wamp, queda instalado, se creó automáticamente, una carpeta de nombre C:\wamp\www

Para saber si Wamp quedó bien instalado y no hay conflictos, arrancamos el programa y aparecerá un icono con una letra W como el que muestra la figura siguiente. Cuando Wamp arranca el icono comienza mostrándose en color rojo, luego cambia al color naranja, y finalmente, si todo anda bien, queda en color verde.

wamp_inst

Luego, se descarga el archivo de instalación de Symfony desde:

http://http://symfony.com/legacy

A continuación, buscamos en este sitio, la versión que necesitamos (yo utilizo la 1.4.18) y la descargamos.

En nuestra PC, se crea una carpeta con el nombre del proyecto, una sub-carpeta de nombre “lib” dentro de esta otra sub-carpeta de nombre “vendor”

Ejemplo: C:\miproyecto\lib\vendor

En este lugar de mi disco duro, copio el archivo sympony 1.4.18.tgz y procedo a descomprimirlo (con WinZip o WinRAR, hacer: extraer aquí)

Luego se renombra la carpeta “symfony1.4.18” que se ha creado automáticamente, como “symfony

Para comprobar que mi servidor reúne los requisitos mínimos para correr aplicaciones desarrolladas con Symfony 1.4, debemos ejecutar el archivo:

check_configuration.php

Para ello voy a la carpeta: symfony\data\bin y allí encuentro el archivo check_configuration.php, lo copio a:

C:\wamp\www (para los que tienen wamp como servidor )

Escribimos en la barra de direcciones de nuestro navegador: http://localhost/check_configuration.php

Se deben cumplir los “Mandatory requirements

Instalamos ahora NetBeans. Este programa, es un recurso muy cómodo y eficiente, para desarrollar aplicaciones con Symfony 1.4.

Iniciamos NetBeans:

Vamos a: Tools|options|PHP elegir pestaña que dice “symfony” solo.

Le digo a NetBeans donde está el archivo “symfony” de mi proyecto. Está en:

C:\miproyecto\lib\vendor\symfony\data\bin\

Luego voy a la pestaña “general” y debo seleccionar el interprete de PHP:

Ejemplo (suponiendo el uso de Wamp):

C:\wamp\bin\php\php5.3.10\php.exe

Hacemos click en “ok”

Vamos ahora a “File|New Proyect

Seleccionamos: “PHP Aplication” luego “Next

Damos nombre al proyecto.

Sources Folder: Seleccionamos la carpeta creada para el proyecto

Default encoding: dejar ISO-8859-1 o UTF-8

Marcar: “Put NetBeans metadata…”

Next

Run As:

Project URL: por ejemplo: http://miproyecto.local

Next

Marcamos: Symfony PHP web Framework…

Click en Finish

Los usuarios de Wamp van a:

Apache|httpd.conf

Abrimos el archivo, vamos al final y agregamos las líneas que se muestran abajo. Se debe elegir un puerto específico para el proyecto por ejemplo: 8080


# Asegúrate de tener sólo una vez esta línea en su configuración
NameVirtualHost 127.0.0.1:8080

# Esta es la configuración de Jobeet
Listen 127.0.0.1:8080

DocumentRoot «E:\proyectos\conflictosnew\web»

DirectoryIndex index.php
<Directory «E:\proyectos\conflictosnew\web»>

AllowOverride All
Allow from All
</Directory>
Alias /sf E:/proyectos/conflictosnew/lib/vendor/symfony/data/web/sf
<Directory «E:\proyectos\conflictosnew\lib\vendor\symfony\data\web\sf»>
AllowOverride All
Allow from All
</Directory>

Luego procedemos a Grabar
Si se utiliza Xampp como servidor, el código a incorporar sería:


# Asegúrate de tener sólo una vez esta línea en su configuración
NameVirtualHost 127.0.0.1:8080

# Esta es la configuración de Jobeet
Listen 127.0.0.1:8080

DocumentRoot «E:/proyectos/conflictosnew/web»

DirectoryIndex index.php
<Directory «E:/proyectos/conflictosnew/web»>
AllowOverride All
Allow from All
Require all granted
</Directory>

Alias /sf E:/proyectos/conflictosnew/lib/vendor/symfony/data/web/sf
<Directory «E:/proyectos/conflictosnew/lib/vendor/symfony/data/web/sf»>
AllowOverride All
Allow from All
Require all granted
</Directory>

Luego, editar el archivo “hosts” de windows ubicado en:

C:\windows\system32\drivers\etc

Agregar:

127.0.0.1 miproyecto

Reiniciar Apache. Con Wamp sería: “Restart All Service

Para saber si todo el proceso de instalación de Symfony 1.4 ha sido correcto, iniciamos Wamp, abrimos un browser tal como Google Chrome, y en la barra de direcciones escribimos la dirección y el puerto que asignamos a nuestro proyecto en la PC. Por ejemplo: http://127.0.0.1:8050

Si todo se ha instalado bien, deberá aparecer una pantalla similar a la siguiente:

success

Slots y java script: la combinación perfecta

¿Que es un «slot» en Symfony 1.4?

Un slot es simplemente un recurso de Symfony que permite insertar fragmentos de código HTML o java script, en determinados módulos y plantillas.

El caso más simple (sin uso de JavaScript): los títulos de las páginas

Si tuviéramos un simple archivo HTML por fuera de Symfony, y quisiéramos que la página aparezca en el navegador con un título determinado, por ejemplo «Página principal«, escribiríamos el código del siguiente modo:

<html>
<head>
<title>Página principal</title>
</head>
<body>

..........

</body>
</html>

Para poder aplicar el caso del punto anterior, a una plantilla determinada, en Symfony 1.4 debemos utilizar los “slots”.

En la literatura desarrollada por los creadores de Symfony, se despliega el ejemplo de un slot para insertar el título de cada página, que como ya vimos, debe ir dentro de <head> <title>…….</title></head> Además, se contempla el caso en que  queremos un título específico para ciertas y determinadas páginas y uno general, para las demás páginas. Los pasos son los siguientes:

Procedemos a definir, bajo que sección y usando cuales etiquetas, deseamos que aparezca un slot en el archivo layout.php de la aplicación frontend El código quedaría  como sigue:

// Archivo: apps\frontend\templates\layout.php

<head>
<title>
<?php if (!include_slot('title')): ?>
Portal de Conflictividad de la Provincia de Córdoba
<?php endif; ?>
</title>

<title><?php include_slot('title') ?></title>

Vemos que en las líneas de la 4 a la 8, le decimos a Symfony que, si no existe un título definido a través de un slot llamado ‘title‘ directamente use como título por defecto: Portal de Conflictividad de la Provincia de Córdoba

Luego, en la línea 10, queda definido el lugar donde irá el slot para los títulos, llamado ‘title‘ Vemos que el contenido del slot queda encerrado entre los tags <title> </title> .

En la página donde quiero que aparezca un título específico, por ejemplo el título «Listado de Conflictos» en  indexSuccess.php escribo lo siguiente:

// Archivo: apps\frontend\modules\conflictos\templates\indexSuccess.php

<?php slot('title') ?>
<?php echo ('Listado de Conflictos') ?>
<?php end_slot(); ?>

Automáticamente, Symfony sabe que este slot debe ir en el encabezado de la página dentro de las etiquetas <title> </title> porque así lo dejamos definido en layout.php

¿Cómo insertar código java script en plantillas de Symfony 1.4?

La mayoría de los desarrollos en javascript,  constan por un lado de un archivo de extensión js  que contiene las funciones para un uso determinado, que generalmente se guarda en la carpeta web/js Luego debe hacerse el llamado a las funciones, desde una página o plantilla determinada. ¿Cómo insertar este llamado a la función si las plantillas de Symfony 1.4, no tienen una sección <head> </head> ?

En el mismo template indexSuccess.php necesitaba usar una función de javascript que me permitiera ordenar una tabla por una columna determinada, haciendo clic sobre el encabezado de dicha columna. Para ello, necesitaba usar en el template (pero solo en este template) una función incorporada en el archivo jquery.tablesorter.js

Copiamos el archivo que contiene las funciones de java script, en web/js de nuestra aplicación. Como requiere del uso de jQuery, debo también incorporar el archivo de esta aplicación.
Cargamos el archivo desde view.yml

// Archivo: apps\frontend\modules\config\view.yml
stylesheets:    [jquery-ui-1.8.16.custom.css]
javascripts:    jquery-ui-1.9.2.custom.min.js, jquery.tablesorter.js]

Incluímos la siguiente línea, dentro del head en el archivo layout.php :

<?php include_slot('ordenar_tabla') ?>

Finalmente, en el template indexSuccess.php escribimos el llamado a la función, mediante el slot ‘ordenar_tabla‘ Cuando Symfony encuentre este slot definido en indexSuccess.php  sabe que lo debe incorporar al <head> de la página, porque así lo especificamos en el archivo layout.php :

// Archivo: apps\frontend\modules\conflictos\templates\indexSuccess.php

<?php slot('ordenar_tabla') ?>
<script type="text/javascript">
$(document).ready(function()
{
$("#myTable").tablesorter({widgets: ['zebra']});
}
);
</script>
<?php end_slot(); ?>