vendor/boldr/shop-bundle/src/ShopContext.php line 153

Open in your IDE?
  1. <?php
  2. namespace Boldr\Shop\ShopBundle;
  3. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  4. use Symfony\Component\Security\Core\Security;
  5. use Symfony\Component\HttpFoundation\RequestStack;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Boldr\Shop\ShopBundle\Entity\{ Customer, Order };
  8. use Psr\Container\ContainerInterface;
  9. use Boldr\Shop\ShopBundle\OrderFlow\OrderFlowManagerInterface;
  10. class ShopContext implements ServiceSubscriberInterface
  11. {
  12. const GUEST_CUSTOMER_ID_SESSION = 'boldr_shop_guest_customer_id';
  13. const CART_ORDER_ID_SESSION = 'cart_order_id';
  14. public static function getSubscribedServices(): array
  15. {
  16. return [
  17. 'request_stack' => RequestStack::class,
  18. 'security' => Security::class,
  19. 'entity_manager' => EntityManagerInterface::class,
  20. 'order_flow_manager' => OrderFlowManagerInterface::class
  21. ];
  22. }
  23. private ContainerInterface $container;
  24. /** @var Customer|null Cached customer object */
  25. private ?Customer $customer = null;
  26. private string $defaultCurrency;
  27. private array $currencies;
  28. private ?Order $currentOrder = null;
  29. public function __construct(ContainerInterface $container, string $defaultCurrency, array $currencies)
  30. {
  31. $this->container = $container;
  32. $this->defaultCurrency = $defaultCurrency;
  33. $this->currencies = $currencies;
  34. }
  35. public function getSupportedCurrencies(): array
  36. {
  37. return $this->currencies;
  38. }
  39. public function getCurrency(): string
  40. {
  41. return $this->getCustomerCurrency($this->getCustomer());
  42. }
  43. private function getCustomerCurrency(?Customer $customer): string
  44. {
  45. $currency = $this->defaultCurrency;
  46. // If the Customer has a preferred currency set, verify it can be used.
  47. $preferredCurrency = $customer === null ? null : $customer->getPreferredCurrency();
  48. if ($preferredCurrency !== null)
  49. {
  50. // If the customer's preferred currency is available, use it for the order
  51. if (isset($this->currencies[$preferredCurrency]))
  52. {
  53. $currency = $preferredCurrency;
  54. }
  55. // Currency not available anymore, restore currency to default currency
  56. else
  57. {
  58. $customer->setPreferredCurrency($currency);
  59. }
  60. }
  61. return $currency;
  62. }
  63. private function createOrder(Customer $customer, string $state)
  64. {
  65. $currency = $this->getCurrency();
  66. $order = new Order($customer, $state, $currency);
  67. $customer->getOrders()->add($order);
  68. return $order;
  69. }
  70. public function getCurrentOrder(): Order
  71. {
  72. if (!isset($this->currentOrder))
  73. {
  74. $this->currentOrder = $this->_getCurrentOrder();
  75. }
  76. return $this->currentOrder;
  77. }
  78. public function _getCurrentOrder(): Order
  79. {
  80. $cartState = $this->container->get('order_flow_manager')->getCartState();
  81. // Get (or create) customer object
  82. $customer = $this->getCustomer(true);
  83. $session = $this->container->get('request_stack')->getSession();
  84. // If carts are stored in the session only
  85. // @TODO Make global option to share cart across the Customer
  86. if ($customer->getSeparateCartPerSession())
  87. {
  88. $em = $this->container->get('entity_manager');
  89. $session = $this->container->get('request_stack')->getSession();
  90. // Find the cart order if there is one in the session and it belongs to the customer
  91. $cartOrderId = $session->get(self::CART_ORDER_ID_SESSION, null);
  92. if ($cartOrderId !== null)
  93. {
  94. $orderRepository = $em->getRepository(Order::class);
  95. $cartOrder = $orderRepository->find($cartOrderId);
  96. if ($cartOrder !== null && $cartOrder->getCustomer() === $customer)
  97. {
  98. $cartOrder = $this->container->get('order_flow_manager')->getCurrentOrder($customer, [$cartOrder]);
  99. if ($cartOrder !== null)
  100. return $cartOrder;
  101. }
  102. }
  103. // If no cart was stored in the session, create a new cart and store it in the session
  104. $cartOrder = $this->createOrder($customer, $cartState);
  105. $em->flush();
  106. $session->set(self::CART_ORDER_ID_SESSION, $cartOrder->getId());
  107. return $cartOrder;
  108. }
  109. else
  110. {
  111. $orders = null;
  112. if ($session->has(self::CART_ORDER_ID_SESSION))
  113. {
  114. $cartOrderId = $session->get(self::CART_ORDER_ID_SESSION);
  115. $cartOrder = $customer->getOrders()->filter(fn($order) => $order->getId() == $cartOrderId)->first();
  116. if ($cartOrder !== false)
  117. {
  118. $orders = [$cartOrder];
  119. }
  120. }
  121. // If user is logged in as guest, only access current cart. If none selected, create.
  122. if ($session->has(self::GUEST_CUSTOMER_ID_SESSION))
  123. {
  124. $cartOrder = null;
  125. if ($orders !== null)
  126. {
  127. $cartOrder = $this->container->get('order_flow_manager')->getCurrentOrder($customer, $orders);
  128. }
  129. if ($cartOrder === null)
  130. {
  131. $cartOrder = $this->createOrder($customer, $cartState);
  132. $this->container->get('entity_manager')->flush();
  133. $session->set(self::CART_ORDER_ID_SESSION, $cartOrder->getId());
  134. return $cartOrder;
  135. }
  136. }
  137. // Find Order with cart state
  138. $cartOrder = $this->container->get('order_flow_manager')->getCurrentOrder($customer, $orders);
  139. // Create a new order if no cart order exists yet
  140. if ($cartOrder === null)
  141. {
  142. if ($session->has(self::CART_ORDER_ID_SESSION))
  143. {
  144. $session->remove(self::CART_ORDER_ID_SESSION);
  145. $cartOrder = $this->container->get('order_flow_manager')->getCurrentOrder($customer);
  146. }
  147. if ($cartOrder === null)
  148. {
  149. $cartOrder = $this->createOrder($customer, $cartState);
  150. }
  151. }
  152. return $cartOrder;
  153. }
  154. }
  155. public function getCustomer(bool $createIfNotExists = false): ?Customer
  156. {
  157. if ($this->customer !== null)
  158. {
  159. return $this->customer;
  160. }
  161. $em = $this->container->get('entity_manager');
  162. $repoCustomers = $em->getRepository(Customer::class);
  163. $session = $this->container->get('request_stack')->getSession();
  164. // 1. Check for user customer
  165. $user = $this->container->get('security')->getUser();
  166. if ($user !== null)
  167. {
  168. $customer = $repoCustomers->createQueryBuilder('c')
  169. ->leftJoin('c.customerUsers', 'cu')
  170. ->leftJoin('cu.user', 'u')
  171. ->where('u = ?1')
  172. ->setParameter(1, $user)
  173. ->setMaxResults(1)
  174. ->getQuery()
  175. ->getOneOrNullResult();
  176. if ($customer !== null)
  177. {
  178. if ($session->has(self::GUEST_CUSTOMER_ID_SESSION))
  179. {
  180. $id = $session->get(self::GUEST_CUSTOMER_ID_SESSION);
  181. $guestCustomer = $repoCustomers->find($id);
  182. if ($guestCustomer !== null)
  183. {
  184. // Transfer current order to other customer
  185. $currentOrder = $this->container->get('order_flow_manager')->getCurrentOrder($guestCustomer);
  186. if ($currentOrder !== null)
  187. {
  188. $currentOrder->setCustomer($customer);
  189. $customer->getOrders()->add($currentOrder);
  190. $session->set(self::CART_ORDER_ID_SESSION, $currentOrder->getId());
  191. }
  192. $em->flush();
  193. }
  194. }
  195. $this->customer = $customer;
  196. return $customer;
  197. }
  198. }
  199. // 2. Check for guest customer
  200. if ($session->has(self::GUEST_CUSTOMER_ID_SESSION))
  201. {
  202. $id = $session->get(self::GUEST_CUSTOMER_ID_SESSION);
  203. $customer = $repoCustomers->find($id);
  204. if ($customer !== null)
  205. {
  206. if ($customer->getUsers()->count() !== 0)
  207. {
  208. $session->remove(self::GUEST_CUSTOMER_ID_SESSION);
  209. }
  210. else
  211. {
  212. if ($customer !== null)
  213. {
  214. // 2.1. Attach guest customer to user if logged in
  215. if ($user !== null)
  216. {
  217. $customer->addUser($user);
  218. $em->flush($customer);
  219. }
  220. $this->customer = $customer;
  221. return $customer;
  222. }
  223. }
  224. }
  225. }
  226. // If a customer is not really necessary, just return null
  227. if (!$createIfNotExists)
  228. {
  229. return null;
  230. }
  231. // If a customer object is neccessary for data persistence, e.g. when adding products to the cart
  232. // create a new customer object and store it in the session
  233. // 3. Create a new customer
  234. $session = $this->container->get('request_stack')->getSession();
  235. $locale = $this->container->get('request_stack')->getCurrentRequest()->getLocale();
  236. $newCustomer = new Customer();
  237. $newCustomer->setLocale($locale);
  238. $em->persist($newCustomer);
  239. $this->customer = $newCustomer;
  240. // 3.1. Attach the customer to the user if logged in
  241. if ($user !== null)
  242. {
  243. $newCustomer->addUser($user);
  244. $em->flush($newCustomer);
  245. return $newCustomer;
  246. }
  247. // 3.2. Store the new guest customer in the session
  248. // Obtain an ID
  249. $em->flush($newCustomer);
  250. $id = $newCustomer->getId();
  251. $session->set(self::GUEST_CUSTOMER_ID_SESSION, $id);
  252. return $newCustomer;
  253. }
  254. public function setGuestCustomer(Customer $customer): void
  255. {
  256. $session = $this->container->get('request_stack')->getSession();
  257. $session->set(self::GUEST_CUSTOMER_ID_SESSION, $customer->getId());
  258. }
  259. }