as-cornell / as_webhook_entities
Manage Drupal entities like people records and articles via webhook notifications.
Package info
github.com/as-cornell/as_webhook_entities
Type:drupal-custom-module
pkg:composer/as-cornell/as_webhook_entities
Requires
None
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-07 15:42:04 UTC
README
AS WEBHOOK ENTITIES (as_webhook_entities)
INTRODUCTION
Receives webhook notifications from remote systems and creates, updates, or deletes local Drupal entities (people, articles, taxonomy terms) accordingly. Uses a Strategy pattern with per-type handler classes for maintainability and extensibility.
REQUIREMENTS
System Requirements
- Drupal 9.5+ or Drupal 10+
- PHP 8.0+
INSTALLATION
New Installation
-
Enable the module:
drush en as_webhook_entities -y
-
Configure the module settings:
- Navigate to
/admin/config/as_webhook_entities/settings - Configure the authorization token and whether to process notifications as they arrive
- Navigate to
-
Verify the queue worker is registered:
drush queue:list
You should see
webhook_entities_processorin the list.
Upgrading from 1.x to 2.0
-
Pull the updated code and clear cache:
drush cr
-
Verify the module is functioning:
drush watchdog:show --type=as_webhook_entities --count=10
CONFIGURATION
- Settings UI:
/admin/config/as_webhook_entities/settings - Notifications are queued (
webhook_entities_processor) and the listener answers at once - With "Process notifications as soon as they arrive" on (config key
crontrigger), the queue is drained in batches right after the listener responds, and the batch's nodes are indexed in Search API; seeWebhookQueueDrainer - A drain stops claiming after 40 seconds and, if items remain, posts an empty body to its own listener to start the next one, so nothing waits for cron
- Cron still drains the queue (30 seconds per run), which is the only processing when the setting is off
- Logs create/update/delete operations as
as_webhook_entities
ARCHITECTURE
Strategy Pattern (v2.0+)
Per-type field logic is handled by dedicated handler classes. WebhookCrudManager is a thin dispatcher that handles shared logic (title, status, departments/domain access, save) and delegates to the appropriate handler.
as_webhook_entities/
├── src/
│ ├── WebhookCrudManager.php - Thin dispatcher, shared CRUD logic
│ ├── WebhookUuidLookup.php - Looks up existing entities by UUID
│ ├── WebhookHandler/
│ │ ├── WebhookHandlerInterface.php - applyCreateFields / applyUpdateFields
│ │ ├── WebhookHandlerBase.php - Shared lookup helpers
│ │ ├── PersonWebhookHandler.php
│ │ ├── ArticleWebhookHandler.php
│ │ ├── MediaReportEntryWebhookHandler.php
│ │ ├── MediaReportPersonWebhookHandler.php
│ │ └── TermWebhookHandler.php
│ └── Plugin/QueueWorker/
│ └── WebhookEntitiesQueue.php - Queue processor, event dispatcher
Supported Entity Types
| Payload type | Drupal entity | Handler |
|---|---|---|
person |
node:person |
PersonWebhookHandler |
article |
node:article |
ArticleWebhookHandler |
media_report_entry |
node:media_report_entry |
MediaReportEntryWebhookHandler |
media_report_person |
node:person |
MediaReportPersonWebhookHandler |
term |
taxonomy_term |
TermWebhookHandler |
Adding a New Entity Type
- Create a class in
src/WebhookHandler/extendingWebhookHandlerBase - Implement
getType(),applyCreateFields(), andapplyUpdateFields() - Register it in
WebhookCrudManager::__construct():'my_type' => new MyTypeWebhookHandler($entity_type_manager),
MAINTAINERS
Current maintainers for Drupal 10:
- Mark Wilson (markewilson)
TROUBLESHOOTING
Queue items not processing
-
Check the queue size:
drush queue:list
-
Run the queue manually:
drush queue:run webhook_entities_processor
-
Check recent logs:
drush watchdog:show --type=as_webhook_entities --count=20
Entity not created or updated
-
Verify the UUID lookup is finding the entity:
lando drush php-eval " \$lookup = \Drupal::service('as_webhook_entities.uuid_lookup'); \$entity = \$lookup->findEntity('YOUR-UUID-HERE', 'person'); echo \$entity ? 'Found: ' . \$entity->id() : 'Not found'; "
-
Push a test payload directly into the queue:
lando drush php-eval " \$payload = json_encode([ 'event' => 'create', 'type' => 'person', 'uuid' => 'test-uuid-001', 'status' => '1', 'uid' => '1', 'title' => 'Test Person', 'field_departments_programs' => [], 'field_overview_research' => [], 'field_links' => [], ]); \Drupal::queue('webhook_entities_processor')->createItem(\$payload); echo 'Queued.' . PHP_EOL; " lando drush queue:run webhook_entities_processor
-
Check for field errors — if a field in the payload doesn't exist on the destination bundle, the update will fail. Verify field existence:
lando drush php-eval " \$fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'article'); echo implode(', ', array_keys(\$fields)); "
CHANGELOG
2.0
- Refactored
WebhookCrudManagerusing the Strategy pattern — per-type field logic extracted into dedicated handler classes undersrc/WebhookHandler/ - Added
WebhookHandlerInterfaceandWebhookHandlerBasewith shared entity lookup helpers (lookupTermTidsByName,lookupTermTidsByProperty,lookupNodeNidsByRemoteUuid) - Added handler classes:
PersonWebhookHandler,ArticleWebhookHandler,MediaReportEntryWebhookHandler,MediaReportPersonWebhookHandler,TermWebhookHandler WebhookCrudManageris now a thin dispatcher; shared logic (departments/domain access, node creation, save) remains centralised- Simplified
WebhookUuidLookup::findEntity()to a type-keyed lookup map, eliminating duplicate if blocks - Cleaned up
WebhookEntitiesQueue: removed redundant UUID ternary, extracteddispatchCreate()helper, removed dead code - Fixed two bugs in
MediaReportEntryWebhookHandler:field_news_datewas incorrectly read fromfield_outlet_name, andfield_media_report_public_cathad a variable typo - Moved
field_portrait_image_altout of shared update logic intoArticleWebhookHandlerwhere it belongs