3

I've seen multiple ways to programmatically create entities.

In this case I'm creating a taxonomy term. One is using this method

$term = \Drupal\taxonomy\Entity\Term::create([
  'name' => $name, 
  'vid' => $vocabulary,
])->save();

Where I'm using the base entity class's public static create function. Another way to perform the action is using an entity storage manager. Like so:

$term = [
  'name'     => $name,
  'vid'      => $vocabulary,
];

$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->create($term);

I looked up the 'create' function of the base Entity class and it seems to just be implementing what appears in the second example I provided. Is there a better practice between the two? Or does it not matter?

UPDATE: Also is there a difference between what the two return? Unless I'm doing things wrong I noticed that the top method returned an int which I'm assuming is the term id.

2 Answers 2

3

Actually, there is a difference between the two shown snippets: The first will end up containing, in $term, either SAVED_NEW or SAVED_UPDATED because that is the value returned from Entity::save() (and from EntityStorageInterface::save(), indirectly used from the first).

Rewriting the second snippet as follows would mean introducing the same error.

$values = [
  'name'     => $name,
  'vid'      => $vocabulary,
];

$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->create($values)->save();

The correct code to use in the first case would be the following one, especially if $term is later used (for example because passed to a function).

$term = Term::create([
  'name' => $name, 
  'vid' => $vocabulary,
]);

$term->save();

(Don't forget to add the right use statement, which should always go on the top of the file containing the code.)

As for using one or the other snippet, you will often find Drupal code using Node::create(), Term::create(), or Vocabulary::create() in tests, which is (IMO) preferable than using the other snippet you are showing because at least it doesn't directly use the \Drupal class. (Just run grep -rnwI ./ -e Term::create from Bash in the directory containing Drupal core code, and you will see how many times it is used.)

Probably, after [meta] Replace \Drupal with injected services where appropriate in core is marked as fixed, there will be no reason to avoid using methods like Term::create(), which has still the pro to be clearer and shorter.
In any case, if the service I want to use is already available in a class property, or I can inject the service I need in the class I am using, I would rather use that property or inject the service, instead of using a static/global property, directly or indirectly. (Dependency injection is preferable to global properties.)

3

In procedural code it doesn't matter, because both do the same. The static create() is a shortcut for the second example. (The different result is because the first saves the term and the second does not, if you want the term as result then save in a separate step)

In OOP code a better way is dependency injection. The second example points in the right direction. Inject the entity type manager, store it in a class property and use it:

$term = $this->entityTypeManager->getStorage('taxonomy_term')->create($term);

How to inject a service depends on which class you want to use it in.

A lot of base classes include services already and if you are lucky such a common service like this is one of them. Sometimes, for example in a controller, there is a method to retrieve the service. Then add to the code above parentheses:

$term = $this->entityTypeManager()->getStorage('taxonomy_term')->create($term);

See ControllerBase::entityTypeManager().

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.