Those methods were deprecated over six months ago and can now be removed. They are assoacited with the NewsletterOption model which was removed in the previous commit. deprecationError() is also removed as PHPStan was complaining that it is not used anymore. [MAILPOET-5762]
351 lines
10 KiB
PHP
351 lines
10 KiB
PHP
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
|
|
|
namespace MailPoet\Models;
|
|
|
|
use MailPoet\DI\ContainerWrapper;
|
|
use MailPoet\Entities\NewsletterEntity;
|
|
use MailPoet\Newsletter\NewslettersRepository;
|
|
use MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository;
|
|
use MailPoet\Settings\SettingsController;
|
|
use MailPoet\Tasks\Sending as SendingTask;
|
|
use MailPoet\Util\Helpers;
|
|
use MailPoet\Util\Security;
|
|
|
|
/**
|
|
* @property int $id
|
|
* @property int $parentId
|
|
* @property string $type
|
|
* @property object|array|bool $queue
|
|
* @property string $hash
|
|
* @property string $senderName
|
|
* @property string $senderAddress
|
|
* @property string $replyToName
|
|
* @property string $replyToAddress
|
|
* @property string $status
|
|
* @property string|object $meta
|
|
* @property array $options
|
|
* @property bool|array $statistics
|
|
* @property string $sentAt
|
|
* @property string $deletedAt
|
|
* @property int $totalSent
|
|
* @property int $totalScheduled
|
|
* @property array $segments
|
|
* @property string $subject
|
|
* @property string $preheader
|
|
* @property string|array|null $body
|
|
* @property string|null $schedule
|
|
* @property bool|null $isScheduled
|
|
* @property string|null $scheduledAt
|
|
* @property string $gaCampaign
|
|
* @property string $event
|
|
* @property string $unsubscribeToken
|
|
*/
|
|
|
|
class Newsletter extends Model {
|
|
public static $_table = MP_NEWSLETTERS_TABLE; // phpcs:ignore PSR2.Classes.PropertyDeclaration
|
|
const TYPE_AUTOMATIC = NewsletterEntity::TYPE_AUTOMATIC;
|
|
const TYPE_AUTOMATION = NewsletterEntity::TYPE_AUTOMATION;
|
|
const TYPE_AUTOMATION_TRANSACTIONAL = NewsletterEntity::TYPE_AUTOMATION_TRANSACTIONAL;
|
|
const TYPE_STANDARD = NewsletterEntity::TYPE_STANDARD;
|
|
const TYPE_WELCOME = NewsletterEntity::TYPE_WELCOME;
|
|
const TYPE_NOTIFICATION = NewsletterEntity::TYPE_NOTIFICATION;
|
|
const TYPE_AUTOMATION_NOTIFICATION = NewsletterEntity::TYPE_AUTOMATION_NOTIFICATION;
|
|
const TYPE_NOTIFICATION_HISTORY = NewsletterEntity::TYPE_NOTIFICATION_HISTORY;
|
|
const TYPE_WC_TRANSACTIONAL_EMAIL = NewsletterEntity::TYPE_WC_TRANSACTIONAL_EMAIL;
|
|
const TYPE_RE_ENGAGEMENT = NewsletterEntity::TYPE_RE_ENGAGEMENT;
|
|
// standard newsletters
|
|
const STATUS_DRAFT = NewsletterEntity::STATUS_DRAFT;
|
|
const STATUS_SCHEDULED = NewsletterEntity::STATUS_SCHEDULED;
|
|
const STATUS_SENDING = NewsletterEntity::STATUS_SENDING;
|
|
const STATUS_SENT = NewsletterEntity::STATUS_SENT;
|
|
// automatic newsletters status
|
|
const STATUS_ACTIVE = NewsletterEntity::STATUS_ACTIVE;
|
|
|
|
public function __construct() {
|
|
parent::__construct();
|
|
$this->addValidations('type', [
|
|
'required' => __('Please specify a type.', 'mailpoet'),
|
|
]);
|
|
}
|
|
|
|
public function queue() {
|
|
return $this->hasOne(__NAMESPACE__ . '\SendingQueue', 'newsletter_id', 'id');
|
|
}
|
|
|
|
public function children() {
|
|
return $this->hasMany(
|
|
__NAMESPACE__ . '\Newsletter',
|
|
'parent_id',
|
|
'id'
|
|
);
|
|
}
|
|
|
|
public function parent() {
|
|
return $this->hasOne(
|
|
__NAMESPACE__ . '\Newsletter',
|
|
'id',
|
|
'parent_id'
|
|
);
|
|
}
|
|
|
|
public function segments() {
|
|
return $this->hasManyThrough(
|
|
__NAMESPACE__ . '\Segment',
|
|
__NAMESPACE__ . '\NewsletterSegment',
|
|
'newsletter_id',
|
|
'segment_id'
|
|
);
|
|
}
|
|
|
|
public function segmentRelations() {
|
|
return $this->hasMany(
|
|
__NAMESPACE__ . '\NewsletterSegment',
|
|
'newsletter_id',
|
|
'id'
|
|
);
|
|
}
|
|
|
|
public function save() {
|
|
if (is_string($this->deletedAt) && strlen(trim($this->deletedAt)) === 0) {
|
|
$this->set_expr('deleted_at', 'NULL');
|
|
}
|
|
|
|
if (isset($this->body) && ($this->body !== false)) {
|
|
$this->body = $this->getBodyString();
|
|
$this->set(
|
|
'body',
|
|
$this->body
|
|
);
|
|
}
|
|
|
|
$this->set('hash',
|
|
($this->hash)
|
|
? $this->hash
|
|
: Security::generateHash()
|
|
);
|
|
return parent::save();
|
|
}
|
|
|
|
public function trash() {
|
|
$this->save();
|
|
trigger_error('Calling Newsletter::trash() is deprecated and will be removed. Use \MailPoet\Newsletter\NewslettersRepository instead.', E_USER_DEPRECATED);
|
|
ContainerWrapper::getInstance()->get(NewslettersRepository::class)->bulkTrash([$this->id]);
|
|
return $this;
|
|
}
|
|
|
|
public function restore() {
|
|
$this->save();
|
|
trigger_error('Calling Newsletter::restore() is deprecated and will be removed. Use \MailPoet\Newsletter\NewslettersRepository instead.', E_USER_DEPRECATED);
|
|
ContainerWrapper::getInstance()->get(NewslettersRepository::class)->bulkRestore([$this->id]);
|
|
return $this;
|
|
}
|
|
|
|
public function delete() {
|
|
trigger_error('Calling Newsletter::delete() is deprecated and will be removed. Use \MailPoet\Newsletter\NewslettersRepository instead.', E_USER_DEPRECATED);
|
|
ContainerWrapper::getInstance()->get(NewslettersRepository::class)->bulkDelete([$this->id]);
|
|
return null;
|
|
}
|
|
|
|
public function setStatus($status = null) {
|
|
if ($status === self::STATUS_ACTIVE) {
|
|
if (!$this->body || empty(json_decode($this->getBodyString()))) {
|
|
$this->setError(
|
|
Helpers::replaceLinkTags(
|
|
__('This is an empty email without any content and it cannot be sent. Please update [link]the email[/link].', 'mailpoet'),
|
|
'admin.php?page=mailpoet-newsletter-editor&id=' . $this->id
|
|
)
|
|
);
|
|
return $this;
|
|
}
|
|
}
|
|
if (
|
|
in_array($status, [
|
|
self::STATUS_DRAFT,
|
|
self::STATUS_SCHEDULED,
|
|
self::STATUS_SENDING,
|
|
self::STATUS_SENT,
|
|
self::STATUS_ACTIVE,
|
|
])
|
|
) {
|
|
$this->set('status', $status);
|
|
$this->save();
|
|
}
|
|
|
|
$typesWithActivation = [self::TYPE_NOTIFICATION, self::TYPE_WELCOME, self::TYPE_AUTOMATIC];
|
|
|
|
if (($status === self::STATUS_DRAFT) && in_array($this->type, $typesWithActivation)) {
|
|
ScheduledTask::pauseAllByNewsletter($this);
|
|
}
|
|
if (($status === self::STATUS_ACTIVE) && in_array($this->type, $typesWithActivation)) {
|
|
ScheduledTask::setScheduledAllByNewsletter($this);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
public function asArray() {
|
|
$model = parent::asArray();
|
|
|
|
if (isset($model['body'])) {
|
|
$model['body'] = json_decode($model['body'], true);
|
|
}
|
|
return $model;
|
|
}
|
|
|
|
public function withSegments($inclDeleted = false) {
|
|
$this->segments = $this->segments()->findArray();
|
|
if ($inclDeleted) {
|
|
$this->withDeletedSegments();
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
public function withDeletedSegments() {
|
|
if (!empty($this->segments)) {
|
|
$segmentIds = array_column($this->segments, 'id');
|
|
$links = $this->segmentRelations()
|
|
->whereNotIn('segment_id', $segmentIds)->findArray();
|
|
$deletedSegments = [];
|
|
|
|
foreach ($links as $link) {
|
|
$deletedSegments[] = [
|
|
'id' => $link['segment_id'],
|
|
'name' => __('Deleted list', 'mailpoet'),
|
|
];
|
|
}
|
|
$this->segments = array_merge($this->segments, $deletedSegments);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getQueue($columns = '*') {
|
|
return SendingTask::getByNewsletterId($this->id);
|
|
}
|
|
|
|
public function getBodyString(): string {
|
|
if (is_array($this->body)) {
|
|
return (string)json_encode($this->body);
|
|
}
|
|
if ($this->body === null) {
|
|
return '';
|
|
}
|
|
return $this->body;
|
|
}
|
|
|
|
public function withSendingQueue() {
|
|
$queue = $this->getQueue();
|
|
if ($queue === false) {
|
|
$this->queue = false;
|
|
} else {
|
|
$this->queue = $queue->asArray();
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
public static function filterWithOptions($orm, $type) {
|
|
$orm = $orm->select(MP_NEWSLETTERS_TABLE . '.*');
|
|
$optionFieldsRepository = ContainerWrapper::getInstance()->get(NewsletterOptionFieldsRepository::class);
|
|
$optionFieldsEntities = $optionFieldsRepository->findAll();
|
|
foreach ($optionFieldsEntities as $optionField) {
|
|
if ($optionField->getNewsletterType() !== $type) {
|
|
continue;
|
|
}
|
|
$orm = $orm->select_expr(
|
|
'IFNULL(GROUP_CONCAT(CASE WHEN ' .
|
|
MP_NEWSLETTER_OPTION_FIELDS_TABLE . '.id=' . $optionField->getId() . ' THEN ' .
|
|
MP_NEWSLETTER_OPTION_TABLE . '.value END), NULL) as "' . $optionField->getName() . '"');
|
|
}
|
|
$orm = $orm
|
|
->left_outer_join(
|
|
MP_NEWSLETTER_OPTION_TABLE,
|
|
[
|
|
MP_NEWSLETTERS_TABLE . '.id',
|
|
'=',
|
|
MP_NEWSLETTER_OPTION_TABLE . '.newsletter_id',
|
|
]
|
|
)
|
|
->left_outer_join(
|
|
MP_NEWSLETTER_OPTION_FIELDS_TABLE,
|
|
[
|
|
MP_NEWSLETTER_OPTION_FIELDS_TABLE . '.id',
|
|
'=',
|
|
MP_NEWSLETTER_OPTION_TABLE . '.option_field_id',
|
|
]
|
|
)
|
|
->group_by(MP_NEWSLETTERS_TABLE . '.id');
|
|
return $orm;
|
|
}
|
|
|
|
public static function filterStatus($orm, $status = false) {
|
|
if (
|
|
in_array($status, [
|
|
self::STATUS_DRAFT,
|
|
self::STATUS_SCHEDULED,
|
|
self::STATUS_SENDING,
|
|
self::STATUS_SENT,
|
|
self::STATUS_ACTIVE,
|
|
])
|
|
) {
|
|
$orm->where('status', $status);
|
|
}
|
|
return $orm;
|
|
}
|
|
|
|
public static function createOrUpdate($data = []) {
|
|
$data['unsubscribe_token'] = Security::generateUnsubscribeToken(self::class);
|
|
return parent::_createOrUpdate($data, false, function($data) {
|
|
$settings = SettingsController::getInstance();
|
|
// set default sender based on settings
|
|
if (empty($data['sender'])) {
|
|
$sender = $settings->get('sender', []);
|
|
$data['sender_name'] = (
|
|
!empty($sender['name'])
|
|
? $sender['name']
|
|
: ''
|
|
);
|
|
$data['sender_address'] = (
|
|
!empty($sender['address'])
|
|
? $sender['address']
|
|
: ''
|
|
);
|
|
}
|
|
|
|
// set default reply_to based on settings
|
|
if (empty($data['reply_to'])) {
|
|
$replyTo = $settings->get('reply_to', []);
|
|
$data['reply_to_name'] = (
|
|
!empty($replyTo['name'])
|
|
? $replyTo['name']
|
|
: ''
|
|
);
|
|
$data['reply_to_address'] = (
|
|
!empty($replyTo['address'])
|
|
? $replyTo['address']
|
|
: ''
|
|
);
|
|
}
|
|
|
|
return $data;
|
|
});
|
|
}
|
|
|
|
public static function getByHash($hash) {
|
|
return parent::where('hash', $hash)
|
|
->findOne();
|
|
}
|
|
|
|
public function getMeta() {
|
|
if (!$this->meta) return;
|
|
|
|
return (Helpers::isJson($this->meta) && is_string($this->meta)) ? json_decode($this->meta, true) : $this->meta;
|
|
}
|
|
|
|
public static function findOneWithOptions($id) {
|
|
$newsletter = self::findOne($id);
|
|
if (!$newsletter instanceof self) {
|
|
return false;
|
|
}
|
|
return self::filter('filterWithOptions', $newsletter->type)->findOne($id);
|
|
}
|
|
}
|