← All articles
Data Sync
SharePoint List & Webhook Event Engine
Subscribe to SharePoint list changes with webhooks, trigger Drupal workflows or Power Automate flows, and enable two-way list editing.
Published February 25, 2024
drupalsharepoint-listswebhooksreal-time-syncautomationoffice365power-automate
Overview
The SharePoint List & Webhook Event Engine provides real-time synchronization between Drupal and SharePoint Lists. This integration enables automated workflows triggered by list changes, bi-directional editing capabilities, and seamless data flow between platforms using webhooks and the Microsoft Graph API.
Features
- Real-time webhook subscriptions for list changes
- Bi-directional list editing from Drupal
- Automated workflow triggers
- Power Automate flow integration
- Custom list views in Drupal
- Field mapping and transformation
- Batch operations support
- Conflict resolution and versioning
Technical Details
Technologies: Microsoft Graph API, SharePoint REST API, Webhooks, Drupal Entity API, Drupal Views, Power Automate
Requirements:
- Drupal 9.x or 10.x
- SharePoint Online
- Azure AD app with Sites.ReadWrite.All permission
- Public HTTPS endpoint for webhooks
- Valid SSL certificate
- Drupal Views module
API Endpoints:
Create subscription: POST /sites/{site-id}/lists/{list-id}/subscriptions
List items: GET /sites/{site-id}/lists/{list-id}/items?$expand=fields
Create item: POST /sites/{site-id}/lists/{list-id}/items
Update item: PATCH /sites/{site-id}/lists/{list-id}/items/{item-id}/fields
Implementation
- Configure Azure AD app with SharePoint permissions
- Create Drupal entity type for SharePoint list items
- Implement Graph API client for list operations
- Set up webhook subscription endpoint
- Implement webhook validation and renewal
- Create field mapping configuration
- Build bi-directional sync service
- Implement conflict resolution logic
- Add Views integration for list data
- Configure Power Automate connectors
<?php
// Example: SharePoint webhook subscription manager
namespace Drupal\sharepoint_lists\Service;
use Microsoft\Graph\Graph;
class WebhookSubscriptionManager {
protected $graphClient;
protected $siteId;
public function __construct($graph_client, $config) {
$this->graphClient = $graph_client;
$this->siteId = $config->get('site_id');
}
public function createSubscription($list_id) {
$notification_url = Url::fromRoute(
'sharepoint_lists.webhook',
['list_id' => $list_id],
['absolute' => TRUE]
)->toString();
// Subscription expires in 6 months (max allowed)
$expiration = new \DateTime('+6 months');
$subscription_data = [
'resource' => "/sites/{$this->siteId}/lists/{$list_id}",
'notificationUrl' => $notification_url,
'expirationDateTime' => $expiration->format('Y-m-d\TH:i:s.000\Z'),
'clientState' => bin2hex(random_bytes(16)),
];
try {
$endpoint = "/sites/{$this->siteId}/lists/{$list_id}/subscriptions";
$subscription = $this->graphClient
->createRequest('POST', $endpoint)
->attachBody($subscription_data)
->execute();
// Store subscription details
\Drupal::state()->set(
"sharepoint_lists.subscription.{$list_id}",
[
'id' => $subscription->getId(),
'client_state' => $subscription_data['clientState'],
'expiration' => $subscription->getExpirationDateTime(),
]
);
\Drupal::logger('sharepoint_lists')->info(
'Created webhook subscription for list: @list_id',
['@list_id' => $list_id]
);
return $subscription;
} catch (\Exception $e) {
\Drupal::logger('sharepoint_lists')->error(
'Failed to create webhook subscription: @message',
['@message' => $e->getMessage()]
);
throw $e;
}
}
public function handleWebhookNotification($list_id, $notification) {
// Validate client state
$subscription = \Drupal::state()->get("sharepoint_lists.subscription.{$list_id}");
if ($notification['clientState'] !== $subscription['client_state']) {
throw new \Exception('Invalid client state');
}
// Process changes
foreach ($notification['value'] as $change) {
$this->processChange($list_id, $change);
}
}
protected function processChange($list_id, $change) {
$sync_service = \Drupal::service('sharepoint_lists.sync');
// Fetch the changed item
$item = $this->graphClient
->createRequest('GET', $change['resource'])
->setReturnType(Model\ListItem::class)
->execute();
// Sync to Drupal
$sync_service->syncItemToDrupal($list_id, $item);
}
public function renewSubscription($list_id) {
$subscription = \Drupal::state()->get("sharepoint_lists.subscription.{$list_id}");
$new_expiration = new \DateTime('+6 months');
$endpoint = "/sites/{$this->siteId}/lists/{$list_id}/subscriptions/{$subscription['id']}";
$this->graphClient
->createRequest('PATCH', $endpoint)
->attachBody([
'expirationDateTime' => $new_expiration->format('Y-m-d\TH:i:s.000\Z'),
])
->execute();
}
}
Use Cases
- Inventory management synchronization
- Project tracking and status updates
- Customer data management
- Product catalog synchronization
- Multi-system data consistency
Benefits
- Real-time data synchronization across platforms
- Automated workflow triggers from list changes
- Reduced manual data entry and errors
- Centralized data management in SharePoint
- Powerful Drupal views and reporting
- Integration with Power Automate workflows
- Improved data consistency and reliability