code

PHPUnit | Ejecución de pruebas

Video de Youtube
URL de Video remoto
Texto

     Configuración para ejecutar pruebas PHPUnit

     Antes de entrar en materia sobre el uso de Test Unitarios de Php, en Drupal 8 o 9, tendremos que familiarizarnos con esta actividad, conociendo sus fundamentos y las configuraciones iniciales.

     Prerrequisitos:

       - Asegúrate de que las dependencias de Composer estén instaladas

          Si haz realizado tu instalación de Drupal, utilizando composer desde el repositorio de Drupal.org, y quieres asegurarte de tener además, todas las dependencias necesarias para los test unitarios, puedes hacerlo escogiendo una de las siguientes opciones:

  1. Instalar Composer y ejecutar composer install (o actualizar tu Drupal 8 ó 9 existente, ejecutando composer update)
     
  2. Utilizar una versión de desarrollo (por ejemplo, 9.0.x-dev) en lugar de la que tienes en tu sitio actual.
     
  3. Instale las dependencias de desarrollo que necesita manualmente en el directorio de vendor de Drupal o en otro lugar.

     Yo voy a realizar una instalación de Drupal 8, nueva, utilizando la plantilla drupal/recommended-project, para eso en mi consola, ejecutaré el siguiente comando:

composer create-project drupal/recommended-project:^8 mi_drupal

     Si al instalar tu Drupal, haz utilizado la plantilla de Composer drupal/recommended-project, las dependencias de desarrollo pueden ser instaladas utilizando en tu proyecto una vez instalado, nos colocaremos en la carpeta root de Drupal y ejecutaremos el siguiente comando:

composer require --dev 'drupal/core-dev:^8.9'

 

    Si has instalado Drupal, utilizando git, entonces, instala composer y a continuación ejecuta el siguiente comando para que se descarguen las dependencias:

composer install

   Recuerda que las dependencias de desarrollo, nunca deben instalarse en una producción o en un servidor de acceso público, por razones de seguridad. Ver el announcement about our dev dependency packaging changes para más información.

   Las pruebas de Javascript tienen dependencias adicionales; consulta Running PHPUnit Javascript tests.

   Cómo configurar PHPUnit

   PHPUnit almacena la configuración en el archivo llamado phpunit.xml, ubicado dentro de la carpeta raíz de tu Drupal. Drupal viene con una versión de muestra de esto, puedes encontrarlo dentro de la carpeta core/phpunit.xml.dist, así podrías copiar este archivo para comenzar con tus pruebas.

 

   El lugar de tu archivo de configuración dependerá de tu flujo de trabajo:

  • El ejecutable PHPUnit espera encontrar el archivo de configuración phpunit.xml, dentro de tu carpeta raíz. Esto se puede anular con la opción -c.
     
  • Si estás utilizando Composer para administrar el núcleo de Drupal, la actualización del núcleo sobrescribirá el núcleo / carpeta y eliminará su archivo phpunit.xml

     Una vez hayamos copiado, desde el core/phpunit.xml.dist y renombrado nuestro archivo phpunit.xml, lo abriremos para añadir los siguientes cambios:

  • Añadiremos el valor a la variable SIMPLETEST_BASE_URL con la url de nuestro sitio.
     
  • Configuraremos la variable SIMPLETEST_DB para que apunte a la URL de la base de datos de nuestro Drupal.
     
  • Si estas colocando phpunit.xml en algún lugar que no sea core, tendrás que cambiar el valor del atributo 'bootstrap' de la etiqueta phpunit para reflejar la nueva ubicación.
     
  • Para pruebas funcionales y del kernel, establezca el BROWSERTEST_OUTPUT_DIRECTORY

     El resultado debería verse así:

<phpunit bootstrap="tests/bootstrap.php" colors="true"
         beStrictAboutTestsThatDoNotTestAnything="true"
         beStrictAboutOutputDuringTests="true"
         beStrictAboutChangesToGlobalState="true"
         printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter">

<php>
  <!-- Set error reporting to E_ALL. -->
  <ini name="error_reporting" value="32767"/>
  <!-- Do not limit the amount of memory tests take to run. -->
  <ini name="memory_limit" value="-1"/>
  <!-- Example SIMPLETEST_BASE_URL value: http://localhost -->
  <env name="SIMPLETEST_BASE_URL" value="http://drupal8.localhost"/>
  <!-- Example SIMPLETEST_DB value: mysql://username:password@localhost/databasename#table_prefix -->
  <env name="SIMPLETEST_DB" value="mysql://drupal8:drupal8@localhost/drupal8"/>
  <!-- Example BROWSERTEST_OUTPUT_DIRECTORY value: /path/to/webroot/sites/simpletest/browser_output -->
  <env name="BROWSERTEST_OUTPUT_DIRECTORY" value="/var/www/sites/simpletest/browser_output"/>
</php> 
</phpunit>

 

   Una vez hecho todo esto, podremos ejecutar cualquier prueba, sin tener que volver a realizar toda esta configuración. 

   Busque y reemplace rápidamente los valores con sed desde la línea de comando. Los valores de ejemplo son para Lando y se supone que estamos ubicados dentro de la carpeta principal de Drupal, al igual que el archivo de configuración phpunit.xml. Ajústalo para igualarlo a tu configuración:

$ cd core
$ cp phpunit.xml.dist phpunit.xml
$ sed -i 's|name="SIMPLETEST_BASE_URL" value=""|name="SIMPLETEST_BASE_URL" value="http://d8dev\.lndo\.site"|g' phpunit.xml
$ sed -i 's|name="SIMPLETEST_DB" value=""|name="SIMPLETEST_DB" value="mysql://drupal8:drupal8@database/drupal8"|g' phpunit.xml
$ sed -i 's|name="BROWSERTEST_OUTPUT_DIRECTORY" value=""|name="BROWSERTEST_OUTPUT_DIRECTORY" value="../sites/simpletest/browser_output"|g' phpunit.xml

     Creando un directorio para la salida HTML

        Las pruebas funcionales pueden generar las páginas HTML que ve el código de ejecución de la prueba. Estos se generan como archivos HTML sin formato. Para proporcionar una ubicación en la que escribirlos, crearemos un directorio llamado sites/simpletest y nos aseguraremos de que el servidor web pueda escribirlo. Está bien hacer que este directorio sea "world-writable", ej.:

mkdir -p sites/simpletest/browser_output
chmod -R 777 sites/simpletest

 

     Locate the PHPUnit binary

       La ubicación relativa del binario PHPUnit depende de cómo instale Drupal.

  • Si hemos instalado Drupal usando un paquete, ejecutaremos composer update, el directorio vendor está dentro de la raíz de Drupal (adyacente a 'core'). Las instrucciones en esta página asumen que esta es su configuración.
  • Si lo hicimos usando composer require drupal/drupal , terminas con un directorio de proveedores fuera de la raíz de Drupal (arriba del 'core'). Es posible que debamos ajustar la ruta a PHPUnit en los comandos que se dan en esta página:
    vendor/bin/phpunit se convertirá en ../vendor/bin/phpunit and ../vendor/bin/phpunit se convertirá en ../../vendor/bin/phpunit.

     Dependiendo de su flujo de trabajo de desarrollo, puede resultarle útil crear un link simbólico a PHPUnit desde / usr / local / bin ( cd /usr/local/bin; ln -s /var/www/html/vendor/bin/phpunit), o parecido, o añadir vendor/bin a tu PATH.

    Comprobando que se verifiquen las aserciones en tiempo de ejecución

        Al ejecutar pruebas de phpunit, es importante asegurarnos de que se verifiquen, las declaraciones de aserción en tiempo de ejecución. Consulte la nota sobre la ejecución de pruebas localmente en el  change notice about runtime assertions , para más información al respecto.

     Ejecutando pruebas

        Todos los comandos de ejemplo en este documento asumen que estamos dentro del directorio raíz  y nuestro archivo ejecutable de configuración phpunit.xml, se encuentra dentro de la carpeta core.

     Al ejecutar \Drupal\Tests\datetime\Unit\Plugin\migrate\field\DateFieldTest, por ejemplo, su comando se vería así:

../vendor/bin/phpunit modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldTest.php

     Su ruta al ejecutable phpunit puede ser diferente a la anterior.

     Ejecute todas las pruebas unitarias de PHPUnit

        Para ejecutar las pruebas unitarias en OS X, Linux u otros sistemas * nix:

../vendor/bin/phpunit --testsuite=unit

     Nota: Todas las pruebas, incluidas las ubicadas en [drupalroot]/modules o [drupalroot]/sites/*/modules, se ejecutan desde la carpeta principal con el comando:

../vendor/bin/phpunit

 

     Debemos tomar en cuenta, que no necesita tener una instalación de Drupal en funcionamiento, para ejecutar pruebas unitarias basadas en PHPUnit de esta manera. Las pruebas de PHPUnit están aisladas de Drupal y no las necesitan para ejecutarse.

     En Windows, el enlace simbólico almacenado en vendor/bin/phpunit no funcionará. Debemos usar la ruta completa al ejecutable PHPUnit:

../vendor/phpunit/phpunit/phpunit

     Problemas de permisos

        Las pruebas funcionales deben invocarse con un usuario del mismo grupo que el usuario del servidor web. Puede configurar Apache (o Nginx) para que se ejecute como su propio usuario del sistema o ejecutar pruebas como un usuario privilegiado.

        Para desarrollar localmente, un enfoque sencillo, pero también menos seguro, es para ejecutar pruebas como su propio usuario del sistema. Para lograrlo, cambie el usuario Apache predeterminado para que se ejecute como su usuario del sistema. Normalmente, necesitaría modificar en Linux `/etc/apache2/envvars` o en Mac el `/etc/apache2/httpd.conf`

Fuente: https://www.drupal.org/node/2116263

Entity API | Introducción en Drupal 8/9

Video de Youtube
URL de Video remoto

Breve repaso sobre Programación Orientada a Objetos (OOP)

     La Programación Orientada a Objetos (OOP, Object Oriented Programming) es una manera de organizar el código que permite a los desarrolladores agrupar tareas similares en clases. Con esta implementación nuestro código se hace más fácil de mantener y evita repeteciones innecesarias (DRYDon't Repeat Yourself).

     Una de las ventajas de OOP es que si modificamos parte de la información en el script, normalmente sólo hace falta cambiarla en un sitio para actualizar el código. Por ejemplo si se ha usado un sistema de bases de datos como MySQL utilizando PDO (PHP Database Objects)  y queremos cambiar a otro, los métodos que utilizaremos para las sentencias serán los mismos.

     Una clase se puede ver como el esquema de una casa y un objeto como la casa ya construida. Esto significa que en la clase se define su estructura, sus medidas y características y las relaciones entre ellas y el objeto es la casa construida con todos los datos y organización definidos en ella. Se pueden construir las casas (objetos) que se quieran con esa estructura (clase), y cada una tendrá sus propias familias y decoración.

     Para definir una clase se utiliza la palabra reservada class, seguida del nombre de clase y dos llaves, entre las cuales se guardará toda la información del esquema. Esta información se guarda en propiedades (así es como se les llama a las variables dentro de las clases), métodos (funciones dentro de las clases) y constantes.

     El nombre de la clase puede ser cualquier etiqueta válida siempre que no sea una palabra reservada de PHP. Un nombre válido comienza con una letra o guión bajo, seguido de una cantidad arbitraria de letras, números o guiones bajos.

class NombreClase {
    // Declaración de una propiedad
    public $variable = 'Un valor cualquiera';
    // Declaración de un método
    public function mostrarVariable(){
        echo $this->variable;
    }
}

$this es una pseudo-variable que está disponible cuando una clase se instancia. La clase instanciada es un objeto, y $this hace referencia a ese objeto. Vamos a ver un ejemplo en el que se ve más claro a qué hace referencia $this:

class ClaseA {
    function funcionA()
    {
        if(isset($this)){
            echo '$this está definido, su clase es: ';
            // La función get_class devuelve el nombre de la clase de un objeto:
            echo get_class($this) . "<br>";
        } else {
            echo '$this no está definido <br>';
        }
    }
}
class ClaseB {
    function funcionB() {
        // Se llama estáticamente a la función A, pero ésta no es estática
        // Si E_STRICT está activado generará un aviso
        ClaseA::funcionA();
    }
} 

     Para crear una instancia de una clase, se utiliza la palabra new. Un objeto será creado siempre, a no ser que el objeto tenga un constructor definido y lance una excepción como error. Las clases han de definirse antes de instanciarse.

    Introducción a Entity API en Drupal 8/9

         Entity System es la API para la manipulación de entidades (CRUD: crear, leer, actualizar, eliminar). La validación de entidades tiene su propia API (que podría validar una entidad guardada a través de REST, en lugar de un formulario, por ejemplo).

     El sistema de entidades Drupal 8

          En Drupal las entidades son clases con sus respectivos métodos

 

 

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Ambos tipos están definidos y documentados en interfaces.

     Entidad de configuración y entidad de contenido

     Los tipos de entidad en el núcleo vienen en dos variantes.

     Entidad de configuración (Configuration Entity): Utilizado por el sistema de configuración. Admite traducciones y puede proporcionar valores predeterminados personalizados para las instalaciones. Las entidades de configuración se almacenan dentro de la tabla de la base de datos de configuración común como filas.

     Entidad de contenido (Content Entity): Consiste en campos configurables y base, y puede tener revisiones y traducciones de soporte. Las entidades de contenido se almacenan en una tabla de base de datos personalizada como filas. El nombre de la tabla es el mismo que el de la entidad de contenido "id", y las columnas se definen mediante el método "baseFieldDefinitions" de la entidad.

     Paquetes (Bundles)

        Los paquetes son diferentes variantes de un tipo de entidad. Por ejemplo, con el tipo de entidad de nodo, los paquetes son los diferentes tipos de nodo, como 'artículo' y 'página'.

        Normalmente, un paquete está representado por una entidad de configuración, aunque existen otros modelos en los módulos contrib. Entonces, en el ejemplo de nodo, el tipo de nodo 'artículo' es en sí mismo una entidad de configuración. La configuración almacena las diferencias entre los tipos de entidades de contenido, como la configuración y los campos. Al crear un nuevo tipo de entidad que tiene entidades de paquete, creará tanto una Entidad de contenido que administrará los detalles y operaciones del contenido, como una Entidad de configuración que manejará las diferencias entre los tipos de entidad de contenido.

     Anotaciones (Annotations):

          Al crear un nuevo tipo de entidad, deberá utilizar el sistema de anotaciones integrado en el núcleo. Las anotaciones parecen comentarios de docblock encima de la clase, pero el núcleo de Drupal las analiza y almacena en caché. En muchos sentidos, las anotaciones reemplazan algunos de los ganchos de estilo más antiguos utilizados en Drupal 7.

     Analizador de anotaciones (Annotation parser):

        Las anotaciones se leen y analizan en tiempo de ejecución mediante un motor de anotaciones. Drupal 8 usa el analizador de anotaciones de Doctrine, que lo convierte en un objeto que PHP puede usar.

       Sintaxis: la sintaxis de la anotación está rodeada por @ClassName (), se compone predominantemente de pares clave / valor y puede contener matrices que usan llaves. Las claves de nivel superior no deben estar entre comillas, mientras que las claves de matriz deben hacerlo. Cada par clave / valor debe estar en su propia línea, y esa línea debe terminar con una coma. Ciertas funciones se pueden ejecutar en valores, en particular la función @Translation ().

      Ejemplo de sintaxis de anotación que no funciona:

/**
 * @ContentEntityType(
 *   id = "my_entity_type_id",
 *   label = @Translation("My entity type label"),
 *   example_pair = "this_examples_value",
 *   example_array = {
 *     "array_key" = "array_value",
 *     "some_other_key" = "some_other_value",
 *   },
 * )
 */

Anotaciones comunes de nivel superior

 

 

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Manipuladores o (Handlers)

     Los controladores se definen en la anotación de la entidad como una matriz. Apoyan a la entidad al mapear ciertas partes de su ejecución a otras clases de PHP. Esas clases "manejarán" las partes asignadas de la ejecución de la entidad.

     Almacenamiento (Storage): maneja la carga, el guardado y la eliminación de la entidad. De forma predeterminada, las entidades de contenido usan Drupal \ Core \ Entity \ Sql \ SqlContentEntityStorage mientras que las entidades de configuración usan Drupal \ Core \ Config \ Entity \ ConfigEntityStorage. Puede definir un controlador de almacenamiento para ampliar los métodos de almacenamiento predeterminados de su entidad. Es posible que desee hacer esto para proporcionar métodos adicionales para recopilar los ID de revisión de la entidad o determinar el número de traducciones que tiene una entidad.

     Ejemplo: "storage" = "Drupal\node\NodeStorage",

     Formulario (Form): en la anotación de controladores de cualquier entidad, hay varios controladores de formularios que asignan los formularios de agregar, editar y eliminar de la entidad a otras clases de PHP.

     Ejemplo:

"form" = {
  "add" = "Drupal\block\BlockForm",
  "edit" = "Drupal\block\BlockForm",
  "delete" = "Drupal\block\Form\BlockDeleteForm",
}

     Alternativamente, puede definir un formulario "predeterminado" para manejar tanto el formulario de "agregar" como el de "editar" en lugar de definirlos por separado. Vale la pena señalar que el formulario "eliminar" casi siempre será manejado por una clase separada de los otros formularios. Esto se debe a que el formulario de eliminación es generalmente un "formulario de confirmación" que simplemente pregunta si el usuario está seguro de que desea eliminar la entidad.

     Creador de vistas (View builder): este controlador proporciona una clase que manejará la salida de la entidad cuando la vea el usuario final. Por ejemplo, al visitar un nodo en un sitio de Drupal 8, la salida de la entidad es manejada por la clase NodeViewBuilder.

     Ejemplo: "view_builder" = "Drupal\node\NodeViewBuilder",

     Generador de listas (List builder ): la clase del generador de listas manejará la lista de entidades con fines administrativos. Esta clase definirá el contenido de los encabezados, filas y operaciones cuando visite la página de administración de entidades para la entidad. Por ejemplo, al visitar el URI / admin / content de su sitio Drupal, el contenido de la tabla lo proporciona la clase de constructor de listas de la entidad Node.

   Ejemplo: "list_builder" = "Drupal\node\NodeListBuilder",

   Proveedor de ruta (Route provider): un controlador opcional que, si se implementa, genera rutas para la administración de su entidad. La implementación de este controlador puede reemplazar la necesidad de rutas de entidad definidas en el archivo routing.yml de su módulo. Tenga en cuenta que route_provider funciona junto con los enlaces definidos en su entidad (consulte el ejemplo a continuación en la sección Enlaces). La anotación route_provider es una matriz.
     Ejemplo:

"route_provider" = {
  "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
}

     Acceso (Access): el controlador de acceso se puede usar para verificar dinámicamente los permisos de su entidad. Es una asignación a una clase que implementa EntityAccessControlHandlerInterface. Core proporciona una implementación de esta interfaz como EntityAccessControlHandler, pero para un control confiable sobre su entidad, querrá extender esa clase con la suya propia.

     Datos de vistas (Views data): el controlador views_data permite que una entidad amplíe el módulo Vistas con datos personalizados proporcionados por su entidad. Esto puede ser para agregar baseFieldDefinitions de su entidad como campos de Vistas, unir tablas en relaciones de entidad u otras alteraciones de datos relacionadas con Vistas.

     Ejemplo: "views_data" = "Drupal\node\NodeViewsData",

     Esquema de almacenamiento (Storage schema): el controlador storage_schema se puede implementar para modificar aún más la configuración de almacenamiento de la base de datos de la entidad. Por ejemplo, agregar índices de tabla adicionales.

     Ejemplo: "storage_schema" = "Drupal\node\NodeStorageSchema",

     Traducción (Translation): el controlador de traducción se puede utilizar para modificar la forma en que los formularios de su entidad interactúan con las traducciones.

     Ejemplo: "translation" = "Drupal\node\NodeTranslationHandler",

  Ejemplo completo de Manipuladores (handlers):

     El núcleo de Drupal proporciona controladores que puede usar listos para usar, pero en muchos casos querrá extender estas clases con las suyas propias para un mayor control y personalización de su entidad. Este ejemplo muestra una anotación de controladores más completa, utilizando las clases principales que puede ampliar.

handlers = {
  "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
  "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
  "access" = "Drupal\Core\Entity\EntityAccessControlHandler",
  "views_data" = "Drupal\views\EntityViewsData",
  "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
  "storage_schema" = "Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema",
  "translation" = "Drupal\content_translation\ContentTranslationHandler",
  "form" = {
    "default" = "Drupal\Core\Entity\ContentEntityForm",
    "add" = "Drupal\Core\Entity\ContentEntityForm",
    "edit" = "Drupal\Core\Entity\ContentEntityForm",
    "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
  },
  "route_provider" = {
    "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
  },
},

     Enlaces:

         Los enlaces se definen en la anotación de entidad con la sintaxis de matriz. Los enlaces tienen un conjunto específico de claves cuyo valor son URI donde se puede administrar el tipo de entidad o entidades individuales de ese tipo. Tanto las entidades de contenido como las de configuración pueden tener estos enlaces definidos.

     Ejemplo:

id = "node",
handlers = {
  "route_provider" = {
    "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider"
  }
},
links = {
  "canonical" = "/node/{node}",
  "add-page" = "/node/add",
  "add-form" = "/node/add/{node_type}",
  "edit-form" = "/node/{node}/edit",
  "delete-form" = "/node/{node}/delete",
  "collection" = "/admin/content",
},

     La creación de estos enlaces no crea automáticamente las rutas para esos URI. Para que estos enlaces sean accesibles, nuestro módulo deberá implementar su propio archivo routing.yml o usar un controlador "route_provider" en la anotación de la entidad.

     Enlaces y proveedor de rutas (Links & Route Provider):

     Los enlaces anteriores que trabajan junto con un "route_provider" harán que las siguientes rutas nombradas estén disponibles para Drupal.

 

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Uso de enlaces:

          Se puede acceder a estos enlaces con el método toUrl () de una entidad:

$view_url_object = $entity->toUrl();  // Default is 'canonical'
$edit_url_string = $entity->toUrl('edit-form')->toString();

Fuente: Página oficial de Drupal

Tipos de entidad en Drupal 9

Video de Youtube
URL de Video remoto
Texto

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

     Siguiendo con el aprendizaje sobre la API de Drupal, hoy nos toca hablar sobre los Tipos de entidades.

     En Drupal 7, las entidades eran objetos stdClass genéricos.

     A partir de Drupal 8, las entidades ahora son objetos de tipo específico, y cada tipo de entidad define una clase que se utilizará para las instancias de la entidad dada.

Tipos de entidad Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Requerimientos:

          Las clases de entidad (Entity classes), deben colocarse en el subespacio de nombres de entidad del módulo que proporciona el tipo de entidad, p. Ej. \ Drupal \ [nombre_módulo] \ Entidad. Esto significa que los archivos PHP de clase de entidad se pueden encontrar en el directorio src / Entity de un módulo.

Tipos de entidad Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

          El docblock de la clase debe contener una anotación EntityType que defina los metadatos para las entidades de ese tipo. Estos incluyen cosas como la etiqueta del tipo de entidad, controladores, tablas, etc. Para obtener una lista documentada de todas las propiedades de metadatos disponibles, consulte la clase \Drupal\Core\Entity\Annotation\EntityType Haz clic aquí.

Tipos de entidad Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Nomenclatura del Tipo de entidad:

          Los nombres de tipo de entidad deben tener el prefijo del nombre del módulo si el tipo de entidad y el nombre del módulo no son los mismos. No es necesario prefijar la clase del tipo de entidad en sí, ya que vive dentro del espacio de nombres del módulo de definición, siempre que sea lo suficientemente significativo por sí mismo. Por ejemplo, el tipo de entidad para los términos de taxonomía se denomina taxonomy_term y el nombre de la clase es Drupal \ taxonomy \ Entity \ Term.

     Interfaces:

          Drupal 8 recomienda que escriba funciones y métodos con interfaces en lugar de clases. Por ejemplo, para las entidades genéricas utilizaremos los métodos y propiedades de EntityInterface como en hook_entity_insert(EntityInterface $entity) y para trabajar con nodos específicos, utilizaremos los métodos y propiedades de NodeInterface como en hook_node_insert(NodeInterface $node).

Tipos de entidad Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Tipos de entidad Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

         Los campos / propiedades de las entidades suelen ser muy breves, centrados en el almacenamiento y no muy autodescriptivos. Además, las entidades de contenido no usan propiedades definidas para sus campos (incluidos los campos base como el título del nodo) en absoluto.

          Por lo tanto, el enfoque recomendado es proporcionar una interfaz con nombres de métodos documentados. Algunas reglas a seguir al hacerlo:

  • Los métodos suelen tener un prefijo get / set / is o similar: getSomething (), setSomething ($ value), isSomething ().
     
  • Solo agregue métodos para cosas que se supone que debe cambiar otro código. No se supone que se cambie la fecha de último cambio de los nodos ($node->changed), por lo que hay $node->getChangedTime(), pero no el método $node->setChangedTime().
     
  • Utilice nombres de métodos autodescriptivos, por ejemplo, el método para acceder a $node->status se llama $node->isPublished().

     Capacidad de rastreo o Visibilidad (Discoverability):

          Para averiguar qué tipos de entidad proporciona un módulo, consulte las clases en el subespacio de nombres de Entidad de ese módulo que tienen una anotación @EntityType, que también contiene el nombre en la clave de anotación de id.

          Al intentar encontrar dónde se define un tipo de entidad dado, lo primero que debe buscar es el prefijo del tipo de entidad. Si un módulo no sigue esa convención de nomenclatura, se puede encontrar buscando id = "$type". Si se conoce la clase o interfaz en lugar del tipo de entidad, entonces el namespace indica de dónde proviene.

Fuente: https://www.drupal.org/docs/drupal-apis/entity-api/entity-types

Drupal Behaviors | Javascript y librerías Jquery en Drupal 9

Video de Youtube
URL de Video remoto
Texto

    Recientemente, en un proyecto que estoy desarrollando en Drupal 9, tuve que buscar la manera de integrar parte del código, con llamadas realizadas en JavaScript hacia un servidor de Sharepoint, sin la necesidad de implementar webservice, la idea era reaprovechar un código que ya funcionaba correctamente, sin guardar nada en la base de datos de Drupal y como requisito adicional, debía utilizar una librería de Jquery diferente a la que trae el núcleo de Drupal 9, para ser más específico, se trataba de la versión "jquery-3.5.1.min.js".

     El objetivo de este desarrollo era realizar varias llamadas al servidor externo, aprovechando la modificación de una línea del código, para obtener el resultado que íbamos a mostrar dentro de la página, o sea, que en lugar de cargar la librería en el archivo "MITEMA.libraries.yml", haciendo una llamada al "global-styling", para que estuviera accesible desde cualquier punto de la web, opté por llamar directamente en las plantillas específicas al archivo "codigo_personalizado.js", sin tener que cargarlo innecesariamente.

     Por esta razón he querido compartir los pasos que deberás seguir, primero para añadir en tu proyecto Drupal 9, una librería de jquery diferente a la que tienes en el núcleo de Drupal, y luego, mostrarte cómo realizar las llamadas a tus archivos js, desde la o las plantillas ".twig" que tengas en tu proyecto.

     Si quieres saber más sobre el uso de librerías de javascript y Css, puedes visitar la Página oficial de Drupal, donde también te lo cuenta con varios ejemplos, para que puedas elegir el que más te convenga.

     PASOS PARA INSTALAR UNA LÍBRERÍA JQUERY EXTERNA EN TU TEMA PERSONALIZADO:

     Lo primero que deberías saber es Cómo crear un tema personalizado con Bootstrap 3 o Cómo crear un tema personalizado con Bootstrap Barrio, así podrás familiarizarte con los archivos que componen un tema y entenderás más fácilmente la forma de aplicar cambios, como la creación de librerías.

     PASO 1 AÑADIR LA LIBRERÍA EN EL ARCHIVO LIBRARIES DEL SUBTEMA:

     Partiendo de que ya tienes un subtema instalado en tu proyecto, si quieres añadir una librería externa, bastará con que copies el código que te muestro a continuación, en la parte inferior del archivo donde definimos las librerías del tema, ej.: "MITEMA.libraries.yml", recordando siempre el uso de los espacios, porque de lo contrario los archivos .yml no funcionarán.

jquery-custom:
  remote: https://github.com/jquery/jquery
  version: "3.5.1"
  license:
    name: MIT
    url: https://github.com/jquery/jquery/blob/3.5.1/LICENSE.txt
    gpl-compatible: true
  js:
    js/jquery-3.5.1.min.js: { minified: true, weight: -20 }

 

     Con este código le estamos asignado el nombre "jquery-custom", a nuestra libería y de esta forma podremos llamarla desde cualquier plantilla, mediante el código siguiente:

     PASO 2 LLAMAR A LA LIBRERÍA DESDE LA PLANTILLA:

     Dentro de la plantilla que quieras llamar a la librería o archivos js que quieras, tendrás que colocar el siguiente código, sustituyendo el nombre del tema, por el que haz utilizado para tu proyecto.

{# In a Twig template we attach the library. #}
{{ attach_library('MITEMA/jquery-custom') }}

 

     CÓMO CREAR ARCHIVOS JAVASCRIPT Y FUNCIONES DENTRO DE DRUPAL 9: 

     Lo último que te quiero contar, es cómo puedes añadir tus propias funciones de javascript, sin tener conflictos de código. Ahora que ya sabes la forma de agregar una librería de Jquery, diferente a la versión de tu proyecto, lo que nos falta es cómo intengrar funciones o código dentro de mi tema para que se ejecute correctamente.

     Una vez creado el archivo con el nombre ej:  "codigo_pesonalizado.js", y colocado en la carpeta correspondiente dentro de tu tema, ya sólo nos queda comenzar a escribir el resto de nuestro desarrollo.

(function ($, Drupal) {
  'use strict';

  Drupal.behaviors.micodigo = {
    attach : function(context, settings) {

       //PUEDES PONER AQUÍ TU CÓDIGO

    }
  };

})(jQuery, Drupal); 

     A partir de ahora ya podrás añadir funcionalidades de JavaScript o Jquery, dentro de cualquier tipo de plantilla en Drupal 9, ofreciendo mayores alternativas y soluciones para todos tus proyectos.

 

    Si quieres conocer un poco más visitando la página oficial de Drupal, HAZ CLIC AQUÍ

Entity Api | Trabajando con entidades en Drupal 9

Video de Youtube
URL de Video remoto
Texto

Al trabajar con entidades, en nuestros módulos personalizados, podremos realizar todo tipo de comprobaciones, para asegurarnos de obtener los cambios o respuestas que esperamos según su tipo o relación.

 

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

     Esta vez nos toca abordar el tema de Cómo trabajar con la API de entidades en Drupal 9 o (Entity API). Como mencionamos en el capítulo anterior sobre Tipos de entidad en Drupal 9, a partir de Drupal 8 se recomienda que escribamos funciones y métodos con interfaces en lugar de clases.

     ¿Que son las Interfaces?

     Según la documentación oficial de PHP, en la programación orientada a objetos (OOP), las interfaces de objetos permiten crear código con el cual especificar qué métodos deben ser implementados por una clase, sin tener que definir cómo estos métodos son manipulados.

     Las interfaces se definen de la misma manera que una clase, aunque reemplazando la palabra reservada class por la palabra reservada interface y sin que ninguno de sus métodos tenga su contenido definido.

     Todos los métodos declarados en una interfaz deben ser públicos, ya que ésta es la naturaleza de una interfaz.

     Para implementar una interfaz, se utiliza el operador implements. Todos los métodos en una interfaz deben ser implementados dentro de la clase; el no cumplir con esta regla resultará en un error fatal. Las clases pueden implementar más de una interfaz si se deseara, separándolas cada una por una coma.

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     En Drupal, para las entidades genéricas utilizaremos los métodos y propiedades de EntityInterface como en hook_entity_insert(EntityInterface $entity) y para trabajar con nodos específicos, utilizaremos los métodos y propiedades de NodeInterface como en hook_node_insert(NodeInterface $node).

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Entidades Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Los métodos que cubren la mayoría de nuestras necesidades, cuando trabajamos con entidades genéricas son:

  • Entity::create()
     
  • Entity::load()
     
  • Entity::save()
     
  • Entity::id()
     
  • Entity::bundle()
     
  • Entity::isNew()
     
  • Entity::label()

    Comprobación de entidades (Check):

         Al trabajar con entidades, en nuestros módulos personalizados, podremos realizar todo tipo de comprobaciones, para asegurarnos de obtener los cambios o respuestas que esperamos según su tipo o relación.

         A continuación los ejemplos más frecuentes, en las operaciones de comprobación con entidades:

// Asegúrese de que un objeto sea una entidad.
if ($entity instanceof \Drupal\Core\Entity\EntityInterface) {
}

// Asegúrate de que sea una entidad de contenido.
if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface) {
}
// o también:
if ($entity->getEntityType()->getGroup() == 'content') {
}

// Obtener el tipo de entidad o el ID del tipo de entidad.
$entity->getEntityType();
$entity->getEntityTypeId();

// Asegúrate de que sea un nodo.
if ($entity instanceof \Drupal\node\NodeInterface) {
}

// El uso de entityType () funciona mejor cuando el tipo de entidad necesario es dinámico.
$needed_type = 'node';
if ($entity->getEntityTypeId() == $needed_type) {
}

     Obtener información de una entidad / métodos de entidad:

     Existe varios métodos genéricos disponibles para obtener información de una entidad, como el ID, el paquete, el ID de revisión, etc. Consulte la documentación de EntityInterface para obtener más detalles.

// Obtiene el ID de la entidad.
$entity->id();

// Obtiene el paquete.
$entity->bundle();

// Comprueba si la entidad es nueva.
$entity->isNew();

// Obtén la etiqueta de una entidad. Reemplazo de entity_label().
$entity->label();

// Obtener el objeto URL de una entidad.
$entity->toUrl();

// Obtener ruta interna, alias de ruta si existe, para una entidad.
$entity->toUrl()->toString();

// Cree un duplicado que se pueda guardar como una nueva entidad.
$duplicate = $entity->createDuplicate();

     Creación de entidades:

// Es recomendable que utilicemos el Entity Manager para crear entidades.
$node = \Drupal::entityTypeManager()->getStorage('node')->create(['type' => 'article', 'title' => 'Another node']);


// Podemos usar el método estático create () si conocemos la clase de entidad.
$node = Node::create([
  'type' => 'article',
  'title' => 'The node title',
]);

     Los valores predeterminados de configuración de la anotación de tipo de campo solo se agregan para las claves de nivel superior que faltan; no se realiza una fusión profunda.

     Evita usar el método estático Entity::create() en código orientado a objetos. En su lugar, use la inyección de dependencia para inyectar el administrador de tipos de entidad y crear la entidad con $this->entityTypeManager->getStorage($entity_type)->create(). Esto asegura que el código esté desacoplado correctamente y se pueda probar unitario.

     Si quieres saber más sobre la Inyección de Dependencias, te lo cuento en este artículo: Cómo crear un servicio personalizado en Drupal 9

     Para lograr la visibilidad dentro de un IDE, también puede asignar la interfaz de almacenamiento de la entidad a una propiedad. Por ejemplo, $this->nodeStorage = $this->entityTypeManager->getStorage('node'); Para crear una entidad, puede usar $this->nodeStorage->create().

     Carga de entidades (Load):

// Usando el controlador de almacenamiento (recomendado).
$entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load(1);

// Usa el método estático
$node = Node::load(1);

// Carga varias entidades, también existe como entity_load_multiple().
$entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple([1, 2, 3]);

// Cargar entidades por sus valores de propiedad.
$entities = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => 'article']);

     Para actualizar una entidad, cárguela y luego guárdela con sus cambios.

         Evite usar el método estático Entity::load() en código orientado a objetos. En su lugar, use la inyección de dependencia para inyectar el administrador de tipos de entidad y cargar la entidad con $this->entityTypeManager->getStorage($entity_type)->load($entity_id). Esto asegura que el código esté desacoplado correctamente y se pueda probar unitario.

          Si quieres saber más sobre la Inyección de Dependencias, te lo cuento en este artículo: Cómo crear un servicio personalizado en Drupal 9

     Guardar los cambios en la entidad (Save):

// Para guardar los cambios en una entidad.
$entity->save();

     Eso funciona tanto para entidades nuevas como existentes, la propia entidad realiza un seguimiento de si es nueva o no. De forma predeterminada, para las entidades de contenido, eso depende de si tiene un ID o no. Para guardar una entidad que tiene un ID como una entidad nueva (por ejemplo, al importar algo), se puede aplicar la marca isNew.

// Lo siguiente intentará insertar un nuevo nodo con el ID 5, esto fallará si ese nodo ya existe.
$node->nid->value = 5;
$node->enforceIsNew(TRUE);
$node->save();

     Eliminar entidades (Delete):

// Eliminar una sola entidad.
$entity = \Drupal::entityTypeManager()->getStorage('node')->load(1);
$entity->delete();

// Elimina varias entidades a la vez.
\Drupal::entityTypeManager()->getStorage($entity_type)->delete([$id1 => $entity1, $id2 => $entity2]);

    Consultando entidades (Query):

$entity = \Drupal::entityTypeManager()->getStorage('node');
$query = $entity->getQuery();
    
$ids = $query->condition('status', 1)
 ->condition('type', 'article')#type = ID de paquete (nombre de la máquina)
 #->sort('created', 'ASC') #ordenada
 #->pager(15) #límite de 15 artículos
 ->execute();

// Cargar carga de artículo único o múltiple($id)
$articles = $entity->loadMultiple($ids);

     Control de acceso a entidades (Access control):

     El método access() se puede utilizar para comprobar quién puede hacer qué con una entidad. El método admite diferentes operaciones, las operaciones estándar son ver, actualizar, eliminar y crear, crear es algo especial, ver más abajo.

     Las comprobaciones de acceso se envían al controlador de acceso.

// Verifique el acceso a la vista de una entidad.
// De forma predeterminada, se verifica el acceso del usuario que ha iniciado sesión actualmente..
if ($entity->access('view')) {

}

// Compruebe si un usuario determinado puede eliminar una entidad.
if ($entity->access('delete', $account)) {

}

     Al marcar el acceso de creación, generalmente no hay una entidad todavía. Crear uno solo para comprobar si alguien podría crearlo es una operación costosa. Por lo tanto, la creación de acceso para aquellos debe verificarse directamente en el controlador de acceso.

\Drupal::entityTypeManager()->getAccessControlHandler('node')->createAccess('article');

     Si ya existe una entidad, $entity->access('create') también funciona, que solo reenvía al método  createAccess(), de la misma manera que otras operaciones reenvían al método access () en el controlador de acceso.

     NOTA: Algunas guías en línea usan \Drupal::entityManager(), pero está obsoleto en 8.x y se eliminará en 9.x. Entonces puede usar \Drupal::entityTypeManager() en lugar de \Drupal::entityManager().

Fuente: https://www.drupal.org/docs/drupal-apis/entity-api/working-with-the-entity-api#s-delete

Bloque personalizado | Creación programáticamente en Drupal 9

Video de Youtube
URL de Video remoto
Texto

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

QUÉ ES UN BLOQUE Y CÓMO FUNCIONAN

     Hoy te quiero hablar sobre los bloques en Drupal, que no son más que regiones, en las que puedes incluir prácticamente cualquier tipo de contenido, imágenes, texto simple o añadir campos editables por el usuario y que luego podrán mostrarse en cualquier área y página de tu web, además de ofrecerte la opción para controlar quiénes podrán ver su contenido, configurando los permisos de usuario.

     Por defecto, una instalación de Drupal viene dividida en varias zonas con "Bloques" en su interior, el nombre y la cantidad de dichos bloques podrían variar, en función del "Theme" o tema que tengas instalado en tu proyecto. 

     Para que entiendas el concepto de Bloques, imagina que tu web es como una casa, con sus respectivas habitaciones, y que el mobiliario o la decoración que puedes añadir, quitar o modificar en cualquier de ellas es el bloque.

     Para administrar los bloques, tendrás que ir a la url "/admin/structure/block", allí encontrarás el listado de todos los bloques activados con las diferentes zonas de tu proyecto.

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

     Desde esta pantalla, tendrás la oportunidad de añadir cualquier otro bloque en la zona que desees, haciendo clic en el botón "Colocar Bloque" y seleccionando posteriormente cualquiera de los que se mostrará en el listado que te aparecerá a continuación. 

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

     Además de añadir, también podrás desactivar, recolocar o remover menús, vistas personalizadas del tipo bloque, información del sitio, etc. o si lo necesitaras, utilizar instancias del mismo bloque en zonas diferentes de tu web.

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

BIBLIOTECA DE BLOQUES PERSONALIZADOS

     Otra de las opciones disponibles al trabajar con bloques, es la Biblioteca de bloques personalizados, donde podrás crear un modelo de bloque, para reutilizarlo como base siempre que te haga falta. 

     Un ejemplo práctico, sería que tuvieras en tu web un tipo de bloque personalizado al que llamaras, por ejemplo "Banner Publicitario", con la opción de añadir, editar o eliminar dentro de él, diferentes imágenes anunciando ofertas o descuentos, en varias partes de la web, sin tener que construir cada vez un bloque nuevo.

     Los bloques personalizados se guardan en la pestaña "Biblioteca de bloques personalizados", y desde este apartado puedes modificar el modelo principal, por ejemplo añadiendo un botón que se llame "precio especial", y que automáticamente estará disponible para todo el resto de bloques que usan este modelo como base.

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

CÓMO CREAR UN BLOQUE PROGRAMÁTICAMENTE EN DRUPAL 9

PRERREQUISITOS:

     PASO 1 CREAR MÓDULO PERSONALIZADO:

          Lo primero que debemos hacer para crear un bloque, usando nuestro propio módulo, es añadir una carpeta con el nombre del módulo, dentro de la carpeta "modules/custom", con el objetivo de tener separados los módulos contribuidos de Drupal, que son los que descargamos desde la Página Oficial, y que si utilizamos Composer, se guardarán automáticamente en la ubicación "modules/contrib"

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

          Una vez hayamos creado la carpeta con el nombre de nuestro módulo, lo siguiente será añadir el archivo que utiliza Drupal para identificar cualquier módulo, el nombre de este archivo deberá coincidir con el nombre de nuestra carpeta y terminar con la extensión ".info.yml", en nuestro caso, nuestro archivo se llamará drupal_block.info.yml.

          Puedes crear el archivo y copiar el siguiente código dentro para continuar con el ejercicio.

name: Drupal Block
description: 'Create custom block'
package: drupaladicto

type: module
core_version_requirement: ^8.8.0 || ^9.0

          Puedes comprobar que todo funciona correctamente, si activas el módulo en la url "/admin/modules/". Aunque no hará más nada que confirmarte con un mensaje en la parte superior de la pantalla, indicándote que se ha activado correctamente.

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

     Ahora desinstala el módulo nuevamente, antes de continuar con las siguientes modificaciones para evitar errores.

     PASO 2 CREACIÓN DEL BLOQUE PERSONALIZADO:

          Para lograr que nuestro módulo personalizado genere un Bloque, una vez lo hayamos terminado, tendremos que crear varios archivos. 

          Crearemos tres carpetas: "src""Plugin" y "Block", estas deberán estar una dentro de la otra, respetando los estándares de estructura para que Drupal reconozca su contenido y funcione correctamente.

Custom Module Drupal  | www.drupaladicto.com - Consultor y formador especializado en Drupal y Symfony

          A continuación, crearemos el archivo php con la clase responsable de construir nuestro módulo, es recomendable que el nombre de tu clase corresponda con el de tu módulo, utilizando Mayúsculas en el caso de que lo formen varias palabras. Por lo tanto, para nuestro ejemplo, la clase se llamará DrupalBlock.php y tendrá dentro el siguiente contenido:

<?php

namespace  Drupal\drupal_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * @Block(
 *   id = "Drupal Block",
 *   admin_label = @translation("Drupal Block"),
 *   category = @translation("Drupal Block"),
 * )
 */


class DrupalBlock extends BlockBase{

  /**
   * {@inheritdoc }
   */

  public function build(){
    return [
      '#markup' => $this->getFrases(),
      '#cache' => [
        'max-age' => 0,
      ]
    ];
  }
   private function getFrases(){
    $frase = [
      'Hola, que tal',
      'Otras vez por aquí?',
      'Nos vemos pronto!!!'
    ];
    return $frase[array_rand($frase)];
   }
}

     Explicación: 

          En la primera parte del código, tenemos el namespace, que permite a Drupal encontrar la ubicación de nuestro módulo para leer su contenido. A continuación, invocamos a la clase BlockBase, porque será necesaria para genera nuestro bloque, ya que heredaremos de ésta algunas funcionalidades, utilizando la palabra extends, que utilizaremos dentro de nuestra clase.

<?php

namespace  Drupal\drupal_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;

 

     La siguiente fracción del código, corresponde a lo que se conoce como Annotations, puedes visitar la Página oficial de Drupal para saber más sobre ellas. En resumen, aunque su formato es similar al de los comentarios de Php, su función va mucho más allás, permitiendo pasar varios parámetros necesarios para que Drupal interprete, en este caso, que se trata de un Bloque personalizado y muestre varias informaciones relacionadas, que podremos ver una vez esté activado el módulo, dentro de la pantalla de Administración de Bloques.

/**
 * @Block(
 *   id = "Drupal Block",
 *   admin_label = @translation("Drupal Block"),
 *   category = @translation("Drupal Block"),
 * )
 */

     La última parte que nos falta, es el contenido en sí, de nuestra clase. En esencia, lo que estamos haciendo es, construir el bloque, utilizando el método build(){ }, que nos devolverá un arreglo o array, con un elemento html que envolverá una frase, además al refrescar el navegador, dicha frase también cambiará aleatoriamente, ya que hemos utilizado el array_rand() de php para conseguirlo.

class DrupalBlock extends BlockBase{

  /**
   * {@inheritdoc }
   */

  public function build(){
    return [
      '#markup' => $this->getFrases(),
      '#cache' => [
        'max-age' => 0,
      ]
    ];
  }
   private function getFrases(){
    $frase = [
      'Hola, que tal',
      'Otras vez por aquí?',
      'Nos vemos pronto!!!'
    ];
    return $frase[array_rand($frase)];
   }
}

Si quieres más información sobre los bloques personalizados, puedes visitar la página oficial de Drupal

Drush , introducción y comandos más útiles

Video de Youtube
URL de Video remoto
Texto

     Para todos los que trabajamos, en el desarrollo de páginas web utilizando Drupal, es muy importante que nos mantengamos informados, sobre las últimas actualizaciones, tanto a nivel de las funcionalidades o parches de seguridad, del propio CMS, como de las herramientas relacionadas con éste, por ejemplo, el gestor de paquetes Composer, recomendado para todos los proyectos, a partir de Drupal 8 y que hace poco, lanzó una nueva versión ( Cómo instalar Composer 2 en Ubuntu 20.04 ) o superior o la consola Drush.

     Con el propósito de facilitar tus tareas de desarrollo, hoy quiero hablarte sobre, La interfaz de línea de comandos (en inglés, command-line interfaceCLI), que se utiliza en Drupal, conocida como Drush, para que puedas sacarle el mayor provecho posible y obtener mejores resultados.

   INSTALACIÓN DE DRUSH CON COMPOSER

        Hace varios años, se recomendaba que al trabajar con Drush y Drupal, realizáramos una instalación global, con la que pudiéramos efectuar toda clase de operaciones, sin importar la versión de nuestro proyecto; pero a partir de Drupal 8, se comenzó a proponer instalaciones individuales, para evitar errores producidos por incompatibilidades, ya fuera entre versiones de php, o del núcleo de Drupal.

        Actualmente, para instalar Drush en cualquier proyecto de Drupal 8 o superior, utilizaremos el gestor de paquetes Composer, y al igual que con otros módulos de Drupal, dejaremos en él la responsabilidad de descargar todos los archivos necesarios para su funcionamiento, para ello escribiremos desde la carpeta raíz de nuestra instlación, el siguiente comando:

composer require drush/drush

     De inmediato se iniciará el proceso de descarga de la versión más actual y estable, que esté disponible sobre esta herramienta de comandos, en el momento en que escribo este artículo, es la versión 10.5.0

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     DRUSH LAUNCHER

         Con el Drush Launcher podrás ejecutar comandos de Drush en todos tus proyectos, sin la necesidad de escribir la ruta completa ej: "/vendor/bin/drush cr". Exiten varias formas para descargar e instalarlo, puedes revisar la documentación en Repositorio Drush Launcher

     5 COMANDOS DRUSH QUE DEBERÍAS CONOCER

     GENERAR UN MÓDULO

       Drush te genera automáticamente y de manera configurable, toda la estructura de archivos necesaria para crear un módulo. (Funcionalidad de la antigua Drupal Console)

drush generate module

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     RECUPERAR ACCESO ADMIN

     En algunos casos, es posible que perdamos el acceso del usuario admin, al realizar algún traspaso de entornos o no haber guardado los datos de acceso en un lugar fácil de encontrar. Para estos casos, el siguiente comando te da la posiblidad de acceder como administrador para que puedas cambiar la clave de acceso por una nueva.

drush:uli 

     Forma de uso: Copia en el navegador el enlace generado, a partir de "/user" y pégalo en el navegador a continuación del dominio de tu página. Al presionar enter accederás directamente a la página de configuración del usuario administrador para que puedas cambiar la clave de acceso sin necesidad de acordarte de la anterior.

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     VER LA TABLA DE ERRORES SIN ABRIR DRUPAL

     Como ya sabrás, Drupal ofrece la posibilidad de verificar, todos los errores que registra a nivel de base de datos, ya que los guarda en una tabla llamada Watchdog, con Drush podrás acceder a estos datos, sin la necesidad de entrar a la interfaz de usuario usando el siguiente comando:

drush wd-show

     Al ejecutarlo, verás inmediatamente en consola, todos los datos que haya guardado Drupal dentro de esta tabla, facilitándote el análisis de posibles errores más rápidamente.

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     VER LOS MÓDULOS Y/O TEMAS ACTIVADOS

     En algunos proyectos, sobretodo cuando se trata de instalaciones muy grandes, necesitamos tener una idea rápida de los módulos o temas que se encuentran activados en un momento determinado. Este comando nos mostrará en pantalla, un listado completo de todos los módulos y temas, con la correspodiente información acerca su versión y de si están o no activados.

drush pml

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     EXPORTAR BASE DE DATOS COMPLETA

     Cuando estamos haciendo el traspaso de entornos, es posible que necesitemos exportar toda la base de datos para dicho traspaso, con este comando, podremos generar rápidamente un backup que se guardará a la altura de nuestra carpeta raíz del proyecto:

drush sql:dump --result-file=../mi_backup.sql

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     BORRAR BASE DE DATOS EXISTENTE:

drush sql-drop

     IMPORTAR UNA COPIA DE LA BASE DE DATOS:

drush sql-cli < ~/my-sql-dump-file-name.sql

Volcará la base de datos y la comprimirá, colocándola en el directorio predeterminado de drush bajo una marca de tiempo

drush sql-dump --gzip --result-file

Volcará la base de datos en el archivo especificado antes de comprimirlo con gzip

drush sql-dump --gzip --result-file=/path/to/file.sql

Fijar un tema por defecto para tu instalación de Drupal, ejemplo el theme Bartik

drush config-set system.theme default bartik

     Puedes aprende más sobre el uso y los comando de drush, visitando su drushcommands o www.drush.org/latest/

Tablas | Creación programáticamente en Drupal 9

Video de Youtube
URL de Video remoto
Texto

     A veces, cuando trabajamos en proyectos web utilizando Drupal, nos encontraremos con la necesidad de añadir en un solo módulo, todos los elementos que vamos a utilizar, ya sea porque se trate de un proyecto existente al que vamos a agregar una nueva funcionalidad, o por que este desarrollo pueda implementarse en varios proyectos a la vez, compartiéndolo con otros miembros del equipo de trabajo o de una comunidad de desarrolladores.

     Ya hemos explicado Cómo crear un módulo en Drupal 9 y además ya tienes los conocimientos necesarios para saber Cómo crear formularios programáticamente en Drupal 9, por lo tanto, el próximo paso, antes de desarrollar módulos más complejos, sería descubrir la forma de añadir tablas en tu base de datos, para que puedas controlar los elementos que instalarás relacionados con tu módulo.

     Por esta razón, hoy nos enfocaremos en la implementación de los requerimientos necesarios para crear, programáticamente, una o varias tablas, dependiendo de la necesidad que tengas para tu proyecto, utilizando el hook_schema(), dentro del archivo install en nuestro proyecto Drupal 9. 

Requisitos:

Cómo crear tablas programáticamente en Drupal 9

    Hoy aprenderemos a utilizar el archivo "MIMODULO.install" dentro de nuestro módulo personalizado. Si ponemos atención en la manera de implementarlo dentro de nuestros proyectos, tendremos el conocimiento suficiente para crear módulos más complejos, que nos permitirán la creación de contenidos directamente dentro de la base de datos de Drupal.

     Un ejemplo práctico, que explicaremos en otro artículo y su respectivo video, sería un módulo que al instalarse, además de crear una tabla, con la configuración necesaria para guardar la información sobre los participantes a un curso, nos añadiera un formulario de inscripción, conectado a esta tabla, con el cual los usuarios pudieran rellenarla directamente.

       Paso 1 Creación de tu módulo:

          Lo primero que deberías saber es cómo crear un módulo personalizado. Esencialmente para este ejemplo, lo que necesitarás será una carpeta con el nombre de tu módulo y dentro el archivo con el nombre del módulo y la extensión, eje.: "mimodulo.info.yml"

name: Mi tabla
description: 'Crea una tabla'
package: drupaladicto

type: module
core_version_requirement: ^8.8.0 || ^9.0

     Paso  2 Creación del archivo .install:

     En el archivo "MIMODULO.install", es donde tendremos que indicarle a Drupal la configuración para que pueda crear nuestra tabla, para ello utilizaremos el "hook_schema()", que se encargará de interpretar los datos y creará dicha tabla.

/**
 * Implment hook_schema()
 */
function mi_tabla_schema() {

  $schema['mitabla'] = array(
    'description' => 'Guarda los datos de los participantes',
    'fields' => array(
      'pid' => array(
        'type' => 'serial',
        'not null' => TRUE,
        'description' => 'Primary Key: Identificador único del participante.',
      ),
      'uid' => array(
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
        'description' => "Creador de usuarios {users}.uid",
      ),
      'nombre' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
        'description' => 'Nombre del participante.',
      ),
      'apellido' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
        'description' => 'Apellido del participante.',
      ),
      'edad' => array(
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
        'size' => 'tiny',
        'description' => 'Edad del participante.',
      ),
    ),
    'primary key' => array('pid'),
    'indexes' => array(
      'nombre' => array('nombre'),
      'apellido' => array('apellido'),
      'edad' => array('edad'),
    ),
  );
  return $schema;
}

     Explicación:

          En la primera parte del hook_schema(), estamos definiendo el nombre de la tabla dentro de un array global, que es nuestro esquema $schema['mi_tabla'] = [ ], dentro de este array general, tendremos dos elementos fundamentales, que son el campo con la descripción de la tabla y a continuación otro array general, llamado "'fields' => array()", que será donde iremos añadiendo todos los campos, con sus respectivos atributos, como tipo de campo, si es nulo, si tendrá valor por defecto, etc.

$schema['mitabla'] = array(
  'description' => 'Guarda los datos de los participantes',
  'fields' => array(
    'pid' => array(
      'type' => 'serial',
      'not null' => TRUE,
      'description' => 'Primary Key: Identificadro único del participante.',
    ),
    'uid' => array(
      'type' => 'int',
      'not null' => TRUE,
      'default' => 0,
      'description' => "Creator user's {users}.uid",
    ),
    'nombre' => array(

     Luego de definir todos los campos, encontraremos en la parte inferior del "hook_schema()", el lugar donde definiremos la clave primaria de nuestra tabla, acompañada de los índices.

),
'primary key' => array('pid'),
'indexes' => array(
  'nombre' => array('nombre'),
  'apellido' => array('apellido'),
  'edad' => array('edad'),
),

     Por último, y no menos importante, está el retorno del esquema, que es quien permitirá verdaderamente que Drupal pueda ejecutar toda la información que hemos añadido en el mismo.

  );
  return $schema;
}

     Opcional Creación de datos por defecto:

          Para nuestro ejemplo, además de implementar el hook_schema() y generar nuestra tabla, hemos decidido añadir además, algunos datos por defecto, que se colocarán en sus respectivos campos, al momento de instalar nuestro módulo.

         Para realizar esta operación, hemos implementado el "hook_install()" target="_blank", que se ejecutará una vez se haya ejecutado el hook_schema() y esté generada nuestra tabla.

/**
 *  hook_install()
 */
function mi_tabla_install() {
  $values = [
    [
      'nombre' => 'Pepito',
      'apellido' => 'Pérez',
      'edad' => 30,
      'uid' => 1,
    ],
    [
      'nombre' => 'Ana',
      'apellido' => 'Medina',
      'edad' => 28,
      'uid' => 1,
    ],
  ];
  $database = \Drupal::database();
  $query = $database->insert('mitabla')->fields(['nombre', 'apellido', 'edad', 'uid']);
  foreach ($values as $participante) {
    $query->values($participante);
  }
  $query->execute();

}

     Explicación:

     En la primera parte de este "hook_install()", estamos pasándole a drupal los valores que se añadirán a los campos de nuestra tabla, dentro del array "$values = [ ] ", debes asegurarte que cada campo corresponde, con los que haz definido en dentro del $schema[ ].

$values = [
  [
    'nombre' => 'Pepito',
    'apellido' => 'Pérez',
    'edad' => 30,
    'uid' => 1,
  ],
  [
    'nombre' => 'Ana',
    'apellido' => 'Medina',
    'edad' => 28,
    'uid' => 1,
  ],
];

     En la siguiente parte, utilizando el servicio "\Drupal::database();", realizamos una consulta a la base de datos y mediante un insert, añadimos a la tabla, los campos correspondientes dentro del array fields, luego recorremos todos valores, utilizando el foreach y por último, ejecutamos la consulta.

$database = \Drupal::database();
$query = $database->insert('mitabla')->fields(['nombre', 'apellido', 'edad', 'uid']);
foreach ($values as $participante) {
  $query->values($participante);
}
$query->execute();

Módulo personalizado en Drupal 9 (Parte 3)

Video de Youtube
URL de Video remoto
Texto

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

Cómo crear un módulo en Drupal 9 (3ra Parte)

Para completar nuestro pequeño tutorial sobre Cómo crear un módulo en Drupal 9, sólo nos falta saber cómo añadir un enlace desde el menú principal para que los usuarios puedan navegar hasta el contenido de nuestro módulo e interactuar con él.

Por último veremos cómo configurar permisos para restringir el acceso y así podremos decidir, qué tipo de usuarios podrán ver, editar o administrar el contenido relacionado con nuestro módulo.

Antes de continuar, te recomiendo que leas Cómo crear un módulo en Drupal 9, para que puedas realizar el proceso paso a paso y entender en qué consiste y de esta manera, a medida que avances, acumularás la experiencia y conocimientos necesarios, que te ayudarán en el desarrollo de módulos y funcionalidades más avanzadas para tus proyectos en Drupal 9.

 

Si ya lo tienes, vamos a empezar...

En esta ocasión, vamos a añadir un enlace, en el menú principal de la web, que apuntará a la página del controlador con la cual estuvimos trabajando en el anterior artículo, si todavía no lo haz leído, aquí lo tienes Cómo crear un módulo en Drupal 9 (2da Parte), si ya lo haz hecho, recordarás que la url de la que hablamos, es la que pusimos dentro del mi_modulo.routing.yml, en el apartado de "path", en mi caso esta url de la página es "/mypage", pero tú puedes poner la que quieras.

Ahora, nos toca crear un nuevo archivo, al que llamaremos mi_modulo.links.menu.yml y dentro colocaremos el siguiente contenido, recuerda respetar los espacios y no utilices el tabulador; en su lugar, utiliza la barra espaciadora y deja dos espacios, en los casos necesarios, contando a partir del margen izquierdo.

mi_modulo.mynewpage:
  title: 'My Page'
  description: 'Page Created with MyModule'
  route_name: mymodule.mypage
  weight: 10
  menu_name: main

A continuación te explico cada parte del archivo para que puedas entenderlo y hacer los cambios necesarios y adaptarlos a tu propio módulo:

mi_modulo.mynewpage:

En esta primera línea, hemos utilizado el nombre de nuestro módulo, esto se recomienda para evitar conflictos con otros módulos existentes, y luego está el nombre con que el que idenficaremos este comportamiento .mynewpage: , presta mucha atención en los detalles, en la primera línea no hemos dejado ningún espacio a la izquierda y tenemos los dos puntos al final.

  title: 'My Page'
  description: 'Page Created with MyModule'

Las dos líneas siguientes, simplemente indican el nombre que aparecerá en el botón del menú y un texto descriptivo, que se mostrará al colocarnos encima de dicho botón. Haz visto que a partir de aquí, siempre mantenemos dos espacios con respecto al margen izquierdo de la página. Si por error, sobra o falta un espacio, el archivo no funcionará.

  route_name: mymodule.mypage

Seguro que en esta línea, hay algo que te suena haber visto anteriormente, si es así, felicidades por prestar atención a los detalles, me refiero al nombre de la ruta, el que definimos en la primera línea del archivo mi_modulo.routing.yml, con ello indicamos a Drupal, que al hacer clic en el elemento del menú correspondiente, deberá buscar esta ruta y mostrar los contenidos definidos en dicho archivo.

  weight: 10
  menu_name: main

Para finalizar, indicamos la posición del enlace con respecto a otros elementos del menú utilizando el "weight" o peso; los elementos del menú cuentan a partir de la posición Cero y tendrán valores positivos o negativos, correspondientes a si estarán debajo o encima del elemento cuyo "weight" o peso equivale a Cero.

En la última línea, indicamos el Menú Padre "main", para nuestro enlace, como dijimos al principio, en este caso, el botón para este módulo personalizado, estará dentro del menú principal.

Ahora vamos a echar un vistazo a los permisos del módulo

Una de las ventajas que ofrece el desarrollo de webs utilizando CMS o gestores como Drupal, es la capacidad para gestionar usuarios y restringir sus accesos, según creamos conveniente.

Para añadir permisos específicos en nuestro módulo personalizado, tendremos que crear un archivo, al que, en este ejemplo, llamaremos mi_modulo.permissions.yml y lo siguiente que haremos es añadir estas líneas: 

view mymodule:
  title: 'Ver contenido'
  description: 'El usuario puede ver el contenido relacionado con el módulo'
access mymodule:
  title: 'Acceder a contenido restringido'
  description: 'El usuario con este permiso podrá ver contenido restringido'
administer mymodule:
  title: 'Administrar el módulo'
  description: 'Sólo los administradores podrán modificar la configuración del módulo'
  restrict access: TRUE

Si ya conoces el apartado de Drupal, donde puedes gestionar los permisos para los usuarios, o sea la url que te lleva será algo como "http://drupal9composer.localhost/admin/people/permissions", una vez creado este nuevo archivo, al vaciar las cachés, podrás comprobar que los nuevos permisos se han añadido al listado y que estarán para activarlos según el rol que desees.

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Un último apunte, para que tus permisos tengan efecto deberás modificar la última línea del mi_modulo.rounting.yml y cambiar el "access content", por el nombre del permiso que desees aplicar, ejemplo (access mymodule), te dejo una imagen para que lo veas mejor.

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Espero haberte ayudado a comprender un poco más sobre Drupal y que puedas crear o trabajar en grandes proyectos donde poner a prueba tus conocimientos, experiencias y ganas de superación.

¡Hasta la próxima y buena suerte!

 

Módulo personalizado en Drupal 9 (Parte 2)

Video de Youtube
URL de Video remoto
Texto

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

Cómo crear un módulo en Drupal 9 (2da Parte)

Siguiendo con el desarrollo de nuestro módulo personalizado, hoy trataré de explicarte qué es el controlador o Contoller, para qué nos sirve y cómo podemos añadirlo a nuestro módulo personalizado.

Si todavía no haz creado tu módulo personalizado, antes de continuar leyendo, te recomiendo que primero leas Cómo crear un módulo en Drupal 9 (1era Parte), sigue los pasos y cuando tengas el módulo funcionando, vuelve aquí para que puedas seguir ampliándolo y entendiendo el proceso de desarrollo.

Una de las estructuras o formas de desarrollo para toda clase de aplicaciones y que además emplean los más conocidos frameworks que existen en el mercado, es el (MVC), o separación del código según sus funcionalidades en "Modelo Vista y Controlador", que esencialmente divide el total del código de la siguiente forma:

  • La parte correspondiente a la base de datos es para el (Modelo)
     
  • La parte correspondiente a mostrar los datos es para (Vista)  
     
  • La parte que sirve para conectar MODELO+ VISTA es para (Controlador o Controller)

Ahora bien, ¿Cómo aplicaremos esto dentro de nuestro módulo personalizado?, en Drupal y para nuestro ejemplo en particular, el controlador nos servirá para crear una página y posteriormente poder acceder a ella desde una url. 

Para añadir un Controlador o Controller, se debe respetar una estructura específica de archivos y del código a implementar, así que, vamos allá:

Paso 1:

Abre la carpeta de tu módulo personalizado que haz creado previamente siguiendo el anterior artículo y a continuación crearás una carpeta llamada src y dentro de ella otra carpeta a la que llamarás Controller.

Fíjate bien, en que la primera carpeta tiene el nombre en minúsculas y la segunda, que es dónde estará nuestra clase Controlador o Controller, deberá iniciar por mayúscula.

Paso 2:

Dentro de la carpeta Controller, ahora vas a añadir un archivo php, que será nuestra clase Controlador a la que llamaremos MyModuloController.php

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Paso 3:

Dentro del archivo MyModuloController.php, asegúrate de que tengas la etiqueta de apertura de <?php para que funcione, no nos hará falta cerrar la etiqueta en el caso de crear esta clase de archivos para Drupal.

Paso 4:

Añade el siguiente código a tu controlador y guarda el archivo. (Trata de escribirlo y no copiarlo para que se te grave en al memoria más fácilmente)

Ahora te explico qué es lo que tenemos aquí dentro paso a paso para que puedas aprenderlo:

En la primera parte, tenemos los comentarios, que en php se escriben entre /*** COMENTARIO AQUI ***/, y que para seguir una cierta estructura en el desarrollo, se emplea tal y como lo vez.

El @file le permite a Drupal identificar que se trata de un archivo, es recomendable añadirlo siempre en tus desarrollos para módulos personalizados.

Y a continuación, lo que estamos diciendo es que dentro de este archivo, se implementará la clase Controller de Drupal.

/**
 * @file
 * Implement MyModuleController
 */

Las versiones más recientes de php utilizan lo que se conoce como namespace con lo que se evita conflictos por el uso de clases duplicadas y la ubicación específica para la clase que deseamos utilizar en nuestros desarrollos.

namespace Drupal\mymodule\Controller;

Con esta línea en particular, estamos diciéndole a Drupal, dónde podrá encontrar nuestra clase Controller, indicándole que la busque dentro de nuestro módulo y a continuación, dentro de la carpeta llamada Controller.

La siguiente línea, es para indicar que vamos a utilizar una de las clases incluidas en la instalación de Drupal, que el algunos casos, también podría ser de Symfony, ya que Drupal 8 y 9 están basado en este Framework.

Cada vez que tengamos que utilizar una clase, primero necesitamos indicar que la utilizaremos escriendo una línea como la que hemos puesto nosotros en este caso.

use Drupal\Core\Controller\ControllerBase;

La clase ControllerBase nos servirá para emplear sus métodos y otras características definidas en ella, mediante la herencia de objetos en php para que el proceso se ejecute, añadiremos a la declaración de nuestra clase MyModuleController, la palabra  extends y así es como el código que escribamos en el Controller funcionará según lo esperado.


class MyModuleController extends ControllerBase {

 

}

Ahora que ya hemos llegado hasta aquí, sólo nos queda incluir el código restante dentro de nuestra clase, que lo único que hará es devolvernos un texto estático, al escribir en el navegador la url que le asignaremos con otro archivo, que aún no hemos creado y que se llamará mi_modulo.routing.yml

public function mypage(){
  return array(
    '#type' => 'markup',
    '#markup' => t('Este es el contenido de la página de MyModule'),
  );
}

Paso 5:

Para que podamos acceder a nuestra nueva página (mypage), tendremos que crear, al mismo nivel que el archivo "mi_modulo.info.yml", otro archivo al que llamaremos mi_modulo.routing.yml y dentro escribiermos la siguientes líneas, debes vigilar que se mantengan los espacios, no uses la teclas TAB, usa la barra espaciadora y controla siempre la estructura de dos en dos en cada zona indicada o tu código no funcionará:

mymodule.mypage:
  path: '/mypage'
  defaults:
    _title: 'Tïtulo de mi página para el módulo'
    _controller: '\Drupal\mymodule\Controller\MyModuleController::mypage'
  requirements:
    _permission: 'access content'

Vamos a explicar lo que tenemos dentro del archivo mi_modulo.routing.yml:

En la primera línea, y sin ningún espacio, hemos escrito el nombre del módulo, se recomienda para evitar conflictos con otros módulos que se llamen igual, luego hemos puesto un punto y a continuación el nombre que identifica nuestra ruta. 

mymodule.mypage:

En la segunda línea, con hemos dado dos veces a la barra espaciadora y luego hemos escrito lo que será la url para acceder a nuestra página.

  path: '/mypage'

En las siguientes líneas, primero estamos definiendo el título que aparecerá en la parte superior de la página y al que Drupal le asigna por defecto la etiqueta html <h1></h1>, y luego estamos indicando la ruta dónde Drupal deberá buscar el contenido de nuestra página, para ello, hemos definido entre comillas, la ruta completa comenzando con la barra inclinada seguida de Drupal hasta llegar al nombre de nuestra clase y finalmente, como nuestra página es un método, para que funcione hemos puesto los cuatro puntos.

defaults:
  _title: 'Tïtulo de mi página para el módulo'
  _controller: '\Drupal\mymodule\Controller\MyModuleController::mypage'

     Y ya hemos llegado al final del archivo, donde hemos definido que todo el que tenga permisos para ver el contenido publicado en nuestra web, también podrá acceder para ver esta página si pone la url en el navegador.

requirements:
  _permission: 'access content'

     ¡Ya está!, ahora que ya has realizado todos los cambios, creado los archivos y has seguido el consejo de no copiar y pegar, sino escribir todo el código, porque quieres llegar a entender y programar con responsabilidad, lo siguiente que tienes que hacer es, una vez hayas guardado los cambios, borrar las cachés y en el navegador escribir la url que hemos definido previamente, en la parte donde dice "path:",  es decir, escibe en el navegador  http://drupal9composer.localhost/mypage

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Si al Vaciar cachés y escribir la url en el navegador ves esta página, ¡Felicidades!, porque ya has aprendido a crear una página utilizando la clase Controller en un módulo personalizado.

El archivo para definir las rutas y ubicación del controlador del módulo personalizado, tendrá la extensión: .routing.yml