44
55namespace Shopsys \FrontendApiBundle \Model \Resolver \Transport ;
66
7+ use ArrayObject ;
8+ use Shopsys \FrameworkBundle \Component \Cache \InMemoryCache ;
9+ use Shopsys \FrameworkBundle \Model \Cart \Cart ;
710use Shopsys \FrameworkBundle \Model \Customer \User \CurrentCustomerUser ;
11+ use Shopsys \FrameworkBundle \Model \Transport \Transport ;
812use Shopsys \FrameworkBundle \Model \Transport \TransportFacade ;
13+ use Shopsys \FrameworkBundle \Model \Transport \TransportUnavailabilityReasonInCartEnum ;
14+ use Shopsys \FrameworkBundle \Model \Transport \TransportVisibilityCalculation ;
15+ use Shopsys \FrontendApiBundle \Component \GqlContext \GqlContextHelper ;
916use Shopsys \FrontendApiBundle \Model \Cart \CartApiFacade ;
1017use Shopsys \FrontendApiBundle \Model \Resolver \AbstractQuery ;
1118
1219class TransportsQuery extends AbstractQuery
1320{
21+ protected const string CART_CACHE_NAMESPACE = 'transportsQueryCart ' ;
22+ protected const string EXCLUDING_PRODUCTS_CACHE_NAMESPACE = 'transportsQueryExcludingProductsByTransportId ' ;
23+ protected const string CURRENT_CUSTOMER_CART_CACHE_KEY = 'currentCustomerCart ' ;
24+
1425 public function __construct (
1526 protected readonly TransportFacade $ transportFacade ,
1627 protected readonly CartApiFacade $ cartApiFacade ,
1728 protected readonly CurrentCustomerUser $ currentCustomerUser ,
29+ protected readonly GqlContextHelper $ gqlContextHelper ,
30+ protected readonly InMemoryCache $ inMemoryCache ,
31+ protected readonly TransportVisibilityCalculation $ transportVisibilityCalculation ,
1832 ) {
1933 }
2034
@@ -23,18 +37,112 @@ public function __construct(
2337 */
2438 public function transportsQuery (?string $ cartUuid = null ): array
2539 {
26- $ customerUser = $ this ->currentCustomerUser -> findCurrentCustomerUser ( );
40+ $ cart = $ this ->findCart ( $ cartUuid );
2741
28- if ($ customerUser === null && $ cartUuid === null ) {
42+ if ($ cart === null ) {
2943 return $ this ->transportFacade ->getVisibleOnCurrentDomainWithEagerLoadedDomainsAndTranslations ();
3044 }
3145
32- $ cart = $ this ->cartApiFacade ->findCart ($ customerUser , $ cartUuid );
46+ $ transports = $ this ->transportFacade ->getVisibleOnCurrentDomainWithEagerLoadedDomainsAndTranslations ($ cart );
47+
48+ return $ this ->sortAvailableTransportsFirst ($ transports , $ cart , $ cartUuid );
49+ }
50+
51+ /**
52+ * @return array<int, array{reason: string, products: \Shopsys\FrameworkBundle\Model\Product\Product[]}>
53+ */
54+ public function transportProductsBlockingSelectionInCartQuery (
55+ Transport $ transport ,
56+ ?string $ cartUuid = null ,
57+ ?ArrayObject $ context = null ,
58+ ): array {
59+ $ resolvedCartUuid = $ cartUuid ?? $ this ->gqlContextHelper ->getCartUuid ($ context );
60+ $ cart = $ this ->findCart ($ resolvedCartUuid );
3361
3462 if ($ cart === null ) {
35- return $ this ->transportFacade ->getVisibleOnCurrentDomainWithEagerLoadedDomainsAndTranslations ();
63+ return [];
64+ }
65+
66+ return $ this ->getProductsBlockingSelectionGroupedByReason ($ transport , $ cart , $ resolvedCartUuid );
67+ }
68+
69+ /**
70+ * @return array<int, array{reason: string, products: \Shopsys\FrameworkBundle\Model\Product\Product[]}>
71+ */
72+ protected function getProductsBlockingSelectionGroupedByReason (
73+ Transport $ transport ,
74+ Cart $ cart ,
75+ ?string $ cartUuid ,
76+ ): array {
77+ $ productsGroupedByReason = [];
78+
79+ $ excludingProducts = $ this ->getExcludingProductsByTransportId ($ cart , $ cartUuid )[$ transport ->getId ()] ?? [];
80+
81+ if ($ excludingProducts !== []) {
82+ $ productsGroupedByReason [] = [
83+ 'reason ' => TransportUnavailabilityReasonInCartEnum::EXCLUDED_FOR_PRODUCT ,
84+ 'products ' => $ excludingProducts ,
85+ ];
86+ }
87+
88+ $ personalPickupOnlyProducts = array_values ($ cart ->getPersonalPickupOnlyProducts ());
89+
90+ if (!$ transport ->isPersonalPickup () && $ personalPickupOnlyProducts !== []) {
91+ $ productsGroupedByReason [] = [
92+ 'reason ' => TransportUnavailabilityReasonInCartEnum::PERSONAL_PICKUP_REQUIRED ,
93+ 'products ' => $ personalPickupOnlyProducts ,
94+ ];
95+ }
96+
97+ return $ productsGroupedByReason ;
98+ }
99+
100+ protected function findCart (?string $ cartUuid ): ?Cart
101+ {
102+ return $ this ->inMemoryCache ->getOrSaveValue (
103+ self ::CART_CACHE_NAMESPACE ,
104+ function () use ($ cartUuid ): ?Cart {
105+ $ customerUser = $ this ->currentCustomerUser ->findCurrentCustomerUser ();
106+
107+ if ($ customerUser === null && $ cartUuid === null ) {
108+ return null ;
109+ }
110+
111+ return $ this ->cartApiFacade ->findCart ($ customerUser , $ cartUuid );
112+ },
113+ $ cartUuid ?? self ::CURRENT_CUSTOMER_CART_CACHE_KEY ,
114+ );
115+ }
116+
117+ /**
118+ * @return array<int, \Shopsys\FrameworkBundle\Model\Product\Product[]>
119+ */
120+ protected function getExcludingProductsByTransportId (Cart $ cart , ?string $ cartUuid ): array
121+ {
122+ return $ this ->inMemoryCache ->getOrSaveValue (
123+ self ::EXCLUDING_PRODUCTS_CACHE_NAMESPACE ,
124+ fn (): array => $ this ->transportVisibilityCalculation ->getExcludingProductsByTransportIdForCart ($ cart ),
125+ $ cartUuid ?? self ::CURRENT_CUSTOMER_CART_CACHE_KEY ,
126+ );
127+ }
128+
129+ /**
130+ * @param \Shopsys\FrameworkBundle\Model\Transport\Transport[] $transports
131+ * @return \Shopsys\FrameworkBundle\Model\Transport\Transport[]
132+ */
133+ protected function sortAvailableTransportsFirst (array $ transports , Cart $ cart , ?string $ cartUuid ): array
134+ {
135+ $ availableTransports = [];
136+ $ unavailableTransports = [];
137+
138+ foreach ($ transports as $ transport ) {
139+ if ($ this ->getProductsBlockingSelectionGroupedByReason ($ transport , $ cart , $ cartUuid ) === []) {
140+ $ availableTransports [] = $ transport ;
141+ } else {
142+ $ unavailableTransports [] = $ transport ;
143+ }
36144 }
37145
38- return $ this -> transportFacade -> getVisibleOnCurrentDomainWithEagerLoadedDomainsAndTranslations ( $ cart ) ;
146+ return [... $ availableTransports , ... $ unavailableTransports ] ;
39147 }
40148}
0 commit comments