1129 lines
32 KiB
Plaintext
1129 lines
32 KiB
Plaintext
<?php
|
||
|
||
/**
|
||
* @file
|
||
* Provide features components for exporting core blocks and settings.
|
||
*/
|
||
|
||
/**
|
||
* Version number for the current fe_block export definition.
|
||
*/
|
||
define('FE_BLOCK_VERSION', '2.0');
|
||
|
||
/**
|
||
* Implements hook_features_api().
|
||
*/
|
||
function fe_block_features_api() {
|
||
$info = array();
|
||
|
||
$key = 'fe_block_settings';
|
||
$info[$key] = array(
|
||
'name' => t('Block settings'),
|
||
'feature_source' => TRUE,
|
||
'default_hook' => 'default_' . $key,
|
||
'default_file' => FEATURES_DEFAULTS_INCLUDED,
|
||
);
|
||
|
||
$key = 'fe_block_boxes';
|
||
$info[$key] = array(
|
||
'name' => t('Block contents (boxes)'),
|
||
'feature_source' => TRUE,
|
||
'default_hook' => 'default_' . $key,
|
||
'default_file' => FEATURES_DEFAULTS_INCLUDED,
|
||
);
|
||
|
||
return $info;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export_options().
|
||
*/
|
||
function fe_block_settings_features_export_options() {
|
||
$options = array();
|
||
|
||
$blocks = _fe_block_get_blocks();
|
||
usort($blocks, '_fe_block_compare');
|
||
|
||
foreach ($blocks as $block) {
|
||
// @see features.block.inc
|
||
if (strpos($block['module'], '-') !== FALSE) {
|
||
continue;
|
||
}
|
||
|
||
$block_id = _fe_block_build_id($block);
|
||
if (empty($block_id)) {
|
||
continue;
|
||
}
|
||
$options[$block_id] = '[' . $block_id . '] ' . $block['info'];
|
||
}
|
||
|
||
return $options;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export().
|
||
*/
|
||
function fe_block_settings_features_export($data, &$export, $module_name = '') {
|
||
$pipe = array();
|
||
$export['dependencies']['fe_block'] = 'fe_block';
|
||
|
||
$component = 'fe_block_settings';
|
||
// Add the components.
|
||
foreach ($data as $object_name) {
|
||
$export['features'][$component][$object_name] = $object_name;
|
||
|
||
// Boxes.
|
||
if (strpos($object_name, 'block-') === 0) {
|
||
$machine_name = substr($object_name, strlen('block-'));
|
||
$pipe['fe_block_boxes'][$machine_name] = $machine_name;
|
||
}
|
||
// @todo Export menu blocks.
|
||
// Others.
|
||
else {
|
||
$pipe['block'][$object_name] = $object_name;
|
||
}
|
||
}
|
||
|
||
return $pipe;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export_render().
|
||
*/
|
||
function fe_block_settings_features_export_render($module_name = '', $data) {
|
||
$code = array();
|
||
$code[] = ' $export = array();';
|
||
$code[] = '';
|
||
|
||
// The way the blocks are exported has changed throughout the history of the
|
||
// module. We provide an export format version string to provide backwards
|
||
// compatibility. Note that it is ok to use the array key "version" here.
|
||
// Block ids always have a '-' in their string.
|
||
$code[] = ' $export[\'version\'] = \'' . FE_BLOCK_VERSION . '\';';
|
||
$code[] = '';
|
||
|
||
// Get a list of all active themes to cycle through.
|
||
$themes = _fe_block_get_active_themes();
|
||
|
||
// Retrieve block settings for all blocks in all active themes.
|
||
$blocks = array();
|
||
foreach ($themes as $theme) {
|
||
$blocks[$theme] = _fe_block_info_by_theme($theme);
|
||
}
|
||
|
||
// We use the first theme's block settings as master settings. Some settings
|
||
// are specific to each theme, but these are processed later in the loop.
|
||
$default_theme = reset($themes);
|
||
|
||
// We try to build an export for each defined data element.
|
||
foreach ($data as $name) {
|
||
// Check if the block still exists in the block definitions.
|
||
if (!empty($blocks[$default_theme][$name])) {
|
||
$block = $blocks[$default_theme][$name];
|
||
|
||
// We start to build the export object for this block.
|
||
// First we retrieve data that is valid for any theme.
|
||
$export_block = _fe_block_get_global_settings($block);
|
||
// Ensure core custom block export keys are transformed.
|
||
$export_block = _fe_block_prepare_custom_blocks_for_export($export_block);
|
||
// Add node type settings.
|
||
$export_block['node_types'] = _fe_block_get_block_node_types($block);
|
||
// Add role visibility settings.
|
||
$export_block['roles'] = _fe_block_get_block_roles($block);
|
||
// Add theme specific settings for every active theme.
|
||
$export_block['themes'] = array();
|
||
foreach ($themes as $theme) {
|
||
$export_block['themes'][$theme] = _fe_block_get_theme_specific_settings($blocks[$theme][$name]);
|
||
}
|
||
|
||
// Sort export array keys.
|
||
ksort($export_block);
|
||
|
||
// Export to code.
|
||
$code[] = ' $export[\'' . $name . '\'] = ' . features_var_export($export_block, ' ') . ';';
|
||
// Add an empty line.
|
||
$code[] = '';
|
||
}
|
||
}
|
||
|
||
$code[] = ' return $export;';
|
||
$code = implode("\n", $code);
|
||
|
||
return array('default_fe_block_settings' => $code);
|
||
}
|
||
|
||
/**
|
||
* Returns the block definitions for a specific theme.
|
||
*
|
||
* @param string $theme
|
||
* Machine name of the theme.
|
||
*
|
||
* @return array
|
||
* Array of block definitions.
|
||
*/
|
||
function _fe_block_info_by_theme($theme) {
|
||
$blocks = array();
|
||
foreach (_fe_block_get_blocks($theme) as $block) {
|
||
// Blocks are only valid for export if we got a machine name for them.
|
||
if ($id = _fe_block_build_id($block)) {
|
||
$blocks[$id] = $block;
|
||
}
|
||
}
|
||
// Sort blocks by keys to get a consistent order.
|
||
ksort($blocks);
|
||
return $blocks;
|
||
}
|
||
|
||
/**
|
||
* Retrieve the global (non-theme-specific) part of a block definition.
|
||
*
|
||
* @param array $block
|
||
* A block definition.
|
||
*
|
||
* @return array
|
||
* The block definition filtered on non-theme-specific settings.
|
||
*/
|
||
function _fe_block_get_global_settings($block) {
|
||
$theme_specific_defaults = _fe_block_theme_specific_defaults();
|
||
// Filter on any keys other than the theme specific ones.
|
||
$return = array_diff_key($block, $theme_specific_defaults);
|
||
|
||
// Remove the serial.
|
||
if (isset($return['bid'])) {
|
||
unset($return['bid']);
|
||
}
|
||
// Remove the info from hook_block_info().
|
||
if (isset($return['info'])) {
|
||
unset($return['info']);
|
||
}
|
||
|
||
return $return;
|
||
}
|
||
|
||
/**
|
||
* Helper to prepare a core custom block for export.
|
||
*
|
||
* Replaces the block delta that is used by the core block module with a unique
|
||
* machine name.
|
||
*
|
||
* @param array $block
|
||
* Block definition - can be only part of the original definition.
|
||
*
|
||
* @return array
|
||
* Altered block array.
|
||
*/
|
||
function _fe_block_prepare_custom_blocks_for_export($block) {
|
||
if ($block['module'] == 'block') {
|
||
$block['machine_name'] = fe_block_get_machine_name($block['delta']);
|
||
unset($block['delta']);
|
||
}
|
||
return $block;
|
||
}
|
||
|
||
/**
|
||
* Helper function. Prepares an exported core custom block for import.
|
||
*
|
||
* @param array $block
|
||
* Block definition from the import code.
|
||
*
|
||
* @return array
|
||
* Altered array with machine_name replaced by delta.
|
||
*/
|
||
function _fe_block_prepare_custom_blocks_for_import($block) {
|
||
if ($block['module'] == 'block') {
|
||
$block['delta'] = fe_block_get_bid($block['machine_name'], TRUE);
|
||
unset($block['machine_name']);
|
||
}
|
||
return $block;
|
||
}
|
||
|
||
/**
|
||
* Helper function to get the theme specific settings for a block.
|
||
*
|
||
* @param array $block
|
||
* A single block definition.
|
||
*
|
||
* @return array
|
||
* A filtered block definition with only theme-specific settings.
|
||
*/
|
||
function _fe_block_get_theme_specific_settings($block) {
|
||
$defaults = _fe_block_theme_specific_defaults();
|
||
$settings = array_intersect_key($block, $defaults);
|
||
// Region.
|
||
if ($settings['region'] == BLOCK_REGION_NONE) {
|
||
$settings['status'] = 0;
|
||
$settings['region'] = '';
|
||
}
|
||
ksort($settings);
|
||
return $settings;
|
||
}
|
||
|
||
/**
|
||
* Helper function for filtering theme specific settings.
|
||
*
|
||
* @see _fe_block_get_global_settings()
|
||
* @see _fe_block_get_theme_specific_settings()
|
||
*
|
||
* @return array
|
||
* An array of default settings, keyed by name.
|
||
*/
|
||
function _fe_block_theme_specific_defaults() {
|
||
return array(
|
||
'theme' => '',
|
||
'status' => '',
|
||
'weight' => 0,
|
||
'region' => '',
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Get node type visibility settings for the specified block.
|
||
*
|
||
* @param array $block
|
||
* Block definition array.
|
||
*
|
||
* @return array
|
||
* Array of node types associated with the block.
|
||
*/
|
||
function _fe_block_get_block_node_types($block) {
|
||
$query = db_select('block_node_type', 'bnt')
|
||
->condition('module', $block['module'])
|
||
->condition('delta', $block['delta'])
|
||
->fields('bnt', array('type'))
|
||
->orderBy('bnt.type', 'ASC');
|
||
return $query->execute()->fetchCol();
|
||
}
|
||
|
||
/**
|
||
* Returns the blocks currently exported by modules.
|
||
*
|
||
* This is derived from _block_rehash().
|
||
*
|
||
* @param $theme
|
||
* The theme to retrieve blocks for. If not provided, defaults to the
|
||
* currently used theme.
|
||
*
|
||
* @return
|
||
* Blocks currently exported by modules.
|
||
*/
|
||
function _fe_block_get_blocks($theme = NULL) {
|
||
global $theme_key;
|
||
$blocks = array();
|
||
|
||
drupal_theme_initialize();
|
||
if (!isset($theme)) {
|
||
// If theme is not specifically set, rehash for the current theme.
|
||
$theme = $theme_key;
|
||
}
|
||
|
||
$regions = system_region_list($theme);
|
||
// These are the blocks defined by code and modified by the database.
|
||
$current_blocks = array();
|
||
// These are {block}.bid values to be kept.
|
||
$bids = array();
|
||
$or = db_or();
|
||
// Gather the blocks defined by modules.
|
||
foreach (module_implements('block_info') as $module) {
|
||
$module_blocks = module_invoke($module, 'block_info');
|
||
foreach ($module_blocks as $delta => $block) {
|
||
// Compile a condition to retrieve this block from the database.
|
||
$condition = db_and()
|
||
->condition('module', $module)
|
||
->condition('delta', $delta);
|
||
$or->condition($condition);
|
||
// Add identifiers.
|
||
$block['module'] = $module;
|
||
$block['delta'] = $delta;
|
||
$block['theme'] = $theme;
|
||
$current_blocks[$module][$delta] = $block;
|
||
}
|
||
}
|
||
// Retrieve database settings for all blocks that are defined by modules.
|
||
$code_blocks = $current_blocks;
|
||
$database_blocks = db_select('block', 'b')
|
||
->fields('b')
|
||
->condition($or)
|
||
->condition('theme', $theme)
|
||
->execute();
|
||
foreach ($database_blocks as $block) {
|
||
// Preserve info which is not in the database.
|
||
$block->info = $current_blocks[$block->module][$block->delta]['info'];
|
||
// The cache mode can only by set from hook_block_info(), so that has
|
||
// precedence over the database's value.
|
||
if (isset($current_blocks[$block->module][$block->delta]['cache'])) {
|
||
$block->cache = $current_blocks[$block->module][$block->delta]['cache'];
|
||
}
|
||
// Blocks stored in the database override the blocks defined in code.
|
||
$current_blocks[$block->module][$block->delta] = get_object_vars($block);
|
||
// Preserve this block.
|
||
$bids[$block->bid] = $block->bid;
|
||
}
|
||
drupal_alter('block_info', $current_blocks, $theme, $code_blocks);
|
||
foreach ($current_blocks as $module => $module_blocks) {
|
||
foreach ($module_blocks as $delta => $block) {
|
||
if (!isset($block['pages'])) {
|
||
// {block}.pages is type 'text', so it cannot have a
|
||
// default value, and not null, so we need to provide
|
||
// value if the module did not.
|
||
$block['pages'] = '';
|
||
}
|
||
// Make sure weight is set.
|
||
if (!isset($block['weight'])) {
|
||
$block['weight'] = 0;
|
||
}
|
||
// Disable blocks that are not assigned to a region in the theme.
|
||
if (!empty($block['region']) && $block['region'] != BLOCK_REGION_NONE && !isset($regions[$block['region']]) && $block['status'] == 1) {
|
||
// Disabled modules are moved into the BLOCK_REGION_NONE later so no
|
||
// need to move the block to another region.
|
||
$block['status'] = 0;
|
||
}
|
||
// Set region to none if not enabled and make sure status is set.
|
||
if (empty($block['status'])) {
|
||
$block['status'] = 0;
|
||
$block['region'] = BLOCK_REGION_NONE;
|
||
}
|
||
// Add to the list of blocks we return.
|
||
$blocks[] = $block;
|
||
}
|
||
}
|
||
return $blocks;
|
||
}
|
||
|
||
/**
|
||
* Returns a list of machine names of active themes.
|
||
*
|
||
* @return array
|
||
* An array of theme machine names.
|
||
*/
|
||
function _fe_block_get_active_themes() {
|
||
$theme_names = array();
|
||
foreach (list_themes() as $machine_name => $theme) {
|
||
if (!empty($theme->status)) {
|
||
$theme_names[] = $machine_name;
|
||
}
|
||
}
|
||
sort($theme_names);
|
||
return $theme_names;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_revert().
|
||
*/
|
||
function fe_block_settings_features_revert($module_name = NULL) {
|
||
$component = 'fe_block_settings';
|
||
$defaults = features_get_default($component, $module_name);
|
||
if (empty($defaults)) {
|
||
return;
|
||
}
|
||
|
||
// We remove the version, as we now want to deal with actual block settings.
|
||
unset($defaults['version']);
|
||
|
||
$themes_rehashed = array();
|
||
$active_themes = _fe_block_get_active_themes();
|
||
// The fallback theme for theme specific settings.
|
||
$theme_default = variable_get('theme_default', 'bartik');
|
||
|
||
foreach ($defaults as $block) {
|
||
// Core custom blocks are prepared with a delta value.
|
||
$block = _fe_block_prepare_custom_blocks_for_import($block);
|
||
|
||
// Remove the additional settings from the block array, to process them
|
||
// later. We explicitely set NULL, if no setting was given in the defaults.
|
||
$block_themes = $block['themes'];
|
||
$block_node_types = isset($block['node_types']) ? $block['node_types'] : NULL;
|
||
$block_roles = isset($block['roles']) ? $block['roles'] : NULL;
|
||
unset($block['themes']);
|
||
unset($block['node_types']);
|
||
unset($block['roles']);
|
||
|
||
// Restore theme specific settings for every active theme.
|
||
foreach ($active_themes as $theme) {
|
||
|
||
// Rehash if we did not yet.
|
||
if (empty($themes_rehashed[$theme])) {
|
||
_block_rehash($theme);
|
||
$themes_rehashed[$theme] = TRUE;
|
||
}
|
||
|
||
// Get the theme specific setting for the active theme.
|
||
if (isset($block_themes[$theme])) {
|
||
$key = $theme;
|
||
}
|
||
// Or fallback on the default theme.
|
||
elseif (isset($block_themes[$theme_default])) {
|
||
$key = $theme_default;
|
||
}
|
||
// Or fallback on the first available theme spec.
|
||
else {
|
||
$key = key($block_themes);
|
||
}
|
||
|
||
// Write block settings.
|
||
$write = array_merge($block, $block_themes[$key]);
|
||
drupal_write_record('block', $write, array('module', 'delta', 'theme'));
|
||
}
|
||
// Ensure global settings.
|
||
_fe_block_settings_update_global_settings($block);
|
||
|
||
// Set node type settings
|
||
// (only if there were some defined, to avoid overwriting not yet exported
|
||
// data).
|
||
if (isset($block_node_types)) {
|
||
_fe_block_settings_update_block_node_type_settings($block, $block_node_types);
|
||
}
|
||
|
||
// Apply role visibility settings.
|
||
if (isset($block_roles)) {
|
||
_fe_block_settings_update_block_roles($block, $block_roles);
|
||
}
|
||
}
|
||
|
||
// Clear block cache.
|
||
cache_clear_all(NULL, 'cache_block');
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* Helper to update global block settings for a specific block.
|
||
*
|
||
* @param array $block
|
||
* block definition
|
||
*/
|
||
function _fe_block_settings_update_global_settings($block) {
|
||
$globals = _fe_block_get_global_settings($block);
|
||
db_update('block')
|
||
->fields($globals)
|
||
->condition('module', $block['module'])
|
||
->condition('delta', $block['delta'])
|
||
->execute();
|
||
}
|
||
|
||
/**
|
||
* Helper to update node type settings for a given block.
|
||
*
|
||
* @param array $block
|
||
* block definition
|
||
* @param array $node_types
|
||
* array of node types
|
||
*/
|
||
function _fe_block_settings_update_block_node_type_settings($block, $node_types) {
|
||
|
||
// First delete the old node type settings.
|
||
db_delete('block_node_type')
|
||
->condition('module', $block['module'])
|
||
->condition('delta', $block['delta'])
|
||
->execute();
|
||
|
||
if (!empty($node_types)) {
|
||
$insert = db_insert('block_node_type')
|
||
->fields(array('module', 'delta', 'type'));
|
||
foreach ($node_types as $type) {
|
||
$insert->values(array(
|
||
'module' => $block['module'],
|
||
'delta' => $block['delta'],
|
||
'type' => $type,
|
||
));
|
||
}
|
||
$insert->execute();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Helper to update the block role settings for a given block.
|
||
*
|
||
* @param array $block
|
||
* block definiton
|
||
* @param array $roles
|
||
* Associative array of roles
|
||
* - key: role name
|
||
* - value: (foreign) role id
|
||
*/
|
||
function _fe_block_settings_update_block_roles($block, $block_roles) {
|
||
static $roles;
|
||
|
||
// First get the current set of roles, so we can match role names to rids.
|
||
if (!isset($roles)) {
|
||
$roles = db_select('role', 'r')
|
||
->fields('r', array('rid', 'name'))
|
||
->execute()
|
||
->fetchAllKeyed(1, 0);
|
||
}
|
||
|
||
// First delete the old block role settings.
|
||
db_delete('block_role')
|
||
->condition('module', $block['module'])
|
||
->condition('delta', $block['delta'])
|
||
->execute();
|
||
// Then write the new settings, if any are present.
|
||
if (!empty($block_roles)) {
|
||
$insert = db_insert('block_role')
|
||
->fields(array('module', 'delta', 'rid'));
|
||
// We use a found flag, to avoid empty inserts if no role names match.
|
||
$found = FALSE;
|
||
foreach ($block_roles as $name => $rid) {
|
||
// We only write for roles, matching the given role name.
|
||
if (isset($roles[$name])) {
|
||
$insert->values(array(
|
||
'module' => $block['module'],
|
||
'delta' => $block['delta'],
|
||
'rid' => $roles[$name],
|
||
));
|
||
$found = TRUE;
|
||
}
|
||
}
|
||
if ($found) {
|
||
$insert->execute();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_disable_feature().
|
||
*/
|
||
function fe_block_settings_features_disable_feature($module) {
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_enable_feature().
|
||
*/
|
||
function fe_block_settings_features_enable_feature($module) {
|
||
fe_block_settings_features_revert($module);
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_rebuild().
|
||
*/
|
||
function fe_block_settings_features_rebuild($module) {
|
||
fe_block_settings_features_revert($module);
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export_options().
|
||
*/
|
||
function fe_block_boxes_features_export_options() {
|
||
$table = 'fe_block_boxes';
|
||
$options = array();
|
||
|
||
// Defaults.
|
||
$schema = ctools_export_get_schema($table);
|
||
$export = $schema['export'];
|
||
$defaults = _ctools_export_get_defaults($table, $export);
|
||
foreach ($defaults as $obj) {
|
||
$options[$obj->machine_name] = t('@name [@machine_name]', array('@name' => $obj->info, '@machine_name' => $obj->machine_name));
|
||
}
|
||
|
||
// Normals.
|
||
$query = "SELECT * FROM {{$table}} {$table} INNER JOIN {block_custom} b ON b.bid = {$table}.bid ORDER BY b.bid ASC";
|
||
$result = db_query($query);
|
||
foreach ($result as $obj) {
|
||
$options[$obj->machine_name] = t('@name [@machine_name]', array('@name' => $obj->info, '@machine_name' => $obj->machine_name));
|
||
}
|
||
|
||
ksort($options);
|
||
return $options;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export().
|
||
*/
|
||
function fe_block_boxes_features_export($data, &$export, $module_name = '') {
|
||
$pipe = array();
|
||
$export['dependencies']['fe_block'] = 'fe_block';
|
||
|
||
$table = 'fe_block_boxes';
|
||
// Add the components
|
||
foreach ($data as $object_name) {
|
||
$export['features'][$table][$object_name] = $object_name;
|
||
}
|
||
|
||
return $pipe;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_export_render().
|
||
*/
|
||
function fe_block_boxes_features_export_render($module_name = '', $data) {
|
||
ctools_include('export');
|
||
$component = 'fe_block_boxes';
|
||
$schema = ctools_export_get_schema($component);
|
||
$objects = ctools_export_load_object($component);
|
||
|
||
$code = array();
|
||
$code[] = ' $export = array();';
|
||
$code[] = '';
|
||
foreach ($data as $machine_name) {
|
||
// The object to be exported.
|
||
if (isset($objects[$machine_name]) && $object = $objects[$machine_name]) {
|
||
$additions = array();
|
||
// Load box.
|
||
if (!empty($object->bid) && $box = block_custom_block_get($object->bid)) {
|
||
$additions = (array) $box;
|
||
unset($additions['bid'], $additions['body']);
|
||
|
||
// Code.
|
||
$identifier = $schema['export']['identifier'];
|
||
$code[] = ctools_export_object($component, $object, ' ', $identifier, $additions) . ' $' . $identifier . '->body = ' . features_var_export($box['body']) . ';';
|
||
$code[] = '';
|
||
$code[] = ' $export[\'' . $machine_name . '\'] = $' . $identifier . ';';
|
||
$code[] = '';
|
||
}
|
||
}
|
||
}
|
||
$code[] = ' return $export;';
|
||
$code = implode("\n", $code);
|
||
|
||
return array($schema['export']['default hook'] => $code);
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_revert().
|
||
*/
|
||
function fe_block_boxes_features_revert($module_name = NULL) {
|
||
$defaults = features_get_default('fe_block_boxes', $module_name);
|
||
if (empty($defaults)) {
|
||
return;
|
||
}
|
||
|
||
// Revert.
|
||
foreach ($defaults as $object) {
|
||
if (empty($object->machine_name)) {
|
||
continue;
|
||
}
|
||
|
||
$bid = fe_block_get_bid($object->machine_name);
|
||
if (empty($bid) || !($box = block_custom_block_get($bid))) {
|
||
$result = _fe_block_save_box((array) $object);
|
||
if (!empty($result['bid'])) {
|
||
$or = db_or()
|
||
->condition('bid', $result['bid'])
|
||
->condition('machine_name', $object->machine_name);
|
||
db_delete('fe_block_boxes')
|
||
->condition($or)
|
||
->execute();
|
||
db_insert('fe_block_boxes')
|
||
->fields(array(
|
||
'bid' => $result['bid'],
|
||
'machine_name' => $object->machine_name,
|
||
))
|
||
->execute();
|
||
}
|
||
}
|
||
else {
|
||
$object->bid = $bid;
|
||
$result = _fe_block_save_box((array) $object);
|
||
}
|
||
}
|
||
// Clear block cache
|
||
cache_clear_all(NULL, 'cache_block');
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_disable_feature().
|
||
*/
|
||
function fe_block_boxes_features_disable_feature($module) {
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_enable_feature().
|
||
*/
|
||
function fe_block_boxes_features_enable_feature($module) {
|
||
fe_block_boxes_features_revert($module);
|
||
}
|
||
|
||
/**
|
||
* Implements hook_features_rebuild().
|
||
*/
|
||
function fe_block_boxes_features_rebuild($module) {
|
||
fe_block_boxes_features_revert($module);
|
||
}
|
||
|
||
/**
|
||
* Implements hook_form_alter().
|
||
*/
|
||
function fe_block_form_alter(&$form, $form_state, $form_id) {
|
||
$default_values = array();
|
||
|
||
if ($form_id == 'block_add_block_form' && $form['module']['#value'] == 'block' && user_access('administer features')) {
|
||
$default_values['machine_name'] = '';
|
||
$default_values['bid'] = 0;
|
||
}
|
||
elseif ($form_id == 'block_admin_configure' && $form['module']['#value'] == 'block' && user_access('administer features')) {
|
||
$bid = $form['delta']['#value'];
|
||
$machine_name = fe_block_get_machine_name($bid);
|
||
$default_values['machine_name'] = empty($machine_name) ? '' : $machine_name;
|
||
$default_values['bid'] = $bid;
|
||
}
|
||
// Delete a block.
|
||
elseif ($form_id == 'block_box_delete') {
|
||
$form['#submit'][] = 'fe_block_machine_name_delete';
|
||
}
|
||
|
||
// Add & edit
|
||
if (!empty($default_values)) {
|
||
$form['settings']['machine_name'] = array(
|
||
'#type' => 'textfield',
|
||
'#title' => t('Machine name'),
|
||
'#default_value' => $default_values['machine_name'],
|
||
'#maxlength' => 32,
|
||
'#description' => t('Give the block a machine name to make it exportable with "!features" module.', array('!features' => l('Features', 'http://drupal.org/project/features'))),
|
||
'#weight' => -50,
|
||
);
|
||
$form['bid'] = array(
|
||
'#type' => 'value',
|
||
'#value' => $default_values['bid'],
|
||
);
|
||
|
||
// Validate & submit.
|
||
$form['#validate'][] = 'fe_block_machine_name_validate';
|
||
$form['#submit'][] = 'fe_block_machine_name_submit';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Validate machine name.
|
||
*/
|
||
function fe_block_machine_name_validate($form, &$form_state) {
|
||
if (empty($form_state['values']['machine_name'])) {
|
||
return;
|
||
}
|
||
$table = 'fe_block_boxes';
|
||
|
||
$query = db_select($table)
|
||
->condition('bid', $form_state['values']['bid'], '<>')
|
||
->condition('machine_name', $form_state['values']['machine_name']);
|
||
|
||
$count = $query->countQuery()->execute()->fetchField();
|
||
|
||
if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['machine_name'])) {
|
||
form_set_error('machine_name', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
|
||
}
|
||
elseif ($count > 0) {
|
||
form_set_error('machine_name', t('The machine-readable name has been taken. Please pick another one.'));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Save machine name.
|
||
*/
|
||
function fe_block_machine_name_submit($form, &$form_state) {
|
||
// Insert
|
||
if (empty($form_state['values']['bid'])) {
|
||
$form_state['values']['bid'] = db_select('block_custom')
|
||
->fields('block_custom', array('bid'))
|
||
->condition('info', $form_state['values']['info'])
|
||
->execute()->fetch()->bid;
|
||
}
|
||
if (empty($form_state['values']['bid'])) {
|
||
return;
|
||
}
|
||
|
||
$table = 'fe_block_boxes';
|
||
db_delete($table)
|
||
->condition('bid', $form_state['values']['bid'])
|
||
->execute();
|
||
if (!empty($form_state['values']['machine_name'])) {
|
||
drupal_write_record($table, $form_state['values']);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Delete machine name.
|
||
*/
|
||
function fe_block_machine_name_delete($form, &$form_state) {
|
||
$table = 'fe_block_boxes';
|
||
db_delete($table)->condition('bid', $form_state['values']['bid']);
|
||
}
|
||
|
||
/**
|
||
* Public APIs.
|
||
*
|
||
* TODO
|
||
*/
|
||
|
||
/**
|
||
* Internal functions.
|
||
*/
|
||
|
||
/**
|
||
* Sort blocks with "module" and "delta".
|
||
*/
|
||
function _fe_block_compare($a, $b) {
|
||
$module_cmp = strcmp($a['module'], $b['module']);
|
||
if (!empty($module_cmp)) {
|
||
return $module_cmp;
|
||
}
|
||
return strcmp($a['delta'], $b['delta']);
|
||
}
|
||
|
||
/**
|
||
* Provided for backwards compatibility. Use fe_block_get_machine_name().
|
||
*/
|
||
function _fe_block_get_machine_name($bid) {
|
||
debug(t('The function @function is deprecated.', array('@function' => __FUNCTION__ . '()')));
|
||
return fe_block_get_machine_name($bid);
|
||
}
|
||
|
||
/**
|
||
* Returns the machine name that corresponds to a given block id.
|
||
*
|
||
* @param int $bid
|
||
* The block id for which to retrieve the machine name.
|
||
*
|
||
* @return string | FALSE
|
||
* The machine name, or FALSE if it could not be found.
|
||
*/
|
||
function fe_block_get_machine_name($bid) {
|
||
$machine_names = &drupal_static(__FUNCTION__);
|
||
if (!isset($machine_names[$bid])) {
|
||
$result = db_select('fe_block_boxes')
|
||
->fields('fe_block_boxes', array('machine_name'))
|
||
->condition('bid', $bid)
|
||
->execute()
|
||
->fetch();
|
||
|
||
if (empty($result)) {
|
||
return FALSE;
|
||
}
|
||
$machine_names[$bid] = $result->machine_name;
|
||
}
|
||
return $machine_names[$bid];
|
||
}
|
||
|
||
/**
|
||
* Provided for backwards compatibility. Use fe_block_get_bid() instead.
|
||
*/
|
||
function _fe_block_get_bid($machine_name, $reset = FALSE) {
|
||
debug(t('The function @function is deprecated.', array('@function' => __FUNCTION__ . '()')));
|
||
return fe_block_get_bid($machine_name, $reset);
|
||
}
|
||
|
||
/**
|
||
* Returns the block id that corresponds to a given machine name.
|
||
*
|
||
* @param string $machine_name
|
||
* The machine name of a block for which to retrieve the block id.
|
||
*
|
||
* @return int | FALSE
|
||
* The block id, or FALSE if the machine name was not found.
|
||
*/
|
||
function fe_block_get_bid($machine_name, $reset = FALSE) {
|
||
$bids = &drupal_static(__FUNCTION__);
|
||
if (!isset($bids[$machine_name]) || $reset) {
|
||
$result = db_select('fe_block_boxes')
|
||
->fields('fe_block_boxes', array('bid'))
|
||
->condition('machine_name', $machine_name)
|
||
->execute()
|
||
->fetch();
|
||
|
||
if (empty($result)) {
|
||
return FALSE;
|
||
}
|
||
$bids[$machine_name] = (int) $result->bid;
|
||
}
|
||
return $bids[$machine_name];
|
||
}
|
||
|
||
/**
|
||
* Generate block ID.
|
||
*/
|
||
function _fe_block_build_id($block) {
|
||
if (empty($block['module']) || (empty($block['delta']) && !is_numeric($block['delta']))) {
|
||
return NULL;
|
||
}
|
||
if ($block['module'] == 'block') {
|
||
$machine_name = fe_block_get_machine_name($block['delta']);
|
||
if (empty($machine_name)) {
|
||
return NULL;
|
||
}
|
||
return $block['module'] . '-' . $machine_name;
|
||
}
|
||
else {
|
||
return $block['module'] . '-' . $block['delta'];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Save a box.
|
||
*
|
||
* @param $settings
|
||
* @return array
|
||
*/
|
||
function _fe_block_save_box($settings = array()) {
|
||
if (empty($settings['info'])) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 'info' must be unique.
|
||
if (empty($settings['bid'])) {
|
||
$conflict = db_query("SELECT COUNT(*) as count FROM {block_custom} WHERE info = :info", array('info' => $settings['info']));
|
||
}
|
||
else {
|
||
$conflict = db_query("SELECT COUNT(*) as count FROM {block_custom} WHERE info = :info AND bid <> :bid", array('info' => $settings['info'], ':bid' => $settings['bid']));
|
||
}
|
||
|
||
if (!empty($conflict->fetch()->count)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// Defaults
|
||
$default_settings = array(
|
||
'info' => '',
|
||
'body' => '',
|
||
'format' => 'FILTER_FORMAT_DEFAULT',
|
||
);
|
||
$settings = array_merge($default_settings, $settings);
|
||
|
||
// Save
|
||
if (empty($settings['bid'])) {
|
||
drupal_write_record('block_custom', $settings);
|
||
}
|
||
else {
|
||
drupal_write_record('block_custom', $settings, 'bid');
|
||
}
|
||
|
||
return $settings;
|
||
}
|
||
|
||
/**
|
||
* Implements hook_module_implements_alter().
|
||
*/
|
||
function fe_block_module_implements_alter(&$implementations, $hook) {
|
||
if ($hook == 'default_fe_block_settings_alter') {
|
||
// Ensure fe_block is the first imlementation to be called, so we can
|
||
// convert to the newest format.
|
||
$group = $implementations['fe_block'];
|
||
unset($implementations['fe_block']);
|
||
$rest = array_reverse($implementations, TRUE);
|
||
$rest['fe_block'] = $group;
|
||
$implementations = array_reverse($rest, TRUE);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Implements hook_default_fe_block_settings_alter().
|
||
*/
|
||
function fe_block_default_fe_block_settings_alter(&$defaults) {
|
||
// Convert the settings in the newest format.
|
||
$defaults = _fe_block_settings_convert($defaults);
|
||
}
|
||
|
||
/**
|
||
* Helper function to get the block roles visibility settings.
|
||
*
|
||
* @param array $block
|
||
* the block definition array
|
||
*
|
||
* @return array
|
||
* associated role settings for the block
|
||
* - key: role name
|
||
* - value: role id
|
||
*/
|
||
function _fe_block_get_block_roles($block) {
|
||
$query = db_select('block_role', 'br')
|
||
->condition('br.module', $block['module'])
|
||
->condition('br.delta', $block['delta']);
|
||
$query->innerJoin('role', 'r', 'r.rid = br.rid');
|
||
$query->fields('r', array('name', 'rid'))
|
||
->orderBy('r.name', 'ASC');
|
||
$roles = $query->execute()->fetchAllKeyed(0, 1);
|
||
return $roles;
|
||
}
|
||
|
||
/**
|
||
* Helper function to convert an older export into the new format.
|
||
*
|
||
* @param array $defaults
|
||
* array of fe_block_settings definition.
|
||
*
|
||
* @return array
|
||
* array of current fe_block_settings definition
|
||
*/
|
||
function _fe_block_settings_convert($defaults) {
|
||
|
||
$version = (isset($defaults['version'])) ? $defaults['version'] : 0;
|
||
|
||
// Directly return if the version is the current one.
|
||
if ($version == FE_BLOCK_VERSION) {
|
||
return $defaults;
|
||
}
|
||
elseif ($version == '1.0') {
|
||
|
||
// We try to get the default theme for the global definitions, else we take
|
||
// the first.
|
||
$theme_default = variable_get('theme_default', 'bartik');
|
||
if (!isset($defaults['theme'][$theme_default])) {
|
||
$theme_default = key($defaults['theme']);
|
||
}
|
||
|
||
$blocks = array();
|
||
// We get the basic blocks from the visibility array.
|
||
foreach ($defaults['visibility'] as $block_id => $base) {
|
||
$node_types = array();
|
||
if (isset($base['node_type'])) {
|
||
// Node types were specified in node_type => TRUE/FALSE. Now we simply
|
||
// list the selected node types.
|
||
$node_types = array_keys(array_filter($base));
|
||
unset($base['node_type']);
|
||
}
|
||
|
||
$block = $base;
|
||
$block['node_types'] = $node_types;
|
||
|
||
// Global settings.
|
||
$globals = _fe_block_get_global_settings($defaults['theme'][$theme_default][$block_id]);
|
||
$block = array_merge($globals, $block);
|
||
|
||
// Build theme specific array.
|
||
$block['themes'] = array();
|
||
foreach ($defaults['theme'] as $theme => $items) {
|
||
$block['themes'][$theme] = _fe_block_get_theme_specific_settings($items[$block_id]);
|
||
}
|
||
$blocks[$block_id] = $block;
|
||
}
|
||
// Set current version so we can compare it with current version defaults.
|
||
$blocks['version'] = FE_BLOCK_VERSION;
|
||
return $blocks;
|
||
}
|
||
// The oldest version.
|
||
// There we got an array of themes that holded the block settings.
|
||
elseif ($version == 0) {
|
||
|
||
// We try to get the default theme for the global definitions, else we take
|
||
// the first.
|
||
$theme_default = variable_get('theme_default', 'bartik');
|
||
if (!isset($defaults[$theme_default])) {
|
||
$theme_default = key($defaults);
|
||
}
|
||
|
||
$blocks = array();
|
||
foreach ($defaults as $theme => $items) {
|
||
foreach ($items as $block_id => $item) {
|
||
|
||
// Avoid php notices.
|
||
if (!isset($blocks[$block_id])) {
|
||
$blocks[$block_id] = array(
|
||
'themes' => array(),
|
||
);
|
||
}
|
||
|
||
// Set theme specific settings.
|
||
$blocks[$block_id]['themes'][$theme] = _fe_block_get_theme_specific_settings($item);
|
||
|
||
// We add the global settings for the default theme.
|
||
if ($theme == $theme_default) {
|
||
$globals = _fe_block_get_global_settings($item);
|
||
$blocks[$block_id] = array_merge($blocks[$block_id], $globals);
|
||
}
|
||
}
|
||
}
|
||
// Set current version so we can compare it with current version defaults.
|
||
$blocks['version'] = FE_BLOCK_VERSION;
|
||
|
||
return $blocks;
|
||
}
|
||
}
|