Resolviendo node.save en Services

El módulo services viene con algunos servicios por default. Node Service pone a nuestra disposición varios servicios relativos a nodos. Uno de ellos es node.save.

node.save permite publicar un nodo desde otro site. En particular, otro site Drupal.

Sin Keys
Servidor
Suponiendo que el site donde queremos publicar es http://myserver.example.com, allí se instala services. Hay que activar los módulos:
  • Services
  • XMLRPC Server
  • Node Service
En la interfaz de administración (admin/build/services), en la pestaña Browse, puede navegar por los servicios disponibles.

Como está activado Node Service, estarán disponibles:
  • node.view
  • node.get
  • node.save
  • node.delete
Cuando elige un servicio, se le mostrará su sintaxis y un formulario de prueba. En el caso de node.save, se requiere como parámetro un array node.

Como la publicación se hará como usuario anónimo, hay que darle los permisos necesarios para crear el tipo de nodo que deseamos. Por ejemplo, si queremos crear de este modo un nodo de tipo 'job', entonces habrá que darle a los usuarios anónimos permiso para eso. Además del permiso load node data del módulo node_service.

Cliente
En algún módulo del cliente, podrá usar un código similar a:

function mymodule_job_plandevuelo_publicar($nid) {
  $plandevuelo_url = 'http://myserver.example.com/';
  $node = node_load($nid);
  $node->type = 'job';
  unset($node->nid);
  $xmlrpc_result = xmlrpc($plandevuelo_url.'xmlrpc.php', 'node.save', $node);
  return $xmlrpc_result;
}

En este ejemplo, el cliente obtiene, de sus propias tablas, un nodo con nid especificado. Luego, usa la función xmlrpc para llamar al servicio node.save en el servidor.

Notar que el url es el del archivo xmlrpc.php del servidor. También que el nombre del service es el segundo parámetro de xmlrpc(). A partir de allí, los parámetros restantes son pasados en el mismo orden a la función que atiende el servicio, en el servidor. Así que $node será el primer parámetro para la función que atiende node.save.

Aunque es importante seguir las reglas del service, a veces puede ser frustrante. Por ejemplo, para crear un nuevo nodo, el service requiere que el nodo no tenga nid. Si lo tiene, se obtiene un mensaje de Acceso Denegado. También requiere que se indique el tipo del nodo ('job', en este ejemplo).

Con Keys
Servidor
Se configura el servidor como en el caso Sin Keys.

Se requiere activar, además, los módulos:
  • Key Authentication
  • System Service
También, en la interfaz de administración (admin/build/services), en la pestaña Opciones, elegir en el combo que el módulo de autentificación es Key authentication.

Si marca la casilla Use keys, cuando guarde las opciones, aparecerá una pestaña Keys donde puede definir llaves para limitar el acceso a services por dominio.

Por ejemplo, podría definir una llave My Client, para el dominio myclient.example.com, marcando alli node.save y otros servicios que se deseen.

Deje marcada la casilla Use sessid para usar incluir un session id en la identificación. El session id se obtiene con ayuda del servicio system.connect.

Entrando a Browse y eligiendo node.save, podrá ver que la sintaxis ha cambiado y requiere más parámetros antes del node.

a) Si dejó desmarcada la opción Use keys, node.save requerirá dos parámetros:
  1. sessid
  2. node
b) Si dejó marcada la opción Use keys, node.save requerirá seis parámetros:
  1. hash
  2. domain_name
  3. domain_time_stamp
  4. nonce
  5. sessid
  6. node
Cliente

a) Sin Use keys
Si se dejó desmarcada la opción Use keys en el servidor, en el cliente se podrá usar un código similar a:

function mymodule_job_plandevuelo_publicar($nid) {
  $plandevuelo_url = 'http://myserver.example.com/';
  $node = node_load($nid);
  $node->type = 'job';
  unset($node->nid);

  $domain_name = $_SERVER['HTTP_HOST'];
  $domain_time_stamp = (string) time();

  // connect
  $method = 'system.connect';
  $xmlrpc_result = xmlrpc($plandevuelo_url.'xmlrpc.php', $method);
  $sessid  = $xmlrpc_result['sessid'];

  // save
  $method = 'node.save';
  
  $xmlrpc_result = xmlrpc($plandevuelo_url.'xmlrpc.php', $method,
    $sessid,
    $node
  );
  
  return $xmlrpc_result;
}

Notar que ahora se requiere invocar a system.connect para obtener sessid.

b) Con Use keys
Si se dejó marcada la opción Use keys en el servidor, podrá usar un código similar a:

function mymodule_job_plandevuelo_publicar($nid) {
  $plandevuelo_url = 'http://myserver.example.com/';
  $node = node_load($nid);
  $node->type = 'job';
  unset($node->nid);

  $domain_name = $_SERVER['HTTP_HOST'];
  $domain_time_stamp = (string) time();

  // connect
  $method = 'system.connect';
  $xmlrpc_result = xmlrpc($plandevuelo_url.'xmlrpc.php', $method);
  $sessid  = $xmlrpc_result['sessid'];

  // save
  $method = 'node.save';
  $nonce = user_password();
  $domain_time_stamp = (string) time();
  $hash = hash_hmac('sha256', $domain_time_stamp .';'.$domain_name .';'. $nonce .';'.$method, '90a84268ba54e7ea02571524586997db');
  
  $xmlrpc_result = xmlrpc($plandevuelo_url.'xmlrpc.php', $method,
    $hash,
    $domain_name,
    $domain_time_stamp,
    $nonce,
    $sessid,
    $node
  );
  
  return $xmlrpc_result;
}

Una forma de hacer update

node.save requiere el $node->nid y además un $node->changed actualizado, por ejemplo:

...
  /* // CREATE
  $node->type = 'job';
  unset($node->nid);
  */
  // UPDATE
  $node->nid = 16;
  $node->changed = time();
...

Algunas precauciones
Aunque en este ejemplo he pasado a node.save casi directamente el $node que obtenía con node_load(), he notado que puede ser más conveniente formar un array con sólamente los valores requeridos y pasar recién ese array a node.save.

De otro modo, puede tener resultados inesperados. Por ejemplo, si el nodo en el local no tiene habilitado la opción de comentarios, mientras que en el destino se desea que sí lo tenga, si uno pasa el node completo se pasan también esas preferencias. Crearía un nodo sin la opción de comentarios o, al actualizar, eliminaría los comentarios que se le hubieran asociado.

Referencias:

Comentarios

Entradas populares de este blog

Debug con Xdebug y Aptana (y Notepad++)

Drupal sí, drupal no

CSS3 para mejorar el breadcrumb de un tema Zen