• Deployment de una aplicación realizada con prestashop

    Deployment de una aplicación realizada con prestashop

    Me he metido de lleno con esta herramienta para realización de tiendas.  Es cierto, que algunos puntos son un poco tediosos a la hora de modificar, pero creo que es una excelente herramienta para programar tiendas, siempre y cuando el desarrollo pueda ser flexible y la funcionalidad no demasiado concreta.

    Al ir programando desde local, me he dado cuenta que tampoco hay una herramienta propia para hacer un deployment al entorno de producción.  Tenemos que tener en cuenta que la base de datos en el caso de prestashop va muy ligada al código.  Es decir, como funciona por módulos. mucha información de éstos se guarda en la base de datos.  Para realizar el deployment del código y la base de datos, he creado un script que sincroniza los datos de local con los de producción, actualizando la base de datos de este último entorno con los de local.  IMPORTANTE, NO EJECUTAR ESTE SCRIPT SI EN PRODUCCIÓN HAY DATOS REALES QUE NO ESTÁN EN DESARROLLO, sino nos los cargaríamos.  Además es aconsejable realizar una copia de seguridad previa, tanto de datos como de código.

    El script está realizado en un mac osx.  Creo que es totalmente compatible con linux.  Lo único que habría que hacer previamente es introducir las variables correspondientes.

    sync.sh

    =====

    SSH_USER=XX
    SSH_DOMAIN=XX
    PATH_SITE_PROD=XX/YY

    PATH_MYSQLDUMP=/Applications/MAMP/Library/bin/mysqldump
    PATH_PROJECT=/XX/ZZ
    DATA_FOLDER=data
    DOMAIN=XX
    DB_LOCAL_USER=XX
    DB_LOCAL_DB_NAME=XX
    SHOP_ID=1

    $PATH_MYSQLDUMP -u $DB_LOCAL_USER -p -a $DB_LOCAL_DB_NAME > $PATH_PROJECT/$DATA_FOLDER/database.sql
    echo “UPDATE ps_shop_url set domain=’$DOMAIN’, domain_ssl=’$DOMAIN’ where id_shop_url=$SHOP_ID;” >> $PATH_PROJECT/$DATA_FOLDER/database.sql

    rsync –verbose –compress –recursive \
    –times –links –exclude “cache/smarty/compile” –exclude “.DS_Store” –exclude “config/defines.inc.php” –exclude “config/settings.inc.php” –exclude –exclude “sync.sh”  \
    . $SSH_USER@$SSH_DOMAIN:$PATH_SITE_PROD

    ====================================================

    Una vez ejecutado el script desde el servidor tenemos que ejecutar el siguiente comando para actualizar la BD:

     

    mysql -u USER_DB -p -D NAME_DB < PATH_PROYECT/data/database.sql

     

  • sfDependentSelectPlugin ordenado por texto

    sfDependentSelectPlugin ordenado por texto

    Utilicé este interesante plugin para mostrar select box dependientes. En concreto para mostrar un select box de “Sector” y “Puesto”, siendo los puestos dependientes del sector elegido.

    El plugin funciona bien, pero tiene un problema y es que los valores de los selects, tanto del padre como del dependiente, no muestra los valores ordenados por el texto, sino por el ID del registro al que se refiere.  Ni siquiera poniendo la opción “order_by” al declarar el widget:

     

    this->widgetSchema[“puesto_id”] = new sfWidgetFormDoctrineDependentSelect(array(‘model’ => ‘Puesto’,
                                                                                                                                                                              ‘depends’ => ‘Sector’,
                                                                                                                                                                              ‘add_empty’ => true,
                                                                                                                                                                              ‘ajax’ => true,
                                                                                                                                                                              ‘ref_method’ => ‘getSectorId’,
                                                                                                                                                                              ‘url’ => sfContext::getInstance()->getController()->genUrl(‘sfDependentSelectAuto/_ajax’),
                                                                                                                                                                              ‘cache’ => true,
                                                                                                                                                                              // the same of sfWidgetForm{Doctrine|Propel}Choice are available ¿?
                                                                                                                                                                              ‘order_by’ => array(‘nombre’, ‘asc’),
                                                                                                                                                                              ‘method’ => ‘__toString’,
                                                                                                                                                                              ‘key_method’ => ‘getId’,
                                                                                                                                                             ) );

     

    Para solventar este problema, he modificado el código del archivo SelectDependiente.js, dentro del método mostrar, sustituyendo

    this.agregarOpcion(valor, this.opciones[this.grupo][valor]);

    por:

    var ordered = new Array();

    // Ordenamos array
    for (var valor in this.opciones[this.grupo]){
         var elemento = new Array();
          elemento[“id”] = valor;
         elemento[“text”] = this.opciones[this.grupo][valor];
         var found = false;
         for (var valor2 in ordered){
              if (elemento[“text”] < ordered[valor2][“text”]){
                   ordered.splice(valor2, 0, elemento);
                   found = true;
                   break;
              }
         }
         if (!found)
              ordered.push(elemento);
    } // Fin orden

    // Agregamos los elementos ordenados
    for (var i in ordered)
         this.agregarOpcion(ordered[i][“id”], ordered[i][“text”]);

     

    El cambio es válido para cualquier proyecto que utilice SelectDependiente.js, sin ser estrictamente necesario que se utilice bajo el framework de Symfony.

    Espero que este post ayude a aquellos usuarios que se hayan encontrado con este problema al utilizar este útil javascript.

  • En Symfony, es muy tedioso configurar uno a uno los distintos mensajes de error al enviar un formulario.

    El método tradicional para un widget en concreto es (dentro de la clase del formulario):

    class ProductoForm extends BaseProductoForm
    {
      public function configure()
      {

         […]

         $this->validatorSchema[“email”]->setMessage(“invalid”, “El email es inválido”);

      } 

    }

    Este error solo se mostrará en el caso de que el email sea inválido y habría que hacerlo uno a uno en todos los validadores de todos los campos.

     

    Para crear un mensaje genérico para todos los widgets de cualquier formulario:

    Para esto hay que introducir el siguiente código en la clase configuration de la aplicación:

    class frontendConfiguration extends sfApplicationConfiguration{

    public function configure()
    {
      sfValidatorBase::setDefaultMessage(‘required’,’Obligatorio’);
      sfValidatorBase::setDefaultMessage(‘invalid’, ‘Inválido’);
      sfValidatorBase::setDefaultMessage(‘max_length’, “%value% es muy largo (%max_length% caracteres max.)”);
    }
    }

    De esta forma, cuando nos dejamos un campo obligatorio aparecerá el texto “Obligatorio”, en lugar de “Required”, etc.

     

    Para que este mensaje sea multiidioma:

    En ese caso primero hay que cargar el helper I18N:

    $this->loadHelpers(array(‘I18N’));

    Y así ya podemos utilizar la función de internacionalización:

    if (sfContext::hasInstance()){

      sfValidatorBase::setDefaultMessage(‘required’,__(‘Obligatorio’));

    }

    Lo de comprobar si tiene una instancia es porque sino da problemas a la hora de hacer algunas operaciones desde la línea de comandos de symfony, como limpiando caché symfony cc.