View source
<?php
use Drupal\Core\Database\Database;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
define('SIMPLENEWS_COMMAND_SEND_SCHEDULE', 4);
function simplenews_scheduler_form_simplenews_node_tab_alter(array &$form, FormStateInterface $form_state) {
$user = \Drupal::currentUser();
if (\Drupal::currentUser()
->hasPermission('send scheduled newsletters')) {
$node = $form_state
->get('node');
if (isset($form['send']) && !isset($node->simplenews_scheduler_edition)) {
$scheduler = array();
$record = \Drupal::database()
->select('simplenews_scheduler', 's')
->fields('s')
->condition('nid', $node
->id())
->execute()
->fetchAssoc();
if (!empty($record)) {
$scheduler = $record;
$checked = TRUE;
}
else {
$scheduler['activated'] = 0;
$checked = FALSE;
}
$form_state
->set('scheduler', $scheduler);
$form['scheduler'] = array(
'#type' => 'details',
'#open' => TRUE,
'#title' => t('Scheduled Newsletter'),
);
$form['scheduler']['enable_scheduler'] = array(
'#type' => 'checkbox',
'#title' => t('Enable scheduled newsletter'),
'#default_value' => $checked,
);
if ($checked) {
$form['test']['#open'] = FALSE;
$form['send']['#open'] = FALSE;
}
$start_date = !empty($scheduler['start_date']) ? $scheduler['start_date'] : REQUEST_TIME;
$stop_date = !empty($scheduler['stop_date']) ? $scheduler['stop_date'] : REQUEST_TIME + 2 * 365 * 24 * 60 * 60;
$default_start_date = DrupalDateTime::createFromTimestamp($start_date);
$default_stop_date = DrupalDateTime::createFromTimestamp($stop_date);
$date_format = '';
$time_format = '';
if ($date_format_entity = DateFormat::load('html_date')) {
$date_format = $date_format_entity
->getPattern();
}
if ($time_format_entity = DateFormat::load('html_time')) {
$time_format = $time_format_entity
->getPattern();
}
$site_timezones_url = Url::fromRoute('entity.date_format.collection');
$user_timezones_url = Url::fromRoute('entity.user.edit_form', [
'user' => $user
->id(),
]);
$form['scheduler']['settings'] = array(
'#type' => 'container',
'#states' => array(
'invisible' => array(
':input[name="enable"]' => array(
'checked' => FALSE,
),
),
),
);
$form['scheduler']['settings']['start_date'] = array(
'#type' => 'datetime',
'#title' => t('Start sending on'),
'#default_value' => $default_start_date,
'#required' => TRUE,
'#date_date_format' => $date_format,
'#date_time_format' => $time_format,
'#date_year_range' => '-0:+3',
'#description' => t('Intervals work by creating a new node at the
desired time and marking this to be sent, ensure
you have your @site_link
configured and @user_link
configured.', array(
'@site_link' => Link::fromTextAndUrl(t('site timezones'), $site_timezones_url)
->toString(),
'@user_link' => Link::fromTextAndUrl(t('user timezone'), $user_timezones_url)
->toString(),
)),
);
$intervals = array(
'hour' => t('Hour'),
'day' => t('Day'),
'week' => t('Week'),
'month' => t('Month'),
);
$form['scheduler']['settings']['interval'] = array(
'#type' => 'select',
'#title' => t('Sending interval'),
'#options' => $intervals,
'#description' => t('Interval to send at'),
'#default_value' => !empty($scheduler['send_interval']) ? $scheduler['send_interval'] : 'week',
);
$form['scheduler']['settings']['frequency'] = array(
'#type' => 'textfield',
'#title' => t('Interval frequency'),
'#size' => 5,
'#default_value' => !empty($scheduler['interval_frequency']) ? $scheduler['interval_frequency'] : 1,
'#description' => t('Set the number of Intervals between newsletter transmission.'),
);
$stoptypes = array(
t('Never'),
t('On a given date'),
t('After a maximum number of editions'),
);
$form['scheduler']['settings']['stoptype'] = array(
'#type' => 'radios',
'#title' => t('Stop sending'),
'#options' => $stoptypes,
'#default_value' => !empty($scheduler['stop_type']) ? $scheduler['stop_type'] : 0,
'#attributes' => array(
'class' => array(
'simplenews-command-stop',
),
),
);
$form['scheduler']['settings']['stop_edition'] = array(
'#type' => 'textfield',
'#default_value' => isset($scheduler['stop_edition']) ? $scheduler['stop_edition'] : 0,
'#size' => 5,
'#maxlength' => 5,
'#required' => TRUE,
'#description' => t('The maximum number of editions which should be sent.'),
'#states' => array(
'visible' => array(
':input[name="stoptype"]' => array(
'value' => (string) 2,
),
),
),
);
$form['scheduler']['settings']['stop_date'] = array(
'#type' => 'datetime',
'#title' => t('Stop sending on'),
'#default_value' => $default_stop_date,
'#required' => TRUE,
'#date_date_format' => $date_format,
'#date_time_format' => $time_format,
'#date_year_range' => '-0:+3',
'#description' => t('The date when the last sent newsletter will be sent.'),
'#states' => array(
'visible' => array(
':input[name="stoptype"]' => array(
'value' => (string) 1,
),
),
),
);
$form['scheduler']['settings']['title'] = array(
'#type' => 'textfield',
'#title' => t('Title pattern for new edition nodes'),
'#description' => t('New edition nodes will have their title set to the above string, with tokens replaced.'),
'#required' => TRUE,
'#default_value' => isset($scheduler['title']) ? $scheduler['title'] : '[node:title]',
);
if (\Drupal::moduleHandler()
->moduleExists('token')) {
$form['scheduler']['settings']['token_browser'] = array(
'#theme' => 'token_tree_link',
'#token_types' => array(
'node',
),
);
}
$form['scheduler']['activated'] = array(
'#type' => 'value',
'#value' => $scheduler['activated'],
);
$form['scheduler']['settings']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save scheduler settings'),
'#submit' => array(
'simplenews_scheduler_submit',
),
);
}
elseif (isset($node->simplenews_scheduler_edition)) {
$parent_node = \Drupal::entityTypeManager()
->getStorage('node')
->load($node->simplenews_edition_parent);
$form['scheduler_msg'] = array(
'#markup' => t('This node is part of a scheduled newsletter configuration. View the original newsletter @parent.', array(
'@parent' => Link::fromTextAndUrl(t('here'), $parent_node
->toUrl())
->toString(),
)),
'#weight' => -99,
);
}
}
}
function simplenews_scheduler_submit(array &$form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
$node = $form_state
->get('node');
$nid = $node
->id();
if ($form_state
->getValue('enable_scheduler')) {
$stoptype = $values['stoptype'];
$start_date = strtotime($values['start_date']);
$stop_date = $stoptype == 1 ? strtotime($values['stop_date']) : 0;
$record = array(
'nid' => $nid,
'send_interval' => $values['interval'],
'interval_frequency' => $values['frequency'],
'start_date' => $start_date,
'stop_type' => $stoptype,
'stop_date' => $stop_date,
'stop_edition' => $values['stop_edition'],
'title' => $values['title'],
'activated' => 1,
);
if (!isset($values['next_run'])) {
$record['next_run'] = $start_date;
}
\Drupal::database()
->merge('simplenews_scheduler')
->key(array(
'nid' => $nid,
))
->fields($record)
->execute();
}
else {
\Drupal::database()
->update('simplenews_scheduler')
->condition('nid', $nid)
->fields([
'activated' => 0,
])
->execute();
}
\Drupal::entityTypeManager()
->getStorage('node')
->resetCache([
$node
->id(),
]);
\Drupal::messenger()
->addMessage(t('Newsletter schedule preferences have been saved.'));
}
function simplenews_scheduler_node_storage_load($nodes) {
$nids = array_keys($nodes);
$result = \Drupal::database()
->select('simplenews_scheduler', 's')
->fields('s')
->condition('nid', $nids, 'IN')
->execute()
->fetchAll();
foreach ($result as $record) {
$nodes[$record->nid]->simplenews_scheduler = $record;
}
$result = \Drupal::database()
->select('simplenews_scheduler_editions', 's')
->fields('s')
->condition('eid', $nids, 'IN')
->execute()
->fetchAll();
foreach ($result as $record) {
$nodes[$record->eid]->simplenews_scheduler_edition = $record;
$nodes[$record->eid]->is_edition = TRUE;
$nodes[$record->eid]->simplenews_edition_parent = $record->pid;
}
}
function simplenews_scheduler_node_delete(NodeInterface $node) {
\Drupal::database()
->delete('simplenews_scheduler')
->condition('nid', $node
->id())
->execute();
\Drupal::database()
->delete('simplenews_scheduler_editions')
->condition('eid', $node
->id())
->execute();
}
function simplenews_scheduler_cron() {
$now_time = REQUEST_TIME;
$newsletters_to_send = simplenews_scheduler_get_newsletters_due($now_time);
foreach ($newsletters_to_send as $newsletter_parent_data) {
$edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $now_time);
$eid = _simplenews_scheduler_new_edition($newsletter_parent_data->nid, $edition_time);
simplenews_scheduler_scheduler_update($newsletter_parent_data, $now_time);
_simplenews_scheduler_send_new_edition($edition_time, $newsletter_parent_data, $eid);
}
}
function simplenews_scheduler_scheduler_update($newsletter_parent_data, $now_time) {
$newsletter_parent_data->next_run = simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $now_time);
\Drupal::database()
->merge('simplenews_scheduler')
->key(array(
'nid' => $newsletter_parent_data->nid,
))
->fields(get_object_vars($newsletter_parent_data))
->execute();
}
function simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $now_time) {
$offset_string = _simplenews_scheduler_make_time_offset($newsletter_parent_data->send_interval, $newsletter_parent_data->interval_frequency);
$date_interval = DateInterval::createFromDateString($offset_string);
if ($newsletter_parent_data->last_run) {
$start_date = date('Y-m-d H:i:s', $newsletter_parent_data->last_run);
}
else {
$start_date = date('Y-m-d H:i:s', $newsletter_parent_data->start_date);
}
$pointer_date = new DateTime($start_date);
while ($pointer_date
->getTimestamp() <= $now_time) {
$timestamp_old = $pointer_date
->getTimestamp();
$pointer_date
->add($date_interval);
if ($pointer_date
->getTimestamp() > $now_time) {
return $timestamp_old;
}
}
}
function simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $now_time) {
$offset_string = _simplenews_scheduler_make_time_offset($newsletter_parent_data->send_interval, $newsletter_parent_data->interval_frequency);
$date_interval = DateInterval::createFromDateString($offset_string);
if ($newsletter_parent_data->last_run) {
$start_date = date('Y-m-d H:i:s', $newsletter_parent_data->last_run);
}
else {
$start_date = date('Y-m-d H:i:s', $newsletter_parent_data->start_date);
}
$pointer_date = new DateTime($start_date);
while ($pointer_date
->getTimestamp() <= $now_time) {
$pointer_date
->add($date_interval);
}
return $pointer_date
->getTimestamp();
}
function _simplenews_scheduler_make_time_offset($interval, $frequency) {
$offset_string = "+{$frequency} {$interval}";
return $offset_string;
}
function simplenews_scheduler_get_newsletters_due($timestamp) {
$result = \Drupal::database()
->query("SELECT * FROM {simplenews_scheduler} WHERE activated = 1 AND next_run <= :now AND (stop_date > :now OR stop_date = 0)", array(
':now' => $timestamp,
));
$newsletters = array();
foreach ($result as $newsletter_parent_data) {
$pid = $newsletter_parent_data->nid;
$stop = $newsletter_parent_data->stop_type;
$stop_edition = $newsletter_parent_data->stop_edition;
$edition_count = \Drupal::database()
->query('SELECT COUNT(*) FROM {simplenews_scheduler_editions} WHERE pid = :pid', array(
':pid' => $pid,
))
->fetchField();
if ($stop == 2 && $edition_count >= $stop_edition) {
continue;
}
$newsletters[$pid] = $newsletter_parent_data;
}
return $newsletters;
}
function _simplenews_scheduler_send_new_edition($edition_time, $newsletter_parent_data, $eid) {
$pid = $newsletter_parent_data->nid;
\Drupal::database()
->update('simplenews_scheduler')
->fields(array(
'last_run' => $edition_time,
))
->condition('nid', $pid)
->execute();
$node = \Drupal::entityTypeManager()
->getStorage('node')
->load($eid);
$node
->setPublished();
$node->simplenews_issue->status = SIMPLENEWS_STATUS_SEND_NOT;
\Drupal::service('simplenews.spool_storage')
->addIssue($node);
}
function simplenews_scheduler_clone_node(NodeInterface $node) {
if ($node
->id() > 0) {
$clone = $node
->createDuplicate();
$clone->clone_from_original_nid = $node
->id();
$clone
->save();
return $clone;
}
}
function _simplenews_scheduler_new_edition($nid, $edition_time) {
$template_node = \Drupal::entityTypeManager()
->getStorage('node')
->load($nid);
$edition_node = simplenews_scheduler_clone_node($template_node);
$edition_node->created = $edition_time;
$schedrecord = \Drupal::database()
->select('simplenews_scheduler', 's')
->fields('s')
->condition('nid', $template_node
->id())
->execute()
->fetchAssoc();
$edition_node->title = \Drupal::token()
->replace($schedrecord['title'], array(
'node' => $edition_node,
));
\Drupal::moduleHandler()
->alter('simplenews_scheduler_edition_node', $edition_node, $template_node);
$edition_node
->save();
$values = array(
'eid' => $edition_node
->id(),
'pid' => $template_node
->id(),
'date_issued' => $edition_time,
);
\Drupal::database()
->insert('simplenews_scheduler_editions')
->fields($values)
->execute();
$context = array(
'%title' => $edition_node
->label(),
'link' => Link::fromTextAndUrl(t('view'), $edition_node
->toUrl())
->toString(),
);
\Drupal::logger('simplenews_sched')
->notice('Created a new newsletter edition %title', $context);
return $edition_node
->id();
}