Understanding Drupal8

Ivan Tsekhmistro

@ADYAX

The One with Questions

  • What is the structure of Drupal 8?
    • Symfony, Components ...?
    • Service Container
    • Event Subsribers
    • Routing
  • How it works?

The One with Past

The One with Warning

Things have changed...

get over it.

IN DRUPAL 8

The One with .... you know

Request

Repsonse

Magic!

how it works

Run...

Usually it's just some magic but...

The One with D8 Structure

Symfony 2 Components

  • HttpFoundation
  • DependencyInjection
  • EventDispatcher
  • Routing

+ D8 Components

+ DrupalKernel

+ Extended HTTPKernel

+ StackHTTPKernel

The One with DrupalKernel

DrupalKernelInterface

extends

HttpKernelInterface 

  • boot()
  • shutdown()
  • discoverServiceProviders()
  • getServiceProviders()
  • getContainer()
  • ...
  • handlePageCache()
  • preHandle()
  • handle()

The One with Service Container

Symfony uses a service container that can be used to efficiently manage services in the application. 

 

This Service Container is a global object that is created and contained by the DrupalKernel before a request is handled. It can be used later in code to fetch services, lazy-loaded on the fly.

The One with Service Container configuration

services:
  cache_factory:
    class: Drupal\Core\Cache\CacheFactory
    arguments: ['@settings']
    calls:
      - [setContainer, ['@service_container']]
...
  http_kernel:
    class: Drupal\Core\HttpKernel
    arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack']
    parent: container.trait
  language_manager:
    class: Drupal\Core\Language\LanguageManager
    arguments: ['@language.default']
  language.default:
    class: Drupal\Core\Language\LanguageDefault
    arguments: ['%language.default_values%']
...

code snippet from `core.services.yml` file

Drupal's service configuration is based on YAML-files.

The One with Service Container compiled sample

    /**
     * Gets the 'http_kernel' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * @return Drupal\Core\HttpKernel A Drupal\Core\HttpKernel instance.
     */
    protected function getHttpKernelService()
    {
        $this->services['http_kernel'] = $instance = new \Drupal\Core\HttpKernel(
            $this->get('event_dispatcher'), 
            $this->get('controller_resolver'),
            $this->get('request_stack')
        );

        $instance->setContainer($this);

        return $instance;
    }
/**
 * service_container_prod
 *
 * This class has been auto-generated
 * by the Symfony Dependency Injection Component.
 */
class service_container_prod extends \Drupal\Core\DependencyInjection\Container
{
    public function __construct()
    {
        $this->parameters = $this->getDefaultParameters();
        // ...
        $this->methodMap = array(
            'accept_header_matcher' => 'getAcceptHeaderMatcherService',
            'access_arguments_resolver' => 'getAccessArgumentsResolverService',
            'access_check.cron' => 'getAccessCheck_CronService',
            'access_check.csrf' => 'getAccessCheck_CsrfService',
            'access_check.custom' => 'getAccessCheck_CustomService',
            // ...
            'http_kernel' => 'getHttpKernelService',
            ///...

The One with Tagged Services

services:
  access_check.permission:
    class: Drupal\user\Access\PermissionAccessCheck
    tags:
      - { name: access_check, applies_to: _permission }

How does Drupal understand these tags and know what to do with them?

The One with Compiler Passes

/**
 * Adds services tagged 'access_check' to the access_manager service.
 */
class RegisterAccessChecksPass implements CompilerPassInterface {
/**
   * Implements CompilerPassInterface::process().
   *
   * Adds services tagged 'access_check' to the access_manager service.
   */
  public function process(ContainerBuilder $container) {
    // ...
  }
}

In Drupal, there are some important compiler passes, such as the RegisterAccessChecksPass, which attempts to find all services tagged with access_check (see previous slide) and adds it to the AccessManager service. 

The One with the Flow

  • Set the class loader,
  • Set the Drupal error handler.
  • Read the settings.php file, and generate some other settings dynamically, 
  • Detect if Drupal is actually installed. If it is not, redirect to the installer script.

Create DrupalKernel from Request

Create the HTTP Request object (using Symfony HttpFoundation component)

Run StackHTTPKernel middleware stack ( aka stackphp )

  • Handle Request via ReveseProxyMiddleware
  • Handle Request via PageCache
  • Handle Request via KernelPreHandle

Let DrupalKernel handle Request

boot() - load legacy includes, init Container, register streamwrappers, etc

of how the system works

 The One with Kernel Events

When handle method of the DrupalKernel is called, it finally delegates the call to (Symfony2’s) HttpKernel, which further handles the request by dispatching Events step by step.

  • kernel.request 
  • routing.route_dynamic
  • routing.route_alter
  • ...
  • kernel.response

The One with Event Subscribers

Previously we have had a look at compiler passes. One particularly important usage of tagged services are the event_subscriber-tagged services.

Drupal's Subsrcibers for "kernel.request"

  • AuthenticationSubscriber  -  Loads the session and sets the global user.
  • PathSubscriber - Converts the url to a system path (url aliases, etc).
  • MaintenanceModeSubscriber - If in maintenance mode, show the maintenance page.
  • RouteProvider - Gets the a fully loaded router object.
  • ...

The One with Router

Drupal 7

Drupal 8

Drupal 8 introduces a new mechanism for registering routes, implementing Symfony2's Routing component and the Symfony2 CMF Routing component extension.

Routes basically are the mappings between URL paths and their corresponding page and access callbacks.

The One left behind the scene

  • Configuration
  • Entities
  • Plugins
  • Drupal class

The One in summary

Developing our first Drupal 8 project was a real p... a lot of fun for our team.  

 

Yes, I said fun.  We enjoyed it,  because it was our internal project and we were able to focus on learning the new stuff, contributing bugfixes, and developing best practices. 

To be truly honest sometimes it was a real pain in the ass. Mainly because, some parts of D8 were "unstable".

But Future is coming.

Recommended links

Thank you

Questions?

understanding-d8

By Ivan Tsekhmistro

understanding-d8

  • 1,055