subscriptions-2.0.x-dev/subscriptions_content/subscriptions_content.module
subscriptions_content/subscriptions_content.module
<?php
/**
* @file
* Subscriptions Content Events.
*
* Subscriptions_content extends the Subscriptions module to allow users to
* subscribe by content type. If a user subscribes to a content he will receive
* notifications each time a node is published.
*
* Subscriptions_content also provides the ability to subscribe to comments and
* updates of nodes by content type or by other kinds of subscriptions (defined
* by other Subscriptions submodules).
*/
use Drupal\subscriptions\Event\SubscriptionsEvent;
use Drupal\subscriptions\Event\SubscriptionsEvents;
/**
* Implements hook_form_FORM_ID_alter().
*
* Adds the "Send Subscriptions Notifications" checkbox to the Publishing Options
* fieldset on the node add/edit form.
*
* This also includes a custom form submit
* handler: subscriptions_content_subscriptions_notify_submit(). This will
* validate the node/add and node/edit forms checking if subscriptions should be
* sent.
*
* @param array $form
* @param array $form_state
* @param string $form_id
*
* @ingroup hooks
* @ingroup form
*/
function subscriptions_content_form_node_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
// Make sure the Promotion options section is set on the node form.
if (isset($form['options'])) {
$tr = 't';
// Make sure the option is the last item on the list.
$form['subscriptions_notify'] = [
'#weight' => 50,
'#type' => 'details',
'#tree' => TRUE,
'#group' => 'advanced',
'#title' => 'Notifications',
];
// Add checkbox to the form and set default to TRUE.
$form['subscriptions_notify']['subscriptions_notify'] = [
'#type' => 'checkbox',
'#title' => t('Send subscriptions notifications'),
'#default_value' => (isset($form['#node']->subscriptions_notify) ? $form['#node']->subscriptions_notify : TRUE),
'#attributes' => ['class' => ['subscriptions-notifications']]
];
// Add checkbox description details for educating the user.
$form['subscriptions_notify']['note'] = [
'#type' => 'item',
'#description' => t('You may want to turn %Send_subscriptions_notifications OFF when you only change %Publishing_options, otherwise Subscriptions will send out "update" notifications — this option is not saved.<br />Subscriptions does not send notifications for unpublished nodes (except to users who have the %administer_nodes permission), but when you set %Published to ON, Subscriptions will send out "new" notifications, unless you turn this off here.',
[
'%Send_subscriptions_notifications' => t('Send subscriptions notifications'),
'%Publishing_options' => $tr('Publishing options'),
'%administer_nodes' => $tr('Administer content'),
'%Published' => $tr('Published')
]),
];
// Add custom submit handler for adding/silencing subscription events.
$form['actions']['submit']['#submit'][] = 'subscriptions_content_subscriptions_notify_submit';
}
}
/**
* Node: Submit handler to send or silence a notification event on a node.
*
* Note: If you're looking for how the comments dispatch notifications works.
* You need to look at the following:
* - docroot/cp-elements (cp-comments) webcomponent handles the display of comments and comment form.
* - cp-comments.js handles the comment interactions, data prep, event dispatching.
* - docroot/red_hat_comments/js/injected_comments.js handles the actual api calls.
*
* @param $form
* Form data information.
* @param $form_state
* State of the form when the user saves.
*
*/
function subscriptions_content_subscriptions_notify_submit(array $form, \Drupal\Core\Form\FormStateInterface $form_state) {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $form_state->getFormObject()->getEntity();
// Fetch form field values.
$values = $form_state->getValues();
// Validate if the subscription notify field is being provided.
if (!array_key_exists('subscriptions_notify', $values)){
// Don't send notifications by default.
return;
}
// Check if user wants to send notifications.
if ($values['subscriptions_notify']['subscriptions_notify'] == FALSE) {
// Don't send notifications.
return;
}
// Send notification event, Validation checks will be handled in the
// NotificationsEventSubscriber.php class.
_subscription_content_dispatch_notification_event($entity);
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Handles dispatching delete subscription event(s) on comment and node delete
* forms.
*/
function subscriptions_content_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
// Send subscription event on comment or Node deletes.
if ($form_id == 'comment_page_comment_delete_form' || $form_id == 'node_page_delete_form') {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $form_state->getFormObject()->getEntity();
// Deleting a comment (delete)
$event = new SubscriptionsEvent($entity, 'delete');
\Drupal::service('event_dispatcher')
->dispatch(SubscriptionsEvents::OPERATION_DELETE, $event);
// @todo: As of now this event will be thrown on every request. There is
// no way to prevent this. We may want to expand the subscription notify
// checkbox to this one off form.
}
}
/**
* Implements: hook_ENTITY_TYPE_insert().
*
* When a new comment is created we want to check if a notification should be
* sent out or not.
*
* The notifications configurations are fetched when a user on any platform
* saves the admin/config/system/subscriptions/subscriptions-content. This form
* submits to the /api/comments/notifications/config (comment_api.routing.yml).
*
* @param \Drupal\Core\Entity\EntityInterface $entity
*
* @return void
*/
function subscriptions_content_comment_insert(Drupal\Core\Entity\EntityInterface $entity) {
// Send Subscription Event always. Note: Validation checks are handled in the
// NotificationsEventSubscriber.php class.
_subscription_content_dispatch_notification_event($entity, 'insert');
}
/**
* Implements: hook_ENTITY_TYPE_update().
*
* When a new comment is updated we want to check if a notification should be
* sent out or not.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
*
* @return void
*/
function subscriptions_content_comment_update(Drupal\Core\Entity\EntityInterface $entity) {
// Send Subscription Event always. Note: Validation checks are handled in the
// NotificationsEventSubscriber.php class.
_subscription_content_dispatch_notification_event($entity, 'update');
}
/**
* Validation handling that checks the subscription configuration settings
* against the content type and determine if notifications should be set out.
*
* @param string $content_type
* Form State value for the subscription_notify checkbox.
*
* @param int $nid
* Node id that comments are going on.
*
* @param \stdClass $notifcation_config
* Node object if the data is being set from an API and we need to do some
* special logic.
*
* @return bool
* Returns TRUE if they should be sent out, FALSE if they should NOT be sent.
*/
function _subscriptions_content_notifications_validate_configuration_settings($source_content_type, $source_nid, stdClass $notification_config) {
// Set defaults so they send notifications, unless otherwise.
$is_blocked = FALSE;
$is_unlisted = FALSE;
$is_nid_blocked = FALSE;
// Check for unlisted items.
if (!empty($notification_config->unlisted_content_types)) {
foreach ($notification_config->unlisted_content_types as $type) {
if (!empty($type) && $type == $source_content_type) {
$is_unlisted = TRUE;
}
}
}
// Check for blocked items.
if (!empty($notification_config->blocked_nodes)) {
foreach ($notification_config->blocked_nodes as $type) {
if (!empty($type) && $type == $source_content_type) {
$is_blocked = TRUE;
}
}
}
// Check for blocked nid.
if (!empty($notification_config->blocked_nodes)) {
foreach ($notification_config->blocked_nodes as $blocked_nid) {
if (!empty($blocked_nid->target_id) && $blocked_nid->target_id == $source_nid) {
$is_nid_blocked = TRUE;
}
}
}
// Validate against the unlisted / blocked lists.
if ($is_unlisted || $is_blocked || $is_nid_blocked) {
// Node type is on the unlisted/Blocked list OR the node is blocked.
return FALSE;
}
else {
// Content type is not flagged, send notifications.
return TRUE;
}
}
/**
* Send notifications based on a node insert/update events on node save.
*
* @param object $node
* Node object for this request.
* @param string|null $action
* Used to determine what kind of notification event to send. This is used
* with comments right now.
*
* @return void
* Nothing is returned, but it does send notifications.
*/
function _subscription_content_dispatch_notification_event($node, $action = NULL) {
// Check if content type save is new or an update.
if (empty($action)) {
// Node save triggered this.
$new_content = $node->isNew();
}
else {
// API request sent over an action.
if ($action == 'insert') {
$new_content = TRUE;
}
else if ($action == 'edit') {
$new_content = FALSE;
}
}
// Decide if it is insert or Update.
$operation = $new_content ? SubscriptionsEvents::OPERATION_INSERT : SubscriptionsEvents::OPERATION_UPDATE;
// Send subscription event for insert/update.
$event = new SubscriptionsEvent($node, $operation);
\Drupal::service('event_dispatcher')
->dispatch($operation, $event);
}
