From e2fde76aff6d75a6139b831e1fa0052fcc430966 Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Tue, 19 Apr 2016 16:32:54 +0200 Subject: [PATCH] updated features --- .../contrib/admin/features/features.admin.inc | 26 ++-- .../contrib/admin/features/features.api.php | 4 +- .../contrib/admin/features/features.drush.inc | 49 +++++-- .../admin/features/features.export.inc | 128 +++++++----------- .../contrib/admin/features/features.info | 10 +- .../contrib/admin/features/features.module | 99 +++++--------- .../features/includes/features.contact.inc | 115 ++++++++++++++++ .../features/includes/features.field.inc | 29 ++-- .../features/includes/features.locale.inc | 4 +- .../admin/features/includes/features.menu.inc | 4 +- .../admin/features/includes/features.node.inc | 9 ++ .../admin/features/tests/features.test | 2 +- .../tests/features_test/features_test.info | 6 +- 13 files changed, 295 insertions(+), 190 deletions(-) create mode 100644 sites/all/modules/contrib/admin/features/includes/features.contact.inc diff --git a/sites/all/modules/contrib/admin/features/features.admin.inc b/sites/all/modules/contrib/admin/features/features.admin.inc index 8360e974..46752c89 100644 --- a/sites/all/modules/contrib/admin/features/features.admin.inc +++ b/sites/all/modules/contrib/admin/features/features.admin.inc @@ -88,6 +88,12 @@ function features_settings_form($form, $form_state) { '#default_value' => variable_get('features_rebuild_on_flush', TRUE), '#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'), ); + $form['general']['features_rebuild_modules_page'] = array( + '#type' => 'checkbox', + '#title' => t('Rebuild features on accessing modules list page'), + '#default_value' => variable_get('features_rebuild_modules_page', FALSE), + '#description' => t('If you have a large site with many features, you may experience lag on accessing the modules administration page. If disabled, features will not rebuild when viewing the modules list.'), + ); return system_settings_form($form); } @@ -109,7 +115,7 @@ function features_export_form($form, $form_state, $feature = NULL) { $feature_name = !empty($feature->name) ? $feature->name : ''; $form = array( - '#attributes' => array('class' => array('features-export-form')), + '#attributes' => array('class' => array('features-export-form', 'clearfix')), '#feature' => isset($feature) ? $feature : NULL, ); $form['info'] = array( @@ -756,7 +762,7 @@ function features_export_form_rebuild($form, &$form_state) { function features_export_components_json($feature_name) { module_load_include('inc', 'features', 'features.export'); - $export = array(); + $export = array('features' => array()); if (!empty($_POST['items'])) { $excluded = (!empty($_POST['excluded'])) ? $_POST['excluded'] : array(); $stub = array(); @@ -1143,7 +1149,7 @@ function features_admin_form($form, $form_state) { // As of 7.0 beta 2 it matters where the "vertical_tabs" element lives on the // the array. We add it late, but at the beginning of the array because that // keeps us away from trouble. - $form = array('packages' => array('#type' => 'vertical_tabs')) + $form; + $form = array_merge(array('packages' => array('#type' => 'vertical_tabs')), $form); $form['buttons'] = array( '#theme' => 'features_form_buttons', @@ -1328,7 +1334,7 @@ function features_form_submit(&$form, &$form_state) { // page callback rather than as part of the submit handler as some modules // have includes/other directives of importance in hooks that have already // been called in this page load. - $form_state['redirect'] = 'admin/structure/features/cleanup/clear'; + $form_state['redirect'] = array('admin/structure/features/cleanup', array('query' => array('token' => drupal_get_token()))); $features = $form['#features']; if (!empty($features)) { @@ -1352,21 +1358,19 @@ function features_form_rebuild() { } /** - * Form for clearing cache after enabling a feature. + * Callback for clearing cache after enabling a feature. */ -function features_cleanup_form($form, $form_state, $cache_clear = FALSE) { - // Clear caches if we're getting a post-submit redirect that requests it. - if ($cache_clear) { +function features_cleanup() { + if (!empty($_GET['token']) && drupal_valid_token($_GET['token'])) { drupal_flush_all_caches(); - // The following functions need to be run because drupal_flush_all_caches() // runs rebuilds in the wrong order. The node type cache is rebuilt *after* // the menu is rebuilt, meaning that the menu tree is stale in certain // circumstances after drupal_flush_all_caches(). We rebuild again. menu_rebuild(); - } - drupal_goto('admin/structure/features'); + } + return MENU_NOT_FOUND; } /** diff --git a/sites/all/modules/contrib/admin/features/features.api.php b/sites/all/modules/contrib/admin/features/features.api.php index 6a13b0c1..d7c7edec 100644 --- a/sites/all/modules/contrib/admin/features/features.api.php +++ b/sites/all/modules/contrib/admin/features/features.api.php @@ -42,7 +42,7 @@ * are declared "dynamically" or are part of a family of components. * * 'alter_type': What type of alter hook this hook uses. 'normal' is called - * after the main hook is called. 'inline' is embeded within the default hook + * after the main hook is called. 'inline' is embedded within the default hook * and may not be implemented by some default hooks. * 'none' is no alter hook exists. Defaults to 'normal' * @@ -310,7 +310,7 @@ function hook_features_pipe_COMPONENT_alter(&$pipe, $data, $export) { * The module being exported contained in $export['module_name']. */ function hook_features_pipe_alter(&$pipe, $data, $export) { - if ($export['component'] == 'node' && in_array($data, 'my-node-type')) { + if ($export['component'] == 'node' && in_array('my-node-type', $data)) { $pipe['dependencies'][] = 'mymodule'; } } diff --git a/sites/all/modules/contrib/admin/features/features.drush.inc b/sites/all/modules/contrib/admin/features/features.drush.inc index 6fdbc263..696825d6 100644 --- a/sites/all/modules/contrib/admin/features/features.drush.inc +++ b/sites/all/modules/contrib/admin/features/features.drush.inc @@ -32,6 +32,12 @@ function features_drush_command() { ), 'drupal dependencies' => array('features'), 'aliases' => array('fl', 'features'), + 'outputformat' => array( + 'default' => 'table', + 'pipe-format' => 'list', + 'field-labels' => array('name' => 'Name', 'feature' => 'Feature', 'status' => 'Status', 'version' => 'Version', 'state' => 'State'), + 'output-data-type' => 'format-table', + ), ); $items['features-export'] = array( 'description' => "Export a feature from your site into a module.", @@ -207,12 +213,12 @@ function drush_features_list() { } module_load_include('inc', 'features', 'features.export'); - $rows = array(array(dt('Name'), dt('Feature'), dt('Status'), dt('Version'), dt('State'))); // Sort the Features list before compiling the output. $features = features_get_features(NULL, TRUE); ksort($features); + $rows = array(); foreach ($features as $k => $m) { switch (features_get_storage($m->name)) { case FEATURES_DEFAULT: @@ -230,16 +236,19 @@ function drush_features_list() { ($m->status == 0 && ($status == 'all' || $status == 'disabled')) || ($m->status == 1 && ($status == 'all' || $status == 'enabled')) ) { - $rows[] = array( - $m->info['name'], - $m->name, - $m->status ? dt('Enabled') : dt('Disabled'), - $m->info['version'], - $storage + $rows[$k] = array( + 'name' => $m->info['name'], + 'feature' => $m->name, + 'status' => $m->status ? dt('Enabled') : dt('Disabled'), + 'version' => $m->info['version'], + 'state' => $storage ); } } - drush_print_table($rows, TRUE); + if (version_compare(DRUSH_VERSION, '6.0', '<')) { + drush_print_table($rows, TRUE); + } + return $rows; } /** @@ -337,8 +346,13 @@ function _drush_features_component_filter($all_components, $patterns = array(), // Rewrite * to %. Let users use both as wildcard. $pattern = strtr($pattern, array('*' => '%')); $sources = array(); - $source_pattern = strtok($pattern, ':'); - $component_pattern = strtok(':'); + if (strpos($pattern, ':') !== FALSE) { + list($source_pattern, $component_pattern) = explode(':', $pattern, 2); + } + else { + $source_pattern = $pattern; + $component_pattern = ''; + } // If source is empty, use a pattern. if ($source_pattern == '') { $source_pattern = '%'; @@ -607,9 +621,18 @@ function _drush_features_export($info, $module_name = NULL, $directory = NULL) { drush_op('mkdir', $directory); } if (is_dir($directory)) { + // Ensure that the export will be created in the English language. + // The export language must be set before flushing caches as that can + // result into translatables being statically cached. + $language = _features_export_language(); + drupal_flush_all_caches(); $export = _drush_features_generate_export($info, $module_name); $files = features_export_render($export, $module_name, TRUE); + + // Restore the language + _features_export_language($language); + // Copy any files if _files key is there. if (!empty($files['_files'])) { foreach ($files['_files'] as $file_name => $file_info) { @@ -685,7 +708,7 @@ function _drush_features_generate_export(&$info, &$module_name) { } else { // Split version number parts. - $pattern = '/([0-9]-[a-z]+([0-9])+)/'; + $pattern = '/([0-9]-[a-z]+([0-9]+))/'; $matches = array(); preg_match($pattern, $version_minor, $matches); $number = array_pop($matches); @@ -797,7 +820,7 @@ function drush_features_revert() { } } else { - drush_features_list(); + drush_print_table(drush_features_list()); return; } } @@ -851,7 +874,7 @@ function drush_features_revert_all() { */ function drush_features_diff() { if (!$args = func_get_args()) { - drush_features_list(); + drush_print_table(drush_features_list()); return; } $module = $args[0]; diff --git a/sites/all/modules/contrib/admin/features/features.export.inc b/sites/all/modules/contrib/admin/features/features.export.inc index 5cf2a8c8..5045b131 100644 --- a/sites/all/modules/contrib/admin/features/features.export.inc +++ b/sites/all/modules/contrib/admin/features/features.export.inc @@ -46,7 +46,7 @@ function features_populate($info, $module_name) { */ function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE) { // Ensure that the export will be created in the english language. - _features_set_export_language(); + $language = _features_export_language(); if ($reset) { drupal_static_reset(__FUNCTION__); @@ -92,6 +92,7 @@ function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE) } } } + _features_export_language($language); return $export; } @@ -843,6 +844,13 @@ function features_get_default($component, $module_name = NULL, $alter = TRUE, $r /** * Get a map of components to their providing modules. + * + * @param string $component + * @param string $attribute + * @param callable $callback + * @param bool $reset + * + * @return array|bool */ function features_get_default_map($component, $attribute = NULL, $callback = NULL, $reset = FALSE) { $map = &drupal_static(__FUNCTION__, array()); @@ -891,6 +899,9 @@ function features_get_default_map($component, $attribute = NULL, $callback = NUL * Retrieve an array of features/components and their current states. */ function features_get_component_states($features = array(), $rebuild_only = TRUE, $reset = FALSE) { + // Ensure that the export will be created in the English language. + $language = _features_export_language(); + if ($reset) { drupal_static_reset(__FUNCTION__); } @@ -901,7 +912,7 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE // Retrieve only rebuildable components if requested. features_include(); - $components = array_keys(features_get_components()); + $components = array_keys(features_get_components(NULL, NULL, $reset)); if ($rebuild_only) { foreach ($components as $k => $component) { if (!features_hook($component, 'features_rebuild')) { @@ -984,6 +995,9 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE foreach ($return as $k => $v) { $return[$k] = array_intersect_key($return[$k], array_flip($components)); } + + _features_export_language($language); + return $return; } @@ -1006,17 +1020,14 @@ function _features_linetrim($code) { * @param bool $remove_empty if set, remove null or empty values for assoc arrays. */ function features_sanitize(&$array, $component = NULL, $remove_empty = TRUE) { - // make a deep copy of data to prevent problems when removing recursion later. - $array = unserialize(serialize($array)); + $array = features_remove_recursion($array); if (isset($component)) { $ignore_keys = _features_get_ignore_keys($component); // remove keys to be ignored - // doing this now allows us to better control which recursive parts are removed if (count($ignore_keys)) { _features_remove_ignores($array, $ignore_keys); } } - features_remove_recursion($array); _features_sanitize($array, $remove_empty); } @@ -1069,81 +1080,45 @@ function _features_is_assoc($array) { /** * Removes recursion from an object or array. * - * @param $item - * An object or array passed by reference. - */ -function features_remove_recursion(&$item) { - $uniqid = __FUNCTION__ . mt_rand(); // use of uniqid() here impacts performance - $stack = array(); - return _features_remove_recursion($item, $stack, $uniqid); -} - -/** - * Helper to removes recursion from an object/array. + * Taken from https://code.google.com/p/formaldehyde/source/browse/trunk/formaldehyde.php + * Also used in node_export module * - * @param $item - * An object or array passed by reference. + * @param $o mixed + * @return mixed + * returns a copy of the object or array with recursion removed */ -function _features_remove_recursion(&$object, &$stack = array(), $uniqid) { - if ((is_object($object) || is_array($object)) && $object) { - $in_stack = FALSE; - foreach ($stack as &$item) { - if (_features_is_ref_to($object, $item, $uniqid)) { - $in_stack = TRUE; - break; - } - } - unset($item); - - if (!$in_stack) { - $stack[] = $object; - foreach ($object as $key => &$subobject) { - if (_features_remove_recursion($subobject, $stack, $uniqid)) { - if (is_object($object)) { - unset($object->$key); - } - else { - unset($object[$key]); - } +function features_remove_recursion($o) { + static $replace; + if (!isset($replace)) { + $replace = create_function( + '$m', + '$r="\x00{$m[1]}ecursion_features";return \'s:\'.strlen($r.$m[2]).\':"\'.$r.$m[2].\'";\';' + ); + } + if (is_array($o) || is_object($o)) { + $re = '#(r|R):([0-9]+);#'; + $serialize = serialize($o); + if (preg_match($re, $serialize)) { + $last = $pos = 0; + while (false !== ($pos = strpos($serialize, 's:', $pos))) { + $chunk = substr($serialize, $last, $pos - $last); + if (preg_match($re, $chunk)) { + $length = strlen($chunk); + $chunk = preg_replace_callback($re, $replace, $chunk); + $serialize = substr($serialize, 0, $last) . $chunk . substr($serialize, $last + ($pos - $last)); + $pos += strlen($chunk) - $length; } + $pos += 2; + $last = strpos($serialize, ':', $pos); + $length = substr($serialize, $pos, $last - $pos); + $last += 4 + $length; + $pos = $last; } - unset($subobject); - } - else { - return TRUE; + $serialize = substr($serialize, 0, $last) . preg_replace_callback($re, $replace, substr($serialize, $last)); + $o = unserialize($serialize); } } - return FALSE; -} - -/** - * Helper function in determining equality of arrays. Credit to http://stackoverflow.com/a/4263181 - * - * @see _features_remove_recursion() - * - * @param $a - * object a - * @param $b - * object b - * @return bool - * - */ -function _features_is_ref_to(&$a, &$b, $uniqid) { - if (is_object($a) && is_object($b)) { - return ($a === $b); - } - - $temp_a = $a; - $temp_b = $b; - - $b = $uniqid; - - if ($a === $uniqid) $return = true; - else $return = false; - - $a = $temp_a; - $b = $temp_b; - return $return; + return $o; } /** @@ -1162,7 +1137,7 @@ function _features_remove_ignores(&$item, $ignore_keys, $level = -1) { if (!is_array($item) && !is_object($item)) { return; } - foreach ($item as $key => $value) { + foreach ($item as $key => &$value) { if (isset($ignore_keys[$key]) && ($ignore_keys[$key] == $level)) { if ($is_object) { unset($item->$key); @@ -1175,6 +1150,7 @@ function _features_remove_ignores(&$item, $ignore_keys, $level = -1) { _features_remove_ignores($value, $ignore_keys, $level+1); } } + unset($value); } /** diff --git a/sites/all/modules/contrib/admin/features/features.info b/sites/all/modules/contrib/admin/features/features.info index e18cc8f1..d28a617b 100644 --- a/sites/all/modules/contrib/admin/features/features.info +++ b/sites/all/modules/contrib/admin/features/features.info @@ -3,12 +3,16 @@ description = "Provides feature management for Drupal." core = 7.x package = "Features" files[] = tests/features.test +test_dependencies[] = image +test_dependencies[] = strongarm +test_dependencies[] = taxonomy +test_dependencies[] = views configure = admin/structure/features/settings -; Information added by Drupal.org packaging script on 2015-06-24 -version = "7.x-2.6" +; Information added by Drupal.org packaging script on 2016-04-18 +version = "7.x-2.10" core = "7.x" project = "features" -datestamp = "1435165997" +datestamp = "1461011641" diff --git a/sites/all/modules/contrib/admin/features/features.module b/sites/all/modules/contrib/admin/features/features.module index 2fcc660b..3c48d713 100644 --- a/sites/all/modules/contrib/admin/features/features.module +++ b/sites/all/modules/contrib/admin/features/features.module @@ -84,8 +84,7 @@ function features_menu() { $items['admin/structure/features/cleanup'] = array( 'title' => 'Cleanup', 'description' => 'Clear cache after enabling/disabling a feature.', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('features_cleanup_form', 4), + 'page callback' => 'features_cleanup', 'type' => MENU_CALLBACK, 'file' => 'features.admin.inc', 'weight' => 1, @@ -128,7 +127,7 @@ function features_menu() { 'description' => 'Display components of a feature.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_admin_components', 3), - 'load arguments' => array(3, TRUE), + 'load arguments' => array(TRUE), 'access callback' => 'user_access', 'access arguments' => array('administer features'), 'type' => MENU_CALLBACK, @@ -147,7 +146,7 @@ function features_menu() { 'description' => 'Recreate an existing feature.', 'page callback' => 'drupal_get_form', 'page arguments' => array('features_export_form', 3), - 'load arguments' => array(3, TRUE), + 'load arguments' => array(TRUE), 'access callback' => 'user_access', 'access arguments' => array('administer features'), 'type' => MENU_LOCAL_TASK, @@ -160,7 +159,7 @@ function features_menu() { 'description' => 'Compare default and current feature.', 'page callback' => 'features_feature_diff', 'page arguments' => array(3, 5), - 'load arguments' => array(3, TRUE), + 'load arguments' => array(TRUE), 'access callback' => 'features_access_override_actions', 'access arguments' => array(3), 'type' => MENU_LOCAL_TASK, @@ -173,7 +172,7 @@ function features_menu() { 'description' => 'Lock a feature or components.', 'page callback' => 'features_admin_lock', 'page arguments' => array(3, 5, 6), - 'load arguments' => array(3, TRUE, TRUE), + 'load arguments' => array(TRUE), 'access arguments' => array('administer features'), 'type' => MENU_CALLBACK, 'file' => 'features.admin.inc', @@ -183,7 +182,7 @@ function features_menu() { 'description' => 'Javascript status call back.', 'page callback' => 'features_feature_status', 'page arguments' => array(3), - 'load arguments' => array(3, TRUE), + 'load arguments' => array(TRUE), 'access callback' => 'user_access', 'access arguments' => array('administer features'), 'type' => MENU_CALLBACK, @@ -278,7 +277,11 @@ function features_flush_caches() { features_get_modules(NULL, TRUE); } } - return array('cache_features'); + + if (db_table_exists('cache_features')) { + return array('cache_features'); + } + return array(); } /** @@ -515,7 +518,7 @@ function features_load_feature($name, $reset = FALSE) { * Return a module 'object' including .info information. * * @param $name - * The name of the module to retrieve information for. If ommitted, + * The name of the module to retrieve information for. If omitted, * an array of all available modules will be returned. * @param $reset * Whether to reset the cache. @@ -757,9 +760,9 @@ function features_get_info($type = 'module', $name = NULL, $reset = FALSE) { $cache->data = $data; } if (!empty($name)) { - return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : array(); + return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : FALSE; } - return !empty($cache->data[$type]) ? $cache->data[$type] : array(); + return !empty($cache->data[$type]) ? $cache->data[$type] : FALSE; } /** @@ -906,7 +909,7 @@ function features_access_override_actions($feature) { features_include(); module_load_include('inc', 'features', 'features.export'); - $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW)) && user_access('administer features'); + $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_DEFAULT, FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW)); } return $access[$feature->name]; } @@ -917,7 +920,9 @@ function features_access_override_actions($feature) { * Implements hook_form_alter() for system_modules form(). */ function features_form_system_modules_alter(&$form) { - features_rebuild(); + if (variable_get('features_rebuild_modules_page', FALSE)) { + features_rebuild(); + } } /** @@ -1219,12 +1224,14 @@ function features_feature_unlock($feature, $component = NULL) { } /** - * Sets the current language to english to ensure a proper export. + * Sets/Returns the current language to english to ensure a proper export. */ -function _features_set_export_language() { - // Ensure this is only done if the language isn't already en. - // This can be called multiple times - ensure the handling is done just once. - if ($GLOBALS['language']->language != 'en' && !drupal_static(__FUNCTION__)) { +function _features_export_language($language = NULL) { + $current = $GLOBALS['language']; + if (isset($language)) { + $GLOBALS['language'] = $language; + } + elseif ($GLOBALS['language']->language != 'en') { // Create the language object as language_default() does. $GLOBALS['language'] = (object) array( 'language' => 'en', @@ -1239,57 +1246,8 @@ function _features_set_export_language() { 'weight' => 0, 'javascript' => '', ); - // Ensure that static caches are cleared, as they might contain language - // specific information. But keep some important ones. The call below - // accesses a non existing key and requests to reset it. In such cases the - // whole caching data array is returned. - $static = drupal_static(uniqid('', TRUE), NULL, TRUE); - drupal_static_reset(); - // Restore some of the language independent, runtime state information to - // keep everything working and avoid unnecessary double processing. - $static_caches_to_keep = array( - 'conf_path', - 'system_list', - 'ip_address', - 'drupal_page_is_cacheable', - 'list_themes', - 'drupal_page_header', - 'drupal_send_headers', - 'drupal_http_headers', - 'language_list', - 'module_implements', - 'drupal_alter', - 'path_is_admin', - 'path_get_admin_paths', - 'drupal_match_path', - 'menu_get_custom_theme', - 'menu_get_item', - 'arg', - 'drupal_system_listing', - 'drupal_parse_info_file', - 'libraries_get_path', - 'module_hook_info', - 'drupal_add_js', - 'drupal_add_js:jquery_added', - 'drupal_add_library', - 'drupal_get_library', - 'drupal_add_css', - 'menu_set_active_trail', - 'menu_link_get_preferred', - 'menu_set_active_menu_names', - 'theme_get_registry', - 'features_get_components', - 'features_get_components_by_key', - ); - foreach ($static_caches_to_keep as $cid) { - if (isset($static[$cid])) { - $data = &drupal_static($cid); - $data = $static[$cid]; - } - } - $called = &drupal_static(__FUNCTION__); - $called = TRUE; } + return $current; } /** @@ -1326,6 +1284,11 @@ function features_features_ignore($component) { case 'field': $ignores['locked'] = 1; break; + case 'field_base': + $ignores['indexes'] = 0; + break; + case 'taxonomy': + $ignores['hierarchy'] = 0; } return $ignores; } diff --git a/sites/all/modules/contrib/admin/features/includes/features.contact.inc b/sites/all/modules/contrib/admin/features/includes/features.contact.inc new file mode 100644 index 00000000..af9b9193 --- /dev/null +++ b/sites/all/modules/contrib/admin/features/includes/features.contact.inc @@ -0,0 +1,115 @@ + array( + 'name' => t('Contact categories'), + 'feature_source' => TRUE, + 'default_hook' => 'contact_categories_defaults', + 'default_file' => FEATURES_DEFAULTS_INCLUDED, + ), + ); +} + +/** + * Implements hook_features_export_options(). + */ +function contact_categories_features_export_options() { + $options = array(); + $categories = db_select('contact', 'c')->fields('c')->execute()->fetchAll(); + foreach ($categories as $category) { + $options["$category->category"] = "$category->category"; + } + return $options; +} + +/** + * Implements hook_features_export(). + */ +function contact_categories_features_export($data, &$export, $module_name = '') { + $export['dependencies']['features'] = 'features'; + $export['dependencies']['contact'] = 'contact'; + + foreach ($data as $name) { + $export['features']['contact_categories'][$name] = $name; + } + + return array(); +} + +/** + * Implements hook_features_export_render(). + */ +function contact_categories_features_export_render($module, $data, $export = NULL) { + $render = array(); + foreach ($data as $name) { + $export_category = db_select('contact', 'c') + ->fields('c', array('cid', 'category')) + ->condition('category', $name, 'LIKE') + ->execute() + ->fetchAll(); + if (isset($export_category[0]->cid) && ($category = contact_load($export_category[0]->cid))) { + unset($category['cid']); + $render[$name] = $category; + } + } + return array('contact_categories_defaults' => ' return ' . features_var_export($render, ' ') . ';'); +} + +/** + * Implements hook_features_revert(). + */ +function contact_categories_features_revert($module) { + return contact_categories_features_rebuild($module); +} + +/** + * Implements hook_features_rebuild(). + */ +function contact_categories_features_rebuild($module) { + if ($defaults = features_get_default('contact_categories', $module)) { + foreach ($defaults as $default_category) { + $existing_categories = db_select('contact', 'c') + ->fields('c', array('cid', 'category')) + ->execute() + ->fetchAll(); + if ($existing_categories) { + foreach ($existing_categories as $existing_category) { + if ($default_category['category'] == $existing_category->category) { + db_update('contact') + ->fields( + array( + 'recipients' => $default_category['recipients'], + 'reply' => $default_category['reply'], + 'weight' => $default_category['weight'], + 'selected' => $default_category['selected'], + ) + ) + ->condition('category', $existing_category->category, '=') + ->execute(); + } + else { + db_merge('contact') + ->key(array('category' => $default_category['category'])) + ->fields($default_category) + ->execute(); + } + } + } + else { + db_merge('contact') + ->key(array('category' => $default_category['category'])) + ->fields($default_category) + ->execute(); + } + } + } +} diff --git a/sites/all/modules/contrib/admin/features/includes/features.field.inc b/sites/all/modules/contrib/admin/features/includes/features.field.inc index c6202748..849081dd 100644 --- a/sites/all/modules/contrib/admin/features/includes/features.field.inc +++ b/sites/all/modules/contrib/admin/features/includes/features.field.inc @@ -158,7 +158,7 @@ function field_base_features_export_render($module, $data, $export = NULL) { unset($field['storage']); } // If we still have a storage declaration here it means that a non-default - // storage type was altered into to the field definition. And noone would + // storage type was altered into to the field definition. And no one would // never need to change the 'details' key, so don't render it. if (isset($field['storage']['details'])) { unset($field['storage']['details']); @@ -170,10 +170,10 @@ function field_base_features_export_render($module, $data, $export = NULL) { $field_identifier = features_var_export($identifier); if (features_field_export_needs_wrap($field_prefix, $field_identifier)) { $code[] = rtrim($field_prefix); - $code[] = " // {$field_identifier}"; + $code[] = " // {$field_identifier}."; } else { - $code[] = $field_prefix . $field_identifier; + $code[] = $field_prefix . $field_identifier . '.'; } $code[] = " \$field_bases[{$field_identifier}] = {$field_export};"; $code[] = ""; @@ -201,10 +201,10 @@ function field_instance_features_export_render($module, $data, $export = NULL) { $instance_identifier = features_var_export($identifier); if (features_field_export_needs_wrap($instance_prefix, $instance_identifier)) { $code[] = rtrim($instance_prefix); - $code[] = " // {$instance_identifier}"; + $code[] = " // {$instance_identifier}."; } else { - $code[] = $instance_prefix . $instance_identifier; + $code[] = $instance_prefix . $instance_identifier . '.'; } $code[] = " \$field_instances[{$instance_identifier}] = {$field_export};"; $code[] = ""; @@ -276,11 +276,21 @@ function field_base_features_rebuild($module) { $existing_field = $existing_fields[$field['field_name']]; $array_diff_result = drupal_array_diff_assoc_recursive($field + $existing_field, $existing_field); if (!empty($array_diff_result)) { - field_update_field($field); + try { + field_update_field($field); + } + catch (FieldException $e) { + watchdog('features', 'Attempt to update field %label failed: %message', array('%label' => $field['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR); + } } } else { - field_create_field($field); + try { + field_create_field($field); + } + catch (FieldException $e) { + watchdog('features', 'Attempt to create field %label failed: %message', array('%label' => $field['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR); + } $existing_fields[$field['field_name']] = $field; } variable_set('menu_rebuild_needed', TRUE); @@ -410,7 +420,7 @@ function field_features_export_render($module, $data, $export = NULL) { unset($field['field_config']['storage']); } // If we still have a storage declaration here it means that a non-default - // storage type was altered into to the field definition. And noone would + // storage type was altered into to the field definition. And no one would // never need to change the 'details' key, so don't render it. if (isset($field['field_config']['storage']['details'])) { unset($field['field_config']['storage']['details']); @@ -562,5 +572,6 @@ function features_field_load($identifier) { * @see https://www.drupal.org/node/1354 */ function features_field_export_needs_wrap($prefix, $identifier) { - return (strlen($prefix) + strlen($identifier) > 80); + // Check for 79 characters, since the comment ends with a full stop. + return (strlen($prefix) + strlen($identifier) > 79); } diff --git a/sites/all/modules/contrib/admin/features/includes/features.locale.inc b/sites/all/modules/contrib/admin/features/includes/features.locale.inc index 126d177d..258d5413 100644 --- a/sites/all/modules/contrib/admin/features/includes/features.locale.inc +++ b/sites/all/modules/contrib/admin/features/includes/features.locale.inc @@ -141,8 +141,8 @@ function _features_language_save($language) { } // Update Existing language. else { - // @TODO: get properties from schema. - $properties = array('language', 'name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight', 'javascript'); + // Get field list from table schema. + $properties = drupal_schema_fields_sql('languages'); // The javascript hash is not in the imported data but should be empty if (!isset($language->javascript)) { $language->javascript = ''; diff --git a/sites/all/modules/contrib/admin/features/includes/features.menu.inc b/sites/all/modules/contrib/admin/features/includes/features.menu.inc index 6ba83e6e..edd47514 100644 --- a/sites/all/modules/contrib/admin/features/includes/features.menu.inc +++ b/sites/all/modules/contrib/admin/features/includes/features.menu.inc @@ -103,7 +103,6 @@ function menu_custom_features_export_render($module, $data) { $code[] = features_translatables_export($translatables, ' '); } - $code[] = ''; $code[] = ' return $menus;'; $code = implode("\n", $code); return array('menu_default_menu_custom' => $code); @@ -248,7 +247,7 @@ function menu_links_features_export_render($module, $data, $export = NULL) { unset($link['plid']); unset($link['mlid']); - $code[] = " // Exported menu link: {$new_identifier}"; + $code[] = " // Exported menu link: {$new_identifier}."; $code[] = " \$menu_links['{$new_identifier}'] = ". features_var_export($link, ' ') .";"; $translatables[] = $link['link_title']; } @@ -316,6 +315,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { foreach ($unordered as $link) { $identifier = menu_links_features_identifier($link); $ordered[$identifier] = 0; + $all_links[$identifier] = $link; } asort($ordered); } diff --git a/sites/all/modules/contrib/admin/features/includes/features.node.inc b/sites/all/modules/contrib/admin/features/includes/features.node.inc index f40341af..25a2c1cd 100644 --- a/sites/all/modules/contrib/admin/features/includes/features.node.inc +++ b/sites/all/modules/contrib/admin/features/includes/features.node.inc @@ -145,11 +145,14 @@ function node_features_disable_feature($module) { * When a features module is enabled, modify any node types it provides so * they can no longer be deleted manually through the content types UI. * + * Update the database cache of node types if needed. + * * @param $module * Name of module that has been enabled. */ function node_features_enable_feature($module) { if ($default_types = features_get_default('node', $module)) { + $rebuild = FALSE; foreach ($default_types as $type_name => $type_info) { // Ensure the type exists. if ($type_info = node_type_load($type_name)) { @@ -160,6 +163,12 @@ function node_features_enable_feature($module) { $type_info->disabled = 0; node_type_save($type_info); } + else { + $rebuild = TRUE; + } + } + if ($rebuild) { + node_types_rebuild(); } } } diff --git a/sites/all/modules/contrib/admin/features/tests/features.test b/sites/all/modules/contrib/admin/features/tests/features.test index bbdeb0b9..025ef23c 100644 --- a/sites/all/modules/contrib/admin/features/tests/features.test +++ b/sites/all/modules/contrib/admin/features/tests/features.test @@ -218,7 +218,7 @@ class FeaturesEnableTestCase extends DrupalWebTestCase { /** - * Tests intergration of ctools for features. + * Tests integration of ctools for features. */ class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase { protected $profile = 'testing'; diff --git a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info index 50085c55..04f01d33 100644 --- a/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info +++ b/sites/all/modules/contrib/admin/features/tests/features_test/features_test.info @@ -21,9 +21,9 @@ features[user_permission][] = create features_test content features[views_view][] = features_test hidden = 1 -; Information added by Drupal.org packaging script on 2015-06-24 -version = "7.x-2.6" +; Information added by Drupal.org packaging script on 2016-04-18 +version = "7.x-2.10" core = "7.x" project = "features" -datestamp = "1435165997" +datestamp = "1461011641"