dfbb89bd209dac7f335cbb4ef8863cd1225f9d49
[yaffs-website] / web / core / modules / field / src / Tests / Views / HandlerFieldFieldTest.php
1 <?php
2
3 namespace Drupal\field\Tests\Views;
4
5 use Drupal\Core\Field\FieldStorageDefinitionInterface;
6 use Drupal\views\ViewExecutable;
7 use Drupal\views\Views;
8 use Drupal\field\Entity\FieldStorageConfig;
9
10 /**
11  * Tests the field itself of the Field integration.
12  *
13  * @group field
14  * @TODO
15  *   Check a entity-type with bundles
16  *   Check a entity-type without bundles
17  *   Check locale:disabled, locale:enabled and locale:enabled with another language
18  *   Check revisions
19  */
20 class HandlerFieldFieldTest extends FieldTestBase {
21
22   /**
23    * {@inheritdoc}
24    */
25   public static $modules = ['node', 'field_test'];
26
27   /**
28    * Views used by this test.
29    *
30    * @var array
31    */
32   public static $testViews = ['test_view_fieldapi'];
33
34   /**
35    * Test nodes.
36    *
37    * @var \Drupal\node\NodeInterface[]
38    */
39   public $nodes;
40
41   /**
42    * {@inheritdoc}
43    */
44   protected function setUp() {
45     parent::setUp();
46
47     // Setup basic fields.
48     $this->setUpFieldStorages(3);
49
50     // Setup a field with cardinality > 1.
51     $this->fieldStorages[3] = FieldStorageConfig::create([
52       'field_name' => 'field_name_3',
53       'entity_type' => 'node',
54       'type' => 'string',
55       'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
56     ]);
57     $this->fieldStorages[3]->save();
58     // Setup a field that will have no value.
59     $this->fieldStorages[4] = FieldStorageConfig::create([
60       'field_name' => 'field_name_4',
61       'entity_type' => 'node',
62       'type' => 'string',
63       'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
64     ]);
65     $this->fieldStorages[4]->save();
66
67     // Setup a text field.
68     $this->fieldStorages[5] = FieldStorageConfig::create([
69       'field_name' => 'field_name_5',
70       'entity_type' => 'node',
71       'type' => 'text',
72     ]);
73     $this->fieldStorages[5]->save();
74
75     // Setup a text field with access control.
76     // @see field_test_entity_field_access()
77     $this->fieldStorages[6] = FieldStorageConfig::create([
78       'field_name' => 'field_no_view_access',
79       'entity_type' => 'node',
80       'type' => 'text',
81     ]);
82     $this->fieldStorages[6]->save();
83
84     $this->setUpFields();
85
86     // Create some nodes.
87     $this->nodes = [];
88     for ($i = 0; $i < 3; $i++) {
89       $edit = ['type' => 'page'];
90
91       foreach ([0, 1, 2, 5] as $key) {
92         $field_storage = $this->fieldStorages[$key];
93         $edit[$field_storage->getName()][0]['value'] = $this->randomMachineName(8);
94       }
95       // Add a hidden value for the no-view field.
96       $edit[$this->fieldStorages[6]->getName()][0]['value'] = 'ssh secret squirrel';
97       for ($j = 0; $j < 5; $j++) {
98         $edit[$this->fieldStorages[3]->getName()][$j]['value'] = $this->randomMachineName(8);
99       }
100       // Set this field to be empty.
101       $edit[$this->fieldStorages[4]->getName()] = [['value' => NULL]];
102
103       $this->nodes[$i] = $this->drupalCreateNode($edit);
104     }
105
106     $this->container->get('views.views_data')->clear();
107   }
108
109   /**
110    * Sets up the testing view with random field data.
111    *
112    * @param \Drupal\views\ViewExecutable $view
113    *   The view to add field data to.
114    */
115   protected function prepareView(ViewExecutable $view) {
116     $view->storage->invalidateCaches();
117     $view->initDisplay();
118     foreach ($this->fieldStorages as $field_storage) {
119       $field_name = $field_storage->getName();
120       $view->display_handler->options['fields'][$field_name]['id'] = $field_name;
121       $view->display_handler->options['fields'][$field_name]['table'] = 'node__' . $field_name;
122       $view->display_handler->options['fields'][$field_name]['field'] = $field_name;
123     }
124   }
125
126   public function testFieldRender() {
127     $this->_testSimpleFieldRender();
128     $this->_testInaccessibleFieldRender();
129     $this->_testFormatterSimpleFieldRender();
130     $this->_testMultipleFieldRender();
131   }
132
133   public function _testSimpleFieldRender() {
134     $view = Views::getView('test_view_fieldapi');
135     $this->prepareView($view);
136     $this->executeView($view);
137
138     // Tests that the rendered fields match the actual value of the fields.
139     for ($i = 0; $i < 3; $i++) {
140       for ($key = 0; $key < 2; $key++) {
141         $field_name = $this->fieldStorages[$key]->getName();
142         $rendered_field = $view->style_plugin->getField($i, $field_name);
143         $expected_field = $this->nodes[$i]->$field_name->value;
144         $this->assertEqual($rendered_field, $expected_field);
145       }
146     }
147   }
148
149   public function _testInaccessibleFieldRender() {
150     $view = Views::getView('test_view_fieldapi');
151     $this->prepareView($view);
152     $this->executeView($view);
153
154     // Check that the field handler for the hidden field is correctly removed
155     // from the display.
156     // @see https://www.drupal.org/node/2382931
157     $this->assertFalse(array_key_exists('field_no_view_access', $view->field));
158
159     // Check that the access-denied field is not visible.
160     for ($i = 0; $i < 3; $i++) {
161       $field_name = $this->fieldStorages[6]->getName();
162       $rendered_field = $view->style_plugin->getField($i, $field_name);
163       $this->assertFalse($rendered_field, 'Hidden field not rendered');
164     }
165   }
166
167   /**
168    * Tests that fields with formatters runs as expected.
169    */
170   public function _testFormatterSimpleFieldRender() {
171     $view = Views::getView('test_view_fieldapi');
172     $this->prepareView($view);
173     $view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['type'] = 'text_trimmed';
174     $view->displayHandlers->get('default')->options['fields'][$this->fieldStorages[5]->getName()]['settings'] = [
175       'trim_length' => 3,
176     ];
177     $this->executeView($view);
178
179     // Make sure that the formatter works as expected.
180     // @TODO: actually there should be a specific formatter.
181     for ($i = 0; $i < 2; $i++) {
182       $rendered_field = $view->style_plugin->getField($i, $this->fieldStorages[5]->getName());
183       $this->assertEqual(strlen(html_entity_decode($rendered_field)), 3);
184     }
185   }
186
187   public function _testMultipleFieldRender() {
188     $view = Views::getView('test_view_fieldapi');
189     $field_name = $this->fieldStorages[3]->getName();
190
191     // Test delta limit.
192     $this->prepareView($view);
193     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
194     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
195     $this->executeView($view);
196
197     for ($i = 0; $i < 3; $i++) {
198       $rendered_field = $view->style_plugin->getField($i, $field_name);
199       $items = [];
200       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
201       $pure_items = array_splice($pure_items, 0, 3);
202       foreach ($pure_items as $j => $item) {
203         $items[] = $pure_items[$j]['value'];
204       }
205       $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited.');
206     }
207
208     // Test that an empty field is rendered without error.
209     $view->style_plugin->getField(4, $this->fieldStorages[4]->getName());
210     $view->destroy();
211
212     // Test delta limit + offset
213     $this->prepareView($view);
214     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
215     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
216     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 1;
217     $this->executeView($view);
218
219     for ($i = 0; $i < 3; $i++) {
220       $rendered_field = $view->style_plugin->getField($i, $field_name);
221       $items = [];
222       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
223       $pure_items = array_splice($pure_items, 1, 3);
224       foreach ($pure_items as $j => $item) {
225         $items[] = $pure_items[$j]['value'];
226       }
227       $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and the offset is correct.');
228     }
229     $view->destroy();
230
231     // Test delta limit + reverse.
232     $this->prepareView($view);
233     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_offset'] = 0;
234     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
235     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
236     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = TRUE;
237     $this->executeView($view);
238
239     for ($i = 0; $i < 3; $i++) {
240       $rendered_field = $view->style_plugin->getField($i, $field_name);
241       $items = [];
242       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
243       array_splice($pure_items, 0, -3);
244       $pure_items = array_reverse($pure_items);
245       foreach ($pure_items as $j => $item) {
246         $items[] = $pure_items[$j]['value'];
247       }
248       $this->assertEqual($rendered_field, implode(', ', $items), 'The amount of items is limited and they are reversed.');
249     }
250     $view->destroy();
251
252     // Test delta first last.
253     $this->prepareView($view);
254     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
255     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 0;
256     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = TRUE;
257     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_reversed'] = FALSE;
258     $this->executeView($view);
259
260     for ($i = 0; $i < 3; $i++) {
261       $rendered_field = $view->style_plugin->getField($i, $field_name);
262       $items = [];
263       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
264       $items[] = $pure_items[0]['value'];
265       $items[] = $pure_items[4]['value'];
266       $this->assertEqual($rendered_field, implode(', ', $items), 'Items are limited to first and last.');
267     }
268     $view->destroy();
269
270     // Test delta limit + custom separator.
271     $this->prepareView($view);
272     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_first_last'] = FALSE;
273     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
274     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
275     $view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = ':';
276     $this->executeView($view);
277
278     for ($i = 0; $i < 3; $i++) {
279       $rendered_field = $view->style_plugin->getField($i, $field_name);
280       $items = [];
281       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
282       $pure_items = array_splice($pure_items, 0, 3);
283       foreach ($pure_items as $j => $item) {
284         $items[] = $pure_items[$j]['value'];
285       }
286       $this->assertEqual($rendered_field, implode(':', $items), 'The amount of items is limited and the custom separator is correct.');
287     }
288     $view->destroy();
289
290     // Test separator with HTML, ensure it is escaped.
291     $this->prepareView($view);
292     $view->displayHandlers->get('default')->options['fields'][$field_name]['group_rows'] = TRUE;
293     $view->displayHandlers->get('default')->options['fields'][$field_name]['delta_limit'] = 3;
294     $view->displayHandlers->get('default')->options['fields'][$field_name]['separator'] = '<h2>test</h2>';
295     $this->executeView($view);
296
297     for ($i = 0; $i < 3; $i++) {
298       $rendered_field = $view->style_plugin->getField($i, $field_name);
299       $items = [];
300       $pure_items = $this->nodes[$i]->{$field_name}->getValue();
301       $pure_items = array_splice($pure_items, 0, 3);
302       foreach ($pure_items as $j => $item) {
303         $items[] = $pure_items[$j]['value'];
304       }
305       $this->assertEqual($rendered_field, implode('<h2>test</h2>', $items), 'The custom separator is correctly escaped.');
306     }
307     $view->destroy();
308   }
309
310 }