diff --git a/lib/DI/ContainerConfigurator.php b/lib/DI/ContainerConfigurator.php index 517ab0fa0f..3df2f5a7ee 100644 --- a/lib/DI/ContainerConfigurator.php +++ b/lib/DI/ContainerConfigurator.php @@ -256,6 +256,7 @@ class ContainerConfigurator implements IContainerConfigurator { $container->autowire(\MailPoet\Segments\WooCommerce::class)->setPublic(true); $container->autowire(\MailPoet\Segments\SubscribersFinder::class); $container->autowire(\MailPoet\Segments\SegmentsRepository::class); + $container->autowire(\MailPoet\Segments\DynamicSegments\Filters\UserRole::class)->setPublic(true); // Services $container->autowire(\MailPoet\Services\Bridge::class)->setPublic(true); $container->autowire(\MailPoet\Services\AuthorizedEmailsController::class); diff --git a/lib/Entities/DynamicSegmentFilterEntity.php b/lib/Entities/DynamicSegmentFilterEntity.php index 3a09bbbcd2..60e74ffe14 100644 --- a/lib/Entities/DynamicSegmentFilterEntity.php +++ b/lib/Entities/DynamicSegmentFilterEntity.php @@ -18,6 +18,8 @@ class DynamicSegmentFilterEntity { use UpdatedAtTrait; use SafeToOneAssociationLoadTrait; + const TYPE_USER_ROLE = 'userRole'; + /** * @ORM\ManyToOne(targetEntity="MailPoet\Entities\SegmentEntity", inversedBy="filters") * @var SegmentEntity|null diff --git a/lib/Segments/DynamicSegments/Filters/Filter.php b/lib/Segments/DynamicSegments/Filters/Filter.php index 53e4741175..7869eea462 100644 --- a/lib/Segments/DynamicSegments/Filters/Filter.php +++ b/lib/Segments/DynamicSegments/Filters/Filter.php @@ -2,8 +2,9 @@ namespace MailPoet\Segments\DynamicSegments\Filters; +use MailPoet\Entities\DynamicSegmentFilterEntity; use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder; interface Filter { - public function apply(QueryBuilder $queryBuilder): QueryBuilder; + public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder; } diff --git a/lib/Segments/DynamicSegments/Filters/UserRole.php b/lib/Segments/DynamicSegments/Filters/UserRole.php index 54a7e41fc1..4e19586d69 100644 --- a/lib/Segments/DynamicSegments/Filters/UserRole.php +++ b/lib/Segments/DynamicSegments/Filters/UserRole.php @@ -2,17 +2,31 @@ namespace MailPoet\Segments\DynamicSegments\Filters; +use MailPoet\Entities\DynamicSegmentFilterEntity; +use MailPoet\Entities\SubscriberEntity; +use MailPoet\Segments\DynamicSegments\Exceptions\InvalidFilterException; use MailPoetVendor\Doctrine\DBAL\Query\QueryBuilder; +use MailPoetVendor\Doctrine\ORM\EntityManager; class UserRole implements Filter { - /** @var string */ - private $role; + /** @var EntityManager */ + private $entityManager; - public function __construct(string $role) { - $this->role = $role; + public function __construct(EntityManager $entityManager) { + $this->entityManager = $entityManager; } - public function apply(QueryBuilder $queryBuilder): QueryBuilder { - return $queryBuilder; + public function apply(QueryBuilder $queryBuilder, DynamicSegmentFilterEntity $filterEntity): QueryBuilder { + global $wpdb; + $role = $filterEntity->getFilterDataParam('wordpressRole'); + if (!$role) { + throw new InvalidFilterException('Missing role', InvalidFilterException::MISSING_ROLE); + } + + $subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName(); + return $queryBuilder->join($subscribersTable, $wpdb->users, 'wpusers', "$subscribersTable.wp_user_id = wpusers.id") + ->join('wpusers', $wpdb->usermeta, 'wpusermeta', 'wpusers.id = wpusermeta.user_id') + ->andWhere("wpusermeta.meta_key = '{$wpdb->prefix}capabilities' AND wpusermeta.meta_value LIKE :role") + ->setParameter(':role', '%"' . $role . '"%'); } } diff --git a/tests/integration/Segments/DynamicSegments/Filters/UserRoleTest.php b/tests/integration/Segments/DynamicSegments/Filters/UserRoleTest.php new file mode 100644 index 0000000000..093bd593e2 --- /dev/null +++ b/tests/integration/Segments/DynamicSegments/Filters/UserRoleTest.php @@ -0,0 +1,92 @@ +userRole = $this->diContainer->get(UserRole::class); + $this->cleanWpUsers(); + // Insert WP users and subscribers are created automatically + 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', + ]); + } + + public function testItAppliesFilter() { + $segmentFilter = $this->getSegmentFilter('editor'); + $queryBuilder = $this->userRole->apply($this->getQueryBuilder(), $segmentFilter); + $result = $queryBuilder->execute()->fetchAll(); + expect(count($result))->equals(2); + $subscriber1 = $this->entityManager->find(SubscriberEntity::class, $result[0]['id']); + assert($subscriber1 instanceof SubscriberEntity); + $subscriber2 = $this->entityManager->find(SubscriberEntity::class, $result[1]['id']); + assert($subscriber2 instanceof SubscriberEntity); + expect($subscriber1->getEmail())->equals('user-role-test1@example.com'); + expect($subscriber2->getEmail())->equals('user-role-test3@example.com'); + } + + public function testItDoesntGetSubString() { + $segmentFilter = $this->getSegmentFilter('edit'); + $queryBuilder = $this->userRole->apply($this->getQueryBuilder(), $segmentFilter); + $result = $queryBuilder->execute()->fetchAll(); + expect(count($result))->equals(0); + } + + private function getQueryBuilder() { + $subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName(); + return $this->entityManager + ->getConnection() + ->createQueryBuilder() + ->select("$subscribersTable.id") + ->from($subscribersTable); + } + + private function getSegmentFilter(string $role): DynamicSegmentFilterEntity { + return new DynamicSegmentFilterEntity( + new SegmentEntity('segment', SegmentEntity::TYPE_DYNAMIC), + [ + 'segmentType' => DynamicSegmentFilterEntity::TYPE_USER_ROLE, + 'wordpressRole' => $role, + ] + ); + } + + public function _after() { + $this->cleanWpUsers(); + $this->truncateEntity(SubscriberEntity::class); + } + + private function cleanWpUsers() { + $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); + } + } + } +}