Display.php 5.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
<?php

/**
 * @file
 * Definition of Drupal\layout\Plugin\Core\Entity\Display.
 */

namespace Drupal\layout\Plugin\Core\Entity;

use Drupal\layout\Config\DisplayBase;
use Drupal\layout\Config\BoundDisplayInterface;
use Drupal\layout\Config\UnboundDisplayInterface;
use Drupal\layout\Plugin\LayoutInterface;
14
use Drupal\Core\Entity\Annotation\EntityType;
15 16 17 18 19
use Drupal\Core\Annotation\Translation;

/**
 * Defines the display entity.
 *
20
 * @EntityType(
21 22 23
 *   id = "display",
 *   label = @Translation("Display"),
 *   module = "layout",
24 25 26
 *   controllers = {
 *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController"
 *   },
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
 *   config_prefix = "display.bound",
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid"
 *   }
 * )
 */
class Display extends DisplayBase implements BoundDisplayInterface {

  /**
   * A two-level array expressing block ordering within regions.
   *
   * The outer array is associative, keyed on region name. Each inner array is
   * indexed, with the config address of a block as values and sorted according
   * to order in which those blocks should appear in that region.
   *
   * This property is not stored statically in config, but is derived at runtime
   * by DisplayBase::sortBlocks(). It is not stored statically because that
   * would make using weights for ordering more difficult, and weights make
   * external mass manipulation of displays much easier.
   *
   * @var array
   */
  protected $blocksInRegions;

  /**
   * The layout instance being used to serve this page.
   *
   * @var \Drupal\layout\Plugin\LayoutInterface
   */
  protected $layoutInstance;

  /**
   * The name of the layout plugin to use.
   *
   * @var string
   */
  public $layout;

  /**
   * The settings with which to instantiate the layout plugin.
   *
   * @var array
   */
  public $layoutSettings = array();

  /**
   * Implements BoundDisplayInterface::getSortedBlocksByRegion().
   *
   * @throws \Exception
   */
  public function getSortedBlocksByRegion($region) {
    if ($this->blocksInRegions === NULL) {
      $this->sortBlocks();
    }

    if (!isset($this->blocksInRegions[$region])) {
      throw new \Exception(sprintf("Region %region does not exist in layout %layout", array('%region' => $region, '%layout' => $this->getLayoutInstance()->name)), E_RECOVERABLE_ERROR);
    }

    return $this->blocksInRegions[$region];
  }

  /**
   * Implements BoundDisplayInterface::getAllSortedBlocks().
   */
  public function getAllSortedBlocks() {
    if ($this->blocksInRegions === NULL) {
      $this->sortBlocks();
    }

    return $this->blocksInRegions;
  }

  /**
   * Transform the stored blockConfig into a sorted, region-oriented array.
   */
  protected function sortBlocks() {
    $layout_instance = $this->getLayoutInstance();
    if ($this->layout !== $layout_instance->getPluginId()) {
      $block_config = $this->mapBlocksToLayout($layout_instance);
    }
    else {
      $block_config = $this->blockInfo;
    }

    $this->blocksInRegions = array();

    $regions = array_fill_keys(array_keys($layout_instance->getRegions()), array());
    foreach ($block_config as $config_name => $info) {
      $regions[$info['region']][$config_name] = $info;
    }

    foreach ($regions as $region_name => &$blocks) {
      uasort($blocks, 'drupal_sort_weight');
      $this->blocksInRegions[$region_name] = array_keys($blocks);
    }
  }

  /**
   * Implements BoundDisplayInterface::remapToLayout().
   */
  public function remapToLayout(LayoutInterface $layout) {
    $this->blockInfo = $this->mapBlocksToLayout($layout);
    $this->setLayout($layout->getPluginId());
  }

  /**
   * Set the contained layout plugin.
   *
   * @param string $plugin_id
   *   The plugin id of the desired layout plugin.
   */
  public function setLayout($plugin_id) {
    // @todo verification?
    $this->layout = $plugin_id;
    $this->layoutInstance = NULL;
    $this->blocksInRegions = NULL;
  }

  /**
   * Implements BoundDisplayInterface::generateUnboundDisplay().
   *
   * @throws \Exception
   */
  public function generateUnboundDisplay($id, $entity_type = 'unbound_display') {
    $block_info = $this->getAllBlockInfo();
    foreach ($block_info as &$info) {
      unset($info['region']);
    }

    $values = array(
      'blockInfo' => $block_info,
      'id' => $id,
    );

    $entity = entity_create($entity_type, $values);
    if (!$entity instanceof UnboundDisplayInterface) {
      throw new \Exception(sprintf('Attempted to create an unbound display using an invalid entity type.'), E_RECOVERABLE_ERROR);
    }

    return $entity;
  }

  /**
   * Returns the instantiated layout object.
   *
   * @throws \Exception
   */
  public function getLayoutInstance() {
    if ($this->layoutInstance === NULL) {
      if (empty($this->layout)) {
        throw new \Exception(sprintf('Display "%id" had no layout plugin attached.', array('%id' => $this->id())), E_RECOVERABLE_ERROR);
      }

      $this->layoutInstance = layout_manager()->createInstance($this->layout, $this->layoutSettings);
      // @todo add handling for remapping if the layout could not be found
    }

    return $this->layoutInstance;
  }
}