D8 Updating drupal - pierregermain/MyDrupal GitHub Wiki

Rector

https://github.com/palantirnet/drupal-rector

composer require --dev palantirnet/drupal-rector	
cp vendor/palantirnet/drupal-rector/rector.php .
# workflow
$ vendor/bin/rector process web/modules/contrib/[YOUR_MODULE] --dry-run
#Apply suggested changes:
$ vendor/bin/rector process web/modules/contrib/[YOUR_MODULE]

Funciones de actualización

Algunas modificaciones que se realizan en un módulo requieren programar una actualización. Debemos identificar los cambios en el modelo de datos:

  • Cambios de configuración en entidades y campos. Por ejemplo, si un campo cambia de un tipo a otro.
  • Cambios en los esquemas de configuración.
  • Cambios en la definición de las tablas de la base de datos.

Función hook_update_N()

  • Se mete en el fichero mymodule.install

  • Se ejecuta al ejecutar update.php entre versiones menores de drupal.

  • Las funciones de actualización se implementan en el archivo .install del módulo

  • https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Extension!module.api.php/function/hook_update_N/8

  • En cada implementación de la función debemos especificar el valor de N, formado por 4 dígitos con la siguiente estructura: ABCC.

    • A. El primer dígito se corresponde con la versión de Drupal: 8. Cuando lleguemos a Drupal 10 se podrán usar 2 dígitos.
    • B. El segundo dígito se corresponde con la versión del módulo. Por ejemplo, para la versión 8.x-1.* el valor es 1, y para la versión 8.x-2.* el valor es 2. Los módulos personalizados y contribuidos tienen su propio número de versión independiente del núcleo, mientras que los módulos incluidos en el núcleo tienen la misma versión del núcleo.
    • CC. Secuencia, comenzando en 01, que indica el orden de las actualizaciones.

Ejemplo: Módulo mymodule

function mymodule_update_8101() {
//Primera actualización para la versión 8.x-1.x del módulo
}
function mymodule_update_8102() {
//Segunda actualización para la versión 8.x-1.x del módulo
}
function mymodule_update_8201() {
//Primera actualización para la versión 8.x-2.x del módulo
}

La ejecución de las funciones de actualización se realizará secuencialmente, a partir de la versión del módulo instalado. Según el ejemplo anterior, si instalamos el módulo en la versión 8.x-2.x, se aplicarán todas las funciones de actualización.

Supongamos que se lanza una nueva versión del módulo que incluye, además de las anteriores, la siguiente función de actualización:

function example_module_update_8202() {
//Segunda actualización para la versión 8.x-2.x del módulo
}

Si actualizamos el módulo, solo se tendrán en cuenta las funciones de actualización que no se hayan ejecutado con anterioridad (en este caso la 8202). Para que esto sea posible, el sistema mantiene un registro de todas las funciones de actualización que se han aplicado, por lo que las funciones ya implementadas nunca deben ser renumeradas (ni modificadas).

La programación de funciones de actualización es muy delicada y se tienen que tener en cuenta una serie de recomendaciones, que puedes consultar aquí:

https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Extension!module.api.php/function/hook_update_N/8#sec_notes

Revertir

Para revertir el registro de actualizaciones para un módulo determinado para evitar tener que cambiar el número a la función hook_update_N()

drush ev "\Drupal::keyValue('system.schema')->set('forcontu_blocks', (int) 8000)";

Actualización de entidades y campos

https://www.drupal.org/docs/8/api/update-api/updating-entities-and-fields-in-drupal-8

Actualización de campos

Cambio en la definición del tipo de campo

Se actua sobre 'field_storage_config'

https://api.drupal.org/api/drupal/core!modules!field!src!Entity!FieldStorageConfig.php/class/FieldStorageConfig/8

Ejemplo: Cambio el tipo (type) de los campos de tipo 'foo' a 'bar'.

use Drupal\field\Entity\FieldStorageConfig;
//..

$field_storage_configs = \Drupal::entityTypeManager()->getStorage('field_storage_config')->loadByProperties(['type' => 'foo']);
foreach ($field_storage_configs as $field_storage) {
  $new_field_storage = $field_storage->toArray();
  $new_field_storage['type'] = 'bar';
  $new_field_storage['module'] = 'mymodule';
  $new_field_storage = FieldStorageConfig::create($new_field_storage);
  $new_field_storage->original = $new_field_storage;
  $new_field_storage->enforceIsNew(FALSE);
  $new_field_storage->save();
}

Cambio en la configuración de un campo

Se actúa sobre 'field_config'

https://api.drupal.org/api/drupal/core!modules!field!src!Entity!FieldConfig.php/class/FieldConfig/8

Ejemplo: cambiamos el tipo del campo 'field_tags', y establecemos algunas opciones de configuración:

use Drupal\field\Entity\FieldConfig;
//..

$fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties(['field_name' => 'field_tags']);
foreach ($fields as $field) {
  $new_field = $field->toArray();
  $new_field['field_type'] = 'entity_reference';
  $new_field['settings'] = [
    'handler' => 'default:taxonomy_term',
    'handler_settings' => [
      'target_bundles' => [
        $vocabulary_name => $vocabulary_name
      ],
      'auto_create' => TRUE,
    ],
  ];
  $new_field = FieldConfig::create($new_field);
  $new_field->original = $field;
  $new_field->enforceIsNew(FALSE);
  $new_field->save();
}

Actualización de entidades

Cambios en la presentación de la entidad

Se actúa sobre 'entity_view_display'

Ejemplo: Obtenemos la configuración de presentación de los nodos de tipo artículo. Luego extraemos la información específica del campo 'field_tags', utilizando el método getComponent(), y cambiamos la configuración de 'links' (setComponent()).

    $properties = [
      'targetEntityType' => 'node',
      'bundle' => 'article'
    ];
    $view_displays = \Drupal::entityTypeManager()->getStorage('entity_view_display')->loadByProperties($properties);
    foreach ($view_displays as $view_display) {
      $component = $view_display->getComponent('field_tags');
      $settings = [
        'link' => TRUE,
      ];
      $view_display->setComponent('field_tags', [
          'settings' => $settings,
        ] + $component)->save();
    }

Cambios en la Configuración del formulario de edición de la entidad

Actúamos sobre 'entity_form_display'

Ejemplo: Obtenemos la entidad de configuración del formulario de los nodos de tipo artículo. Luego cargamos el componente del campo 'field_tags' y cambiamos la configuración de 'match_operator'.

$properties = [
      'targetEntityType' => 'node',
      'bundle' => 'article'
];
$form_displays = \Drupal::entityTypeManager()->getStorage('entity_form_display')->loadByProperties($properties);
foreach ($form_displays as $form_display) {
  $component = $form_display->getComponent('field_tags');
  $form_display->setComponent('field_tags', [
      'settings' => [
        'match_operator' => 'STARTS_WITH',
      ],
    ] + $component)->save();
}

Tipps

  • Puedes realizar los ejemplos desde PHP
  • Si realizas modificaciones sobre un elemento, vuelve a obtenerlo para comprobar que la configuración se ha modificado correctamente.

Actualización de configuración

Cuando los cambios se hacen en ficheros de configuración haremos lo siguiente:

    1. Actualizar los archivos de esquema de configuración (archivos .yml en /config/schema.)
    1. Actualizar los archivos de configuración (Archivos .yml en /config/install y /config/optional)
    1. En la función de actualización hook_update_N(), implementaremos la actualización de la configuración

Actualización de configuración: https://www.drupal.org/docs/8/api/update-api/updating-entities-and-fields-in-drupal-8

Para realizar modificaciones en la configuración, partimos de la factoría de configuración (ConfigFactory), para llegar al objeto de configuración (Config): https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Config!ConfigFactory.php/class/ConfigFactory/8

https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Config!Config.php/class/Config/8

Para guardar el objeto de configuración (una vez realizados los cambios), usamos el método:

Config::save($has_trusted_data = FALSE)

Pues bien, tenemos que asegurarnos de pasar el parámetro $has_trusted_data a TRUE, para que el método no compruebe el esquema de configuración. Esto debe hacerse así porque no podemos asegurar en este punto que el esquema de configuración en el módulo se corresponda con la configuración que se está realizando en esta función de actualización, ya que puede ser una actualización intermedia.

Por ejemplo:

$config->save(TRUE);

Ejemplo

Archivo de configuración previo:

pets:
  - dog
  - cat

Archivo de configuración nuevo:

pets:
  - dog
  - cat
fruit:
  - apple
  - banana
  - mango

Función de actualización:

function example_update_8001() {
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('example.configuration');
  $config->set('fruit', ['apple', 'banana', 'mango']);
  $config->save(TRUE);
}

Más ejemplos

  1. Consulta otros ejemplos de actualización de configuración en: https://www.drupal.org/docs/8/api/update-api/updating-configuration-in-drupal-8

  2. buscando \Drupal::configFactory()->getEditable( en archivos *.install.

/**
* Removes the system.filter configuration.
*/
function system_update_8002() {
  \Drupal::configFactory()->getEditable('system.filter')->delete();
  return t('The system.filter configuration has been removed');
}

Actualización de la base de datos

Pasos:

  1. Actualizar hook_shema() para que al instalar el módulo se instalen bien las tablas en la db.
  2. Implementar una nueva función hook_update_N()

Más info en:

Añadir una nueva columna a una tabla

Ejemplo: Añadir columna 'title' a la tabla 'menu_tree'.

function system_update_8001(&$sandbox = NULL) {
  $database = \Drupal::database();
  $schema = $database->schema();
  $spec = [
    'description' => 'The title for the link.',
    'type' => 'blob',
    'size' => 'big',
    'not null' => FALSE,
    'serialize' => TRUE,
];
$schema->addField('menu_tree', 'title', $spec);
}

Métodos relacionados

Schema:changeField(). Modificar un campo de una tabla.
Schema:dropField(). Eliminar un campo de una tabla

Añadir una nueva tabla

Schema::createTable()

Ejemplo: Crear tabla foo con los campos bar y baz

  $database = \Drupal::database();
  $schema = $database->schema();
  $spec = [
    'description' => 'The Foo table',
    'fields' => [
      'bar' => [
        'description' => 'Bar field description.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ],
      'baz' => [
        'description' => 'Baz field description',
        'type' => 'text',
        'not null' => TRUE,
      ],
    ],
    'primary key' => ['bar'],
  ];
  $schema->createTable('foo', $spec);

Añadir claves primarias o índices

Ejemplo:

$database = \Drupal::database();
$schema = $database->schema();
$spec = ['bar'];

// Add bar as a normal index.
$schema->addIndex('mytable', $spec);

// Add bar as a primary key.
$schema->addPrimaryKey('mytable', $spec);

Hazlo desde la consola

Comandos de drush

Listar las actualizaciones de la base de datos pendientes de aplicar.

drush updatedb-status

Lanzar update.php


drush updatedb

actualizar los cambios en configuración de entidades.

drush updatedb --entity-updates

# Otra forma:
drush entity-updates

Comandos drupal console

Lista las actualizaciones de la base de datos pendientes de aplicar

drupal update:debug

Actualizar el núcleo, un módulo o varios módulos. https://drupalconsole.com/docs/en/commands/module-update

OJO: Ejecutar drupal module:update sólo se puede con la opción --composer mymodule.OJO: Esto actualiza todo drupal también y gestiona el módulo sólo si está gestionado por composer.

drupal module:update

Ejecutar una función específica de actualización dentro de un módulo, o todas si no se especifica un número.

https://drupalconsole.com/docs/en/commands/update-execute

drupal update:execute

Implementar una función de actualización

drupal generate:update

Esto modifica el archivo .install del módulo creando el esqueleto de la función.

Ejemplo completo Uno

  1. Añadimos columna en el mymodule.install usando el hook_update_N()
  2. Actualizar db:
drush updatedb-status
drush updatedb
  1. Realizar cambios en el código
  2. Hacer otro hook_update_N() para que registros existentes tengan un valor por defecto en el nuevo campo.

Ejemplo completo Dos

Resizing Fields in Drupal 8 Without Losing Data