Move dynamic segments from Premium plugin
[MAILPOET-2382]
This commit is contained in:
committed by
Jack Kitterhing
parent
0af9f09f50
commit
70a89b7939
219
lib/API/JSON/v1/DynamicSegments.php
Normal file
219
lib/API/JSON/v1/DynamicSegments.php
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\API\JSON\v1;
|
||||||
|
|
||||||
|
use MailPoet\API\JSON\Endpoint as APIEndpoint;
|
||||||
|
use MailPoet\API\JSON\Error;
|
||||||
|
use MailPoet\API\JSON\Response;
|
||||||
|
use MailPoet\Config\AccessControl;
|
||||||
|
use MailPoet\Listing\BulkActionController;
|
||||||
|
use MailPoet\Listing\Handler;
|
||||||
|
use MailPoet\Models\Model;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\ErrorSavingException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\FormDataMapper;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Saver;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
|
class DynamicSegments extends APIEndpoint {
|
||||||
|
|
||||||
|
public $permissions = [
|
||||||
|
'global' => AccessControl::PERMISSION_MANAGE_SEGMENTS,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var FormDataMapper */
|
||||||
|
private $mapper;
|
||||||
|
|
||||||
|
/** @var Saver */
|
||||||
|
private $saver;
|
||||||
|
|
||||||
|
/** @var SingleSegmentLoader */
|
||||||
|
private $dynamic_segments_loader;
|
||||||
|
|
||||||
|
/** @var SubscribersCount */
|
||||||
|
private $subscribers_counts_loader;
|
||||||
|
|
||||||
|
/** @var BulkActionController */
|
||||||
|
private $bulk_action;
|
||||||
|
|
||||||
|
/** @var Handler */
|
||||||
|
private $listing_handler;
|
||||||
|
|
||||||
|
public function __construct(BulkActionController $bulk_action, Handler $handler, $mapper = null, $saver = null, $dynamic_segments_loader = null, $subscribers_counts_loader = null) {
|
||||||
|
$this->bulk_action = $bulk_action;
|
||||||
|
$this->listing_handler = $handler;
|
||||||
|
$this->mapper = $mapper ?: new FormDataMapper();
|
||||||
|
$this->saver = $saver ?: new Saver();
|
||||||
|
$this->dynamic_segments_loader = $dynamic_segments_loader ?: new SingleSegmentLoader(new DBMapper());
|
||||||
|
$this->subscribers_counts_loader = $subscribers_counts_loader ?: new SubscribersCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get($data = []) {
|
||||||
|
if (isset($data['id'])) {
|
||||||
|
$id = (int)$data['id'];
|
||||||
|
} else {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::BAD_REQUEST => WPFunctions::get()->__('Missing mandatory argument `id`.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$segment = $this->dynamic_segments_loader->load($id);
|
||||||
|
|
||||||
|
$filters = $segment->getFilters();
|
||||||
|
|
||||||
|
return $this->successResponse(array_merge([
|
||||||
|
'name' => $segment->name,
|
||||||
|
'description' => $segment->description,
|
||||||
|
'id' => $segment->id,
|
||||||
|
], $filters[0]->toArray()));
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::NOT_FOUND => WPFunctions::get()->__('This segment does not exist.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save($data) {
|
||||||
|
try {
|
||||||
|
$dynamic_segment = $this->mapper->mapDataToDB($data);
|
||||||
|
$this->saver->save($dynamic_segment);
|
||||||
|
|
||||||
|
return $this->successResponse($data);
|
||||||
|
} catch (InvalidSegmentTypeException $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::BAD_REQUEST => $this->getErrorString($e),
|
||||||
|
], [], Response::STATUS_BAD_REQUEST);
|
||||||
|
} catch (ErrorSavingException $e) {
|
||||||
|
$statusCode = Response::STATUS_UNKNOWN;
|
||||||
|
if ($e->getCode() === Model::DUPLICATE_RECORD) {
|
||||||
|
$statusCode = Response::STATUS_CONFLICT;
|
||||||
|
}
|
||||||
|
return $this->errorResponse([$statusCode => $e->getMessage()], [], $statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getErrorString(InvalidSegmentTypeException $e) {
|
||||||
|
switch ($e->getCode()) {
|
||||||
|
case InvalidSegmentTypeException::MISSING_TYPE:
|
||||||
|
return WPFunctions::get()->__('Segment type is missing.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::INVALID_TYPE:
|
||||||
|
return WPFunctions::get()->__('Segment type is unknown.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::MISSING_ROLE:
|
||||||
|
return WPFunctions::get()->__('Please select user role.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::MISSING_ACTION:
|
||||||
|
return WPFunctions::get()->__('Please select email action.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::MISSING_NEWSLETTER_ID:
|
||||||
|
return WPFunctions::get()->__('Please select an email.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::MISSING_PRODUCT_ID:
|
||||||
|
return WPFunctions::get()->__('Please select category.', 'mailpoet-premium');
|
||||||
|
case InvalidSegmentTypeException::MISSING_CATEGORY_ID:
|
||||||
|
return WPFunctions::get()->__('Please select product.', 'mailpoet-premium');
|
||||||
|
default:
|
||||||
|
return WPFunctions::get()->__('An error occurred while saving data.', 'mailpoet-premium');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trash($data = []) {
|
||||||
|
if (isset($data['id'])) {
|
||||||
|
$id = (int)$data['id'];
|
||||||
|
} else {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::BAD_REQUEST => WPFunctions::get()->__('Missing mandatory argument `id`.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$segment = $this->dynamic_segments_loader->load($id);
|
||||||
|
$segment->trash();
|
||||||
|
return $this->successResponse(
|
||||||
|
$segment->asArray(),
|
||||||
|
['count' => 1]
|
||||||
|
);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::NOT_FOUND => WPFunctions::get()->__('This segment does not exist.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore($data = []) {
|
||||||
|
if (isset($data['id'])) {
|
||||||
|
$id = (int)$data['id'];
|
||||||
|
} else {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::BAD_REQUEST => WPFunctions::get()->__('Missing mandatory argument `id`.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$segment = $this->dynamic_segments_loader->load($id);
|
||||||
|
$segment->restore();
|
||||||
|
return $this->successResponse(
|
||||||
|
$segment->asArray(),
|
||||||
|
['count' => 1]
|
||||||
|
);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::NOT_FOUND => WPFunctions::get()->__('This segment does not exist.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete($data = []) {
|
||||||
|
if (isset($data['id'])) {
|
||||||
|
$id = (int)$data['id'];
|
||||||
|
} else {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::BAD_REQUEST => WPFunctions::get()->__('Missing mandatory argument `id`.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$segment = $this->dynamic_segments_loader->load($id);
|
||||||
|
$segment->delete();
|
||||||
|
return $this->successResponse(null, ['count' => 1]);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
Error::NOT_FOUND => WPFunctions::get()->__('This segment does not exist.', 'mailpoet-premium'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function listing($data = []) {
|
||||||
|
$listing_data = $this->listing_handler->get('\MailPoet\Premium\Models\DynamicSegment', $data);
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ($listing_data['items'] as $segment) {
|
||||||
|
$segment->subscribers_url = WPFunctions::get()->adminUrl(
|
||||||
|
'admin.php?page=mailpoet-subscribers#/filter[segment=' . $segment->id . ']'
|
||||||
|
);
|
||||||
|
|
||||||
|
$row = $segment->asArray();
|
||||||
|
$segment_with_filters = $this->dynamic_segments_loader->load($segment->id);
|
||||||
|
$row['count'] = $this->subscribers_counts_loader->getSubscribersCount($segment_with_filters);
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->successResponse($data, [
|
||||||
|
'count' => $listing_data['count'],
|
||||||
|
'filters' => $listing_data['filters'],
|
||||||
|
'groups' => $listing_data['groups'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function bulkAction($data = []) {
|
||||||
|
try {
|
||||||
|
$meta = $this->bulk_action->apply('\MailPoet\Premium\Models\DynamicSegment', $data);
|
||||||
|
return $this->successResponse(null, $meta);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->errorResponse([
|
||||||
|
$e->getCode() => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
lib/API/JSON/v1/NewsletterLinks.php
Normal file
20
lib/API/JSON/v1/NewsletterLinks.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\API\JSON\v1;
|
||||||
|
|
||||||
|
use MailPoet\API\JSON\Endpoint as APIEndpoint;
|
||||||
|
use MailPoet\Config\AccessControl;
|
||||||
|
use MailPoet\Models\NewsletterLink;
|
||||||
|
|
||||||
|
class NewsletterLinks extends APIEndpoint {
|
||||||
|
|
||||||
|
public $permissions = [
|
||||||
|
'global' => AccessControl::PERMISSION_MANAGE_SEGMENTS,
|
||||||
|
];
|
||||||
|
|
||||||
|
function get($data = []) {
|
||||||
|
$links = NewsletterLink::select(['id', 'url'])->where('newsletter_id', $data['newsletterId'])->findArray();
|
||||||
|
return $this->successResponse($links);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -66,12 +66,14 @@ class ContainerConfigurator implements IContainerConfigurator {
|
|||||||
$container->autowire(\MailPoet\API\JSON\v1\AutomatedLatestContent::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\AutomatedLatestContent::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\AutomaticEmails::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\AutomaticEmails::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\CustomFields::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\CustomFields::class)->setPublic(true);
|
||||||
|
$container->autowire(\MailPoet\API\JSON\v1\DynamicSegments::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\FeatureFlags::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\FeatureFlags::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\Forms::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\Forms::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\ImportExport::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\ImportExport::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\Mailer::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\Mailer::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\MP2Migrator::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\MP2Migrator::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\Newsletters::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\Newsletters::class)->setPublic(true);
|
||||||
|
$container->autowire(\MailPoet\API\JSON\v1\NewsletterLinks::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\NewsletterTemplates::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\NewsletterTemplates::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\Segments::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\Segments::class)->setPublic(true);
|
||||||
$container->autowire(\MailPoet\API\JSON\v1\SendingQueue::class)->setPublic(true);
|
$container->autowire(\MailPoet\API\JSON\v1\SendingQueue::class)->setPublic(true);
|
||||||
|
7
lib/DynamicSegments/Exceptions/ErrorSavingException.php
Normal file
7
lib/DynamicSegments/Exceptions/ErrorSavingException.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Exceptions;
|
||||||
|
|
||||||
|
class ErrorSavingException extends \Exception {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Exceptions;
|
||||||
|
|
||||||
|
class InvalidSegmentTypeException extends \Exception {
|
||||||
|
|
||||||
|
const MISSING_TYPE = 1;
|
||||||
|
const INVALID_TYPE = 2;
|
||||||
|
const MISSING_ROLE = 3;
|
||||||
|
const MISSING_ACTION = 4;
|
||||||
|
const MISSING_NEWSLETTER_ID = 5;
|
||||||
|
const MISSING_CATEGORY_ID = 6;
|
||||||
|
const MISSING_PRODUCT_ID = 7;
|
||||||
|
|
||||||
|
};
|
109
lib/DynamicSegments/Filters/EmailAction.php
Normal file
109
lib/DynamicSegments/Filters/EmailAction.php
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Models\StatisticsClicks;
|
||||||
|
use MailPoet\Models\StatisticsNewsletters;
|
||||||
|
use MailPoet\Models\StatisticsOpens;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
class EmailAction implements Filter {
|
||||||
|
|
||||||
|
const SEGMENT_TYPE = 'email';
|
||||||
|
|
||||||
|
const ACTION_OPENED = 'opened';
|
||||||
|
const ACTION_NOT_OPENED = 'notOpened';
|
||||||
|
const ACTION_CLICKED = 'clicked';
|
||||||
|
const ACTION_NOT_CLICKED = 'notClicked';
|
||||||
|
|
||||||
|
private static $allowed_actions = [
|
||||||
|
EmailAction::ACTION_OPENED,
|
||||||
|
EmailAction::ACTION_NOT_OPENED,
|
||||||
|
EmailAction::ACTION_CLICKED,
|
||||||
|
EmailAction::ACTION_NOT_CLICKED,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $newsletter_id;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $link_id;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $action;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $connect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $newsletter_id
|
||||||
|
* @param int $link_id
|
||||||
|
* @param string $action
|
||||||
|
* @param string $connect
|
||||||
|
*/
|
||||||
|
public function __construct($action, $newsletter_id, $link_id = null, $connect = null) {
|
||||||
|
$this->newsletter_id = (int)$newsletter_id;
|
||||||
|
if ($link_id) {
|
||||||
|
$this->link_id = (int)$link_id;
|
||||||
|
}
|
||||||
|
$this->setAction($action);
|
||||||
|
$this->connect = $connect;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setAction($action) {
|
||||||
|
if (!in_array($action, EmailAction::$allowed_actions)) {
|
||||||
|
throw new \InvalidArgumentException("Unknown action " . $action);
|
||||||
|
}
|
||||||
|
$this->action = $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSql(\ORM $orm) {
|
||||||
|
if (($this->action === EmailAction::ACTION_CLICKED) || ($this->action === EmailAction::ACTION_NOT_CLICKED)) {
|
||||||
|
$table = StatisticsClicks::$_table;
|
||||||
|
} else {
|
||||||
|
$table = StatisticsOpens::$_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->action === EmailAction::ACTION_NOT_CLICKED) || ($this->action === EmailAction::ACTION_NOT_OPENED)) {
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . StatisticsNewsletters::$_table,
|
||||||
|
'statssent.subscriber_id = ' . Subscriber::$_table . '.id AND statssent.newsletter_id = ' . $this->newsletter_id,
|
||||||
|
'statssent'
|
||||||
|
);
|
||||||
|
$orm->rawJoin(
|
||||||
|
'LEFT JOIN ' . $table,
|
||||||
|
$this->createNotStatsJoin(),
|
||||||
|
'stats'
|
||||||
|
);
|
||||||
|
$orm->whereNull('stats.id');
|
||||||
|
} else {
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $table,
|
||||||
|
'stats.subscriber_id = ' . Subscriber::$_table . '.id AND stats.newsletter_id = ' . $this->newsletter_id,
|
||||||
|
'stats'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (($this->action === EmailAction::ACTION_CLICKED) && ($this->link_id)) {
|
||||||
|
$orm->where('stats.link_id', $this->link_id);
|
||||||
|
}
|
||||||
|
return $orm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createNotStatsJoin() {
|
||||||
|
$clause = 'statssent.subscriber_id = stats.subscriber_id AND stats.newsletter_id = ' . $this->newsletter_id;
|
||||||
|
if (($this->action === EmailAction::ACTION_NOT_CLICKED) && ($this->link_id)) {
|
||||||
|
$clause .= ' AND stats.link_id = ' . $this->link_id;
|
||||||
|
}
|
||||||
|
return $clause;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray() {
|
||||||
|
return [
|
||||||
|
'action' => $this->action,
|
||||||
|
'newsletter_id' => $this->newsletter_id,
|
||||||
|
'link_id' => $this->link_id,
|
||||||
|
'connect' => $this->connect,
|
||||||
|
'segmentType' => EmailAction::SEGMENT_TYPE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
11
lib/DynamicSegments/Filters/Filter.php
Normal file
11
lib/DynamicSegments/Filters/Filter.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
interface Filter {
|
||||||
|
|
||||||
|
function toSql(\ORM $orm);
|
||||||
|
|
||||||
|
function toArray();
|
||||||
|
|
||||||
|
}
|
44
lib/DynamicSegments/Filters/UserRole.php
Normal file
44
lib/DynamicSegments/Filters/UserRole.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
class UserRole implements Filter {
|
||||||
|
|
||||||
|
const SEGMENT_TYPE = 'userRole';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $role;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $connect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $role
|
||||||
|
* @param string $connect
|
||||||
|
*/
|
||||||
|
public function __construct($role, $connect = null) {
|
||||||
|
$this->role = $role;
|
||||||
|
$this->connect = $connect;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSql(\ORM $orm) {
|
||||||
|
global $wpdb;
|
||||||
|
$orm->join($wpdb->users, ['wpusers.id', '=', MP_SUBSCRIBERS_TABLE . '.wp_user_id'], 'wpusers')
|
||||||
|
->join($wpdb->usermeta, ['wpusers.ID', '=', 'wpusermeta.user_id'], 'wpusermeta')
|
||||||
|
->whereEqual('wpusermeta.meta_key', $wpdb->prefix . 'capabilities')
|
||||||
|
->whereLike('wpusermeta.meta_value', '%"' . $this->role . '"%');
|
||||||
|
return $orm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray() {
|
||||||
|
return [
|
||||||
|
'wordpressRole' => $this->role,
|
||||||
|
'connect' => $this->connect,
|
||||||
|
'segmentType' => UserRole::SEGMENT_TYPE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRole() {
|
||||||
|
return $this->role;
|
||||||
|
}
|
||||||
|
}
|
74
lib/DynamicSegments/Filters/WooCommerceCategory.php
Normal file
74
lib/DynamicSegments/Filters/WooCommerceCategory.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
|
class WooCommerceCategory implements Filter {
|
||||||
|
|
||||||
|
const SEGMENT_TYPE = 'woocommerce';
|
||||||
|
|
||||||
|
const ACTION_CATEGORY = 'purchasedCategory';
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $category_id;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $connect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $category_id
|
||||||
|
* @param string $connect
|
||||||
|
*/
|
||||||
|
public function __construct($category_id, $connect = null) {
|
||||||
|
$this->category_id = (int)$category_id;
|
||||||
|
$this->connect = $connect;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSql(\ORM $orm) {
|
||||||
|
global $wpdb;
|
||||||
|
$orm->distinct();
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $wpdb->postmeta,
|
||||||
|
"postmeta.meta_key = '_customer_user' AND " . Subscriber::$_table . '.wp_user_id=postmeta.meta_value',
|
||||||
|
'postmeta'
|
||||||
|
);
|
||||||
|
$orm->join($wpdb->prefix . 'woocommerce_order_items', ['postmeta.post_id', '=', 'items.order_id'], 'items');
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta',
|
||||||
|
"itemmeta.order_item_id = items.order_item_id AND itemmeta.meta_key = '_product_id'",
|
||||||
|
'itemmeta'
|
||||||
|
);
|
||||||
|
$orm->join($wpdb->term_relationships, ['itemmeta.meta_value', '=', 'term_relationships.object_id'], 'term_relationships');
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $wpdb->term_taxonomy,
|
||||||
|
'
|
||||||
|
term_taxonomy.term_taxonomy_id=term_relationships.term_taxonomy_id
|
||||||
|
AND
|
||||||
|
term_taxonomy.term_id IN (' . join(',', $this->getAllCategoryIds()) . ')',
|
||||||
|
'term_taxonomy'
|
||||||
|
);
|
||||||
|
$orm->where('status', Subscriber::STATUS_SUBSCRIBED);
|
||||||
|
return $orm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAllCategoryIds() {
|
||||||
|
$subcategories = WPFunctions::get()->getTerms('product_cat', ['child_of' => $this->category_id]);
|
||||||
|
if (!is_array($subcategories)) return [];
|
||||||
|
$ids = array_map(function($category) {
|
||||||
|
return $category->term_id;
|
||||||
|
}, $subcategories);
|
||||||
|
$ids[] = $this->category_id;
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray() {
|
||||||
|
return [
|
||||||
|
'action' => WooCommerceCategory::ACTION_CATEGORY,
|
||||||
|
'category_id' => $this->category_id,
|
||||||
|
'connect' => $this->connect,
|
||||||
|
'segmentType' => WooCommerceCategory::SEGMENT_TYPE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
56
lib/DynamicSegments/Filters/WooCommerceProduct.php
Normal file
56
lib/DynamicSegments/Filters/WooCommerceProduct.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
class WooCommerceProduct implements Filter {
|
||||||
|
|
||||||
|
const SEGMENT_TYPE = 'woocommerce';
|
||||||
|
|
||||||
|
const ACTION_PRODUCT = 'purchasedProduct';
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $product_id;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $connect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $product_id
|
||||||
|
* @param string $connect
|
||||||
|
*/
|
||||||
|
public function __construct($product_id, $connect = null) {
|
||||||
|
$this->product_id = (int)$product_id;
|
||||||
|
$this->connect = $connect;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSql(\ORM $orm) {
|
||||||
|
global $wpdb;
|
||||||
|
$orm->distinct();
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $wpdb->postmeta,
|
||||||
|
"postmeta.meta_key = '_customer_user' AND " . Subscriber::$_table . '.wp_user_id=postmeta.meta_value',
|
||||||
|
'postmeta'
|
||||||
|
);
|
||||||
|
$orm->join($wpdb->prefix . 'woocommerce_order_items', ['postmeta.post_id', '=', 'items.order_id'], 'items');
|
||||||
|
$orm->rawJoin(
|
||||||
|
'INNER JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta',
|
||||||
|
"itemmeta.order_item_id=items.order_item_id
|
||||||
|
AND itemmeta.meta_key='_product_id'
|
||||||
|
AND itemmeta.meta_value=" . $this->product_id,
|
||||||
|
'itemmeta'
|
||||||
|
);
|
||||||
|
$orm->where('status', Subscriber::STATUS_SUBSCRIBED);
|
||||||
|
return $orm;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray() {
|
||||||
|
return [
|
||||||
|
'action' => WooCommerceProduct::ACTION_PRODUCT,
|
||||||
|
'product_id' => $this->product_id,
|
||||||
|
'connect' => $this->connect,
|
||||||
|
'segmentType' => WooCommerceProduct::SEGMENT_TYPE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount;
|
||||||
|
|
||||||
|
class AddToNewslettersSegments {
|
||||||
|
|
||||||
|
/** @var Loader */
|
||||||
|
private $loader;
|
||||||
|
|
||||||
|
/** @var \MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount */
|
||||||
|
private $subscribersCountLoader;
|
||||||
|
|
||||||
|
public function __construct(Loader $loader, SubscribersCount $subscribersCountLoader) {
|
||||||
|
$this->loader = $loader;
|
||||||
|
$this->subscribersCountLoader = $subscribersCountLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $initial_segments
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function add(array $initial_segments) {
|
||||||
|
$dynamic_segments = $this->getListings();
|
||||||
|
return array_merge($initial_segments, $dynamic_segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getListings() {
|
||||||
|
$dynamic_segments = $this->loader->load();
|
||||||
|
return $this->buildResult($dynamic_segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildResult($dynamic_segments) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($dynamic_segments as $dynamic_segment) {
|
||||||
|
$result[] = [
|
||||||
|
'id' => $dynamic_segment->id,
|
||||||
|
'name' => $dynamic_segment->name,
|
||||||
|
'subscribers' => $this->subscribersCountLoader->getSubscribersCount($dynamic_segment),
|
||||||
|
'deleted_at' => $dynamic_segment->deleted_at,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount;
|
||||||
|
|
||||||
|
class AddToSubscribersFilters {
|
||||||
|
|
||||||
|
/** @var \MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader */
|
||||||
|
private $loader;
|
||||||
|
|
||||||
|
/** @var SubscribersCount */
|
||||||
|
private $subscribersCountLoader;
|
||||||
|
|
||||||
|
public function __construct(Loader $loader, SubscribersCount $subscribersCountLoader) {
|
||||||
|
$this->loader = $loader;
|
||||||
|
$this->subscribersCountLoader = $subscribersCountLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $segment_filters
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function add(array $segment_filters) {
|
||||||
|
$dynamic_segments = $this->getListings();
|
||||||
|
return $this->sort(array_merge($segment_filters, $dynamic_segments));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getListings() {
|
||||||
|
$dynamic_segments = $this->loader->load();
|
||||||
|
return $this->buildResult($dynamic_segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildResult($dynamic_segments) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($dynamic_segments as $dynamic_segment) {
|
||||||
|
$result[] = [
|
||||||
|
'value' => $dynamic_segment->id,
|
||||||
|
'label' => sprintf(
|
||||||
|
'%s (%s)',
|
||||||
|
$dynamic_segment->name,
|
||||||
|
number_format($this->subscribersCountLoader->getSubscribersCount($dynamic_segment))
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sort($segment_filters) {
|
||||||
|
$special_segment_filters = [];
|
||||||
|
$segments = [];
|
||||||
|
foreach ($segment_filters as $segment_filter) {
|
||||||
|
if (is_numeric($segment_filter['value'])) {
|
||||||
|
$segments[] = $segment_filter;
|
||||||
|
} else {
|
||||||
|
$special_segment_filters[] = $segment_filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usort($segments, function ($a, $b) {
|
||||||
|
return strcasecmp($a["label"], $b["label"]);
|
||||||
|
});
|
||||||
|
return array_merge($special_segment_filters, $segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersIds;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SendingNewslettersSubscribersFinder {
|
||||||
|
|
||||||
|
/** @var SingleSegmentLoader */
|
||||||
|
private $single_segment_loader;
|
||||||
|
|
||||||
|
/** @var \MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersIds */
|
||||||
|
private $subscribers_ids_loader;
|
||||||
|
|
||||||
|
public function __construct(SingleSegmentLoader $single_segment_loader, SubscribersIds $subscribers_ids_loader) {
|
||||||
|
$this->single_segment_loader = $single_segment_loader;
|
||||||
|
$this->subscribers_ids_loader = $subscribers_ids_loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Segment $segment
|
||||||
|
* @param int[] $subscribers_to_process_ids
|
||||||
|
*
|
||||||
|
* @return Subscriber[]
|
||||||
|
*/
|
||||||
|
function findSubscribersInSegment(Segment $segment, array $subscribers_to_process_ids) {
|
||||||
|
if ($segment->type !== DynamicSegment::TYPE_DYNAMIC) return [];
|
||||||
|
$dynamic_segment = $this->single_segment_loader->load($segment->id);
|
||||||
|
return $this->subscribers_ids_loader->load($dynamic_segment, $subscribers_to_process_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Segment $segment
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getSubscriberIdsInSegment(Segment $segment) {
|
||||||
|
if ($segment->type !== DynamicSegment::TYPE_DYNAMIC) return [];
|
||||||
|
$dynamic_segment = $this->single_segment_loader->load($segment->id);
|
||||||
|
$result = $this->subscribers_ids_loader->load($dynamic_segment);
|
||||||
|
return $this->createResultArray($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createResultArray($subscribers) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($subscribers as $subscriber) {
|
||||||
|
$result[] = $subscriber->asArray();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Listing\BulkActionController;
|
||||||
|
use MailPoet\Listing\BulkActionFactory;
|
||||||
|
use MailPoet\Listing\Handler;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersBulkActionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $segment
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
function apply(array $segment, array $data) {
|
||||||
|
if ($segment['type'] === DynamicSegment::TYPE_DYNAMIC) {
|
||||||
|
$bulkAction = new BulkActionController(new BulkActionFactory(), new Handler());
|
||||||
|
return $bulkAction->apply('\MailPoet\Premium\Models\SubscribersInDynamicSegment', $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Listing\Handler;
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersListingsHandlerFactory {
|
||||||
|
|
||||||
|
function get(Segment $segment, $data) {
|
||||||
|
if ($segment->type === DynamicSegment::TYPE_DYNAMIC) {
|
||||||
|
$listing = new Handler();
|
||||||
|
return $listing_data = $listing->get('\MailPoet\Premium\Models\SubscribersInDynamicSegment', $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
lib/DynamicSegments/Mappers/DBMapper.php
Normal file
86
lib/DynamicSegments/Mappers/DBMapper.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Mappers;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\EmailAction;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\Filter;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\WooCommerceCategory;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\WooCommerceProduct;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class DBMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \MailPoet\Premium\Models\DynamicSegment $segment_data
|
||||||
|
* @param DynamicSegmentFilter[] $filters_data
|
||||||
|
*
|
||||||
|
* @return DynamicSegment
|
||||||
|
*/
|
||||||
|
function mapSegment(DynamicSegment $segment_data, array $filters_data) {
|
||||||
|
$filters = $this->getFilters($segment_data->id, $filters_data);
|
||||||
|
$segment_data->setFilters($filters);
|
||||||
|
return $segment_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \MailPoet\Premium\Models\DynamicSegment[] $segments_data
|
||||||
|
* @param DynamicSegmentFilter[] $filters_data
|
||||||
|
*
|
||||||
|
* @return DynamicSegment[]
|
||||||
|
*/
|
||||||
|
function mapSegments(array $segments_data, array $filters_data) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($segments_data as $segment_data) {
|
||||||
|
$result[] = $this->mapSegment($segment_data, $filters_data);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFilters($segment_id, $all_filters) {
|
||||||
|
$result = [];
|
||||||
|
foreach ($all_filters as $filter) {
|
||||||
|
if ($filter->segment_id === $segment_id) {
|
||||||
|
$result[] = $this->createFilter($filter->filter_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return Filter
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function createFilter(array $data) {
|
||||||
|
switch ($this->getSegmentType($data)) {
|
||||||
|
case 'userRole':
|
||||||
|
if (!$data['wordpressRole']) throw new InvalidSegmentTypeException('Missing role');
|
||||||
|
return new UserRole($data['wordpressRole'], 'and');
|
||||||
|
case 'email':
|
||||||
|
return new EmailAction($data['action'], $data['newsletter_id'], $data['link_id']);
|
||||||
|
case 'woocommerce':
|
||||||
|
if ($data['action'] === WooCommerceProduct::ACTION_PRODUCT) {
|
||||||
|
return new WooCommerceProduct($data['product_id']);
|
||||||
|
}
|
||||||
|
return new WooCommerceCategory($data['category_id']);
|
||||||
|
default:
|
||||||
|
throw new InvalidSegmentTypeException('Invalid type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
* @return string
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function getSegmentType(array $data) {
|
||||||
|
if (!isset($data['segmentType'])) {
|
||||||
|
throw new InvalidSegmentTypeException('Segment type is not set');
|
||||||
|
}
|
||||||
|
return $data['segmentType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
120
lib/DynamicSegments/Mappers/FormDataMapper.php
Normal file
120
lib/DynamicSegments/Mappers/FormDataMapper.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Mappers;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\EmailAction;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\Filter;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\WooCommerceCategory;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\WooCommerceProduct;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class FormDataMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return DynamicSegment
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
function mapDataToDB(array $data) {
|
||||||
|
$filters = $this->getFilters($data);
|
||||||
|
$dynamic_segment = $this->createDynamicSegment($data);
|
||||||
|
|
||||||
|
$dynamic_segment->setFilters($filters);
|
||||||
|
|
||||||
|
return $dynamic_segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createDynamicSegment($data) {
|
||||||
|
$dataToSave = [
|
||||||
|
'name' => isset($data['name']) ? $data['name'] : '',
|
||||||
|
'description' => isset($data['description']) ? $data['description'] : '',
|
||||||
|
];
|
||||||
|
$dynamic_segment = null;
|
||||||
|
if (isset($data['id'])) {
|
||||||
|
$dynamic_segment = DynamicSegment::findOne($data['id']);
|
||||||
|
}
|
||||||
|
if ($dynamic_segment instanceof DynamicSegment) {
|
||||||
|
$dynamic_segment->set($dataToSave);
|
||||||
|
} else {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
if ($dynamic_segment instanceof DynamicSegment) {
|
||||||
|
$dynamic_segment->hydrate($dataToSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $dynamic_segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Filter[]
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function getFilters(array $data) {
|
||||||
|
switch ($this->getSegmentType($data)) {
|
||||||
|
case 'userRole':
|
||||||
|
if (!$data['wordpressRole']) throw new InvalidSegmentTypeException('Missing role', InvalidSegmentTypeException::MISSING_ROLE);
|
||||||
|
return [new UserRole($data['wordpressRole'])];
|
||||||
|
case 'email':
|
||||||
|
return $this->createEmail($data);
|
||||||
|
case 'woocommerce':
|
||||||
|
return $this->createWooCommerce($data);
|
||||||
|
default:
|
||||||
|
throw new InvalidSegmentTypeException('Invalid type', InvalidSegmentTypeException::INVALID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function getSegmentType(array $data) {
|
||||||
|
if (!isset($data['segmentType'])) {
|
||||||
|
throw new InvalidSegmentTypeException('Segment type is not set', InvalidSegmentTypeException::MISSING_TYPE);
|
||||||
|
}
|
||||||
|
return $data['segmentType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return EmailAction[]
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function createEmail(array $data) {
|
||||||
|
if (empty($data['action'])) throw new InvalidSegmentTypeException('Missing action', InvalidSegmentTypeException::MISSING_ACTION);
|
||||||
|
if (empty($data['newsletter_id'])) throw new InvalidSegmentTypeException('Missing newsletter id', InvalidSegmentTypeException::MISSING_NEWSLETTER_ID);
|
||||||
|
if (isset($data['link_id'])) {
|
||||||
|
return [new EmailAction($data['action'], $data['newsletter_id'], $data['link_id'])];
|
||||||
|
} else {
|
||||||
|
return [new EmailAction($data['action'], $data['newsletter_id'])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Filter[]
|
||||||
|
* @throws InvalidSegmentTypeException
|
||||||
|
*/
|
||||||
|
private function createWooCommerce($data) {
|
||||||
|
if (empty($data['action'])) throw new InvalidSegmentTypeException('Missing action', InvalidSegmentTypeException::MISSING_ACTION);
|
||||||
|
switch ($data['action']) {
|
||||||
|
case WooCommerceCategory::ACTION_CATEGORY:
|
||||||
|
if (!isset($data['category_id'])) throw new InvalidSegmentTypeException('Missing category', InvalidSegmentTypeException::MISSING_CATEGORY_ID);
|
||||||
|
return [new WooCommerceCategory($data['category_id'])];
|
||||||
|
case WooCommerceProduct::ACTION_PRODUCT:
|
||||||
|
if (!isset($data['product_id'])) throw new InvalidSegmentTypeException('Missing product', InvalidSegmentTypeException::MISSING_PRODUCT_ID);
|
||||||
|
return [new WooCommerceProduct($data['product_id'])];
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException("Unknown action " . $data['action']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
lib/DynamicSegments/Persistence/Loading/Loader.php
Normal file
35
lib/DynamicSegments/Persistence/Loading/Loader.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class Loader {
|
||||||
|
|
||||||
|
/** @var DBMapper */
|
||||||
|
private $mapper;
|
||||||
|
|
||||||
|
public function __construct(DBMapper $mapper) {
|
||||||
|
$this->mapper = $mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DynamicSegment[]
|
||||||
|
*/
|
||||||
|
function load() {
|
||||||
|
$segments = DynamicSegment::findAll();
|
||||||
|
return $this->loadFilters($segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadFilters(array $segments) {
|
||||||
|
$ids = array_map(function($segment) {
|
||||||
|
return $segment->id;
|
||||||
|
}, $segments);
|
||||||
|
$filters = DynamicSegmentFilter::getAllBySegmentIds($ids);
|
||||||
|
|
||||||
|
return $this->mapper->mapSegments($segments, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SingleSegmentLoader {
|
||||||
|
|
||||||
|
/** @var DBMapper */
|
||||||
|
private $mapper;
|
||||||
|
|
||||||
|
public function __construct(DBMapper $mapper) {
|
||||||
|
$this->mapper = $mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|int $segment_id
|
||||||
|
* @return DynamicSegment
|
||||||
|
*/
|
||||||
|
function load($segment_id) {
|
||||||
|
|
||||||
|
$segment = DynamicSegment::findOne($segment_id);
|
||||||
|
if (!$segment instanceof DynamicSegment) {
|
||||||
|
throw new \InvalidArgumentException('Segment not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$filters = $segment->dynamicSegmentFilters()->findMany();
|
||||||
|
|
||||||
|
return $this->mapper->mapSegment($segment, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
23
lib/DynamicSegments/Persistence/Loading/SubscribersCount.php
Normal file
23
lib/DynamicSegments/Persistence/Loading/SubscribersCount.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersCount {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DynamicSegment $dynamic_segment
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function getSubscribersCount(DynamicSegment $dynamic_segment) {
|
||||||
|
$orm = Subscriber::selectExpr('count(distinct ' . Subscriber::$_table . '.id) as cnt');
|
||||||
|
foreach ($dynamic_segment->getFilters() as $filter) {
|
||||||
|
$orm = $filter->toSql($orm);
|
||||||
|
}
|
||||||
|
return $orm->findOne()->cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
lib/DynamicSegments/Persistence/Loading/SubscribersIds.php
Normal file
29
lib/DynamicSegments/Persistence/Loading/SubscribersIds.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersIds {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds subscribers in a dynamic segment and returns their ids.
|
||||||
|
*
|
||||||
|
* @param DynamicSegment $dynamic_segment
|
||||||
|
* @param array $limit_to_subscribers_ids If passed the result will be limited only to ids within this array
|
||||||
|
*
|
||||||
|
* @return Subscriber[]
|
||||||
|
*/
|
||||||
|
function load(DynamicSegment $dynamic_segment, $limit_to_subscribers_ids = null) {
|
||||||
|
$orm = Subscriber::selectExpr(Subscriber::$_table . '.id');
|
||||||
|
foreach ($dynamic_segment->getFilters() as $filter) {
|
||||||
|
$orm = $filter->toSql($orm);
|
||||||
|
}
|
||||||
|
if ($limit_to_subscribers_ids) {
|
||||||
|
$orm->whereIn(Subscriber::$_table . '.id', $limit_to_subscribers_ids);
|
||||||
|
}
|
||||||
|
return $orm->findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
77
lib/DynamicSegments/Persistence/Saver.php
Normal file
77
lib/DynamicSegments/Persistence/Saver.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence;
|
||||||
|
|
||||||
|
use MailPoet\Models\Model;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\ErrorSavingException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\Filter;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class Saver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DynamicSegment $segment
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
* @throws ErrorSavingException
|
||||||
|
*/
|
||||||
|
function save(DynamicSegment $segment) {
|
||||||
|
$db = \ORM::get_db();
|
||||||
|
$db->beginTransaction();
|
||||||
|
|
||||||
|
$data_segment = $this->saveSegment($db, $segment);
|
||||||
|
$this->saveFilters($db, $segment, $data_segment->id());
|
||||||
|
$db->commit();
|
||||||
|
return $data_segment->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ErrorSavingException
|
||||||
|
*/
|
||||||
|
private function saveSegment(\PDO $db, DynamicSegment $segment) {
|
||||||
|
$segment->save();
|
||||||
|
$this->checkErrors($db, $segment);
|
||||||
|
return $segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ErrorSavingException
|
||||||
|
*/
|
||||||
|
private function checkErrors(\PDO $db, Model $model) {
|
||||||
|
$errors = $model->getErrors();
|
||||||
|
if ($errors) {
|
||||||
|
$code = null;
|
||||||
|
if (array_key_exists(Model::DUPLICATE_RECORD, $errors)) {
|
||||||
|
$code = Model::DUPLICATE_RECORD;
|
||||||
|
}
|
||||||
|
$db->rollBack();
|
||||||
|
throw new ErrorSavingException(join(", ", $model->getErrors()), $code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ErrorSavingException
|
||||||
|
*/
|
||||||
|
private function saveFilters(\PDO $db, DynamicSegment $segment, $saved_data_id) {
|
||||||
|
$this->deleteFilters($segment);
|
||||||
|
foreach ($segment->getFilters() as $filter) {
|
||||||
|
$data_filter = $this->saveFilter($filter, $saved_data_id);
|
||||||
|
$this->checkErrors($db, $data_filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteFilters(DynamicSegment $segment) {
|
||||||
|
DynamicSegmentFilter::deleteAllBySegmentIds([$segment->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveFilter(Filter $filter, $data_segment_id) {
|
||||||
|
$data_filter = DynamicSegmentFilter::create();
|
||||||
|
if ($data_filter instanceof DynamicSegmentFilter) {
|
||||||
|
$data_filter->segment_id = $data_segment_id;
|
||||||
|
$data_filter->filter_data = $filter->toArray();
|
||||||
|
$data_filter->save();
|
||||||
|
}
|
||||||
|
return $data_filter;
|
||||||
|
}
|
||||||
|
}
|
114
lib/Models/DynamicSegment.php
Normal file
114
lib/Models/DynamicSegment.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\Models;
|
||||||
|
|
||||||
|
use MailPoet\Models\Segment as MailPoetSegment;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\Filter;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $description
|
||||||
|
* @property string $created_at
|
||||||
|
* @property string $updated_at
|
||||||
|
*/
|
||||||
|
class DynamicSegment extends MailPoetSegment {
|
||||||
|
|
||||||
|
const TYPE_DYNAMIC = 'dynamic';
|
||||||
|
|
||||||
|
/** @var Filter[] */
|
||||||
|
private $filters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Filter[]
|
||||||
|
*/
|
||||||
|
public function getFilters() {
|
||||||
|
return $this->filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Filter[] $filters
|
||||||
|
*/
|
||||||
|
public function setFilters(array $filters) {
|
||||||
|
$this->filters = $filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
$this->set('type', DynamicSegment::TYPE_DYNAMIC);
|
||||||
|
return parent::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dynamicSegmentFilters() {
|
||||||
|
return $this->has_many(__NAMESPACE__ . '\DynamicSegmentFilter', 'segment_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
static function findAll() {
|
||||||
|
$query = self::select('*');
|
||||||
|
return $query->where('type', DynamicSegment::TYPE_DYNAMIC)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function listingQuery(array $data = []) {
|
||||||
|
$query = self::select('*');
|
||||||
|
$query->where('type', DynamicSegment::TYPE_DYNAMIC);
|
||||||
|
if (isset($data['group'])) {
|
||||||
|
$query->filter('groupBy', $data['group']);
|
||||||
|
}
|
||||||
|
if (isset($data['search'])) {
|
||||||
|
$query->filter('search', $data['search']);
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function groups() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'name' => 'all',
|
||||||
|
'label' => WPFunctions::get()->__('All', 'mailpoet-premium'),
|
||||||
|
'count' => DynamicSegment::getPublished()->where('type', DynamicSegment::TYPE_DYNAMIC)->count(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'trash',
|
||||||
|
'label' => WPFunctions::get()->__('Trash', 'mailpoet-premium'),
|
||||||
|
'count' => parent::getTrashed()->where('type', DynamicSegment::TYPE_DYNAMIC)->count(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete() {
|
||||||
|
DynamicSegmentFilter::where('segment_id', $this->id)->deleteMany();
|
||||||
|
return parent::delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function bulkTrash($orm) {
|
||||||
|
$count = parent::bulkAction($orm, function($ids) {
|
||||||
|
$placeholders = join(',', array_fill(0, count($ids), '?'));
|
||||||
|
DynamicSegment::rawExecute(join(' ', [
|
||||||
|
'UPDATE `' . DynamicSegment::$_table . '`',
|
||||||
|
'SET `deleted_at` = NOW()',
|
||||||
|
'WHERE `id` IN (' . $placeholders . ')',
|
||||||
|
]), $ids);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ['count' => $count];
|
||||||
|
}
|
||||||
|
|
||||||
|
static function bulkDelete($orm) {
|
||||||
|
$count = parent::bulkAction($orm, function($ids) {
|
||||||
|
$placeholders = join(',', array_fill(0, count($ids), '?'));
|
||||||
|
DynamicSegmentFilter::rawExecute(join(' ', [
|
||||||
|
'DELETE FROM `' . DynamicSegmentFilter::$_table . '`',
|
||||||
|
'WHERE `segment_id` IN (' . $placeholders . ')',
|
||||||
|
]), $ids);
|
||||||
|
DynamicSegment::rawExecute(join(' ', [
|
||||||
|
'DELETE FROM `' . DynamicSegment::$_table . '`',
|
||||||
|
'WHERE `id` IN (' . $placeholders . ')',
|
||||||
|
]), $ids);
|
||||||
|
});
|
||||||
|
|
||||||
|
return ['count' => $count];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
lib/Models/DynamicSegmentFilter.php
Normal file
55
lib/Models/DynamicSegmentFilter.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\Models;
|
||||||
|
|
||||||
|
use MailPoet\Models\Model;
|
||||||
|
use MailPoet\WP\Functions as WPFunctions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property array|string|null $filter_data
|
||||||
|
* @property string $segment_id
|
||||||
|
*/
|
||||||
|
class DynamicSegmentFilter extends Model {
|
||||||
|
|
||||||
|
public static $_table = MP_DYNAMIC_SEGMENTS_FILTERS_TABLE;
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
if (is_null($this->filter_data)) {
|
||||||
|
$this->filter_data = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WPFunctions::get()->isSerialized($this->filter_data)) {
|
||||||
|
$this->filter_data = serialize($this->filter_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::save();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getAllBySegmentIds($segmentIds) {
|
||||||
|
if (empty($segmentIds)) return [];
|
||||||
|
$query = self::tableAlias('filters')
|
||||||
|
->whereIn('filters.segment_id', $segmentIds);
|
||||||
|
|
||||||
|
$query->findMany();
|
||||||
|
return $query->findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
$value = parent::__get($name);
|
||||||
|
if ($name === 'filter_data' && WPFunctions::get()->isSerialized($value)) {
|
||||||
|
return unserialize($value);
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function deleteAllBySegmentIds($segmentIds) {
|
||||||
|
if (empty($segmentIds)) return;
|
||||||
|
|
||||||
|
$query = self::tableAlias('filters')
|
||||||
|
->whereIn('segment_id', $segmentIds);
|
||||||
|
|
||||||
|
$query->deleteMany();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
lib/Models/SubscribersInDynamicSegment.php
Normal file
27
lib/Models/SubscribersInDynamicSegment.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\Models;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader;
|
||||||
|
|
||||||
|
class SubscribersInDynamicSegment extends Subscriber {
|
||||||
|
|
||||||
|
static function listingQuery(array $data = []) {
|
||||||
|
$query = self::select(self::$_table . '.*');
|
||||||
|
$single_segment_loader = new SingleSegmentLoader(new DBMapper());
|
||||||
|
$dynamic_segment = $single_segment_loader->load($data['filter']['segment']);
|
||||||
|
foreach ($dynamic_segment->getFilters() as $filter) {
|
||||||
|
$query = $filter->toSql($query);
|
||||||
|
}
|
||||||
|
if (isset($data['group'])) {
|
||||||
|
$query->filter('groupBy', $data['group']);
|
||||||
|
}
|
||||||
|
if (isset($data['search']) && $data['search']) {
|
||||||
|
$query->filter('search', $data['search']);
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
239
tests/integration/API/JSON/v1/DynamicSegmentsTest.php
Normal file
239
tests/integration/API/JSON/v1/DynamicSegmentsTest.php
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\API\JSON\v1;
|
||||||
|
|
||||||
|
use Codeception\Stub;
|
||||||
|
use Codeception\Stub\Expected;
|
||||||
|
use MailPoet\DI\ContainerWrapper;
|
||||||
|
use MailPoet\Listing\BulkActionController;
|
||||||
|
use MailPoet\Listing\Handler;
|
||||||
|
use MailPoet\Models\Model;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\ErrorSavingException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class DynamicSegmentsTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
const SUCCESS_RESPONSE_CODE = 200;
|
||||||
|
const SEGMENT_NOT_FOUND_RESPONSE_CODE = 404;
|
||||||
|
const INVALID_DATA_RESPONSE_CODE = 400;
|
||||||
|
const SERVER_ERROR_RESPONSE_CODE = 409;
|
||||||
|
|
||||||
|
/** @var BulkActionController */
|
||||||
|
private $bulk_action;
|
||||||
|
|
||||||
|
/** @var Handler */
|
||||||
|
private $listing_handler;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->bulk_action = ContainerWrapper::getInstance()->getPremiumContainer()->get(BulkActionController::class);
|
||||||
|
$this->listing_handler = ContainerWrapper::getInstance()->getPremiumContainer()->get(Handler::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetReturnsResponse() {
|
||||||
|
$loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader', [
|
||||||
|
'load' => function () {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 's1',
|
||||||
|
'description' => '',
|
||||||
|
]);
|
||||||
|
$dynamic_segment->setFilters([new UserRole('Editor', 'or')]);
|
||||||
|
return $dynamic_segment;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, $loader);
|
||||||
|
$response = $endpoint->get(['id' => 5]);
|
||||||
|
expect($response)->isInstanceOf('\MailPoet\API\JSON\SuccessResponse');
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->data)->equals([
|
||||||
|
'id' => null,
|
||||||
|
'name' => 's1',
|
||||||
|
'description' => '',
|
||||||
|
'segmentType' => 'userRole',
|
||||||
|
'wordpressRole' => 'Editor',
|
||||||
|
'connect' => 'or',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetReturnsError() {
|
||||||
|
$loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader', [
|
||||||
|
'load' => function () {
|
||||||
|
throw new \InvalidArgumentException('segment not found');
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, $loader);
|
||||||
|
$response = $endpoint->get(['id' => 5]);
|
||||||
|
expect($response)->isInstanceOf('\MailPoet\API\JSON\ErrorResponse');
|
||||||
|
expect($response->status)->equals(self::SEGMENT_NOT_FOUND_RESPONSE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSaverSavesData() {
|
||||||
|
$mapper = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Mappers\FormDataMapper', ['mapDataToDB' => Expected::once(function () {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
return $dynamic_segment;
|
||||||
|
})]);
|
||||||
|
$saver = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Saver', ['save' => Expected::once()]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, $mapper, $saver);
|
||||||
|
$response = $endpoint->save([]);
|
||||||
|
expect($response)->isInstanceOf('\MailPoet\API\JSON\SuccessResponse');
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSaverReturnsErrorOnInvalidData() {
|
||||||
|
$mapper = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Mappers\FormDataMapper', ['mapDataToDB' => Expected::once(function () {
|
||||||
|
throw new InvalidSegmentTypeException();
|
||||||
|
})]);
|
||||||
|
$saver = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Saver', ['save' => Expected::never()]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, $mapper, $saver);
|
||||||
|
$response = $endpoint->save([]);
|
||||||
|
expect($response)->isInstanceOf('\MailPoet\API\JSON\ErrorResponse');
|
||||||
|
expect($response->status)->equals(self::INVALID_DATA_RESPONSE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSaverReturnsErrorOnSave() {
|
||||||
|
$mapper = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Mappers\FormDataMapper', ['mapDataToDB' => Expected::once(function () {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
return $dynamic_segment;
|
||||||
|
})]);
|
||||||
|
$saver = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Saver', ['save' => Expected::once(function () {
|
||||||
|
throw new ErrorSavingException('Error saving data', Model::DUPLICATE_RECORD);
|
||||||
|
})]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, $mapper, $saver);
|
||||||
|
$response = $endpoint->save([]);
|
||||||
|
expect($response)->isInstanceOf('\MailPoet\API\JSON\ErrorResponse');
|
||||||
|
expect($response->status)->equals(self::SERVER_ERROR_RESPONSE_CODE);
|
||||||
|
expect($response->errors[0]['message'])->equals('Error saving data');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanTrashASegment() {
|
||||||
|
DynamicSegment::deleteMany();
|
||||||
|
$dynamic_segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'Trash test',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader', [
|
||||||
|
'load' => function () use($dynamic_segment) {
|
||||||
|
return $dynamic_segment;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, $loader);
|
||||||
|
$response = $endpoint->trash(['id' => $dynamic_segment->id]);
|
||||||
|
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->data)->equals($dynamic_segment->asArray());
|
||||||
|
expect($response->meta['count'])->equals(1);
|
||||||
|
|
||||||
|
$dynamic_segment = DynamicSegment::findOne($dynamic_segment->id);
|
||||||
|
expect($dynamic_segment->deleted_at)->notNull();
|
||||||
|
|
||||||
|
$dynamic_segment->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanRestoreASegment() {
|
||||||
|
DynamicSegment::deleteMany();
|
||||||
|
$dynamic_segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'Restore test',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader', [
|
||||||
|
'load' => function () use($dynamic_segment) {
|
||||||
|
return $dynamic_segment;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, $loader);
|
||||||
|
$response = $endpoint->restore(['id' => $dynamic_segment->id]);
|
||||||
|
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->data)->equals($dynamic_segment->asArray());
|
||||||
|
expect($response->meta['count'])->equals(1);
|
||||||
|
|
||||||
|
$dynamic_segment = DynamicSegment::findOne($dynamic_segment->id);
|
||||||
|
expect($dynamic_segment->deleted_at)->equals(null);
|
||||||
|
|
||||||
|
$dynamic_segment->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanDeleteASegment() {
|
||||||
|
DynamicSegment::deleteMany();
|
||||||
|
$dynamic_segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'Delete test',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$filter = DynamicSegmentFilter::createOrUpdate([
|
||||||
|
'segment_id' => $dynamic_segment->id,
|
||||||
|
]);
|
||||||
|
$loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader', [
|
||||||
|
'load' => function () use($dynamic_segment) {
|
||||||
|
return $dynamic_segment;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, $loader);
|
||||||
|
$response = $endpoint->delete(['id' => $dynamic_segment->id]);
|
||||||
|
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->data)->equals(null);
|
||||||
|
expect($response->meta['count'])->equals(1);
|
||||||
|
|
||||||
|
expect(DynamicSegment::findOne($dynamic_segment->id))->equals(false);
|
||||||
|
expect(DynamicSegmentFilter::findOne($filter->id))->equals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItCanBulkDeleteSegments() {
|
||||||
|
DynamicSegment::deleteMany();
|
||||||
|
$dynamic_segment_1 = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'Test 1',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$dynamic_segment_2 = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'Test 2',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$filter = DynamicSegmentFilter::createOrUpdate([
|
||||||
|
'segment_id' => $dynamic_segment_1->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$endpoint = new DynamicSegments($this->bulk_action, $this->listing_handler, null, null, null);
|
||||||
|
$response = $endpoint->bulkAction([
|
||||||
|
'action' => 'trash',
|
||||||
|
'listing' => ['group' => 'all'],
|
||||||
|
]);
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->meta['count'])->equals(2);
|
||||||
|
|
||||||
|
$response = $endpoint->bulkAction([
|
||||||
|
'action' => 'delete',
|
||||||
|
'listing' => ['group' => 'trash'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->meta['count'])->equals(2);
|
||||||
|
|
||||||
|
$response = $endpoint->bulkAction([
|
||||||
|
'action' => 'delete',
|
||||||
|
'listing' => ['group' => 'trash'],
|
||||||
|
]);
|
||||||
|
expect($response->status)->equals(self::SUCCESS_RESPONSE_CODE);
|
||||||
|
expect($response->meta['count'])->equals(0);
|
||||||
|
|
||||||
|
expect(DynamicSegment::count())->equals(0);
|
||||||
|
expect(DynamicSegmentFilter::findOne($filter->id))->equals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
tests/integration/DynamicSegments/Filters/EmailActionTest.php
Normal file
103
tests/integration/DynamicSegments/Filters/EmailActionTest.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\StatisticsClicks;
|
||||||
|
use MailPoet\Models\StatisticsNewsletters;
|
||||||
|
use MailPoet\Models\StatisticsOpens;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
class EmailActionTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->newsletter = Newsletter::createOrUpdate([
|
||||||
|
'subject' => 'newsletter 1',
|
||||||
|
'status' => 'sent',
|
||||||
|
'type' => Newsletter::TYPE_NOTIFICATION,
|
||||||
|
]);
|
||||||
|
$this->subscriber_opened_clicked = Subscriber::createOrUpdate([
|
||||||
|
'email' => 'opened_clicked@example.com',
|
||||||
|
]);
|
||||||
|
$this->subscriber_opened_not_clicked = Subscriber::createOrUpdate([
|
||||||
|
'email' => 'opened_not_clicked@example.com',
|
||||||
|
]);
|
||||||
|
$this->subscriber_not_opened = Subscriber::createOrUpdate([
|
||||||
|
'email' => 'not_opened@example.com',
|
||||||
|
]);
|
||||||
|
$this->subscriber_not_sent = Subscriber::createOrUpdate([
|
||||||
|
'email' => 'not_sent@example.com',
|
||||||
|
]);
|
||||||
|
StatisticsNewsletters::createMultiple([
|
||||||
|
['newsletter_id' => $this->newsletter->id, 'subscriber_id' => $this->subscriber_opened_clicked->id, 'queue_id' => 1],
|
||||||
|
['newsletter_id' => $this->newsletter->id, 'subscriber_id' => $this->subscriber_opened_not_clicked->id, 'queue_id' => 1],
|
||||||
|
['newsletter_id' => $this->newsletter->id, 'subscriber_id' => $this->subscriber_not_opened->id, 'queue_id' => 1],
|
||||||
|
]);
|
||||||
|
StatisticsOpens::getOrCreate($this->subscriber_opened_clicked->id, $this->newsletter->id, 1);
|
||||||
|
StatisticsOpens::getOrCreate($this->subscriber_opened_not_clicked->id, $this->newsletter->id, 1);
|
||||||
|
StatisticsClicks::createOrUpdateClickCount(1, $this->subscriber_opened_clicked->id, $this->newsletter->id, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetOpened() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_OPENED, $this->newsletter->id);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNotOpened() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_NOT_OPENED, $this->newsletter->id);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetClickedWithoutLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_CLICKED, $this->newsletter->id);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetClickedWithLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_CLICKED, $this->newsletter->id, 1);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetClickedWithWrongLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_CLICKED, $this->newsletter->id, 2);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetNotClickedWithLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_NOT_CLICKED, $this->newsletter->id, 1);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetNotClickedWithWrongLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_NOT_CLICKED, $this->newsletter->id, 2);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetNotClickedWithoutLink() {
|
||||||
|
$emailAction = new EmailAction(EmailAction::ACTION_NOT_CLICKED, $this->newsletter->id);
|
||||||
|
$sql = $emailAction->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
StatisticsClicks::where('newsletter_id', $this->newsletter->id)->findResultSet()->delete();
|
||||||
|
StatisticsNewsletters::where('newsletter_id', $this->newsletter->id)->findResultSet()->delete();
|
||||||
|
StatisticsOpens::where('newsletter_id', $this->newsletter->id)->findResultSet()->delete();
|
||||||
|
$this->newsletter->delete();
|
||||||
|
$this->subscriber_opened_clicked->delete();
|
||||||
|
$this->subscriber_opened_not_clicked->delete();
|
||||||
|
$this->subscriber_not_opened->delete();
|
||||||
|
$this->subscriber_not_sent->delete();
|
||||||
|
}
|
||||||
|
}
|
56
tests/integration/DynamicSegments/Filters/UserRoleTest.php
Normal file
56
tests/integration/DynamicSegments/Filters/UserRoleTest.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
class UserRoleTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test1',
|
||||||
|
'user_email' => 'user-role-test1@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test2',
|
||||||
|
'user_email' => 'user-role-test2@example.com',
|
||||||
|
'role' => 'administrator',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test3',
|
||||||
|
'user_email' => 'user-role-test3@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItConstructsQuery() {
|
||||||
|
$userRole = new UserRole('editor', 'and');
|
||||||
|
$sql = $userRole->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItDoesntGetSubString() {
|
||||||
|
$userRole = new UserRole('edit', 'and');
|
||||||
|
$sql = $userRole->toSql(Subscriber::selectExpr('*'));
|
||||||
|
expect($sql->count())->equals(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
$emails = ['user-role-test1@example.com', 'user-role-test2@example.com', 'user-role-test3@example.com'];
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$user = get_user_by('email', $email);
|
||||||
|
if ($user) {
|
||||||
|
wp_delete_user($user->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
class WooCommerceCategoryTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
public function testToArray() {
|
||||||
|
$filter = new WooCommerceCategory("5");
|
||||||
|
$data = $filter->toArray();
|
||||||
|
expect($data)->notEmpty();
|
||||||
|
expect($data['segmentType'])->same('woocommerce');
|
||||||
|
expect($data['action'])->same('purchasedCategory');
|
||||||
|
expect($data['category_id'])->same(5);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use Codeception\Stub;
|
||||||
|
use Codeception\Stub\Expected;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class AddToNewslettersSegmentsTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function testItReturnsOriginalArray() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment1',
|
||||||
|
'description' => '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$segment_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader', ['load' => Expected::once(function () {
|
||||||
|
return [];
|
||||||
|
})]);
|
||||||
|
|
||||||
|
$subscribers_count_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount', ['getSubscribersCount' => Expected::never()]);
|
||||||
|
|
||||||
|
$filter = new AddToNewslettersSegments($segment_loader, $subscribers_count_loader);
|
||||||
|
$result = $filter->add([$dynamic_segment]);
|
||||||
|
expect($result)->equals([$dynamic_segment]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItAddsDynamicSegments() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment2',
|
||||||
|
'description' => '',
|
||||||
|
'id' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$segment_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader', ['load' => Expected::once(function () use ($dynamic_segment) {
|
||||||
|
return [$dynamic_segment];
|
||||||
|
})]);
|
||||||
|
|
||||||
|
$subscribers_count_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount', ['getSubscribersCount']);
|
||||||
|
$subscribers_count_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getSubscribersCount')
|
||||||
|
->with($this->equalTo($dynamic_segment))
|
||||||
|
->will($this->returnValue(4));
|
||||||
|
|
||||||
|
$filter = new AddToNewslettersSegments($segment_loader, $subscribers_count_loader);
|
||||||
|
$result = $filter->add([]);
|
||||||
|
|
||||||
|
expect($result)->count(1);
|
||||||
|
expect($result[0])->equals([
|
||||||
|
'id' => 1,
|
||||||
|
'name' => 'segment2',
|
||||||
|
'subscribers' => 4,
|
||||||
|
'deleted_at' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use Codeception\Stub;
|
||||||
|
use Codeception\Stub\Expected;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class AddToSubscribersFiltersTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function testItReturnsOriginalArray() {
|
||||||
|
$original_segment = [
|
||||||
|
'label' => 'segment1',
|
||||||
|
'value' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$segment_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader', ['load' => Expected::once(function () {
|
||||||
|
return [];
|
||||||
|
})]);
|
||||||
|
|
||||||
|
$subscribers_count_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount', ['getSubscribersCount' => Expected::never()]);
|
||||||
|
|
||||||
|
$filter = new AddToSubscribersFilters($segment_loader, $subscribers_count_loader);
|
||||||
|
$result = $filter->add([$original_segment]);
|
||||||
|
expect($result)->equals([$original_segment]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItAddsDynamicSegments() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment2',
|
||||||
|
'description' => '',
|
||||||
|
'id' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$segment_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader', ['load' => Expected::once(function () use ($dynamic_segment) {
|
||||||
|
return [$dynamic_segment];
|
||||||
|
})]);
|
||||||
|
|
||||||
|
$subscribers_count_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount', ['getSubscribersCount']);
|
||||||
|
$subscribers_count_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getSubscribersCount')
|
||||||
|
->with($this->equalTo($dynamic_segment))
|
||||||
|
->will($this->returnValue(4));
|
||||||
|
|
||||||
|
$filter = new AddToSubscribersFilters($segment_loader, $subscribers_count_loader);
|
||||||
|
$result = $filter->add([]);
|
||||||
|
|
||||||
|
expect($result)->count(1);
|
||||||
|
expect($result[0])->equals([
|
||||||
|
'label' => 'segment2 (4)',
|
||||||
|
'value' => 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItSortsTheResult() {
|
||||||
|
$dynamic_segment1 = DynamicSegment::create();
|
||||||
|
$dynamic_segment1->hydrate([
|
||||||
|
'name' => 'segment b',
|
||||||
|
'description' => '',
|
||||||
|
'id' => '1',
|
||||||
|
]);
|
||||||
|
$dynamic_segment2 = DynamicSegment::create();
|
||||||
|
$dynamic_segment2->hydrate([
|
||||||
|
'name' => 'segment a',
|
||||||
|
'description' => '',
|
||||||
|
'id' => '2',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$segment_loader = Stub::makeEmpty(
|
||||||
|
'\MailPoet\Premium\DynamicSegments\Persistence\Loading\Loader',
|
||||||
|
[
|
||||||
|
'load' => Expected::once(function () use ($dynamic_segment1, $dynamic_segment2) {
|
||||||
|
return [$dynamic_segment1, $dynamic_segment2];
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$subscribers_count_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersCount', ['getSubscribersCount']);
|
||||||
|
$subscribers_count_loader
|
||||||
|
->expects($this->exactly(2))
|
||||||
|
->method('getSubscribersCount')
|
||||||
|
->will($this->returnValue(4));
|
||||||
|
|
||||||
|
$filter = new AddToSubscribersFilters($segment_loader, $subscribers_count_loader);
|
||||||
|
$result = $filter->add([
|
||||||
|
['value' => '', 'label' => 'Special segment filter'],
|
||||||
|
['value' => '3', 'label' => 'segment c'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($result)->count(4);
|
||||||
|
expect($result[0]['value'])->equals('');
|
||||||
|
expect($result[1]['value'])->equals('2');
|
||||||
|
expect($result[2]['value'])->equals('1');
|
||||||
|
expect($result[3]['value'])->equals('3');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use Codeception\Util\Stub;
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SendingNewslettersSubscribersFinderTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
/** @var \MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader */
|
||||||
|
private $single_segment_loader;
|
||||||
|
|
||||||
|
/** @var \MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersIds */
|
||||||
|
private $subscribers_ids_loader;
|
||||||
|
|
||||||
|
/** @var SendingNewslettersSubscribersFinder */
|
||||||
|
private $subscribers_in_segments_finder;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->single_segment_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SingleSegmentLoader');
|
||||||
|
$this->subscribers_ids_loader = Stub::makeEmpty('\MailPoet\Premium\DynamicSegments\Persistence\Loading\SubscribersIds');
|
||||||
|
$this->subscribers_in_segments_finder = new SendingNewslettersSubscribersFinder($this->single_segment_loader, $this->subscribers_ids_loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFindSubscribersInSegmentReturnsEmptyIfNotDynamic() {
|
||||||
|
$this->single_segment_loader
|
||||||
|
->expects($this->never())
|
||||||
|
->method('load');
|
||||||
|
$this->subscribers_ids_loader
|
||||||
|
->expects($this->never())
|
||||||
|
->method('load');
|
||||||
|
$segment = Segment::create();
|
||||||
|
$segment->type = Segment::TYPE_DEFAULT;
|
||||||
|
$segment->id = 3;
|
||||||
|
$result = $this->subscribers_in_segments_finder->findSubscribersInSegment($segment, []);
|
||||||
|
expect($result)->count(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFindSubscribersInSegmentReturnsSubscribers() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => '',
|
||||||
|
]);
|
||||||
|
$ids = [1, 2, 3];
|
||||||
|
$this->single_segment_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('load')
|
||||||
|
->with($this->equalTo(3))
|
||||||
|
->will($this->returnValue($dynamic_segment));
|
||||||
|
$this->subscribers_ids_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('load')
|
||||||
|
->with($this->equalTo($dynamic_segment), $ids)
|
||||||
|
->will($this->returnValue([new Subscriber()]));
|
||||||
|
$segment = DynamicSegment::create();
|
||||||
|
$segment->type = DynamicSegment::TYPE_DYNAMIC;
|
||||||
|
$segment->id = 3;
|
||||||
|
$result = $this->subscribers_in_segments_finder->findSubscribersInSegment($segment, $ids);
|
||||||
|
expect($result)->count(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testGetSubscriberIdsInSegmentReturnsEmptyIfNotDynamic() {
|
||||||
|
$this->single_segment_loader
|
||||||
|
->expects($this->never())
|
||||||
|
->method('load');
|
||||||
|
$this->subscribers_ids_loader
|
||||||
|
->expects($this->never())
|
||||||
|
->method('load');
|
||||||
|
$segment = DynamicSegment::create();
|
||||||
|
$segment->type = DynamicSegment::TYPE_DEFAULT;
|
||||||
|
$result = $this->subscribers_in_segments_finder->getSubscriberIdsInSegment($segment);
|
||||||
|
expect($result)->count(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetSubscriberIdsInSegmentReturnsSubscribers() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment 2',
|
||||||
|
'description' => '',
|
||||||
|
]);
|
||||||
|
$subscriber1 = Subscriber::create();
|
||||||
|
$subscriber1->hydrate(['id' => 1]);
|
||||||
|
$subscriber2 = Subscriber::create();
|
||||||
|
$subscriber2->hydrate(['id' => 2]);
|
||||||
|
$this->single_segment_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('load')
|
||||||
|
->with($this->equalTo(3))
|
||||||
|
->will($this->returnValue($dynamic_segment));
|
||||||
|
$this->subscribers_ids_loader
|
||||||
|
->expects($this->once())
|
||||||
|
->method('load')
|
||||||
|
->with($this->equalTo($dynamic_segment))
|
||||||
|
->will($this->returnValue([$subscriber1, $subscriber2]));
|
||||||
|
$segment = DynamicSegment::create();
|
||||||
|
$segment->type = DynamicSegment::TYPE_DYNAMIC;
|
||||||
|
$segment->id = 3;
|
||||||
|
$result = $this->subscribers_in_segments_finder->getSubscriberIdsInSegment($segment);
|
||||||
|
expect($result)->count(2);
|
||||||
|
expect($result[0]['id'])->equals(1);
|
||||||
|
expect($result[1]['id'])->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersBulkActionHandlerTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function testItReturnsNullWithUnknownSegment() {
|
||||||
|
$segment = [
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'desc',
|
||||||
|
'type' => 'unknown',
|
||||||
|
];
|
||||||
|
$handler = new SubscribersBulkActionHandler();
|
||||||
|
$result = $handler->apply($segment, [
|
||||||
|
'listing' => ['filter' => ['segment' => 5]],
|
||||||
|
'action' => 'trash',
|
||||||
|
]);
|
||||||
|
expect($result)->null();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItReturnsDataForDynamicSegment() {
|
||||||
|
$segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'desc',
|
||||||
|
'type' => DynamicSegment::TYPE_DYNAMIC,
|
||||||
|
]);
|
||||||
|
$handler = new SubscribersBulkActionHandler();
|
||||||
|
$result = $handler->apply($segment->asArray(), [
|
||||||
|
'listing' => ['filter' => ['segment' => $segment->id()]],
|
||||||
|
'action' => 'trash',
|
||||||
|
]);
|
||||||
|
expect($result)->notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\FreePluginConnectors;
|
||||||
|
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersListingsHandlerFactoryTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function testItReturnsNullWithUnknownSegment() {
|
||||||
|
$segment = DynamicSegment::create();
|
||||||
|
$segment->id = 1;
|
||||||
|
$segment->name = 'name';
|
||||||
|
$segment->type = 'unknown';
|
||||||
|
$listings = new SubscribersListingsHandlerFactory();
|
||||||
|
$result = $listings->get($segment, []);
|
||||||
|
expect($result)->null();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItReturnsDataForDynamicSegment() {
|
||||||
|
$segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'desc',
|
||||||
|
'type' => DynamicSegment::TYPE_DYNAMIC,
|
||||||
|
]);
|
||||||
|
$listings = new SubscribersListingsHandlerFactory();
|
||||||
|
$result = $listings->get($segment, []);
|
||||||
|
expect($result)->notNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
114
tests/integration/DynamicSegments/Mappers/FormDataMapperTest.php
Normal file
114
tests/integration/DynamicSegments/Mappers/FormDataMapperTest.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Mappers;
|
||||||
|
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class FormDataMapperTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
/** @var FormDataMapper */
|
||||||
|
private $mapper;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->mapper = new FormDataMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItThrowsForEmptyData() {
|
||||||
|
$data = [
|
||||||
|
'name' => '',
|
||||||
|
'description' => '',
|
||||||
|
'segmentType' => '',
|
||||||
|
];
|
||||||
|
$this->setExpectedException('\MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException');
|
||||||
|
$this->mapper->mapDataToDB($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItThrowsForInvalidType() {
|
||||||
|
$data = [
|
||||||
|
'name' => '',
|
||||||
|
'description' => '',
|
||||||
|
'segmentType' => 'invalid',
|
||||||
|
];
|
||||||
|
$this->setExpectedException('\MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException');
|
||||||
|
$this->mapper->mapDataToDB($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCreatesUserRoleFilter() {
|
||||||
|
$data = [
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'segmentType' => 'userRole',
|
||||||
|
'wordpressRole' => 'administrator',
|
||||||
|
];
|
||||||
|
$segment = $this->mapper->mapDataToDB($data);
|
||||||
|
$this->assertInstanceOf('\MailPoet\Premium\Models\DynamicSegment', $segment);
|
||||||
|
$this->assertEquals('Name', $segment->name);
|
||||||
|
$this->assertEquals('Description', $segment->description);
|
||||||
|
$this->assertNull($segment->id);
|
||||||
|
$this->assertCount(1, $segment->getFilters());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItFailsIfWooCommerceFilterDataIsMissing() {
|
||||||
|
$data = [
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'segmentType' => 'woocommerce',
|
||||||
|
];
|
||||||
|
$this->setExpectedException('\MailPoet\Premium\DynamicSegments\Exceptions\InvalidSegmentTypeException');
|
||||||
|
$this->mapper->mapDataToDB($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCreatesWooCommerceCategoryFilter() {
|
||||||
|
$data = [
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'segmentType' => 'woocommerce',
|
||||||
|
'category_id' => '45',
|
||||||
|
'action' => 'purchasedCategory',
|
||||||
|
];
|
||||||
|
$segment = $this->mapper->mapDataToDB($data);
|
||||||
|
$this->assertInstanceOf('\MailPoet\Premium\Models\DynamicSegment', $segment);
|
||||||
|
$this->assertEquals('Name', $segment->name);
|
||||||
|
$this->assertEquals('Description', $segment->description);
|
||||||
|
$this->assertNull($segment->id);
|
||||||
|
$filters = $segment->getFilters();
|
||||||
|
$this->assertCount(1, $filters);
|
||||||
|
$this->assertInstanceOf('\MailPoet\Premium\DynamicSegments\Filters\WooCommerceCategory', $filters[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCreatesWooCommerceProductFilter() {
|
||||||
|
$data = [
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'segmentType' => 'woocommerce',
|
||||||
|
'product_id' => '45',
|
||||||
|
'action' => 'purchasedProduct',
|
||||||
|
];
|
||||||
|
$segment = $this->mapper->mapDataToDB($data);
|
||||||
|
$this->assertInstanceOf('\MailPoet\Premium\Models\DynamicSegment', $segment);
|
||||||
|
$this->assertEquals('Name', $segment->name);
|
||||||
|
$this->assertEquals('Description', $segment->description);
|
||||||
|
$this->assertNull($segment->id);
|
||||||
|
$filters = $segment->getFilters();
|
||||||
|
$this->assertCount(1, $filters);
|
||||||
|
$this->assertInstanceOf('\MailPoet\Premium\DynamicSegments\Filters\WooCommerceProduct', $filters[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItSetsIdOnEdit() {
|
||||||
|
$dynamic_segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'segment',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$data = [
|
||||||
|
'id' => (string)$dynamic_segment->id(),
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'segmentType' => 'userRole',
|
||||||
|
'wordpressRole' => 'administrator',
|
||||||
|
];
|
||||||
|
$segment = $this->mapper->mapDataToDB($data);
|
||||||
|
$this->assertSame($dynamic_segment->id(), $segment->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class LoaderTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
private $segments;
|
||||||
|
|
||||||
|
/** @var Loader */
|
||||||
|
private $loader;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->loader = new Loader(new DBMapper());
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
$this->segments[] = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$this->segments[] = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'segment 2',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$filter = new UserRole('Administrator', 'and');
|
||||||
|
$filter_data = DynamicSegmentFilter::create();
|
||||||
|
$filter_data->hydrate([
|
||||||
|
'segment_id' => $this->segments[1]->id,
|
||||||
|
'filter_data' => $filter->toArray(),
|
||||||
|
]);
|
||||||
|
$filter_data->save();
|
||||||
|
$filter = new UserRole('Editor', 'or');
|
||||||
|
$filter_data = DynamicSegmentFilter::create();
|
||||||
|
$filter_data->hydrate([
|
||||||
|
'segment_id' => $this->segments[0]->id,
|
||||||
|
'filter_data' => $filter->toArray(),
|
||||||
|
]);
|
||||||
|
$filter_data->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItLoadsSegments() {
|
||||||
|
$data = $this->loader->load();
|
||||||
|
expect($data)->count(2);
|
||||||
|
expect($data[0])->isInstanceOf('\MailPoet\Premium\Models\DynamicSegment');
|
||||||
|
expect($data[1])->isInstanceOf('\MailPoet\Premium\Models\DynamicSegment');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItDoesNotLoadTrashedSegments() {
|
||||||
|
$this->segments[0]->trash();
|
||||||
|
$data = $this->loader->load();
|
||||||
|
expect($data)->count(1);
|
||||||
|
expect($data[0])->isInstanceOf('\MailPoet\Premium\Models\DynamicSegment');
|
||||||
|
expect($data[0]->name)->equals('segment 2');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItPopulatesCommonData() {
|
||||||
|
$data = $this->loader->load();
|
||||||
|
expect($data[0]->name)->equals('segment 1');
|
||||||
|
expect($data[1]->name)->equals('segment 2');
|
||||||
|
expect($data[0]->description)->equals('description');
|
||||||
|
expect($data[1]->description)->equals('description');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItPopulatesFilters() {
|
||||||
|
$data = $this->loader->load();
|
||||||
|
$filters0 = $data[0]->getFilters();
|
||||||
|
$filters1 = $data[1]->getFilters();
|
||||||
|
expect($filters0)->count(1);
|
||||||
|
expect($filters1)->count(1);
|
||||||
|
expect($filters0[0])->isInstanceOf('\MailPoet\Premium\DynamicSegments\Filters\UserRole');
|
||||||
|
expect($filters1[0])->isInstanceOf('\MailPoet\Premium\DynamicSegments\Filters\UserRole');
|
||||||
|
expect($filters0[0]->getRole())->equals('Editor');
|
||||||
|
expect($filters1[0]->getRole())->equals('Administrator');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Mappers\DBMapper;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class SingleSegmentLoaderTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
private $segment;
|
||||||
|
|
||||||
|
/** @var SingleSegmentLoader */
|
||||||
|
private $loader;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->loader = new SingleSegmentLoader(new DBMapper());
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
$this->segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$filter = new UserRole('Administrator', 'and');
|
||||||
|
$filter_data = DynamicSegmentFilter::create();
|
||||||
|
$filter_data->hydrate([
|
||||||
|
'segment_id' => $this->segment->id,
|
||||||
|
'filter_data' => $filter->toArray(),
|
||||||
|
]);
|
||||||
|
$filter_data->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItLoadsSegments() {
|
||||||
|
$data = $this->loader->load($this->segment->id);
|
||||||
|
expect($data)->isInstanceOf('\MailPoet\Premium\Models\DynamicSegment');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItThrowsForUnknownSegment() {
|
||||||
|
$this->setExpectedException('InvalidArgumentException');
|
||||||
|
$this->loader->load($this->segment->id + 11564564);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItPopulatesCommonData() {
|
||||||
|
$data = $this->loader->load($this->segment->id);
|
||||||
|
expect($data->name)->equals('segment 1');
|
||||||
|
expect($data->description)->equals('description');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItPopulatesFilters() {
|
||||||
|
$data = $this->loader->load($this->segment->id);
|
||||||
|
$filters0 = $data->getFilters();
|
||||||
|
expect($filters0)->count(1);
|
||||||
|
expect($filters0[0])->isInstanceOf('\MailPoet\Premium\DynamicSegments\Filters\UserRole');
|
||||||
|
expect($filters0[0]->getRole())->equals('Administrator');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersCountTest extends \MailPoetTest {
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test1',
|
||||||
|
'user_email' => 'user-role-test1@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test2',
|
||||||
|
'user_email' => 'user-role-test2@example.com',
|
||||||
|
'role' => 'administrator',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test3',
|
||||||
|
'user_email' => 'user-role-test3@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItConstructsQuery() {
|
||||||
|
$userRole = DynamicSegment::create();
|
||||||
|
$userRole->hydrate([
|
||||||
|
'name' => 'segment',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$userRole->setFilters([new UserRole('editor', 'and')]);
|
||||||
|
|
||||||
|
$loader = new SubscribersCount();
|
||||||
|
$count = $loader->getSubscribersCount($userRole);
|
||||||
|
expect($count)->equals(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
$emails = ['user-role-test1@example.com', 'user-role-test2@example.com', 'user-role-test3@example.com'];
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$user = get_user_by('email', $email);
|
||||||
|
if ($user) {
|
||||||
|
wp_delete_user($user->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence\Loading;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
|
||||||
|
class SubscribersIdsTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
private $editors_wp_ids = [];
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
$this->editors_wp_ids[] = wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test1',
|
||||||
|
'user_email' => 'user-role-test1@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test2',
|
||||||
|
'user_email' => 'user-role-test2@example.com',
|
||||||
|
'role' => 'administrator',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
$this->editors_wp_ids[] = wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test3',
|
||||||
|
'user_email' => 'user-role-test3@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItConstructsSubscribersIdQueryForAnyDynamicSegment() {
|
||||||
|
$userRole = DynamicSegment::create();
|
||||||
|
$userRole->hydrate([
|
||||||
|
'name' => 'segment',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$userRole->setFilters([new UserRole('editor', 'and')]);
|
||||||
|
$loader = new SubscribersIds();
|
||||||
|
$result = $loader->load($userRole);
|
||||||
|
$wp_ids = [
|
||||||
|
Subscriber::findOne($result[0]->id)->wp_user_id,
|
||||||
|
Subscriber::findOne($result[1]->id)->wp_user_id,
|
||||||
|
];
|
||||||
|
$this->assertEquals($wp_ids, $this->editors_wp_ids, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
$emails = ['user-role-test1@example.com', 'user-role-test2@example.com', 'user-role-test3@example.com'];
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$user = get_user_by('email', $email);
|
||||||
|
if ($user) {
|
||||||
|
wp_delete_user($user->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
tests/integration/DynamicSegments/Persistence/SaverTest.php
Normal file
65
tests/integration/DynamicSegments/Persistence/SaverTest.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\DynamicSegments\Persistence;
|
||||||
|
|
||||||
|
use MailPoet\Models\Model;
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegment;
|
||||||
|
use MailPoet\Premium\Models\DynamicSegmentFilter;
|
||||||
|
|
||||||
|
class SaverTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
/** @var Saver */
|
||||||
|
private $saver;
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->saver = new Saver();
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItSavesSegment() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => 'desc',
|
||||||
|
]);
|
||||||
|
$id = $this->saver->save($dynamic_segment);
|
||||||
|
$loaded = DynamicSegment::findOne($id);
|
||||||
|
expect($loaded->name)->equals('segment 1');
|
||||||
|
expect($loaded->description)->equals('desc');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItThrowsOnDuplicateSegment() {
|
||||||
|
$dynamic_segment1 = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => 'description',
|
||||||
|
]);
|
||||||
|
$dynamic_segment2 = DynamicSegment::create();
|
||||||
|
$dynamic_segment2->hydrate([
|
||||||
|
'name' => 'segment 2',
|
||||||
|
'description' => 'desc2',
|
||||||
|
'id' => $dynamic_segment1->id,
|
||||||
|
]);
|
||||||
|
$this->setExpectedException('\MailPoet\Premium\DynamicSegments\Exceptions\ErrorSavingException', 'Another record already exists. Please specify a different "PRIMARY".', Model::DUPLICATE_RECORD);
|
||||||
|
$this->saver->save($dynamic_segment2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testItSavesFilters() {
|
||||||
|
$dynamic_segment = DynamicSegment::create();
|
||||||
|
$dynamic_segment->hydrate([
|
||||||
|
'name' => 'segment 1',
|
||||||
|
'description' => 'desc',
|
||||||
|
]);
|
||||||
|
$dynamic_segment->setFilters([new UserRole('editor', 'and')]);
|
||||||
|
$id = $this->saver->save($dynamic_segment);
|
||||||
|
$loaded = DynamicSegmentFilter::select('*')->where('segment_id', $id)->findOne();
|
||||||
|
expect($loaded)->isInstanceOf('\MailPoet\Premium\Models\DynamicSegmentFilter');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
83
tests/integration/Models/SubscribersInDynamicSegmentTest.php
Normal file
83
tests/integration/Models/SubscribersInDynamicSegmentTest.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Premium\Models;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
||||||
|
|
||||||
|
use MailPoet\Premium\DynamicSegments\Filters\UserRole;
|
||||||
|
|
||||||
|
class SubscribersInDynamicSegmentTest extends \MailPoetTest {
|
||||||
|
|
||||||
|
function _before() {
|
||||||
|
$this->cleanData();
|
||||||
|
$this->dynamic_segment = DynamicSegment::createOrUpdate([
|
||||||
|
'name' => 'name',
|
||||||
|
'description' => 'desc',
|
||||||
|
]);
|
||||||
|
$filter = new UserRole('editor', 'and');
|
||||||
|
$data_filter = DynamicSegmentFilter::create();
|
||||||
|
$data_filter->segment_id = $this->dynamic_segment->id;
|
||||||
|
$data_filter->filter_data = $filter->toArray();
|
||||||
|
$data_filter->save();
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test1',
|
||||||
|
'user_email' => 'user-role-test1@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test2',
|
||||||
|
'user_email' => 'user-role-test2@example.com',
|
||||||
|
'role' => 'administrator',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
wp_insert_user([
|
||||||
|
'user_login' => 'user-role-test3',
|
||||||
|
'user_email' => 'user-role-test3@example.com',
|
||||||
|
'role' => 'editor',
|
||||||
|
'user_pass' => '12123154',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testListingQuery() {
|
||||||
|
$listing_data = [
|
||||||
|
'filter' => ['segment' => $this->dynamic_segment->id],
|
||||||
|
'group' => 'all',
|
||||||
|
'search' => '',
|
||||||
|
];
|
||||||
|
$query = SubscribersInDynamicSegment::listingQuery($listing_data);
|
||||||
|
$data = $query->orderByAsc('email')->findMany();
|
||||||
|
expect($data)->count(2);
|
||||||
|
expect($data[0]->email)->equals('user-role-test1@example.com');
|
||||||
|
expect($data[1]->email)->equals('user-role-test3@example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testListingQueryWithSearch() {
|
||||||
|
$listing_data = [
|
||||||
|
'filter' => ['segment' => $this->dynamic_segment->id],
|
||||||
|
'group' => 'all',
|
||||||
|
'search' => 'user-role-test1',
|
||||||
|
];
|
||||||
|
$query = SubscribersInDynamicSegment::listingQuery($listing_data);
|
||||||
|
$data = $query->findMany();
|
||||||
|
expect($data)->count(1);
|
||||||
|
expect($data[0]->email)->equals('user-role-test1@example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
$this->cleanData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanData() {
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegment::$_table);
|
||||||
|
\ORM::raw_execute('TRUNCATE ' . DynamicSegmentFilter::$_table);
|
||||||
|
$emails = ['user-role-test1@example.com', 'user-role-test2@example.com', 'user-role-test3@example.com'];
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$user = get_user_by('email', $email);
|
||||||
|
if ($user) {
|
||||||
|
wp_delete_user($user->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user