1<?php
2
3namespace Drupal\Tests\views\Kernel\Handler;
4
5use Drupal\Component\Render\FormattableMarkup;
6use Drupal\Core\Entity\EntityTypeInterface;
7use Drupal\Core\Form\FormState;
8use Drupal\Tests\block\Traits\BlockCreationTrait;
9use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
10use Drupal\views\Entity\View;
11use Drupal\views\Views;
12
13/**
14 * Tests the generic entity area handler.
15 *
16 * @group views
17 * @see \Drupal\views\Plugin\views\area\Entity
18 */
19class AreaEntityTest extends ViewsKernelTestBase {
20
21  use BlockCreationTrait;
22
23  /**
24   * Modules to enable.
25   *
26   * @var array
27   */
28  public static $modules = ['entity_test', 'user', 'block'];
29
30  /**
31   * Views used by this test.
32   *
33   * @var array
34   */
35  public static $testViews = ['test_entity_area'];
36
37  /**
38   * {@inheritdoc}
39   */
40  protected function setUp($import_test_views = TRUE) {
41    parent::setUp();
42  }
43
44  /**
45   * {@inheritdoc}
46   */
47  protected function setUpFixtures() {
48    // Install the themes used for this test.
49    $this->container->get('theme_installer')->install(['bartik']);
50    $this->container->get('config.factory')->getEditable('system.theme')->set('default', 'bartik')->save();
51
52    $this->installEntitySchema('user');
53    $this->installEntitySchema('entity_test');
54    $this->installConfig(['entity_test']);
55
56    $this->placeBlock('system_main_block', ['id' => 'test_block']);
57
58    parent::setUpFixtures();
59  }
60
61  /**
62   * Tests views data for entity area handlers.
63   */
64  public function testEntityAreaData() {
65    $data = $this->container->get('views.views_data')->get('views');
66    $entity_types = $this->container->get('entity_type.manager')->getDefinitions();
67
68    $expected_entities = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
69      return $entity_type->hasViewBuilderClass();
70    });
71
72    // Test that all expected entity types have data.
73    foreach (array_keys($expected_entities) as $entity) {
74      $this->assertTrue(!empty($data['entity_' . $entity]), new FormattableMarkup('Views entity area data found for @entity', ['@entity' => $entity]));
75      // Test that entity_type is set correctly in the area data.
76      $this->assertEqual($entity, $data['entity_' . $entity]['area']['entity_type'], new FormattableMarkup('Correct entity_type set for @entity', ['@entity' => $entity]));
77    }
78
79    $expected_entities = array_filter($entity_types, function (EntityTypeInterface $type) {
80      return !$type->hasViewBuilderClass();
81    });
82
83    // Test that no configuration entity types have data.
84    foreach (array_keys($expected_entities) as $entity) {
85      $this->assertTrue(empty($data['entity_' . $entity]), new FormattableMarkup('Views config entity area data not found for @entity', ['@entity' => $entity]));
86    }
87  }
88
89  /**
90   * Tests the area handler.
91   */
92  public function testEntityArea() {
93    /** @var \Drupal\Core\Entity\EntityInterface[] $entities */
94    $entities = [];
95    for ($i = 0; $i < 3; $i++) {
96      $random_label = $this->randomMachineName();
97      $data = ['bundle' => 'entity_test', 'name' => $random_label];
98      $entity_test = $this->container->get('entity_type.manager')
99        ->getStorage('entity_test')
100        ->create($data);
101
102      $uuid_map[0] = 'aa0c61cb-b7bb-4795-972a-493dabcf529c';
103      $uuid_map[1] = '62cef0ff-6f30-4f7a-b9d6-a8ed5a3a6bf3';
104      $uuid_map[2] = '3161d6e9-3326-4719-b513-8fa68a731ba2';
105      $entity_test->uuid->value = $uuid_map[$i];
106
107      $entity_test->save();
108      $entities[] = $entity_test;
109      \Drupal::state()
110        ->set('entity_test_entity_access.view.' . $entity_test->id(), $i != 2);
111    }
112
113    $this->doTestCalculateDependencies();
114    $this->doTestRender($entities);
115  }
116
117  /**
118   * Tests rendering the entity area handler.
119   *
120   * @param \Drupal\Core\Entity\EntityInterface[] $entities
121   *   The entities.
122   */
123  public function doTestRender($entities) {
124    /** @var \Drupal\Core\Render\RendererInterface $renderer */
125    $renderer = $this->container->get('renderer');
126    $view = Views::getView('test_entity_area');
127    $preview = $view->preview('default', [$entities[1]->id()]);
128    $this->setRawContent(\Drupal::service('renderer')->renderRoot($preview));
129    $view_class = 'js-view-dom-id-' . $view->dom_id;
130    $header_xpath = '//div[@class = "' . $view_class . '"]/header[1]';
131    $footer_xpath = '//div[@class = "' . $view_class . '"]/footer[1]';
132
133    $result = $this->xpath($header_xpath);
134    $this->assertStringContainsString($entities[0]->label(), (string) $result[0], 'The rendered entity appears in the header of the view.');
135    $this->assertStringContainsString('full', (string) $result[0], 'The rendered entity appeared in the right view mode.');
136
137    $result = $this->xpath($footer_xpath);
138    $this->assertStringContainsString($entities[1]->label(), (string) $result[0], 'The rendered entity appears in the footer of the view.');
139    $this->assertStringContainsString('full', (string) $result[0], 'The rendered entity appeared in the right view mode.');
140
141    $preview = $view->preview('default', [$entities[1]->id()]);
142    $this->setRawContent($renderer->renderRoot($preview));
143
144    $result = $this->xpath($header_xpath);
145    $this->assertStringContainsString($entities[0]->label(), (string) $result[0], 'The rendered entity appears in the header of the view.');
146    $this->assertStringContainsString('full', (string) $result[0], 'The rendered entity appeared in the right view mode.');
147
148    $result = $this->xpath($footer_xpath);
149    $this->assertStringContainsString($entities[1]->label(), (string) $result[0], 'The rendered entity appears in the footer of the view.');
150    $this->assertStringContainsString('full', (string) $result[0], 'The rendered entity appeared in the right view mode.');
151
152    // Mark entity_test test view_mode as customizable.
153    $entity_view_mode = \Drupal::entityTypeManager()->getStorage('entity_view_mode')->load('entity_test.test');
154    $entity_view_mode->enable();
155    $entity_view_mode->save();
156
157    // Change the view mode of the area handler.
158    $view = Views::getView('test_entity_area');
159    $item = $view->getHandler('default', 'header', 'entity_entity_test');
160    $item['view_mode'] = 'test';
161    $view->setHandler('default', 'header', 'entity_entity_test', $item);
162
163    $preview = $view->preview('default', [$entities[1]->id()]);
164    $this->setRawContent($renderer->renderRoot($preview));
165    $view_class = 'js-view-dom-id-' . $view->dom_id;
166    $result = $this->xpath('//div[@class = "' . $view_class . '"]/header[1]');
167    $this->assertStringContainsString($entities[0]->label(), (string) $result[0], 'The rendered entity appears in the header of the view.');
168    $this->assertStringContainsString('test', (string) $result[0], 'The rendered entity appeared in the right view mode.');
169
170    // Test entity access.
171    $view = Views::getView('test_entity_area');
172    $preview = $view->preview('default', [$entities[2]->id()]);
173    $this->setRawContent($renderer->renderRoot($preview));
174    $view_class = 'js-view-dom-id-' . $view->dom_id;
175    $result = $this->xpath('//div[@class = "' . $view_class . '"]/footer[1]');
176    $this->assertStringNotContainsString($entities[2]->label(), $result[0], 'The rendered entity does not appear in the footer of the view.');
177
178    // Test the available view mode options.
179    $form = [];
180    $form_state = (new FormState())
181      ->set('type', 'header');
182    $view->display_handler->getHandler('header', 'entity_entity_test')->buildOptionsForm($form, $form_state);
183    $this->assertTrue(isset($form['view_mode']['#options']['test']), 'Ensure that the test view mode is available.');
184    $this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available.');
185  }
186
187  /**
188   * Tests the calculation of the rendered dependencies.
189   */
190  public function doTestCalculateDependencies() {
191    $view = View::load('test_entity_area');
192
193    $dependencies = $view->calculateDependencies()->getDependencies();
194    // Ensure that both config and content entity dependencies are calculated.
195    $this->assertEqual([
196      'config' => ['block.block.test_block'],
197      'content' => ['entity_test:entity_test:aa0c61cb-b7bb-4795-972a-493dabcf529c'],
198      'module' => ['views_test_data'],
199    ], $dependencies);
200  }
201
202}
203