Change record status: 
Project: 
Introduced in branch: 
8.5.x
Introduced in version: 
8.5.0
Description: 

The procedural functions drupal_set_message() and drupal_get_messages() have been deprecated and replaced with a dedicated Messenger service.

You should now inject this service as a dependency for your own services and controllers:

my_module.services.yml:

services:
  my_module.service:
    class: \Drupal\my_module\MyModuleService
    arguments: ['@messenger']
namespace Drupal\my_module;

use Drupal\Core\Messenger\MessengerInterface;

class MyModuleService {

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * MyModuleService constructor.
   *
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   */
  public function __construct(MessengerInterface $messenger) {
    $this->messenger = $messenger;
  }

  /**
   * Before Example.
   */
  public function beforeExample() {
    // Add message (defaults to "status" message type).
    drupal_set_message('Hello world');

    // Add specific type of message.
    drupal_set_message('Hello world', 'custom');
    drupal_set_message('Hello world', 'error');
    drupal_set_message('Hello world', 'status');
    drupal_set_message('Hello world', 'warning');

    // Retrieve and remove specific type of message.
    $errors = drupal_get_messages('error');

    // Retrieve specific type of message, without removing it.
    $errors = drupal_get_messages('error', FALSE);

    // Retrieve and remove all messages.
    $messages = drupal_get_messages();

    // Retrieve all messages, without removing them.
    $messages = drupal_get_messages(NULL, FALSE); // or
    $messages = drupal_set_message();
  }

  /**
   * After Example.
   */
  public function afterExample() {
    // Add message (defaults to "status" message type).
    $this->messenger->addMessage('Hello world');

    // Add specific type of message.
    $this->messenger->addMessage('Hello world', 'custom');
    $this->messenger->addError('Hello world');
    $this->messenger->addStatus('Hello world');
    $this->messenger->addWarning('Hello world');

    // Retrieve and remove specific type of message.
    $this->messenger->deleteByType('error');

    // Retrieve specific type of message, without removing it.
    $this->messenger->messagesByType('error');

    // Retrieve and remove all messages.
    $messages = $this->messenger->deleteAll();

    // Retrieve all messages, without removing them.
    $messages = $this->messenger->all();
  }

}

We did add some easier way (Drupal\Core\Messenger\MessengerTrait) for custom code:

use Drupal\Core\Messenger\MessengerTrait;
class MyModuleService {
  use MessengerTrait;

  public function traitUsageExample() {
    // Add message (defaults to "status" message type).
    $this->messenger()->addMessage('Hello world');

    // Add specific type of message.
    $this->messenger()->addMessage('Hello world', 'custom');
    $this->messenger()->addError('Hello world');
    $this->messenger()->addStatus('Hello world');
    $this->messenger()->addWarning('Hello world');

    // Retrieve and remove specific type of message.
    $this->messenger()->deleteByType('error');

    // Retrieve specific type of message, without removing it.
    $this->messenger()->messagesByType('error');

    // Retrieve and remove all messages.
    $messages = $this->messenger()->deleteAll();

    // Retrieve all messages, without removing them.
    $messages = $this->messenger()->all();
  }
}

Note, a few common base classes now have this trait added, so you may not need to redefine it in your implementations if you extend from them:

Drupal/Core/Block/BlockBase
Drupal/Core/Form/ConfigFormBase
Drupal/Core/Plugin/PluginBase

Procedural code

In rare occasions, you may need to use the Messenger service in procedural functions (hooks, alters, callbacks/static method callbacks, etc.) where the dependency injected Messenger service is not accessible (e.g. no $this->messenger). In these instances, the \Drupal::messenger() static helper method is available for you to use. This helper method should only be used in places where the service cannot be injected and should never be used as a way to create a new service that requires this service.

e.g.

\Drupal::messenger()->addError("migration failed");

Differences from drupal_get_messages($type)

drupal_get_messages($type)

returned an nested array structure keyed by message type:

['error' => ['error message 1', 'error message 2']]

MessengerInterface::messagesByType($type)

just returns an array of messages in the format:

['error message 1', 'error message 2']
Impacts: 
Module developers

Comments

Marko B’s picture

There is missing part for DI and Create method

public static function create(ContainerInterface $container) {
return new static(
$container->get('messenger')
);
}

imclean’s picture

Services don't require the create method. See the example services YML file at the top of the change record and the documentation.

b.khouy’s picture

For this example:

// Retrieve and remove specific type of message.
    $this->messenger->deleteByType('error');

I think it would be better to store retrieved messages in a variable so we can use theme when its needed instead of just losing them:

// Retrieve and remove specific type of message.
    $messages = $this->messenger->deleteByType('error');
tfrech’s picture

Jeez! I remember when you could just say "do this" and Drupal did it. Now you have to invent an entire app just to get it to say "hello" to you.

greg boggs’s picture

For some things, I agree, it's hard that we are missing the old helper functions. For this tho?

Old code:

drupal_set_message('message');

New code:

\Drupal::messenger()->addMessage('message');

brooke_heaton’s picture

The Drupal 9 codebase is immense, and heavy and difficult to learn. This is one of the reasons immense numbers of Drupal 7 sites will become Wordpress sites. All the madness above is a great example of the decline of Drupal adoption.

Ilya K’s picture

I can't understand how to use new method instead of drupal_get_messages
First of all, i add:

use Drupal\Core\Messenger\MessengerInterface;

then, i write this:

  /**
   * {@inheritdoc}
   */
  public function ajaxSubmitCallback(array &$form, FormStateInterface $form_state): AjaxResponse {
    $ajax_response = new AjaxResponse();
    $message = [
      '#theme' => 'status_messages',
      '#message_list' => MessengerInterface::all(),     <-------- HERE
      '#status_headings' => [
        'status' => t('Status message'  ),
        'error' => t('Error message'),
        'warning' => t('Warning message'),
      ],
    ];
    $messages = \Drupal::service('renderer')->render($message);
    $ajax_response->addCommand(new HtmlCommand('#form-system-messages', $messages));
    return $ajax_response;
  }

but it gives me an error
what exactly am I doing wrong or what is missing?

harishst’s picture

all() is not a static function. You should call it by either injecting or use the MessengerTrait as like in the above example.
Injecting the "messenger" service is the way to go.

donpwinston’s picture

This is f'ing stupid. No way in hell am I doing this. I'll use \Drupal::messenger()->addMessage('message'); every time.

Simpler is always better.

matt b’s picture

Totally agree.

brooke_heaton’s picture

There are many reasons for the lack of Drupal adoption post Drupal 7. The complete waste of time of the above is one of them. There's such substantial code bloat and performance decay with Drupal 9, it's baffling.

vineet.bhardwaj’s picture

Agree

rajesh.vishwakarma’s picture

Get messages by their types like status, warning, and error.
\Drupal::messenger()->messagesByType('status'); Get Status messages

Some other useful methods

\Drupal::messenger()->all();
\Drupal::messenger()->deleteByType();
\Drupal::messenger()->deleteAll();