Please Note: Drupal 8 is under development as of this writing (12/31/2013), and can and most likely will change further. Your experience may differ from my own!
For the last several weeks now, I’ve been making my way through the new Symfony structure that has been incorporated into Drupal 8. My initial observations were not overwhelmingly positive; as with many OOP-based frameworks, I immediately noticed that the incidents of WSODs (White Screens of Death) increased dramatically.
This is primarily due to an increase in system requirements, namely, PHP. I quickly found that my old(er) releases of Debian / Ubuntu / Fedora were not up to the task of running D8, as they do not necessarily ship with PHP 5.4. That said, I was successful running D8 with PHP 5.3.27-1~dotdeb.0 on Debian Squeeze 7.
Chalk up installation to: Somewhere in Between. Educate yourself before installing D8, and verify that your OS has newer versions of PHP and MySQL installed.
After successfully installing D8, I started poking around a bit. The difference in speed, after the initial cache-building exercise, is unreal. Many will remember waiting on a fresh D7 install with bated breath, hoping against hope that the initial load did not time out. Waiting a full 60 seconds was not unheard of. D8 has fixed this, and fixed it a dramatic fashion. After a scant 15 second initial load time, the Symfony cache was on fire on my local virtual machine. Nearly all operations were instantaneous, unless of course the cache was being rebuilt.
Verdict? Stupendous. At least right now, we can rest assured in knowing that the trend towards ever-slower sites running native Drupal has been reversed.
Ok then, what next? Drupal is renowned for having a module for, well, nearly anything someone would want to do. Since Views is now in Core (yeah!), I began to look for other old standby modules. Normally, the first one I install is admin_menu, since it reduces the number of clicks I need to make to navigate around the backend. I pulled admin_menu down, extracted it in the new directory structure (/var/www/modules rather than /var/www/sites/all/modules – see what they did there?), went to the modules management interface, enabled it, and… BOOM! White Screen of Death. Oh boy.
With contrib modules, one may want to wait until they have been truly converted and tested. This was Scary, as I had a brand-spanking new D8 install and just blew it up. Not one page, mind you, no, not one single page would load. I went to my trusty /var/log/messages and found that admin_menu was conflicting with something, so I needed to uninstall it.
Now, the incorporation of Symfony has many benefits. “yaml” files are a necessary evil, with an emphasis on the “evil”. Just try to uninstall a module in D8 and forget about yaml files and cache. Just try. I found myself grepping through the entire directory structure in order to find all incidents of admin_menu so that I could blow them away. The cache directories under /var/www/sites/default/files/config_xxxxxxxxxxxxxxxxx and /var/www/sites/default/files/php had to be removed, I removed the admin_menu directory from /var/www/modules, and then I browsed to http://localhost/update.php in order to hopefully finish the job. The amount of caching done in D8 is impressive, but this makes it a major pain to recover from a cached incident of WSOD. This entire process was quite Scary, and I admit I ended up moving webroot and recreating it fresh just to get D8 running again, at least at first.
Since I am a backend developer, it was only natural that I next attempted to create a custom module. This is definitely Somewhere in Between, as most of the resources out on the internet address custom modules as they were with earlier releases of D8, and do not necessarily reference correct class names (leading to WSODs, of course).
After analyzing core modules, I built a test module that actually runs, prints out a line, and can be accessed via the Drupal menu system! It sounds simple, but I have quite a few less hairs than I had before, but I digress. Here is my step-by-step process for successfully creating a Drupal 8 module, in the new Drupal fashion.
1. Create your module path. This has changed in D8, so create a new directory under /var/www/modules, called “testmodule”. I have not tested whether Drupal still iterates through directories, but one may roll with the assumption that it does, so the directory could possibly be called /var/www/modules/custom/testmodule.
2. Create an info yaml file, which replaces the old Drupal info file, at testmodule.info.yml:
name: TestModule type: module description: 'initial test module' package: Custom version: 8.x-1.0 core: 8.x dependencies: - node hidden: false
Many of the configuration items should look familiar, but note the change of syntax and formatting (spaces are important!).
3. Build the new “routing” file required by the Symfony controllers:
testmodule: path: 'admin/testmodule' defaults: _content: 'Drupal\testmodule\Controller\TestModuleController::testmodulePage' requirements: _permission: 'access administration pages'
This is one of two places I have discovered so far that identical data must be entered. Much of this looks familiar, and is reproduced again in the traditional module file. This may change, and I would presume that it should become unnecessary to replicate this data in the module file itself; however, I was unsuccessful in rendering a page without both the routing yaml file and the traditional hook_menu return in the module.
4. Create testmodule.module, the ol’ standby:
<?php
function testmodule_menu() { $items['admin/testmodule'] = array( 'title' => 'Test Module', 'description' => 'Demo test module.', 'route_name' => 'testmodule', ); return $items; }
All of this should look pretty familiar, save perhaps the “route_name”, which is passed to the Symfony routing controller.
5. Start creating a plethora of subdirectories. Yes, we know what “plethora” is, and yes, there are a plethora. First, we need a “lib” directory:
/var/www/modules/testmodule/lib
Next, a “Drupal” directory:
/var/www/modules/testmodule/lib/Drupal
Since a module can presumably have lots of things happening in one place, we now need a module-level directory:
/var/www/modules/testmodule/lib/Drupal/testmodule
Now we need to specify that the multiple-things-happening-issue belongs to the Controller specifically:
/var/www/modules/testmodule/lib/Drupal/testmodule/Controller
Finally! I am sure there is a solid explanation as to why a more intuitive directory structure (no more sites/all, for example) was replaced with a four-deep hierarchy within a custom module, but I have not found it yet.
That said, we now get to the meat of the major change in Drupal 8 – the inclusion of more OOP! Many hate it, many love it, but all must agree that it is more scaleable after getting it set up and architected. Much blood has been spilled over the move to OOP in D8, but in the programming world there is one constant, and that constant is “change”. Having coded for over 30 years in a linear, procedural fashion, this is a mindset shift, but a welcome one.
One may continue to program Drupal using the old hooks, creating a hybrid mismash of old-and-new, but I am a fan of jumping in with both feet to see how wet I can get. The Drupal Core team has done a great job of rolling oft-used functionality into Symfony classes, so one cannot even really say that we are forced to go blindly into the OOP yonder; they’ve wrapped things up in nice namespaces for us, we just have to take advantage of them!
So, without further adieu, here’s our new, shiny extended controller named TestModuleController.php:
<?php
namespace Drupal\testmodule\Controller;
use Drupal\Core\Controller\ControllerBase;
class TestModuleController extends ControllerBase {
public function testmodulePage() { return array( '#markup' => t('This is a demo test module.'), ); } }
See how relatively painless that is? The module can now be enabled and browsed to at http://localhost/admin/testmodule
For now, the list of namespaces in Drupal 8 is as follows: https://api.drupal.org/api/drupal/namespace/Drupal%21Core%21Controller/8
Class |
Description |
|
---|---|---|
AjaxController |
Default controller for ajax requests. |
|
ControllerBase |
Utility base class for thin controllers. |
|
ControllerResolver |
ControllerResolver to enhance controllers beyond Symfony's basic handling. |
|
ControllerResolverInterface |
Extends the ControllerResolverInterface from symfony. |
|
DialogController |
Defines a default controller for dialog requests. |
|
ExceptionController |
This controller handles HTTP errors generated by the routing system. |
|
HtmlFormController |
Wrapping controller for forms that serve as the main page body. |
|
HtmlPageController |
Default controller for most HTML pages. |
|
TitleResolver |
Provides the default implementation of the title resolver interface. |
|
TitleResolverInterface |
Defines a class which knows how to generate the title from a given route. |
Overall, I think that Drupal 8 will be a Stupendous improvement, but there will definitely be some growing pains, especially when it comes to documenting all the new Symfony features. Until then, I hope this exercise has proved useful and elucidating – happy coding!