Skip to content

Instantly share code, notes, and snippets.

@mparker17
Last active December 19, 2015 17:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mparker17/5990429 to your computer and use it in GitHub Desktop.
Save mparker17/5990429 to your computer and use it in GitHub Desktop.
2013-07-13 DrupalCampTO Presentation - Whose Hook is it Anyway?

Whose Hook is it Anyway?

A comedic look into Drupal 8

Presented at DrupalCamp Toronto 2013 (2013-07-13). By @mparker17 and @emarchak

Dependency injection in D8

What is dependency injection?

Rather than creating objects in our own code, we ask a DI Container to create them for us and hand us the finished project. Drupal 8 core’s main DI container is named ContainerBuilder.

Why do it this convoluted way?

Modules can ask ContainerBuilder to substitute certain objects with better ones. (This is analogous to the way the “Taxonomy node” module in D6 substituted nodes for taxonomy terms in a way transparent to the user.)

Also, it’s easier to test because you can use mock objects — lightweight objects that have the same interface as other objects, but don’t do anything.

How does it work?

The key to this is to use Interfaces instead of specific classes (as much as you can) when writing your code. Instead of referring to specific classes, refer to the interface or interfaces that class has.

Drupal uses DI mainly for services (e.g.: database connection, module handler). If your object provides a service, you can register it with ContainerBuilder and give it a Service ID. When you need to use an service, you ask ContainerBuilder to get you an object with that Service ID, and it chooses the best one.

Alternately, using specially-formatted comments in your objects, you can get ContainerBuilder to create objects and pass them into the constructor or setter functions.

Credits

How the Drupal 8 page router works

What’s a page router?

The new hook_menu(). Actually, technically just the part of hook_menu() that runs code when a certain path is requested.

Why?

Mainly because we wanted to create routes on more than just the path (e.g.: have one function generate HTML and another generate XML and JSON).

Simplifies things a bit too, because hook_menu() handled a few related but different features.

What’s changed?

You put all your page callback functions into one or more Controller objects instead of the global namespace.

Then, you map paths to their corresponding functions in your module’s .routing.yml file, along with information about what the function returns (a form, HTML, JSON, etc.), and what permissions a user needs to see it.

How does it work?

When a request for a page comes in, Drupal’s new Kernel:

  1. Figures out what route to call based on it’s list.
  2. Checks permissions.
  3. Creates the Controller object (our old friend ContainerBuilder will pass in any helper objects it needs).
  4. Calls the specified function and gets it’s output.
  5. Based on the information about what the function returns, the Kernel gives that output to the appropriate handler to do any final preparations before sending it to the browser.

The Backtrace

  1. drupal_render_page()
    • initial call back for page assembly. We still have access to hook_page_alter :(
  2. drupal_render()
    • assembles overall page.
  3. theme()
    • if the element has a #theme_wrapper declared. If the item is configured to be cached, this is after this point where it is cached.
    • this is where it checks for all theme hook suggestions (preprocess_ or theme_ functions)
  4. twig_render_template
    • loads the twig template files renders twig blocks and return the output as a string, if debug setting is enabled returns template suggestions in html comments.
    • passes all children through render() function, which is a wrapper for drupal_render().
    • twig_render_var() handles all parsing of twig variables
  5. Twig_Template
    • is the object that assembles all twig blocks and renders them out.
    • this can be extended to include more functionality for twig as needed.

twig_render_var

  • located in twig.engine, is a wrapper for render() function. This allows objects to be casted to strings, and arrays to be passed through render() so we no longer have inconsistent types within the tpl files.

Theme/Preprocess

  • there are still both theme and preprocess functions, we haven't stripped them both out of core (that was a goal of the twig initiative, they're still there)
  • theme_ functions still assemble render arrays, and the return the array passed through drupal_render(). We're not totally free from the render arrays of doom, but they have been pushed further back into the development "stack".
    • the drupal_render() function itself appears to remain the same from D7 to D8.
  • hide() and show() functions still work as expected, but are now called using twig syntax {% hide(content.links) %}

Twig templates

  • there is two way communication between the template files and the admin UI because D8 is able to parse the .html.twig files and assemble options for the content admin.
  • twig sanitizes variables that it prints out, there is no need for additional check_plain().
  • it can also modify variables using the pipe ( | ), so it introduces filters for things such as capitalization, json encoding/decoding, conversion of new lines to html line breaks, url encoding and more!
  • for/if/else control loops work as expected, nothing insane. You can still loop through elements as we have before.

Template inheritance

  • you can include additional templates using the {% include 'sidebar.html' %} syntax, and they inherit context passed to them such as context included from a for loop.
  • you can override certain block elements within a global template. You can define Twig blocks that can be overridden in child templates.
    • for example, you can define a sidebar block as {% block sidebar %} … {% endblock %} in a global page template.
    • To override that block in a specific node-page template, you need to include {% extends "page.twig.html" %} in your template and access the blocks using the same markup of {% block sidebar %} … {% endblock %}

Credits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment