EntityCrudHookTest.php 17.7 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\Core\Database\Database;
11

12 13 14 15
/**
 * Tests invocation of hooks when performing an action.
 *
 * Tested hooks are:
16 17 18
 * - hook_entity_insert()
 * - hook_entity_load()
 * - hook_entity_update()
19
 * - hook_entity_predelete()
20 21 22 23
 * - hook_entity_delete()
 * As well as all type-specific hooks, like hook_node_insert(),
 * hook_comment_update(), etc.
 */
24
class EntityCrudHookTest extends EntityUnitTestBase {
25

26 27 28 29 30
  /**
   * Modules to enable.
   *
   * @var array
   */
31
  public static $modules = array('block', 'block_test', 'entity_crud_hook_test', 'file', 'taxonomy', 'node', 'comment');
32

33 34 35 36 37
  protected $ids = array();

  public static function getInfo() {
    return array(
      'name' => 'Entity CRUD hooks',
38
      'description' => 'Tests the invocation of hooks when creating, inserting, loading, updating or deleting an entity.',
39 40 41 42
      'group' => 'Entity API',
    );
  }

43 44 45 46 47 48 49
  public function setUp() {
    parent::setUp();
    $this->installSchema('user', array('users_roles', 'users_data'));
    $this->installSchema('node', array('node', 'node_revision', 'node_type', 'node_access'));
    $this->installSchema('comment', array('comment', 'node_comment_statistics'));
  }

50
  /**
51
   * Checks the order of CRUD hook execution messages.
52
   *
53 54 55 56 57
   * 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.
58
   */
59 60 61 62 63 64 65 66
  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;
      }
67
    }
68 69 70 71 72

    // 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.');
73 74
  }

75 76 77 78 79 80 81 82
  /**
   * Tests hook invocations for CRUD operations on blocks.
   */
  public function testBlockHooks() {
    $entity = entity_create('block', array(
      'id' => 'stark.test_html_id',
      'plugin' => 'test_html_id',
    ));
83 84 85 86 87 88

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

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
    $_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();
    $entity = entity_load('block', $entity->id());

    $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',
    ));
  }

129
  /**
130
   * Tests hook invocations for CRUD operations on comments.
131 132
   */
  public function testCommentHooks() {
133 134
    $account = $this->createUser();

135
    $node = entity_create('node', array(
136
      'uid' => $account->uid,
137 138 139 140 141 142
      'type' => 'article',
      'title' => 'Test node',
      'status' => 1,
      'comment' => 2,
      'promote' => 0,
      'sticky' => 0,
143
      'langcode' => LANGUAGE_NOT_SPECIFIED,
144 145
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
146 147
    ));
    $node->save();
148
    $nid = $node->nid;
149
    $_SESSION['entity_crud_hook_test'] = array();
150

151
    $comment = entity_create('comment', array(
152
      'node_type' => 'node_type_' . $node->bundle(),
153 154 155
      'cid' => NULL,
      'pid' => 0,
      'nid' => $nid,
156
      'uid' => $account->uid,
157 158 159 160
      'subject' => 'Test comment',
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
      'status' => 1,
161
      'langcode' => LANGUAGE_NOT_SPECIFIED,
162
    ));
163

164 165 166 167 168
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_comment_create called',
      'entity_crud_hook_test_entity_create called for type comment',
    ));

169 170 171
    $_SESSION['entity_crud_hook_test'] = array();
    comment_save($comment);

172 173 174 175 176 177
    $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',
    ));
178 179

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

182 183 184 185
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type comment',
      'entity_crud_hook_test_comment_load called',
    ));
186 187

    $_SESSION['entity_crud_hook_test'] = array();
188
    $comment->subject->value = 'New subject';
189 190
    comment_save($comment);

191 192 193 194 195 196
    $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',
    ));
197 198

    $_SESSION['entity_crud_hook_test'] = array();
199
    $comment->delete();
200

201 202 203 204 205 206
    $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',
    ));
207 208 209
  }

  /**
210
   * Tests hook invocations for CRUD operations on files.
211 212
   */
  public function testFileHooks() {
213
    $this->installSchema('file', array('file_managed', 'file_usage'));
214 215
    $url = 'public://entity_crud_hook_test.file';
    file_put_contents($url, 'Test test test');
216
    $file = entity_create('file', array(
217 218 219 220 221 222 223 224
      'fid' => NULL,
      'uid' => 1,
      'filename' => 'entity_crud_hook_test.file',
      'uri' => $url,
      'filemime' => 'text/plain',
      'filesize' => filesize($url),
      'status' => 1,
      'timestamp' => REQUEST_TIME,
225
    ));
226 227 228 229 230 231

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

232
    $_SESSION['entity_crud_hook_test'] = array();
233
    $file->save();
234

235 236 237 238 239 240
    $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',
    ));
241 242 243 244

    $_SESSION['entity_crud_hook_test'] = array();
    $file = file_load($file->fid);

245 246 247 248
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type file',
      'entity_crud_hook_test_file_load called',
    ));
249 250 251

    $_SESSION['entity_crud_hook_test'] = array();
    $file->filename = 'new.entity_crud_hook_test.file';
252
    $file->save();
253

254 255 256 257 258 259
    $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',
    ));
260 261

    $_SESSION['entity_crud_hook_test'] = array();
262
    $file->delete();
263

264 265 266 267 268 269
    $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',
    ));
270 271 272
  }

  /**
273
   * Tests hook invocations for CRUD operations on nodes.
274 275
   */
  public function testNodeHooks() {
276 277
    $account = $this->createUser();

278
    $node = entity_create('node', array(
279
      'uid' => $account->id(),
280 281 282 283 284 285
      'type' => 'article',
      'title' => 'Test node',
      'status' => 1,
      'comment' => 2,
      'promote' => 0,
      'sticky' => 0,
286
      'langcode' => LANGUAGE_NOT_SPECIFIED,
287 288
      'created' => REQUEST_TIME,
      'changed' => REQUEST_TIME,
289
    ));
290 291 292 293 294 295

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

296
    $_SESSION['entity_crud_hook_test'] = array();
297
    $node->save();
298

299 300 301 302 303 304
    $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',
    ));
305 306 307 308

    $_SESSION['entity_crud_hook_test'] = array();
    $node = node_load($node->nid);

309 310 311 312
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type node',
      'entity_crud_hook_test_node_load called',
    ));
313 314 315

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

318 319 320 321 322 323
    $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',
    ));
324 325 326 327

    $_SESSION['entity_crud_hook_test'] = array();
    node_delete($node->nid);

328 329 330 331 332 333
    $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',
    ));
334 335 336
  }

  /**
337
   * Tests hook invocations for CRUD operations on taxonomy terms.
338 339
   */
  public function testTaxonomyTermHooks() {
340 341
    $this->installSchema('taxonomy', array('taxonomy_term_data', 'taxonomy_term_hierarchy'));

342
    $vocabulary = entity_create('taxonomy_vocabulary', array(
343
      'name' => 'Test vocabulary',
344
      'vid' => 'test',
345
      'langcode' => LANGUAGE_NOT_SPECIFIED,
346 347
      'description' => NULL,
      'module' => 'entity_crud_hook_test',
348
    ));
349
    $vocabulary->save();
350
    $_SESSION['entity_crud_hook_test'] = array();
351

352
    $term = entity_create('taxonomy_term', array(
353
      'vid' => $vocabulary->id(),
354
      'name' => 'Test term',
355
      'langcode' => LANGUAGE_NOT_SPECIFIED,
356 357
      'description' => NULL,
      'format' => 1,
358
    ));
359 360 361 362 363 364

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

365
    $_SESSION['entity_crud_hook_test'] = array();
366
    $term->save();
367

368 369 370 371 372 373
    $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',
    ));
374 375

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

378 379 380 381
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type taxonomy_term',
      'entity_crud_hook_test_taxonomy_term_load called',
    ));
382 383 384

    $_SESSION['entity_crud_hook_test'] = array();
    $term->name = 'New name';
385
    $term->save();
386

387 388 389 390 391 392
    $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',
    ));
393 394

    $_SESSION['entity_crud_hook_test'] = array();
395
    $term->delete();
396

397 398 399 400 401 402
    $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',
    ));
403 404 405
  }

  /**
406
   * Tests hook invocations for CRUD operations on taxonomy vocabularies.
407 408
   */
  public function testTaxonomyVocabularyHooks() {
409 410
    $this->installSchema('taxonomy', array('taxonomy_term_data', 'taxonomy_term_hierarchy'));

411
    $vocabulary = entity_create('taxonomy_vocabulary', array(
412
      'name' => 'Test vocabulary',
413
      'vid' => 'test',
414
      'langcode' => LANGUAGE_NOT_SPECIFIED,
415 416
      'description' => NULL,
      'module' => 'entity_crud_hook_test',
417
    ));
418 419 420 421 422 423

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

424
    $_SESSION['entity_crud_hook_test'] = array();
425
    $vocabulary->save();
426

427 428 429 430 431 432
    $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',
    ));
433 434

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

437 438 439 440
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type taxonomy_vocabulary',
      'entity_crud_hook_test_taxonomy_vocabulary_load called',
    ));
441 442 443

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

446 447 448 449 450 451
    $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',
    ));
452 453

    $_SESSION['entity_crud_hook_test'] = array();
454
    $vocabulary->delete();
455

456 457 458 459 460 461
    $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',
    ));
462 463 464
  }

  /**
465
   * Tests hook invocations for CRUD operations on users.
466 467
   */
  public function testUserHooks() {
468
    $account = entity_create('user', array(
469 470 471 472 473
      'name' => 'Test user',
      'mail' => 'test@example.com',
      'created' => REQUEST_TIME,
      'status' => 1,
      'language' => 'en',
474
    ));
475 476 477 478 479 480

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

481
    $_SESSION['entity_crud_hook_test'] = array();
482
    $account->save();
483

484 485 486 487 488 489
    $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',
    ));
490 491

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

494 495 496 497
    $this->assertHookMessageOrder(array(
      'entity_crud_hook_test_entity_load called for type user',
      'entity_crud_hook_test_user_load called',
    ));
498 499

    $_SESSION['entity_crud_hook_test'] = array();
500 501
    $account->name = 'New name';
    $account->save();
502

503 504 505 506 507 508
    $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',
    ));
509 510 511 512

    $_SESSION['entity_crud_hook_test'] = array();
    user_delete($account->uid);

513 514 515 516 517 518
    $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',
    ));
519
  }
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

  /**
   * Tests rollback from failed insert in EntityNG.
   */
  function testEntityNGRollback() {
    // Create a block.
    try {
      $entity = entity_create('entity_test', array('name' => 'fail_insert'))->save();
      $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.
536
      $ids = \Drupal::entityQuery('entity_test')->condition('name', 'fail_insert')->execute();
537 538 539 540
      $this->assertTrue(empty($ids), 'Transactions supported, and entity not found in database.');
    }
    else {
      // Check that the block exists in the database.
541
      $ids = \Drupal::entityQuery('entity_test')->condition('name', 'fail_insert')->execute();
542 543 544
      $this->assertFalse(empty($ids), 'Transactions not supported, and entity found in database.');
    }
  }
545
}