Skip to content

aklump/drupal_feature_switches

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Feature Switches Drupal Module

Summary

Allows you to flag features as ready/not ready and live/not live from a central "switchboard". Based on these switches your codebase can act one way or another.

Install with Composer

  1. Because this is an unpublished package, you must define it's repository in your project's composer.json file. Add the following to composer.json:

    "repositories": [
        {
            "type": "github",
            "url": "https://github.com/aklump/drupal_feature_switches"
        }
    ]
  2. Then composer require aklump_drupal/feature_switches:^0.0

  3. It will be installed to web/modules/custom/feature_switches, which should be excluded from source control.

  4. Enable this module.

  5. See section below about declaring as a Drupal dependency.

How to Define Feature Switches

  1. Create a file in the same directory as settings.php. Call it feature_switches.php.

  2. Add to settings.php, the following. Note: you should add this AFTER $config['system.logging']['error_level'] otherwise you may not see the expected error output, if your features are in error.

    include_once __DIR__ . '/feature_switches.php';
  3. Open feature_switches.php and add one or more features, like this:

\Drupal\feature_switches\FeatureSwitches::getOperator()
  ->add(\Drupal\feature_switches\Feature::create('show_outlines')
    ->setDescription('Add outlines to all images.')
    ->setIsReady(TRUE)
    ->turnOn()
  )
  ->add(\Drupal\feature_switches\Feature::create('user_files_download')
    ->setDescription('Allow users to download their own backups.')
    ->setIsReady(TRUE)
    ->turnOff()
  );

For dynamic switch values--such as those depending on the DI container--you will need to set those switches later in the bootstrap of Drupal, for example inside an event listener.

Enforcing All Live Features are Also Ready

To require that any live feature must also be marked as ready, set the \Drupal\feature_switches\OperatorOptions::REQUIRE_READY_LIVE option. Doing so will cause a \Drupal\feature_switches\FeatureNotReadyException to be thrown if you try to add a feature that is live but not ready.

FeatureSwitches::setOptions(\Drupal\feature_switches\OperatorOptions::REQUIRE_READY_LIVE);

This has to be done before adding features, otherwise no exceptions are thrown.

Setting Switches Inside Event Listeners

If you have a switch that is dependent on the current user having, say, a given role, you will need to wait until that current user is loaded to calculate that value and set the switch since the container is not yet initialized in settings.php when you defined the switch. So to do that, you can listen for the \Symfony\Component\HttpKernel\KernelEvents::REQUEST event, and then set the value accordingly.

It's possible to set a switch anywhere in your code, so this is just a tested suggestion. This event is the earliest point when the user is available, in the Drupal bootstrap.

When you do this you must have a custom module, where you can add the event listener.

And you must declare a dependency on the feature_switches module.

The Event Listener Class

my_module/src/EventSubscriber/MyModuleFeatureSwitches.php

namespace Drupal\my_module\EventSubscriber;

use Drupal\feature_switches\FeatureSwitches;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MyModuleFeatureSwitches implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = [];
    // Best practice; use class_exists().
    // @link https://www.drupal.org/project/drupal/issues/2825358
    if (class_exists(KernelEvents::CLASS)) {
      $events[KernelEvents::REQUEST][] = ['setUserDependentFeatureSwitches', 0];
    }

    return $events;
  }

  /**
   * Respond to a new request event.
   *
   * @param RequestEvent $event
   *   A new event instance.
   */
  public function setUserDependentFeatureSwitches(RequestEvent $event) {
    $early_access = in_array('early_access', \Drupal::currentUser()
      ->getRoles(TRUE));
    FeatureSwitches::get('user_files_download')->setIsLive($early_access);
  }

}

FeatureSwitches::get('bogus')->turnOn() will fail quietly, when bogus is not added. In other words setIsLive() will have no effect. If you call FeatureSwitches::isLive('bogus) it will return FALSE.

Make a Service Class Entry

my_module.services.yml

services:
  my_module.feature_switches:
    class: \Drupal\my_module\EventSubscriber\MyModuleFeatureSwitches
    tags: [ { name: event_subscriber } ]

Declare Module Dependency

my_module.info.yml

dependencies:
  - feature_switches:feature_switches

Using Your Feature Switches

The whole point of this module to is allow your codebase to react differently based on a feature being live or not. Once your features have been created, it's quite simple to check them.

Do Something When the Feature Is Live

if (\Drupal\feature_switches\FeatureSwitches::isLive('user_files_download')) {
  // Proceed with the process...
}

Access the Feature Info

/** @var \Drupal\feature_switches\Feature $foo_feature */
$download_feature = \Drupal\feature_switches\FeatureSwitches::get('download');
$download_feature->getId();
$download_feature->getDescription();

// Note: these two are synonymous.
$download_feature->isReady();
$download_feature->isLive();

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published