logotipo prestashop

Prestashop pone a disposición de los desarrolladores un formulario que genera los archivos necesarios para la creación de un módulo, incluyendo opciones como para compatibilidad de versiones, hooks a los que se anclará el módulo, uso de posible tabla propia en la base de datos…

La siguiente dirección nos permitirá generar los archivos necesarios para comenzar con la creación de cualquier módulo:

https://validator.prestashop.com/generator

A partir de las instrucciones de la documentación de Prestashop, hemos seguido un «tutorial» para crea un módulo muy básico, disponible ya en mi repositorio a través de esta dirección:

https://github.com/JorgeGolo/first-upload-module

Este es el enlace a la documentación oficial:

Voy a listar unas notas que me han parecido bastante esclarecedoras sobre la forma que tiene Prestashop de estructurar sus módulos, y de cómo seguir sus estándares. Algunas ya las conocía de otras versiones:

  • Todo módulo generado con el formulario que hemos comentado, llamado «Nombredelmodulo», tiene un archivo principal llamado nombredelmodulo.php, con una estructura de carpetas similar a todos los demás módulos
  • Si tiene una sección de «Configuración» en el BackOffice tiene una función llamada getContent() en el archivo nombredelmodulo.php
  • Tools::isSubmit() es un método específico de Prestashop que comprueba si un formulario ha sido ejecutado.
  • Tools::getValue() es otro método específico que lee el parámetro desde POST o GET. En el ejemplo, Tools::getValue(‘MYMODULE_CONFIG’), donde MYMODULE_CONFIG es el name que le hemos dado al input del formulario.
  • updateValue(‘MYMODULE_CONFIG’, $nombrevariable) actualizará el texto del campo del formulario.
  • El objeto Validate contiene muchos métodos de validación, uno de ellos es isGenericName(), que ayuda a validar una string con «formato Prestashop válido», es decir, sin caracteres especiales.
  • displayError() muestra un mensaje de error
  • Hay algunos otros métodos explicados en el ejemplo que son fáciles de seguir.

En el tutorial también se habla de HelperForm. En el contexto de programación web y sistemas de gestión de contenido como PrestaShop, HelperForm es una función o clase utilizada para simplificar la creación de formularios en el back office de PrestaShop. Estos formularios suelen ser parte de módulos o extensiones que se integran en el panel de administración de PrestaShop. Aquí tienes una lista de ventajas del uso de los estándares con HelperForm:

  1. Facilita el Desarrollo:
    • Un helperform podría proporcionar métodos y funciones listas para usar que simplifican la creación de elementos comunes de formularios, como campos de entrada, botones, selectores, etc.
    • La estandarización facilita el desarrollo, ya que los desarrolladores pueden utilizar la misma interfaz y estructura para crear formularios en diferentes partes del back office.
  2. Consistencia Visual:
    • Al utilizar una clase o función común para la creación de formularios, se promueve la consistencia visual en la interfaz de administración de PrestaShop.
    • Los elementos del formulario generados por el helperform seguirían un estilo y diseño coherentes, lo que mejora la experiencia del usuario y la apariencia general del back office.
  3. Reutilización de Código:
    • La función o clase «helperform» podría contener métodos que encapsulen la lógica comúnmente utilizada en la manipulación y validación de datos de formularios.
    • Esto permite a los desarrolladores reutilizar código, evitando la duplicación y reduciendo la probabilidad de errores.
  4. Adaptabilidad a Futuras Actualizaciones:
    • Al seguir una interfaz estandarizada proporcionada por el helperform, los módulos y extensiones desarrollados con esta clase pueden ser más adaptables a futuras actualizaciones de PrestaShop.
    • Cambios en la implementación interna de PrestaShop podrían ser manejados dentro de la clase helperform, minimizando el impacto en los módulos existentes.
  5. Documentación Clara:
    • Una función o clase dedicada simplifica la documentación para los desarrolladores. Pueden entender rápidamente cómo crear formularios y qué métodos están disponibles, facilitando la adopción y el mantenimiento.
  6. Aumento de la Productividad:
    • Al reducir la complejidad y la cantidad de código necesario para crear formularios, los desarrolladores pueden ser más productivos y centrarse en la lógica específica de sus módulos en lugar de la implementación de formularios.
  • Para generar un formulario, usamos un array multinivel y luego se lo pasamos como parámetro a la clase HelperForm
  • Se crea una instancia de la clase y se le pasan parámetros a sus métodos.
  • Luego se usa el método generateForm() pasándole como variable el array que hemos creado anteriormente.
  • Todo esto dentro de una función displayForm() que tendrá este return:        
return $helper->generateForm([$form]);
  • La función displayForm la pasamos a su vez al return de getContent(), junto con otras variables (si queremos):      
return $output . $this->displayForm();

Prestashop pone a disposición de los desarrolladores otros helpers como HelperList. En esta entrada se hace uso de HelperList:

https://www.prestashop.com/forums/topic/334228-solved-helperlist-not-generating-the-list/

Archivos que vamos a tratar

  • /database/seeders/DatabaseSeeder.php
  • /migrations

Rellenaremos la base de datos con datos de prueba para hacer consultas con Eloquent.

Antes de crear Seeders y Factories, ejecutamos este comando:

php artisan migrate:reset

Esto eliminará todas las tablas de la base de datos. Lo hacemos porque vamos a eliminar las migraciones que creamos en el capítulo anterior, y vamos a agregar una columna a la tabla cursos manualmente, añadimos una columna llamada «categoría»:

    public function up()
    {
        Schema::create('cursos', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->text('categoria'); // nueva columna
            $table->timestamps();
        });
    }

Luego abrimos el archivo DatabaseSeeder.php. Tenemos que escribir al principio de este archivo que estamos usando el modelo Curso:

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Curso; // añadimos esta línea

Y dentro de la función run() escribimos lo que practicábamos con Tinker en la lección anterior, para crear un registro:

    public function run()
    {
        $curso = new Curso();
        $curso->name('Laravel');
        $curso->description('El mejor Framework');
        $curso->categoria('Desarrollo web');

        $curso->save();
    }

Podemos ejecutar el comando fresh para que se borren y se creen todas las tablas de nuevo:

php artisan migrate:fresh

Y luego ejecutamos los seeders:

php artisan db:seed

Ya se ha añadido el primer registro. Añadamos tres a la vez:

    public function run()
    {
        $curso = new Curso();
        $curso->name='Laravel';
        $curso->description='El mejor Framework';
        $curso->categoria='Desarrollo web';

        $curso->save();
        
        $curso2 = new Curso();
        $curso2->name='Laravel';
        $curso2->description='El mejor Framework';
        $curso2->categoria='Desarrollo web';

        $curso2->save();
        
        $curso3 = new Curso();
        $curso3->name='Laravel';
        $curso3->description='El mejor Framework';
        $curso3->categoria='Desarrollo web';

        $curso3->save();
    }

Ejecutamos de nuevo los comandos para tener más registros en la base de datos:

php artisan migrate:fresh
php artisan db:seed

Pero lo podemos hacer mejor, creando un seeder para los cursos:

php artisan make:seeder CursoSeeder

Dentro del archivo CursoSeeder, pegamos los registros que creamos en DatabaseSeeder. Además, llamamos al modelo Curso como lo hicimos allí también. Y en DatabaseSeeder, en vez de la creación de registros de la función pública run (que ahora está en CursoSeeder):

$this->Call(CursoSeeder::class);

Ahora ejecutamos los dos comandos de artisan fresh y seed, pero esta vez lo haremos en una sola línea:

php artisan migrate:fresh --seed

Recursos

Enlace de Youtube: https://www.youtube.com/watch?v=zNTF3U2Hsq0&list=PLZ2ovOgdI-kWWS9aq8mfUDkJRfYib-SvF&index=13

Seeders con tablas relacionadas: https://www.php-dev-zone.com/blog/seeding-table-with-relationships-in-laravel-8

Definiciones

  • ORM: Modelo de programación que permite mapear las estructuras de una base de datos relacional (en nuestro ejercicio, MySQL), sobre una estructura lógica de entidades para simplificar y acelerar el desarrollo. Las estructuras de la base de datos quedan vinculadas con las entidades lógicas o base de datos virtual definida en el ORM, de tal modo que las acciones CRUD (CreateReadUpdateDelete) se realizan de forma indirecta por medio del ORM. Así, realizar consultas a la base de datos se puede hacer sin escribir código SQL, sino utilizando objetos y métodos.
  • Modelos: En Laravel crearemos un modelo por cada una de las tablas que queramos administrar. Existe una convención para el nombre de las tablas y los modelos, ya que éstos tendrán el nombre en singular para un nombre de tabla en plural (en inglés). Siempre podemos crear una variable de tipo protected dentro de la clase del modelo para especificar otro nombre de tabla, si fuera necesario no seguir la convención.
  • Eloquent: El ORM que incluye Laravel.
  • Tinker: es una herramienta para ejecutar código php en la consola de Laravel, con la que podemos hacer pruebas de funcionamiento, y también podemos usar la directivas de Eloquent.

Vamos a ejercitarnos con el uso de Tinker, una herramienta que nos permite ejecutar el consola acciones sobre la base de datos mediante el ORM, instanciando objetos y llamado a sus métodos. Para ejecutar Tinker, en consola:

php artisan tinker

Para salir de Tinker, simplemente ejecutamos exit.

Antes de continuar, vamos a crear un modelo para la tabla «cursos», por lo que lo llamamos Curso siguiendo la convención:

php artisan make:model Curso

Ya tenemos nuestro archivo dentro de la capeta Models.

Insertar registros en la base de datos

  • Llamamos al modelo con el comando use y su namespace
  • Crear una instancia del objeto con el comando new
  • Agregar propiedades a los métodos
  • Salvar con save; si queremos guardar los registros en la base de datos.

En Tinker:

use App\Models\Curso
$curso = new Curso; // aquí estamos instanciando el objeto 
// dentro de una variable llamada curso
$curso->name ="nombre del curso"; // asignamos un valor 
// a la propiedad name
// que es un campo de la tabla
$curso->description="descripción del curso"; // más propiedades
$curso; // esta línea sólo devuelve info del objeto
$curso->save(); // guarda la info del objeto en la tabla

Si después de salvar, volvemos a ejecutar:

$curso;

Tendremos la información de los campos created_at y updated_at leídos directamente desde la base de datos. Si modificáramos el objeto, se actualizaría el campo updated_at.

Para actualizar un campo, como el objeto ya está creado, basta con escribir:

$curso->description="descripción actualizada";
$curso->save();

Podemos así añadir más campos:

$curso2 = new Curso;
$curso2->name ="otro curso"; 
$curso2->description="otra descripción del curso";
$curso2->save();

Recursos

Enlace de Youtube: https://www.youtube.com/watch?v=MUOKdpbgbNk&list=PLZ2ovOgdI-kWWS9aq8mfUDkJRfYib-SvF&index=12

Comentario sobre git: https://es.stackoverflow.com/questions/368437/como-crear-versiones-de-un-proyecto-con-git

Guía breve para git: https://rogerdudler.github.io/git-guide/index.es.html

Archivos/carpetas
  • database/migrations

Diferencia entre migrate:fresh y migrate:refresh

El primero ejecuta uno a uno el método down de cada migración, y luego ejecuta uno a uno el método up.

El segundo borra todas las tablas, y ejecuta uno a uno el método up.

Son métodos destructivos, que eliminarían los registros de la base de datos si los hubiera. Por ello vamos a aprender a modificar las tablas in tener que ejecutar estos métodos

Agregar campos a una tabla

Vamos a añadir un campo a nuestra tabla users.

Para practicar esto, añadimos manualmente un registro, con phpmyadmin, a la tabla users, con nombre, contraseña y email.

Creamos una nueva migración, escrita con una convención para facilitarnos las cosas.

php artisan make:migration add_avatar_to_users_table

add_avatar_to_users_table indica que estamos haciendo una migración de añadir una campo lamado avatar a la tabla users. Esto creará un archivo de migración que contiene las siguientes funciones:

public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }

La función up llama a la clase Schema con el método table, que incluye la función con el parámetro del tipo Blueprint con nombre table, para que podamos añadir campos a la tabla. En la función down escribiremos lo necesario para revertir los campos.

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('avatar')->nullable();            
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('avatar');
        });
    }

Hemos usado el método nullable para el campo avatar, indicando que éste puede ser null. Ahora podemos ejecutar la migración con php artisan migrate para ver los cambios.

    php artisan migrate

Y vamos a volver a migrar modificando antes el método up de nuestra migración, donde añadimos el método after para colocar el campo donde queremos:

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('avatar')->nullable()->after('email');            
        });
    }

El campo está al final de la tabla, donde ya hay registros, y tiene el valor null. Revertimos los cambios con un rollback:

    php artisan migrate:rollback

Modificar propiedades de un campo de una tabla

Observamos que el campo name acepta 255 caracteres. Vamos a hacer que sólo acepte 150.

Para este tipo de cambios necesitamos instalar una dependencia, ejecutando este comando en la terminal:

composer require doctrine/dbal

Debemos crear una migración como la que sigue, usando también el nombre por convención:

php artisan make:migration cambiar_propiedades_to_users_table

Ya tenemos nuestro nuevo archivo de migración que, como en el ejercicio anterior, está nombrado por convención para facilitar la escrituradel código.

El siguiente comando ejecuta el método up de cada una de las migraciones, así crearemos las tablas. Desde la consola, migramos. recordamos que para migrar tenemos que ejecutar este comando:

php artisan migrate

El método down eliminará la tabla cuando ejecutemos ciertos comandos de artisan. Modificamos las funciones up y down como sigue, creo que el código se explica solo: estamos usando el método change para cambiar el número de caracteres del campo name de la tabla users, y poniéndolo como estaba en la función down usando el mismo método:

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('name', 150)->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('name', 255)->change();
        });
    }

Podemos ejecutar la migración y comprobar los cambios con phpmyadmin. En ningún momento estamos perdiendo datos de la tabla.

Seguimos practicando: añadamos un poco más de código, para hacer que name acepte campos nulos:

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('name', 150)->nullable()->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('name', 255)->nullable('false')->change();
        });
    }

Hemos añadido la opción de que el campo name pueda contener valores nulos. para hacer efectivo este nuevo cambio, debemos hacer un rollback y migrar de nuevo.

Recursos

Enlace de Youtube: https://www.youtube.com/watch?v=2pppMAtIlro&list=PLZ2ovOgdI-kWWS9aq8mfUDkJRfYib-SvF&index=11

Carpetas de esta lección
  • config/database.php
  • .env
  • database/migrations

Creamos base de datos con phpmyadmin

Creamos una base de datos desde phpmyadmin y la llamamos blog, el mismo nombre que nuestro proyecto.

Abrimos el archivo config/database.php.

Ahí está definida el tipo de base de datos con la que nos conectamos, así como otras variables por defecto. El tipo de base de datos está en esta línea:

    'default' => env('DB_CONNECTION', 'mysql'),

Más abajo debemos indicar el host, la base de datos, el usuario, la contraseña. Podemos hacerlo ahí directamente, pero es mejor no hacerlo porque al subirlo a Github quedaría expuesto. Por eso es recomendado hacerlo en el archivo .env, como indica el mismo archivo. Nos podemos quedar con los valores por defecto para este ejercicio, que son los valores que adjudica XAMPP.

Creación de tablas, migraciones

Podemos crear las tablas desde phpmyadmin, mas lo vamos a hacer usando las herramientas de Laravel.

Las migraciones son el control de versiones de la base de datos, así como su estructura. Echemos un vistazo a la migración de database/migrations llamado create_users. Vemos dos funciones públicas, up y down, y nos detendremos en la función up que nos va a crear nuestra tabla con sus columnas:

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

La función up llamará a la clase Schema con el método create, con dos parámetros: el nombre de la tabla y una función que recibe como parámetro el objeto de tipo Blueprint llamado $table, y ese objeto llama´ra sucesivamente a varios métodos. Cada uno de ellos tiene unas propiedades muy concretas que las asignará a cada tabla. por ejemplo, el solo hecho de llamar al método id() hará que se cree un campo id que tendrá la propiedad autoincrement, del tipo entero y sin signo.

No nos detendremos de momento a analizar cada uno de los métodos que nos proporciona Laravel para los campos de la tabla, con muchas propiedades distintas y con su utilidad. En la documentación de Laravel tendremos todas las propiedades de las columnas y los métodos.

El siguiente comando ejecuta el método up de cada una de las migraciones, así crearemos las tablas. Desde la consola:

php artisan migrate

El método down eliminará la tabla cuando ejecutemos ciertos comandos de artisan.

Más sobre migraciones

En nuestras base de datos se ha creado una tabla adicional, donde se registran cada una de las migraciones, la tabla migrations. Cada vez que creemos y hagamos nuevas migraciones, se grabará un registro en esta tabla.

Para crear nuestras migraciones, tenemos el siguiente comando:

php artisan make:migration cursos

Así crearemos una nueva migración, con el nombre «cursos». Este comando creará un archivo php con toda la estructura de una migración, incluyendo los métodos up y down (por ahora vacíos) para nuestra migración. En ella podemos crear una tabla o modificar alguna tabla existente.

En el método up, llamamos a la clase Schema, con el método create, que recibe dos parámetros, el nombre de la tabla y una función anónima, que a su vez recibirá un parámetro que es un objeto de tipo Blueprint, instanciado con la variable $table:

public function up()
    {
        Schema::create('cursos', function(Blueprint $table){
            //métodos
        })
    }

Ahora tenemos que llamar a varios de sus métodos, para crear los campos de la tabla. Aquí llamaremos al método id() y al método timestamps() (para crear las tablas created_at y update_at):

    public function up()
    {
        Schema::create('cursos', function(Blueprint $table){
            $table->id();
            $table->timestamps();
        })
    }

Creamos dos columnas más, una para el nombre del curso y otra para la descripción. El campo del nombre puede ser del tipo varchar, así que usamos el método string(), para un campo de máximo 255 caracteres. Necesitamos que el campo de la descripción almacene más de 255 caracteres, por lo que usamos el método text(). A estos dos métodos le pasamos también el nombre de la tabla como parámetro.

    public function up()
    {
        Schema::create('cursos', function(Blueprint $table){
            $table->id(); 
            $table->string('name'); 
            $table->text('description'); 
            $table->timestamps(); 
        });
    }

No podemos olvidar el método down, donde borraremos la tabla en la migración. Para ello usamos de nuevo la clase Schema con el método dropIfExist:

    public function down()
    {
        Schema::dropIfExists('cursos');
    }

Si ejecutamos de nuevo el comando de artisan php artisan migrate podremos crear la nueva tabla. En consola obtendremos esta respuesta:

Migrating: 2022_07_03_102823_cursos
Migrated:  2022_07_03_102823_cursos (47.42ms)

Ojo con la tabla migrations, pues se ha añadido un registro con el campo batch (lote) con el valor 2, el segundo lote de nuestras migraciones. Para eliminar este registro, tenemos que «ir un paso atrás».

Para revertir la última migración, usamos el siguiente comando, rollback. El registro de migrations al que hemos hecho mención se eliminará, y también se ejecutará el método down de la última migración, es decir, se eliminará la nueva tabla.:

php artisan migrate:rollback

De hecho, si volvemos a ejecutar el comando se eliminarán por completo todas las tablas, pues están creadas en el lote 1. Basta con volver a ejecutar php artisan migrate para crear, en esta ocasión, todas a la vez.

En este punto, nos interesa dejar la base de datos vacía, luego eliminar manualmente el archivo de la migración de cursos, y luego migrar de nuevo, pues vamos a crear la tabla cursos de otra forma:

php artisan make:migration create_cursos_table

Si seguimos esta convención, crearemos una migración como anteriormente, con la tabla cursos… pero en esta ocasión Laravel ya incluye los campos id, created at y updated at, y ya rellena el método down:

    public function up()
    {
        Schema::create('cusos', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('cusos');
    }

Ahora sólo nos quedaría añadir manualmente los campos nombre y descripción para nuestra tabla y volver a hacer la migración.

Explicaremos el siguiente comando:

   php artisan migrate:fresh

Ejecuta el método down de cada una de las migraciones, seguido del método up. Es decir, elimina todas la tablas y las vuelve a crear. No es recomendable cuando el proyecto está en producción, porque al eliminar todas las tablas eliminaría también los registros de las mismas. Por eso, si quisiéramos añadir o quitar campos de una tabla o cambiar propiedades de los campos, tenemos otras posibilidades.

Recursos

Enlace de Youtube: https://www.youtube.com/watch?v=C91FOKq7v-k&list=PLZ2ovOgdI-kWWS9aq8mfUDkJRfYib-SvF&index=9