View.php 8.81 KB
Newer Older
1
<?php
2 3 4

/**
 * @file
5
 * Definition of Drupal\views\Entity\View.
6 7
 */

8
namespace Drupal\views\Entity;
9

10
use Drupal\Core\Cache\Cache;
11
use Drupal\Core\Config\Entity\ConfigEntityBase;
12
use Drupal\Core\Entity\EntityStorageControllerInterface;
13
use Drupal\views\Views;
14
use Drupal\views_ui\ViewUI;
15 16
use Drupal\views\ViewStorageInterface;
use Drupal\views\ViewExecutable;
17

18
/**
19 20
 * Defines a View configuration entity class.
 *
21
 * @EntityType(
22 23
 *   id = "view",
 *   label = @Translation("View"),
24
 *   controllers = {
25 26
 *     "storage" = "Drupal\views\ViewStorageController",
 *     "access" = "Drupal\views\ViewAccessController"
27
 *   },
28
 *   admin_permission = "administer views",
29 30
 *   config_prefix = "views.view",
 *   entity_keys = {
31
 *     "id" = "id",
32
 *     "label" = "label",
33 34
 *     "uuid" = "uuid",
 *     "status" = "status"
35 36
 *   }
 * )
37
 */
38
class View extends ConfigEntityBase implements ViewStorageInterface {
39

40 41 42 43 44
  /**
   * The name of the base table this view will use.
   *
   * @var string
   */
45
  protected $base_table = 'node';
46 47

  /**
48
   * The unique ID of the view.
49 50 51
   *
   * @var string
   */
52
  public $id = NULL;
53

54 55 56 57 58
  /**
   * The label of the view.
   */
  protected $label;

59 60 61 62 63
  /**
   * The description of the view, which is used only in the interface.
   *
   * @var string
   */
64
  protected $description = '';
65 66 67 68 69 70 71 72 73

  /**
   * The "tags" of a view.
   *
   * The tags are stored as a single string, though it is used as multiple tags
   * for example in the views overview.
   *
   * @var string
   */
74
  protected $tag = '';
75 76 77 78 79 80

  /**
   * The core version the view was created for.
   *
   * @var int
   */
81
  protected $core = \Drupal::CORE_COMPATIBILITY;
82 83 84 85 86 87 88 89 90

  /**
   * Stores all display handlers of this view.
   *
   * An array containing Drupal\views\Plugin\views\display\DisplayPluginBase
   * objects.
   *
   * @var array
   */
91
  protected $display = array();
92 93 94 95 96 97

  /**
   * The name of the base field to use.
   *
   * @var string
   */
98
  protected $base_field = 'nid';
99 100

  /**
101
   * The UUID for this entity.
102
   *
103
   * @var string
104
   */
105
  public $uuid = NULL;
106

107
  /**
108
   * Stores a reference to the executable version of this view.
109
   *
110
   * @var \Drupal\views\ViewExecutable
111
   */
112
  protected $executable;
113

114 115 116 117 118
  /**
   * The module implementing this view.
   *
   * @var string
   */
119
  protected $module = 'views';
120

121
  /**
122 123 124 125
   * Gets an executable instance for this view.
   *
   * @return \Drupal\views\ViewExecutable
   *   A view executable instance.
126
   */
127
  public function getExecutable() {
128
    // Ensure that an executable View is available.
129 130
    if (!isset($this->executable)) {
      $this->executable = Views::executableFactory()->get($this);
131 132
    }

133
    return $this->executable;
134 135
  }

136 137 138 139 140 141 142 143 144
  /**
   * Overrides Drupal\Core\Config\Entity\ConfigEntityBase::createDuplicate().
   */
  public function createDuplicate() {
    $duplicate = parent::createDuplicate();
    unset($duplicate->executable);
    return $duplicate;
  }

145
  /**
146
   * Overrides \Drupal\Core\Entity\Entity::label().
147
   *
148
   * When a certain view doesn't have a label return the ID.
149
   */
150
  public function label() {
151 152
    if (!$label = $this->get('label')) {
      $label = $this->id();
153
    }
154
    return $label;
155 156
  }

157
  /**
158
   * Adds a new display handler to the view, automatically creating an ID.
159
   *
160 161 162 163 164 165 166 167 168 169 170 171
   * @param string $plugin_id
   *   (optional) The plugin type from the Views plugin annotation. Defaults to
   *   'page'.
   * @param string $title
   *   (optional) The title of the display. Defaults to NULL.
   * @param string $id
   *   (optional) The ID to use, e.g., 'default', 'page_1', 'block_2'. Defaults
   *   to NULL.
   *
   * @return string|false
   *   The key to the display in $view->display, or FALSE if no plugin ID was
   *   provided.
172
   */
173
  public function addDisplay($plugin_id = 'page', $title = NULL, $id = NULL) {
174
    if (empty($plugin_id)) {
175 176 177
      return FALSE;
    }

178
    $plugin = Views::pluginManager('display')->getDefinition($plugin_id);
179 180 181 182 183
    if (empty($plugin)) {
      $plugin['title'] = t('Broken');
    }

    if (empty($id)) {
184
      $id = $this->generateDisplayId($plugin_id);
185

186 187
      // Generate a unique human-readable name by inspecting the counter at the
      // end of the previous display ID, e.g., 'page_1'.
188 189 190 191 192 193 194 195 196
      if ($id !== 'default') {
        preg_match("/[0-9]+/", $id, $count);
        $count = $count[0];
      }
      else {
        $count = '';
      }

      if (empty($title)) {
197 198 199
        // If there is no title provided, use the plugin title, and if there are
        // multiple displays, append the count.
        $title = $plugin['title'];
200
        if ($count > 1) {
201
          $title .= ' ' . $count;
202 203 204 205
        }
      }
    }

206
    $display_options = array(
207
      'display_plugin' => $plugin_id,
208 209
      'id' => $id,
      'display_title' => $title,
210
      'position' => count($this->display),
211
      'display_options' => array(),
212 213
    );

214 215
    // Add the display options to the view.
    $this->display[$id] = $display_options;
216 217 218 219
    return $id;
  }

  /**
220
   * Generates a display ID of a certain plugin type.
221
   *
222 223
   * @param string $plugin_id
   *   Which plugin should be used for the new display ID.
224
   */
225
  protected function generateDisplayId($plugin_id) {
226 227
    // 'default' is singular and is unique, so just go with 'default'
    // for it. For all others, start counting.
228
    if ($plugin_id == 'default') {
229 230
      return 'default';
    }
231 232
    // Initial ID.
    $id = $plugin_id . '_1';
233 234 235 236 237
    $count = 1;

    // Loop through IDs based upon our style plugin name until
    // we find one that is unused.
    while (!empty($this->display[$id])) {
238
      $id = $plugin_id . '_' . ++$count;
239 240 241 242 243
    }

    return $id;
  }

244
  /**
245
   * {@inheritdoc}
246 247 248 249 250
   */
  public function &getDisplay($display_id) {
    return $this->display[$display_id];
  }

251 252 253 254 255 256 257 258 259
  /**
   * Overrides \Drupal\Core\Config\Entity\ConfigEntityBase::getExportProperties();
   */
  public function getExportProperties() {
    $names = array(
      'base_field',
      'base_table',
      'core',
      'description',
260
      'status',
261
      'display',
262
      'label',
263
      'module',
264
      'id',
265 266
      'tag',
      'uuid',
267
      'langcode',
268 269 270 271 272 273 274 275
    );
    $properties = array();
    foreach ($names as $name) {
      $properties[$name] = $this->get($name);
    }
    return $properties;
  }

276 277 278 279
  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
280 281
    parent::postSave($storage_controller, $update);

282 283 284 285
    // Clear cache tags for this view.
    // @todo Remove if views implements a view_builder controller.
    $id = $this->id();
    Cache::deleteTags(array('view' => array($id => $id)));
286 287 288 289 290
    views_invalidate_cache();
  }

  /**
   * {@inheritdoc}
291 292 293 294 295 296 297 298 299 300
   */
  public static function postLoad(EntityStorageControllerInterface $storage_controller, array &$entities) {
    parent::postLoad($storage_controller, $entities);
    foreach ($entities as $entity) {
      $entity->mergeDefaultDisplaysOptions();
    }
  }

  /**
   * {@inheritdoc}
301 302
   */
  public static function preCreate(EntityStorageControllerInterface $storage_controller, array &$values) {
303 304
    parent::preCreate($storage_controller, $values);

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    // If there is no information about displays available add at least the
    // default display.
    $values += array(
      'display' => array(
        'default' => array(
          'display_plugin' => 'default',
          'id' => 'default',
          'display_title' => 'Master',
          'position' => 0,
          'display_options' => array(),
        ),
      )
    );
  }

  /**
   * {@inheritdoc}
   */
  public function postCreate(EntityStorageControllerInterface $storage_controller) {
324 325
    parent::postCreate($storage_controller);

326 327 328
    $this->mergeDefaultDisplaysOptions();
  }

329 330 331 332
  /**
   * {@inheritdoc}
   */
  public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
333 334
    parent::postDelete($storage_controller, $entities);

335
    $tempstore = \Drupal::service('user.tempstore')->get('views');
336 337
    $tags = array();

338
    foreach ($entities as $entity) {
339 340 341
      $id = $entity->id();
      $tempstore->delete($id);
      $tags['view'][$id] = $id;
342
    }
343 344 345 346

    // Clear cache tags for these views.
    // @todo Remove if views implements a view_builder controller.
    Cache::deleteTags($tags);
347 348
  }

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
  /**
   * {@inheritdoc}
   */
  public function mergeDefaultDisplaysOptions() {
    $displays = array();
    foreach ($this->get('display') as $key => $options) {
      $options += array(
        'display_options' => array(),
        'display_plugin' => NULL,
        'id' => NULL,
        'display_title' => '',
        'position' => NULL,
      );
      // Add the defaults for the display.
      $displays[$key] = $options;
    }
    // Sort the displays.
    uasort($displays, function ($display1, $display2) {
      if ($display1['position'] != $display2['position']) {
        return $display1['position'] < $display2['position'] ? -1 : 1;
      }
      return 0;
    });
    $this->set('display', $displays);
  }

375
}