Score:1

Method getTitle() returns an unexpected value. What causes this?

kz flag

In an implementation of hook_node_insert(), I have the following three lines of code:

dpm($entity, 'entity');
$title = $entity->getTitle();
dpm($title, 'title');

From the first dpm() I get:

entity =>
Drupal\node\Entity\Node {#1632 ▼
  +in_preview: null
  #values: array:27 [▼
    ...
    "title" => array:1 [▼
       "x-default" => array:1 [▼
        0 => array:1 [▼
          "value" => "Expected title"
        ]
     ]
...

I.e. the title field output by the variable dumper is the title field I expected to see.

The second dpm() produces:

title =>
"The previous title"

I.e. when I extract the title from the entity, using the getTitle() method, I get a different value. The value is from an entity (node) the I load in a operations link controller (overriding ControllerBase), but it not saved inside the controller, and should not fire hook_node_insert().

I construct and save a new node in the controller, using this code:

$node = \Drupal::entityTypeManager()->getStorage('node')->create([
  'type' => 'my_type',
  'body' => 'Body',
]);
$node->setTitle('Expected title');
$node->save();

I assume that this is the $node->save();that fires hook_node_insert.

What is going on here?

Why does the bogus title appear in the hook, and how do I get the expected result?

For the record: I am not changing the node in hook_node_insert. I am deleting it if the title meets certain criteria. I am unable to use a constraint for preventing it from being created for reasons unrelated to this question.

4uk4 avatar
cn flag
This is not easy to follow for several reasons. The protected value array in a content entity is not supposed to be read by custom code. It contains always original values, x-default is the constant for the default language. So it's normal getTitle() returns a different result. dpm() is not a real time debugging tool. It puts the output in a session which sometimes is displayed one or two requests later, depending on when the next time the message block is displayed. Try Xdebug. Furthermore hook_node_insert() is too late to change the node, use a presave hook.
Free Radical avatar
kz flag
@4uk4 I thought that the methods provided by the class for getting the protected values were supposed to return the actual value of the field. I am surprised to learn that this is not always true. Thanks for nudging me in the direction of Xdebug
Score:1
cn flag

In a content entity the protected $values array contains the original values of the entity. The actual field values are stored in the protected array $fields, which holds an array of FieldItemList objects. These are lazily built, so when the node is loaded this array is empty. When you get/set fields through the public entity methods and properties the field objects with the actual data will be created and stored in this internal array.

For debugging purpose you can force the $fields array to be fully populated by

$values = $node->toArray();

This returns the entity values by creating all field objects and building an array of actual field values.

To check the object properties don't use dpm() because you don't know whether the displayed result is from the same request.

leymannx avatar
ne flag
Would add the info on the hook and Xdebug. Your comment is gold.
Free Radical avatar
kz flag
Thank you for a very educational answer about how using public entity methods to access protected fields works behind the scenes.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.