Drupal is a registered trademark of Dries Buytaert
drupal 11.3.7 Update released for Drupal core (11.3.7)! drupal 11.2.11 Update released for Drupal core (11.2.11)! drupal 10.6.7 Update released for Drupal core (10.6.7)! drupal 10.5.9 Update released for Drupal core (10.5.9)! cms 2.1.1 Update released for Drupal core (2.1.1)! drupal 11.3.6 Update released for Drupal core (11.3.6)! drupal 10.6.6 Update released for Drupal core (10.6.6)! cms 2.1.0 Update released for Drupal core (2.1.0)! bootstrap 8.x-3.40 Minor update available for theme bootstrap (8.x-3.40). menu_link_attributes 8.x-1.7 Minor update available for module menu_link_attributes (8.x-1.7). eca 3.1.1 Minor update available for module eca (3.1.1). layout_paragraphs 2.1.3 Minor update available for module layout_paragraphs (2.1.3). ai 1.3.3 Minor update available for module ai (1.3.3). ai 1.2.14 Minor update available for module ai (1.2.14). node_revision_delete 2.0.3 Minor update available for module node_revision_delete (2.0.3). moderated_content_bulk_publish 2.0.52 Minor update available for module moderated_content_bulk_publish (2.0.52). klaro 3.0.10 Minor update available for module klaro (3.0.10). klaro 3.0.9 Minor update available for module klaro (3.0.9). layout_paragraphs 2.1.2 Minor update available for module layout_paragraphs (2.1.2). geofield_map 11.1.8 Minor update available for module geofield_map (11.1.8).

hux

530 sites Security covered
View on drupal.org

Read the blog post: A modern alternative to Hooks

Hux is a project specifically designed for developers, allowing hook implementations without needing to define a .module file or any kind of proxy class/service features.

There are a few projects out there that try to introduce an event subscriber driven way of working. Hux is an in between solution, allowing the full benefits of dependency injection and class driven logic without going fully in with events.

Hooks are implemented with classes, wherein methods tagged with attributes are used for discovery. Methods have the same parameter/return signature as original hook implementations. Discovery is automatic, requiring a cache clear for each new class added.

You can also define multiple of the same hook per module!

Requires Drupal 9.4 or later, and PHP 8.0 or later. (Drupal 9.3 users may use a patch in #2616814: Delegate all hook invocations to ModuleHandler)

Usage Examples (See README.md for more)


declare(strict_types = 1);

namespace Drupal\my_module;

use Drupal\hux\Attribute\Alter;
use Drupal\hux\Attribute\Hook;
use Drupal\hux\Attribute\ReplaceOriginalHook;

/**
 * Usage examples.
 */
final class MyModuleHooks {

  public function __construct(
    // Autowiring is enabled.
    // \Drupal\Core\DependencyInjection\ContainerInjectionInterface, or manual service definitions are available for older Drupal installs or usage of non-autowirable services.
    private readonly \Drupal\Component\Datetime\TimeInterface $time,
  )

  #[Hook('entity_access')]
  public function myEntityAccess(EntityInterface $entity, string $operation, AccountInterface $account): AccessResultInterface {
    // A barebones implementation.
    return AccessResult::neutral();
  }

  #[Hook('entity_access', priority: 100)]
  public function myEntityAccess2(EntityInterface $entity, string $operation, AccountInterface $account): AccessResultInterface {
    // You can set priority if you have multiple of the same hook!
    return AccessResult::neutral();
  }

  #[Hook('entity_access', moduleName: 'a_different_module', priority: 200)]
  public function myEntityAccess3(EntityInterface $entity, string $operation, AccountInterface $account): AccessResultInterface {
    // You can masquerade as a different module!
    return AccessResult::neutral();
  }

  #[ReplaceOriginalHook(hook: 'entity_access', moduleName: 'media')]
  public function myEntityAccess4(EntityInterface $entity, string $operation, AccountInterface $account): AccessResultInterface {
    // You can override hooks for other modules! E.g \media_entity_access()
    return AccessResult::neutral();
  }


  #[ReplaceOriginalHook(hook: 'entity_access', moduleName: 'media')]
  public function myEntityAccess5(EntityInterface $entity, string $operation, AccountInterface $account, #[OriginalInvoker] callable $originalInvoker): AccessResultInterface {
    // If you override a hook for another module, you can have the original
    // implementation passed to you as a callable!
    $originalResult = $originalInvoker($entity, $operation, $account);
    // Do something...
    return AccessResult::neutral();
  }

  #[Alter('user_format_name')]
  public function myCustomAlter(string &$name, AccountInterface $account): void {
    $name .= ' altered!'; 
  }

  #[
    Hook('entity_insert'),
    Hook('entity_delete'),
  ]
  public function myEntityInsertOrDelete(EntityInterface $entity): void {
    // Associate with multiple!
    // Also works with Alters and Replacements.
  }

}

Contribution tips

Only Merge Requests are accepted. Patches are not accepted.

Tests use a customized Gitlab template with custom PHP Code Sniffer and PHPStan ruleset. You can fix these issues by running linting locally or wait for errors after pushing your work to an MR.

Similar projects

Versions

  • 1.1.x is compatible with Drupal 9 and 10.
  • 1.2.x, Drupal ^10.0
  • 1.3.x, Drupal ^10.1
  • 1.4.x, Drupal ^10.2
  • 1.5.x, Drupal ^10.3
  • 1.6.x, Drupal ^10.3 || ^11
  • 1.7.x, Drupal 11.0 minimum
  • 1.8.x, Drupal 11.1 minimum

Actual constraints may vary. Older incompatible releases may match an untested version of core.

Activity

Total releases
5
First release
Jan 2025
Latest release
11 months ago
Release cadence
26 days
Stability
80% stable

Release Timeline

Releases

Version Type Release date
1.6.1 Stable May 15, 2025
1.7.1 Stable May 15, 2025
1.8.1 Stable May 15, 2025
1.8.0 Stable Jan 31, 2025
1.8.x-dev Dev Jan 31, 2025