PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Domain/Product/Repository/OfferRepository.php

https://gitlab.com/snips3/rfpr
PHP | 462 lines | 389 code | 63 blank | 10 comment | 7 complexity | 7ca5c4a4fb97aed5bdbd2e9377f2cc86 MD5 | raw file
  1. <?php
  2. namespace App\Domain\Product\Repository;
  3. use App\Domain\Category\Entity\Category;
  4. use App\Domain\City\Entity\City;
  5. use App\Domain\Product\Collection\OfferCollection;
  6. use App\Domain\Product\Entity\Offer;
  7. use App\Domain\Product\Entity\Product;
  8. use App\Domain\Product\Entity\Price;
  9. use App\Domain\Product\Entity\ProductInfo;
  10. use App\Domain\Shop\Entity\Shop;
  11. use App\Traits\QueryBuilderTrait;
  12. use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
  13. use Doctrine\ORM\Query\Expr\Join;
  14. use Doctrine\ORM\QueryBuilder;
  15. use Doctrine\Persistence\ManagerRegistry;
  16. /**
  17. * @method Offer|null find($id, $lockMode = null, $lockVersion = null)
  18. * @method Offer|null findOneBy(array $criteria, array $orderBy = null)
  19. * @method Offer[] findAll()
  20. */
  21. class OfferRepository extends ServiceEntityRepository
  22. {
  23. use QueryBuilderTrait;
  24. public function __construct(ManagerRegistry $registry)
  25. {
  26. parent::__construct($registry, Offer::class);
  27. }
  28. public function findBy(
  29. array $criteria,
  30. array $orderBy = null,
  31. $limit = null,
  32. $offset = null
  33. ): OfferCollection {
  34. return new OfferCollection(
  35. parent::findBy(
  36. $criteria,
  37. $orderBy,
  38. $limit,
  39. $offset
  40. )
  41. );
  42. }
  43. public function getProductsWithOffersByCityAndCategory(City $city, Category $category): array
  44. {
  45. $offers = [];
  46. $data = $this->getOffersByCityAndCategory($city, $category);
  47. foreach ($data as $offer) {
  48. $offers[$offer['product_id']][$offer['id']] = $offer;
  49. unset($offers[$offer['product_id']][$offer['id']]['product_id']);
  50. }
  51. $products = $this->getProductsByIds(array_keys($offers));
  52. foreach ($products as &$row) {
  53. $row['offers'] = array_values($offers[$row['id']]);
  54. }
  55. return $products;
  56. }
  57. public function getProductsWithOffersByCityAndQuery(City $city, string $query, ?int $offset = 0): array
  58. {
  59. $offers = [];
  60. $data = $this->getOffersByCityAndQuery($city, $query, $offset);
  61. foreach ($data as $offer) {
  62. $offers[$offer['product_id']][$offer['id']] = $offer;
  63. unset($offers[$offer['product_id']][$offer['id']]['product_id']);
  64. }
  65. $products = $this->getProductsByIds(array_keys($offers));
  66. foreach ($products as &$row) {
  67. $row['offers'] = array_values($offers[$row['id']]);
  68. }
  69. return $products;
  70. }
  71. public function getOffersByCityAndCategory(City $city, Category $category): array
  72. {
  73. $shopsIds = $city->getShops()->getIds();
  74. $categoryIds = $category->getIds();
  75. $qb = $this->getEntityManager()->createQueryBuilder();
  76. $qb
  77. ->select('offer')
  78. ->addSelect('partial price.{id, shop, quantity, actual, old}')
  79. ->from(Price::class, 'price')
  80. ->join(
  81. Offer::class,
  82. 'offer',
  83. Join::WITH,
  84. $qb->expr()->eq('price.offer', 'offer')
  85. )
  86. ->join(
  87. Product::class,
  88. 'product',
  89. Join::WITH,
  90. $qb->expr()->andX(
  91. $qb->expr()->in('product.category', $categoryIds),
  92. $qb->expr()->eq('product', 'offer.product'),
  93. )
  94. )
  95. ->where($qb->expr()->in('price.shop', $shopsIds));
  96. $sql = $qb->getQuery()->getSQL();
  97. $result = $this->getEntityManager()
  98. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  99. $result = $this->clearKeys($result);
  100. $offers = [];
  101. foreach ($result as $row) {
  102. if (empty($offers[$row['product_id']][$row['id']])) {
  103. $offers[$row['id']] = array_filter([
  104. 'id' => (int) $row['id'],
  105. 'name' => $row['name'],
  106. 'product_id' => (int) $row['product_id'],
  107. 'barcode' => $row['bar_code'],
  108. ]);
  109. }
  110. $offers[$row['id']]['prices'][] = array_filter([
  111. 'actual' => (int) $row['actual'],
  112. 'old' => (int) $row['old'],
  113. 'shop' => (int) $row['shop_id'],
  114. ]);
  115. }
  116. return $offers;
  117. }
  118. public function getOffersByCityAndQuery(City $city, string $query, ?int $offset = 0): array
  119. {
  120. $shopsIds = $city->getShops()->map(function (Shop $shop): int {
  121. return $shop->getId();
  122. })->toArray();
  123. sort($shopsIds);
  124. $qb = $this->getEntityManager()->createQueryBuilder();
  125. $qb
  126. ->select('offer')
  127. ->addSelect('partial price.{id, shop, quantity, actual, old}')
  128. ->from(Price::class, 'price')
  129. ->join(
  130. Offer::class,
  131. 'offer',
  132. Join::WITH,
  133. $qb->expr()->eq('price.offer', 'offer')
  134. )
  135. ->join(
  136. Product::class,
  137. 'product',
  138. Join::WITH,
  139. 'product = offer.product'
  140. )
  141. ->join(
  142. ProductInfo::class,
  143. 'info',
  144. Join::WITH,
  145. 'info.product = product AND info.name LIKE \'%:query%\''
  146. )
  147. ->where($qb->expr()->in('price.shop', $shopsIds))
  148. ->setMaxResults(60)
  149. ->setFirstResult($offset);
  150. $qb->set(':query', $query);
  151. $sql = $qb->getQuery()->getSQL();
  152. $result = $this->getEntityManager()
  153. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  154. $result = $this->clearKeys($result);
  155. $offers = [];
  156. foreach ($result as $row) {
  157. if (empty($offers[$row['product_id']][$row['id']])) {
  158. $offers[$row['id']] = [
  159. 'id' => (int) $row['id'],
  160. 'product_id' => $row['product_id'],
  161. 'barcode' => $row['bar_code'],
  162. ];
  163. }
  164. $offers[$row['id']]['prices'][] = [
  165. 'actual' => (int) $row['actual'],
  166. 'old' => (int) $row['old'],
  167. 'shop' => (int) $row['shop_id'],
  168. ];
  169. }
  170. return $offers;
  171. }
  172. public function getOffersByCityAndProduct(City $city, Product $product): array
  173. {
  174. $shopsIds = $city->getShops()->map(function (Shop $shop): int {
  175. return $shop->getId();
  176. })->toArray();
  177. sort($shopsIds);
  178. $qb = $this->getEntityManager()->createQueryBuilder();
  179. $qb
  180. ->select('offer')
  181. ->addSelect('partial price.{id, shop, quantity, actual, old}')
  182. ->from(Price::class, 'price')
  183. ->join(
  184. Offer::class,
  185. 'offer',
  186. Join::WITH,
  187. $qb->expr()->eq('price.offer', 'offer')
  188. )
  189. ->join(
  190. Product::class,
  191. 'product',
  192. Join::WITH,
  193. $qb->expr()->eq('offer.product', $product->getId())
  194. )
  195. ->where($qb->expr()->in('price.shop', $shopsIds));
  196. $sql = $qb->getQuery()->getSQL();
  197. $result = $this->getEntityManager()
  198. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  199. $result = $this->clearKeys($result);
  200. $offers = [];
  201. foreach ($result as $row) {
  202. if (empty($offers[$row['product_id']][$row['id']])) {
  203. $offers[$row['id']] = [
  204. 'id' => (int) $row['id'],
  205. 'product_id' => $row['product_id'],
  206. 'barcode' => $row['bar_code'],
  207. ];
  208. }
  209. $offers[$row['id']]['prices'][] = [
  210. 'actual' => (int) $row['actual'],
  211. 'old' => (int) $row['old'],
  212. 'shop' => (int) $row['shop_id'],
  213. ];
  214. }
  215. return $offers;
  216. }
  217. public function getOffersAndProductsIdsBy(City $city, Category $category): array
  218. {
  219. $shopsIds = $city->getShops()->map(function (Shop $shop): int {
  220. return $shop->getId();
  221. })->toArray();
  222. sort($shopsIds);
  223. $categoryIds = $category->getIds();
  224. sort($categoryIds);
  225. $categoryIds = array_unique($categoryIds);
  226. $qb = $this->getEntityManager()->createQueryBuilder();
  227. $qb
  228. ->select('partial offer.{id, product}')
  229. ->from(Price::class, 'price')
  230. ->join(
  231. Offer::class,
  232. 'offer',
  233. Join::WITH,
  234. $qb->expr()->eq('price.offer', 'offer')
  235. )
  236. ->join(
  237. Product::class,
  238. 'product',
  239. Join::WITH,
  240. $qb->expr()->andX(
  241. $qb->expr()->in('product.category', $categoryIds),
  242. $qb->expr()->eq('product', 'offer.product'),
  243. )
  244. )
  245. ->where($qb->expr()->in('price.shop', $shopsIds));
  246. $sql = $qb->getQuery()->getSQL();
  247. $result = $this->getEntityManager()
  248. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  249. $result = $this->clearKeys($result);
  250. $offers = [];
  251. foreach ($result as $k => $row) {
  252. $offers[$row['id']] = (int) $row['product_id'];
  253. unset($result[$k]);
  254. }
  255. return $offers;
  256. }
  257. private function getProductsByIds(array $productIds): array
  258. {
  259. if (empty($productIds)) {
  260. $productIds[] = 0;
  261. }
  262. sort($productIds);
  263. $qb = $this->getEntityManager()->createQueryBuilder();
  264. $qb
  265. ->select('product')
  266. ->addSelect('info')
  267. ->from(Product::class, 'product')
  268. ->join(ProductInfo::class, 'info', Join::WITH, $qb->expr()->eq('info.product', 'product'))
  269. ->where($qb->expr()->in('product.id', $productIds));
  270. $sql = $qb->getQuery()->getSQL();
  271. $result = $this->getEntityManager()
  272. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  273. $result = $this->clearKeys($result);
  274. foreach ($result as &$row) {
  275. $row = [
  276. 'id' => (int) $row['id'],
  277. 'category' => (int) $row['category_id'],
  278. 'name' => $row['name'],
  279. 'slug' => $row['slug'],
  280. 'article' => $row['article'],
  281. 'code' => $row['code'],
  282. 'weight' => $row['weight'],
  283. 'image' => $row['code'],
  284. 'images' => [],
  285. ];
  286. }
  287. return $result;
  288. }
  289. public function createOfferQueryBuilder(City $city, array $categoriesIds): QueryBuilder
  290. {
  291. $shopsIds = $city->getShops()->getIds();
  292. $qb = $this->getEntityManager()->createQueryBuilder();
  293. $qb
  294. ->select('partial offer.{id, product}')
  295. ->from(Price::class, 'price')
  296. ->join(
  297. Offer::class,
  298. 'offer',
  299. Join::WITH,
  300. $qb->expr()->eq('price.offer', 'offer')
  301. )
  302. ->join(
  303. Product::class,
  304. 'product',
  305. Join::WITH,
  306. $qb->expr()->andX(
  307. $qb->expr()->in('product.category', $categoriesIds),
  308. $qb->expr()->eq('product', 'offer.product'),
  309. )
  310. )
  311. ->where($qb->expr()->in('price.shop', $shopsIds));
  312. return $qb;
  313. }
  314. public function getRelatedProductsWithOffers(City $city, Product $product): array
  315. {
  316. $related = $product->getRelated();
  317. if ($related->count()) {
  318. return $related->toArray();
  319. }
  320. $categories = $product->getCategory()->getRelated();
  321. if (!$categories->count()) {
  322. return [];
  323. }
  324. $sql = $this
  325. ->createOfferQueryBuilder($city, $categories->getIds(false))
  326. ->getQuery()
  327. ->getSQL();
  328. $result = $this->getEntityManager()
  329. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  330. $productIds = [];
  331. foreach ($result as $k => $row) {
  332. $row = $this->clearKeysRow($row);
  333. $productIds[] = (int) $row['product_id'];
  334. unset($result[$k]);
  335. }
  336. return $productIds;
  337. }
  338. /**
  339. * For yandex market
  340. */
  341. public function getOffersByCity(City $city): array
  342. {
  343. $shopsIds = $city->getShops()->getIds();
  344. $qb = $this->getEntityManager()->createQueryBuilder();
  345. $qb
  346. ->addSelect('partial offer.{id, barCode}')
  347. ->addSelect('partial price.{id, shop, quantity, actual, old}')
  348. ->addSelect('partial info.{product, name, description}')
  349. ->addSelect('partial product.{id, category, code}')
  350. ->from(Price::class, 'price')
  351. ->join(
  352. Offer::class,
  353. 'offer',
  354. Join::WITH,
  355. $qb->expr()->eq('price.offer', 'offer')
  356. )
  357. ->join(
  358. Product::class,
  359. 'product',
  360. Join::WITH,
  361. $qb->expr()->eq('offer.product', 'product')
  362. )
  363. ->join(
  364. ProductInfo::class,
  365. 'info',
  366. Join::WITH,
  367. $qb->expr()->eq('info.product', 'product')
  368. )
  369. ->where($qb->expr()->in('price.shop', $shopsIds))
  370. ->andWhere($qb->expr()->gt('price.actual', 200))
  371. ;
  372. $sql = $qb->getQuery()->getSQL();
  373. //dd($sql);
  374. $result = $this->getEntityManager()
  375. ->getConnection()->executeQuery($sql)->fetchAllAssociative();
  376. $result = $this->clearKeys($result);
  377. $offers = [];
  378. foreach ($result as $row) {
  379. // dd($row);
  380. if (empty($offers[$row['product_id']][$row['id']])) {
  381. $offers[$row['id']] = [
  382. 'id' => (int) $row['id'],
  383. 'product_id' => (int) $row['product_id'],
  384. 'category_id' => (int) $row['category_id'],
  385. 'barcode' => $row['bar_code'],
  386. 'code' => $row['code'],
  387. 'name' => $row['name'],
  388. 'description' => $row['description'],
  389. ];
  390. }
  391. $offers[$row['id']]['prices'][] = [
  392. 'actual' => (int) $row['actual'],
  393. 'old' => (int) $row['old'],
  394. 'shop' => (int) $row['shop_id'],
  395. ];
  396. }
  397. return $offers;
  398. }
  399. }