diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 7b42253..7585ddb 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -56,6 +56,25 @@ function hook_entity_info_alter(&$entity_info) { } /** + * Act on a newly created entity. + * + * This hook runs after a new entity object has just been instantiated. It can + * be used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + */ +function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { + if (!isset($entity->foo)) { + // @todo This example assumes that $entity is an instance of EntityNG, but + // any object implementing EntityInterface will work here and in the + // entity type specific version of this hook. + // Remove this comment when merging Entity and EntityNG. + $entity->foo->value = 'bar'; + } +} + +/** * Act on entities when loaded. * * This is a generic load hook called for all entity types loaded via the diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php index e6d8fe6..6ccea0e 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php @@ -451,6 +451,10 @@ public function create(array $values) { $entity->{$this->uuidKey} = $uuid->generate(); } + // Modules might need to add or change the data initially held by the new + // entity object, for instance to fill-in default values. + $this->invokeHook('create', $entity); + return $entity; } diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index adbb047..5660a4d 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -263,7 +263,12 @@ public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User public function language() { // @todo: Replace by EntityNG implementation once all entity types have been // converted to use the entity field API. - return !empty($this->langcode) ? language_load($this->langcode) : new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED)); + $language = language_load($this->langcode); + if (!$language) { + // Make sure we return a proper language object. + $language = new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED)); + } + return $language; } /** diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 7df5b1e..3aad28c 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -266,8 +266,7 @@ public function language() { $language = $this->get('langcode')->language; if (!$language) { // Make sure we return a proper language object. - // @todo Refactor this, see: http://drupal.org/node/1834542. - $language = language_default(); + $language = new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED)); } return $language; } diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php index 0a67837..2539dee 100644 --- a/core/modules/comment/comment.api.php +++ b/core/modules/comment/comment.api.php @@ -49,6 +49,21 @@ function hook_comment_update(Drupal\comment\Comment $comment) { } /** + * Act on a newly created comment. + * + * This hook runs after a new comment object has just been instantiated. It can + * be used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\comment\Plugin\Core\Entity\Comment $comment + * The comment object. + */ +function hook_comment_create(\Drupal\comment\Plugin\Core\Entity\Comment $comment) { + if (!isset($comment->foo)) { + $comment->foo->value = 'bar'; + } +} + +/** * Act on comments being loaded from the database. * * @param array $comments diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php index 62a7812..003ce32 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentApprovalTest.php @@ -47,7 +47,7 @@ function testApprovalAdminInterface() { // Get unapproved comment id. $this->drupalLogin($this->admin_user); $anonymous_comment4 = $this->getUnapprovedComment($subject); - $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body)); + $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'node_type' => '', 'subject' => $subject, 'comment' => $body)); $this->drupalLogout(); $this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.'); @@ -111,7 +111,7 @@ function testApprovalNodeInterface() { // Get unapproved comment id. $this->drupalLogin($this->admin_user); $anonymous_comment4 = $this->getUnapprovedComment($subject); - $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body)); + $anonymous_comment4 = entity_create('comment', array('id' => $anonymous_comment4, 'node_type' => '', 'subject' => $subject, 'comment' => $body)); $this->drupalLogout(); $this->assertFalse($this->commentExists($anonymous_comment4), 'Anonymous comment was not published.'); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php index 5cf0720..1294de4 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentCSSTest.php @@ -50,6 +50,7 @@ function testCommentClasses() { // Add a comment. $comment = entity_create('comment', array( 'nid' => $node->nid, + 'node_type' => 'node_type_' . $node->bundle(), 'uid' => $case['comment_uid'], 'status' => $case['comment_status'], 'subject' => $this->randomName(), diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php index 902dbdd..35a49fd 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php @@ -145,7 +145,12 @@ function postComment($node, $comment, $subject = '', $contact = NULL) { } if (isset($match[1])) { - return entity_create('comment', array('id' => $match[1], 'subject' => $subject, 'comment' => $comment)); + return entity_create('comment', array( + 'id' => $match[1], + 'node_type' => is_object($node) ? 'node_comment_' . $node->bundle() : '', + 'subject' => $subject, + 'comment' => $comment, + )); } } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/Views/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/Views/CommentTestBase.php index 476c0ef..c913883 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/Views/CommentTestBase.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/Views/CommentTestBase.php @@ -48,6 +48,7 @@ function setUp() { 'nid' => $this->node_user_commented->nid, 'cid' => '', 'pid' => '', + 'node_type' => '', ); $this->comment = entity_create('comment', $comment); $this->comment->save(); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/Views/DefaultViewRecentComments.php b/core/modules/comment/lib/Drupal/comment/Tests/Views/DefaultViewRecentComments.php index b8e7d75..60a3365 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/Views/DefaultViewRecentComments.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/Views/DefaultViewRecentComments.php @@ -77,11 +77,10 @@ public function setUp() { // Create some comments and attach them to the created node. for ($i = 0; $i < $this->masterDisplayResults; $i++) { - $comment = entity_create('comment', array()); + $comment = entity_create('comment', array('node_type' => 'comment_node_' . $this->node->type)); $comment->uid = 0; $comment->nid = $this->node->nid; $comment->subject = 'Test comment ' . $i; - $comment->node_type = 'comment_node_' . $this->node->type; $comment->comment_body[LANGUAGE_NOT_SPECIFIED][0]['value'] = 'Test body ' . $i; $comment->comment_body[LANGUAGE_NOT_SPECIFIED][0]['format'] = 'full_html'; diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc index 32a8c37..3a6fca3 100644 --- a/core/modules/field/field.attach.inc +++ b/core/modules/field/field.attach.inc @@ -1156,7 +1156,6 @@ function field_attach_presave($entity) { * it leaves unspecified. */ function field_attach_insert(EntityInterface $entity) { - _field_invoke_default('insert', $entity); _field_invoke('insert', $entity); // Let any module insert field data before the storage engine, accumulating diff --git a/core/modules/field/field.default.inc b/core/modules/field/field.default.inc index 9168265..27ba32c 100644 --- a/core/modules/field/field.default.inc +++ b/core/modules/field/field.default.inc @@ -54,37 +54,6 @@ function field_default_validate(EntityInterface $entity, $field, $instance, $lan } /** - * Inserts a default value if no $entity->$field_name entry was provided. - * - * This can happen with programmatic saves, or on form-based creation where - * the current user doesn't have 'edit' permission for the field. This is the - * default field 'insert' operation. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity for the operation. - * @param $field - * The field structure for the operation. - * @param $instance - * The instance structure for $field in $entity's bundle. - * @param $langcode - * The language associated with $items. - * @param $items - * An array that this function will populate with default values. - */ -function field_default_insert(EntityInterface $entity, $field, $instance, $langcode, &$items) { - // _field_invoke() populates $items with an empty array if the $entity has no - // entry for the field, so we check on the $entity itself. - // We also check that the current field translation is actually defined before - // assigning it a default value. This way we ensure that only the intended - // languages get a default value. Otherwise we could have default values for - // not yet open languages. - if (empty($entity) || (!isset($entity->{$field['field_name']}[$langcode]) && !property_exists($entity, $field['field_name'])) || - (isset($entity->{$field['field_name']}[$langcode]) && count($entity->{$field['field_name']}[$langcode]) == 0)) { - $items = field_get_default_value($entity, $field, $instance, $langcode); - } -} - -/** * Copies source field values into the entity to be prepared. * * @param \Drupal\Core\Entity\EntityInterface $entity diff --git a/core/modules/field/field.module b/core/modules/field/field.module index df37a5b..e30f16a 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -387,6 +387,43 @@ function field_data_type_info() { } /** + * Implements hook_entity_create(). + */ +function field_entity_create(EntityInterface $entity) { + $info = $entity->entityInfo(); + if (!empty($info['fieldable'])) { + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + field_populate_default_values($entity, $langcode); + } + } +} + +/** + * Inserts a default value for each entity field not having one. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity for the operation. + * @param string $langcode + * (optional) The field language code to fill-in with the default value. + * Defaults to the entity language. + */ +function field_populate_default_values(EntityInterface $entity, $langcode = NULL) { + $entity_type = $entity->entityType(); + $langcode = $langcode ?: $entity->language()->langcode; + foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) { + $field = field_info_field($field_name); + $field_langcode = field_is_translatable($entity_type, $field) ? $langcode : LANGUAGE_NOT_SPECIFIED; + // We need to preserve existing values. + if (empty($entity->{$field_name}) || !array_key_exists($field_langcode, $entity->{$field_name})) { + $items = field_get_default_value($entity, $field, $instance, $field_langcode); + if (!empty($items)) { + $entity->{$field_name}[$field_langcode] = $items; + } + } + } +} + +/** * Implements hook_entity_field_info() to define all configured fields. */ function field_entity_field_info($entity_type) { diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php index c4e1e26..4fb8d5b 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php @@ -84,11 +84,6 @@ public function form(EntityInterface $entity, $langcode, array $items, array &$f $field_name => array(), ); - // Populate widgets with default values when creating a new entity. - if (empty($items) && ($entity->isNew())) { - $items = field_get_default_value($entity, $field, $instance, $langcode); - } - // Store field information in $form_state. if (!field_form_get_state($parents, $field_name, $langcode, $form_state)) { $field_state = array( diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php index 1de9ffa..5ae3610 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php @@ -340,9 +340,12 @@ function testFieldAttachSaveMissingDataDefaultValue() { $this->instance['default_value_function'] = 'field_test_default_value'; field_update_instance($this->instance); + // Verify that fields are populated with default values. $entity_type = 'test_entity'; $entity_init = field_test_create_entity(); $langcode = LANGUAGE_NOT_SPECIFIED; + $default = field_test_default_value($entity_init, $this->field, $this->instance); + $this->assertEqual($entity_init->{$this->field_name}[$langcode], $default, 'Default field value correctly populated.'); // Insert: Field is NULL. $entity = clone($entity_init); @@ -350,6 +353,7 @@ function testFieldAttachSaveMissingDataDefaultValue() { field_attach_insert($entity); $entity = clone($entity_init); + $entity->{$this->field_name} = array(); field_attach_load($entity_type, array($entity->ftid => $entity)); $this->assertTrue(empty($entity->{$this->field_name}[$langcode]), 'Insert: NULL field results in no value saved'); @@ -359,9 +363,14 @@ function testFieldAttachSaveMissingDataDefaultValue() { field_attach_insert($entity); $entity = clone($entity_init); + $entity->{$this->field_name} = array(); field_attach_load($entity_type, array($entity->ftid => $entity)); - $values = field_test_default_value($entity, $this->field, $this->instance); - $this->assertEqual($entity->{$this->field_name}[$langcode], $values, 'Insert: missing field results in default value saved'); + $this->assertEqual($entity->{$this->field_name}[$langcode], $default, 'Insert: missing field results in default value saved'); + + // Verify that prepopulated field values are not overwritten by defaults. + $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127))); + $entity = entity_create('test_entity', array('fttype' => $entity_init->bundle(), $this->field_name => array($langcode => $value))); + $this->assertEqual($entity->{$this->field_name}[$langcode], $value, 'Prepopulated field value correctly maintained.'); } /** diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php index 4df7218..77ac613 100644 --- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php @@ -69,7 +69,6 @@ function testFieldFormSingle() { $this->assertText($token_description, 'Token replacement for description is displayed'); $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed'); $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed'); - // TODO : check that the widget is populated with default value ? // Check that hook_field_widget_form_alter() does not believe this is the // default value form. @@ -113,7 +112,34 @@ function testFieldFormSingle() { entity_get_controller('test_entity')->resetCache(array($id)); $entity = field_test_entity_test_load($id); $this->assertIdentical($entity->{$this->field_name}, array(), 'Field was emptied'); + } + /** + * Tests field widget default values on entity forms. + */ + function testFieldFormDefaultValue() { + $this->field = $this->field_single; + $this->field_name = $this->field['field_name']; + $this->instance['field_name'] = $this->field_name; + $default = rand(1, 127); + $this->instance['default_value'] = array(array('value' => $default)); + field_create_field($this->field); + field_create_instance($this->instance); + $langcode = LANGUAGE_NOT_SPECIFIED; + + // Display creation form. + $this->drupalGet('test-entity/add/test_bundle'); + // Test that the default value is displayed correctly. + $this->assertFieldByXpath("//input[@name='{$this->field_name}[$langcode][0][value]' and @value='$default']"); + + // Try to submit an empty value. + $edit = array("{$this->field_name}[$langcode][0][value]" => ''); + $this->drupalPost(NULL, $edit, t('Save')); + preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match); + $id = $match[1]; + $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.'); + $entity = field_test_entity_test_load($id); + $this->assertTrue(empty($entity->{$this->field_name}), 'Field is now empty.'); } function testFieldFormSingleRequired() { diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php index 8930d97..f2ada97 100644 --- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php @@ -242,6 +242,52 @@ function testTranslatableFieldSaveLoad() { } $this->assertTrue($result, format_string('%language translation correctly handled.', array('%language' => $langcode))); } + + // Test default values. + $field_name_default = drupal_strtolower($this->randomName() . '_field_name'); + $field = $this->field; + $field['field_name'] = $field_name_default; + $instance = $this->instance; + $instance['field_name'] = $field_name_default; + $default = rand(1, 127); + $instance['default_value'] = array(array('value' => $default)); + field_create_field($field); + field_create_instance($instance); + $translation_langcodes = array_slice($available_langcodes, 0, 2); + asort($translation_langcodes); + $translation_langcodes = array_values($translation_langcodes); + + $eid++; + $evid++; + $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); + foreach ($translation_langcodes as $langcode) { + $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']); + } + $entity = entity_create($entity_type, $values); + + ksort($entity->{$field_name_default}); + $field_langcodes = array_keys($entity->{$field_name_default}); + $this->assertEqual($translation_langcodes, $field_langcodes, 'Missing translations did not get a default value.'); + + foreach ($entity->{$field_name_default} as $langcode => $items) { + $this->assertEqual($items, $instance['default_value'], format_string('Default value correctly populated for language %language.', array('%language' => $langcode))); + } + + // Check that explicit empty values are not overridden with default values. + foreach (array(NULL, array()) as $empty_items) { + $eid++; + $evid++; + $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]); + foreach ($translation_langcodes as $langcode) { + $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']); + $values[$field_name_default][$langcode] = $empty_items; + } + $entity = entity_create($entity_type, $values); + + foreach ($entity->{$field_name_default} as $langcode => $items) { + $this->assertEqual($items, $empty_items, format_string('Empty value correctly populated for language %language.', array('%language' => $langcode))); + } + } } /** diff --git a/core/modules/field/tests/modules/field_test/field_test.entity.inc b/core/modules/field/tests/modules/field_test/field_test.entity.inc index 2a7f295..aeb1634 100644 --- a/core/modules/field/tests/modules/field_test/field_test.entity.inc +++ b/core/modules/field/tests/modules/field_test/field_test.entity.inc @@ -121,7 +121,7 @@ function field_test_delete_bundle($bundle) { * Creates a basic test_entity entity. */ function field_test_create_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $label = '') { - $entity = entity_create('test_entity', array()); + $entity = entity_create('test_entity', array('fttype' => $bundle)); // Only set id and vid properties if they don't come as NULL (creation form). if (isset($id)) { $entity->ftid = $id; @@ -131,7 +131,6 @@ function field_test_create_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $l // Flag to make sure that the provided vid is used for a new revision. $entity->use_provided_revision_id = $vid; } - $entity->fttype = $bundle; $label = !empty($label) ? $label : $bundle . ' label'; $entity->ftlabel = $label; diff --git a/core/modules/file/file.api.php b/core/modules/file/file.api.php index fb59229..00dd3c0 100644 --- a/core/modules/file/file.api.php +++ b/core/modules/file/file.api.php @@ -7,6 +7,21 @@ /** + * Act on a newly created file. + * + * This hook runs after a new file object has just been instantiated. It can be + * used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\file\Plugin\Core\Entity\File $file + * The file object. + */ +function hook_file_create(\Drupal\file\Plugin\Core\Entity\File $file) { + if (!isset($file->foo)) { + $file->foo->value = 'bar'; + } +} + +/** * Load additional information into file entities. * * file_load_multiple() calls this hook to allow modules to load diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php index de28051..4dd8fde 100644 --- a/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php +++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumBlockTest.php @@ -104,6 +104,7 @@ public function testActiveForumTopicsBlock() { $node = $this->drupalGetNodeByTitle($topics[$index]); $comment = entity_create('comment', array( 'nid' => $node->nid, + 'node_type' => 'node_type_' . $node->bundle(), 'subject' => $this->randomString(20), 'comment_body' => array(LANGUAGE_NOT_SPECIFIED => $this->randomString(256)), 'created' => $timestamp + $index, diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php index 0667e1b..2ca53b1 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessPagerTest.php @@ -47,6 +47,7 @@ public function testCommentPager() { for ($i = 0; $i < 60; $i++) { $comment = entity_create('comment', array( 'nid' => $node->nid, + 'node_type' => 'node_type_' . $node->bundle(), 'subject' => $this->randomName(), 'comment_body' => array( LANGUAGE_NOT_SPECIFIED => array( diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php index 0959e76..754aa37 100644 --- a/core/modules/node/node.api.php +++ b/core/modules/node/node.api.php @@ -16,9 +16,9 @@ * node.module (for content types created in the user interface) or the module * that implements hook_node_info() to define the content type. * - * During node operations (create, update, view, delete, etc.), there are - * several sets of hooks that get invoked to allow modules to modify the base - * node operation: + * During node operations (create, insert, update, view, delete, etc.), there + * are several sets of hooks that get invoked to allow modules to modify the + * base node operation: * - Node-type-specific hooks: These hooks are only invoked on the primary * module, using the "base" return component of hook_node_info() as the * function prefix. For example, poll.module defines the base for the Poll @@ -36,6 +36,9 @@ * * Here is a list of the node and entity hooks that are invoked, field * operations, and other steps that take place during node operations: + * - Instantiating a new node: + * - hook_node_create() (all) + * - hook_entity_create() (all) * - Creating a new node (calling node_save() on a new node): * - field_attach_presave() * - hook_node_presave() (all) @@ -535,6 +538,23 @@ function hook_node_insert(Drupal\node\Node $node) { } /** + * Act on a newly created node. + * + * This hook runs after a new node object has just been instantiated. It can be + * used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\node\Plugin\Core\Entity\Node $node + * The node object. + * + * @ingroup node_api_hooks + */ +function hook_node_create(\Drupal\node\Plugin\Core\Entity\Node $node) { + if (!isset($node->foo)) { + $node->foo->value = 'bar'; + } +} + +/** * Act on arbitrary nodes being loaded from the database. * * This hook should be used to add information that is not in the node or node diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php index db722bb..499d0bd 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php @@ -86,6 +86,7 @@ public function testCommentHooks() { $nid = $node->nid; $comment = entity_create('comment', array( + 'node_type' => 'node_type_' . $node->bundle(), 'cid' => NULL, 'pid' => 0, 'nid' => $nid, diff --git a/core/modules/taxonomy/taxonomy.api.php b/core/modules/taxonomy/taxonomy.api.php index 956b8b4..dec08d5 100644 --- a/core/modules/taxonomy/taxonomy.api.php +++ b/core/modules/taxonomy/taxonomy.api.php @@ -13,6 +13,21 @@ */ /** + * Act on a newly created vocabulary. + * + * This hook runs after a new vocabulary object has just been instantiated. It + * can be used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary + * The vocabulary object. + */ +function hook_taxonomy_vocabulary_create(\Drupal\taxonomy\Plugin\Core\Entity\Vocabulary $vocabulary) { + if (!isset($vocabulary->foo)) { + $vocabulary->foo->value = 'bar'; + } +} + +/** * Act on taxonomy vocabularies when loaded. * * Modules implementing this hook can act on the vocabulary objects before they @@ -110,6 +125,21 @@ function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Plugin\Core\Entity\Voca } /** + * Act on a newly created term. + * + * This hook runs after a new term object has just been instantiated. It can be + * used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\taxonomy\Plugin\Core\Entity\Term $term + * The term object. + */ +function hook_taxonomy_term_create(\Drupal\taxonomy\Plugin\Core\Entity\Term $term) { + if (!isset($term->foo)) { + $term->foo->value = 'bar'; + } +} + +/** * Act on taxonomy terms when loaded. * * Modules implementing this hook can act on the term objects returned by diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index 38e3170..6ac5515 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -13,6 +13,21 @@ */ /** + * Act on a newly created user. + * + * This hook runs after a new user object has just been instantiated. It can be + * used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\user\Plugin\Core\Entity\User $user + * The user object. + */ +function hook_user_create(\Drupal\user\Plugin\Core\Entity\User $user) { + if (!isset($user->foo)) { + $user->foo->value = 'bar'; + } +} + +/** * Act on user objects when loaded from the database. * * Due to the static cache in user_load_multiple() you should not use this diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php index 1e5b72f..01eaca3 100644 --- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php @@ -108,6 +108,7 @@ protected function setUp() { $comment = array( 'uid' => $user->uid, 'nid' => $node->nid, + 'node_type' => 'node_type_' . $node->bundle(), ); entity_create('comment', $comment)->save(); }