Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions headless.module
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ function headless_menu() {
'access callback' => TRUE,
'page arguments' => array(3, 4),
);
// The following is for the node type where an id is not specified - to return all of the specified or a paginated subset.
$items['api/node/%'] = array(
'page callback' => 'headless_types',
'access callback' => TRUE,
'page arguments' => array(2),
);
// Return JSON for individual terms.
$items['api/%/term/%'] = array(
'page callback' => 'headless_term_item',
Expand Down Expand Up @@ -133,6 +139,51 @@ function headless_type_v2($type, $nid) {
}
}

/**
* Page callback for nodes type when no {$id} is specified - with or without pagination.
*
* Queries are in the format of :
* GET /api/node/{type}?page[number]=X&page[size]=Y
* OR
* GET /api/node/{type}
*
* @param string $type
* A string indicating the node type to query
*/
function headless_types($type) {
$opt_page_number = NULL;
$opt_page_size = NULL;

$config = config_get('headless.settings', 'node');
// Check if output is enabled... if not return an error.
if ($config[$type] != 1) {
$json_error = ['code' => 404];
backdrop_json_output($json_error);
backdrop_exit();
}

// Get any optional arguments provided -- specifically we're interested in page[number]=value and page[size]=value.
$opt_query_args = backdrop_get_query_parameters();
// Is this proper php etiquette? Can it be safely removed?
// furthermore, we ASSUME that both the page number AND page size will always be specified as a pair.
if (count($opt_query_args) > 0) {
$opt_page_number = $opt_query_args['page']["number"];
$opt_page_size = $opt_query_args['page']['size'];
}

// Validate all the optional argument possibilities. If anything looks wonky, return the specified error.
$ret_json_err = _validate_optional_values($opt_page_size, $opt_page_number);
if (is_null($ret_json_err) == FALSE) {
backdrop_json_output($ret_json_err);
backdrop_exit();
}

// Get the items to be returned in this JSON query..
$nodes_to_return = _nodes_get_node_result($type, $opt_page_size, $opt_page_number);
backdrop_json_output($nodes_to_return);
backdrop_exit();
}

/**
* Page callback for terms.
*/
Expand Down Expand Up @@ -301,3 +352,111 @@ function _views_get_view_result($name, $display_id = NULL, $args = NULL) {
return array();
}
}

/**
* Validate the various possible optional values if they're specified.
*
* Return the first issue found if any.
*
* @param int $opt_page_size
* Specifies the optional page size for paginated queries or NULL if not desired
*
* @param int $opt_page_number
* Specifies the optional page number for paginated queries or NULL if not desired
*
* @return array
* An associative array identifying the JSON error to be returned
* OR NULL if no error found
*/
function _validate_optional_values($opt_page_size, $opt_page_number) {
$ret_json_err = NULL;

// First check to see if neither were specified -- if so we can just return..
if ((is_null($opt_page_number) == TRUE) && (is_null($opt_page_size) == TRUE)) {
return $ret_json_err;
}

// Check the optional arguments to ensure both are specified and not just one.
if ((is_null($opt_page_number) == TRUE) && (is_null($opt_page_size) == FALSE)) {
// If either-or then this is considered an error and we can return one.
$ret_json_err = ['code' => 422,
'source' => "page[size] specified but NOT page[number]",
'title' => "Invalid optional argument",
'detail' => "Both Page size and Page number MUST be specified as a pair"];
return $ret_json_err;
}

if ((is_null($opt_page_number) == FALSE) && (is_null($opt_page_size) == TRUE)) {
// If either-or then this is considered an error and we can return one.
$ret_json_err = ['code' => 422,
'source' => "page[number] specified but NOT page[size]",
'title' => "Invalid optional argument",
'detail' => "Both Page size and Page number MUST be specified as a pair"];
return $ret_json_err;
}

// Check to see if either page number or page size = 0. If so return an error..
if ($opt_page_size == 0) {
$ret_json_err = ['code' => 422,
'source' => "page[size] specified as zero",
'title' => "Invalid optional argument",
'detail' => "Page size must be >0"];
return $ret_json_err;
}

if ($opt_page_number == 0) {
$ret_json_err = ['code' => 422,
'source' => "page[number] specified as zero",
'title' => "Invalid optional argument",
'detail' => "Page number must be >0"];
return $ret_json_err;
}
return $ret_json_err;
}

/**
* Issue a query to the database to get the desired nodes for the specified type.
*
* Return the nodes matching what the user wants - pagination will be done if specified by the arguments below.
*
* @param string $type
* A string specifying the node type to search for.
*
* @param int $page_size
* An integer indicating the page size to use for queries using pagination. If pagination is not desired, use NULL.
*
* @param int $page_number
* An integer indicating the page number to use for queries using pagination. If pagination is not desired, use NULL.
*
* @return bool|EntityInterface|null
* An array of nodes matching the type specified and according to the pagination values (if provided).
*/
function _nodes_get_node_result($type, $page_size, $page_number) {
// Load the requested node and check to see if types match or not.
$query = new EntityFieldQuery();
$nodes = NULL;

// If pagination is not specified, just return the entire set of nodes..
if ((is_null($page_number) == TRUE) && (is_null($page_size) == TRUE)) {
$query->entityCondition('entity_type', 'node')
->entityCondition('bundle', $type)
// Get only published items by checking the status.
->propertyCondition('status', 1);
}
else {
// If we get here we're doing a paginated query.. Figure out what range we need to use.
$start_index = ($page_size * $page_number) - $page_size;
$query->entityCondition('entity_type', 'node')
->entityCondition('bundle', $type)
// Get only published items by checking the status.
->propertyCondition('status', 1)
->range($start_index, $page_size);
}

// Do the query..
$result = $query->execute();
if (isset($result['node'])) {
$nodes = entity_load('node', array_keys($result['node']));
}
return ($nodes);
}