Add support for more product ids in filter
[MAILPOET-3954]
This commit is contained in:
@ -150,6 +150,8 @@ class DynamicSegments extends APIEndpoint {
|
|||||||
return WPFunctions::get()->__('Please select a type for the comparison, an amount and a number of days.', 'mailpoet');
|
return WPFunctions::get()->__('Please select a type for the comparison, an amount and a number of days.', 'mailpoet');
|
||||||
case InvalidFilterException::MISSING_FILTER:
|
case InvalidFilterException::MISSING_FILTER:
|
||||||
return WPFunctions::get()->__('Please add at least one condition for filtering.', 'mailpoet');
|
return WPFunctions::get()->__('Please add at least one condition for filtering.', 'mailpoet');
|
||||||
|
case InvalidFilterException::MISSING_OPERATOR:
|
||||||
|
return WPFunctions::get()->__('Please select a type for the comparison.', 'mailpoet');
|
||||||
default:
|
default:
|
||||||
return WPFunctions::get()->__('An error occurred while saving data.', 'mailpoet');
|
return WPFunctions::get()->__('An error occurred while saving data.', 'mailpoet');
|
||||||
}
|
}
|
||||||
|
@ -19,4 +19,5 @@ class InvalidFilterException extends InvalidStateException {
|
|||||||
const INVALID_DATE_VALUE = 12;
|
const INVALID_DATE_VALUE = 12;
|
||||||
const MISSING_COUNTRY = 13;
|
const MISSING_COUNTRY = 13;
|
||||||
const MISSING_FILTER = 14;
|
const MISSING_FILTER = 14;
|
||||||
|
const MISSING_OPERATOR = 15;
|
||||||
};
|
};
|
||||||
|
@ -171,8 +171,10 @@ class FilterDataMapper {
|
|||||||
if (!isset($data['category_id'])) throw new InvalidFilterException('Missing category', InvalidFilterException::MISSING_CATEGORY_ID);
|
if (!isset($data['category_id'])) throw new InvalidFilterException('Missing category', InvalidFilterException::MISSING_CATEGORY_ID);
|
||||||
$filterData['category_id'] = $data['category_id'];
|
$filterData['category_id'] = $data['category_id'];
|
||||||
} elseif ($data['action'] === WooCommerceProduct::ACTION_PRODUCT) {
|
} elseif ($data['action'] === WooCommerceProduct::ACTION_PRODUCT) {
|
||||||
if (!isset($data['product_id'])) throw new InvalidFilterException('Missing product', InvalidFilterException::MISSING_PRODUCT_ID);
|
if (!isset($data['product_ids'])) throw new InvalidFilterException('Missing product', InvalidFilterException::MISSING_PRODUCT_ID);
|
||||||
$filterData['product_id'] = $data['product_id'];
|
if (!isset($data['operator'])) throw new InvalidFilterException('Missing operator', InvalidFilterException::MISSING_OPERATOR);
|
||||||
|
$filterData['operator'] = $data['operator'];
|
||||||
|
$filterData['product_ids'] = $data['product_ids'];
|
||||||
} elseif ($data['action'] === WooCommerceCountry::ACTION_CUSTOMER_COUNTRY) {
|
} elseif ($data['action'] === WooCommerceCountry::ACTION_CUSTOMER_COUNTRY) {
|
||||||
if (!isset($data['country_code'])) throw new InvalidFilterException('Missing country', InvalidFilterException::MISSING_COUNTRY);
|
if (!isset($data['country_code'])) throw new InvalidFilterException('Missing country', InvalidFilterException::MISSING_COUNTRY);
|
||||||
$filterData['country_code'] = $data['country_code'];
|
$filterData['country_code'] = $data['country_code'];
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<?php
|
<?php declare(strict_types = 1);
|
||||||
|
|
||||||
namespace MailPoet\Segments\DynamicSegments\Filters;
|
namespace MailPoet\Segments\DynamicSegments\Filters;
|
||||||
|
|
||||||
|
use MailPoet\Entities\DynamicSegmentFilterData;
|
||||||
use MailPoet\Entities\DynamicSegmentFilterEntity;
|
use MailPoet\Entities\DynamicSegmentFilterEntity;
|
||||||
use MailPoet\Entities\SubscriberEntity;
|
use MailPoet\Entities\SubscriberEntity;
|
||||||
use MailPoet\Util\Security;
|
use MailPoet\Util\Security;
|
||||||
|
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||||
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
|
use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder;
|
||||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
@ -23,24 +25,79 @@ class WooCommerceProduct implements Filter {
|
|||||||
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filter): QueryBuilder {
|
public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filter): QueryBuilder {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$filterData = $filter->getFilterData();
|
$filterData = $filter->getFilterData();
|
||||||
$productId = (int)$filterData->getParam('product_id');
|
$operator = $filterData->getOperator();
|
||||||
|
$productIds = $filterData->getParam('product_ids');
|
||||||
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
||||||
$parameterSuffix = $filter->getId() ?? Security::generateRandomString();
|
$parameterSuffix = $filter->getId() ?? Security::generateRandomString();
|
||||||
|
$completedOrder = "postmeta.post_id NOT IN ( SELECT id FROM {$wpdb->posts} AS p WHERE p.post_status IN ('wc-cancelled', 'wc-failed'))";
|
||||||
|
|
||||||
|
if ($operator === DynamicSegmentFilterData::OPERATOR_ANY) {
|
||||||
|
$this->applyPostmetaJoin($queryBuilder);
|
||||||
|
$this->applyOrderItemsJoin($queryBuilder);
|
||||||
|
$this->applyOrderItemmetaJoin($queryBuilder);
|
||||||
|
$queryBuilder->where("itemmeta.meta_value IN (:products_{$parameterSuffix})");
|
||||||
|
|
||||||
|
} elseif ($operator === DynamicSegmentFilterData::OPERATOR_ALL) {
|
||||||
|
$this->applyPostmetaJoin($queryBuilder);
|
||||||
|
$this->applyOrderItemsJoin($queryBuilder);
|
||||||
|
$this->applyOrderItemmetaJoin($queryBuilder);
|
||||||
|
$queryBuilder->where("itemmeta.meta_value IN (:products_{$parameterSuffix})")
|
||||||
|
->groupBy("{$subscribersTable}.id, items.order_id")
|
||||||
|
->having('COUNT(items.order_id) = :count')
|
||||||
|
->setParameter('count', count($productIds));
|
||||||
|
|
||||||
|
} elseif ($operator === DynamicSegmentFilterData::OPERATOR_NONE) {
|
||||||
|
$this->applyPostmetaJoin($queryBuilder);
|
||||||
|
$this->applyOrderItemsJoin($queryBuilder);
|
||||||
|
// subQuery with subscriber ids that bought products
|
||||||
|
$subQuery = $this->createQueryBuilder($subscribersTable);
|
||||||
|
$subQuery->select("DISTINCT $subscribersTable.id");
|
||||||
|
$subQuery = $this->applyPostmetaJoin($subQuery);
|
||||||
|
$subQuery = $this->applyOrderItemsJoin($subQuery);
|
||||||
|
$subQuery = $this->applyOrderItemmetaJoin($subQuery);
|
||||||
|
$subQuery->where("itemmeta.meta_value IN (:products_{$parameterSuffix})")
|
||||||
|
->andWhere($completedOrder);
|
||||||
|
// application subQuery for negation
|
||||||
|
$queryBuilder->where("{$subscribersTable}.id NOT IN ({$subQuery->getSQL()})");
|
||||||
|
}
|
||||||
|
return $queryBuilder
|
||||||
|
->andWhere($completedOrder)
|
||||||
|
->setParameter("products_{$parameterSuffix}", $productIds, Connection::PARAM_STR_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyPostmetaJoin(QueryBuilder $queryBuilder): QueryBuilder {
|
||||||
|
global $wpdb;
|
||||||
|
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
||||||
return $queryBuilder->innerJoin(
|
return $queryBuilder->innerJoin(
|
||||||
$subscribersTable,
|
$subscribersTable,
|
||||||
$wpdb->postmeta,
|
$wpdb->postmeta,
|
||||||
'postmeta',
|
'postmeta',
|
||||||
"postmeta.meta_key = '_customer_user' AND $subscribersTable.wp_user_id=postmeta.meta_value"
|
"postmeta.meta_key = '_customer_user' AND $subscribersTable.wp_user_id=postmeta.meta_value"
|
||||||
)->join('postmeta',
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyOrderItemsJoin(QueryBuilder $queryBuilder): QueryBuilder {
|
||||||
|
global $wpdb;
|
||||||
|
return $queryBuilder->join('postmeta',
|
||||||
$wpdb->prefix . 'woocommerce_order_items',
|
$wpdb->prefix . 'woocommerce_order_items',
|
||||||
'items',
|
'items',
|
||||||
'postmeta.post_id = items.order_id'
|
'postmeta.post_id = items.order_id'
|
||||||
)->innerJoin(
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyOrderItemmetaJoin(QueryBuilder $queryBuilder): QueryBuilder {
|
||||||
|
global $wpdb;
|
||||||
|
return $queryBuilder->innerJoin(
|
||||||
'items',
|
'items',
|
||||||
$wpdb->prefix . 'woocommerce_order_itemmeta',
|
$wpdb->prefix . 'woocommerce_order_itemmeta',
|
||||||
'itemmeta',
|
'itemmeta',
|
||||||
"itemmeta.order_item_id=items.order_item_id AND itemmeta.meta_key='_product_id' AND itemmeta.meta_value=:product" . $parameterSuffix
|
"itemmeta.order_item_id=items.order_item_id AND itemmeta.meta_key='_product_id'"
|
||||||
)->andWhere('postmeta.post_id NOT IN ( SELECT id FROM ' . $wpdb->posts . ' as p WHERE p.post_status IN ("wc-cancelled", "wc-failed"))'
|
);
|
||||||
)->setParameter('product' . $parameterSuffix, $productId);
|
}
|
||||||
|
|
||||||
|
private function createQueryBuilder(string $table): QueryBuilder {
|
||||||
|
return $this->entityManager->getConnection()
|
||||||
|
->createQueryBuilder()
|
||||||
|
->from($table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user