Drupal 8 Migrate API Process Plugins – Pt

Drupal 8 Migração de API: Migrar conteúdo de uma fonte JSON

 

Migrar API

Plugins de migração são a cola que une source (origem), destination (destino), e múltiplos process plugins (processo), todos juntos para mover informação de um sítio para outro. Geralmente referidos como modelos de migração ou simplesmente migrações. Os plugins de migração são ficheiros YAML que explicam ao Drupal onde ir buscar a informação, como a processar e onde guardar o resultado.

A migração é um processo de Extrair – Transformar – Carregar (ETC):

d8-migrate-etl-process

FONTE: Drupal.org (2019). Migrate API overview. Acedido em: 10 de julho de 2019, em: https://www.drupal.org/docs/8/api/migrate-api/migrate-api-overview

  • fase de extrair é chamada source
  • fase de transformar é chamada process
  • fase de carregar é chamada destination

Módulo de comunidade: migrate_plus

O Migrate Plus estende a funcionalidade da API de Migração do Drupal, adicionando novos recursos, como o source plugin de url, permitindo-nos fazer migrações de ficheiros com formatos JSON, XML e Soap.

Módulo de comunidade: migrate_tools

O Migrate Tools adiciona ferramentas para gerir e correr migrações. Mais importante, os seguintes comandos drush são os que vamos usar enquanto corremos as migrações:

  • migrate-status – Lista todas as migrações e os seus estados;
  • migrate-import – Corre uma migração;
  • migrate-rollback – Reverte uma migração;
  • migrate-reset-status – Repõe um estado de migração para inativo. É utilizado se algo correr mal durante o processo de migrate-import e o estado fica preso em “A importar”.

 

Exemplo de migração Json (from dados.gov.pt):

 

Uma migração JSON tem a ver com configuração

Uma migração, quando se utilizam plugins já existentes, não é mais do que um ficheiro .yml a explicar como a informação da source deve chegar à destination.

No nosso exemplo, a source será um ficheiro JSON e a nossa destination será uma entidade (node).

Foi criado um Content Type de antemão com os seguintes campos, que serão preenchidos desde o ficheiro source.

Node market:

title – Nome do mercado. Vai ser a designacao do source file.

field_coordinates – Um Geofield com as latitudes e longitudes do source file.

field_freguesia – Uma taxonomia do tipo freguesia que vai ao encontro do campo com o mesmo nome do source file.

field_id – Um identificador único que vai ao encontro do entityId do source file. Vamos usá-lo como o nosso ID de migração.

field_address – Morada do mercado que vai ao encontro do campo morada do source file.

E o vocabulário da taxonomia Freguesia que será utilizado para o campo field_freguesia também foi criado.

Módulo migrate_markets:

As migrações têm de ser anexadas a um módulo, pois vão alojar os ficheiros config.

Um módulo personalizado foi criado na pasta modules/custom.

migrate_markets.info.yml

E por baixo da pasta config/install do módulo, criaremos o nosso ficheiro de migração migrate_markets.migration.market.yml.

Informação de identificação geral

Podemos começar por definir a informação básica para a nossa migração aqui:

Destination

Também podemos ir em frente e definir o plugin de destino, já que é simples:

Isto diz à migração que ela deve colocar a informação num node. Podemos definir o tipo de node (bundle) onde ela a vai colocar, mais tarde. Na fase de processo.

Source

Para o source plugin, iremos utilizar o url plugin já mencionado, que vem com o módulo de comunidade migrate_plus.

Isto são muitas entradas diferentes, vamos passo a passo:

Plugin

Iremos utilizar o url source plugin, localizado em modules/contrib/migrate_plus/src/Plugin/migrate/source/Url.php

Este source plugin terá um fetcher e parser plugin associados a ele.

Data Fetcher

O migrate plus suporta estes data fetchers, localizados em modules/contrib/migrate_plus/src/Plugin/migrate_plus/data_fetcher:

  • file File.php
  • http Http.php

A sua utilização é bastante simples. Se tivermos a source file localmente no nosso site Drupal, utilizaremos file. Desde que tenhamos um ENDPOINT que se atualiza automaticamente num URL externo, então utilizaremos o fetcher http. Nota: Esta opção suporta Autorização. No nosso caso, o ENDPOINT é público, então não irá ser necessário. O ficheiro já nos dá um exemplo de anotação, que se pode utilizar se quisermos saber todos os valores que ele aceita.

Data Parser

Quanto a data parsers, o migrate_plus suporta os seguintes, localizados em modules/contrib/migrate_plus/src/Plugin/migrate_plus/data_parser:

  • JSON Json.php
  • SimpleXml SimpleXml.php
  • Soap Soap.php
  • Xml Xml.php

Iremos utilizar JSON nos nossos exemplos, portanto não vamos passar pelos outros.

Headers

A propriedade headers deve ser auto-explicativa e é utilizada em junção com o nosso http data fetcher. Para o nosso exemplo, vamos apenas definir os headers que preparam o pedido para receber uma resposta JSON.

URLs

Aqui definimos o(s) URL(s) da nossa source, então a migração saberá onde o(s) ir buscar. Também é bastante auto-explicativo.

Item Selector

Este será um selecionador Xpath da raiz de onde está a nossa informação. Se vires o nosso exemplo JSON acima, podes reparar que toda a nossa informação está dentro de uma matriz de chave d. Então dizemos à migração para ver dentro dessa matriz. Se a tua informação JSON já está dentro da raiz de JSON, podes definir esta como NULL.

Fields

fields é uma matriz que vai quase como servir de ponte entre os campos JSON em variáveis que podemos usar no nosso process plugin.

Eles devem ter um name, que nos deixará referenciá-los no ficheiro de migração.

A label é utilizada maioritariamente como identificador para qualquer UI a lidar com migrações.

O selector, muito parecido à propriedade anterior, item selector, é um selecionador xPath que indica onde é que está o field na nossa source.

ID

A propriedade id vai combinar com o nosso identificador único para esta migração. Esta irá assegurar que, quando corremos de novo uma migração, os itens que já foram processados, não serão processados outra vez.

 

Uma forma fácil de olhar para isto é percebendo que o source plugin, deve responder à seguintes questões:

Where (de onde) vem a source? Definido na propriedade urls.

What (o que é que) estou a receber da source? Definido utilizando a propriedade fields.

How (como) devo receber a informação da source? Definido utilizando todas as outras propriedades.

Process

O único passo que falta configurar é o nosso process plugin.

Aqui, definimos como cada campo de source deve ser processado pelo Drupal, antes de acabarem como campos para o nosso node de destination.

Cada campo terá, pelo menos, um process plugin a ele associado. Se não definires explicitamente um plugin e só fizeres o mapeamento entre o campo destination do Drupal e o campo source como o nosso title, por exemplo:

title: title

Então, como padrão, o plugin get vai ser utilizado. É um plugin bastante básico que indica que não é preciso nenhum processamento do campo JSON, e que o campo deve ser introduzido como está. Então, pegando no exemplo anterior, seria assim:

A key deve ser o campo de nome destination (no nosso caso, um node), enquanto o valor deve ser o atributo name na nossa matriz de source field.

Alguns campos irão requerer o uso de um process plugin. Por exemplo, para definir o nosso tipo de node, neste exemplo, vamos codificar o bundle do node (que é como quem diz, nome de máquina de Content Type), desde que sabemos que estes nodes devem ser todos do tipo market.

Podemos utilizar o plugin default_value para isto, se não é dada nenhuma source ou se o valor da source voltar vazio (útil para campos que podem não estar definidos para todos os objetos JSON, mas precisam de ter sempre um valor na nossa Drupal Entity).

Estamos a utilizar dois process plugins, de comunidade, um do módulo migrate_plus, chamado entity_generate, e outro do módulo geofield, chamado geofield_latlon.

O plugin geofield_latlon é muito simples. Ele pega nos valores de latitude e longitude (que definimos nos nossos source fields) e cria um GeoField com eles.

O plugin entity_generate vai:

  • Procurar por um taxonomy_term do tipo “freguesia”, e combinar o source field *“freguesia” com o nome da taxonomia.
  • Se já existir uma taxonomia com esse nome, essa será a utilizada.
  • Se não, será criada uma com esse nome.

No nosso exemplo de migração, não iremos utilizar process plugins, personalizados, mas se os plugins disponíveis do Core e o Migrate Plus module não corresponderem exatamente às tuas necessidades, podes facilmente, fazer o teu.

E é isto! O nosso ficheiro migrate_markets.migration.market.yml deverá parecer-se com isto:

Tudo o que falta é ativar o nosso módulo com drush en migrate_markets e, se tudo correu bem, devemos poder já ver a nossa migração a aparecer utilizando drush migration-status:

Screenshot from 2019-06-27 12-11-57

Podemos correr a nossa migração utilizando drush migration-import market. Quando lidamos com um grande número de entidades de migração, é recomendado utilizar a flag limitadora com um número pequeno, por exemplo --limit=10 ou semelhante, quando se corre a migração pela primeira vez, para testar que tudo corre bem.

Screenshot from 2019-06-27 12-12-59

Nota: Utilizamos o Lando como o nosso ambiente de desenvolvimento, pelo que os nossos comandos de consola têm o lando a eles anexado. A não ser que o estejas a utilizar também, provavelmente não precisarás de escrever isto.

 

E é isso! Acabámos de carregar o nosso website com todos os Mercados da região da Amadora. Poderíamos utilizar essa informação para mostrar um mapa de todos os mercados pela Amadora, por exemplo:

Screenshot_2019-07-01 Homepage Mercados Amadora

Ou a listar todos os Mercados de uma Freguesia específica:

Screenshot_2019-07-01 Mina de Água Mercados Amadora

Fontes / Links úteis