0

I have a certain content-type B with an entity reference to items of content-type A.

I'm trying to programmatically create a content-type B node when a bool field in content-type A is set to true, whether during creation of content-type A or update/editing of content-type A.

Something like this story:

When user creates or edits a news content (ie, sets the push_to_slider field as true), create a slide content if it doesn't exist. If the user sets the field as false, delete the slide content.

I've been exploring how to do this, and I found out about hook_entity_presave. So, right now, I'm able to check what was edited in the content-type A form, and if it is being created or updated.

My questions are:

  • How can I find out the ID of the content-type A node? I need to know it so I can pass it along when I getStorage('type-B')->create(array). This might be available when editing a A-type node, but not when inserting it, at least not in hook_entity_presave. As far as I can tell, I might be doing this in the wrong place as this hook operates before the DB insertion, is this correct? As such I think I wouldn't have access to an ID at this point. What could be the alternative?

  • Also, how can I find out if a B-type content already exists referencing the A-type node I'm working with? I intend to use that to find out if what I need to delete in case the option in the form is set to false.

Hope this makes sense. If not, let me know and I'll try to clarify. Any help would be very appreciated.

1
  • 1
    I used rules for this and in the rules engine you directly have the nodeid available. . In rules there is also the possibility to implement php so maybe this is a solution
    – Justme
    Jul 25, 2016 at 14:51

2 Answers 2

1

How can I find out the ID of the content-type A node?

You should use devel module's kint function to get all available methods of an object, and you could easy find out, that it's: $node_object->id();

how can I find out if a B-type content already exists referencing the A-type node I'm working with?

You will write a Database service query (not pure sql query), where you will have two important condition:

  • the node type must be B
  • it's reference field contains the id of the A content.

You will of course have to use table joins. To better understand the schema representation of your content types, I suggest you do use phpmyadmin parallel.

1

I'll try to document what I learned during the process of trying to figure out how D8 works (namely, 8.1.x, which is the version I'm working with), in order to find a solution to my problem.

So, the first thing I had to find out was where I had to produce the changes I needed. I though of hook_entity_presave but it wasn't the way to go because I would need info on nodes that might not exist at the time that hook would be called. I found out there are 2 hooks used when inserting or updating nodes. As both of my entities are nodes, this is where the magic happens each time you edit or create new content nodes - in my case, both the A and B types mentioned in the question.

Each of these functions has an $entity parameter variable with methods available for pretty much everything you might need.

For instance, if you need to know which content-type the $entity represents in a given call to these hooks you can simply call its bundle() method:

$node_content_type = $entity->bundle();

In many cases, the node's value for fields will be available like this:

$title_field_value = $entity->title->value;

Other times, like this:

$custom_field_value = $entity->toArray()['field_custom_field_name'][0]['value'];

Particularly, if you need the id for a node, you can simply:

$node_id = $entity->id();

But maybe most importantly, I found out about Drupal 8's entityQuery function, and how to use it. In my scenario, I used it to check for the existence of certain node id to programmatically produce some behavior.

This takes me to the node methods I was looking for:

  • Node::load($id): when you already have an ID (for instance as a result of the query), and want to load the entire node for some operation on its values;

  • Node::create(array): you can create a new node with this method by passing it an array of the values you want/need. Needs to be save()'d after creation;

  • Node::delete(): deletes the node. DOES NOT need save();

  • Node->set(field, value): after you load() a node, you can use this method to set (ie, update) its values. Also needs save() when done.

On a final notice, remember that when using save()you will always go through either the insert or update hooks, if you either create a new node or update it, respectively. Remember this especially if you create a new node when updating another one - I did it wrong and got caught in a loop between inserting and updating nodes that generated heaps of repeated content in my D8 install (oops!...).

DISCLAIMER: I wrote this answer to my own question because I felt the need to clarify many of these aspects for someone that might have a similar issue. I also +1'd @ssibal's answer because it pointed me to the need of using entityQuery. I think D8's documentation is still very sparse/inconsistent and I had to scavenge lots of sources to figure this out. Hope it helps anyone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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