class Layout {
var $name = '';
var $title = '';
var $description;
var $module;
private $path;
var $weight = 0;
var $storage;
var $layout;
var $layout_template;
var $disabled = FALSE;
var $locked = FALSE;
var $conditions = array();
var $relationships = array();
var $menu_item = NULL;
var $settings = array();
var $content = array();
var $positions = array();
var $in_progress;
var $renderer_name = 'standard';
var $orphaned_blocks = array();
var $refuge_region;
private $contexts = array();
var $removed_blocks = array();
function __construct(array $config = array()) {
foreach ($config as $property => $property_value) {
$this->{$property} = $property_value;
}
$this->settings += array(
'title' => '',
'title_display' => LAYOUT_TITLE_DEFAULT,
'title_block' => NULL,
);
if (isset($this->layout) && !isset($this->layout_template)) {
$this->layout_template = $this->layout;
unset($this->layout);
}
if (isset($config['module'])) {
if (empty($config['storage']) || $config['storage'] == LAYOUT_STORAGE_DEFAULT) {
$this->storage = LAYOUT_STORAGE_DEFAULT;
}
else {
$this->storage = LAYOUT_STORAGE_OVERRIDE;
}
}
else {
$this->storage = LAYOUT_STORAGE_NORMAL;
}
$handlers = array(
'content' => 'block',
'conditions' => 'layout_access',
'contexts' => 'layout_context',
'relationships' => 'layout_relationship',
);
foreach ($handlers as $property_key => $plugin_type) {
foreach ($this->{$property_key} as $plugin_type_key => $plugin_data) {
if ($property_key == 'contexts') {
$plugin_data['data']['storage'] = TRUE;
}
$this->{$property_key}[$plugin_type_key] = layout_create_handler($plugin_type, $plugin_data['plugin'], $plugin_data['data']);
}
}
if (is_null($this->contexts)) {
$this->contexts = array();
}
}
function save() {
if ($this->storage === LAYOUT_STORAGE_DEFAULT) {
$this->storage = LAYOUT_STORAGE_OVERRIDE;
}
$is_new = !empty($this->is_new);
foreach ($this->contexts as $key => $context) {
if (!$context->storage) {
unset($this->contexts[$key]);
}
}
foreach (module_implements('layout_presave') as $module) {
$function = $module . '_layout_presave';
$function($this);
}
$data = array(
'path' => $this->path,
'name' => $this->name,
'title' => $this->title,
'description' => $this->description,
'renderer_name' => $this->renderer_name,
'module' => $this->module,
'weight' => $this->weight,
'storage' => $this->storage,
'layout_template' => $this->layout_template,
'disabled' => $this->disabled,
'settings' => $this->settings,
'positions' => $this->positions,
'contexts' => $this->contexts,
'relationships' => $this->relationships,
);
if (empty($this->name)) {
throw new LayoutSaveException(t('The layout must have a name specified to save.'));
}
$sub_parts = array(
'content',
'conditions',
'contexts',
'relationships',
);
foreach ($sub_parts as $config_type) {
foreach ($this->$config_type as $config_type_key => $config_type_data) {
unset($config_type_data->is_new);
$data[$config_type][$config_type_key] = array(
'plugin' => $config_type_data->plugin,
'data' => $config_type_data->toArray(),
);
}
}
if (isset($this->original_name) && $this->original_name != $this->name) {
config('layout.layout.' . $this->original_name)->delete();
}
config('layout.layout.' . $this->name)
->setData($data)
->save();
$fids = array();
foreach ($this->content as $content) {
if (is_a($content, 'BlockText')) {
$block_content = $content->settings['content'];
$block_fids = filter_parse_file_fids($block_content);
if (isset($block_fids)) {
$fids = array_merge($fids, $block_fids);
}
}
}
$files = file_load_multiple($fids);
foreach ($files as $fid => $file) {
if ((int) ($file && $file->status) !== FILE_STATUS_PERMANENT) {
file_usage_add($file, 'file', 'file', $file->fid);
}
}
if ((layout_provides_path($this->path) === FALSE) && menu_get_item($this->path)) {
if ($this->menu_item) {
$this->menu_item->delete();
}
}
else {
if ($this->menu_item) {
if ($this->menu_item->path !== $this->path) {
$new_menu_item = clone($this->menu_item);
$new_menu_item->path = $this->path;
$new_menu_item->name = $this->name;
$new_menu_item->is_new = TRUE;
$this->menu_item->reassign();
$this->menu_item = $new_menu_item;
$this->menu_item->save();
}
else {
if (isset($this->original_name) && $this->original_name !== $this->name && $this->menu_item->name === $this->original_name) {
config('layout.menu_item.' . $this->original_name)->delete();
}
$this->menu_item->save();
}
}
}
layout_reset_caches();
$new_this = layout_load($this->name);
if ($is_new) {
$new_this->invokeHook('insert');
}
else {
$new_this->invokeHook('update');
}
}
function delete() {
if ($this->storage === LAYOUT_STORAGE_NORMAL) {
config('layout.layout.' . $this->name)->delete();
if ($this->menu_item && $this->menu_item->name === $this->name) {
$this->menu_item->reassign();
}
$this->invokeHook('delete');
layout_reset_caches();
}
else {
$this->disable();
}
}
function revert() {
if (!empty($this->module)) {
config('layout.layout.' . $this->name)->delete();
config_install_default_config($this->module, 'layout.layout.' . $this->name);
if ($this->menu_item && $this->menu_item->name === $this->name) {
$this->menu_item->revert();
}
layout_reset_caches();
$this->invokeHook('revert');
}
}
function disable() {
$this->disabled = TRUE;
$this->save();
if ($this->menu_item && $this->menu_item->name === $this->name) {
$this->menu_item->reassign();
}
$this->invokeHook('disable');
}
function enable() {
$this->disabled = FALSE;
$this->save();
if ($this->menu_item && $this->menu_item->name === $this->name) {
$this->menu_item->reassign();
}
$this->invokeHook('enable');
}
protected function invokeHook($hook) {
module_invoke_all('layout_' . $hook, $this);
}
function getClone() {
$clone = clone($this);
$clone->name = NULL;
$clone->is_new = TRUE;
$clone->module = NULL;
$clone->storage = LAYOUT_STORAGE_NORMAL;
$clone->content = array();
$clone->positions = array();
foreach ($this->positions as $region => $block_uuids) {
foreach ($block_uuids as $block_uuid) {
$new_block = $this->content[$block_uuid]->getClone();
$clone->content[$new_block->uuid] = $new_block;
$clone->positions[$region][] = $new_block->uuid;
}
}
$clone->weight--;
return $clone;
}
function form(&$form, &$form_state) {
}
function addBlock($block_module, $block_delta, $region_name, $position = NULL) {
$block = layout_create_handler('block', $block_module . ':' . $block_delta);
$uuid = new Uuid();
$block->uuid = $uuid->generate();
$this->content[$block->uuid] = $block;
$this->positions[$region_name][] = $block->uuid;
if ($position) {
$positions = array();
foreach ($this->positions[$region_name] as $n => $uuid) {
if ($position == $n) {
$positions[] = $block->uuid;
}
if ($uuid != $block->uuid) {
$positions[] = $uuid;
}
}
$this->positions[$region_name] = $positions;
}
return $block;
}
function removeBlock($block_uuid) {
$this->removed_blocks[$block_uuid] = $this->content[$block_uuid];
unset($this->content[$block_uuid]);
foreach ($this->positions as $region => $positions) {
$key = array_search($block_uuid, $positions);
if ($key !== FALSE) {
unset($this->positions[$region][$key]);
unset($this->content[$block_uuid]);
}
}
}
function getBlockPosition($block_uuid, $type = 'region') {
foreach ($this->positions as $region => $blocks) {
foreach (array_values($blocks) as $position => $uuid) {
if ($block_uuid === $uuid) {
return $type === 'region' ? $region : $position;
}
}
}
return FALSE;
}
function setBlockPosition($block_uuid, $region_name, $position = NULL) {
if (empty($this->positions[$region_name]) || $position > count($this->positions[$region_name])) {
$position = NULL;
}
if ($current_region = $this->getBlockPosition($block_uuid)) {
$current_position = array_search($block_uuid, $this->positions[$current_region]);
if ($current_position !== FALSE) {
unset($this->positions[$current_region][$current_position]);
$this->positions[$current_region] = array_values($this->positions[$current_region]);
}
}
if (isset($region_position)) {
$new_positions = array();
foreach (array_values($this->positions[$region_name]) as $region_position => $existing_uuid) {
if ($region_position === $position) {
$new_positions[] = $block_uuid;
}
$new_positions[] = $existing_uuid;
}
$this->positions[$region_name] = $new_positions;
}
else {
$this->positions[$region_name][] = $block_uuid;
}
}
function formValidate($form, &$form_state) {
}
function formSubmit($form, &$form_state) {
}
function setPath($path) {
if (empty($this->menu_item) || $this->menu_item->path !== $path) {
if ($existing_item = layout_menu_item_load_multiple_by_path($path)) {
$this->menu_item = $existing_item;
}
elseif (layout_provides_path($path) === NULL) {
if (empty($this->menu_item)) {
$menu_item_settings = array(
'path' => $path,
'name' => $this->name,
);
$this->menu_item = new LayoutMenuItem($menu_item_settings);
}
else {
$this->menu_item->path = $path;
}
}
else {
if ($this->menu_item) {
$this->menu_item->delete();
}
$this->menu_item = NULL;
}
}
if ($this->path !== $path) {
$this->path = $path;
$this->resetContexts();
}
}
function getPath() {
if ($this->menu_item) {
return $this->menu_item->path;
}
else {
return $this->path;
}
}
function setLayoutTemplate($layout_name, $region_mapping = array()) {
if ($layout_name === $this->layout_template && empty($region_mapping)) {
return;
}
if (!isset($this->layout_template)) {
$this->layout_template = $layout_name;
return;
}
$old_layout_info = layout_get_layout_template_info($this->layout_template);
$new_layout_info = layout_get_layout_template_info($layout_name);
$new_positions = array();
$new_regions = array_keys($new_layout_info['regions']);
foreach ($new_regions as $new_region_name) {
$new_positions[$new_region_name] = array();
}
if ($region_mapping) {
$regions = array_keys($region_mapping);
$regions = array_unique(array_merge($regions, array_keys($old_layout_info['regions'])));
}
else {
$regions = array_keys($old_layout_info['regions']);
}
foreach ($regions as $old_region_name) {
if (isset($region_mapping[$old_region_name])) {
$new_region_name = $region_mapping[$old_region_name];
}
elseif (array_key_exists($old_region_name, $new_layout_info['regions'])) {
$new_region_name = $old_region_name;
}
else {
$new_region_name = '';
}
if (isset($this->positions[$old_region_name])) {
foreach ($this->positions[$old_region_name] as $uuid) {
if (!empty($new_region_name)) {
$new_positions[$new_region_name][] = $uuid;
}
elseif ($new_region_name === '') {
$this->orphaned_blocks[] = $uuid;
}
else {
unset($this->content[$uuid]);
}
}
}
}
if (!empty($this->orphaned_blocks)) {
end($new_positions);
$this->refuge_region = !empty($new_layout_info['default region']) ? $new_layout_info['default region'] : key($new_positions);
foreach ($this->orphaned_blocks as $uuid) {
$new_positions[$this->refuge_region][] = $uuid;
}
}
$this->layout_template = $layout_name;
$this->positions = $new_positions;
module_invoke_all('layout_template_change', $this, $old_layout_info['name']);
}
function getContexts($include_types = LayoutContext::USAGE_TYPE_ALL) {
if (is_null($this->contexts)) {
$this->contexts = array();
}
foreach ($this->contexts as $key => $context) {
if (!isset($context->position) && !is_object($context->data)) {
$context_info = layout_get_context_info($context->plugin);
if (isset($context_info['load callback'])) {
$context_data = call_user_func_array($context_info['load callback'], $context->settings);
$context->setData($context_data);
}
}
}
if ($this->menu_item) {
$this->contexts += $this->menu_item->getContexts();
}
elseif ($this->path) {
$this->contexts += layout_context_required_by_path($this->path);
}
if ($include_types & LayoutContext::USAGE_TYPE_RELATIONSHIP) {
$this->contexts += $this->getContextsFromRelationships();
}
if (!isset($this->contexts['current_user'])) {
$this->contexts['current_user'] = layout_current_user_context();
}
if (empty($this->menu_item) && !isset($this->contexts['overrides_path'])) {
$this->contexts['overrides_path'] = layout_create_context('overrides_path', array(
'name' => 'overrides_path',
'locked' => TRUE,
));
}
if ($include_types === LayoutContext::USAGE_TYPE_ALL) {
return $this->contexts;
}
$return_contexts = array();
foreach ($this->contexts as $key => $context) {
if ($context->usageType & $include_types) {
$return_contexts[$key] = $context;
}
}
return $return_contexts;
}
function setContexts($key, $context) {
$this->contexts[$key] = $context;
}
function clearContexts($key) {
unset($this->contexts[$key]);
}
function resetContexts() {
foreach ($this->contexts as $key => $context) {
if (!$context->storage) {
unset($this->contexts[$key]);
}
}
if ($this->menu_item) {
$this->menu_item->resetContexts();
}
}
function hasContexts($required_contexts) {
$all_contexts = $this->getContexts();
foreach ($required_contexts as $required_context_name) {
$context_missing = TRUE;
foreach ($all_contexts as $context) {
if ($context->isA($required_context_name)) {
$context_missing = FALSE;
break;
}
}
if ($context_missing) {
return FALSE;
}
}
return TRUE;
}
private function getContextFromRelationship(LayoutRelationship $relationship, LayoutContext $source_context) {
$new_context = clone($source_context);
$context = $relationship->getContext($new_context);
if ($context) {
$context->usageType = LayoutContext::USAGE_TYPE_RELATIONSHIP;
return $context;
}
return FALSE;
}
private function getContextsFromRelationships() {
$contexts = array();
$contexts_from_relationships_list = array();
foreach ($this->relationships as $relationship_name => $relationship_data) {
$key = 'relationship_' . $relationship_name;
if (!isset($contexts_from_relationships_list[$key])) {
foreach ($this->contexts as $context) {
if ($context->plugin == $relationship_data->context) {
$plugin_array = explode(':', $relationship_data->settings['relationship']);
if ($plugin_array[1] != 'child') {
$relationship_data->childDelta = $plugin_array[1];
}
$contexts_from_relationships_list[$key] = $this->getContextFromRelationship($relationship_data, $context);
}
}
}
}
if ($contexts_from_relationships_list) {
foreach ($contexts_from_relationships_list as $key => $context_from_relationships) {
if (is_object($context_from_relationships)) {
$contexts[$key] = $context_from_relationships;
}
}
}
return $contexts;
}
function isDefault() {
return in_array($this->name, array('default', 'admin_default'));
}
function checkAccess() {
$contexts = $this->getContexts();
foreach ($this->conditions as $condition) {
$condition->setContexts($contexts);
if (!$condition->checkAccess()) {
return FALSE;
}
}
return TRUE;
}
}