Submitted by chrishu on Sat, 10/05/2013 - 16:20

Introduction

The first problem I had to sort out for the Blog module for Drupal 8 was a number of errors being thrown in the db_selects responsible for the two listing views and the RSS feeds. Although I got the pages working again the Select object couldn't have a pager attached in the Drupal 7 manner and had a number of other differences (no limit for example).

Although initially I got the Blog module working again, I had no paging (I limited the query with a range so that there wouldn't be crazy long listing pages).

Views or not?

Views being in core for Drupal 8 is big news, for the varioius listing pages that appear in core Drupal the plan as desctibed here appears to be to use Views but to have a fallback in case Views module has been disabled (Edit: Thanks to the comment by Eelke Blok I know realise this recommendation is just for admin views). I am not sure where this leaves best practice for modules in contrib. however.

My initial thought was to go with the views (making Blog module dependent on Views module) and then provide a fallback later. I had trouble with the Views I needed though. Simple listings were easy, in brief you can create a view in the UI  grab the yaml configuration for it, place the configuration in the the config directory of your module and hey presto the View gets installed with your module. Making the combination of RSS feeds and contextual filters I needed for Blog module alongside overridden titles was beyond me though unfortunately, a similar view for Taxonomy that gets installed in disabled state, suffered similar issues when I enabled it.

I had to conclude that Views weren't quite ready for my needs yet, I suspect I need a new or better plugin for user related views.

Paging the db_select

A little research and I found out how to extend db_select to enable paging, there wasn't really any documentation that I could find easily so I dug around in core. It turns out that the Select object returned by db_select in Drupal 8 has an extend function. Extending the Select object with a PagerSelectExtender wraps it with all the functionality required for paging.

All the above is a little convoluted, one of the listing views for the Blog module is displayed below, it should be clearer how the paging is added if you look for where the query is extended. In Drupal 7 even where objects were used in core it was quite possible to gloss over them, in Drupal 8 is seems a lot more important to dig in and understand how those objects are working. 

function blog_page_last() {

  $build = array();

  $query = db_select('node_field_data', 'n');
  $query->addTag('node_access');
  $query->condition('type','blog');
  $query->condition('status',1);

  $count_query = clone $query;
  $count_query->addExpression('Count(n.nid)');
  
  $paged_query = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender');
  $paged_query->limit(Drupal::config('node.settings')->get('items_per_page'));
  $paged_query->setCountQuery($count_query);

  $nids = $paged_query
    ->fields('n', array('nid', 'sticky', 'created'))
    ->orderBy('sticky', 'DESC')
    ->orderBy('created', 'DESC')
    ->execute()
    ->fetchCol();

  if (!empty($nids)) {
    $nodes = node_load_multiple($nids);
    $build['nodes'] = node_view_multiple($nodes);
    $build['pager'] = array(
      '#theme' => 'pager',
      '#weight' => 5,
    );
  }
  else {
    drupal_set_message(t('No blog entries have been created.'));
  }
  drupal_add_feed('blog/feed', t('RSS - blogs'));

  return $build;
}

Best practice and EntityQuery?

I am more interested in finding out what it takes to get a working module that will work with the first release of Drupal8 than best practice right now, especially as it is not always quite clear what best practice is for Drupal 8 yet. 

Unlike the example I found in core, I changed the name of $query to $paged_query to make it clear that the object has changed and that is why I can now call limit() on it, I am sure that once everything is Drupal 8 compliant there will be quite a lot to make better.

Finally it was easier to learn about db_select changes as the original implementation worked this way, but I suspect that the more abstract EntityQuery would be more appropriate for this kind of listing. The ancestor of EntityQuery, EntityFieldQuery was woefully underused in core D7 (imho), I would suspect for example that using that I would not have to 'just know' that the meat of the node data I wanted was in the node_field_data table (perhaps I do though that is a story for another day). 

 

Comments

Chris Dolby (not verified)
Sat, 10/05/2013 - 23:45

Interesting article.

I always found that I had issues with EntityFieldQuery when I wanted to use it most - things like no ability to left join or find entities without a value for something. With EntityQuery I find that it's well thought through, so I'm very keen to make use of it in 8 and avoid kludgy use of SelectQuery.

Eelke Blok (not verified)
Sun, 10/06/2013 - 09:31

I may be misreading the linked issue and/or your mention of it, but it looks to me it is only suggested to have Views-less fallbacks for admin pages. For anything else, it would seem like duplicated effort. I'd say that with Views in core, it is perfectly valid to require Views for end-user-facing listings.

chrishu
Sun, 10/06/2013 - 12:13

In reply to by Eelke Blok (not verified)

Thanks for that, I agree, I misread the intention, and in principle I agree about using views for user facing listings, although at the moment there still needs to be a last bit of polish on views (and or default plugins) before I can use it. I will ammend to article to reflect this.

 

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.