Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
442 lines (400 sloc) 11.7 KB
<?php
// $Id$
/**
* @file
* Core functionality for the Set module.
*/
//TODO: What happens when something is added to or removed from a set?
/**
* Implementation of hook_theme().
*/
function sets_theme() {
return array(
'sets_help' => array(
'arguments' => array()
),
);
}
/**
* Builds a formatted list of sets and descriptions.
*
* @return
* An HTML table containing the formatting docs.
*/
function theme_sets_help() {
$sets = sets_list_sets();
$headers = array(t('Set'), t('Description'));
$rows = array();
foreach ($sets as $set) {
$rows[] = array(
'[' . $set['tag'] . ']',
$set['description'],
);
}
$output = theme('table', $headers, $rows, array('class' => 'description'));
return $output;
}
/**
* Return all Set-tags in a string
*
* @param $string
* The string to search for Set tags in
* @return
* Array of tag names.
*/
function sets_string_get_tags($string) {
return _sets_string_get_tags($string);
}
/**
* Recursive internal function - return all Set-tags in a string
*
* @param $string
* The string to search for Set tags in
* @param $offset
* The position to start search for tags in.
* @return
* Array of tag names.
*/
function _sets_string_get_tags($string, $offset = 0) {
$results = array();
$sets = sets_list_sets();
$start_pos = strpos($string, '[', $offset);
$end_pos = strpos($string, ']', $start_pos);
if ($start_pos !== FALSE && $end_pos !== FALSE) {
$tag = substr($string, $start_pos + 1, $end_pos - $start_pos - 1);
if (isset($sets[$tag])) {
$results[] = $tag;
}
$results = array_merge($results, _sets_string_get_tags($string, $end_pos + 1));
}
return $results;
}
/**
* Returns all possible combinations of set values in string
*
* @param $string
* The string to insert set values in.
* @return
* Array of all possible combinations of values as well as the actual values inserted.
*/
function sets_string_get($string) {
return _sets_string_get($string);
}
function _sets_string_get($string, $values = array(), $offset = 0) {
$results = array();
$sets = sets_list_sets();
$start_pos = strpos($string, '[', $offset);
$end_pos = strpos($string, ']', $start_pos);
if ($start_pos !== FALSE && $end_pos !== FALSE) {
$tag = substr($string, $start_pos + 1, $end_pos - $start_pos - 1);
if (!isset($sets[$tag])) {
$result = _sets_string_get($string, $values, $end_pos + 1);
if ($result === FALSE) {
$results = FALSE;
}
else {
$results = array_merge($results, $result);
}
}
else {
$set = sets_get_set($tag);
foreach ($set as $value) {
$new_values = $values;
$new_values[] = array(
'tag' => $sets[$tag],
'value' => $value,
);
$new_string = substr($string, 0, $start_pos) . $value . substr($string, $end_pos + 1);
$result = _sets_string_get($new_string, $new_values, $offset);
if ($result === FALSE) {
$results[] = array(
'string' => $new_string,
'values' => $new_values,
);
}
else {
$results = array_merge($results, $result);
}
}
}
}
else {
$results = FALSE;
}
return $results;
}
/**
* Recursively iterates over a subset of all Set tags in a string and calls the callback for each variant.
*
* @param $string
* The string to iterate over all Set tags in
* @param $callback
* A function to be called for each variant of $string
* @param $count
* The maximum number of iterations to be performed
* @param $set_offset
* An array by reference with the key being the position of a set in the string and the value
* the offset to start iterate that set in
* @param
* Any number of additional arguments to be sent to the callback
* @return
* An associative array of additional options, with the following keys:
* - 'count'
* How many iterations that was done.
* - 'results'
* Any results that might have been returned by the callbacks.
*/
function sets_string_iterate_subset($string, $callback, $count, &$set_offset = array()) {
$args = func_get_args();
unset($args[0], $args[1], $args[2], $args[3]);
return _sets_string_iterate($string, $callback, array('max_count' => $count), $args, $set_offset);
}
/**
* Recursively iterates over all Set tags in a string and calls the callback for each variant.
*
* @param $string
* The string to iterate over all Set tags in
* @param $callback
* A function to be called for each variant of $string
* @param
* Any number of additional arguments to be sent to the callback
* @return
* An associative array of additional options, with the following keys:
* - 'count'
* How many iterations that was done.
* - 'results'
* Any results that might have been returned by the callbacks.
*/
function sets_string_iterate($string, $callback) {
$args = func_get_args();
unset($args[0], $args[1]);
return _sets_string_iterate($string, $callback, array(), $args);
}
/**
* Internal function - iterates over all Set tags in a string recursively and calls the callback for each variant.
*
* @param $string
* The string to iterate over all Set tags in
* @param $callback
* A function to be called for each variant of $string
* @param $options
* An associative array of additional options, with the following keys:
* - 'values'
* An array containing all values of previously replaced tags - used when the original
* string contains more than one Set tag.
* - 'string offset'
* Where to start search for Set tags in a string - used when the original string
* contains more than one Set tag and useful when one of them doesn't exist.
* - 'max_count'
* How many iterations to perform at max.
* @param $args
* Additional argumenst to be sent to the callback
* @param $set_offset
* The offset for each individual set.
* @return
* An associative array of additional options, with the following keys:
* - 'count'
* How many iterations that was done.
* - 'results'
* Any results that might have been returned by the callbacks.
*/
function _sets_string_iterate($string, $callback, $options = array(), $args = array(), &$set_offset = array()) {
if (isset($options['pos'])) {
$options['pos'] += 1;
}
$options += array(
'values' => array(),
'string_offset' => 0,
'max_count' => FALSE,
'pos' => 0,
'current_count' => 0,
);
$answers = array();
$count = 0;
$sets = sets_list_sets();
$start_pos = strpos($string, '[', $offset);
$end_pos = strpos($string, ']', $start_pos);
if ($start_pos !== FALSE && $end_pos !== FALSE) {
$tag = substr($string, $start_pos + 1, $end_pos - $start_pos - 1);
if (!isset($sets[$tag])) {
$options['string_offset'] = $end_pos + 1;
$result = _sets_string_iterate($string, $callback, $options, $args, $set_offset);
$answers = array_merge($answers, $result['results']);
$count = $result['count'];
}
else {
if ($options['max_count'] !== FALSE) {
if (!isset($set_offset[$options['pos']])) {
$set_offset[$options['pos']] = 0;
}
$set = sets_get_subset($tag, $options['max_count'], $set_offset[$options['pos']]);
if ($options['pos'] == 0 && $set_offset[$options['pos']] != 0 && empty($set)) {
$set_offset = array();
}
}
else {
$set = sets_get_set($tag);
}
foreach ($set as $value) {
$new_options = $options;
$new_options['values'][] = array(
'tag' => $sets[$tag],
'value' => $value,
);
$new_options['current_count'] = $count;
$new_string = substr($string, 0, $start_pos) . $value . substr($string, $end_pos + 1);
$result = _sets_string_iterate($new_string, $callback, $new_options, $args, $set_offset);
$answers = array_merge($answers, $result['results']);
$count += $result['count'] === FALSE ? 1 : $result['count'];
if ($options['max_count'] !== FALSE && $options['max_count'] <= $options['current_count'] + $count) {
break;
}
elseif ($max_count !== FALSE) {
$set_offset = array_slice($set_offset, 0, $options['pos'] + 1);
$set_offset[$options['pos']] += 1;
}
}
}
}
else {
//Call callback
array_unshift($args, $string, $options['values']);
$result = call_user_func_array($callback, $args);
if ($result !== NULL) {
$answers[] = $result;
}
$count = FALSE;
}
return array(
'count' => $count,
'results' => $answers,
);
}
/**
* Gets the definition of a single provider.
*
* @param $set
* The name of a provider as a string
* @return
* Array with the provider definition
*/
function sets_get_set_provider($set) {
ctools_include('plugins');
return ctools_get_plugins('sets', 'set_provider', $set);
}
/**
* Gets the definitions of all providers.
*
* @return
* Array of provider definitions as arrays.
*/
function sets_get_set_providers() {
ctools_include('plugins');
return ctools_get_plugins('sets', 'set_provider');
}
/**
* Gets all the values of a set
*
* @param $tag
* The name of the set
* @return
* An array containing all of the values of the set
*/
function sets_get_set($tag) {
$sets = sets_list_sets();
$provider = sets_get_set_provider($sets[$tag]['provider']);
return call_user_func($provider['set load'], $sets[$tag]);
}
/**
* Gets a subset of all the values of a set
*
* @param $tag
* The name of the set
* @param $count
* The maximum amount of values to return
* @param $offset
* The position of the first value to return
* @return
* An array containing all of the values of the set
*/
function sets_get_subset($tag, $count, $offset = 0) {
$set = array();
$sets = sets_list_sets();
$provider = sets_get_set_provider($sets[$tag]['provider']);
if (isset($provider['subset load'])) {
$set = call_user_func($provider['subset load'], $sets[$tag], $count, $offset);
}
else {
$set = call_user_func($provider['set load'], $sets[$tag]);
$length = count($set);
if ($length <= $offset) {
$set = array();
}
else {
if ($count + $offset > $length) {
$count = $length - $offset;
}
$set = array_slice($set, $offset, $count);
}
}
return $set;
}
/**
* Lists the available sets.
*
* @return
* Array with the tag as key and an array with properties as the value.
*/
function sets_list_sets() {
static $sets;
if (!isset($sets)) {
$sets = array();
$providers = sets_get_set_providers();
foreach ($providers as $provider_name => $provider) {
$tmp = call_user_func($provider['sets list'], $context);
foreach ($tmp as $key => $value) {
if (is_array($value)) {
$sets[$key] = $value + array(
'tag' => $key,
'provider' => $provider_name,
);
}
else {
$sets[$value] = array(
'tag' => $value,
'provider' => $provider_name,
);
}
}
}
}
return $sets;
}
/**
* Function to clean a tag to only use a-z, 0-9 as well as - and _.
*
* @param $tag
* The string to clean
* @return
* The cleaned string
*/
function sets_clean_tag($tag) {
return preg_replace('/\W/', '-', strtolower($tag));
}
/**
* Implementation of hook_ctools_plugin_TYPE().
*/
function sets_ctools_plugin_set_provider() {
//TODO: Make it possible to add cache here
return array(
'hook' => 'set_provider',
);
}
/**
* Implementation of hook_ctools_plugin_directory().
*/
function sets_ctools_plugin_directory($module, $plugin) {
if ($module == 'sets' && $plugin == 'set_provider') {
return 'plugins';
}
}