{"id":22466934,"url":"https://github.com/mavimo/biblio_import","last_synced_at":"2025-06-18T05:33:19.378Z","repository":{"id":25719784,"uuid":"29156723","full_name":"mavimo/biblio_import","owner":"mavimo","description":"Drupal 7 migrate sample","archived":false,"fork":false,"pushed_at":"2015-01-16T22:19:22.000Z","size":184,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T07:54:58.186Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mavimo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-12T21:01:18.000Z","updated_at":"2015-01-12T21:01:18.000Z","dependencies_parsed_at":"2022-08-24T14:13:13.195Z","dependency_job_id":null,"html_url":"https://github.com/mavimo/biblio_import","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavimo%2Fbiblio_import","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavimo%2Fbiblio_import/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavimo%2Fbiblio_import/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mavimo%2Fbiblio_import/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mavimo","download_url":"https://codeload.github.com/mavimo/biblio_import/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245868327,"owners_count":20685609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-06T10:14:41.206Z","updated_at":"2025-03-27T15:20:49.020Z","avatar_url":"https://github.com/mavimo.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Importare dati in Drupal\n\nSpesso capita di dover scrivere procedure di importazione per caricare informazioni presenti da contesti precedenti (durante la migrazione da applicativi in dismisione) o da data source esterni. Fortunatamente Drupal mette a disposizione una suite di funzionalità racchiuse nel modulo [Migrate](https://www.drupal.org/project/migrate).\n\nQuesto modulo è stato sviluppato inizialmente da [Cyrve](http://cyrve.com/) società specializzata in data migration per Drupal, e successivamente acquistata da [Acquia](https://www.acquia.com/) che attraverso Mike Ryan ne è l'attuale maintainer. Il modulo è stato utilizzato per migrare grosse quantità di dati in diversi progetti, quali *GenomeWeb* e *The Economist*; per maggiori informazioni vi rimandiamo alla documentazione linkata sulla pagina del progetto.\n\nIl modulo migrate è stato portato a [Drupal 8](https://groups.drupal.org/imp) ed è diventato il meccanismo di base per il processo di upgrade da versioni precedenti di Drupal verso l'ultima versione in fase di rilascio.\n\nIn questa guida affronteremo i temi principali relativi alla logica di funzionamento del modulo Migrate e proveremo a scrivere un breve modulo che ci permette di importare il CSV di una ipotetica biblioteca. Questa biblioteca è organizzata per avere i vari libri riposti in stanze, ogni stanza contiene più scaffali, ognuno dei quali ha diversi ripiani e per ogni ripiano sono presenti diversi libri.\n\n## I concetti base\n\nMigrate basa il suo funzionamento sullo stream di informazioni da una sorgente (tipicamente una fonte di dati, quale un CSV, un database, file JSON, webservice, ...) ad una destinazione (tipicamente un entità Drupal come un nodo, un termine di tassonomia, un utente, ..).\nDurante il passaggio dei dati tra questi due elementi le informazioni possono essere manipolate, arricchite, ... questo permette la massima flessibilità del processo stesso.\n\nLe *sorgenti* e *destinazioni* dei dati sono implementate attraverso delle classi PHP che -attraverso dei parametri passati al costruttore- definiscono le impostazioni delle stesse.\n\nLe classi principali che troviamo come **sorgenti** sono:\n\n * ```MigrateSourceCSV```: Utilizzato per sorgenti di dati che sono strutturate in file CSV (o ricondicibili a tali, come ad esempio un foglio di Excel).\n * ```MigrateSourceJSON```: Da usare quando la sorgente di dati è un file JSON.\n * ```MigrateSourceMongoDB```:  Da usare per sorgenti dati presenti sul database documentale MongoDB.\n * ```MigrateSourceSQL```: Da usare per sorgenti dati presenti su database SQL based (tipicamente MySQL / PostgreSQL).\n * ```MigrateSourceXML```:  Da usare quando la sorgente di dati è un file XML.\n\nMentre le pricipali presenti come **destinazione** sono:\n\n * ```MigrateDestinationEntity```:  costruisce un Entity generica in Drupal, classe tipicalmente estesa per l'implementazione di entità più specifiche, quali quelle di seguito riportate.\n * ```MigrateDestinationComment```: costruisce un oggetto Comment in Drupal.\n * ```MigrateDestinationFile```:  costruisce un File in Drupal.\n * ```MigrateDestinationNode```:  costruisce un oggetto Node in Drupal.\n * ```MigrateDestinationTerm```:  costruisce un Taxonomy term in Drupal.\n * ```MigrateDestinationUser```:  costruisce un User in Drupal.\n\nMigrate mantiene una relazione tra una determinata sorgente di dati e la sua destinazione, in modo che in caso di una modifica alla sorgente sia possibile effettuare un aggiornamento dei dati migrati consentendo quindi di aggiornare anche i dati importati in Drupal. Questo viene svolto dalla classe di **mapping**; la classe tipicamente utilizzata per questo tipo di operazioni è la classe ```MigrateSQLMap``` che mantiene questa correlazione scrivendo i dati all'interno di una tabella sullo schema SQL dell'istanza di Drupal in cui vengono importati i dati.\n\nIl meccanismo che definisce il passaggio dei dati dalla sorgente alla destinazione, mantenendo il collegamento tra le stesse attraverso un mapping e che consente la manipolazione dei dati nel passaggio è definito come **Migration**.\n\nDa questa brevissima introduziona abbiamo già identificato un subset specifico di componenti che sono coinvolti nella migrazione e sono:\n\n * La sorgente dati (spesso definita anche come ```DataSource```)\n * La destinazione dei dati (detta anche ```DestinationSoruce```)\n * Il meccanismo di mapping\n * Il meccanismo di migrazione dati (la ```Migration```)\n\n### Data Source\n\nLe sorgenti dati sono appunto il sistema che consente di leggere i dati di partenza da una sorgente esterna. Tipicamente la sorgente dati è costituita da una lista di elementi (```MigrateList```) ognuno dei quali costituisce una riga di dati da migrare (```MigrateItem```).\n\nPrendiamo ad esempio una sorgente definita come *SQL Source*, avremo una query SQL che riporta l'elenco degli oggetti da migrare, questa query restituisce l'elenco degli elementi mentre ogni singola riga dei risultati della query è un item della migrazione (in realtà vedremo in seguito che questa è vero, ma potrebbe anche essere solo un'approssimazione).\n\n#### SQL Source\n\nQualora la nostra sorgente fosse un database, quasi sicuramente ci troveremo con l'esigenza di mappare la sorgente dei dati con una query (ricordiamoci, in prima battuta dobbiamo riportare ad ogni riga un elemento da migrare).\n\nUna volta individuata la query che ci consente di avere la nostra sorgende di dati dobbiamo \"trasformarla\" nell'equivalente della query definita usando la ```SelectQueryInterface``` di Drupal, quindi ad esempio:\n\n```sql\nSELECT fname, lname, birthday FROM myapp_user WHERE birthday \u003c NOW();\n````\n\nVerrà convertita in:\n\n```php\n$query = db_select('myapp_user', 'u')\n             -\u003efields('u', array('fname', 'lname', 'birthday'));\n$query-\u003econdition('u.birtday', 'NOW()', '\u003e');\n\n$source = new MigrateSourceSQL($query);\n```\n\nUna volta costruita la query dovremmo passare questa informazione alla classe ```MigrateSourceSQL``` che costruirà la sorgente di dati usata da Migrate per effettuare la migrazione dei dati.\n\nLa signature completa del costruttore della classe riporta:\n\n```php\nMigrateSourceSQL(\n  SelectQueryInterface $query,\n  array $fields = array(),\n  SelectQueryInterface $count_query = NULL,\n  array $options = array()\n)\n```\n\nDove appunto vediamo che il primo (e unico) parametro obbligatorio è appunto la query che fa da sorgente nella nostra migrazione.\n\n#### CSV Source\n\n\nQualora la nostra sorgente fosse un file CSV dovremmo passare questa informazione alla classe ```MigrateSourceCSV``` che costruirà la sorgente di dati usata da Migrate per effettuare la migrazione dei dati.\n\nLa signature completa del costruttore della classe riporta:\n\n```php\nMigrateSourceCSV(\n  $path,\n  array $csvcolumns = array(),\n  array $options = array(),\n  array $fields = array()\n)\n```\n\nDove appunto vediamo che il primo (e unico) parametro obbligatorio è il percorso del file contenente la nostra sorgente dati. Il secondo parametro, invece, riporta l'elenco delle colonne presente nel CSV. Il sistema, nel caso in cui non sia definito, cercherà di individuare i campi presenti nel file e individuare quindi le colonne, ma per comodità è sempre preferibile esplicitare le colonne che ne fanno parte. Il terzo parametro, invece, specifica le opzioni di parsing del CSV, quindi il separatore dei campi, l'enclosure (come vengono \"racchiusi\" i campi) ed il carattere di escaping ed è anche è utilizzato per indicare la presenza di una riga di intestazione.\n\nFacciamo l'esempio di una sorgente contenente appunto nome, cognome e data di nascita, in un file CSV (con nome ```app_users.csv``` posizionato nella cartella ```data``` del nostro modulo) come di seguito riportato:\n\n```csv\nfname;lname;brithday\n\"Marco\";\"Moscaritolo\";1983-04-22\n\"Mario\";\"Rossi\";1984-09-03\n```\n\nNel nostro caso avremo:\n\n```php\n$path = drupal_get_path('module', 'biblio_import') . '/data/app_users.csv';\n\n$columns = array(\n  array('fname', 'User: First name'),\n  array('lname', 'User: Last name'),\n  array('birthday', 'User: Birthday'),\n);\n\n$options = array(\n  'delimiter' =\u003e ';',\n  'enclosure' =\u003e '\"',\n  'escape' =\u003e '\\\\',\n  'header_rows' =\u003e 1,\n);\n\n$source = new MigrateSourceCSV($path, $columns, $options);\n```\n\ndove nelle colonne è specificato come primo valore dell'array il nome della colonna, mentre nel secondo la descrizione visibile nella UI di migrate.\n\n### Destination Source\n\nSe il *Data Source* ci serviva a definire da dove prelevare i dati da migrare, con il *Destination Source* specificheremo dove le informazioni vanno a confluire all'interno di Drupal. Nella quasi totalità dei casi le destinazioni dei nostri dati sono delle entità Drupal (nodi, utenti, termini di tassonomia, ...) pertanto -come abbiamo visto in precedenza- esistono le classi di destinazione già customizzate per le principali entity di base di Drupal, con la possibilità di creare destinazioni custom ulteriori.\nVediamo ad esempio le tre principali classi di destination:\n\n#### Node\n\nPrendiamo ad esempio la classe ```MigrateDestinationNode``` che permette di definire come destinazione una entity di tipo ```Node```, questa classe accetta come parametro il node type dell'entità che deve essere costituita (il bundle), per istanziare una destinazione di nodo, quindi è necessario costruirla specificando questo parametro, ad esempio:\n\n```php\n$destination = new MigrateDestinationNode('biblio_doc');\n```\nQuesto indica al sistema che per ogni riga sorgente avremo una entity di tipo node di tipo *biblio_doc* creata.\n\n#### User\n\nAllo stesso modo la classe ```MigrateDestinationUser``` definisce che l'entity che viene creata è di tipo utente; in questo caso non è necessario specificare ulteriori parametri:\n\n```php\n$destination = new MigrateDestinationUser();\n```\n\n#### Termine della tassonomia\n\nPrendiamo ad esempio la classe ```MigrateDestinationTerm``` che permette di definire come destinazione una entity di tipo ```TaxonomyTerm```, questa classe accetta come parametro il machine name del vocabolario a cui il termini creato deve appartenere, quindi ad esempio:\n\n```php\n$destination = new MigrateDestinationTerm('biblio_book_type');\n```\n\nVi è un secondo parametro usato per la gestione dei duplicati, in caso di necessità vi rimandiamo alla documentazione per approfondire i valiri delle opzioni.\n\n### Mapping\n\nCome abbiamo detto precedentemente Drupal mantiene un collegamento tra la sorgente e la destinazione (l'entity di Drupal creata) della migrazione, per fare questo viene usato un mapping, mapping che solitamente viene costituito usando la classe di mapping ```MigrateSQLMap```. Questa classe ha la seguente firma del costruttore:\n\n```php\nMigrateSQLMap(\n  $machine_name,\n  array $source_key,\n  array $destination_key,\n  $connection_key = 'default',\n  $options = array()\n)\n```\nDove il primo parametro indica il nome identificativo del mapping, solitamente questo valore corrisponde con in nome della migrazione corrente, ma può essere variato in alcune situazioni, ad esempio per avere migrazioni differenti ma con un unica tabella di mapping. Solitamente il valore usato per definire il machine name è la proprietà ```machineName``` della migrazione corrente.\n\nIl secondo parametro (```$source_key```) identifica le chiavi delle sorgenti usate come chiavi identificative della l'elemento della sorgente. A scopo di esempio, supponiamo che l'elenco di utenti usato come esempio precedentemente non consenta l'omonimia, per constraddistinguere in maniera univoca un utente è necessario la coppia *fname/lname*, pertanto la nostra chiave sorgente sarà definita come costituita da queste due chiavi. Per ognuna delle chiavi poi dovranno essere definiti gli attributi della colonna SQL necessari ad archiviare questo dato, nel nostro esempio avremo qualcosa di simile a:\n```php\n$source_key = array(\n  'fname' =\u003e array(\n    'type' =\u003e 'varchar',\n    'length' =\u003e 255,\n    'not null' =\u003e TRUE,\n    'description' =\u003e 'User first name'\n  ),\n  'lname' =\u003e array(\n    'type' =\u003e 'varchar',\n    'length' =\u003e 255,\n    'not null' =\u003e TRUE,\n    'description' =\u003e 'User last name'\n  ),\n);\n```\n\nLa stessa cosa viene effettuata per la ```$destination_key``` con la differenza che in questo caso andremo ad usare la chiave primaria dell'entity creata durante la migrazione, ad esempio per gli utenti andremo ad usare l'uid. Per semplificare la definizione tutte le destination source definiscono un metodo statico ```getKeySchema``` che serve a restituire appunto la definizione della destination key, quindi per l'utente avremo:\n\n```php\n$destination_key = MigrateDestinationUser::getKeySchema();\n```\n\nDi coneguenza la nostra migration map sarà simile a:\n\n```php\n$map = new MigrateSQLMap(\n  $this-\u003emachineName,\n  array(\n    'fname' =\u003e array(\n      'type' =\u003e 'varchar',\n      'length' =\u003e 255,\n      'not null' =\u003e TRUE,\n      'description' =\u003e 'User first name'\n    ),\n    'lname' =\u003e array(\n      'type' =\u003e 'varchar',\n      'length' =\u003e 255,\n      'not null' =\u003e TRUE,\n      'description' =\u003e 'User last name'\n    ),\n  ),\n  MigrateDestinationUser::getKeySchema()\n);\n```\n\n\n### Migration\n\nArriviamo ora al collante di tutto ciò che abbiamo visto fino ad ora, la classe di migrazione. Questa classe tipicamente estende la classe base di migration ```Migration``` e implementa nel costruttore tutte le configurazioni necessarie, a solo scopo esemplificativo:\n\n```php\nclass BiblioUserMigrate extends Migrate {\n  public function __construct($arguments) {\n    parent::__construct($arguments);\n\n    // Mapping =================================================================\n    $this-\u003emap = new MigrateSQLMap(\n      $this-\u003emachineName,\n      array(\n        'fname' =\u003e array(\n          'type' =\u003e 'varchar',\n          'length' =\u003e 255,\n          'not null' =\u003e TRUE,\n          'description' =\u003e 'User first name'\n        ),\n        'lname' =\u003e array(\n          'type' =\u003e 'varchar',\n          'length' =\u003e 255,\n          'not null' =\u003e TRUE,\n          'description' =\u003e 'User last name'\n        ),\n      ),\n      MigrateDestinationUser::getKeySchema()\n    );\n\n    // Source ==================================================================\n    $path = drupal_get_path('module', 'biblio_import') . '/data/app_users.csv';\n\n    $columns = array(\n      array('fname', 'User: First name'),\n      array('lname', 'User: Last name'),\n      array('birthday', 'User: Birthday'),\n    );\n\n    $options = array(\n      'delimiter' =\u003e ';',\n      'enclosure' =\u003e '\"',\n      'escape' =\u003e '\\\\',\n      'header_rows' =\u003e 1,\n    );\n\n    $this-\u003esource = new MigrateSourceCSV($path, $columns, $options);\n\n    // Destination =============================================================\n    $this-\u003edestination = new MigrateDestinationUser();\n  }\n}\n```\n\ndove come possiamo vedere abbiamo usato le classi di source, destination e mapping viste in precedenza, assegnandone il valore a delle proprietà della classi migrate, in particolare alle proprietà ```map```, ```source``` e ```destination```.\n\n#### Modificare i dati in ingresso\n\nQualche volta i dati in ingresso hanno necessità di essere modificati o di essere estesi, ad esempio per creare dati aggiuntivi. Nell'esempio che abbiamo preso in considerazione fino ad ora nell'importazione dell'utente -ad esempio- non abbiamo un attributo definito come username, che vogliamo corrisponda con nome e cogonome, in minuscolo, separati da un punto. Per fare questo possiamo sfruttare il metodo ```prepareRow``` della migrazione. Questo metodo permette di alterare i dati in ingresso per ottenere le informazioni che riteniamo necessarie, ad esempio:\n\n```php\nclass BiblioUserMigrate extends Migrate {\n  public function __construct($arguments) {\n    // ...\n    $this-\u003eaddFieldMapping('username', 'generated_username');\n  }\n\n  public function prepareRow(\u0026$row) {\n    $row-\u003egenerated_username = strtolower($row-\u003efname . '.' . $row-\u003elname);\n  }\n}\n```\n\nLa stessa funzione può anche essere utilizzata per evitare che un determinato record venga migrato; per fare questo è sufficiente che la funzione ritorni false. Nel nostro esempio vogliamo escludere l'importazione dei dati dove la lunghezza del nome o del cognome è minore di 3 caratteri perché probabilmente si tratta di un dato fasullo; la nostra implementazione diventerebbe:\n\n```php\nclass BiblioUserMigrate extends Migrate {\n  // ...\n\n  public function prepareRow(\u0026$row) {\n    if (strlen($row-\u003efname) \u003c 3 || strlen($row-\u003elname) \u003c 3) {\n      return FALSE;\n    }\n\n    // ...\n  }\n}\n```\n\n### Field mapping\n\nCon le informazioni minime viste in precedenza la nostra migrazione è effetivamente utilizzabile, ma manca ancora un ultimo step molto importante, ovvero il mapping delle informazioni estratte nella sorgente con quelle della destinazione. Questa operazione viene effettuata usando il metodo ```addFiedlMapping``` della classe di migrazione.\n\nQuesto metodo ha la seguente firma:\n\n```php\naddFieldMapping(\n  $destination_field,\n  $source_field = NULL,\n  $warn_on_override = TRUE\n);\n```\n\nDove il primo valore indica il nome del field di destinazione, ovvero la proprietà dell'entità di destinazione in cui le informazioni verrano inserite. Queste proprietà possono essere proprietà tipiche dell'entity di destinazione (ad esempio username o password per l'utente) o i machine name dei valori dei field. Supponendo che abbiamo inserito sull'utente in drupal tre field, due testuali e uno di tipo date, i cui machine name saranno:\n\n * field_user_fname\n * field_user_lname\n * field_user_birthday\n\nIl secondo valore indica il nome nella sorgente, ad esempio il nome della colonna nelle migrazioni da CSV come sorgente o il nome del campo della tabella risultante come query in caso di sorgenti SQL.\n\nL'ultimo valore in input indica se scatenare un warn nel caso in cui la migrazione effettui il mapping due volte della stessa property.\n\nIl field mapping della migrazione sopra definita risulterà quindi simile a:\n\n```php\n$this-\u003eaddFieldMapping('field_user_fname', 'fname');\n$this-\u003eaddFieldMapping('field_user_lname', 'lname');\n$this-\u003eaddFieldMapping('field_user_birthday', 'birthday');\n```\n\ndove appunto stiamo inserendo i valori delle colonne dei campi CSV dentro i field dell'entity di Drupal.\n\n#### Valori di default\n\nCome potete ben immaginare non sempre tutti i campi delle entità di destinazione sono presenti nei dati di partenza, quindi potrebbe essere necessario predisporre dei valori predefiniti per alcuni di essi, ad esempio per gli utenti potremmo voler specificare che questi utenti devono essere attivi e che la data di creazione e modifica non è la data corrente, ma il 1 gennaio 2015.\n\nPer fare questo è possibile mappare, usando la funzione già vista in precedenza, solamente il campi di destinazione e utilizzare poi il metodo ```defaultValue```, quindi nel nostro caso avremo:\n\n```php\n$this-\u003eaddFieldMapping('status')-\u003edefaultValue(1);\n$this-\u003eaddFieldMapping('created')-\u003edefaultValue(strtotime('2015-01-01'));\n```\n\n#### Valori multipli\n\nNel momento in cui abbiamo necessità di avere dei valori multipli associati ad un singolo field, ad esempio perché all'utente abbiamo assegnato assegnato un campo di tipo testo multiplo (chiamato ```field_user_notes```) in cui vengono inserite alcune note. Nel nostro CSV di partenza, essendo che per ogni elemento migrato (quindi ogni utente) dobbiamo avere una sola riga, avremo le diverse note concatenate con un carattere separatore, ad esempio il carattere ```|```. Il nostro fil CSV diventerebbe qui:\n\n```csv\nfname;lname;brithday;notes\n\"Marco\";\"Moscaritolo\";1983-04-22;\"Prima nota|Seconda nota\"\n\"Mario\";\"Rossi\";1984-09-03;\"Terza nota|Quarta nota|Quinta nota\"\n```\n\nPer far si che questo venga interpretato correttamente durante la migrazione useremo il metodo ```separator```, specificando come argomento il carattere da usare -appunto- come separatore:\n\n```php\n$this-\u003eaddFieldMapping('field_user_notes', 'notes')-\u003eseparator('|');\n```\n\n#### Callbacks\n\nCosa succede invece quando il valore di una proprietà non è corrispondente al valore sorgente, ma dobbiamo procedere con una modifica (ad esempio dobbiamo convertire il formato della data)? Ci viene in aiuto l'utilizzo delle callback che servono appunto a processare un dato in ingresso prima che questo venga preso in considerazione dalla migrazione, ma senza modificare il dato della sorgente, ovvero mantenendo l'informazione originale come dato di sorgente.\n\nNel nostro esempio precedente, per la data avremo:\n\n```php\n$this-\u003eaddFieldMapping('field_user_birthday', 'birthday')-\u003ecallbacks('strtotime');\n```\n\ndove stiamo dicendo che prima di assegnare alla proprietà ```field_user_birthday``` dell'utente il valore presente nel campo ```birthday``` della sorgente, andremo a passare questo valore attraverso la funzione ```strtotime``` di PHP, ovvero faremo un operazione simile a:\n\n```php\n$destination-\u003efield_user_birthday = strtotime($source-\u003ebirthday);\n```\n\nQualora avessimo necessità di svolgere operazioni più complesse, potremmo dichiarare all'interno della nostra classe di migrazione un metodo pubblico e usare questo come callback, ad esempio:\n\n```php\nclass BiblioUserMigrate extends Migrate {\n  public function __construct($arguments) {\n    // ...\n    $this-\u003eaddFieldMapping('field_user_birthday', 'birthday')\n      -\u003ecallbacks(array($this, 'convertBirthday'));\n  }\n\n  public function convertBirthday($data) {\n    // Faccio quello che serve...\n    return strtotime($data);\n  }\n}\n```\n\n#### Dipendenze tra migrazioni\n\nSpesso capita che determinate migrazioni dipendano da altri informazioni che devono essere migrate, ad esempio potremmo voler taggare i nostri utenti con dei tag che sono a loro volta importati da un altra migrazione, ad esempio se consideriamo i nostri utenti della bilbioteca potremmo avere diverse categorie di generi lettari e vorremo taggare gli utenti con i generi letterari che preferiscono.\n\nLa sorgente delle categorie letterarie, sempre da CSV, risulta quindi essere:\n\n```csv\ncategory\n\"Romanzo\"\n\"Sci-fi\"\n\"Saggio\"\n\"Fantasy\"\n```\n\nE la corrispettiva migrazione, che importa questi tag all'interno del vocabolario ```book_category```:\n\n```php\nclass BiblioCategoryMigrate extends Migrate {\n  public function __construct($arguments) {\n    parent::__construct($arguments);\n\n    // Mapping =================================================================\n    $this-\u003emap = new MigrateSQLMap(\n      $this-\u003emachineName,\n      array(\n        'category' =\u003e array(\n          'type' =\u003e 'varchar',\n          'length' =\u003e 255,\n          'not null' =\u003e TRUE,\n          'description' =\u003e 'Book category'\n        ),\n      ),\n      MigrateDestinationTerm::getKeySchema()\n    );\n\n    // Source ==================================================================\n    $path = drupal_get_path('module', 'biblio_import') . '/data/book_category.csv';\n\n    $columns = array(\n      array('category', 'Book category'),\n    );\n\n    $options = array(\n      'delimiter' =\u003e ';',\n      'enclosure' =\u003e '\"',\n      'escape' =\u003e '\\\\',\n      'header_rows' =\u003e 1,\n    );\n\n    $this-\u003esource = new MigrateSourceCSV($path, $columns, $options);\n\n    // Destination =============================================================\n    $this-\u003edestination = new MigrateDestinationTerm('book_category');\n\n    // Fileds mapping ==========================================================\n    $this-\u003eaddFieldMapping('name', 'category');\n\n    // ...\n  }\n}\n```\n\nLa migrazione procede quindi creando dei termini di tassonomia, mappando come chiave della sorgente il nome del termine stesso.\n\nNella nostra sorgente di dati dobbiamo quindi avere informazioni relative alla categorie di interesse dell'utente, quindi il nostro CSV diventerà:\n\n\n```csv\nfname;lname;brithday;notes;preferences\n\"Marco\";\"Moscaritolo\";1983-04-22;\"Prima nota|Seconda nota\";\"Sci-Fi|Fantasy\"\n\"Mario\";\"Rossi\";1984-09-03;\"Terza nota|Quarta nota|Quinta nota\";\"Sci-Fi|Romanzo\"\n```\n\nE di conseguenza la migrazione degli utenti, ipotizzando che il nome del campo associato all'utente sia ```field_user_categories``` avremo:\n\n```php\n$this-\u003eaddFieldMapping('field_user_categories', 'categories')\n  -\u003eseparator('|')\n  -\u003esourceMigration('BiblioCategory');\n```\n\ncome vediamo stiamo usando nuovamente il metodo ```separator``` poiché abbiamo più di un elemento nel nostro campo, ma la parte interessante è il metodo ```sourceMigration``, che indica che migrazione usare per \"convertire\" il nostro valore di partenza con il valore identificativo dell'entità di destinazione della migrazione dipendente. Nel caso riprotato pocanzi la migrazione ```BiblioCategoryMigration``` ha migrato i dati del CSV in termini della tassonomia, salvando nella tabella di mapping la chiave della sorgente (il nome del termine) e la chiave di destinazione (l'ID del termine, il TID). Il source migration utilizza i dati salvati nella tabella di mapping per convertire il valore in ingresso (che sarà la chiave della sorgente) nella corrispettiva chiave della destinazione. questo consente di avere i TID corretti che sono quelli che vengono poi realmente referenziati all'interno della destinazione della migrazione utente.\n\n## Dichiarazione delle migrazioni\n\nUna volta costruite le migrazioni come visto fino ad ora dobbiamo \"informare\" Drupal dell'esistenza di queste migrazioni. Per fare questo dobbiamo creare un modulo che fornisca queste informazioni. Per fare questo dovremo creare un modulo (con i classici file ```info``` e ```module```). Nel file ```info``` avremo:\n\n```ini\nname = \"Biblio import\"\ndescription = \"Import biblio informations\"\npackage = \"Biblio\"\ncore = 7.x\n\ndependencies[] = migrate\n\nfiles[] = migration/biblio_category.inc\nfiles[] = migration/biblio_user.inc\nfiles[] = migration/biblio_item.inc\n```\n\nin cui, oltre alle classiche informazioni sul nome, descrizione, package e versione di Drupal, abbiamo definito una dipendenza verso il modulo ```migrate``` (che si occupa di effettuare le migrazioni) e dell'esistenza di tre file contenenti le classi di migrazioni.\n\nIl file ```module``` non necessità di particolari dichiarazioni, quindi avremo:\n\n```php\n\u003c?php\n\n/**\n * @file\n * Import biblio informations in Drupal\n */\n```\n\nOltre alla definizione del modulo creeremo il file ```NOME_MODULO.migrate.inc``` in cui andremo a definire l'implementazione dell'```hook_migrate_api``` che riporta effettivamente quali sono le migrazioni che il nostro modulo implementa, quindi:\n\n```php\n\u003c?php\n/**\n * @file\n * Our own hook implementation.\n */\n\n/**\n * Implements hook_migrate_api().\n */\nfunction biblio_import_migrate_api() {\n  $api = array(\n    'api' =\u003e MIGRATE_API_VERSION,\n    'groups' =\u003e array(\n      'biblio' =\u003e array(\n        'title' =\u003e t('Biblio'),\n      ),\n    ),\n    'migrations' =\u003e array(\n      'BiblioCategory' =\u003e array(\n        'class_name' =\u003e 'BiblioCategoryMigration',\n        'group_name' =\u003e 'biblio',\n      ),\n      'BiblioUser' =\u003e array(\n        'class_name' =\u003e 'BiblioUserMigration',\n        'group_name' =\u003e 'biblio',\n      ),\n      'BiblioItem' =\u003e array(\n        'class_name' =\u003e 'BiblioItemMigration',\n        'group_name' =\u003e 'biblio',\n      ),\n    ),\n  );\n\n  return $api;\n}\n```\n\ndove stiamo indicando che esiste un gruppo di migrazione (con machien name ```biblio```) la cui label sarà ```Biblio```, e tre migrazioni in cui indichiamo per ogni machine name quale è la classe di migrazione che definisce la migrazione e a quale gruppo questa migrazione appartiene.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmavimo%2Fbiblio_import","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmavimo%2Fbiblio_import","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmavimo%2Fbiblio_import/lists"}