module builder

Regenerating plugin dependency injection with Module Builder

Dependency injection is a pattern that adds a lot of boilerplate code, but Drupal Code Builder makes it easy to add injected services to plugins, forms, and service classes.

Now that the Drupal 8 version of Module Builder (the Drupal front-end to the Drupal Code Builder library) uses an autocomplete for service names in the edit form, adding injected services is even easier, and any of the hundreds of services in your site’s codebase (443 on my local sandbox Drupal 8 site!) can be injected.

I often used this when I want to add a service to an existing plugin: re-generate the code, and copy-paste the new code I need.

This is an area in which Module Builder now outshines its Drush counterpart, because unlike the Drush front end for Drupal Code Builder, which generates code with input parameters every time, Module Builder lets you save your settings for the generated module (as a config entity).

So you can return to the plugin you generated to start with, add an extra service to it, and generate the code again. You can copy and paste, or have Module Builder write the file and then use git to revert custom code it’s removed. (The ability to insert generated code into existing files is on my list of desirable features, but is realistically a long way off, as it would be rather complex, a require the addition of a code parsing library.)

But why stop at generating code for your own modules? I recently filed an issue on Search API, suggesting that its plugins could do with tweaking to follow the standard core pattern of a static factory method and constructor, rather than rely on setters for injection. It’s not a complex change, but a lot of code churn. Then it occurred to me: Drupal Code Builder can generate that boilerplate code: simply create a module in Module Builder called ‘search_api’, and then add a plugin with the name of one that is already in Search API, and then set its injected services to the services the real plugin needs.

Drupal Code Builder already knows how to build a Search API plugin: its code analysis detects the right plugin base class and annotation to use, and also any parameters that the constructor method should pass up to the base class.

So it’s pretty quick to copy the plugin name and service names from Search API’s plugin class to the form in Module Builder, and then save and generate the code, and then copy the generated factory methods back to Search API to make a patch.

I’m now rather glad I decided to use config entities for generated entities. Originally, I did that just because it was a quick and convenient way to get storage for serialized data (and since then I discovered in other work that map fields are broken in D8 so I’m very glad I didn’t try to make then content entities!). But the ability to save the generating settings for a module, and then return to it to add to them has proved very useful.

Never Write A Line Of Code Again!

Okay, so I lied. But module builder can save you a lot of time when writing custom modules.

And it now works with drush, too. I added support for drush a few weeks ago, which let you do things like "$ drush mb mymodule cron init menu nodeapi --write" and hey presto, a new module folder is created, with an info file and a module file, with hook implementations ready to do your (evil) bidding. (Note: this blog does not sanction use of Drupal, module builder, or drush for evil.)

If you're super lazy you can even say "$ drush mb mymodule cron init menu nodeapi --go", using the wash 'n' go option which writes all the files and enables the new module for you. But don't do this if you're writing an install or enable hook, as they won't have any code in them!

The downside was that you needed to install module builder into each Drupal installation you wanted to generate modules for. Bit of a pain if you're developing a few sites and have a few more test sites kicking around.

But no more! You can now stick the module builder folder wherever drush can find it, and build modules in any Drupal 6 installation. You can download hook data to that installation with "$drush mbdl", or store it in a central location by specifying the --data option.

You might say at this point, core hooks are all very good, but what about hooks for CCK, Views, Ubercart, and so on? Well, like all good modules, module builder comes with a hook. Implement hook_module_builder_info, tell it where you hook documentation can be found on the interwebs, and add your module's distinctiveness to module builder's sugary goodness.

And how might you do this?

drush mb foo module_builder_info

With module builder, of course!

Subscribe to RSS - module builder