Skip to main content
Drupal is a registered trademark of Dries Buytaert
Release: OpenID Connect / OAuth client 3.0.0-alpha9 New alpha version released for module openid_connect (3.0.0-alpha9). Release: Opensolr Search 4.5.0 Minor update available for module opensolr_search (4.5.0). Release: Timelinr 1.0.1 Minor update available for module timelinr (1.0.1). Usage Milestone: Simplify Module simplify crossed 10,000 active installs. Usage Milestone: Views Reference Filter Module entityreference_filter crossed 10,000 active installs. Usage Milestone: Dropdown Language Module dropdown_language crossed 10,000 active installs. Usage Milestone: Paragraphs Browser Module paragraphs_browser crossed 10,000 active installs. Usage Milestone: OpenAPI Module openapi crossed 10,000 active installs. Usage Milestone: Decoupled Router Module decoupled_router crossed 10,000 active installs. Module Revived: Entityqueue Buttons 1.1.2 Module entityqueue_buttons updated after 8 months of inactivity (1.1.2).

Hux

653 sites Security covered Drupal 10–11
View on drupal.org

Hux allows developers to implement Drupal hooks using classes and methods tagged with attributes, eliminating the need for .module files. This approach provides the benefits of dependency injection and class-driven logic for hook implementations, and allows for multiple implementations of the same hook.

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.

Depends on

Dependencies of the latest stable release

No dependencies recorded for this project.

Required by

1 tracked project depends on this one

Activity

Tracked releases
5
Tracked since
Jan 2025
Latest release
1 year ago
Releases (12 mo)
0 ▼ from 5
Maintenance
Dormant

Release Timeline

Releases

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