3

I have a service class declared like this:

 class MyService implements MyServiceInterface {

I want to get rid of a (working) call to a the static \Drupal::service('date.formatter') function and replace with a injected call to $this->dateFormatter.

I am looking at the most upvoted answer to this question: Make a custom date formatter for view.

It suggests that you can output a custom formatted timestamp like this:

$now = \Drupal::time()->getCurrentTime();
$currenttime = $this->dateFormatter->format($now, 'custom', 'Y-m-d H:i');

However, this does not work for me. It uses an injected call to the public function DateFormatter::format, and the upvoted answer does not explain how to set up the class where it is used to inject this service. This produces a WSOD on my site. The cause is obviously that dateFormatter has not been initialized.

As noted, I know that using a static call works:

$now = \Drupal::time()->getCurrentTime();
$currenttime = \Drupal::service('date.formatter')->format($now, 'custom', 'Y-m-d H:i');

I have a rough idea bout how to set up a service class to initialize an injected service. I.e. I think to be able to use it, I need to do at least three things:

  1. Declare the injected service as an argument in myservice.services.yml.
  2. Declare the injected property as a $protected variable.
  3. Initialize it in the class' contructor.

But I am not even sure if this is correct. And the details eludes me. For example: How do I discover what name to include in myservice.services.yml?

Any guidance will be appreciated.

PS: I have studied this answer: How do I inject services in a service, but I don't understand how it applies to my question.

It has been suggested that Inject a class as dependecy injection in a service is a duplicate. The accepted answer to that question is not about the @date.formatter service that is the subject of my question, and it does not mention using autowire to solve the problem. (Which I learned how to use in the answer I now have accepted.)

6
  • A brief comment explaining why you downvote this question would be appreciated. I am open to improving it. Nov 6, 2023 at 17:40
  • 1
    Does this answer your question? Inject a class as depency injection in a service
    – leymannx
    Nov 6, 2023 at 18:24
  • No, the answer does not address the use case where the service already exists, as is the case with the @date.formatter service, so there is no need to create a factory for it. It is an answer for a different use case. Nov 6, 2023 at 18:55
  • 2
    The linked post is how to do it - factories aren’t relevant here, date formatter is a singleton service. These days you can also autowire the arguments in services.yml instead of specifying them if you’d prefer. I haven’t voted but I’m guessing the downvotes are because this is covered pretty exhaustively on this site already and the greater net at large
    – Clive
    Nov 6, 2023 at 19:16
  • I now have received an answer introducing the autowire feature. That is not mentioned in the linked post that is supposed to be a duplicate of this one. Nov 7, 2023 at 9:28

1 Answer 1

5

But I am not even sure if this is correct. And the details eludes me. For example: How do I discover what name to include in myservice.services.yml?

Now that Drupal 9 is end of life you no longer need to do that. Replace the argument list with the autowire option:

mymodule.services.yml

services:
  mymodule.my_service:
    class: Drupal\mymodule\MyService
    autowire: true

and in the service class:

  /**
   * The date formatter.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * Constructs \Drupal\mymodule\MyService
   *
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter.
   */
  public function __construct(DateFormatterInterface $date_formatter) {
    $this->dateFormatter = $date_formatter;
  }

So to discover the service you only need the interface DateFormatterInterface. Use autocomplete and the IDE will automatically add a use statement at the top:

use Drupal\Core\Datetime\DateFormatterInterface;

See the change record: Core services provide aliases for autowiring

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.