Recently, I had the need to refer back to a custom module I wrote at a previous job years ago and like it tends to do, the code scared me. As far as I know, this module is still chugging along doing its job to this day, and hasn’t had any issues. But for it to work for us at Mediacurrent, it needed some serious refactoring.
It did the job - why change it?
One of the biggest issues in a team environment is making sure your code is maintainable and clean. That means it needs to be readable and make sense to anyone you work with - whether that’s in your own organization or the larger Drupal community itself - a contrib module will be seen and worked on by many different developers around the world.
Community involvement is essential to Drupal and a key factor in distributed teams working together is consistency. Following the same set of coding standards will help everyone focus on the same objectives - not the unimportant details of indentation and whitespace. You’ll want to download the coder module and run against your own module to see what it recommends:
drush coder-review module-name
Use hook_schema and hook_update_N
If your module stores data in the database that isn’t Drupal entities or nodes that need to be served up as content on their own, chances are your module will be needing its own database tables. The thing to do here is to declare the table schema you will need using hook_schema in the module.install file and then it will be created and removed automatically when the module is installed or uninstalled.
If the schema needs to change at any point - adding, removing or modifying columns - it’s easy to implement these changes in an update hook. Using hook_update_N and bumping the version number, the changes can be performed by any other developer who pulls in your code simply by running:
This eliminates a mess of different configurations in a distributed environment.
While we are on the topic of databases, it is also helpful to form queries using Drupal’s db_select, db_update, and db_insert calls. While it’s possible to safely query the database using db_query and using placeholders, this method promotes best practices of not accidentally including strings that haven’t been sanitized, as Drupal does the query building logic for you.
Use what Drupal gives you
Drupal comes with a ton of built-in admin functionality for storing and displaying your module’s data and settings. Module settings pages can be defined with hook_menu and by setting the page_callback to drupal_get_form all you will need to do in the callback function is define and return the settings that need to be stored.
These will be automatically stored in the variable table and that prevents you from storing them yourself and keeps things standardized. A benefit here are that you can also define submit and validate handlers to the form (in case the values need to be integers, or need to be existing data fetched from an API, etc.). These settings can be retrieved and updated using variable_get and variable_set within your module. Additionally, these can also be exported to a feature with the assistance of the strongarm module.
Now that your module has settings screens, you’re going to want to implement some permissions to keep unauthorized users from modifying your settings. Typically, sites may do a check to see if the logged in user is the admin user (user 1) and grant them access. However, to make your module scalable, you’ll want to account for scenarios where a team of admins or content editors will be utilizing it, and implement permission(s) specific to your module(s) needs. Perhaps a simple “administer custom module” will do, or you may want to implement permissions for users who can view data/settings and those who can modify them.
Using hook_permission, you can define one or more permissions that can be assigned to users of different roles in a given site. The permissions that the site admins choose to give can also be exported to features and thus stored in code.
Working with cron
Drupal has built-in cron functionality and a task queue for a reason - it’s something lots of modules need to make use of, so why not use what Drupal already has in place?
There may be a few reasons you might to try to roll your own solution here - maybe your hosting provider doesn’t permit cron tasks to be configured, or maybe there are other issues preventing you from configuring it to run regularly - so, check your site’s status report to be sure.
Your module can implement hook_cron, and integrate its repetitive tasks such as updating content from a third-party, performing reporting, or some other task that needs to occur regularly. This keeps things consistent and gives the benefit of seeing how your module interacts with any other cron tasks that run regularly.