Desarrollo Web con Symfony2 integrando Sonata Project parte 3

De WikiSalud
Saltar a: navegación, buscar
Symfony Sonata05.jpg

veasé Desarrollo web con Symfony2 y Sonata Project parte 2

Contenido

Customización de vistas

Se iniciará con la customización de vista y agregando un poco de javascript y Jquery a dichas vistas. Se iniciar generando a la entidad CtlCanton un mantenimiento con el CRUD de Sonata

Vista edit

php app/console sonata:admin:generate
  • Modelo: Minsal/CatalogosBundle/Entity/CtlCanton
  • Nombre del Bundle: MinsalCatalogosBundle
  • Nombre de la clase Admin: CtlCantonAdmin
  • Generar Controlador: yes
  • Nombre del Controlador: CtlCantonAdminController
  • Actualización del servcio: yes
  • Nombre del servicio: services.yml
  • ID del servcio: minsal_catalogos.admin.ctl_canton

Generación de la clase Admin de CtlCanton Cambiar la siguiente linea del archivo services.yml:

- {name: sonata.admin, manager_type: orm, group: admin, label: CtlCanton}

Por la siguiente

- {name: sonata.admin, manager_type: orm, group: "AD-1-Administración", label: Cantón}


Agregando a la clase Admin:

 public function getTemplate($name) {
        switch ($name) {
            case 'edit':
                return 'MinsalCatalogosBundle:CtlCanton:edit.html.twig';
                break;
            default:
                return parent::getTemplate($name);
                break;
        }
    }

Cambiando en clase admin

use Doctrine\ORM\EntityRepository;
 
 
protected function configureFormFields(FormMapper $formMapper) {
        $formMapper
                ->add('nombre', null, array('label' => 'Nombre del cantón:'))
                ->add('codigoDigestyc', null, array('label' => 'Código Digestyc:'))
                ->add('rural', null, array('label' => 'Es un cantón de la zona Rurarl:'))
                ->add('idDepartamento', 'entity', array(
                    'label' => 'Seleccione el Departamento:',
                    'mapped' => false, 'required' => true,
                    'empty_value' => 'Seleccione..',
                    'class' => 'MinsalCatalogosBundle:CtlDepartamento',
                    'property' => 'nombre',
                    'query_builder' => function(EntityRepository $repositorio) {
                        return $repositorio
                                ->createQueryBuilder('departamento')
                                ->where('departamento.idPais=68');
                    }
                ))
                ->add('idMunicipio', 'entity', array(
                    'label' => 'Seleccione el Municipio:',
                    'required' => true,
                    'empty_value' => 'Seleccione..',
                    'class' => 'MinsalCatalogosBundle:CtlMunicipio',
                    'property' => 'nombre'
                ))
        ;
    }

Y crear dicha vista en el directorio Resources/view/CtlCanton, con el siguiente contenido:

{% extends base_template %}
 
{% block title %}
    {% if admin.id(object) is not null %}
        {{ "title_edit"|trans({'%name%': admin.toString(object)|truncate(15) }, 'SonataAdminBundle') }}
    {% else %}
        {{ "title_create"|trans({}, 'SonataAdminBundle') }}
    {% endif %}
{% endblock%}
 
{% block navbar_title %}
    {{ block('title') }}
{% endblock %}
 
{% block actions %}
    <li>{% include 'SonataAdminBundle:Button:show_button.html.twig' %}</li>
    <li>{% include 'SonataAdminBundle:Button:history_button.html.twig' %}</li>
    <li>{% include 'SonataAdminBundle:Button:acl_button.html.twig' %}</li>
    <li>{% include 'SonataAdminBundle:Button:list_button.html.twig' %}</li>
    <li>{% include 'SonataAdminBundle:Button:create_button.html.twig' %}</li>
{% endblock %}
 
{% block tab_menu %}{{ knp_menu_render(admin.sidemenu(action), {'currentClass' : 'active', 'template': admin_pool.getTemplate('tab_menu_template')}, 'twig') }}{% endblock %}
 
{% use 'SonataAdminBundle:CRUD:base_edit_form.html.twig' with form as parentForm %}
{% import "SonataAdminBundle:CRUD:base_edit_form_macro.html.twig" as form_helper %}
 
{% block form %}
    {{ block('parentForm') }}
{% endblock %}

Agregando archivo funciones_generales.js

//FUNCIÓN QUE SE UTILIZA PARA PERMITIR SOLO LETRAS Y UN SOLO ESPACIO.
//QUITANDO TODA TILDE, DIERESIS,ETC
function limpiar_nombres(text) {
    var text = text.toLowerCase(); // a minusculas
    text = text.replace(/[áàäâå]/, 'a');
    text = text.replace(/[éèëê]/, 'e');
    text = text.replace(/[íìïî]/, 'i');
    text = text.replace(/[óòöô]/, 'o');
    text = text.replace(/[úùüû]/, 'u');
    text = text.replace(/[ýÿ]/, 'y');
    text = text.replace(/[^a-zA-ZñÑ\s]/g, '');
    text = text.replace(/\s{2,}/, ' ');
    text = text.toUpperCase();
    return text;
}
 
function defalutlModalBodyMessage(e) {
 
    e = typeof e !== 'undefined' ? e : '';
 
    var html = '<div class="alert alert-block alert-error">\
                <h4>Error al cargar el elemento</h4>\
                Lo sentimos, hubo un problema al cargar la vista, \
                por favor intente nuevamente.<br /> \
                Si el problema persiste por favor contacte al administrador...</div>';
 
    if(e != '') {
        html = html + '<p><b>Detalle del Error</b><br />' + e + '</p>';
    }
    return html;
}
 
/*
 * Función que se utiliza para generalizar el uso de los select2
 * Parámetros de entrada:
 *              -element: elemento Jquery a modificar
 *              -removeChildren: true si se desea eliminar los hijos, false si no se desea borrar nada
 *              -placeholder: es el string que muestra al momento de realizar la selección
 *              -allowClear: si se desea el botón de limpiar se coloca true
 * 
 */
 
function initSelect2(element, removeChildren, placeholder, allowClear){
 
               if(removeChildren){
                   element.children().remove();
               }
 
               element.prepend('<option/>').val(function(){
                       return $('[selected]',this).val();
                   });
 
               element.select2({
                   placeholder: placeholder,
                   allowClear: allowClear,
                   width:'100%'
               });
           };
 
 
/*
 * Funcion que facilita mostrar los Message Dialog
 * Parametros:
 *      title: titulo de dialog
 *      msg: mensaje dentro del dialog
 *      dialogClass: [dialog-warning | dialog-error | dialog-info | dialog-success]
 */
 
function showDialogMsg(title, msg, dialogClass, closeBtnName, arrayBtns, createDefaultBtnClose) {
    if(jQuery('body #dialog-message').length > 0)
        jQuery('body #dialog-message').remove();
 
    jQuery("body").append('<div id="dialog-message"></div>');
    var element = jQuery('body #dialog-message');
 
    if (typeof dialogClass === "undefined" || dialogClass === null || dialogClass === '') {
        dialogClass = 'dialog-info'
    }
 
    if (typeof arrayBtns === "undefined" || arrayBtns === null || arrayBtns === '') {
        arrayBtns = [];
    }
 
    if (typeof closeBtnName === "undefined" || closeBtnName === null || closeBtnName === '') {
        closeBtnName = 'Cerrar';
    }
 
    if (typeof createDefaultBtnClose === "undefined" || createDefaultBtnClose === null || createDefaultBtnClose === '') {
        createDefaultBtnClose = true;
    }
 
    if(createDefaultBtnClose === true || arrayBtns.length === 0) {
        arrayBtns.push({
            text: closeBtnName, click: function() {
                jQuery( this ).dialog( "close" );
            }
        });
    }
 
    if (typeof title === "undefined" || title === null || title === '') {
        switch(dialogClass.replace('dialog-','')) {
            case 'error':
                title = 'Ha ocurrido un Error!';
                break;
            case 'warning':
                title = 'Advertencia!';
                break;
            case 'success':
                title = 'Realizado correctamente!';
                break;
            default:
                title = 'Informaci&oacute;n';
                break;
        }
    }
 
    if (typeof msg === "undefined" || msg === null || msg === '') {
        switch(dialogClass.replace('dialog-','')) {
            case 'error':
                msg = 'Se ha producido un error inesperado! Por favor, verifique los datos ingresados e intente nuevamente.';
                break;
            case 'warning':
                msg = 'Atenci&oacute;n, verifique la información proporcionada y que los datos esten completos. Estos podría generar un error.';
                break;
            case 'success':
                msg = 'La acci&oacute;n se ha realizado correctamente.';
                break;
            default:
                msg = 'No se ha definido información a mostrar al usuario.';
        }
    }
 
    var msgWi = '';
 
    switch(dialogClass.replace('dialog-','')) {
        case 'error':
            msgWi = '<i class="fa fa-fw fa-times-circle"></i>&nbsp;&nbsp;'+msg;
            break;
        case 'warning':
            msgWi = '<i class="fa fa-fw fa-warning"></i>&nbsp;&nbsp;'+msg;
            break;
        case 'success':
            msgWi = '<i class="fa fa-fw fa-check-circle"></i>&nbsp;&nbsp;'+msg;
            break;
        default:
            msgWi = '<i class="fa fa-fw fa-info-circle"></i>&nbsp;&nbsp;'+msg;
    }
 
    element.append(msgWi);
 
    element.dialog({
        dialogClass: dialogClass,
        modal: true,
        title: title,
        buttons: arrayBtns
    });
}

Agregando funciones generales a layout.html.twig en el bloque javascript

<script src="{{ asset('bundles/minsalcatalogos/js/funciones_generales.js') }}"></script>

Agregando bloque de javascript a edit.html.twig

{% block javascripts %}
    {{ parent() }}
    <script type="text/javascript">
        jQuery(document).ready(function ($) {
            var departamento = $('select[id$="_idDepartamento"]');
            var municipio = $('select[id$="_idMunicipio"]');
 
            initSelect2(municipio, true, 'Seleccione Municipio...', true);
            departamento.change(function () {
                initSelect2(municipio, true, 'Seleccione Municipio...', true);
                if ($(this).val() != '') {
                    jQuery.ajax({
                        url: Routing.generate('obtener_municipios', {idDepartamento: $(this).val()}),
                        async: false,
                        dataType: 'json',
                        timeout: 8000, // 8 sec
                        success: function (data) {
                            $.each(data.municipios, function (indice, muni) {
                                municipio.append($('<option>', {value: muni.id, text: muni.nombre}));
                            });
 
                        },
                        error: function (xhr, textStatus, errorThrown) {
                            showDialogMsg('Error...', 'Hubo un error al intentar obtener los departamento', 'dialog-error');
                        }
                    });
                }
            });
 
        });
    </script>
{% endblock%}

Agregando Controlador 'GeneralController.php' con el siguiente contenido:

<?php
 
namespace Minsal\CatalogosBundle\Controller;
 
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
 
class GeneralController extends Controller
{
 
    /**
     * @Route("/obtener/municipios", name="obtener_municipios", options={"expose"=true})
     * @Method("GET")
     */
    public function obtenerMunicipiosAction() {
 
        $request = $this->getRequest();
        $idDeptartamento = $request->get('idDepartamento');
 
        $em = $this->getDoctrine()->getManager();
        $dql = "SELECT m 
                FROM MinsalCatalogosBundle:CtlMunicipio m
                WHERE m.idDepartamento = :idDepartamento ";
        $municipios['municipios'] = $em->createQuery($dql)
                ->setParameter('idDepartamento', $idDeptartamento)
                ->getArrayResult();
 
        return new Response(json_encode($municipios));
    }
}

Reportes

Para la reportería, el MINSAL no posee una librería que sea obligatoria. El único requisito es que sea libre. Como demostración se utilizarán las siguientes librerías.

  • JasperReports Server
  • Wktmltopdf

JasperReports Server

Si ya se tiene intalado el entorno de desarrollo se debe instalar los siguientes paquetes:

aptitude install postgresql postgresql-contrib openjdk-7-jdk openjdk-7-jre

Cambio de contraseña de postgres

Para poder instalar JasperReports en el proceso de instalación es necesario la creación de ciertas bases de datos; para ello el instalador solicita la contraseña de usuario postgres. Por defecto Postgresql no tiene asignada ninguna contraseña cuando se realiza la instalación inicial, por lo que se debe asignar una momentáneamente sólo para este proceso. Como usuario root desde la consola:

su postgres
psql

Aparecerá en el prompt de la consola lo siguiente:

ALTER USER postgres WITH PASSWORD 'postgres';

Salir de la consola de postgres con \q

Descarga de JasperReports Server

Ingresa al siguiente enlace para poder descargar Jasper Reports Server http://community.jaspersoft.com/project/jasperreports-server y descargar la versión que se desee. En este caso utilizaremos la versión 5.1.0.

Instalar JasperReports Server

Abrir una terminal y como usuario 'root procederemos a darle permisos de ejecución:

chmod +x jasperreports-server-cp-5.x.x-linux-x64-installer.run

Ahora se procederá a la instalación de JasperReports Server con la siguiente sentencia:

./jasperreports-server-cp-5.x.x-linux-x64-installer.run

Lo primero que nos pide es leer la licencia de acuerdo del JasperReports Server. Aparecerá una imagen similar a la siguiente:

Instalacion01.png

Presionar tecla ENTER hasta terminar toda la licencia.

luego se procede a aceptar los términos de la licencia (Do you accept this license? [y/n] tecleando la letra “y”

Instalacion02.png

y posteriormente presionamos nuevamente la tecla ENTER.

Instalacion03.png

Ahora nos preguntará la opción de instalación que deseamos instalar , para nuestro caso presionaremos el numero 2 para seleccionar la opción Custom Install (Instalación Personalizada), ya que la primera opción instalaría todos los componentes y archivos de ejemplos pero pesa alrededor de 1.3 GB.

Instalacion04.png

Se procede a seleccionar la ruta de instalación del JasperReports; por defecto el instalador propone /opt, para seleccionar esta opción solo presionar enter.

Instalacion05.png

El siguiente paso es relacionado al servidor Apache Tomcat, el instalador propone instalar este servicio junto con su servidor. Presionar el numero 1 para seleccionar la opción I want to use the bundled Tomcat (Deseo utilizar el paquete Tomcat)

Instalacion06.png

El instalador pregunta si se desea instalar el SGDB Postgresql o utilizar uno ya instalado. Para esta opción presionar el numero 2 que indica la opción I want to use an existing PostgreSQL database (Quiero usar una base de datos PostgreSQL existente).

Instalacion07.png

Luego el instalador indica que se desea instalar nuevas bases de datos, pregunta si se desean sobrescribir si en caso existieran. Presionamos la tecla y.

Instalacion08.png

Se procede a la configuración de los servicios, tanto los nuevos a instalar como los instalados anteriormente. Primero preguntará el puerto por el que escuchará Apache Tomcat, se dejará el por defecto 8080, solo presionar enter

Instalacion09.png

La siguiente configuración es la del puerto por el cual se apagará Apache Tomcat, se dejará el puerto por defecto 8005 presionar tecla enter.

Instalacion10.png

Luego se debe de especificar el directorio en donde se encuentran los archivos binarios de postgresql. Los archivos binarios que necesita son:

  • psql
  • pg_restore
  • vacuumdb

Estos archivos se encuentran ubicados en la ruta /usr/bin/ por lo tanto se debe digitar esta ruta en el prompt y presionar enter.

Instalacion11.png

Ahora procederemos a configurar los parámetros específicos de la base de datos. La primera pregunta es escribir la IP o el Host de Postgresql, por defecto coloca la IP 127.0.0.1 así que solo presionar enter.

Instalacion12.png

La segunda opción es el puerto del gestor, por defecto aparece el 5432 así que presionar enter.

Instalacion13.png

Como última opción para la configuración de Postgresql se pide la contraseña asignada al usuario postgres, para este paso se debe de escribir la contraseña cambiada en el primer paso; es decir escribir postgres que es la clave que nosotros hemos asignado para el usuario postgres. La contraseña se deberá escribir dos veces para confirmar que la contraseña es correcta.

Instalacion15.png

Ahora el instalador pregunta si se desea instalar las bases de datos de ejemplo; en este caso ya que no son necesarias presionar n y luego presionar enter.

Instalacion16.png


Todos los pasos anteriores solo han sido para la preparación de la instalación, en este ultimo paso vamos a confirmar el inicio de la instalación para realizar esta acción presionar “y” y luego presionar la tecla enter.

Con este paso se procede a la instalación. Aparecerá una barrita de avance para la instalación. Este paso puede tardar algunos minutos, PRECAUCIÓN: No presionar ninguna tecla ni cancelar la instalación.

Instalacion17.png

Esperar hasta que el instalador realice la siguiente pregunta:For more information please visit: www.jaspersoft.com/heartbeat Presionar el tecla n y luego enter. Para finalizar la instalación.

Instalacion18.png

Ahora se procede a levantar el servicio del JasperReports, para estar seguros que la instalación se ha realizado correctamente. Como usuario root ubicarse en el directorio de instalación del JaspeReports Server que es /opt/jasperreports-server-cp-5.x.x/ con la siguiente sentencia:

cd /opt/jasperreports-server-cp-5.x.x
Instalacion19.png

Ejecutar la siguiente sentencia para levantar el servicio:

./ctlscript.sh start
Instalacion20.png

Abrir el navegador de su preferencia y probar la siguiente url http://localhost:8080/jasperserver/login.html deberá aparecer una pantalla similar a la siguiente:

Instalacion21.png
Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas