Drupal: Importar y sincronizar desde un JSON local o remoto con Migrate
Con archivos JSON tenemos dos posibles casos:
- Un JSON simple
- Y proporcionando dos archivos: uno que provea los ID y otro archivo que contenga la información de un item específico. Esta última opcion es especialmente util para atacar API’s que por ejemplo en /posts entrega un listado de ID’s y en /posts/:id proporciona un item especifico.
Primera forma: un JSON simple
Digamos que nuestro archivo json tiene esta pinta:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[ { "post_id": "1000", "title": "Post de blog 1", "content": "Este es el contenido del post 1", "createdDate": "2013-06-15T23:39:27.433Z" }, { "post_id": "1001", "title": "Post de blog 2", "content": "Este es el contenido del post 2", "createdDate": "2013-06-16T23:39:27.433Z" }, { "post_id": "1002", "title": "Post de blog 3", "content": "Este es el contenido del post 3", "createdDate": "2013-06-17T23:39:27.433Z" }, { "post_id": "1003", "title": "Post de blog 4", "content": "Este es el contenido del post 4", "createdDate": "2013-06-18T23:39:27.433Z" } ] |
Como se ve no es mas que un array de objetos. De hecho hacer un migrator que lo procese no difiere mucho de lo que hicimos con los XML, CSV y DB’s:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php class MigrationFromJSON extends Migration { public function __construct($arguments) { parent::__construct($arguments); $module_path = DRUPAL_ROOT . '/' . drupal_get_path('module', 'mimodulo'); $json_file = $module_path . '/json/posts.json'; $this->source = new MigrateSourceJSON($json_file, 'post_id', array(), array("track_changes" => TRUE)); $this->destination = new MigrateDestinationNode('page'); $this->map = new MigrateSQLMap($this->machineName, array( 'post_id' => array( 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, ), ), MigrateDestinationNode::getKeySchema() ); $this->addFieldMapping('uid')->defaultValue(1); $this->addFieldMapping('title', 'title'); $this->addFieldMapping('body', 'content'); $this->addFieldMapping('created', 'createdDate'); } } |
Lo único que cambia en este migrator es obviamente el $this->source (MigrateSourceJSON). El resto se mantiene como en las anteriores implementaciones.
Segunda forma: API style
Para este ejemplo he colgado las siguientes URL:
Obtener el listado de post a importar:
http://ecapy.com/Archivos/API-style/ids.json
Posts individuales:
- http://ecapy.com/Archivos/API-style/posts/2fed35eaa9839ad7.json
- http://ecapy.com/Archivos/API-style/posts/5862cff98c7d68e2.json
- http://ecapy.com/Archivos/API-style/posts/33a01947248498de.json
Mientras este blog exista ahí las voy a dejar para que hagamos pruebas de este tipo de llamadas cuando haga falta.
Bien, entonces tenemos este caso en el que en una URL recibimos todos los ID de los post que queremos importar, y luego tenemos que ir llamando uno a uno los archivos JSON con el contenido de estos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php class MigrationFromJSON_API_Style extends Migration { public function __construct($arguments) { parent::__construct($arguments); $list_url = 'http://ecapy.com/Archivos/API-style/ids.json'; $item_url = 'http://ecapy.com/Archivos/API-style/posts/:id.json'; $this->source = new MigrateSourceList( new MigrateListJSON($list_url), new MigrateItemJSON($item_url, array()), array(), array("track_changes" => TRUE) ); $this->destination = new MigrateDestinationNode('page'); $this->map = new MigrateSQLMap($this->machineName, array( 'id' => array( 'type' => 'varchar', 'length' => 20, 'not null' => TRUE, ), ), MigrateDestinationNode::getKeySchema() ); $this->addFieldMapping('uid')->defaultValue(1); $this->addFieldMapping('title', 'title'); $this->addFieldMapping('body', 'content'); } } |
La gran diferencia con respecto a todos los migrators que hemos creado hasta ahora está en $this>source:
1 2 3 4 5 6 |
$this->source = new MigrateSourceList( new MigrateListJSON($list_url), new MigrateItemJSON($item_url, array()), array(), array("track_changes" => TRUE) ); |
Estamos usando MigrateSourceList() que está justamente indicada para este tipo de casos. Como parametros estan bastante claros asi que no los explico.
Lo unico que si que quiero que presten atención es en $item_url. En este string hay un token (:id) y es porque el migrador a medida que vaya iterando los id que haya encontrado, va a generar la url desde la que se supone que tiene que obtener el contenido, y va a aplicar el ID sobre esa URL base que le hemos dado usando el token :id como placeholder.
La importación de JSON tiene mucho juego. Pueden ver como hacer cosas mas locas en https://drupal.org/node/1152160.
Chau!