1<?php
2/**
3 * Copyright since 2007 PrestaShop SA and Contributors
4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
5 *
6 * NOTICE OF LICENSE
7 *
8 * This source file is subject to the Open Software License (OSL 3.0)
9 * that is bundled with this package in the file LICENSE.md.
10 * It is also available through the world-wide-web at this URL:
11 * https://opensource.org/licenses/OSL-3.0
12 * If you did not receive a copy of the license and are unable to
13 * obtain it through the world-wide-web, please send an email
14 * to license@prestashop.com so we can send you a copy immediately.
15 *
16 * DISCLAIMER
17 *
18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
19 * versions in the future. If you wish to customize PrestaShop for your
20 * needs please refer to https://devdocs.prestashop.com/ for more information.
21 *
22 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
23 * @copyright Since 2007 PrestaShop SA and Contributors
24 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
25 */
26
27namespace PrestaShop\PrestaShop\Core\Grid\Query;
28
29use Doctrine\DBAL\Connection;
30use Doctrine\DBAL\Query\QueryBuilder;
31use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
32
33/**
34 * Class ManufacturerQueryBuilder is responsible for building queries for manufacturers grid data.
35 */
36final class ManufacturerQueryBuilder extends AbstractDoctrineQueryBuilder
37{
38    /**
39     * @var DoctrineSearchCriteriaApplicatorInterface
40     */
41    private $searchCriteriaApplicator;
42    /**
43     * @var int[]
44     */
45    private $contextShopIds;
46
47    /**
48     * @param Connection $connection
49     * @param string $dbPrefix
50     * @param DoctrineSearchCriteriaApplicatorInterface $searchCriteriaApplicator
51     * @param array $contextShopIds
52     */
53    public function __construct(
54        Connection $connection,
55        $dbPrefix,
56        DoctrineSearchCriteriaApplicatorInterface $searchCriteriaApplicator,
57        array $contextShopIds
58    ) {
59        parent::__construct($connection, $dbPrefix);
60
61        $this->contextShopIds = $contextShopIds;
62        $this->searchCriteriaApplicator = $searchCriteriaApplicator;
63    }
64
65    /**
66     * {@inheritdoc}
67     */
68    public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria)
69    {
70        $addressesQb = $this->connection->createQueryBuilder();
71        $addressesQb->select('COUNT(a.`id_manufacturer`) AS `addresses_count`')
72            ->from($this->dbPrefix . 'address', 'a')
73            ->where('a.`id_manufacturer` != 0')
74            ->andWhere('m.`id_manufacturer` = a.`id_manufacturer`')
75            ->andWhere('a.`deleted` = 0')
76            ->groupBy('a.`id_manufacturer`')
77        ;
78
79        $qb = $this->getQueryBuilder($searchCriteria->getFilters());
80        $qb
81            ->select('m.`id_manufacturer`, m.`name`, m.`active`')
82            ->addSelect('COUNT(p.`id_product`) AS `products_count`')
83            ->addSelect('(' . $addressesQb->getSQL() . ') AS addresses_count')
84            ->groupBy('m.`id_manufacturer`')
85        ;
86
87        $this->searchCriteriaApplicator
88            ->applyPagination($searchCriteria, $qb)
89            ->applySorting($searchCriteria, $qb)
90        ;
91
92        return $qb;
93    }
94
95    /**
96     * {@inheritdoc}
97     */
98    public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria)
99    {
100        $qb = $this->getQueryBuilder($searchCriteria->getFilters());
101        $qb->select('COUNT(DISTINCT m.`id_manufacturer`)');
102
103        return $qb;
104    }
105
106    /**
107     * Get generic query builder.
108     *
109     * @param array $filters
110     *
111     * @return QueryBuilder
112     */
113    private function getQueryBuilder(array $filters)
114    {
115        $allowedFilters = ['id_manufacturer', 'name', 'active'];
116
117        $qb = $this->connection
118            ->createQueryBuilder()
119            ->from($this->dbPrefix . 'manufacturer', 'm')
120            ->innerJoin(
121                'm',
122                $this->dbPrefix . 'manufacturer_shop',
123                'ms',
124                'ms.`id_manufacturer` = m.`id_manufacturer`'
125            )
126            ->leftJoin(
127                'm',
128                $this->dbPrefix . 'product',
129                'p',
130                'm.`id_manufacturer` = p.`id_manufacturer`'
131            )
132        ;
133
134        foreach ($filters as $filterName => $value) {
135            if (!in_array($filterName, $allowedFilters, true)) {
136                continue;
137            }
138
139            if ('name' === $filterName) {
140                $qb->andWhere('m.`name` LIKE :' . $filterName)
141                    ->setParameter($filterName, '%' . $value . '%');
142                continue;
143            }
144            $qb->andWhere('m.`' . $filterName . '` = :' . $filterName)
145                ->setParameter($filterName, $value);
146        }
147
148        $qb->andWhere('ms.`id_shop` IN (:contextShopIds)');
149
150        $qb->setParameter('contextShopIds', $this->contextShopIds, Connection::PARAM_INT_ARRAY);
151
152        return $qb;
153    }
154}
155