Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

drupal_set_title()

Titles on routes now can be set on various ways, depending on your usecase.
Previously just drupal_set_title() was called in whatever place. The following usecases exists:

  1. Static title:
    For static titles you set a '_title' on the routing definition:
    block.admin_add:
      path: '/admin/structure/block/add/{plugin_id}/{theme}'
      defaults:
        _controller: '\Drupal\block\Controller\BlockAddController::blockAddConfigureForm'
        _title: 'Configure block'
      requirements:
        _permission: 'administer blocks'
  2. Dynamic title:
    If you write a controller and you need a dynamic title, for example depending on the site configuration, use _title_callback in the route defaults.
    mymodule.test:
      path: '/mymodule/test'
      defaults:
        _controller: '\Drupal\mymodule\Controller\Test::getContent'
        _title_callback: '\Drupal\mymodule\Controller\Test::getTitle'

    <?php
    class Test {

      /**
       * Returns a page title.
       */
      public function getTitle() {
        return  'Foo: ' . \Drupal::config()->get('system.site')->get('name');
      }

      /**
       * Returns a page render array.
       */
      public function getContent() {
        $build = array();
        $build['#markup'] = 'Hello Drupal';
        return $build;
      }
    }
    ?>
  3. Final title override:

    If you write a controller and you need to override the title from the route, you can return #title in the render array. This should generally to be avoided, since the title for the page when fully rendered could be different from the title in other contexts (like in the breadcrumb).

    <?php
    class Test {

      /**
       * Renders a page with a title.
       *
       * @return array
       *   A render array as expected by drupal_render()
       */
      public function getContentWithTitle() {
        $build = array();
        $build['#markup'] = 'Hello Drupal';
        $build['#title'] = 'Foo: ' . Drupal::config()->get('system.site')->get('name');

        return $build;
      }

    }
    ?>

Output flag of drupal_set_title #

The output validation in Drupal 8 is opposite to Drupal 7. We have to explicitly specify PASS_THROUGH and CHECK_PLAIN is by default in Drupal 7, whereas in Drupal 8 the situation is different. Output is autoescaped unless it is marked safe. Both t() and new FormattableMarkup return objects that will not be autoescaped.

Drupal 7:

<?php
  drupal_set_title(t('Add new shortcut'));
?>

Drupal 8:

<?php
  $form['#title'] = $this->t('Add new shortcut');
?>

Drupal 7:

<?php
  drupal_set_title(t("%name block", array('%name' => $info[$block->delta]['info'])), PASS_THROUGH);
?>

Drupal 8

<?php
  $form['#title'] = $this->t("'%name' block", array('%name' => $info[$block->delta]['info']));
?>

drupal_get_title()

As titles on routes now can be set on various ways (see above), drupal_get_title() has been removed. In its place you should call the title_resolver service.

Drupal 7:

<?php
  $title = drupal_get_title();
?>

Drupal 8:

<?php
  $request = \Drupal::request();
  $route_match = \Drupal::routeMatch();
  $title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());
?>
Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done

Comments

pownraj’s picture

\Drupal::config()->get('system.site')->get('name'); doesn't work anymore.

You have to include the parameters within config itself.

\Drupal::config('system.site')->get('name');

Torenware’s picture

I've been playing with this for a while; clearly, some of the callbacks for this have a signature. But it varies.

Where is this set? And how is it related to the rest of the routing information?

Rob Thorne
Torenware Networks
http://www.torenware.com

Torenware’s picture

This really needs to be documented, and after spending some quality time in the debugger, I can tell you how this works.

If your routing file says something like this:

mymodule.item.edit:
  path: '/mymodule/item/{my_item_object}'
  defaults:
    _controller: '\Drupal\mymodule\Controller\Test::getContent'
    _title_callback: '\Drupal\mymodule\Controller\Test::getTitle'

then you should declare getTitle like this:

<?php
class Test ... {

...

  /**
    * My title callback
    * @param MyItemObjectInterface $my_item_object
    * @return string
    */
   public function getTitle(MyItemObjectInterface $my_item_object) {
      //format your string using your object..
      return "formatted title"
   }
..

}
?>

where the parameter name $my_item_object is an exact match for the parameter you used in your route's path, and MyItemObjectInterface is the appropriate class for an object that the routing system will load when it sees the parameter {my_item_object} in the route.

I don't think this is directly documented anywhere else; I figured it out by seeing what the Symfony routing code does.

Rob Thorne
Torenware Networks
http://www.torenware.com