09 November 2012

Drupal 8 with symfony

We all know that Symfony is already in the core of Drupal 8 but how it works and how both systems work? Not that many people understand fully this integration. Me neither but I would like to pubilsh my research notes about how Drupal 8 works now. Surely this material is based on the snapshot of beginning September and I really hope that more things will happen so this information is relevant only for some time.

I have little experience of the building projects with Symfony so my knowledge is very close to majority of drupal developers.

So lets start.

First changes we see in index.php that bootstrap is done on the level of DRUPAL_BOOTSTRAP_CODE instead of DRUPAL_BOOTSTRAP_FULL like in Drupal 7. From documentation about phases of bootstrap of Drupal 8 we can see that phase that "initialize language, path, theme, and modules" is not done yet.

Next thing we see that we instantiate object of the DrupalKernel class (inherits from Symfony Kernel class)
Kernel class in Symfony is responsible for building Dependency Injection Container and registering bundles. We will come back to Dependency Injection Container later. Bundles are like "modules" of drupal world.

Next thing that happens that we instantiate Request object (instance of Symfony HttpFoundation component). This is the object that grabs all global variables form the request and has methods to retrieve them. The idea behind it is that we do not use any global variables in the code anywhere but interact only with this object as a source.

Next part is simple ask kernel object to handle our request
$response = $kernel->handle($request)->prepare($request)->send();
$kernel->terminate($request, $response);

Now lets take a look of internals of the kernel object and what it does to handle our request.

Kernel handle method calls $this->boot() method and then $this->getHttpKernel()->handle($request, $type, $catch);

Booting of the Kernel consists of following steps:
  • Registering Bundles: Bundles are like modules in drupal world. DrupalKernel overrides method registerBundles() to register CoreBundle and allows other modules to provide Symfony-like bundles to the system.
  • Initialize Dependency Injection Container: Container is the object that handles all information about dependencies between objects. So when you want to initiate object of class A but in order to do that system should pass object B to constructor of the object A, Container knows about this dependency and does it for you. In Symfony code this is also called Service Container. Documentation I have found about it is here (Dependency Injection).
  • Also Container is statically cached with drupal_container() function so we can access it in any place of the code. Minimal available Container will consist of information about config system of drupal (config.storage.options). Every bundle also registers new components to Container (see CoreBundle:: build() method for that. It registers services: 'request', 'dispatcher' (Event Dispatcher), , 'resolver', 'http_kernel', 'language_manager'. We can also see that plenty subscribers registered. In terms of this is similar to our hooks system. Here event is fired and dispatcher knows what subscribers are 'registered' for which events and executes their correspond methods (see Drupal\Core\EventSubscriber\PathSubscriber for example).
  • Pass Container to all registered bundles (it is saved in bundle's container property) and call boot() method on bundles. boot() method doesn't do anything at the moment.

After booting the kernel we run its handler method. It comes down firing KernelEvents::REQUEST event where our routing system plays its role. I believe new routing system deserves separate article. After event we have controller we fire event KernelEvents::CONTROLLER that resolves menu callback (in terms of our old menu system). After executing menu callback we fire KernelEvents::VIEW event and our subscribers prepare $response object that is finally returned.

Having response object avaialble we run prepare( ) method that prepares headers, and run send( ) method that prints rendered output.

Finally we run kernel's terminate method that in the end fire KernelEvents::TERMINATE event.

This is very brief overview from the beginner point of view to the system. I hope it made some feeling of understanding of how things work now or at least triggered your interest to learn more about it. Also please remember that things are changing as this are parts that are in active development right now.

07 November 2012

How does caching work in Drupal?

In my experience, there seems to be a lot of misunderstanding how Drupal caching works. I'm not talking about advanced caching mechanisms like Varnish, APC or memcache here, I'm talking about the core Drupal caching: page cache and block cache which are available in Drupal 7 core. Drupal 6 is similar but works a but differently because page caching was simplified for Drupal 7 (e.g. aggresive mode is now a available as a settings.php var) and the entire system also has become pluggable.

Everybody knows this screen and the settings. But what do they exactly mean? What difference do they actually make? What do they do? Here is an attempt to explain the settings at '/admin/config/development/performance'.

Page Caching:
  • If enables, page caching will only be used for anonymous users.
  • If you enable page caching, the entire HTML of each page will be stored in the database. This significantly reduces the amount of queries needed.
  • This automatically means that blocks will also get cached, disregarded their own cache settings.
  • If Varnish is configured, this will also enable varnish caching
  • The page cache max-age will be used (see below) for each page.
  • You can check the "X-Drupal-Cache" HTTP header to check if this cache is HIT.
Block Caching:
  • If you enable block caching, without enabling page caching, the block cache settings will be used (for anonymous and authenticated).
  • The defaults for most blocks is "don't cache" because that is the default for blocks who don't have their cache settings specifically declared.
  • You can use block_cache_alter module to set this for each block.
  • When it's block created by Views, you can set the cache settings for a block in Views.
Minimum Cache Lifetime:
  • This is the amount of time before the page cache is cleared.
  • Page caches are cleared on each cron run
  • Be warned: incorrect settings of your cron and this setting might kill your website performance.
Expiration of Cached Page:
  • This only applies for external caching mechanisms, for example your browser cache or Varnish.
  • It sets the Cache-Control max-age value in the HTTP-HEADERS.
  • This setting only takes effect when page caching is turned on.

10 February 2012

Theming Views 2 – The Basics

Views 2 provides a well structured theming environment allowing presentation control for each element of your view. And in my humble opinion, it rocks!
Those with no past experience with Views 1 will find Views 2 uses standard PHPTemplate theming techniques. All of your experience theming Drupal can be used with Views.
Views 1 themers starting with Views 2 might be a bit confused at first. I was. The single callback in template.php where everything happened is gone, refactored into a consistent framework of template files. All of the freedom that existed in the single function still exists with the added benefit of a well defined structure
Views handles querying the database and organizing the information for display. It creates the output display by converting retrieved data into variables and passing them through a series of templates. Each template handles a different "level" of output creation. The number of templates used to create a view's output depends on the view's type and style, as well as the number of fields involved. These templates exist as files (with a .tpl.php extension), in either the module's or the theme's directory, and follow PHPTemplate's theming conventions.
Generally speaking, the template levels are:
  1. Field: When fields are used in the view ("Row style" = Fields), each field can be themed with a field specific template file. If "Row style" = Node, the node's .tpl.php file is used.
  2. Row: Controls how the individual fields are assembled together into a row. This template isn't used for table styles
  3. Style: Controls how the rows are assembled into the output. For example, in a list view a foreach loop places each row entry into the list entry (<li>) of an unordered list (<ul>).
  4. Display: Controls the other information making up the view such as title, header and footer.

Each level becomes input variables for the next level up. The output of field templates are input variables for the row template, the output for the row template becomes input variables for the style template, and so on. There are also level specific variables available, such as row number. A diagram is available at http://views-help.doc.logrus.com/help/views/analyze-theme.
A template file naming convention is used to make the template highly specific or highly general. Through appropriate naming, a template file can apply to all views, a view of a specific type, or a specific display of a specific view. Where multiple files might apply to a view, the one with the most specific name is used.
Template Files
Each theming level has a default template file. The default templates are located in the theme directory of the Views module. e.g., /root/sites/all/modules/views/theme. These files can provide both a starting point and an example for customization, though their general nature sometimes makes them less useful than one would hope.
Views Module Theme Files
Views Module Theme Files
The theme information link on the Views 2 interface shows views theme file information. Each display has slightly different theming information, so make sure the correct display is selected.
Theme Information Link
Theme Information Link
Clicking the link produces a display pane (shown below). It shows, in bold, the template file used at each level and provides a list of template file names that will override the default templates.
Theme Template Information Pane
Theme Template Information Pane
When you're ready to theme your view, click the theme information link and decide on the appropriate template file name to use. Generally you'll be theming a particular display of a particular view and will select one of the more specific names, if not the most specific name.
Once you've identified the appropriate level to theme, copy the default template file from the modules/views/theme directory to your theme directory and rename it to your chosen name.
Identifying and Copying a Template File
Identifying and Copying a Template File
Pressing the Rescan button in the Information section will refresh the cached information and confirm the file you just copied and renamed has been detected by Views.
You can now modify the template file to your required specifications.
In addition to the recognizing the theme directory as a template file location, Views will also recognize template files in a subdirectory named "views". Placing your views template files in a views subdirectory aids file organization if you have a lot of theme files

Template Variables

Seeing what's used in the default template code is a good starting place but might not give you an idea of all your options. The default templates are highly generalized, as they must be, and it's sometimes difficult to glean useful information from the variables in the for-each loops. Fortunately there are some simple techniques for displaying available variables.
First, don't ignore the comments at the head of the file. For example, the comments in the row template named views-view-fields.tpl.php tell you how the field objects are structured. But good comments can't tell you the specific name of field related variables.
The most tempting course is to place something like this in your template:

<?php print print_r(get_defined_vars(), 1) ?>
Unfortunately, the variables available include the view object, which contains references to itself. The recursion in the resulting output is so long that it's difficult to scan and it can produce memory exceeded errors. A safer approach is using:

   print print_r(array_keys(get_defined_vars()), 1);

  // Or if you have the developer module installed
Each array key is the name of a variable. e.g., an array key named 'field' appears in the template file as $field. This will give you a safe starting point for exploring variables.
If your view templates has a $fields variable you can repeat this trick to get a list of field names:

  print print_r(array_keys($fields), 1);

  // Or if you have the developer module installed
Depending on how you're displaying the information, you may want to wrap the output in a tag and use the htmlentities function if the variable contains HTML:

  print '' . htmlentities(print_r($rows, 1)) . '';
Since Views 2 uses standard PHPTemplate theming, you can use variable preprocessor functions in template.php. More information of preprocessors: http://drupal.org/node/223430. The hook name is the template file name minus .tpl.php and with hyphens converted to underscores. In the example above where the template file is named views-view-list--comments-recent--page.tpl.php, the preprocessor function for template.php is:

function phptemplate_preprocess_views_view_list__comments_recent__page(&$vars) {
  // code

Views 1 to Views 2

Some quick differences Views 1 themers might find useful:
  1. Theming is now handled by template files, not functions in template.php
  2. Views theming is now consistant with the way nodes are themed (i.e., PHPTemplate)
  3. Where Views 1 theming provided sample code and naming instructions via the "Theme wizard" tab, Views 2 uses the Information button and default files in views/theme directory
  4. The closest equivalent template file to the Views 1 theming function is the "Row style output" template file


Basic steps for theming a Views 2 view:
  1. Use the theme information link to determine your template file starting point and naming options
  2. Copy the default template file from modules/views/theme to your theme directory
  3. Rename the file with your selected name
  4. Press rescan to reload the cache and confirm you've done the copy/rename correctly
  5. Read the template file comments and use:
      print print_r(array_keys(get_defined_vars()), 1);    // Or if you have the developer module installed   
    to find variable names - Use a views subdirectory in your theme directory to keep your theme files organized

Article taken from http://www.group42.ca/theming_views_2_the_basics