EntityCrudHookTest.php 18.1 KB
Newer Older
1 2 3
<?php

/**
4
 * @file
5
 * Definition of Drupal\system\Tests\Entity\EntityCrudHookTest.
6 7
 */

8
namespace Drupal\system\Tests\Entity;
9

10
use Drupal\comment\Entity\Comment;
11
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
12
use Drupal\Core\Database\Database;
13
use Drupal\Core\Language\LanguageInterface;
14
use Drupal\block\Entity\Block;
15

16
/**
17 18
 * Tests the invocation of hooks when creating, inserting, loading, updating or
 * deleting an entity.
19 20
 *
 * Tested hooks are:
21 22 23 24 25 26 27
 * - hook_entity_insert() and hook_ENTITY_TYPE_insert()
 * - hook_entity_load() and hook_ENTITY_TYPE_load()
 * - hook_entity_update() and hook_ENTITY_TYPE_update()
 * - hook_entity_predelete() and hook_ENTITY_TYPE_predelete()
 * - hook_entity_delete() and hook_ENTITY_TYPE_delete()
 *
 * These hooks are each tested for several entity types.
28 29
 *
 * @group Entity
30
 */
31
class EntityCrudHookTest extends EntityUnitTestBase {
32

33 34 35 36 37
  /**
   * Modules to enable.
   *
   * @var array
   */
38
  public static $modules = array('block', 'block_test', 'entity_crud_hook_test', 'file', 'taxonomy', 'node', 'comment');
39

40 41
  protected $ids = array();

42
  protected function setUp() {
43
    parent::setUp();
44 45 46 47

    $this->installEntitySchema('node');
    $this->installEntitySchema('comment');

48
    $this->installSchema('user', array('users_data'));
49 50 51
    $this->installSchema('file', array('file_usage'));
    $this->installSchema('node', array('node_access'));
    $this->installSchema('comment', array('comment_entity_statistics'));
52 53
  }

54
  /**
55
   * Checks the order of CRUD hook execution messages.
56
   *
57 58 59 60 61
   * entity_crud_hook_test.module implements all core entity CRUD hooks and
   * stores a message for each in $_SESSION['entity_crud_hook_test'].
   *
   * @param $messages
   *   An array of plain-text messages in the order they should appear.
62
   */
63 64 65 66 67 68 69 70
  protected function assertHookMessageOrder($messages) {
    $positions = array();
    foreach ($messages as $message) {
      // Verify that each message is found and record its position.
      $position = array_search($message, $_SESSION['entity_crud_hook_test']);
      if ($this->assertTrue($position !== FALSE, $message)) {
        $positions[] = $position;
      }
71
    }
72 73 74 75 76

    // Sort the positions and ensure they remain in the same order.
    $sorted = $positions;
    sort($sorted);
    $this->assertTrue($sorted == $positions, 'The hook messages appear in the correct order.');
77 78
  }

79 80 81 82 83
  /**
   * Tests hook invocations for CRUD operations on blocks.
   */
  public function testBlockHooks() {
    $entity = entity_create('block', array(
84
      'id' => 'stark_test_html',
85
      'plugin' => 'test_html',
86
      'theme' => 'stark',
87
    ));
88 89 90 91 92 93

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_block_create called',
      'entity_crud_hook_test_entity_create called for type block',
    ));

94 95 96 97 98 99 100 101 102 103 104
    $_SESSION['entity_crud_hook_test'] = array();
    $entity->save();

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_block_presave called',
      'entity_crud_hook_test_entity_presave called for type block',
      'entity_crud_hook_test_block_insert called',
      'entity_crud_hook_test_entity_insert called for type block',
    ));

    $_SESSION['entity_crud_hook_test'] = array();
105
    $entity = Block::load($entity->id());
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

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type block',
      'entity_crud_hook_test_block_load called',
    ));

    $_SESSION['entity_crud_hook_test'] = array();
    $entity->label = 'New label';
    $entity->save();

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_block_presave called',
      'entity_crud_hook_test_entity_presave called for type block',
      'entity_crud_hook_test_block_update called',
      'entity_crud_hook_test_entity_update called for type block',
    ));

    $_SESSION['entity_crud_hook_test'] = array();
    $entity->delete();

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_block_predelete called',
      'entity_crud_hook_test_entity_predelete called for type block',
      'entity_crud_hook_test_block_delete called',
      'entity_crud_hook_test_entity_delete called for type block',
    ));
  }

134
  /**
135
   * Tests hook invocations for CRUD operations on comments.
136 137
   */
  public function testCommentHooks() {
138
    $account = $this->createUser();
139 140 141 142
    entity_create('node_type', array(
      'type' => 'article',
      'name' => 'Article',
    ))->save();
143
    $this->container->get('comment.manager')->addDefaultField('node', 'article', 'comment', CommentItemInterface::OPEN);
144

145
    $node = entity_create('node', array(
146
      'uid' => $account->id(),
147 148 149 150 151
      'type' => 'article',
      'title' => 'Test node',
      'status' => 1,
      'promote' => 0,
      'sticky' => 0,
152
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
153 154
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
155 156
    ));
    $node->save();
157
    $nid = $node->id();
158
    $_SESSION['entity_crud_hook_test'] = array();
159

160
    $comment = entity_create('comment', array(
161 162
      'cid' => NULL,
      'pid' => 0,
163 164 165
      'entity_id' => $nid,
      'entity_type' => 'node',
      'field_name' => 'comment',
166
      'uid' => $account->id(),
167 168 169 170
      'subject' => 'Test comment',
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
      'status' => 1,
171
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
172
    ));
173

174 175 176 177 178
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_comment_create called',
      'entity_crud_hook_test_entity_create called for type comment',
    ));

179
    $_SESSION['entity_crud_hook_test'] = array();
180
    $comment->save();
181

182 183 184 185 186 187
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_comment_presave called',
      'entity_crud_hook_test_entity_presave called for type comment',
      'entity_crud_hook_test_comment_insert called',
      'entity_crud_hook_test_entity_insert called for type comment',
    ));
188 189

    $_SESSION['entity_crud_hook_test'] = array();
190
    $comment = Comment::load($comment->id());
191

192 193 194 195
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type comment',
      'entity_crud_hook_test_comment_load called',
    ));
196 197

    $_SESSION['entity_crud_hook_test'] = array();
198
    $comment->setSubject('New subject');
199
    $comment->save();
200

201 202 203 204 205 206
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_comment_presave called',
      'entity_crud_hook_test_entity_presave called for type comment',
      'entity_crud_hook_test_comment_update called',
      'entity_crud_hook_test_entity_update called for type comment',
    ));
207 208

    $_SESSION['entity_crud_hook_test'] = array();
209
    $comment->delete();
210

211 212 213 214 215 216
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_comment_predelete called',
      'entity_crud_hook_test_entity_predelete called for type comment',
      'entity_crud_hook_test_comment_delete called',
      'entity_crud_hook_test_entity_delete called for type comment',
    ));
217 218 219
  }

  /**
220
   * Tests hook invocations for CRUD operations on files.
221 222
   */
  public function testFileHooks() {
223 224
    $this->installEntitySchema('file');

225 226
    $url = 'public://entity_crud_hook_test.file';
    file_put_contents($url, 'Test test test');
227
    $file = entity_create('file', array(
228 229 230 231 232 233 234
      'fid' => NULL,
      'uid' => 1,
      'filename' => 'entity_crud_hook_test.file',
      'uri' => $url,
      'filemime' => 'text/plain',
      'filesize' => filesize($url),
      'status' => 1,
235 236
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
237
    ));
238 239 240 241 242 243

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_file_create called',
      'entity_crud_hook_test_entity_create called for type file',
    ));

244
    $_SESSION['entity_crud_hook_test'] = array();
245
    $file->save();
246

247 248 249 250 251 252
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_file_presave called',
      'entity_crud_hook_test_entity_presave called for type file',
      'entity_crud_hook_test_file_insert called',
      'entity_crud_hook_test_entity_insert called for type file',
    ));
253 254

    $_SESSION['entity_crud_hook_test'] = array();
255
    $file = file_load($file->id());
256

257 258 259 260
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type file',
      'entity_crud_hook_test_file_load called',
    ));
261 262

    $_SESSION['entity_crud_hook_test'] = array();
263
    $file->setFilename('new.entity_crud_hook_test.file');
264
    $file->save();
265

266 267 268 269 270 271
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_file_presave called',
      'entity_crud_hook_test_entity_presave called for type file',
      'entity_crud_hook_test_file_update called',
      'entity_crud_hook_test_entity_update called for type file',
    ));
272 273

    $_SESSION['entity_crud_hook_test'] = array();
274
    $file->delete();
275

276 277 278 279 280 281
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_file_predelete called',
      'entity_crud_hook_test_entity_predelete called for type file',
      'entity_crud_hook_test_file_delete called',
      'entity_crud_hook_test_entity_delete called for type file',
    ));
282 283 284
  }

  /**
285
   * Tests hook invocations for CRUD operations on nodes.
286 287
   */
  public function testNodeHooks() {
288 289
    $account = $this->createUser();

290
    $node = entity_create('node', array(
291
      'uid' => $account->id(),
292 293 294 295 296
      'type' => 'article',
      'title' => 'Test node',
      'status' => 1,
      'promote' => 0,
      'sticky' => 0,
297
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
298 299
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
300
    ));
301 302 303 304 305 306

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_node_create called',
      'entity_crud_hook_test_entity_create called for type node',
    ));

307
    $_SESSION['entity_crud_hook_test'] = array();
308
    $node->save();
309

310 311 312 313 314 315
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_node_presave called',
      'entity_crud_hook_test_entity_presave called for type node',
      'entity_crud_hook_test_node_insert called',
      'entity_crud_hook_test_entity_insert called for type node',
    ));
316 317

    $_SESSION['entity_crud_hook_test'] = array();
318
    $node = node_load($node->id());
319

320 321 322 323
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type node',
      'entity_crud_hook_test_node_load called',
    ));
324 325 326

    $_SESSION['entity_crud_hook_test'] = array();
    $node->title = 'New title';
327
    $node->save();
328

329 330 331 332 333 334
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_node_presave called',
      'entity_crud_hook_test_entity_presave called for type node',
      'entity_crud_hook_test_node_update called',
      'entity_crud_hook_test_entity_update called for type node',
    ));
335 336

    $_SESSION['entity_crud_hook_test'] = array();
337
    $node->delete();
338

339 340 341 342 343 344
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_node_predelete called',
      'entity_crud_hook_test_entity_predelete called for type node',
      'entity_crud_hook_test_node_delete called',
      'entity_crud_hook_test_entity_delete called for type node',
    ));
345 346 347
  }

  /**
348
   * Tests hook invocations for CRUD operations on taxonomy terms.
349 350
   */
  public function testTaxonomyTermHooks() {
351
    $this->installEntitySchema('taxonomy_term');
352

353
    $vocabulary = entity_create('taxonomy_vocabulary', array(
354
      'name' => 'Test vocabulary',
355
      'vid' => 'test',
356
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
357 358
      'description' => NULL,
      'module' => 'entity_crud_hook_test',
359
    ));
360
    $vocabulary->save();
361
    $_SESSION['entity_crud_hook_test'] = array();
362

363
    $term = entity_create('taxonomy_term', array(
364
      'vid' => $vocabulary->id(),
365
      'name' => 'Test term',
366
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
367 368
      'description' => NULL,
      'format' => 1,
369
    ));
370 371 372 373 374 375

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_term_create called',
      'entity_crud_hook_test_entity_create called for type taxonomy_term',
    ));

376
    $_SESSION['entity_crud_hook_test'] = array();
377
    $term->save();
378

379 380 381 382 383 384
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_term_presave called',
      'entity_crud_hook_test_entity_presave called for type taxonomy_term',
      'entity_crud_hook_test_taxonomy_term_insert called',
      'entity_crud_hook_test_entity_insert called for type taxonomy_term',
    ));
385 386

    $_SESSION['entity_crud_hook_test'] = array();
387
    $term = entity_load('taxonomy_term', $term->id());
388

389 390 391 392
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type taxonomy_term',
      'entity_crud_hook_test_taxonomy_term_load called',
    ));
393 394

    $_SESSION['entity_crud_hook_test'] = array();
395
    $term->setName('New name');
396
    $term->save();
397

398 399 400 401 402 403
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_term_presave called',
      'entity_crud_hook_test_entity_presave called for type taxonomy_term',
      'entity_crud_hook_test_taxonomy_term_update called',
      'entity_crud_hook_test_entity_update called for type taxonomy_term',
    ));
404 405

    $_SESSION['entity_crud_hook_test'] = array();
406
    $term->delete();
407

408 409 410 411 412 413
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_term_predelete called',
      'entity_crud_hook_test_entity_predelete called for type taxonomy_term',
      'entity_crud_hook_test_taxonomy_term_delete called',
      'entity_crud_hook_test_entity_delete called for type taxonomy_term',
    ));
414 415 416
  }

  /**
417
   * Tests hook invocations for CRUD operations on taxonomy vocabularies.
418 419
   */
  public function testTaxonomyVocabularyHooks() {
420
    $this->installEntitySchema('taxonomy_term');
421

422
    $vocabulary = entity_create('taxonomy_vocabulary', array(
423
      'name' => 'Test vocabulary',
424
      'vid' => 'test',
425
      'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
426 427
      'description' => NULL,
      'module' => 'entity_crud_hook_test',
428
    ));
429 430 431 432 433 434

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_vocabulary_create called',
      'entity_crud_hook_test_entity_create called for type taxonomy_vocabulary',
    ));

435
    $_SESSION['entity_crud_hook_test'] = array();
436
    $vocabulary->save();
437

438 439 440 441 442 443
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_vocabulary_presave called',
      'entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary',
      'entity_crud_hook_test_taxonomy_vocabulary_insert called',
      'entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary',
    ));
444 445

    $_SESSION['entity_crud_hook_test'] = array();
446
    $vocabulary = entity_load('taxonomy_vocabulary', $vocabulary->id());
447

448 449 450 451
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type taxonomy_vocabulary',
      'entity_crud_hook_test_taxonomy_vocabulary_load called',
    ));
452 453 454

    $_SESSION['entity_crud_hook_test'] = array();
    $vocabulary->name = 'New name';
455
    $vocabulary->save();
456

457 458 459 460 461 462
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_vocabulary_presave called',
      'entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary',
      'entity_crud_hook_test_taxonomy_vocabulary_update called',
      'entity_crud_hook_test_entity_update called for type taxonomy_vocabulary',
    ));
463 464

    $_SESSION['entity_crud_hook_test'] = array();
465
    $vocabulary->delete();
466

467 468 469 470 471 472
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_taxonomy_vocabulary_predelete called',
      'entity_crud_hook_test_entity_predelete called for type taxonomy_vocabulary',
      'entity_crud_hook_test_taxonomy_vocabulary_delete called',
      'entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary',
    ));
473 474 475
  }

  /**
476
   * Tests hook invocations for CRUD operations on users.
477 478
   */
  public function testUserHooks() {
479
    $account = entity_create('user', array(
480 481 482 483 484
      'name' => 'Test user',
      'mail' => 'test@example.com',
      'created' => REQUEST_TIME,
      'status' => 1,
      'language' => 'en',
485
    ));
486 487 488 489 490 491

    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_user_create called',
      'entity_crud_hook_test_entity_create called for type user',
    ));

492
    $_SESSION['entity_crud_hook_test'] = array();
493
    $account->save();
494

495 496 497 498 499 500
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_user_presave called',
      'entity_crud_hook_test_entity_presave called for type user',
      'entity_crud_hook_test_user_insert called',
      'entity_crud_hook_test_entity_insert called for type user',
    ));
501 502

    $_SESSION['entity_crud_hook_test'] = array();
503
    user_load($account->id());
504

505 506 507 508
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type user',
      'entity_crud_hook_test_user_load called',
    ));
509 510

    $_SESSION['entity_crud_hook_test'] = array();
511 512
    $account->name = 'New name';
    $account->save();
513

514 515 516 517 518 519
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_user_presave called',
      'entity_crud_hook_test_entity_presave called for type user',
      'entity_crud_hook_test_user_update called',
      'entity_crud_hook_test_entity_update called for type user',
    ));
520 521

    $_SESSION['entity_crud_hook_test'] = array();
522
    user_delete($account->id());
523

524 525 526 527 528 529
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_user_predelete called',
      'entity_crud_hook_test_entity_predelete called for type user',
      'entity_crud_hook_test_user_delete called',
      'entity_crud_hook_test_entity_delete called for type user',
    ));
530
  }
531 532

  /**
533
   * Tests rollback from failed entity save.
534
   */
535
  function testEntityRollback() {
536 537
    // Create a block.
    try {
538
      entity_create('entity_test', array('name' => 'fail_insert'))->save();
539 540 541 542 543 544 545 546
      $this->fail('Expected exception has not been thrown.');
    }
    catch (\Exception $e) {
      $this->pass('Expected exception has been thrown.');
    }

    if (Database::getConnection()->supportsTransactions()) {
      // Check that the block does not exist in the database.
547
      $ids = \Drupal::entityQuery('entity_test')->condition('name', 'fail_insert')->execute();
548 549 550 551
      $this->assertTrue(empty($ids), 'Transactions supported, and entity not found in database.');
    }
    else {
      // Check that the block exists in the database.
552
      $ids = \Drupal::entityQuery('entity_test')->condition('name', 'fail_insert')->execute();
553 554 555
      $this->assertFalse(empty($ids), 'Transactions not supported, and entity found in database.');
    }
  }
556
}