Sunt în curs de portare a unei baze de date non-Drupal în Drupal 9.
Baza de date originală conține, printre altele, un tabel de Cărți (cu informațiile obișnuite) și un tabel separat (nu mă întrebați de ce) pentru Cărți de călătorie. Primul are 10.000 de înregistrări și a fost migrat cu succes de la un cărți.csv
către Drupal. Acesta din urmă (cărți de călătorie.csv
) este de doar 200 de înregistrări.
Ceea ce este interesant (sic!) este că majoritatea Cărților de călătorie sunt, de asemenea, în tabelul Cărți, cu câteva câmpuri noi în tabelul Cărți de călătorie, în special o țară și numărul de pagini (sic din nou!).
În Drupal avem o taxonomie pentru tip de carte
cu lucruri de genul romantism
, aventură
, povești adevărate
, crima
, poezie
etc.. precum şi Ghid turistic
.
Cărți de la cărți.csv
sunt deja în Drupal, cu noduri noi și termeni de taxonomie corecti aplicați domeniului field_book_type
care, desigur, este un câmp cu mai multe valori.
Acum vreau să migrez cărți de călătorie.csv
în Drupal dar:
- dacă o carte există deja (căutând cu titlu, deoarece ID-urile din tabelele originale erau diferite!), trebuie doar să actualizați nodul în Drupal, adăugând termenul de taxonomie
Ghid turistic
- dacă o carte nu există în Drupal, creați-o și doar setați termenul de taxonomie
Ghid turistic
Până acum am reușit să fac asta printr-un plugin Destination personalizat și nu doar cu o configurație de migrare YAML.
Iată ce am sperat să folosesc:
uuid: d66124cf-232b-4080-911c-1d26aefd0246
langcode: en
stare: adevărat
dependențe: { }
id: quote_fornitore_voucher_csv_import
clasa: nula
field_plugin_method: null
cck_plugin_method: nul
migration_tags: null
migration_group: cărți
etichetă: „Importați cărți de călătorie”
sursă:
plugin: csv
cale: /Users/walter/travel_books.csv
delimitator: ','
incintă: '"'
header_offset: 0
ID-uri:
- id
câmpuri:
-
nume: id
etichetă: „Id unic”
-
nume: titlul_cartei
-
nume: tara
-
nume: pagini
-
nume: rezumat
.....
constante:
travel_book: „Carte de călătorie”
proces:
tip:
plugin: default_value
default_value: carte
field_pages: pagini
field_country: country
titlu: titlul_cartei
field_book_type:
plugin: entity_lookup
entity_type: taxonomy_term
pachet: tip_carte
bundle_key: vid
sursa: constants/travel_book
nid:
plugin: entity_generate
tip_entitate: nod
pachet: carte
bundle_key: tip
value_key: titlu
sursa: titlul_cartei
access_check: 0
destinaţie:
plugin: 'entity:node'
overwrite_properties:
- field_pages
- field_country
dependențe_migrație: nul
Am două probleme cu această migrare:
- Chiar dacă
entity_generate
găsește nodul existent corect pentru cartea curentă, motorul de migrare încă încearcă să CREEZE un nod nou, cu același NID și, desigur, eșuează cu o eroare SQL mare roșie
23000]: Încălcarea constrângerii de integritate: 1062 Dublare intrare „2662” pentru cheia „PRIMARY”: INSERT INTO „node” (“nid”, „vid”, „type”, „uuid”, „langcode”) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4); Matrice
- Am depășit acest lucru, doar pentru a nu putea adăuga la o Carte existentă termenul de taxonomie corect la lista de
field_book_type
.
Am urmărit problema cu 1 pentru a fi pe care o are Entitatea enforceIsNew
setată la Adevărat. Sau cel puțin asta am găsit. Am scris un plugin de destinație care, pe baza unei noi configurații, poate forța entitatea nou creată cu enforceIsNew = FALSE
și se pare că funcționează conform așteptărilor. Sunt create cărți de călătorie care nu se găsesc în Cărți i nDrupal, în timp ce cele deja existente sunt actualizate, cu câmpurile pagini
și țară
actualizat.
Acesta este codul relevant, cred.
clasa abstractă EntityBase implementează EntityInterface {
...
funcția publică este Nouă () {
return !empty($this->enforceIsNew) || !$acest->id();
}
...
Chiar dacă există un ID, care este setat de către nid
proces, enforceIsNew este setat la ADEVĂRAT
și așa isNew() returnează True.
<?php
spațiu de nume Drupal\migrate_books\Plugin\migrate\destination;
utilizați Drupal\Core\Entity\Entity;
utilizați Drupal\Core\Entity\EntityInterface;
utilizați Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
utilizați Drupal\migrate\Plugin\MigrationInterface;
utilizați Drupal\migrate\Row;
utilizați Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @MigrateDestination(
* id = "nod_actualizare"
* )
*/
clasa UpdateNodeDestination extinde EntityContentBase {
/** @var șir $entityType */
public static $entityType = 'nod';
funcția protejată updateEntity(EntityInterface $entity, Row $row) {
$entity = parent::updateEntity($entity, $row);
//verificați parametrul..
if(!empty($this->configuration['prefer_update']) && $this->configuration['prefer_update']){
// forțați să NU aplicați NOU. Acest lucru va evita inserarea de două ori a nodurilor deja prezente (ceea ce va rezulta
// într-o încălcare a integrității din MySQL
$entity->enforceIsNew(FALSE);
}
returnează $entitate;
}
}
iar YAMLS este schimbat cu pluginul meu și noul parametru prefer_update
destinaţie:
plugin: update_node
prefer_update: adevărat
overwrite_properties:
- field_pages
- field_country
dar mi se pare că ar trebui să fie mai simplu de atât. Evident că îmi lipsește ceva. Sunt sigur că acesta este un caz de utilizare destul de standard, așa că ar putea/ar trebui să fie realizabil în întregime în YAML.
În al doilea rând, încă nu pot să adaug corect tip_carte
la lista etichetelor existente.
Dacă adaug field_book_type
la overwrite_properties
, bineînțeles că este suprascris și pierdem toți termenii anteriori.
Nu mi se pare o modalitate de a actualiza prin adăugarea unei valori la un câmp cu mai multe valori.
Orice ajutor?
Mulțumiri
W