Symfony 2.8 y Swiftmailer en entorno de desarrollo

Es posible que Usted como yo, necesite probar que el envío de emails funciona adecuadamente, aunque esté en un entorno de desarrollo. Es decir: Usted quiere que el envío de emails desde su aplicación, funcione como si estuviera en un entorno de producción, y de ese modo el email sea realmente enviado desde su localhost y el destinatario de su correo, los reciba en su bandeja de entrada.

Mi punto de partida

Estoy desarrollando una aplicación con Symfony 2.8. Viene ya instalado el bundle de Swiftmailer para el manejo y envío de emails. Tengo escrito en mi controlador una rutina de prueba como esta:

// DocentesController.php
  public function enviarmailAction($name)
{
        $enviado_por='myemail@gmail.com';
                $enviado_para='toemail@gmail.com';
    $message = \Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom($enviado_por)
        ->setTo($enviado_para)
        ->setBody(
            $this->renderView(
                'docentes/email.txt.twig',
                array('name' => $name)
            )
        )
    ;
    $this->get('mailer')->send($message);
    return $this->render('docentes/email_enviado.html.twig',  
            array('message'=>$message, 'enviado_por' => $enviado_por, 'enviado_para' =>$enviado_para));
}    

Como puede verse, se utilizan dos plantillas de Twig. Una con el texto que contendrá el «Body» del email y otra que se muestra una vez que el email ha sido enviado. Estas plantillas muy simples, se presentan a continuación.
El archivo email.txt.twig solo contiene el siguiente texto:

Este es un mensaje de prueba

La plantilla de Twig que se muestra después del envío, llamada email_enviado.html.twig, es la siguiente:

{% block body %}
    <div align="left">
Usted ha enviado el siguiente e-mail:<br><br>
    De:  {{enviado_por}} <br>   
    Para:    {{enviado_para}}  <br>
    Asunto: {{message.subject}} <br>
    Body: {{message.body}} <br>
    </div>
{% endblock %}    

Mantener las cosas simples

Para hacer las pruebas de envío de emails en el entorno de desarrollo, utilizaré como servidor de correo a gmail, ingresando con mi usuario y contraseña de mi cuenta de gmail

Para probar el envío real de emails desde mi localhost, necesito configurar (y lo haré de la manera más básica posible) en mi aplicación de Symfony, los siguientes archivos:

# config_dev.yml

swiftmailer:
    transport: gmail
    username:  micuenta@gmail.com   
    password:  **********
    spool:
        type: memory

Luego:

# parameters.yml
parameters:
    database_host: 127.0.0.1
    database_port: null
    database_name: cursospiero
    database_user: root
    database_password: null
  
    mailer_user: micuenta@gmail.com
    mailer_password: *********

Verificar la configuración de la cuenta de Gmail

Para que todo lo anterior funcione, debo asegurarme que en mi cuenta de gmail, en htpps://myaccount.google.com/security se configure como: «Permitir el acceso de aplicaciones menos seguras:» a tal como se muestra en la imagen siguiente.
adecuar-google
Además, si tiene configurada la autenticación en dos pasos, deberá cambiarla, porque de otra manera le traerá problemas para usar el servidor de correo de gmail.

Desactivar el antivirus

Otro detalle que no puede obviar, porque le puede complicar la vida, es el antivirus. En mi caso utilizo Avast con todas las funcionalidades de seguridad para Internet, incluido un firewall. Para que las pruebas de envío de emails puedan realizarse sin problemas, deberemos desactivar el antivirus por un tiempo limitado, de otra manera bloqueará el envío de emails a través de nuestro localhost.

Y bien, esto es todo para empezar. Pruébelo para ver si a Usted le funciona.

Symfony2: Como manejarse con una fecha que tenga el valor null

Punto de partida: Trabajo con Symfony 2.8 y he diseñado la base de datos y las tablas que la componen con el software MySQL Workbench. Luego, hice exportar el esquema y crear la base de datos.
En Symfony 2.8, procedí a importar la base de datos ya creada y a generar las entidades.

Manejo de una fecha con valor null en un formulario diseñado con Twig

Mi problema: Tengo una tabla llamada Contratos (ver estructura en la imagen siguiente) con un campo fecha del tipo DateTime llamado fechaArchivo que puede ser nulo (valor=null).

Mi problema era que al utilizar las plantillas new.html.twig o edit.html.twig, Tiwg me exigía completar el valor del campo y no permitía dejarlo en blanco ni colocar una fecha igual a:»0000-00-00″. La solución está en utilizar la condición ‘required’ => false

contratos
Estructura de la tabla Contratos

Aquí la solución detallada con todos los archivos involucrados:

En el archivo donde se define la entidad Contratos, llamado Contratos.php tenemos:

 /**
     * @var \DateTime
     *
     * @ORM\Column(name='fecha_archivo', type='date', nullable=true)
     */
    private $fechaArchivo;

      /**
     * Set fechaArchivo
     *
     * @param \DateTime $fechaArchivo
     * @return Contratos
     */
    public function setFechaArchivo( \DateTime $fechaArchivo=null)
    {

       $this->fechaArchivo = $fechaArchivo;

        return $this;
    }

    /**
     * Get fechaArchivo
     *
     * @return \DateTime
     */
    public function getFechaArchivo()
    {
        return $this->fechaArchivo;
    }

En mi caso, como procedí a importar una base de datos ya existente, Symfony y Doctrine, crearon también un archivo llamado: Contratos.orm.xml que se muestra completo a continuación:

<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
  <entity name="BackendBundle\Entity\Contratos" table="contratos"  repository-class="BackendBundle\Entity\ContratosRepository">
    <indexes>
      <index name="fk_Contratos_Docentes1_idx" columns="docentes_id"/>
      <index name="fk_Contratos_Materias1_idx" columns="materias_id"/>
    </indexes>
    <id name="id" type="integer" column="id">
      <generator strategy="AUTO"/>
    </id>
    <field name="fechaInicio" type="date" column="fecha_inicio" nullable="false"/>
    <field name="fechaFinal" type="date" column="fecha_final" nullable="false"/>
    <field name="fechaFirma" type="date" column="fecha_firma" nullable="false"/>
     <field name="fechaArchivo" type="date" column="fecha_archivo" nullable="true"/>
    <field name="marcaImprimir" type="boolean" column="marca_imprimir" nullable="true"/>
    <field name="monto" type="decimal" column="monto" precision="10" scale="2" nullable="false"/>
    <field name="montoAdicional" type="decimal" column="monto_adicional" precision="10" scale="2" nullable="true"/>
    <many-to-one field="materias" target-entity="Materias">
      <join-columns>
        <join-column name="materias_id" referenced-column-name="id"/>
      </join-columns>
    </many-to-one>
    <many-to-one field="docentes" target-entity="Docentes">
      <join-columns>
        <join-column name="docentes_id" referenced-column-name="id"/>
      </join-columns>
    </many-to-one>
  </entity>
</doctrine-mapping>

Obsérvese con atención la línea 14 del código anterior, donde se fija el atributo nullable=»true» para el campo fechaArchivo

En el archivo donde se definen los atributos de los formularios, tengo:

 public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
             ->add('fechaInicio', 'date', array( 'attr' => array('style' => 'width: 80px'), 'widget' => 'single_text', 'format' => 'dd/MM/yyyy'))
            ->add('fechaFinal', 'date' ,  array( 'attr' => array('style' => 'width: 80px'), 'widget' => 'single_text', 'format' => 'dd/MM/yyyy'))
            ->add('fechaFirma', 'date',  array( 'attr' => array('style' => 'width: 80px'), 'widget' => 'single_text', 'format' => 'dd/MM/yyyy' ))
            ->add('fechaArchivo', 'date',  array('required' => false, 'attr' => array('style' => 'width: 80px'), 'widget' => 'single_text', 'format' => 'dd/MM/yyyy' ))
            ->add('materias')
            ->add('marcaImprimir')
            ->add('monto', 'money', array('currency'=>'ARS' ))
            ->add('montoAdicional', 'money', array('required' => false, 'currency'=>'ARS' ))
            ->add('docentes')
        ;
    }

Obsérvese que tengo cuatro campos fecha, donde tres son obligatorios y el campo fechaArchivo, puede ser null, entonces defino para ese campo la cualidad ‘required’ => false quedando la línea de código completa de la siguiente manera:

 ->add('fechaArchivo', 'date',  array('required' => false, 'attr' => array('style' => 'width: 80px'), 'widget' => 'single_text', 'format' => 'dd/MM/yyyy' ))

¡Y eso es todo! Tanto cuando creo un registro nuevo, como cuando edito uno ya existente, no necesito asignar ningún valor al campo fechaArchivo si no es necesario. Si observamos la tabla con phpMyAdmin, vemos que todos los registros que no tienen una fecha cargada en el campo fechaArchivo, poseen un valor igual a null que yo definí como valor por defecto.

Manejo de una fecha con valor null en una consulta con el uso de Doctrine y Symfony2

Mi problema: ¿Como utilizar una fecha con valor null en una consulta en Symfony2 con Doctrine?
Imaginemos que necesito conocer todos los registros de una tabla que tengan un valor null en un campo fecha. ¿Como es la sintaxis de la consulta?

Solución:En el código de abajo se puede ver la sintaxis correcta para que funcione una consulta, cuando queremos conocer los registros del campo fechaArchivo, que tengan un valor NULL.

public function findNull()
    {
        $em = $this->getEntityManager();

        $consulta = $em->createQuery('
            SELECT c, d, m
            FROM BackendBundle:Contratos c
            JOIN c.docentes d
            JOIN c.materias m
            WHERE c.fechaArchivo IS NULL

            ORDER BY d.apellido, d.nombres
        ');

        return $consulta->getArrayResult();
    }

¿Como mostrar una fecha con valor NULL en un listado de una plantilla de Twig?

Mi problema: Siguiendo con el ejemplo del campo fechaArchivo, si quiero mostrar en un plantilla de Twig el valor de este campo fecha, debo utilizar la siguiente sintaxis para evitar un mensaje de error:

 {% for contrato in contratos %}
                {% if contrato.fechaArchivo %}{{ contrato.fechaArchivo|date('d-m-Y') }}{% endif %}
        {% endfor %}

Esta sintaxis es la correcta para cualquier campo fecha, sea que pueda tener un valor NULL o no. Si el valor fuese NULL, simplemente Twig no mostrará ningún valor en el listado correspondiente.

Symfony 2.8 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 2.8 y luego transformar la información en un archivo de formato PDF usando la libreria TCPDF. También explicaré como puede diseñarse una plantilla Twig, para elegir donde ver publicados los datos: en pantalla o en un archivo pdf.

Aquí no explicaré la instalación de la librería TCPDF en Symfony2.
Un muy buen artículo acerca de como instalar y utilizar TCPDF en Symfony 2.7, puede consultarse aquí:
http://maryitsv.blogspot.com.ar/2014/11/instalacion-de-tcpdf-en-symfony-24.html

Por lo tanto, parto de suponer que Usted ya tiene instalada la librería TCPDF y desea visualizar datos de una base de datos.
Mi ejemplo, parte de tres tablas relacionadas como las que se muestran en la imagen siguiente:
tres_tablas

 

Como se deduce de la imagen, las tablas Materias y Docentes, tiene una relación de uno a muchos con la tabla Comisiones.
Supongamos que necesito hacer un listado que pueda verse en la pantalla y también que permita generar un archivo de formato PDF con los datos contenidos en estas tres tablas.
A continuación, dos capturas de pantallas de los dos resultados posibles:
En formato HTML, busco obtener este resultado:

salida_html

Y utilizando la misma plantilla Twig, quiero obtener en PDF algo como esto:

salida_pdf

Para ello, debemos primero que nada definir las rutas. Yo he creado tres rutas: comisiones_index (para ver el listado en pantalla), comisiones_indexpdf (para generar el listado y prepara la infomarción para obtener un archivo pdf) y finalmente: comisones_imprimirpdf (que procede a crear el archivo PDF y lo muestra en pantalla).

comisiones.yml
comisiones_index:
path: /
defaults: { _controller: "BackendBundle:Comisiones:index" }
methods: GET
comisiones_indexpdf:
path: /indexpdf
defaults: { _controller: "BackendBundle:Comisiones:index" }
methods: GET

A continuación, necesitamos crear los controladores. El archivo que contiene los controladores se llama: ComisionesController.php

/**
* Comisiones controller.
*
*/
class ComisionesController extends Controller
{
/**
* Lists all Comisiones entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$comisiones = $em->getRepository('BackendBundle:Comisiones')->findComisio();

return $this->render('comisiones/index.html.twig', array(
'comisiones' => $comisiones,
));
}
public function indexpdfAction()
{
$em = $this->getDoctrine()->getManager();
$comisiones = $em->getRepository('BackendBundle:Comisiones')->findComisio();

return $this->render('comisiones/index.html.twig', array(
'comisiones' => $comisiones,
));
}

La función indexAction no requiere mayor explicación. Lo único particular que hago, es llamar a una función que me permite construir la consulta a la base de datos. Esto está contenido en la sentencia:

fragmentoLa función indexpdfAction hace lo mismo que indexAction pero la creo para poder distinguir las rutas.

La función findComisio() está en el archivo ComisionesRepository.php

El código correspondiente se muestra más abajo. Podemos observar que en la función findComisio() construyo una consulta sobre las tres tablas: Comisiones, docentes y materias.

ComisionesRepository.php

<?php
namespace BackendBundle\Entity;

use Doctrine\ORM\EntityRepository;

class ComisionesRepository extends EntityRepository

{
public function findComisio()
{
$em = $this->getEntityManager();
$consulta = $em->createQuery('
SELECT c, d, m
FROM BackendBundle:Comisiones c
JOIN c.docentes d
JOIN c.materias m
ORDER BY d.apellido, d.nombres, c.id
');
return $consulta->getArrayResult();
}

Ahora procedo a construir el archivo Twig, llamado listadocomisiones.html.twig que utilizaré tanto para ver los datos en pantalla en formato HTML como también para generar el archivo PDF con los mismos datos.
{% extends 'backend.html.twig' %}
{% block mi_cuerpo %}
{% if app.request.attributes.get('_route') == "comisiones_index" %}
{% set es_pdf = false %}
{% else %}
{% set es_pdf = true %}
{% set para_pdf = '<h1>Listado de Comisiones (ordenadas por docente y materia)</h1>' %}
{% endif %}
{% if es_pdf == true %}
{{ inicio_pdf()}}
{% endif %}
<h3>Fecha de impresión: {{ obtener_fecha() }}</h3>
{% if es_pdf == false %}

<table>
{% else %}
<table cellpadding="5" >
{% endif %}
<tr>
<td>Id</td>
<td>Nro<br>carton</td>
<td>Activa</td>
<td>Docente</td>
<td>Materia</td>
<td>Fecha<br>inicio</td>
<td>Fecha<br>final</td>
<td>Total de <br>Alum.</td>
<td>Alum. Gar.</td>
<td>Horarios</td>
<td>Intensidad</td>
<td>Turno</td>
<td>Nro<br>comision</td>
{% if es_pdf == false %}
<td>Acciones</td>
{% endif %}
</tr>
{% for comisione in comisiones %}
<tr>
<td>{{ comisione.id }}</td>
<td>{{ comisione.nroCarton }}</td>
<td>{% if comisione.activa %}Si{% else %}No{% endif %}</td>
<td>{{ comisione.docentes.apellido }}, {{ comisione.docentes.nombres }}</td>
<td>{{ comisione.materias.descripcion }}</td>
<td style="text-align:center">{% if comisione.fechaInicio %}
{{ comisione.fechaInicio|date('d/m/Y') }}{% endif %}</td>
<td style="text-align:center">{% if comisione.fechaFinal %}
{{ comisione.fechaFinal|date('d/m/Y') }}{% endif %}</td>
<td style="text-align:center">{{ comisione.totalAlumnos }}</td>
<td style="text-align:center">{{ comisione.alumnosGarantia }}</td>
<td>{{ comisione.horarios }}</td>
<td>{{ comisione.intensidad }}</td>
<td>{{ comisione.turno }}</td>
<td>{{ comisione.nroComision }}</td>
{% if es_pdf == false %}
<td>
<ul>
<li>
<a href="{{ path('comisiones_show', { 'id': comisione.id }) }}">Mostrar</a>
</li>
<li>
<a href="{{ path('comisiones_edit', { 'id': comisione.id }) }}">Editar</a>
</li>
{% if comisione.activa %}
<li>
<a href="{{ path('comisiones_liqui', { 'id': comisione.id }) }}">Liquidar</a>
</li>
{% endif %}
</ul>
</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% if es_pdf == true %}
{% set hola = final_pdf(para_pdf) %}
{{ render(controller('BackendBundle:Comisiones:imprimirComisiones', {'posts' : hola })) }}
{% endif %}
{% endblock %}

La primer sentencia busca establecer desde donde se llama a la plantilla Twig. Si se llama desde la ruta comisiones_index definimos una variable es_pdf como «false» y a continuación mostramos por pantalla el título. Si el llamado a la plantilla viene de la otra ruta: comisiones_indexpdf, entonces es_pdf se define como «true». La variable «es_pdf» me permitirá determinar las porciones del código que se muestran en HTML solamente, y cual parte del código solo se utiliza para el archivo PDF. Por supuesto, la mayor parte de la plantilla contiene código común a las dos salidas posibles: HTML o PDF.
Para el caso del archivo PDF, procedo a crear una variable llamada: para_pdf donde se guarda el título del listado. Ya veremos más adelante como concatenar el título contenido en para_pdf con el cuerpo del listado.
En este listado, utilizo tres funciones con código PHP. Como no puedo insertar en forma directa el código PHP en la plantilla Twig, debo proceder a crear las funciones en un archivo llamado AppExtension.php (Ver más abajo)

La primer función invocada en el listado Twig se llama: inicio_pdf, y me permite empezar a grabar en el buffer del navegador los datos que se van generando en la plantilla Twig. Casi al final de la plantilla Twig, se puede ver la otra función esencial para obtener el PDF: final_pdf. A esta función se le pasa como parámetro, para_pdf y luego se concatena el contenido de esta variable con el detalle del listado almacenado en el buffer, cargando todo a la variable «hola». La tercer función que utilizo es opcional para este ejemplo. Se llama obtener_fecha y simplemente me imprime la fecha y hora actual, tanto por pantalla como en el PDF que se genere.
Obsérvese las últimas líneas de la plantilla:

listado5Allí vemos que, en caso de estar generando el archivo PDF, llamamos desde la plantilla Twig a la función imprimirComisiones a la que se le pasa la variable «hola» con todo el contenido de la plantilla Twig (ver el código detallado de la función más abajo). Esta función, que se guarda también en el archivo ComisionesController.php, simplemente construye el archivo PDF, y muestra el resultado por pantalla en formato PDF. Observese que el contenido de la variable «hola» es pasado desde la plantilla Twig al controlador. En el controlador, el contenido de «hola» ingresa como «$posts» y se imprime en el PDF que se genera.

Aquí el código:
public function imprimirComisionesAction($posts)
{
$pdf = $this->get('white_october.tcpdf')->create();
$pdf ->SetAuthor('Piero SRL');
$pdf ->SetTitle('Listado de Comisiones');
$pdf ->SetSubject('Listado');
// activa o desactiva encabezado de página
$pdf ->SetPrintHeader(false);
// activa o desactiva el pie de página
$pdf ->SetPrintFooter(true);
$pdf ->SetFont('times', '', 10);
$pdf->setPageOrientation("L");
// set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 001',
PDF_HEADER_STRING, array(0,64,255), array(0,64,128));
$pdf->setFooterData(array(0,64,0), array(0,64,128));
// 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);
$pdf ->AddPage();
// escribir los datos
$pdf->writeHTMLCell(0, 0, '', '', $posts, 0, 1, 0, true, '', true );
// la siguiente línea es para limpiar el buffer de datos
ob_end_clean();
$pdf->Output('comisiones.pdf', 'I');
}
}

Dijimos que para usar funciones PHP en una plantilla Twig, debemos utilizar las extensiones de Twig. A continuación vemos la ubicación del archivo a crear:

Ubicación de AppExtension.php
appextension
Debemos también habilitar el servicio correspondiente en el archivo services.yml:
services

Finalmente debemos crear las funciones que llamamos desde Twig. El contenido de AppExtension.php puede verse a continuación:

<?php
namespace AppBundle\Twig;

class AppExtension extends \Twig_Extension
{

public function getFunctions()
{
return array(
new \Twig_SimpleFunction('inicio_pdf', array($this, 'iniciopdfFunction')),
new \Twig_SimpleFunction('final_pdf', array($this, 'finalpdfFunction')),
new \Twig_SimpleFunction('obtener_fecha', array($this, 'obtenerFecha')),
);
public function iniciopdfFunction()
{
ob_start();
return;
}

public function finalpdfFunction($para_pdf)
{
$postsbis = ob_get_contents();
$posts=$para_pdf . $postsbis;
ob_end_clean();

return $posts;
}

public function obtenerFecha()
{
setlocale(LC_ALL, "es_ES");
$timestamp=time();
$format='l j F Y H:i';

$trans = array(
'Monday' => 'Lunes,',
'Tuesday' => 'Martes,',
'Wednesday' => 'Miércoles,',
'Thursday' => 'Jueves,',
'Friday' => 'Viernes,',
'Saturday' => 'Sábado,',
'Sunday' => 'Domingo,',
'January' => ' de Enero de ',
'February' => ' de Febrero de ',
'March' => ' de Marzo de ',
'April' => ' de Abril de ',
'May' => ' de Mayo de ',
'June' => ' de Junio de ',
'July' => ' de Julio de ',
'August' => ' de Agosto de ',
'September' => ' de Septiembre de ',
'October' => ' de Octubre de ',
'November' => ' de Noviembre de ',
'December' => ' de Diciembre de ',
);
return strtr(date($format,$timestamp),$trans);
}
public function getName()
{
return 'app_extension';
}
}

Para ver en detalle como usar las extensiones de Twig, consulte el siguiente link:
http://symfony.com/doc/2.8/cookbook/templating/twig_extension.html

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.