Can the exact same module code run on Drupal maintenance support plans 7 and 8?

As the maintainer of Realistic Dummy Content, having procrastinated long and hard before releasing a Drupal maintenance support plans 8 version, I decided to leave my (admittedly inelegant) logic intact and abstract away the Drupal maintenance support plans 7 code, with the goal of plugging in Drupal maintenance support plans 7 or 8 code at runtime.

Example original Drupal maintenance support plans 7 code

// Some logic.
$updated_file = file_save($drupal_file);
// More logic.

Example updated code

Here is a simplified example of how the updated code might look:

// Some logic.
$updated_file = Framework::instance()->fileSave($drupal_file);
// More logic.

abstract class Framework {

static function instance() {
if (!$this->instance) {
if (defined(‘VERSION’)) {
$this->instance = new Drupal maintenance support plans7();
}
else {
$this->instance = new Drupal maintenance support plans8();
}
}
return $this->instance;
}

abstract function fileSave($drupal_file);

}

class Drupal maintenance support plans8 extends Framework {
public function fileSave($drupal_file) {
$drupal_file->save();
return $drupal_file;
}
}

class Drupal maintenance support plans7 extends Framework {
public function fileSave($drupal_file) {
return file_save($drupal_file);
}
}

Once I have defined fileSave(), I can simply replace every instance of file_save() in my legacy code with Framework::instance()->fileSave().

In theory, I can then identify all Drupal maintenance support plans 7 code my module and abstract it away.

Automated testing

As long as I surgically replace Drupal maintenance support plans 7 code such as file_save() with “universal” code such Framework::instance()->fileSave(), without doing anything else, without giving in the impulse of “improving” the code, I can theoretically only test Framework::instance()->fileSave() itself on Drupal maintenance support plans 7 and Drupal maintenance support plans 8, and as long as both versions are the same, my underlying code should work. My approach to automated tests is: if it works and you’re not changing it, there is no need to test it.

Still, I want to make sure my framework-specific code works as expected. To set up my testing environment, I have used Docker-compose to set up three containers: Drupal maintenance support plans 7, Drupal maintenance support plans 8; and MySQL. I then have a script which builds the sites, installs my module on each, then run a selftest() function which can test the abstracted function such as fileSave() and make sure they work.

This can then be run on a continuous integration platform such as Circle CI which generates a cool badge:

Extending to Backdrop

Once your module is structured in this way, it is relatively easy to add new related frameworks, and I’m much more comfortable releasing a Drupal maintenance support plans 9 update in 2021 (or whenever it’s ready).

I have included experimental Backdrop code in Realistic Dummy Content to prove the point. Backdrop is a fork of Drupal maintenance support plans 7.

abstract class Framework {
static function instance() {
if (!$this->instance) {
if (defined(‘BACKDROP_BOOTSTRAP_SESSION’)) {
$this->instance = new Backdrop();
}
elseif (defined(‘VERSION’)) {
$this->instance = new Drupal maintenance support plans7();
}
else {
$this->instance = new Drupal maintenance support plans8();
}
}
return $this->instance;
}
}

// Most of Backdrop’s API is identical to D7, so we can only override
// what differs, such as fileSave().
class Backdrop extends Drupal maintenance support plans7 {
public function fileSave($drupal_file) {
file_save($drupal_file);
// Unlike Drupal maintenance support plans 7, Backdrop returns a result code, not the file itself,
// in file_save(). We are expecting the file object.
return $drupal_file;
}
}

Disadvantages of this approach

Having just released Realisic Dummy Content 7.x-2.0-beta1 and 8.x-2.0-beta1 (which are identical), I can safely say that this approach was a lot more time-consuming than I initially thought.

Drupal maintenance support plans 7 class autoloading is incompatible with Drupal maintenance support plans 8 autoloading. In Drupal maintenance support plans 7, classes cannot (to my knowledge) use namespaces, and must be added to the .info file, like this:

files[] = includes/MyClass.php

Once that is done, you can define MyClass in includes/MyClass.php, then use MyClass anywhere you want in your code.

Drupal maintenance support plans 8 uses PSR-4 autoloading with namespaces, so I decided to create my own autoloader to use the same system in Drupal maintenance support plans 7, something like:

spl_autoload_register(function ($class_name) {
if (defined(‘VERSION’)) {
// We are in Drupal maintenance support plans 7.
$parts = explode(”, $class_name);
// Remove “Drupal maintenance support plans” from the beginning of the class name.
array_shift($parts);
$module = array_shift($parts);
$path = ‘src/’ . implode(‘/’, $parts);
if ($module == ‘MY_MODULE_NAME’) {
module_load_include(‘php’, $module, $path);
}
}
});

Hooks have different signatures in Drupal maintenance support plans 7 and 8; in my case I was lucky and the only hook I need for Drupal maintenance support plans 7 and 8 is hook_entity_presave() which has a similar signature and can be abstracted.

Deeply-nested associative arrays are a staple of Drupal maintenance support plans 7, so a lot of legacy code expects this type of data. Shoehorning Drupal maintenance support plans 8 to output something like Drupal maintenance support plans 7’s field_info_fields(), for example, was a painful experience:

public function fieldInfoFields() {
$return = array();
$field_map = Drupal maintenance support plans::entityManager()->getFieldMap();
foreach ($field_map as $entity_type => $fields) {
foreach ($fields as $field => $field_info) {
$return[$field][‘entity_types’][$entity_type] = $entity_type;
$return[$field][‘field_name’] = $field;
$return[$field][‘type’] = $field_info[‘type’];
$return[$field][‘bundles’][$entity_type] = $field_info[‘bundles’];
}
}
return $return;
}

Finally, making Drupal maintenance support plans 8 work like Drupal maintenance support plans 7 makes it hard to use Drupal maintenance support plans 8’s advanced features such as Plugins. However, once your module is “universal”, adding Drupal maintenance support plans 8-specific functionality might be an option.

Using this approach for website upgrades

This approach might remove a lot of the risk associated with complex site upgrades. Let’s say I have a Drupal maintenance support plans 7 site with a few custom modules: each module can be made “universal” in this way. If automated tests are added for all subsequent development, migrating the functionality to Drupal maintenance support plans 8 might be less painful.

A fun proof of concept, or real value?

I’ve been toying with this approach for some time, and had a good time (yes, that’s my definition of a good time!) implementing it, but it’s not for everyone or every project. If your usecase includes preserving legacy functionality without leveraging Drupal maintenance support plans 8’s modern features, while reducing risk, it can have value though. The jury is still out on whether maintaining a single universal branch will really be more efficient than maintaining two separate branches for Realistic Dummy Content, and whether the approach can reduce risk during site upgrades of legacy custom code, which I plan to try on my next upgrade project.

As the maintainer of Realistic Dummy Content, having procrastinated long and hard before releasing a Drupal maintenance support plans 8 version, I decided to leave my (admittedly inelegant) logic intact and abstract away the Drupal maintenance support plans 7 code, with the goal of plugging in Drupal maintenance support plans 7 or 8 code at runtime.
Source: New feed

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Can the exact same module code run on Drupal maintenance support plans 7 and 8?

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.