Skip to content

Instantly share code, notes, and snippets.

@laradevitt
Last active June 13, 2022 14:36
Show Gist options
  • Save laradevitt/6ab86bf7ebbd3215b20b to your computer and use it in GitHub Desktop.
Save laradevitt/6ab86bf7ebbd3215b20b to your computer and use it in GitHub Desktop.
Extends Drupal Services module to handle requests on node resource containing path alias instead of node id.
name = Services Node Alias to System Path
description = Uses the Services API to convert requests containing a node path alias to a system path (e.g., 'node/5').
core = 7.x
version = 7.x-1.0
<?php
/**
* @file
* Code for the Services Node Alias to System Path module.
*/
/**
* Implements hook_services_resources_alter().
*
* In order to handle aliases with multiple parts (e.g. about/media), the
* string in the request should have slashes converted to triple dashes (---).
*/
function services_node_alias_to_system_path_services_resources_alter(&$resources, &$endpoint) {
$args = array(
'name' => 'alias',
'optional' => FALSE,
'source' => array('path' => 0),
'type' => 'string',
'description' => 'The alias node to get',
);
$resources['node']['operations']['retrieve']['args'] = array($args);
$resources['node']['operations']['retrieve']['callback'] = '_services_node_alias_to_system_path_retrieve';
$resources['node']['operations']['retrieve']['access callback'] = '_services_node_alias_to_system_path_node_resource_access';
$resources['node']['operations']['retrieve']['access arguments append'] = TRUE;
}
function _services_node_alias_to_system_path_retrieve($alias){
$nid = _services_node_alias_to_system_path_find_nid($alias);
if ($nid) {
return _node_resource_retrieve($nid);
}
return FALSE;
}
function _services_node_alias_to_system_path_node_resource_access($op, $alias) {
$nid = _services_node_alias_to_system_path_find_nid($alias[0]);
if ($nid) {
return _node_resource_access($op, array($nid));
}
return services_error(t('Content could not be found.'), 404);
}
/**
* Helper function.
*/
function _services_node_alias_to_system_path_find_nid($alias) {
// Convert dashes to slashes.
$alias = str_replace('---', '/', $alias);
// Look up internal path.
$path = drupal_get_normal_path($alias);
// If drupal_get_normal_path() returns the alias, equate this to FALSE (no
// internal path available).
$is_node = $path !== $alias;
if ($is_node && ctype_digit($nid = str_replace('node/', '', $path))) {
return $nid;
}
return FALSE;
}
@cavla
Copy link

cavla commented Jun 10, 2022

I know it might be a bit late, but I thought I'd share.
I got something working based on your gist.

Basically, I added more arg to the resource alteration to make it work with the node path alias.

The number of arguments to add depends on your URL patterns (5 in the code below)

Query URL: GET <root domain> / <endpoint> / node / <path alias>

example.com/endpoint/node/pathalias1/pathalias2/.../titlenode

function YOUR_MODULE_services_resources_alter(&$resources, &$endpoint) {

  if (isset($endpoint) && $endpoint->name == 'YOUR_ENDPOINT_PATH') {

    if (isset($resources['node']['operations']['retrieve'])) {
      
      $resources['node']['operations']['retrieve'] = array(
          'help' => 'Retrieve a node with a path !',
          'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
          'callback' => 'YOUR_MODULE_node_resource_retrieve',
          // Add as many arg as needed depending on URL patterns
          'args' => array(
            array(
              'name' => 'arg0',
              'optional' => TRUE,
              'source' => array(
                'path' => '0'
              ),
              'type' => 'string',
              'description' => 'The argument 0 of the path of the node to retrieve',
            ),
            array(
              'name' => 'arg1',
              'optional' => TRUE,
              'source' => array(
                'path' => '1'
              ),
              'type' => 'string',
              'description' => 'The argument 1 of the path of the node to retrieve',
            ),
            array(
              'name' => 'arg2',
              'optional' => TRUE,
              'source' => array(
                'path' => '2'
              ),
              'type' => 'string',
              'description' => 'The argument 2 of the path of the node to retrieve',
            ),
            array(
              'name' => 'arg3',
              'optional' => TRUE,
              'source' => array(
                'path' => '3'
              ),
              'type' => 'string',
              'description' => 'The argument 3 of the path of the node to retrieve',
            ),
            array(
              'name' => 'arg4',
              'optional' => TRUE,
              'source' => array(
                'path' => '4'
              ),
              'type' => 'string',
              'description' => 'The argument 4 of the path of the node to retrieve',
            ),            
          ),
          'access callback' => 'YOUR_MODULE_node_resource_access',
          'access arguments' => array('view'),
          'access arguments append' => TRUE,
        );
    }
  }  
}

function YOUR_MODULE_node_resource_access($op = 'view', $args = array()) { 

  // Access logic here 
  // In the module services, _node_resource_access expects node/$nid  
  return true;
}

function YOUR_MODULE_node_resource_retrieve($arg0, $arg1, $arg2, $arg3, $arg4) {
  
  // Retrieve path by joining arguments
  $alias = join('/', array_filter(array($arg0, $arg1, $arg2, $arg3, $arg4)));

  // Look up internal path. 
  $path = drupal_get_normal_path($alias);

  // Check if the alias  exists and the current user has access to it.
  if (!drupal_valid_path($path)) {
    return FALSE;
  }
  
  // If drupal_get_normal_path() returns the alias, equate this to FALSE (no
  // internal path available).
  $is_node = $path !== $alias;
  
  if ($is_node && ctype_digit($nid = str_replace('node/', '', $path))) {
      $node = node_load($nid);
      if ($node) {
        $uri = entity_uri('node', $node);
        $node->path = url($uri['path'], array('absolute' => TRUE));
        // Unset uri as it has complete entity and this
        // cause never ending recursion in rendering.
        unset($node->uri);
      }
      //Lets check field_permissions
      $node = services_field_permissions_clean('view', 'node', $node);
      return $node;
  }
  return FALSE;
}

@laradevitt
Copy link
Author

@cavla Thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment