D8 Updating drupal - pierregermain/MyDrupal GitHub Wiki
- Funciones de actualización
- Actualización de entidades y campos
- Actualización de configuración
- Actualización de la base de datos
- Hazlo desde la consola
- Ejemplo completo Uno
- Ejemplo completo Dos
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
-
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í:
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'
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:
-
- Actualizar los archivos de esquema de configuración (archivos .yml en /config/schema.)
-
- Actualizar los archivos de configuración (Archivos .yml en /config/install y /config/optional)
-
- 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
-
Consulta otros ejemplos de actualización de configuración en: https://www.drupal.org/docs/8/api/update-api/updating-configuration-in-drupal-8
-
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:
- Actualizar hook_shema() para que al instalar el módulo se instalen bien las tablas en la db.
- Implementar una nueva función hook_update_N()
Más info en:
- https://www.drupal.org/docs/8/api/update-api/updating-database-schema-andor-data-in-drupal-8
- https://github.com/pierregermain/MyDrupal/wiki/D8-DB-Database#creaci%C3%B3n-schema
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
- Añadimos columna en el mymodule.install usando el hook_update_N()
- Actualizar db:
drush updatedb-status
drush updatedb
- Realizar cambios en el código
- Hacer otro hook_update_N() para que registros existentes tengan un valor por defecto en el nuevo campo.