Writing Views Handlers – Lets code a module – Time to write a custom field.



Writing Views Handlers – Lets code a module – Time to write a custom field.

0 0


presentation-views-handlers

Writing Views Handlers in Drupal 7

On Github tomfriedhof / presentation-views-handlers

Writing Views Handlers

Presented by Tom Friedhof

Hello everyone, thanks for coming today to my session on extending Views module.

Tom Friedhof

  • we are a Los Angeles based Digital Agency,
  • Drupal is our platform of choice.
  • Our agency has been working on the Drupal platform now for about a decade. We've been part of the community for a while.

Subscribe to our YouTube Channel

http://youtube.com/activelamp

  • Go to our YouTube channel right now and subscribe
  • Now go to all your social feeds and tell everyone to subscribe (just kidding) kind of.
  • We are going to be publishing the 3 sessions that I'm giving this week on our channel

I won't be talking about how to use Views today.

- This session is an intermediate level session, I won't be talking about how to use Views. I'm assuming that everyone in this room has used the Views module at some level.

What I'll be covering today

  • How to extend Views with Handlers.
  • We are going to look at code.
  • What I'm going to be talking about today is how to extend views to do exactly what you want. In this session I'll dig into how to do this. Yes, we're going to look at code. This will be a tutorial style session.

Encapsulation, Inheritance and Polymorphism using Drupal Entities

Go check it out on our YouTube channel (when it's released).

  • How many people here went to my last session?
  • One of the core concepts that I talked about was "Inheritance".
  • Views is one of the few sub systems in Drupal 7 that is Object Oriented and uses Ineritance quite a bit for writing handlers, as you'll see.

Lets code a module

mymodule.info

name = My Cool Module
description = Provides an area handler for views

core = 7.x

dependencies[] = views
dependencies[] = xautoload (>= 7.x-5.0)

mymodule.module

/**
 * Implements hook_views_api().
 */
function mymodule_views_api() {
  return [
    'api' => 3
  ];
}
  • Create two files in here to make this a module that we can enable... the .info file and the .module file.
  • Views basically needs to know what version of the API we're using.
  • Views will now look for a file in our module called modulename.views.inc
  • create that file modulename.views.inc

mymodule.views.inc

/**
 * Implements hook_views_data().
 */
function mymodule_views_data() {
  return [
    'views' => [
      'mymodule_area' => [
        'title' => t('My Custom Area'),
        'help' => t('Adds a custom area handler.'),
        'area' => [
          'handler' => 'Drupal\mymodule\Views\Handlers\Area\MyCoolHandler'
        ]
      ]
    ]
  ];
}
  • Views will load this file before it tries to invoke any hooks that it defines, so this is a good place to put your hook_views_data hook.
  • This hook basically registers any new data that views should know about.
  • So if your module defines a whole new table in the database, you could use this hook to tell views about that table and how to access data from it.
  • Now if you're creating new database tables that you want Views to know about, then that table should probably be an Entity, so that you get the API's surrounding Entities when working with that data.
  • And if you use the Entity API module when creating that Entity, you get the Views integration for free, you don't have to define a hook_views_data for that custom table.
  • Keep in mind that Entities don't have to fieldable, and you don't have to provide a UI for your entities, but in my opinion I can't think of a good reason to not make custom tables that you add to the Drupal database not an Entity, if not simply for the CRUD operations.
  • We are defining an Area Handler here
  • Point out the PSR4 - and explain

Checkout our video on PSR4

Directory structure follows naming convention

mymodule/src/Views/Handlers/Area
  • Basically, the way this works is it's going to look for the MyCoolHandler class in this directory structure...
  • Lets go create our directory structure for this handler, and the actual class
MyCoolHandler.php
namespace Drupal\mymodule\Views\Handlers\Area;

/**
 * Defines a new handler class for views.
 */
class MyCoolHandler {

}
Make sure you have that namespace defined, that's really important. So at this point we should have a handler that can be used within Drupal, however it does absolutely nothing. One thing that we want to do to this handler is have it extend functionality that already exists in Views. Views has base classes for everything. Since we're writing an area handler, lets extend the base class for area handlers. Turn on the module and demo it.

That's how you write every type of handler in Views

Time to write a custom field.

We're going to create a psuedo field

  • Like I said earlier, if you setup new tables using the Entity API module, you won't need define every column
  • I'm going to create a pseudo field on the node table to show you how to define it yourself.
hook_views_data()
'node' => [
  'my_custom_field' => [
    'title' => t('My Custom Field'),
    'help' => t('Showing how to write fields at SandCamp'),
    'real field' => 'created',
    'field' => [
      'handler' => 'Drupal\mymodule\Views\Handlers\Field\MyCustomField'
    ],
    'filter' => [
      'handler' => 'Drupal\mymodule\Views\Handlers\Filter\MyCustomFilter'
    ]
  ],
]
  • You can see that I specified a field called my_custom_field, which doesn't exist on the node table, so that would immediately give me an SQL error, so I specified the 'real field' key to set what actual column I want to query. Now the SQL won't fail.
mymodule/src/Views/Handlers/Field/MyCustomField.php
namespace Drupal\mymodule\Views\Handlers\Field;

class MyCustomField extends \views_handler_field {

  function render($values) {
    $value = $this->get_value($values);
    return date('Y-m-d', $value);
  }

}
  • Lets change how the field is rendered. Lets go in the handler that we defined and override the render method.

Custom Filter

mymodule/src/Views/Handlers/MyCustomFilter.php
function option_definition() {
  $options = parent::option_definition();

  $options['even_odd'] = array('default' => 'odd');

  return $options;
}

function options_form(&$form, &$form_state) {
  $form['even_odd'] = [
    '#type' => 'radios',
    '#title' => t('Even or Odd'),
    '#default_value' => $this->options['even_odd'],
    '#options' => ['odd' => t('Only odd numbers'), 'even' => t('Just even numbers')],
    '#description' => t('Demonstrating how to create your own options form')
  ];

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

function admin_summary() {
  return $this->options['even_odd'] == 'even' ? t('Just even numbers') : t('Just odd numbers');
}
Lets add a custom filter now for this field. Lets customize how we configure this filter by overriding the options_form method so that we can pull only nodes that were created with an odd numbered timestamp or even numbered time stamp

Change the query

mymodule/src/Views/Handlers/MyCustomFilter.php
function query() {
  $this->ensure_my_table();
  $operator = $this->options['even_odd'] == 'even' ? '=' : '>';
  $this->query->add_where_expression($this->options['group'], "($this->table_alias.$this->real_field % 2) $operator 0");
}
Now this is the power of where extending views really shows, we now need to modify the query that views executes so that we can get only nodes with even or odd time stamps. All we have to do is define what the query looks like for this field by implementing the query method There is no way, to my knowledge, of doing that within Views natively. We just did that super easily and with very little code.

Other handlers you can extend

  • views_sort_handlers
  • views_argument_handlers
  • views_relationship_handlers
  • So that's how you can extend Views writing your own handlers. There are several other handlers that you can write that I'm not going to cover today. You do it pretty much the same way for each type of handler. Extend an already existing handler within views, and override just the methods that you need to, to customize for your needs.

Subscribe to our YouTube Channel

http://youtube.com/activelamp

  • Thanks for coming to this session
  • Please go to our YouTube channel and subscribe, and share our channel. We're going to be releasing this session as well as other great content over there.

Questions?

Send me an email:

tom@activelamp.com or in IRC #drupal-la
Writing Views Handlers Presented by Tom Friedhof Hello everyone, thanks for coming today to my session on extending Views module.