Skip to content

Commit 87eccdf

Browse files
[framework] [frontend-api] universal product list (#2901)
2 parents 6d1e819 + 130293d commit 87eccdf

33 files changed

+888
-2
lines changed

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
},
2323
"require": {
2424
"php": "^8.1",
25+
"elasticsearch/elasticsearch": "^7.6.1",
2526
"lcobucci/jwt": "^4.1.5",
2627
"overblog/graphql-bundle": "^1.0",
2728
"overblog/graphiql-bundle": "^0.3",
29+
"overblog/dataloader-bundle": "^0.6.0",
2830
"shopsys/form-types-bundle": "14.0.x-dev",
2931
"shopsys/framework": "14.0.x-dev",
3032
"shopsys/migrations": "14.0.x-dev",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Component\Elasticsearch;
6+
7+
/**
8+
* @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html
9+
*/
10+
class MultipleSearchQuery
11+
{
12+
/**
13+
* @var array<int, mixed>
14+
*/
15+
protected array $body;
16+
17+
/**
18+
* @param string $indexName
19+
* @param \Shopsys\FrameworkBundle\Model\Product\Search\FilterQuery[] $filterQueries
20+
*/
21+
public function __construct(protected readonly string $indexName, array $filterQueries)
22+
{
23+
$this->body = $this->getBody($filterQueries);
24+
}
25+
26+
/**
27+
* @return array
28+
*/
29+
public function getQuery(): array
30+
{
31+
return [
32+
'index' => $this->indexName,
33+
'body' => $this->body,
34+
];
35+
}
36+
37+
/**
38+
* @param \Shopsys\FrameworkBundle\Model\Product\Search\FilterQuery[] $filterQueries
39+
* @return array
40+
*/
41+
protected function getBody(array $filterQueries): array
42+
{
43+
$body = [];
44+
45+
foreach ($filterQueries as $filterQuery) {
46+
$body[] = [];
47+
$body[] = $filterQuery->getQuery()['body'];
48+
}
49+
50+
return $body;
51+
}
52+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Component\Elasticsearch;
6+
7+
use Shopsys\FrameworkBundle\Component\Domain\Domain;
8+
use Shopsys\FrameworkBundle\Component\Elasticsearch\IndexDefinitionLoader;
9+
10+
class MultipleSearchQueryFactory
11+
{
12+
/**
13+
* @param \Shopsys\FrameworkBundle\Component\Elasticsearch\IndexDefinitionLoader $indexDefinitionLoader
14+
* @param \Shopsys\FrameworkBundle\Component\Domain\Domain $domain
15+
*/
16+
public function __construct(
17+
protected readonly IndexDefinitionLoader $indexDefinitionLoader,
18+
protected readonly Domain $domain,
19+
) {
20+
}
21+
22+
/**
23+
* @param string $indexName
24+
* @param \Shopsys\FrameworkBundle\Model\Product\Search\FilterQuery[] $filterQueries
25+
* @return \Shopsys\FrontendApiBundle\Component\Elasticsearch\MultipleSearchQuery
26+
*/
27+
public function create(string $indexName, array $filterQueries): MultipleSearchQuery
28+
{
29+
return new MultipleSearchQuery($this->getIndexAlias($indexName), $filterQueries);
30+
}
31+
32+
/**
33+
* @param string $indexName
34+
* @return string
35+
*/
36+
protected function getIndexAlias(string $indexName): string
37+
{
38+
return $this->indexDefinitionLoader->getIndexDefinition(
39+
$indexName,
40+
$this->domain->getId(),
41+
)->getIndexAlias();
42+
}
43+
}

src/Model/Mutation/Customer/User/CustomerUserMutation.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUserFacade;
1212
use Shopsys\FrameworkBundle\Model\Customer\User\CustomerUserPasswordFacade;
1313
use Shopsys\FrameworkBundle\Model\Customer\User\FrontendCustomerUserProvider;
14+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListFacade;
1415
use Shopsys\FrontendApiBundle\Model\Customer\User\CustomerUserDataFactory;
1516
use Shopsys\FrontendApiBundle\Model\Customer\User\CustomerUserUpdateDataFactory;
1617
use Shopsys\FrontendApiBundle\Model\Mutation\BaseTokenMutation;
@@ -31,6 +32,7 @@ class CustomerUserMutation extends BaseTokenMutation
3132
* @param \Shopsys\FrameworkBundle\Model\Customer\User\CustomerUserFacade $customerUserFacade
3233
* @param \Shopsys\FrontendApiBundle\Model\Customer\User\CustomerUserDataFactory $customerUserDataFactory
3334
* @param \Shopsys\FrontendApiBundle\Model\Token\TokenFacade $tokenFacade
35+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListFacade $productListFacade
3436
*/
3537
public function __construct(
3638
TokenStorageInterface $tokenStorage,
@@ -41,6 +43,7 @@ public function __construct(
4143
protected readonly CustomerUserFacade $customerUserFacade,
4244
protected readonly CustomerUserDataFactory $customerUserDataFactory,
4345
protected readonly TokenFacade $tokenFacade,
46+
protected readonly ProductListFacade $productListFacade,
4447
) {
4548
parent::__construct($tokenStorage);
4649
}
@@ -107,6 +110,8 @@ public function registerMutation(Argument $argument, InputValidator $validator):
107110

108111
$deviceId = Uuid::uuid4()->toString();
109112

113+
$this->productListFacade->mergeProductListsToCustomerUser($argument['input']['productListsUuids'], $customerUser);
114+
110115
return [
111116
'accessToken' => $this->tokenFacade->createAccessTokenAsString($customerUser, $deviceId),
112117
'refreshToken' => $this->tokenFacade->createRefreshTokenAsString($customerUser, $deviceId),

src/Model/Mutation/Login/LoginMutation.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Overblog\GraphQLBundle\Definition\Argument;
88
use Ramsey\Uuid\Uuid;
99
use Shopsys\FrameworkBundle\Model\Customer\User\FrontendCustomerUserProvider;
10+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListFacade;
1011
use Shopsys\FrontendApiBundle\Model\Mutation\AbstractMutation;
1112
use Shopsys\FrontendApiBundle\Model\Mutation\Customer\User\Exception\InvalidAccountOrPasswordUserError;
1213
use Shopsys\FrontendApiBundle\Model\Mutation\Customer\User\Exception\TooManyLoginAttemptsUserError;
@@ -24,13 +25,15 @@ class LoginMutation extends AbstractMutation
2425
* @param \Shopsys\FrontendApiBundle\Model\Token\TokenFacade $tokenFacade
2526
* @param \Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter $loginRateLimiter
2627
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
28+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListFacade $productListFacade
2729
*/
2830
public function __construct(
2931
protected readonly FrontendCustomerUserProvider $frontendCustomerUserProvider,
3032
protected readonly UserPasswordHasherInterface $userPasswordHasher,
3133
protected readonly TokenFacade $tokenFacade,
3234
protected readonly DefaultLoginRateLimiter $loginRateLimiter,
3335
protected readonly RequestStack $requestStack,
36+
protected readonly ProductListFacade $productListFacade,
3437
) {
3538
}
3639

@@ -64,6 +67,8 @@ public function loginMutation(Argument $argument): array
6467

6568
$this->loginRateLimiter->reset($this->requestStack->getCurrentRequest());
6669

70+
$this->productListFacade->mergeProductListsToCustomerUser($input['productListsUuids'], $user);
71+
6772
return [
6873
'accessToken' => $this->tokenFacade->createAccessTokenAsString($user, $deviceId),
6974
'refreshToken' => $this->tokenFacade->createRefreshTokenAsString($user, $deviceId),
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Mutation\ProductList\Exception;
6+
7+
use Overblog\GraphQLBundle\Error\UserError;
8+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnumInterface;
9+
use Shopsys\FrontendApiBundle\Model\Error\UserErrorWithCodeInterface;
10+
11+
class ProductAlreadyInListUserError extends UserError implements UserErrorWithCodeInterface
12+
{
13+
public const CODE = 'product-already-in-list';
14+
15+
/**
16+
* @param string $message
17+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnum $productListType
18+
*/
19+
public function __construct(
20+
string $message,
21+
protected readonly ProductListTypeEnumInterface $productListType,
22+
) {
23+
parent::__construct($message);
24+
}
25+
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function getUserErrorCode(): string
30+
{
31+
return ProductListUserErrorCodeHelper::getUserErrorCode($this->productListType, static::CODE);
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Mutation\ProductList\Exception;
6+
7+
use Overblog\GraphQLBundle\Error\UserError;
8+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnumInterface;
9+
use Shopsys\FrontendApiBundle\Model\Error\UserErrorWithCodeInterface;
10+
11+
class ProductListNotFoundUserError extends UserError implements UserErrorWithCodeInterface
12+
{
13+
public const CODE = 'product-list-not-found';
14+
15+
/**
16+
* @param string $message
17+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnum $productListType
18+
*/
19+
public function __construct(
20+
string $message,
21+
protected readonly ProductListTypeEnumInterface $productListType,
22+
) {
23+
parent::__construct($message);
24+
}
25+
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function getUserErrorCode(): string
30+
{
31+
return ProductListUserErrorCodeHelper::getUserErrorCode($this->productListType, static::CODE);
32+
}
33+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Mutation\ProductList\Exception;
6+
7+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnumInterface;
8+
9+
class ProductListUserErrorCodeHelper
10+
{
11+
/**
12+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnum $productListType
13+
* @param string $code
14+
* @return string
15+
*/
16+
public static function getUserErrorCode(ProductListTypeEnumInterface $productListType, string $code): string
17+
{
18+
return $productListType->value . '-' . $code;
19+
}
20+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrontendApiBundle\Model\Mutation\ProductList\Exception;
6+
7+
use Overblog\GraphQLBundle\Error\UserError;
8+
use Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnumInterface;
9+
use Shopsys\FrontendApiBundle\Model\Error\UserErrorWithCodeInterface;
10+
11+
class ProductNotInListUserError extends UserError implements UserErrorWithCodeInterface
12+
{
13+
public const CODE = 'product-not-in-list';
14+
15+
/**
16+
* @param string $message
17+
* @param \Shopsys\FrameworkBundle\Model\Product\List\ProductListTypeEnum $productListType
18+
*/
19+
public function __construct(
20+
string $message,
21+
protected readonly ProductListTypeEnumInterface $productListType,
22+
) {
23+
parent::__construct($message);
24+
}
25+
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function getUserErrorCode(): string
30+
{
31+
return ProductListUserErrorCodeHelper::getUserErrorCode($this->productListType, static::CODE);
32+
}
33+
}

0 commit comments

Comments
 (0)