class RulesData
A class holding static methods related to data.
Hierarchy
- class \RulesData
Expanded class hierarchy of RulesData
3 string references to 'RulesData'
- RulesData::addMetadataAssertions in includes/
rules.state.inc - Adds asserted metadata to the variable info.
- RulesData::applyMetadataAssertions in includes/
rules.state.inc - Property info alter callback for the entity metadata wrapper.
- RulesState::defaultVariables in includes/
rules.state.inc - Defines always-available variables.
File
-
includes/
rules.state.inc, line 391
View source
class RulesData {
/**
* Returns whether the type match. They match if type1 is compatible to type2.
*
* @param $var_info
* The name of the type to check for whether it is compatible to type2.
* @param $param_info
* The type expression to check for.
* @param bool $ancestors
* (optional) Whether sub-type relationships for checking type compatibility
* should be taken into account. Defaults to TRUE.
*
* @return bool
* Whether the types match.
*/
public static function typesMatch($var_info, $param_info, $ancestors = TRUE) {
$var_type = $var_info['type'];
$param_type = $param_info['type'];
if ($param_type == '*' || $param_type == 'unknown') {
return TRUE;
}
if ($var_type == $param_type) {
// Make sure the bundle matches, if specified by the parameter.
return !isset($param_info['bundles']) || isset($var_info['bundle']) && in_array($var_info['bundle'], $param_info['bundles']);
}
// Parameters may specify multiple types using an array.
$valid_types = is_array($param_type) ? $param_type : array(
$param_type,
);
if (in_array($var_type, $valid_types)) {
return TRUE;
}
// Check for sub-type relationships.
if ($ancestors && !isset($param_info['bundles'])) {
$cache =& rules_get_cache();
self::typeCalcAncestors($cache, $var_type);
// If one of the types is an ancestor return TRUE.
return (bool) array_intersect_key($cache['data_info'][$var_type]['ancestors'], array_flip($valid_types));
}
return FALSE;
}
protected static function typeCalcAncestors(&$cache, $type) {
if (!isset($cache['data_info'][$type]['ancestors'])) {
$cache['data_info'][$type]['ancestors'] = array();
if (isset($cache['data_info'][$type]['parent']) && ($parent = $cache['data_info'][$type]['parent'])) {
$cache['data_info'][$type]['ancestors'][$parent] = TRUE;
self::typeCalcAncestors($cache, $parent);
// Add all parent ancestors to our own ancestors.
$cache['data_info'][$type]['ancestors'] += $cache['data_info'][$parent]['ancestors'];
}
// For special lists like list<node> add in "list" as valid parent.
if (entity_property_list_extract_type($type)) {
$cache['data_info'][$type]['ancestors']['list'] = TRUE;
}
}
}
/**
* Returns data for the given info and the to-be-configured parameter.
*
* Returns matching data variables or properties for the given info and the
* to-be-configured parameter.
*
* @param $source
* Either an array of info about available variables or a entity metadata
* wrapper.
* @param $param_info
* The information array about the to be configured parameter.
* @param string $prefix
* An optional prefix for the data selectors.
* @param int $recursions
* The number of recursions used to go down the tree. Defaults to 2.
* @param bool $suggestions
* Whether possibilities to recurse are suggested as soon as the deepest
* level of recursions is reached. Defaults to TRUE.
*
* @return array
* An array of info about matching variables or properties that match, keyed
* with the data selector.
*/
public static function matchingDataSelector($source, $param_info, $prefix = '', $recursions = 2, $suggestions = TRUE) {
// If an array of info is given, get entity metadata wrappers first.
$data = NULL;
if (is_array($source)) {
foreach ($source as $name => $info) {
$source[$name] = rules_wrap_data($data, $info, TRUE);
}
}
$matches = array();
foreach ($source as $name => $wrapper) {
$info = $wrapper->info();
$name = str_replace('_', '-', $name);
if (self::typesMatch($info, $param_info)) {
$matches[$prefix . $name] = $info;
if (!is_array($source) && $source instanceof EntityListWrapper) {
// Add some more possible list items.
for ($i = 1; $i < 4; $i++) {
$matches[$prefix . $i] = $info;
}
}
}
// Recurse later on to get an improved ordering of the results.
if ($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper) {
$recurse[$prefix . $name] = $wrapper;
if ($recursions > 0) {
$matches += self::matchingDataSelector($wrapper, $param_info, $prefix . $name . ':', $recursions - 1, $suggestions);
}
elseif ($suggestions) {
// We may not recurse any more,
// but indicate the possibility to recurse.
$matches[$prefix . $name . ':'] = $wrapper->info();
if (!is_array($source) && $source instanceof EntityListWrapper) {
// Add some more possible list items.
for ($i = 1; $i < 4; $i++) {
$matches[$prefix . $i . ':'] = $wrapper->info();
}
}
}
}
}
return $matches;
}
/**
* Adds asserted metadata to the variable info.
*
* In case there are already assertions for a variable, the assertions are
* merged such that both apply.
*
* @see RulesData::applyMetadataAssertions()
*/
public static function addMetadataAssertions($var_info, $assertions) {
foreach ($assertions as $selector => $assertion) {
// Convert the selector back to underscores, such it matches the varname.
$selector = str_replace('-', '_', $selector);
$parts = explode(':', $selector);
if (isset($var_info[$parts[0]])) {
// Apply the selector to determine the right target array. We build an
// array like
// $var_info['rules assertion']['property1']['property2']['#info'] = ..
$target =& $var_info[$parts[0]]['rules assertion'];
foreach (array_slice($parts, 1) as $part) {
$target =& $target[$part];
}
// In case the assertion is directly for a variable, we have to modify
// the variable info directly. In case the asserted property is nested
// the info-has to be altered by RulesData::applyMetadataAssertions()
// before the child-wrapper is created.
if (count($parts) == 1) {
// Support asserting a type in case of generic entity references only.
$var_type =& $var_info[$parts[0]]['type'];
if (isset($assertion['type']) && ($var_type == 'entity' || $var_type == 'list<entity>')) {
$var_type = $assertion['type'];
unset($assertion['type']);
}
// Add any single bundle directly to the variable info, so the
// variable fits as argument for parameters requiring the bundle.
if (isset($assertion['bundle']) && count($bundles = (array) $assertion['bundle']) == 1) {
$var_info[$parts[0]]['bundle'] = reset($bundles);
}
}
// Add the assertions, but merge them with any previously added
// assertions if necessary.
$target['#info'] = isset($target['#info']) ? rules_update_array($target['#info'], $assertion) : $assertion;
// Add in a callback that the entity metadata wrapper pick up for
// altering the property info, such that we can add in the assertions.
$var_info[$parts[0]] += array(
'property info alter' => array(
'RulesData',
'applyMetadataAssertions',
),
);
// In case there is a VARNAME_unchanged variable as it is used in update
// hooks, assume the assertions are valid for the unchanged variable
// too.
if (isset($var_info[$parts[0] . '_unchanged'])) {
$name = $parts[0] . '_unchanged';
$var_info[$name]['rules assertion'] = $var_info[$parts[0]]['rules assertion'];
$var_info[$name]['property info alter'] = array(
'RulesData',
'applyMetadataAssertions',
);
if (isset($var_info[$parts[0]]['bundle']) && !isset($var_info[$name]['bundle'])) {
$var_info[$name]['bundle'] = $var_info[$parts[0]]['bundle'];
}
}
}
}
return $var_info;
}
/**
* Property info alter callback for the entity metadata wrapper.
*
* Used for applying the rules metadata assertions.
*
* @see RulesData::addMetadataAssertions()
*/
public static function applyMetadataAssertions(EntityMetadataWrapper $wrapper, $property_info) {
$info = $wrapper->info();
if (!empty($info['rules assertion'])) {
$assertion = $info['rules assertion'];
// In case there are list-wrappers pass through the assertions of the item
// but make sure we only apply the assertions for the list items for
// which the conditions are executed.
if (isset($info['parent']) && $info['parent'] instanceof EntityListWrapper) {
$assertion = isset($assertion[$info['name']]) ? $assertion[$info['name']] : array();
}
// Support specifying multiple bundles, whereas the added properties are
// the intersection of the bundle properties.
if (isset($assertion['#info']['bundle'])) {
$bundles = (array) $assertion['#info']['bundle'];
foreach ($bundles as $bundle) {
$properties[] = isset($property_info['bundles'][$bundle]['properties']) ? $property_info['bundles'][$bundle]['properties'] : array();
}
// Add the intersection.
$property_info['properties'] += count($properties) > 1 ? call_user_func_array('array_intersect_key', $properties) : reset($properties);
}
// Support adding directly asserted property info.
if (isset($assertion['#info']['property info'])) {
$property_info['properties'] += $assertion['#info']['property info'];
}
// Pass through any rules assertion of properties to their info, so any
// derived wrappers apply it.
foreach (element_children($assertion) as $key) {
$property_info['properties'][$key]['rules assertion'] = $assertion[$key];
$property_info['properties'][$key]['property info alter'] = array(
'RulesData',
'applyMetadataAssertions',
);
// Apply any 'type' and 'bundle' assertion directly to the property
// info.
if (isset($assertion[$key]['#info']['type'])) {
$type = $assertion[$key]['#info']['type'];
// Support asserting a type in case of generic entity references only.
if ($property_info['properties'][$key]['type'] == 'entity' && entity_get_info($type)) {
$property_info['properties'][$key]['type'] = $type;
}
}
if (isset($assertion[$key]['#info']['bundle'])) {
$bundle = (array) $assertion[$key]['#info']['bundle'];
// Add any single bundle directly to the variable info, so the
// property fits as argument for parameters requiring the bundle.
if (count($bundle) == 1) {
$property_info['properties'][$key]['bundle'] = reset($bundle);
}
}
}
}
return $property_info;
}
/**
* Property info alter callback for the entity metadata wrapper.
*
* Used to inject metadata for the 'site' variable. In contrast to doing this
* via hook_rules_data_info() this callback makes use of the already existing
* property info cache for site information of entity metadata.
*
* @see RulesPlugin::availableVariables()
*/
public static function addSiteMetadata(EntityMetadataWrapper $wrapper, $property_info) {
$site_info = entity_get_property_info('site');
$property_info['properties'] += $site_info['properties'];
// Also invoke the usual callback for altering metadata, in case actions
// have specified further metadata.
return RulesData::applyMetadataAssertions($wrapper, $property_info);
}
}
Members
Title Sort descending | Modifiers | Object type | Summary |
---|---|---|---|
RulesData::addMetadataAssertions | public static | function | Adds asserted metadata to the variable info. |
RulesData::addSiteMetadata | public static | function | Property info alter callback for the entity metadata wrapper. |
RulesData::applyMetadataAssertions | public static | function | Property info alter callback for the entity metadata wrapper. |
RulesData::matchingDataSelector | public static | function | Returns data for the given info and the to-be-configured parameter. |
RulesData::typeCalcAncestors | protected static | function | |
RulesData::typesMatch | public static | function | Returns whether the type match. They match if type1 is compatible to type2. |