Datamigraatiot Drupal 8 -alustalle
Takaisin lempiaiheeni pariin. Migraatioartikkelin jatko-osa onkin antanutkin odottaa itseään turhan pitkään. Tässä välissä kerkesin kirjoittamaan aiheesta suoraan Drupal.org:in migraatiodokumentaatioon. Kehotan muuten nyt tilaisuuden tullen muitakin Drupal-osaajia tarttumaan siihen mahdollisuuteen. Oma ensidokumentointini otettiin kiitellen vastaan ja prosessi oli helppo. Aihealueen dokumentaatiovastaava katsastaa ja tarpeen vaatiessa modifioi ehdotetun dokumentin, joten pelkästään itse ei tarvitse arvioida tuottamansa tekstin laatua. Valitettavasti toisin kuin Drupalin moduuleita kehitettäessä, tästä ei saa suoraan mainetta ja kunniaa (drupal.org-tunnuksesi ei tule mihinkään näkyviin), mutta dokumentointi on yhtä kaikki tärkeää työtä avoimen lähdekoodin hyväksi.
Miksi sitten tämä on ihan lempiaiheeni kaikkien D8:n osa-alueiden joukossa? Hyvin toteutettu migraatio toimii kuin junan vessa. Kokonaisen verkkokaupan sisällön voi pistää täysin sileäksi ja painaa sen jälkeen nappia: migraatioprosessi noutaa datan ja rakentaa tuotteiden attribuutit, variaatiot ja lopuksi itse tuotteet - jopa ohjekirjoja myöten - verkkokauppaan muutamassa minuutissa. Vaikka asiakas päättäisi uusia koko tuotevalikoimansa tuotehallintajärjestelmässään, niin prosessi on sama. Luonnollisesti migraation räätälöinti täytyy tehdä riittävän geneeriseksi ja tuotehallintajärjestelmässä on täytettävä kaikki vaaditut tuotteen kentät, mutta Drupal 8 ei asiaa rajoita. Muutenkin rajoitteita on varsin vähän: migraatiomoduulit tukevat sekä tiedostosta tuomista, että verkkorajapinnan yli noutamista ja eri tiedostoformaatteja varten on olemassa useita plugareita. Samoin verkkokauppaan voi tuoda asiakas- ja alennusryhmätiedot tai muuta vastaavaa dataa. Toki tietoja voidaan myös viedä REST-rajapinnan yli toiseen suuntaan tai kolmanteen järjestelmään esimerkiksi tilausten jatkokäsittelyä varten, mutta se ansaitsee ihan oman artikkelinsa.
Ensimmäinen tekemämme Drupal 8 & Commerce 2 -sivusto on täysin migraation varaan rakennettu verkkokauppa. Kyseiseen verkkokauppaan voisi periaatteessa lisätä tuotteita manuaalisestikin, mutta nyt kaikki muutokset tehdään aina eri järjestelmään ja vasta sen jälkeen ne ajetaan sisään C2-verkkokauppaan. Kyseinen migraatio on toteutettu em. REST-rajapinnan yli noudetun json-muotoisen tiedoston pohjalta.
Järjestyksessä seuraava C2-verkkokauppatoteutuksemme noudatteli samaa kaavaa eli tuotteet ja asiakkaat tuodaan eri järjestelmästä. Tällä kertaa Visma Novasta ja lataamalla tarvittavat .csv-tiedostot migraation avulla sisään verkkokauppaan. Tämä olisi voitu hoitaa myös Novan tarjoamalla SOAP-pohjaisella Webservices-rajapinnalla, mutta meneillään olevassa tapauksessa se vastaisi suunnilleen kärpäsen tappamista tykillä. Nyt kaikki tuotteet sai migratoitua verkkokauppaan muutaman päivän työmäärällä, ja siitäkin työajasta suuri osa kului värien ja mallitietojen setvimiseen ja purkamiseen tuotekoodista, koska niille ei oltu käytetty omaa kenttää. Lisäksi vinkkinä, että csv:n source plugin sitten toki vaatii ns. BOM-infoa tiedoston alussa, koska muuten esim. scandit tulkitaan miten sattuu.
Nyt päästäänkin näppärästi omien migraatioplugareiden tekemiseen. Koska tuomassamme .csv-tiedostossa oli koodattu tuoteryhmä-, väri- ja mallitietoa suoraan tuotekoodiin, niin ne piti sieltä erottaa omiin kenttiinsä. Tämä on vaivatonta tehdä migraation aikana. Sanottakoon silti, että tässä esitellyt prosessiplugarit ovat lähes kertakäyttökamaa eivätkä kovin hienostuneita. Toisaalta juuri siksi ne palvelevat hyvin esimerkkinä yksinkertaisista prosessiplugineista.
Ennen kuin tuotteen väri- ja mallitietoja voidaan purkaa, on (tässä tapauksessa) tiedettävä kyseisen tuotteen tuoteryhmä. Lisäksi ne voidaan purkaa vain "täysimittaisista" 8 merkin tuotekoodeista ja sitä lyhempien koodien tuotteet jätetään pois verkkokaupasta. Tämän voinee tehdä helpomminkin kuin nyt esimerkissä, mutta regexistä ("regular expression") viime aikoina kiinnostuneena piti tietysti koittaa sitäkin. Lisäksi tuo swith-case -rakenne oli juuri tässä yhteydessä sekä selkeä, että hauska. Huvinsa kullakin. ;)
namespace Drupal\migrate_products\Plugin\migrate\process;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Migrate and decode Custom product model number from product code.
*
* Note! Plugin CustomCategory together with SkipOnEmpty should be called before this.
* Even if this and CustomCategory have some overlapping code, the former combo
* cleans up faulty product codes so they're not ending here.
*
* @MigrateProcessPlugin(
* id = "migrate_products_custom_model"
* )
*/
class CustomModel extends ProcessPluginBase {
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$product_category = substr($value, 0, 2); // Take only two frontmost digits
/**
* The product model number is coded either in the digits xxxx56xx
* or in the digits xx3456xx.
*/
switch ($product_category) {
case 11: // Profiilipellit, fall through
case 12: // Profiilipeltiosat, fall through
case 14: // Ranniosat, fall through
case 17: // Tikasosat, fall through
case 18: // Seinatikasosat, fall through
case 19: // Kattotikasosat, fall through
case 20: // Turvatikaspaketit, fall through
case 21: // Kattoturvaosat, fall through
case 22: // Lumiestepaketit, fall through
case 23: // Kattosiltapaketit, fall through
case 25: // Arkit
$model_code = substr($value, 4, 2);
break;
case 36: // Mittatilauslistat
$model_code = substr($value, 2, 4);
default:
printf("CustomModel.php: default branch! \n");
}
return $model_code;
}
}
Yllä oleva pätkässä oikeastaan ainoa huomionarvoinen seikka, joka näissä plugareissa täytyy muistaa, on Drupal 8:n käyttämä nimiavaruus eli namespace. Prosessiplugari tulee sijoittaa hakemistoon:
/modules/custom/migrate_products/src/Plugin/migrate/process, jossa "migrate_products" on migraatioryhmän nimi.
Plugin-tiedoston alussa määritellään sekä plugarin oma namespace, että ne joista jotain luokkia käytetään. Lisäksi annetaan plugarin id, jo on tässä migrate_products_custom_model. Samalla ideologialla voidaan tehdä source- ja destination-plugineja, vaikkakin useimmiten valmiit kirjastoplugarit riittävät. Yllä esitettyä php-plugaria käytetään migraation yml-tiedostossa seuraavasti:
# This skips all the products that are not categorized as "TYYPPI 0"
status:
plugin: static_map # D8 plugin
source: product_type
map:
0: true
bypass: false
field_category:
-
plugin: migrate_products_custom_category
source: product_code
-
plugin: skip_on_empty
method: row
field_model:
plugin: migrate_products_custom_model
source: product_code
...
Aluksi yml-muotoiset mäppäystiedostot näyttivät vieraalta Drupal 7:n jälkeen, mutta loppujen lopuksi ne ovat käteviä ja havainnollisia käyttää. Tiedostosta näkee yhdellä silmäyksellä mitä kenttiä täytetään ja mistä/miten ne täytetään. <3