View source
<?php
define('FEATURES_OVERRIDE_REQUIRED_CTOOLS_API', '1.7');
define('FEATURES_OVERRIDE_RECURSION_MARKER', 'features_override_recursion_marker');
function features_override_init() {
module_load_include('inc', 'features_override', 'features_override.alter');
foreach (module_list() as $module) {
module_load_include('inc', 'features_override', "modules/{$module}.features_override");
}
}
function features_override_menu() {
$items = array();
$items['admin/structure/features/features-override/extend'] = array(
'type' => MENU_LOCAL_ACTION,
'title' => 'Extend',
'description' => 'Add support for additional feature components',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'features_override_extend',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'features_override.extend.inc',
'weight' => 10,
);
return $items;
}
function features_override_menu_alter(&$items) {
if (isset($items['admin/structure/features/features-override'])) {
$items['admin/structure/features/features-override']['type'] = MENU_LOCAL_TASK;
$items['admin/structure/features/features-override']['weight'] = 10;
}
}
function features_override_ctools_plugin_api($module, $api) {
if ($module == 'features_override' && $api == 'plugins') {
return array(
'version' => 1,
);
}
}
function features_override_ctools_plugin_directory($module, $type) {
if (!module_invoke('ctools', 'api_version', FEATURES_OVERRIDE_REQUIRED_CTOOLS_API)) {
return;
}
if ($module == 'ctools' && $type == 'export_ui') {
return 'plugins/' . $type;
}
}
function features_override_save($features_override) {
ctools_include('export');
return ctools_export_crud_save('features_override', $features_override);
}
function features_override_delete($features_override) {
ctools_include('export');
ctools_export_crud_delete('features_override', $features_override);
}
function features_override_load_all($reset = FALSE) {
ctools_include('export');
if ($reset) {
ctools_export_load_object_reset('features_override');
}
return ctools_export_load_object('features_override', 'all');
}
function features_override_supported_components($hooks = FALSE, $reset = FALSE) {
if ($reset) {
cache_clear_all('features_override:components', 'cache');
}
else {
$components = cache_get('features_override:components');
if (isset($components) && is_array($components)) {
return $hooks ? $components : drupal_map_assoc(array_keys($components));
}
}
$components = array();
foreach (features_get_components() as $component => $info) {
if (isset($info['default_hook']) && module_hook('features_override', $info['default_hook'] . '_alter')) {
$components[$component] = $info['default_hook'];
}
}
drupal_alter('features_override_supported_components', $components);
cache_set('features_override:components', $components);
return $hooks ? $components : drupal_map_assoc(array_keys($components));
}
function features_override_form_system_modules_alter(&$form, $form_state) {
features_override_supported_components(FALSE, TRUE);
}
function features_override_get_overrides() {
features_rebuild();
features_get_info(NULL, NULL, TRUE);
$overrides = array();
$features = features_get_features();
foreach ($features as $name => $module) {
if ($features_overrides = features_override_detect_overrides($module)) {
$overrides = array_merge_recursive($overrides, $features_overrides);
}
}
return $overrides;
}
function features_override_detect_overrides($module) {
static $cache;
if (!isset($cache)) {
$cache = array();
}
if (!isset($cache[$module->name])) {
$export = features_populate($module->info['features'], $module->info['dependencies'], $module->name);
$export = features_export_prepare($export, $module->name);
$overrides = array();
$states = features_get_component_states(array(
$module->name,
), FALSE);
foreach ($states[$module->name] as $component => $state) {
if (in_array($component, features_override_supported_components()) && $state != FEATURES_DEFAULT) {
$normal = features_get_normal($component, $module->name);
$default = features_get_default($component, $module->name);
_features_override_sanitize($normal);
_features_override_sanitize($default);
$component_overrides = array();
if ($normal && is_array($normal) || is_object($normal)) {
foreach ($normal as $name => $properties) {
$component_overrides[$name] = array(
'additions' => array(),
'deletions' => array(),
);
if (isset($default[$name])) {
if ($component == 'views') {
if (is_object($properties) && method_exists($properties, 'destroy')) {
$properties
->destroy();
}
if (is_object($default[$name]) && method_exists($default[$name], 'destroy')) {
$default[$name]
->destroy();
}
}
_features_override_set_additions($default[$name], $properties, $component_overrides[$name]['additions']);
_features_override_leave_hive($default[$name]);
_features_override_set_deletions($default[$name], $properties, $component_overrides[$name]['deletions']);
_features_override_leave_hive($default[$name]);
}
if (empty($component_overrides[$name]['additions']) && empty($component_overrides[$name]['deletions'])) {
unset($component_overrides[$name]);
}
}
if (!empty($component_overrides)) {
$overrides[$component] = $component_overrides;
}
}
}
}
$cache[$module->name] = $overrides;
}
return $cache[$module->name];
}
function _features_override_sanitize(&$array) {
if (is_array($array)) {
$is_assoc = array_keys($array) !== range(0, count($array) - 1);
if ($is_assoc) {
ksort($array);
}
else {
sort($array);
}
foreach ($array as $k => $v) {
if (is_array($v)) {
_features_override_sanitize($array[$k]);
}
}
}
}
function features_override_features_export($data, &$export, $module_name = "") {
$return = ctools_component_features_export('features_override', $data, $export, $module_name);
$map = features_get_component_map();
if (!isset($export['dependencies'])) {
$export['dependencies'] = array();
}
foreach ($data as $component) {
$component = ctools_export_crud_load('features_override', $component);
if (isset($map[$component->component_type]) && isset($map[$component->component_type][$component->component_id])) {
$export['dependencies'] = array_merge($export['dependencies'], drupal_map_assoc($map[$component->component_type][$component->component_id]));
}
}
return $return;
}
function features_override_features_export_options() {
$options = ctools_component_features_export_options('features_override');
if ($current_feature = menu_get_object('feature', 3)) {
$map = features_get_component_map();
foreach ($options as $option) {
$component = ctools_export_crud_load('features_override', $option);
if (isset($map[$component->component_type]) && isset($map[$component->component_type][$component->component_id]) && in_array($current_feature->name, $map[$component->component_type][$component->component_id])) {
unset($options[$option]);
}
}
}
return $options;
}
function features_override_export($alters) {
$prefix = ' ';
foreach ($alters as $alter) {
if (isset($alter['value'])) {
$line = $prefix . ' $items';
foreach ($alter['keys'] as $key) {
if ($key['type'] == 'object') {
$line .= '->' . $key['key'];
}
else {
$line .= "['" . $key['key'] . "']";
}
}
$line .= ' = ' . features_var_export($alter['value'], $prefix, FALSE) . ";\n";
$code .= $line;
}
else {
$line = ' unset($items';
foreach ($alter['keys'] as $key) {
if ($key['type'] == 'object') {
$line .= '->' . $key['key'];
}
else {
$line .= "['" . $key['key'] . "']";
}
}
$line .= ");\n";
$code .= $line;
}
}
return $code;
}
function _features_override_hive(&$bee = NULL) {
static $bees = array();
if (!is_null($bee)) {
$recursion_marker = FEATURES_OVERRIDE_RECURSION_MARKER;
is_object($bee) ? @$bee->{$recursion_marker}++ : @$bee[$recursion_marker]++;
$bees[0][] =& $bee;
}
return $bees[0];
}
function _features_override_leave_hive() {
$hive = _features_override_hive();
foreach ($hive as $i => $bee) {
$recursion_marker = FEATURES_OVERRIDE_RECURSION_MARKER;
if (is_object($bee)) {
unset($hive[$i]->{$recursion_marker});
}
else {
unset($hive[$i][$recursion_marker]);
}
}
}
function _features_override_recursion_marker(&$normal, $object) {
_features_override_hive($normal);
$recursion_marker = FEATURES_OVERRIDE_RECURSION_MARKER;
$r = $object ? @$normal->{$recursion_marker} : @$normal[$recursion_marker];
$r = (int) $r;
return $r;
}
function _features_override_set_additions($default, $normal, &$additions, $keys = array()) {
$object = is_object($normal);
if (_features_override_recursion_marker($default, $object) > 1) {
return;
}
foreach ($normal as $key => $value) {
if (in_array($key, array(
'content_has_extra_fields',
FEATURES_OVERRIDE_RECURSION_MARKER,
))) {
return;
}
if ($object) {
if (!isset($default->{$key}) || $default->{$key} !== $value && !(is_array($value) || is_object($value))) {
$additions[] = array(
'keys' => array_merge($keys, array(
array(
'type' => 'object',
'key' => $key,
),
)),
'value' => $value,
'order' => array_keys((array) $normal),
);
}
elseif (isset($default->{$key}) && $default->{$key} !== $value) {
_features_override_set_additions($default->{$key}, $value, $additions, array_merge($keys, array(
array(
'type' => 'object',
'key' => $key,
),
)));
}
}
else {
if (!isset($default[$key]) || $default[$key] !== $value && !(is_array($value) || is_object($value))) {
$additions[] = array(
'keys' => array_merge($keys, array(
array(
'type' => 'array',
'key' => $key,
),
)),
'value' => $value,
'order' => array_keys($normal),
);
}
elseif (isset($default[$key]) && $default[$key] !== $value) {
_features_override_set_additions($default[$key], $value, $additions, array_merge($keys, array(
array(
'type' => 'array',
'key' => $key,
),
)));
}
}
}
}
function _features_override_set_deletions($default, $normal, &$deletions, $keys = array()) {
$object = is_object($default);
if (_features_override_recursion_marker($default, $object) > 1) {
return;
}
foreach ($default as $key => $value) {
if ($key == FEATURES_OVERRIDE_RECURSION_MARKER) {
continue;
}
if ($object) {
if (!isset($normal->{$key})) {
$deletions[] = array(
'keys' => array_merge($keys, array(
array(
'type' => 'object',
'key' => $key,
),
)),
);
}
elseif (is_object($value) || is_array($value)) {
_features_override_set_deletions($value, $normal->{$key}, $deletions, array_merge($keys, array(
array(
'type' => 'object',
'key' => $key,
),
)));
}
}
else {
if (!isset($normal[$key])) {
$deletions[] = array(
'keys' => array_merge($keys, array(
array(
'type' => 'array',
'key' => $key,
),
)),
);
}
elseif (is_object($value) || is_array($value)) {
_features_override_set_deletions($value, $normal[$key], $deletions, array_merge($keys, array(
array(
'type' => 'array',
'key' => $key,
),
)));
}
}
}
}