View source
<?php
namespace Drupal\simplenews\Spool;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\simplenews\recipientHandler\RecipientHandlerManager;
class SpoolStorage implements SpoolStorageInterface {
use MessengerTrait;
use StringTranslationTrait;
protected $connection;
protected $lock;
protected $config;
protected $moduleHandler;
protected $recipientHandlerManager;
public function __construct(Connection $connection, LockBackendInterface $lock, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, RecipientHandlerManager $recipient_handler_manager) {
$this->connection = $connection;
$this->lock = $lock;
$this->config = $config_factory
->get('simplenews.settings');
$this->moduleHandler = $module_handler;
$this->recipientHandlerManager = $recipient_handler_manager;
}
public function getMails($limit = self::UNLIMITED, array $conditions = []) {
$spool_rows = [];
if (!empty($conditions['nid'])) {
$conditions['entity_type'] = 'node';
$conditions['entity_id'] = $conditions['nid'];
unset($conditions['nid']);
}
if (!isset($conditions['status'])) {
$conditions['status'] = [
SpoolStorageInterface::STATUS_PENDING,
SpoolStorageInterface::STATUS_IN_PROGRESS,
];
}
$status_or = new Condition('OR');
$statuses = is_array($conditions['status']) ? $conditions['status'] : [
$conditions['status'],
];
foreach ($statuses as $status) {
if ($status == SpoolStorageInterface::STATUS_IN_PROGRESS) {
$status_or
->condition((new Condition('AND'))
->condition('status', $status)
->condition('s.timestamp', $this
->getExpirationTime(), '<'));
}
else {
$status_or
->condition('status', $status);
}
}
unset($conditions['status']);
$query = $this->connection
->select('simplenews_mail_spool', 's')
->fields('s')
->condition($status_or)
->orderBy('s.timestamp', 'ASC');
foreach ($conditions as $field => $value) {
$query
->condition($field, $value);
}
if ($this->lock
->acquire('simplenews_acquire_mail')) {
if ($limit > 0) {
$query
->range(0, $limit);
}
foreach ($query
->execute() as $spool_row) {
$spool_rows[$spool_row->msid] = $spool_row;
}
if (count($spool_rows) > 0) {
$this
->updateMails(array_keys($spool_rows), SpoolStorageInterface::STATUS_IN_PROGRESS);
}
$this->lock
->release('simplenews_acquire_mail');
}
return $this
->createSpoolList($spool_rows);
}
public function updateMails(array $msids, $status) {
$this->connection
->update('simplenews_mail_spool')
->condition('msid', (array) $msids, 'IN')
->fields([
'status' => $status,
'timestamp' => REQUEST_TIME,
])
->execute();
}
public function countMails(array $conditions = []) {
if (!empty($conditions['nid'])) {
$conditions['entity_type'] = 'node';
$conditions['entity_id'] = $conditions['nid'];
unset($conditions['nid']);
}
if (!isset($conditions['status'])) {
$conditions['status'] = [
SpoolStorageInterface::STATUS_PENDING,
SpoolStorageInterface::STATUS_IN_PROGRESS,
];
}
$query = $this->connection
->select('simplenews_mail_spool');
foreach ($conditions as $field => $value) {
if ($field == 'status') {
if (!is_array($value)) {
$value = [
$value,
];
}
$status_or = new Condition('OR');
foreach ($value as $status) {
$status_or
->condition('status', $status);
}
$query
->condition($status_or);
}
else {
$query
->condition($field, $value);
}
}
$query
->addExpression('COUNT(*)', 'count');
return (int) $query
->execute()
->fetchField();
}
public function clear() {
$expiration_time = REQUEST_TIME - $this->config
->get('mail.spool_expire') * 86400;
return $this->connection
->delete('simplenews_mail_spool')
->condition('status', [
SpoolStorageInterface::STATUS_DONE,
SpoolStorageInterface::STATUS_SKIPPED,
], 'IN')
->condition('timestamp', $expiration_time, '<=')
->execute();
}
public function deleteMails(array $conditions) {
$query = $this->connection
->delete('simplenews_mail_spool');
foreach ($conditions as $condition => $value) {
$query
->condition($condition, $value);
}
return $query
->execute();
}
public function addIssue(ContentEntityInterface $issue) {
if (!in_array($issue->simplenews_issue->status, [
SIMPLENEWS_STATUS_SEND_NOT,
SIMPLENEWS_STATUS_SEND_PUBLISH,
])) {
return;
}
if (!$issue
->isPublished()) {
$issue->simplenews_issue->status = SIMPLENEWS_STATUS_SEND_PUBLISH;
$issue
->save();
$this
->messenger()
->addMessage($this
->t('Newsletter issue %title will be sent when published.', [
'%title' => $issue
->getTitle(),
]));
return;
}
$recipient_handler = $this
->getRecipientHandler($issue);
$issue->simplenews_issue->subscribers = $recipient_handler
->addToSpool();
$issue->simplenews_issue->sent_count = 0;
$issue->simplenews_issue->error_count = 0;
$issue->simplenews_issue->status = SIMPLENEWS_STATUS_SEND_PENDING;
if (!isset($issue->original)) {
$issue
->save();
}
$this->moduleHandler
->invokeAll('simplenews_spooled', [
$issue,
]);
if (\Drupal::service('simplenews.mailer')
->attemptImmediateSend([
'entity_type' => $issue
->getEntityTypeId(),
'entity_id' => $issue
->id(),
])) {
$this
->messenger()
->addMessage($this
->t('Newsletter issue %title sent.', [
'%title' => $issue
->getTitle(),
]));
}
else {
$this
->messenger()
->addMessage($this
->t('Newsletter issue %title pending.', [
'%title' => $issue
->getTitle(),
]));
}
}
public function deleteIssue(ContentEntityInterface $issue) {
if ($issue->simplenews_issue->status != SIMPLENEWS_STATUS_SEND_PENDING) {
return;
}
$count = $this
->deleteMails([
'entity_type' => $issue
->getEntityTypeId(),
'entity_id' => $issue
->id(),
]);
$issue->simplenews_issue->status = SIMPLENEWS_STATUS_SEND_NOT;
$issue
->save();
$this
->messenger()
->addMessage($this
->t('Sending of %title was stopped. @count pending email(s) were deleted.', [
'%title' => $issue
->getTitle(),
'@count' => $count,
]));
}
public function addMail(array $spool) {
if (!isset($spool['status'])) {
$spool['status'] = SpoolStorageInterface::STATUS_PENDING;
}
if (!isset($spool['timestamp'])) {
$spool['timestamp'] = REQUEST_TIME;
}
if (isset($spool['data'])) {
$spool['data'] = serialize($spool['data']);
}
$this->connection
->insert('simplenews_mail_spool')
->fields($spool)
->execute();
}
public function getRecipientHandler(ContentEntityInterface $issue, array $edited_values = NULL, $return_options = FALSE) {
$field = $issue
->get('simplenews_issue');
$newsletter_ids = $field
->isEmpty() ? [] : array_map(function ($i) {
return $i['target_id'];
}, $field
->getValue());
$newsletter_id = $edited_values['target_id'] ?? $newsletter_ids[0] ?? NULL;
$handler = $edited_values['handler'] ?? $field->handler ?: 'simplenews_all';
$options = $this->recipientHandlerManager
->getOptions($newsletter_id);
if (!isset($options[$handler])) {
reset($options);
$handler = key($options);
}
$handler_settings = $edited_values['handler_settings'] ?? $field->handler_settings;
$handler_settings['_issue'] = $issue;
$handler_settings['_connection'] = $this->connection;
$handler_settings['_newsletter_ids'] = $newsletter_ids;
$recipient_handler = $this->recipientHandlerManager
->createInstance($handler, $handler_settings);
return $return_options ? [
$recipient_handler,
$options,
] : $recipient_handler;
}
public function issueSummary(ContentEntityInterface $issue) {
$status = $issue->simplenews_issue->status;
$params['@sent'] = $summary['sent_count'] = (int) $issue->simplenews_issue->sent_count;
$params['@error'] = $summary['error_count'] = (int) $issue->simplenews_issue->error_count;
$params['@count'] = $summary['count'] = (int) $issue->simplenews_issue->subscribers;
if ($status == SIMPLENEWS_STATUS_SEND_READY) {
$summary['description'] = $this
->t('Newsletter issue sent to @sent subscribers, @error errors.', $params);
}
elseif ($status == SIMPLENEWS_STATUS_SEND_PENDING) {
$summary['description'] = $this
->t('Newsletter issue is pending, @sent mails sent out of @count, @error errors.', $params);
}
else {
$params['@count'] = $summary['count'] = $this
->issueCountRecipients($issue);
if ($status == SIMPLENEWS_STATUS_SEND_NOT) {
$summary['description'] = $this
->t('Newsletter issue will be sent to @count subscribers.', $params);
}
else {
$summary['description'] = $this
->t('Newsletter issue will be sent to @count subscribers on publish.', $params);
}
}
return $summary;
}
public function issueCountRecipients(ContentEntityInterface $issue) {
return $this
->getRecipientHandler($issue)
->count();
}
protected function getExpirationTime() {
$timeout = $this->config
->get('mail.spool_progress_expiration');
$expiration_time = REQUEST_TIME - $timeout;
return $expiration_time;
}
protected function createSpoolList(array $spool_rows) {
return new SpoolList($spool_rows, $this);
}
}