710 lines
21 KiB
PHP
710 lines
21 KiB
PHP
|
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||
|
|
||
|
namespace MailPoet\Models;
|
||
|
|
||
|
if (!defined('ABSPATH')) exit;
|
||
|
|
||
|
|
||
|
use MailPoet\DI\ContainerWrapper;
|
||
|
use MailPoet\Settings\SettingsController;
|
||
|
use MailPoet\Util\Helpers;
|
||
|
use MailPoet\Util\Security;
|
||
|
use MailPoet\WP\Functions as WPFunctions;
|
||
|
|
||
|
/**
|
||
|
* @property int $id
|
||
|
* @property string $email
|
||
|
* @property string $firstName
|
||
|
* @property string $lastName
|
||
|
* @property string $status
|
||
|
* @property string|null $subscribedIp
|
||
|
* @property string|null $confirmedIp
|
||
|
* @property string|null $confirmedAt
|
||
|
* @property string|null $lastSubscribedAt
|
||
|
* @property string|null $deletedAt
|
||
|
* @property string|null $source
|
||
|
* @property string|null $linkToken
|
||
|
* @property int $countConfirmations
|
||
|
* @property int $wpUserId
|
||
|
* @property array $segments
|
||
|
* @property array $subscriptions
|
||
|
* @property string|null $unconfirmedData
|
||
|
* @property int $isWoocommerceUser
|
||
|
*/
|
||
|
|
||
|
class Subscriber extends Model {
|
||
|
public static $_table = MP_SUBSCRIBERS_TABLE; // phpcs:ignore PSR2.Classes.PropertyDeclaration
|
||
|
|
||
|
const STATUS_SUBSCRIBED = 'subscribed';
|
||
|
const STATUS_UNSUBSCRIBED = 'unsubscribed';
|
||
|
const STATUS_UNCONFIRMED = 'unconfirmed';
|
||
|
const STATUS_BOUNCED = 'bounced';
|
||
|
const STATUS_INACTIVE = 'inactive';
|
||
|
|
||
|
const OBSOLETE_LINK_TOKEN_LENGTH = 6;
|
||
|
const LINK_TOKEN_LENGTH = 32;
|
||
|
|
||
|
/** @var string|bool */
|
||
|
public $token;
|
||
|
|
||
|
public function __construct() {
|
||
|
parent::__construct();
|
||
|
|
||
|
$this->addValidations('email', [
|
||
|
'required' => __('Please enter your email address', 'mailpoet'),
|
||
|
'validEmail' => __('Your email address is invalid!', 'mailpoet'),
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
public static function findOne($id = false) {
|
||
|
if (is_int($id) || (string)(int)$id === $id) {
|
||
|
return parent::findOne($id);
|
||
|
} else if (strlen(trim((string)$id)) > 0) {
|
||
|
return parent::where('email', $id)->findOne();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public function segments() {
|
||
|
return $this->has_many_through(
|
||
|
__NAMESPACE__ . '\Segment',
|
||
|
__NAMESPACE__ . '\SubscriberSegment',
|
||
|
'subscriber_id',
|
||
|
'segment_id'
|
||
|
)
|
||
|
->where(MP_SUBSCRIBER_SEGMENT_TABLE . '.status', self::STATUS_SUBSCRIBED);
|
||
|
}
|
||
|
|
||
|
public function save() {
|
||
|
// convert email to lowercase format
|
||
|
$this->email = strtolower((string)$this->email);
|
||
|
return parent::save();
|
||
|
}
|
||
|
|
||
|
public function delete() {
|
||
|
// WP Users cannot be deleted
|
||
|
if (!$this->isWPUser() && !$this->isWooCommerceUser()) {
|
||
|
// delete all relations to segments
|
||
|
SubscriberSegment::deleteSubscriptions($this);
|
||
|
// delete all relations to custom fields
|
||
|
SubscriberCustomField::deleteSubscriberRelations($this);
|
||
|
return parent::delete();
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public function trash() {
|
||
|
// WP Users cannot be trashed
|
||
|
if ($this->isWPUser() || $this->isWooCommerceUser()) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return parent::trash();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function isWPUser() {
|
||
|
return (bool)$this->wpUserId;
|
||
|
}
|
||
|
|
||
|
public function isWooCommerceUser() {
|
||
|
return (bool)$this->isWoocommerceUser;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated Use the version in \MailPoet\Subscribers\SubscribersRepository::getCurrentWPUser
|
||
|
*/
|
||
|
public static function getCurrentWPUser() {
|
||
|
trigger_error('Calling Subscriber::getCurrentWPUser() is deprecated and will be removed. Use MailPoet\Subscribers\SubscribersRepository::getCurrentWPUser(). ', E_USER_DEPRECATED);
|
||
|
$wpUser = WPFunctions::get()->wpGetCurrentUser();
|
||
|
if (empty($wpUser->ID)) {
|
||
|
return false; // Don't look up a subscriber for guests
|
||
|
}
|
||
|
return self::where('wp_user_id', $wpUser->ID)->findOne();
|
||
|
}
|
||
|
|
||
|
public static function filterOutReservedColumns(array $subscriberData) {
|
||
|
$reservedColumns = [
|
||
|
'id',
|
||
|
'wp_user_id',
|
||
|
'is_woocommerce_user',
|
||
|
'status',
|
||
|
'subscribed_ip',
|
||
|
'confirmed_ip',
|
||
|
'confirmed_at',
|
||
|
'created_at',
|
||
|
'updated_at',
|
||
|
'deleted_at',
|
||
|
'unconfirmed_data',
|
||
|
];
|
||
|
$subscriberData = array_diff_key(
|
||
|
$subscriberData,
|
||
|
array_flip($reservedColumns)
|
||
|
);
|
||
|
return $subscriberData;
|
||
|
}
|
||
|
|
||
|
public static function search($orm, $search = '') {
|
||
|
if (strlen(trim($search)) === 0) {
|
||
|
return $orm;
|
||
|
}
|
||
|
|
||
|
return $orm->where_raw(
|
||
|
'(`email` LIKE ? OR `first_name` LIKE ? OR `last_name` LIKE ?)',
|
||
|
['%' . $search . '%', '%' . $search . '%', '%' . $search . '%']
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function filters($data = []) {
|
||
|
$group = (!empty($data['group'])) ? $data['group'] : 'all';
|
||
|
|
||
|
$segments = Segment::orderByAsc('name')
|
||
|
->whereNull('deleted_at')
|
||
|
->whereIn('type', Segment::getSegmentTypes())
|
||
|
->findMany();
|
||
|
$segmentList = [];
|
||
|
$segmentList[] = [
|
||
|
'label' => __('All Lists', 'mailpoet'),
|
||
|
'value' => '',
|
||
|
];
|
||
|
|
||
|
$subscribersWithoutSegment = self::filter('withoutSegments')
|
||
|
->whereNull('deleted_at')
|
||
|
->count();
|
||
|
$subscribersWithoutSegmentLabel = sprintf(
|
||
|
// translators: %s is the number of subscribers without a segment.
|
||
|
__('Subscribers without a list (%s)', 'mailpoet'),
|
||
|
number_format($subscribersWithoutSegment)
|
||
|
);
|
||
|
|
||
|
$segmentList[] = [
|
||
|
'label' => $subscribersWithoutSegmentLabel,
|
||
|
'value' => 'none',
|
||
|
];
|
||
|
|
||
|
foreach ($segments as $segment) {
|
||
|
$subscribersCount = 0;
|
||
|
$subscribers = $segment->subscribers()
|
||
|
->filter('groupBy', $group);
|
||
|
if ($subscribers) {
|
||
|
$subscribersCount = $subscribers->count();
|
||
|
}
|
||
|
|
||
|
$label = sprintf(
|
||
|
'%s (%s)',
|
||
|
$segment->name,
|
||
|
number_format($subscribersCount)
|
||
|
);
|
||
|
|
||
|
$segmentList[] = [
|
||
|
'label' => $label,
|
||
|
'value' => $segment->id(),
|
||
|
];
|
||
|
}
|
||
|
|
||
|
$filters = [
|
||
|
'segment' => $segmentList,
|
||
|
];
|
||
|
|
||
|
return $filters;
|
||
|
}
|
||
|
|
||
|
public static function filterBy($orm, $filters = null) {
|
||
|
if (empty($filters)) {
|
||
|
return $orm;
|
||
|
}
|
||
|
foreach ($filters as $key => $value) {
|
||
|
if ($key === 'segment') {
|
||
|
if ($value === 'none') {
|
||
|
return self::filter('withoutSegments');
|
||
|
} else {
|
||
|
$segment = Segment::findOne($value);
|
||
|
if ($segment instanceof Segment) {
|
||
|
return $segment->subscribers();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $orm;
|
||
|
}
|
||
|
|
||
|
public static function groupBy($orm, $group = null) {
|
||
|
if ($group === 'trash') {
|
||
|
return $orm->whereNotNull('deleted_at');
|
||
|
} else if ($group === 'all') {
|
||
|
return $orm->whereNull('deleted_at');
|
||
|
} else {
|
||
|
return $orm->filter($group);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static function filterWithCustomFields($orm) {
|
||
|
$orm = $orm->select(MP_SUBSCRIBERS_TABLE . '.*');
|
||
|
$customFields = CustomField::findArray();
|
||
|
foreach ($customFields as $customField) {
|
||
|
$orm = $orm->select_expr(
|
||
|
'IFNULL(GROUP_CONCAT(CASE WHEN ' .
|
||
|
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END), NULL) as "' . $customField['name'] . '"');
|
||
|
}
|
||
|
$orm = $orm
|
||
|
->leftOuterJoin(
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||
|
[
|
||
|
MP_SUBSCRIBERS_TABLE . '.id',
|
||
|
'=',
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.subscriber_id',
|
||
|
]
|
||
|
)
|
||
|
->leftOuterJoin(
|
||
|
MP_CUSTOM_FIELDS_TABLE,
|
||
|
[
|
||
|
MP_CUSTOM_FIELDS_TABLE . '.id',
|
||
|
'=',
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.custom_field_id',
|
||
|
]
|
||
|
)
|
||
|
->groupBy(MP_SUBSCRIBERS_TABLE . '.id');
|
||
|
return $orm;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated
|
||
|
*/
|
||
|
public static function filterWithCustomFieldsForExport($orm) {
|
||
|
$orm = $orm->select(MP_SUBSCRIBERS_TABLE . '.*');
|
||
|
$customFields = CustomField::findArray();
|
||
|
foreach ($customFields as $customField) {
|
||
|
$orm = $orm->selectExpr(
|
||
|
'MAX(CASE WHEN ' .
|
||
|
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END) as "' . $customField['id'] . '"'
|
||
|
);
|
||
|
}
|
||
|
$orm = $orm
|
||
|
->leftOuterJoin(
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||
|
[
|
||
|
MP_SUBSCRIBERS_TABLE . '.id', '=',
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.subscriber_id',
|
||
|
]
|
||
|
)
|
||
|
->leftOuterJoin(
|
||
|
MP_CUSTOM_FIELDS_TABLE,
|
||
|
[
|
||
|
MP_CUSTOM_FIELDS_TABLE . '.id','=',
|
||
|
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.custom_field_id',
|
||
|
]
|
||
|
);
|
||
|
return $orm;
|
||
|
}
|
||
|
|
||
|
public static function getSubscribedInSegments($segmentIds) {
|
||
|
$subscribers = SubscriberSegment::tableAlias('relation')
|
||
|
->whereIn('relation.segment_id', $segmentIds)
|
||
|
->where('relation.status', 'subscribed')
|
||
|
->join(
|
||
|
MP_SUBSCRIBERS_TABLE,
|
||
|
'subscribers.id = relation.subscriber_id',
|
||
|
'subscribers'
|
||
|
)
|
||
|
->select('subscribers.id')
|
||
|
->whereNull('subscribers.deleted_at')
|
||
|
->where('subscribers.status', 'subscribed')
|
||
|
->distinct();
|
||
|
return $subscribers;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $customerEmail
|
||
|
* @return bool|Subscriber
|
||
|
*/
|
||
|
public static function getWooCommerceSegmentSubscriber($customerEmail) {
|
||
|
$wcSegment = Segment::getWooCommerceSegment();
|
||
|
return Subscriber::tableAlias('subscribers')
|
||
|
->select('subscribers.*')
|
||
|
->where('subscribers.email', $customerEmail)
|
||
|
->join(
|
||
|
MP_SUBSCRIBER_SEGMENT_TABLE,
|
||
|
'relation.subscriber_id = subscribers.id',
|
||
|
'relation'
|
||
|
)
|
||
|
->where('relation.segment_id', $wcSegment->id)
|
||
|
->where('relation.status', Subscriber::STATUS_SUBSCRIBED)
|
||
|
->whereIn('subscribers.status', [Subscriber::STATUS_SUBSCRIBED, Subscriber::STATUS_UNCONFIRMED])
|
||
|
->where('subscribers.is_woocommerce_user', 1)
|
||
|
->findOne();
|
||
|
}
|
||
|
|
||
|
public function customFields() {
|
||
|
return $this->hasManyThrough(
|
||
|
__NAMESPACE__ . '\CustomField',
|
||
|
__NAMESPACE__ . '\SubscriberCustomField',
|
||
|
'subscriber_id',
|
||
|
'custom_field_id'
|
||
|
)->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value');
|
||
|
}
|
||
|
|
||
|
public static function createOrUpdate($data = []) {
|
||
|
$subscriber = false;
|
||
|
if (is_array($data) && !empty($data)) {
|
||
|
$data = WPFunctions::get()->stripslashesDeep($data);
|
||
|
}
|
||
|
|
||
|
if (isset($data['id']) && (int)$data['id'] > 0) {
|
||
|
$subscriber = self::findOne((int)$data['id']);
|
||
|
unset($data['id']);
|
||
|
}
|
||
|
|
||
|
if ($subscriber === false && !empty($data['email'])) {
|
||
|
$subscriber = self::where('email', $data['email'])->findOne();
|
||
|
if ($subscriber !== false) {
|
||
|
unset($data['email']);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// segments
|
||
|
$segmentIds = false;
|
||
|
if (array_key_exists('segments', $data)) {
|
||
|
$segmentIds = (array)$data['segments'];
|
||
|
unset($data['segments']);
|
||
|
}
|
||
|
|
||
|
// if new subscriber, make sure that required fields are set
|
||
|
if (!$subscriber) {
|
||
|
$data = self::setRequiredFieldsDefaultValues($data);
|
||
|
}
|
||
|
|
||
|
// get custom fields
|
||
|
list($data, $customFields) = self::extractCustomFieldsFromFromObject($data);
|
||
|
|
||
|
// wipe any unconfirmed data at this point
|
||
|
$data['unconfirmed_data'] = null;
|
||
|
|
||
|
$oldStatus = false;
|
||
|
$newStatus = false;
|
||
|
|
||
|
if ($subscriber === false) {
|
||
|
$subscriber = self::create();
|
||
|
$subscriber->hydrate($data);
|
||
|
} else {
|
||
|
$oldStatus = $subscriber->status;
|
||
|
$subscriber->set($data);
|
||
|
$newStatus = $subscriber->status;
|
||
|
}
|
||
|
|
||
|
// Update last_subscribed_at when status changes to subscribed
|
||
|
if ($oldStatus !== self::STATUS_SUBSCRIBED && $subscriber->status === self::STATUS_SUBSCRIBED) {
|
||
|
$subscriber->set('last_subscribed_at', WPFunctions::get()->currentTime('mysql'));
|
||
|
}
|
||
|
|
||
|
if ($subscriber->save()) {
|
||
|
if (!empty($customFields)) {
|
||
|
$subscriber->saveCustomFields($customFields);
|
||
|
}
|
||
|
|
||
|
// check for status change
|
||
|
if (
|
||
|
($oldStatus === self::STATUS_SUBSCRIBED)
|
||
|
&&
|
||
|
($newStatus === self::STATUS_UNSUBSCRIBED)
|
||
|
) {
|
||
|
// make sure we unsubscribe the user from all segments
|
||
|
SubscriberSegment::unsubscribeFromSegments($subscriber);
|
||
|
} else {
|
||
|
if ($segmentIds !== false) {
|
||
|
SubscriberSegment::resetSubscriptions($subscriber, $segmentIds);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $subscriber;
|
||
|
}
|
||
|
|
||
|
public function withCustomFields() {
|
||
|
$customFields = CustomField::select('id')->findArray();
|
||
|
if (empty($customFields)) return $this;
|
||
|
|
||
|
$customFieldIds = array_column($customFields, 'id');
|
||
|
$relations = SubscriberCustomField::select('custom_field_id')
|
||
|
->select('value')
|
||
|
->whereIn('custom_field_id', $customFieldIds)
|
||
|
->where('subscriber_id', $this->id())
|
||
|
->findMany();
|
||
|
foreach ($relations as $relation) {
|
||
|
$this->{'cf_' . $relation->customFieldId} = $relation->value;
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
public function withSegments() {
|
||
|
$this->segments = $this->segments()->findArray();
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
public function withSubscriptions() {
|
||
|
$this->subscriptions = SubscriberSegment::where('subscriber_id', $this->id())
|
||
|
->findArray();
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
public function getCustomField($customFieldId, $default = null) {
|
||
|
$customField = SubscriberCustomField::select('value')
|
||
|
->where('custom_field_id', $customFieldId)
|
||
|
->where('subscriber_id', $this->id())
|
||
|
->findOne();
|
||
|
|
||
|
if ($customField instanceof SubscriberCustomField) {
|
||
|
return $customField->value;
|
||
|
} else {
|
||
|
return $default;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function saveCustomFields($customFieldsData = []) {
|
||
|
// get custom field ids
|
||
|
$customFieldIds = array_keys($customFieldsData);
|
||
|
|
||
|
// get custom fields
|
||
|
$customFields = CustomField::whereIdIn($customFieldIds)->findMany();
|
||
|
|
||
|
foreach ($customFields as $customField) {
|
||
|
$value = (isset($customFieldsData[$customField->id])
|
||
|
? $customFieldsData[$customField->id]
|
||
|
: null
|
||
|
);
|
||
|
// format value
|
||
|
$value = $customField->formatValue($value);
|
||
|
|
||
|
$this->setCustomField($customField->id, $value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function setCustomField($customFieldId, $value) {
|
||
|
return SubscriberCustomField::createOrUpdate([
|
||
|
'subscriber_id' => $this->id(),
|
||
|
'custom_field_id' => $customFieldId,
|
||
|
'value' => $value,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
public function setUnconfirmedData(array $subscriberData) {
|
||
|
$subscriberData = self::filterOutReservedColumns($subscriberData);
|
||
|
$encoded = json_encode($subscriberData);
|
||
|
if (is_string($encoded)) {
|
||
|
$this->unconfirmedData = $encoded;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function getUnconfirmedData() {
|
||
|
if (!empty($this->unconfirmedData)) {
|
||
|
$subscriberData = json_decode($this->unconfirmedData, true);
|
||
|
$subscriberData = self::filterOutReservedColumns((array)$subscriberData);
|
||
|
return $subscriberData;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated Use MailPoet\Util\License\Features\Subscribers::getSubscribersCount or \MailPoet\Subscribers\SubscribersRepository::getTotalSubscribers
|
||
|
*/
|
||
|
public static function getTotalSubscribers() {
|
||
|
return self::whereIn('status', [
|
||
|
self::STATUS_SUBSCRIBED,
|
||
|
self::STATUS_UNCONFIRMED,
|
||
|
self::STATUS_INACTIVE,
|
||
|
])
|
||
|
->whereNull('deleted_at')
|
||
|
->count();
|
||
|
}
|
||
|
|
||
|
public static function getInactiveSubscribersCount() {
|
||
|
return self::where('status', self::STATUS_INACTIVE)
|
||
|
->whereNull('deleted_at')
|
||
|
->count();
|
||
|
}
|
||
|
|
||
|
public static function subscribed($orm) {
|
||
|
return $orm
|
||
|
->whereNull('deleted_at')
|
||
|
->where('status', self::STATUS_SUBSCRIBED);
|
||
|
}
|
||
|
|
||
|
public static function unsubscribed($orm) {
|
||
|
return $orm
|
||
|
->whereNull('deleted_at')
|
||
|
->where('status', self::STATUS_UNSUBSCRIBED);
|
||
|
}
|
||
|
|
||
|
public static function unconfirmed($orm) {
|
||
|
return $orm
|
||
|
->whereNull('deleted_at')
|
||
|
->where('status', self::STATUS_UNCONFIRMED);
|
||
|
}
|
||
|
|
||
|
public static function bounced($orm) {
|
||
|
return $orm
|
||
|
->whereNull('deleted_at')
|
||
|
->where('status', self::STATUS_BOUNCED);
|
||
|
}
|
||
|
|
||
|
public static function inactive($orm) {
|
||
|
return $orm
|
||
|
->whereNull('deleted_at')
|
||
|
->where('status', self::STATUS_INACTIVE);
|
||
|
}
|
||
|
|
||
|
public static function withoutSegments($orm) {
|
||
|
return $orm->select(MP_SUBSCRIBERS_TABLE . '.*')
|
||
|
->whereRaw(
|
||
|
MP_SUBSCRIBERS_TABLE . '.id NOT IN (
|
||
|
SELECT `subscriber_id`
|
||
|
FROM ' . MP_SUBSCRIBER_SEGMENT_TABLE . '
|
||
|
WHERE `status` = "' . self::STATUS_SUBSCRIBED . '" AND `segment_id` IN (
|
||
|
SELECT `id` FROM ' . MP_SEGMENTS_TABLE . ' WHERE `deleted_at` IS NULL
|
||
|
)
|
||
|
)'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function createMultiple($columns, $values) {
|
||
|
return self::rawExecute(
|
||
|
'INSERT INTO `' . self::$_table . '` ' .
|
||
|
'(' . implode(', ', $columns) . ') ' .
|
||
|
'VALUES ' . rtrim(
|
||
|
str_repeat(
|
||
|
'(' . rtrim(str_repeat('?,', count($columns)), ',') . ')' . ', ',
|
||
|
count($values)
|
||
|
),
|
||
|
', '
|
||
|
),
|
||
|
Helpers::flattenArray($values)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function updateMultiple($columns, $subscribers, $updatedAt = false) {
|
||
|
$ignoreColumnsOnUpdate = [
|
||
|
'wp_user_id',
|
||
|
'is_woocommerce_user',
|
||
|
'email',
|
||
|
'created_at',
|
||
|
'last_subscribed_at',
|
||
|
];
|
||
|
// check if there is anything to update after excluding ignored columns
|
||
|
if (!array_diff($columns, $ignoreColumnsOnUpdate)) return;
|
||
|
$subscribers = array_map('array_values', $subscribers);
|
||
|
$emailPosition = array_search('email', $columns);
|
||
|
$sql =
|
||
|
function($type) use (
|
||
|
$columns,
|
||
|
$subscribers,
|
||
|
$emailPosition,
|
||
|
$ignoreColumnsOnUpdate
|
||
|
) {
|
||
|
return array_filter(
|
||
|
array_map(function($columnPosition, $columnName) use (
|
||
|
$type,
|
||
|
$subscribers,
|
||
|
$emailPosition,
|
||
|
$ignoreColumnsOnUpdate
|
||
|
) {
|
||
|
if (in_array($columnName, $ignoreColumnsOnUpdate)) return;
|
||
|
$query = array_map(
|
||
|
function($subscriber) use ($type, $columnPosition, $emailPosition) {
|
||
|
return ($type === 'values') ?
|
||
|
[
|
||
|
$subscriber[$emailPosition],
|
||
|
$subscriber[$columnPosition],
|
||
|
] :
|
||
|
'WHEN email = ? THEN ?';
|
||
|
}, $subscribers);
|
||
|
return ($type === 'values') ?
|
||
|
Helpers::flattenArray($query) :
|
||
|
$columnName . '= (CASE ' . implode(' ', $query) . ' END)';
|
||
|
}, array_keys($columns), $columns)
|
||
|
);
|
||
|
};
|
||
|
return self::rawExecute(
|
||
|
'UPDATE `' . self::$_table . '` ' .
|
||
|
'SET ' . implode(', ', $sql('statement')) . ' ' .
|
||
|
(($updatedAt) ? ', updated_at = "' . $updatedAt . '" ' : '') .
|
||
|
', unconfirmed_data = NULL ' .
|
||
|
'WHERE email IN ' .
|
||
|
'(' . rtrim(str_repeat('?,', count($subscribers)), ',') . ')',
|
||
|
array_merge(
|
||
|
Helpers::flattenArray($sql('values')),
|
||
|
array_column($subscribers, $emailPosition)
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function findSubscribersInSegments(array $subscribersIds, array $segmentsIds) {
|
||
|
return self::getSubscribedInSegments($segmentsIds)
|
||
|
->whereIn('subscribers.id', $subscribersIds)
|
||
|
->select('subscribers.*');
|
||
|
}
|
||
|
|
||
|
public static function extractSubscribersIds(array $subscribers) {
|
||
|
return array_filter(
|
||
|
array_map(function($subscriber) {
|
||
|
return (!empty($subscriber->id)) ? $subscriber->id : false;
|
||
|
}, $subscribers)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public static function setRequiredFieldsDefaultValues($data) {
|
||
|
$settings = SettingsController::getInstance();
|
||
|
$requiredFieldDefaultValues = [
|
||
|
'first_name' => '',
|
||
|
'last_name' => '',
|
||
|
'unsubscribe_token' => Security::generateUnsubscribeToken(self::class),
|
||
|
'link_token' => Security::generateRandomString(self::LINK_TOKEN_LENGTH),
|
||
|
'status' => (!$settings->get('signup_confirmation.enabled')) ? self::STATUS_SUBSCRIBED : self::STATUS_UNCONFIRMED,
|
||
|
];
|
||
|
foreach ($requiredFieldDefaultValues as $field => $value) {
|
||
|
if (!isset($data[$field])) {
|
||
|
$data[$field] = $value;
|
||
|
}
|
||
|
}
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
public static function extractCustomFieldsFromFromObject($data) {
|
||
|
$customFields = [];
|
||
|
foreach ($data as $key => $value) {
|
||
|
if (strpos($key, 'cf_') === 0) {
|
||
|
$customFields[(int)substr($key, 3)] = $value;
|
||
|
unset($data[$key]);
|
||
|
}
|
||
|
}
|
||
|
return [$data, $customFields];
|
||
|
}
|
||
|
|
||
|
public function getAllSegmentNamesWithStatus() {
|
||
|
return Segment::tableAlias('segment')
|
||
|
->select('name')
|
||
|
->select('subscriber_segment.segment_id', 'segment_id')
|
||
|
->select('subscriber_segment.status', 'status')
|
||
|
->select('subscriber_segment.updated_at', 'updated_at')
|
||
|
->join(
|
||
|
SubscriberSegment::$_table,
|
||
|
['subscriber_segment.segment_id', '=', 'segment.id'],
|
||
|
'subscriber_segment'
|
||
|
)
|
||
|
->where('subscriber_segment.subscriber_id', $this->id)
|
||
|
->orderByAsc('name')
|
||
|
->findArray();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This method is here only for BC fix of 3rd party plugin integration.
|
||
|
* @see https://kb.mailpoet.com/article/195-add-subscribers-through-your-own-form-or-plugin
|
||
|
* @deprecated
|
||
|
*/
|
||
|
public static function subscribe($subscriberData = [], $segmentIds = []) {
|
||
|
trigger_error('Calling Subscriber::subscribe() is deprecated and will be removed. Use MailPoet\API\MP\v1\API instead. ', E_USER_DEPRECATED);
|
||
|
$service = ContainerWrapper::getInstance()->get(\MailPoet\Subscribers\SubscriberActions::class);
|
||
|
[$subscriber] = $service->subscribe($subscriberData, $segmentIds);
|
||
|
return $subscriber;
|
||
|
}
|
||
|
}
|