Drupal Planet Posts

Custom access control for Drupal 7 entities

Have you ever used hook_node_access() to control access to various node operations on your site? Have you found this hook unbelievably awesome? Thought to yourself, boy, I'm unstoppable now? Well, I sure did.

The problem is that Drupal 7 entities do not start and end with nodes and you may want to control access to other entities in the same way. However, there is no hook_taxonomy_term_access() or hook_fieldable_panels_pane_access() that you can use to apply this tactic. So what can you do in these cases?

The first thing is to understand that each entity implementation is different. Some have a centralised access callback for all the operations while others simply define permissions or access callbacks to be used directly inside the hook_menu() definition. And I'm sure there are also other ways of handling this but these I think are the most common.

In this article we are going to look at two entity examples: taxonomy terms (from core) and fieldable panels panes (from contrib). We will trace the access pipeline from request to response and see what we can do to intervene in this process and add our own logic. So let's begin.

Taxonomy terms

The first entity type we are going to look at is the regular taxonomy term introduced by core. It's actually pretty easy to understand how this entity type is built and what we can do in order to hook into the access pipeline.

If we take a look at taxonomy_menu(), we can quickly figure out which paths it creates to add and edit terms and what access callback and arguments are defined:

Adding terms to a vocabulary

$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add'] = array(
   'title' => 'Add term',
   'page callback' => 'drupal_get_form',
   'page arguments' => array('taxonomy_form_term', array(), 3),
   'access arguments' => array('administer taxonomy'),
   'type' => MENU_LOCAL_ACTION,
   'file' => 'taxonomy.admin.inc',
);

Editing a particular term

$items['taxonomy/term/%taxonomy_term/edit'] = array(
   'title' => 'Edit',
   'page callback' => 'drupal_get_form',
   // Pass a NULL argument to ensure that additional path components are not
   // passed to taxonomy_form_term() as the vocabulary machine name argument.
   'page arguments' => array('taxonomy_form_term', 2, NULL),
   'access callback' => 'taxonomy_term_edit_access',
   'access arguments' => array(2),
   'type' => MENU_LOCAL_TASK,
   'weight' => 10,
   'file' => 'taxonomy.admin.inc',
);

By nature, viewing taxonomy term pages has to do with node access since they show a list of nodes so we will skip this aspect here and stick with just the add/edit operations.

So let's change the access callbacks and potential passed arguments inside a hook_menu_alter() implementation.

/**
 * Implements hook_menu_alter().
 */
function demo_menu_alter(&$items) {
  $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add']['access callback'] = 'demo_taxonomy_term_access';
  $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add']['access arguments'] = array(3, 'add');

  $items['taxonomy/term/%taxonomy_term/edit']['access callback'] = 'demo_taxonomy_term_access';
  $items['taxonomy/term/%taxonomy_term/edit']['access arguments'][] = 'edit';
}

So what happens here? We are simply replacing the access callback definition for these two menu items with our own custom function demo_taxonomy_term_access(). Additionally, we standardise a bit the arguments this function gets: $entity (either term or vocabulary object) and $op (add or edit). This covers both cases.

Now let's write our callback function:

/**
 * Access callback for taxonomy term add/edit operations
 *
 * @param null $entity
 * @param null $op
 * @return bool
 */
function demo_taxonomy_term_access($entity = null, $op = null) {
  if ($op === 'add') {
    return user_access('administer taxonomy');
  }

  if ($op === 'edit') {
    return taxonomy_term_edit_access($entity);
  }
}

Inside the function we run a check on $op and perform the access logic we want. In doing so, we make use of the $entity object that can be either the term being edited or the vocabulary to which a new term is added. In this example we are replicating exactly the intended access checks of the Taxonomy module. To add a term, a user needs to have the administer taxonomy permission while to edit one it needs either the same permission or a vocabulary specific permission (as seen inside taxonomy_term_edit_access()). Now it's up to you to include inside this logic whatever else you need. And you end up with something not so dissimilar to hook_node_access() but for taxonomy terms.

Fieldable Panels Panes (FPP)

FPP is a contributed module that creates an entity type that is primarily used inside a Panels context. Regardless of any of this though, it too exposes CRUD operations on the entities of this type. And consequently, there are access implications. So let's see how we can hook into this pipeline by starting where we did with the Taxonomy module: at fieldable_panels_panes_menu().

By looking inside this hook implementation we can find many defined paths which relate to these CRUD operations. And we also see that many of them have fieldable_panels_panes_access() as the access callback with some specific arguments passed to it.

But what does this function actually do? Nothing but taking the parameters and deferring to the controller class responsible for this entity type and its access() method. And by checking fieldable_panels_panes_entity_info(), the principle function responsible for defining the entity type, we find that this is the PanelsPaneController class. In there, we find all the logic for determining access rights for various operations.

Now that we know all this, what can we do to hook into this pipeline? We could do like before and override the hook_menu() implementation. But since there are so many menu items and the FPP class controller is already doing such a nice job, that may be counter productive. So let's instead override the entity definition and replace the class controller with one of ours that extends PanelsPaneController. In there, we then do what we want.

First, we implement hook_entity_info_alter():

/**
 * Implements hook_entity_info_alter().
 */
function demo_entity_info_alter(&$entity_info) {
  $entity_info['fieldable_panels_pane']['controller class'] = 'DemoPanelsPaneController';
}

Right after this, we create a file inside our module called DemoPanelsPaneController.inc which contains the following to start with:

<?php

/**
 * Overrides fieldable panels panes controller functionality
 */
class DemoPanelsPaneController extends PanelsPaneController {

}

Finally, we edit the module's .info file and make sure it loads this file:

files[] = DemoPanelsPaneController.inc

Then we clear the cache. If all went well, nothing really has changed on the site in terms of functionality. However, the DemoPanelsPaneController class is being used for controlling the fieldable_panels_pane entity type. And since this one extends PanelsPaneController, all previous functionality remains. It follows to now override the access() method and include our own logic to it:

public function access($op, $entity = NULL, $account = NULL) {
   // $account not always full (defaults to current user)
   return parent::access($op, $entity, $account);
}

In the example above, nothing is really changed because the logic is deferred back to the parent class. But you could add some logic in addition or instead of that depending on various contextual factors.

However, I strongly recommend/warn you to stick to the minimum amount of deviation from default is needed, and for all rest, defer back to the original logic. This is to prevent the opening of any security holes. For example, if your access() method looks like this:

public function access($op, $entity = NULL, $account = NULL) {
   if ($op === 'update') {
     return false;
   }   
}

You are indeed denying access to the edit form but now anybody can create and delete entities because there is no more check on those operations. So make sure you understand this and do not leave any loopholes. The fix in this case would be:

public function access($op, $entity = NULL, $account = NULL) {
   if ($op === 'update') {
     return false;
   }   
   return parent::access($op, $entity, $account);
}

If the operation is edit, the access is denied for everybody (probably not a good idea but suitable for this demo purpose). However, if the operation is delete, create or view, we defer to the logic of the parent class to handle those cases. In which case the default FPP permissions will be used.

Conclusion

In this article we've seen two ways we can hook into the access checking pipeline of entities in Drupal 7. We've learned that there is more than just one way of going about it depending on how the entity type in question has been defined. The purpose was to illustrate how you can approach the matter and where you need to look in order to find a solution. Hope this helps.

Dynamically sort complex data with PHP's sort functionality

PHP Logo

In a previous article I showed you how to use the usort() and uasort() PHP functions to sort some more complex data using a comparator callback function. How cool was that?

Although powerful, this technique is quite restricting though because all the logic for the sorting happens inside the comparator function. In other words, you cannot pass parameters to this callback except for the actual default values that are being compared. So what's the problem with this?

Say you have an array of objects that have a name property that can be retrieved by a getName() getter method. And let's say they also have an address property retrieved by getAddress(). And you have a listing of this data and you need to allow for sorting by any of these properties both ASC and DESC. And forget for one second about the possibility of ordering them as they come out of your data store.

Implementing this with just the default usort() function means you will need 4 different comparer functions (one for each combination of property and sort direction). And what if you want to add more columns to the listing? Oh no..

As you can imagine, the solution to this problem is having a dynamic sorting function (or method in a class) to which you can pass the items to be sorted, the property by which to sort and the direction of sort. And then not have to worry about creating all these ridiculous comparer functions. So how might this look like?

function sortByObjectProps(&$items, $method, $order) {
  if ( ! is_array($items)) {
    return false;
  }

  return usort($items, function($a, $b) use ($method, $order){
    $cmp = strcmp($a->$method(), $b->$method());
    return $order === 'asc' ? $cmp : -$cmp;
  });
}

So what happens here? First of all, $items is passed by reference so we don't need to return it. The return value will just be a boolean indicating the success or failure of the sort. Additionally, we pass the method name that retrieves the property value ($method) and the direction of the sort ($order).

Then we run usort() on the items but - and here is the kicker - with an anonymous function that can use the passed in method and order values. Then it's just a matter of comparing the return values of the getter methods and negate the integer if the order is DESC. Pretty cool no?

So now you can have as many columns as you need and get them sorted in both directions. And obviously even more complex stuff.

Hope this helps.

6 steps for new Drupal 8 developers

So you are taking the plunge into learning Drupal 8 for the purpose of developing sites, modules, themes, etc. You're a great Drupal 7 developer, familiar with many drupalisms but you don't have tons of experience with modern PHP frameworks, principles and practices. Well, Drupal 8 still includes many of the old drupalisms but still attempts to keep in line with times and modernise itself.

In this article I want to outline 6 steps I believe you should take to get started learning how to develop custom modules and/or themes in Drupal 8. On top of these 6 builds everything else.

The first three are PHP related in a more general fashion, while the last three target aspects of Drupal 8 itself.

1. Learn Object Oriented Programming

One of the biggest difference between Drupal 7 and 8 for developers is the way code is written. It's still PHP but it's now much more object oriented. Global procedural functions are still in place but most of the logic happens in classes.

In case you don't have much experience with Object Oriented Programming in PHP, this is the first thing you need to learn, brush upon or revise (depending on your level). There are many resources available out there, all scattered as hyperlinks in this section. There are also courses you can take, both free and paid.

Without quite a solid OOP foundation, you won't be able to understand much of how Drupal 8 modules are built.

2. Learn how to use Composer

One of the consequences of modernizing PHP has been the introduction of the Composer package manager. Projects are no longer built without it as it does a great job of installing, updating and managing in general the external libraries and dependencies of your project. Not to mention its very helpful autoloader.

Drupal 8 uses Composer to manage external PHP libraries and dependencies (such as Symfony components, Guzzle, etc) and there is talk about the ability to handle also contrib modules. So make sure you know how Composer works and even start using it in non-Drupal projects.

3. Get familiar with Symfony

One of the main points of contention (back then) in the Drupal 8 development cycle was the introduction of Symfony components. Some people didn't really agree with this great shift from the Drupal way, but others embraced it wholeheartedly. I am in the latter group as I love Symfony and used it even before developing anything in Drupal 8.

Drupal 7 developers are often being told that knowing Symfony is not required in order to develop in Drupal 8. While technically true, you still end up learning a lot of it through the Drupal experience. That being said, I strongly recommend learning some Symfony before. It is a great modular framework and knowing its concepts will really help you out in understanding how Drupal 8 is built (for the components it uses I mean). Once you can build a small website in Symfony, you'll enjoy developing in Drupal 8 that much more because concepts will be similar a lot of the time. Not too mention that you can use Symfony to build apps on its own.

4. Routing and controllers

Just like with Drupal 7, when starting to learn Drupal 8 you need to create the obligatory hello world module (creating a page with a parameter in the URL( usually world) that displays the text Hello + parameter). This example introduces you to many important things:

  • Module folder structure
  • Routing (no more hook_menu) through routing.yml files that map to Controller methods
  • Controller classes which have various methods that can be mapped to routes
  • Access arguments for these routes
  • Rendering markup to the page inside the Controller methods
  • etc

So I really recommend giving this a go.

5. Plugins

Another important concept you'll need to get familiar with is Plugins. Admittedly, this is not the easiest to grasp, but it is super important because it's everywhere. Not to worry though, it's not rocket science.

Many old Drupal 7 implementations of various concepts have been transformed to plugins: info hooks, blocks, field formatters, views handlers, etc. Understanding plugins is therefore very important for being able to extend default Drupal functionality.

6. Dependency injection and the service container

The last step I am going to mention here is dependency injection. Drupal 8 uses the Symfony dependency injection container to manage service instantiation and injection into classes that need them. This helps decouple functionality and increases testability.

However, many people are scared of this concept, mainly because they don't grasp it. I wasn't super comfortable either before understanding it. But you should definitely learn what it means, why we use it and how we use it. Because it is a very simple concept that is used all the time in procedural code as well.

You can already find many tutorials out there on Drupal 8 that load services statically through the \Drupal class. It is much faster to write so people (me included) prefer it when writing about D8. I usually also tend to make a note that using dependency injection is preferred in theses cases.

Not understanding what the service container and dependency injection is will easily let you fall into the habit of just statically requesting services and coupling your code like it was procedural. Once you are clear on this point, this will hopefully not happen any more and the sight of a \Drupal::get('some_service') will make you think twice.

Conclusion

There you have it. What I think are the first 6 steps you should take when learning Drupal 8 for the first time. Of course there are many other important things to learn and do but I believe they build on top of this foundation. Of course, this is me writing so others may have different opinions (very much welcomed in the comments). So let's discuss.

Creating a custom Views filter in Drupal 8

In the previous article we've seen how we can interact programatically with Views in Drupal 8 in order to create a custom field in our Views results. Today, we will be looking a bit at how we can create a custom filter you can then add to the View in the UI and influence the results based on that.

Filters in Views have to do with the query being run by Views on the base table. Every filter plugin is responsible with adding various clauses in this query in an attempt to limit the results. Some (probably most) take on configuration parameters so you can specify in the UI how the filtering should be done.

If you remember from the last article, to create our field we extended the FieldPluginBase class. Similarly, for filters, there is a FilterPluginBase class that we can extend to create our own custom filter. Luckily though, Views also provides a bunch of plugins that extend the base one and which we can use or extend to make our lives even easier. For example, there is a BooleanOperator class that provides a lot of the functionality needed for this type of filter. Similarly, there is an InOperator class, a String class, etc. You can find them all inside the views/src/Plugin/views/filter directory of the Views core module or here.

In this tutorial, we will create 2 custom filters. One will be a very simple one that won't even require creating a new class. The second one will be slightly more complex and for which we will create our own plugin.

The code we write will go in the same module we started in the previous article and that can be found in this repository.

Node type filter

The first filter we will write is very simple. We want to be able to filter our node results by the machine name of the node type. By default, we can use a filter in which we select which node types to be included. Let's say, for the sake of argument, we want a more complex one, such as the one available for a regular text value like the title. The String class will be perfect for this and will provide actually 100% of our needs.

So let's go to our hook_views_data_alter() implementation and add a new filter:

...

$data['node_field_data']['node_type_filter'] = array(
  'title' => t('Enhanced node type filter'),
  'filter' => array(
    'title' => t('Enhanced node type filter'),
    'help' => t('Provides a custom filter for nodes by their type.'),
    'field' => 'type',
    'id' => 'string'
  ),
);

...

Since the table that we are interested in altering the query for is the node_field_data table, that is what we are extending with our new filter. Under the filter key we have some basic info + the id of the plugin used to perform this task. Since our needs are very simple, we can directly use the String plugin without us having to extend it. The most important thing here though is the field key (under filter). This is where we specify that our node_type_filter field (which is obviously a non-existent table column) should be treated as being the type column on the node_field_data table. So, by default, the query alter happens on that column. And this way we don't have to worry about anything else, the String plugin will take care of everything. If we didn't specify that, we would have to extend the plugin and make sure the query happens on the right column.

And that's it. You can clear your cache, create a View with nodes of multiple types and add the Enhanced node type filter to it. In its configuration you'll have many matching options such as equals, contains, does not contain etc you can use. For example, you can use contains and specify the letters art in order to return results whose node type machine name contain these letters.

Node title filter

The second custom filter we build will allow Views UI users to filter the node results by their title from a list of possibilities. In other words, they will have a list of checkboxes which will make it possible to include/exclude various node titles from the result set.

Like before, we need to declare our filter inside the hook_views_data_alter() implementation:

...

$data['node_field_data']['nodes_titles'] = array(
  'title' => t('Node titles'),
  'filter' => array(
    'title' => t('Node titles'),
    'help' => t('Specify a list of titles a node can have.'),
    'field' => 'title',
    'id' => 'd8views_node_titles'
  ),
);

...

Since we are filtering on the title column, we are extending again on the node_field_data table but with the title column as the real field to be used. Additionally, this time we are creating a plugin to handle the filtering identified as d8views_node_titles. Now it follows to create this class:

src/Plugin/views/filter/NodeTitles.php:

<?php

/**
 * @file
 * Definition of Drupal\d8views\Plugin\views\filter\NodeTitles.
 */

namespace Drupal\d8views\Plugin\views\filter;

use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\filter\InOperator;
use Drupal\views\ViewExecutable;

/**
 * Filters by given list of node title options.
 *
 * @ingroup views_filter_handlers
 *
 * @ViewsFilter("d8views_node_titles")
 */
class NodeTitles extends InOperator {

  /**
   * {@inheritdoc}
   */
  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
    parent::init($view, $display, $options);
    $this->valueTitle = t('Allowed node titles');
    $this->definition['options callback'] = array($this, 'generateOptions');
  }

  /**
   * Override the query so that no filtering takes place if the user doesn't
   * select any options.
   */
  public function query() {
    if (!empty($this->value)) {
      parent::query();
    }
  }

  /**
   * Skip validation if no options have been chosen so we can use it as a
   * non-filter.
   */
  public function validate() {
    if (!empty($this->value)) {
      parent::validate();
    }
  }

  /**
   * Helper function that generates the options.
   * @return array
   */
  public function generateOptions() {
    // Array keys are used to compare with the table field values.
    return array(
      'my title' => 'my title',
      'another title' => 'another title',
    );
  }

}

Since we want our filter to be of a type that allows users to select from a list of options to be included in the results, we are extending from the InOperator plugin. The class is identified with the @ViewsFilter("d8views_node_titles") annotation (the id we specified in the hook_views_data_alter() implementation).

Inside our plugin, we override three methods:

Inside init(), we specify the title of the set of filter options and the callback that generates the values for options. This callback has to be a callable and in this case we opted for the generateOptions() method on this class. The latter just returns an array of options to be presented for the users, the keys of which being used in the query alteration. Alternatively, we could have also directly created the options inside the init() method by filling up the $this->valueOptions property with our available titles. Using a callback is cleaner though as you can perform various logic in there responsible for delivering the necessary node titles.

The point of overriding the query() and validate() methods was to prevent a query and validation from happening in case the user created the filter without selecting any title. This way the filter has no effect on the results rather than returning 0 results. It's a simple preference meant to illustrate how you can override various functionality to tailor your plugins to fit your needs.

And that's it. You can add the Node titles filter and check the box next to the titles you want to allow in the results.

Conclusion

In this article we've looked at how we can create custom filters in Drupal 8 Views. We've seen what are the steps to achieve this and looked at a couple of the existing plugins that are used across the framework and which you can use as is or extend from.

The best way to learn how all these work is by studying the code in those plugin classes. You will see if they are enough for what you want to build or extending them makes sense. In the next article we are going to look at some other Views plugins, so stay tuned.

Creating a custom Views field in Drupal 8

In this article I am going to show you how to create a custom Views field in Drupal 8. At the end of this tutorial, you will be able to add a new field to any node based View which will flag (by displaying a specific message) the nodes of a particular type (configurable in the field configuration). Although I will use nodes, you can use this example to create custom fields for other entities as well.

So let's get started by creating a small module called d8views (which you can also find in this repository):

d8views.info.yml:

name: Drupal 8 Views Demo
description: 'Demo module that illustrates working with the Drupal 8 Views API'
type: module
core: 8.x

In Drupal 7, whenever we want to create a custom field, filter, relationship, etc for Views, we need to implement hook_views_api() and declare the version of Views we are using. That is no longer necessary in Drupal 8. What we do now is create a file called module_name.views.inc in the root of our module and implement the views related hooks there.

To create a custom field for the node entity, we need to implement hook_views_data_alter():

d8views.views.inc:

/**
 * Implements hook_views_data_alter().
 */
function d8views_views_data_alter(array &$data) {
  $data['node']['node_type_flagger'] = array(
    'title' => t('Node type flagger'),
    'field' => array(
      'title' => t('Node type flagger'),
      'help' => t('Flags a specific node type.'),
      'id' => 'node_type_flagger',
    ),
  );
}

In this implementation we extend the node table definition by adding a new field called node_type_flagger. Although there are many more options you can specify here, these will be enough for our purpose. The most important thing to remember is the id key (under field) which marks the id of the views plugin that will be used to handle this field. In Drupal 7 we have instead a handler key in which we specify the class name.

In Drupal 8 we have something called plugins and many things have now been converted to plugins, including views handlers. So let's define ours inside the src/Plugin/views/field folder of our module:

src/Plugin/views/field/NodeTypeFlagger.php

<?php

/**
 * @file
 * Definition of Drupal\d8views\Plugin\views\field\NodeTypeFlagger
 */

namespace Drupal\d8views\Plugin\views\field;

use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\NodeType;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;

/**
 * Field handler to flag the node type.
 *
 * @ingroup views_field_handlers
 *
 * @ViewsField("node_type_flagger")
 */
class NodeTypeFlagger extends FieldPluginBase {

  /**
   * @{inheritdoc}
   */
  public function query() {
    // Leave empty to avoid a query on this field.
  }

  /**
   * Define the available options
   * @return array
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['node_type'] = array('default' => 'article');

    return $options;
  }

  /**
   * Provide the options form.
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    $types = NodeType::loadMultiple();
    $options = [];
    foreach ($types as $key => $type) {
      $options[$key] = $type->label();
    }
    $form['node_type'] = array(
      '#title' => $this->t('Which node type should be flagged?'),
      '#type' => 'select',
      '#default_value' => $this->options['node_type'],
      '#options' => $options,
    );

    parent::buildOptionsForm($form, $form_state);
  }

  /**
   * @{inheritdoc}
   */
  public function render(ResultRow $values) {
    $node = $values->_entity;
    if ($node->bundle() == $this->options['node_type']) {
      return $this->t('Hey, I\'m of the type: @type', array('@type' => $this->options['node_type']));
    }
    else {
      return $this->t('Hey, I\'m something else.');
    }
  }
}

We are defining our NodeTypeFlagger class that extends FieldPluginBase (which is the base plugin abstract class for the views field many plugins extend from). Just above the class declaration we use the @ViewsField annotation to specify the id of this plugin (the same one we declared in the hook_views_data_alter() implementation). We also use the @ingroup annotation to mark that this is a views field handler.

In our example class, we have 4 methods (all overriding the parent class ones).

Query

First, we override the query() method but leave it empty. This is so that views does not try to include this field in the regular node table query (since the field is not backed by a table column).

DefineOptions

The second method is the defineOptions() method through which we specify what configuration options we need for this field. In our case one is enough: we need to specify the node type which we want flagged in the Views results. We set a sensible default as the article node type.

BuildOptionsForm

The third method, buildOptionsForm() is responsible for creating the form for the configuration options we declared earlier. In our case we just have a select list with which we can choose from the existing node types.

Render

Lastly, the render() method which is the most important and which deals with output. We use it to actually render the content of the field for each result. Here is where we perform some business logic based on the currently set node type option and flag with a message whether or not the current result is in fact of the type specified in the configuration.

The $resultRow object is an instance of Drupal\views\ResultRow which contains data returned for the current row by Views and the entity object at the base of the query (in our case the node). Based on this information we can perform our logic.

Keep in mind you can use depedency injection to inject all sorts of services into this class and make use of them in your logic. Additionally, you can override various other methods of the parent class in order to further customize your field.

Conclusion

There you have it. A small custom module that demonstrates how to create a custom Views field (plugin). Relationships, filters, sorters and others work in similar way. I will be covering those in later articles. Stay tuned.

Drupal update hooks with multiple passes

If you do a lot of Drupal development and need to deploy configuration I am sure that you are using update hooks to some extent at least. If you don't use Features and want to create a taxonomy vocabulary or something in code, the hook_update_N() hook is the way to go.

But have you ever needed to perform an update the size of which would exceed PHP's maximum execution time? If you need to create 1000 entities (let's just say as an example), it's not a good idea to trust that the production server will not max out and leave you hanging in the middle of a deploy. So what's the solution?

You can use the batch capability of the update hook. If you were wondering what the &$sandbox argument is for, it's just for that. You use it for two things mainly:

  • store data required for your operations across multiple passes (since it is passed by reference the values remain)
  • tell Drupal when it should stop the process by setting the $sandbox['#finished'] value to 1.

Let me show you how this works. Let's say we want to create a vocabulary and a bunch of taxonomy terms with names from a big array. We want to break this array into chunks and create the terms one chunk at the time so as to avoid the load on the server.

So here is how you do it:

/**
 * Create all the terms
 */
function my_module_update_7001(&$sandbox) {

  $names = array(
    'Fiona',
    'Jesse',
    'Michael',
    ...
    'Sam',
    'Nate',
  );

  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['limit'] = 5;
    $sandbox['max'] = count($names);

    // Create the vocabulary
    $vocab = (object) array(
      'name' => 'Names',
      'description' => 'My name vocabulary.',
      'machine_name' => 'names_vocabulary',
    );

    taxonomy_vocabulary_save($vocab);
    $sandbox['vocab'] = taxonomy_vocabulary_machine_name_load('names_vocabulary');
  }

  // Create the terms
  $chunk = array_slice($names, $sandbox['progress'], $sandbox['limit']);
  if (!empty($chunk)) {
    foreach ($chunk as $key => $name) {
      $term = (object) array(
        'name' => $name,
        'description' => 'The name is: ' . $name,
        'vid' => $sandbox['vocab']->vid,
      );

      taxonomy_term_save($term);
      $sandbox['progress']++;
    }
  }

  $sandbox['#finished'] = ($sandbox['progress'] / $sandbox['max']);


}

So what happens here? First, we are dealing with an array of names (can anybody recognise them by the way?) Then we basically see if we are at the first pass by checking if we had set already the progress key in $sandbox. If we are at the first pass, we set some defaults: a limit of 5 terms per pass out of a total of count($names). Additionally, we create the vocabulary and store it as a loaded object in the sandbox as well (because we need its id for creating the terms).

Then, regardless of the pass we are on, we take a chunk out of the names always offset by the progress of the operation. And with each term created, we increment this progress by one (so with each chunk, the progress increases by 5) and of course create the terms. At the very end, we keep setting the value of $sandbox['#finished'] to the ratio of progress per total. Meaning that with each pass, this value increases from an original of 0 to a maximum of 1 (at which point Drupal knows it needs to stop calling the hook).

And like this, we save a bunch of terms without worrying that PHP will time out or the server will be overloaded. Drupal will keep calling the hook as many times as needed. And depending on the operation, you can set your own sensible chunk sizes.

Hope this helps.

How to remove all the Voting API results for a given node type

Have you ever needed to remove in bulk a bunch of voting results for, let's say, a given content type? There is no option in the UI but you can find in the votingapi.module some handy functions that will allow you to write a customized update hook.

So let's say that we need to remove all the results for the article content type. If we look in the votingapi_vote table, we don't see any bundle or content type column, but we see an entity_id. So we need to get all the ids of our article nodes:

  $query = db_query("SELECT nid FROM node WHERE type = 'article'");
  foreach ($query as $res) {
    $nids[] = $res->nid;
  }

Now we have the $nids array containing all of our node IDs. Next, let's load all the votes for these IDs:

  module_load_include('module', 'votingapi', 'votingapi.module');

  $votes = votingapi_select_votes(array('entity_id' => $nids));

First we include the right module file and then we use one of its functions to select all the votes that match some criteria (in our case an array of IDs). Next, we need to worry also about the votingapi_cache table which contains the results of the voting per entity. We need to remove that as well. So we'll use another helper function from Voting API:

$results = votingapi_select_results(array('entity_id' => $nids));

Now we have also the result objects we need to delete so we can proceed with the actual removal. For this, we can use two more handy methods from the Voting API module:

votingapi_delete_votes($votes);
votingapi_delete_results($results);

And that's it. This will remove all the votes and their aggregated results from both tables. It may take some time so make sure you have enough server resources to perform this task.

To use this code, I recommend creating an update hook in a custom module that you run once. But make sure you properly test it on your test environment before deploying and running the code on production servers. Always keep in mind the possibility of the server running out of resources depending on how many votes you have in the database.

Do you have any better way of batch deleting votes/results? This is what I found and I'm curious if you know of any better ways. Let me know.

PHP: Using the usort / uasort functions

Have you ever had to sort an array in PHP? There are a bunch of functions available, the most common being sort(). This function does a default sorting of the values in your array. So if you have numbers or want to do alphabetical sorting, sort() will get the job done.

But what if you require a more complex sorting logic? Let's say you have an array of names that need to be sorted in a specific order. I don't know, because your client says so. Let me show you how.

Let's say your DB returns a list of names in an array:

$names = array("Christian", "Daniel", "Adrian");

And your client says they need to be arranged in the following order: Adrian, Christian, Daniel. You can use the usort() function together with a comparator function you write yourself. How does this system work?

As a second argument of the usort() function, we pass in the name of our custom comparator function. The way this gets processed is that all the values in the array that needs sorting are passed to this function 2 at the time (usually you'll see them as $a and $b). This is done to determine which one takes precedence over which. The comparator has to return 0 if the 2 values are considered equal, a negative integer if the first value is less than the second value or a positive integer if the second value is less than the first. What less means is up to you to determine. So let's put this in practice with our example:

function _name_comparer($a, $b) {
    $correct_order = array("Adrian", "Christian", "Daniel");

    $a_key = array_search($a, $correct_order);
    $b_key = array_search($b, $correct_order);

    if ($a_key == $b_key) {
        return 0;
    }

    return ($a_key < $b_key) ? -1 : 1;
}

usort($names, "_name_comparer");

So what happens in my comparator function? First, I create an array that contains the proper order of the names. This means that each value has an integer key that can be easily compared (and that I store in the $a_key and $b_key variables). After comparing these, I return 0, a negative or positive integer. The result is that the $names array gets resorted in the order they appear in the $correct_order local variable I created. And that's it.

If the $names variable is associative and you need to maintain the keys as they were, you can use the uasort() function:

$names = array(
    "christian" => "Christian", 
    "daniel" => "Daniel", 
    "adrian" => "Adrian",
);
uasort($names, "_name_comparer");

The comparator function can stay the same, but the uasort() function will take into account and maintain the index association of your values.

And that's it. Hope this helps.

Drupal 8 Dependency Injection, Service Container And All That Jazz

With the move from a mostly procedural to a mostly OOP based architecture in Drupal 8, many Drupal developers have been introduced to new concepts we don't fully understand. I myself was terrified of notions such as dependency injection and service container, making me worry about the future of my Drupal development.

So I took it to Symfony (from where many components have been borrowed) and then Drupal 8 alpha releases and turns out it's not a big deal. All you need in order to understand them is to know basic OOP principles. Check out Larry Garfield's timeless introductory article to Object Oriented Programming on Drupal Watchdog for a good start.

In this article I am going to talk a bit about what dependency injection is and why one would use a container for managing these dependencies. In Symfony and Drupal 8 this is called a service container (because we refer to these global objects as services). Then, we will take a look at how these are applied in Drupal 8. Briefly, because you don't need much to understand them.

So what is dependency injection?

Take the following simple class:

class Car {

  protected $engine;

  public function __construct() {
    $this->engine = new Engine();
  }

  /* ... */

}

When you instantiate a new class Car you go like this:

$car = new Car();

And now you have an object handler ($car) that has an $engine property containing the handler of another object. But what if this car class needs to work with another engine? You'd have to extend the class and overwrite its constructor for each new car with a different engine. Does that make sense? No.

Now consider the following:

class Car {

  protected $engine;

  public function __construct($engine) {
    $this->engine = $engine;
  }

  /* ... */

}

To instantiate an object of this class, you go like this:

$engine = new Engine();
$car = new Car($engine);

Much better. So now if you need to create another car using another engine, you can do so easily without caring about the Car class too much since it is supposedly equipped to work with all the engines in your application.

$turbo = new TurboEngine();
$car2 = new Car($turbo);

And that is dependency injection. The Car class depends on an engine to run (dooh), so we inject one into its constructor which then does what it needs to do. Rather than hardcoding the engine into the Car class which would not make the engine swappable. Such constructor injections are the most common but you'll also find other types such as the setter injection by which we would pass in the engine through a setter method.

So what is this container business?

So far we've seen a very simple class example. But imagine (rightfully) that the Car has many other potentially swappable components (dependencies), like a type of gear shift, breaks or wheels. You have to manually instantiate all these dependent objects just so you can pass them to the one you actually need. This is what the container is for, to do all that for you.

Basically it works like this. You first register with the container your classes and their dependencies. And then at various points of your application, you can access the container and request an instance of a particular class (or service as we call them in Symfony and Drupal 8). The container instantiates an object of that class as well as one of each of its dependencies, then returns you that service object. But what is the difference between services that we usually access through the container and other PHP classes?

A very good definition that makes this distinction comes from the Symfony book:

As a rule, a PHP object is a service if it is used globally in your application. A single Mailer service is used globally to send email messages whereas the many Message objects that it delivers are not services. Similarly, a Product object is not a service, but an object that persists Product objects to a database is a service.

Understanding how the container works under the hood is I believe not crucial for using it. It's enough to know how to register classes and how to access them later. There are multiple ways to register services but in Drupal 8 we use YAML files. In Symfony, you can use directly PHP, YAML or even XML. To know more about how to do this in Drupal 8, check out this documentation page. Accessing the services in Drupal 8, on the other hand, is done in one of two ways: statically and using, yet again, dependency injection.

Statically, it's very simple. We use the global \Drupal namespace to access its service() method that returns the service with the name we pass to it.

$service = \Drupal::service('my service');

This approach is mostly used for when we need a service in our .module files where we are still working with procedural code. If we are in a class (such as a form, controller, entity, etc), we should always inject the service as a dependency to the class. Since I covered it elsewhere and the Drupal documentation mentioned provides a good starting point, I won't go into the exact steps you need to take in order to inject dependent services into your Drupal 8 classes. However, you can check out my introductory series on Drupal 8 module development, on Sitepoint.com, where I covered the process of creating services and injecting them as dependencies (in the third part, published soon if not already).

Conclusion

So there you go. Dependency injection is a very simple concept that has to do with the practice of decoupling functionality between classes. By passing dependencies to objects we can isolate their purpose and easily swap them with others. Additionally, it make is much easier to unit test the classes individually by passing mock objects.

The service container is basically there to manage some classes when things get overwhelming. That is, when the number grows and the number of their dependencies also increases. It keeps track of what a certain service needs before getting instantiated, does it for you and all you have to do is access the container to request that service.

Hope its clear.

4 tools you should definitely use for Drupal development

Developing Drupal sites can be quite a challenge and adventure. And this comes from those who call themselves Drupal developers. Men and women of PHP who work with other frameworks and applications most likely find it even more cumbersome to understand. However, Drupal is fostered by a big community of enthusiastic people who love it, myself included. But in all honesty, the more you work with it, the more you develop this love/hate relationship with all the quirks of Drupal development.

But one thing is certain, and this is applicable to other areas of web development as well: the tools you use for the job can make a big difference in the experience you have. And Drupal makes no exception. I mean, remember when we were writing PHP in Notepad and that one missing semicolon added 2 hours of debugging that day?

In this article I would like to share with you 4 tools that I use for Drupal development. I heavily rely on them to minimise frustration, increase productivity and lower development time. And I can guarantee you that if you are serious about Drupal development and you are not using them, you are missing out. But if you are, kudos, do share some of your experiences that further demonstrate their power.

So here we are, I guess in order of complexity, the 4 tools in my belt when I run vagrant up to spin up a project on my local environment. I will say a few words about each, but I can't go into all of their features. That's for you to explore after I give you a taste of what they can offer.

Devel and Search Krumo modules

Devel is the most used Drupal development module built for aiding with debugging code, generating content and all sorts of other dev tasks. Search Krumo is yet another cool module that plugs into it in order to give us a hand with navigating through huge array structures. And if you know Drupal 7, it is all about big arrays.

These modules are probably the first solution for debugging variables in Drupal. Using Devel's dsm(), dpm(), and krumo() functions in your code you can print out arrays, objects and whatever you need for a great overview of what you have in scope at that moment of execution. And they are not the only ones...

Another great use for the Devel module is content generation. It has a series of submodules that can generate nodes, taxonomy terms, users and more. Sometimes you need 500 nodes on the site to test something out. Additionally, you can use it to execute PHP code in the Drupal environment, switch between users on the site and other awesome functionality. So it's a must have on any Drupal development environment.

Drush

Drush is an awesome command line tool for Drupal that speeds up many tasks. Some people call it the swiss army knife of Drupal and you can't really argue the opposite.

Drush allows you to perform a host of Drupal tasks from the command line. You can download and enable/disable/uninstall/update modules or Drupal core and all sorts of other helpful jobs. This great list of core commands can give you an overview of what you can do with Drush. And if you are looking for some help with setting Drush up on your server, you can read this article I wrote on the subject.

Another great thing about Drush is that aside from all the awesome core commands, you can declare your own. This way, you can expose some of your custom functionality to the command line. This goes behind development and can help with maintenance or even production jobs that need to run with cron. So it truly is versatile.

A good IDE like PHPStorm

I mentioned before the good ol' times (not really) when Notepad was the editor of choice for many developers. Luckily nowadays we don't have to suffer through that as we can use IDEs for coding. I myself use PHPStorm and is of great help.

An IDE can speed up your development time by preventing code mistakes, highlighting syntax for great readability, code hinting for classes and functions in your project and many others. And with Drupal, all of these are important. Since Drupal 7 is mostly procedural you need to be aware of many functions and parameters. The IDE great reduces the time you spend online researching these APIs. And not to mention the integrations you can create with these API documentation resources.

Another great use of IDEs (which for me is the most important) is debugging. Integrating PHPStorm with XDebug on my local server really changed things around. But more on that in the next point.

Xdebug

As great as the Devel module is for printing out variables to the screen, it does not come close to Xdebug when we talk about debugging. After setting it up, all you have to do is place a breakpoint in your code and load your site page. The execution stops at the breakpoint (that was hopefully supposed to be executed) and you have access to a wealth of contextual information. You get all the global and scope variables that you can navigate through, a great callstack of what functions/methods have been triggered so far and many others.

Another cool feature is that you can play forward the execution line by line and jump inside of to be called functions to see where the code is heading. This is great for debugging where your code fails, at which point does that exception get thrown, or why that variable is null. So I do recommend checking it out.

Conclusion

And there you have it: 4 tools you can start using today to make you Drupal development experience more efficient. Using Drush and the Devel module are really only specifically for Drupal, but the use of a good IDE and XDebug is applicable to all other PHP projects as well. And I can guarantee you they are all worth using.