5

I use hook_ENTITY_TYPE_presave() and hook_ENTITY_TYPE_insert() in order to update the node with a title using its ID.

function <module_name>_node_presave($node) {
  // ...
  if ($node->isNew() && $node->getType() == '<custom_content_type>') {
    $node->title = 'New entity ' . $node->id()->value;
  }
}

function <module_name>_node_insert($node) {
  if ($node->getType() == '<custom_content_type>') {
    $node->title = 'Submission #' . $node->id();
    // more code...
    $node->save();

  }
}

The first setting of title in hook_ENTITY_TYPE_presave() is only done because no entity can be saved without title. However, it seems like the setting of the title in hook_ENTITY_TYPE_insert() does not change anything.

I have already tried calling node->save(); in hook_ENTITY_TYPE_insert() but it gives me an exception stating that I try to store an entity using an already existing primary key. The exception message is

The website encountered an unexpected error. Please try again later.

Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '48' for key 'PRIMARY': INSERT INTO {node_revision} (nid, vid, langcode, revision_timestamp, revision_uid, revision_log) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 45 [:db_insert_placeholder_1] => 48 [:db_insert_placeholder_2] => en [:db_insert_placeholder_3] => 1485011236 [:db_insert_placeholder_4] => 11 [:db_insert_placeholder_5] => ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 770 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

Can I change the title of the new entity (using the id)? Should I use another hook?

  • Note that node->id() returns an integer not an object. – Eyal Jan 15 '17 at 21:34
5

Since nodes have no id on insert, you should just save the node twice.

node_save() initiates a database transaction, in which the changes are not yet written, but the id is already reserved (explaining your issues with not being able to save). You will have to await the database transaction before attempting to save the node again. Unfortunately there is no hook for this.

However, there is a workaround: drupal_register_shutdown_function(). This can be used to call an additional function at the end of the request.

You'll end up with a code like this:

function your_module_node_insert($node){
  if($node->type == 'your_node'){
    drupal_register_shutdown_function('_your_module_post_insert',$node);
  }
}

function _your_module_post_insert($node) {
  if ($node) {
      $node->save();
  }
}

Code comes originally from here: https://drupal.stackexchange.com/a/102185/9921

  • See my answer, Re-saving in hook_node_insert() is possible and the ID is available then, even while the transactions is not yet committed. Autoincrement counters run outside of transactions, the same number will not be re-used even if the transaction is reverted, this allows multiple inserts into a table in different transactions that don't block each other – Berdir Jan 15 '17 at 23:31
  • @Berdir, oh thanks. I expected the new save to create a transaction within the first one which would not solve the problem. Good to know it works. – Neograph734 Jan 15 '17 at 23:45
2

The presave hook is called before the entity is saved, due to that, it does not yet have an ID. That makes you can not use it, it will be empty (your code there is also wrong, id(), returns an ID, not an object, either ->nid->value, or ->id(), as you have in insert().

The insert hook does have an ID, but it it's after saving. You're updating the object in memory but it is not persisted (again) automatically. You can persist it if you want to, simply by explicitly calling $node->save() again.

However, that obviously has some performance drawbacks (but it is possible, despite what the other answers said) as you have to save everything twice.

My recommendation would simply be to rely on a value that you do know, which is basically everyting except the ID and revision ID. For example the creation date:

$node->title = 'Submission from ' . \Drupal::service('date.formatter')->format($node->getCreatedTime());

in hook_presave() should work fine and give you a title that contains a user readable timestamp.

  • Thank you very much for your answer. I had already tried calling "node->save()" and got an exception. I updated my question adding the exception details. – Pantelis Natsiavas Jan 21 '17 at 15:12
1

During hook_ENTITY_TYPE_insert the entity does not have an ID. It gets an ID only after it is saved into the database.

You can, of course, save the entity after it has already been saved and use the ID in the entity title.

mymodule_node_insert(Node $node) {
  $node->setTitle('New entity ' . $node->id())->save();
}

However, If you what you really want is to add a unique title to all nodes that are missing one, I would suggest the following:

mymodule_node_create(Node $node) {
  if (empty($node->label()) {
    $node->setTitle('New node ' . $node->uuid());
  }
}

The code above will work because the uuid field always has a value.

  • 1
    Though true and the cause of the problem, this does not answer the question: Can I change the title of the new entity (using the id)? Should I use another hook? – Neograph734 Jan 15 '17 at 22:01
  • Updated my answer – Eyal Jan 20 '17 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.