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 PrestaShopBundle\Entity;
28
29use Doctrine\ORM\Mapping as ORM;
30
31/**
32 * AdminFilter.
33 *
34 * @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="admin_filter_search_id_idx", columns={"employee", "shop", "controller", "action", "filter_id"})})
35 * @ORM\Entity(repositoryClass="PrestaShopBundle\Entity\Repository\AdminFilterRepository")
36 */
37class AdminFilter
38{
39    /**
40     * @var int
41     *
42     * @ORM\Id
43     * @ORM\Column(name="id", type="integer")
44     * @ORM\GeneratedValue(strategy="AUTO")
45     */
46    private $id;
47
48    /**
49     * @var int
50     *
51     * @ORM\Column(name="employee", type="integer")
52     */
53    private $employee;
54
55    /**
56     * @var int
57     *
58     * @ORM\Column(name="shop", type="integer")
59     */
60    private $shop;
61
62    /**
63     * @var string
64     *
65     * @ORM\Column(name="controller", type="string", length=60)
66     */
67    private $controller;
68
69    /**
70     * @var string
71     *
72     * @ORM\Column(name="action", type="string", length=100)
73     */
74    private $action;
75
76    /**
77     * @var string
78     *
79     * @ORM\Column(name="filter", type="text")
80     */
81    private $filter;
82
83    /**
84     * @var string
85     *
86     * @ORM\Column(name="filter_id", type="string", length=191)
87     */
88    private $filterId = '';
89
90    /**
91     * Get id.
92     *
93     * @return int
94     */
95    public function getId()
96    {
97        return $this->id;
98    }
99
100    /**
101     * Set employee.
102     *
103     * @param int $employee
104     *
105     * @return AdminFilter
106     */
107    public function setEmployee($employee)
108    {
109        $this->employee = $employee;
110
111        return $this;
112    }
113
114    /**
115     * Get employee.
116     *
117     * @return int
118     */
119    public function getEmployee()
120    {
121        return $this->employee;
122    }
123
124    /**
125     * Set shop.
126     *
127     * @param int $shop
128     *
129     * @return AdminFilter
130     */
131    public function setShop($shop)
132    {
133        $this->shop = $shop;
134
135        return $this;
136    }
137
138    /**
139     * Get shop.
140     *
141     * @return int
142     */
143    public function getShop()
144    {
145        return $this->shop;
146    }
147
148    /**
149     * Set controller.
150     *
151     * @param string $controller
152     *
153     * @return AdminFilter
154     */
155    public function setController($controller)
156    {
157        $this->controller = $controller;
158
159        return $this;
160    }
161
162    /**
163     * Get controller.
164     *
165     * @return string
166     */
167    public function getController()
168    {
169        return $this->controller;
170    }
171
172    /**
173     * Set action.
174     *
175     * @param string $action
176     *
177     * @return AdminFilter
178     */
179    public function setAction($action)
180    {
181        $this->action = $action;
182
183        return $this;
184    }
185
186    /**
187     * Get action.
188     *
189     * @return string
190     */
191    public function getAction()
192    {
193        return $this->action;
194    }
195
196    /**
197     * Set filter.
198     *
199     * @param string $filter
200     *
201     * @return AdminFilter
202     */
203    public function setFilter($filter)
204    {
205        $this->filter = $filter;
206
207        return $this;
208    }
209
210    /**
211     * Get filter.
212     *
213     * @return string
214     */
215    public function getFilter()
216    {
217        return $this->filter;
218    }
219
220    /**
221     * @return string
222     */
223    public function getFilterId()
224    {
225        return $this->filterId;
226    }
227
228    /**
229     * @param string $filterId
230     *
231     * @return AdminFilter
232     */
233    public function setFilterId($filterId)
234    {
235        $this->filterId = $filterId;
236
237        return $this;
238    }
239
240    /**
241     * Gets an array with each filter key needed by Product catalog page.
242     *
243     * Values are filled with empty strings.
244     *
245     * @return array
246     */
247    public static function getProductCatalogEmptyFilter()
248    {
249        return [
250            'filter_category' => '',
251            'filter_column_id_product' => '',
252            'filter_column_name' => '',
253            'filter_column_reference' => '',
254            'filter_column_name_category' => '',
255            'filter_column_price' => '',
256            'filter_column_sav_quantity' => '',
257            'filter_column_active' => '',
258            'last_offset' => 0,
259            'last_limit' => 20,
260            'last_orderBy' => 'id_product',
261            'last_sortOrder' => 'desc',
262        ];
263    }
264
265    /**
266     * Gets an array with filters needed by Product catalog page.
267     *
268     * The data is decoded and filled with empty strings if there is no value on each entry
269     * .
270     *
271     * @return array
272     */
273    public function getProductCatalogFilter()
274    {
275        $decoded = json_decode($this->getFilter(), true);
276
277        return array_merge(
278            $this->getProductCatalogEmptyFilter(),
279            $decoded
280        );
281    }
282
283    /**
284     * Set the filters for Product catalog page into $this->filter.
285     *
286     * Filters input data to keep only Product catalog filters, and encode it.
287     *
288     * @param array $filter
289     *
290     * @return AdminFilter tis object for fluent chaining
291     */
292    public function setProductCatalogFilter($filter)
293    {
294        $filter = array_intersect_key(
295            $filter,
296            $this->getProductCatalogEmptyFilter()
297        );
298        $filter = self::sanitizeFilterParameters($filter);
299
300        return $this->setFilter(json_encode($filter));
301    }
302
303    /**
304     * Sanitize filter parameters.
305     *
306     * @param array $filter
307     *
308     * @return mixed
309     */
310    public static function sanitizeFilterParameters(array $filter)
311    {
312        $filterMinMax = function ($filter) {
313            return function ($subject) use ($filter) {
314                $operator = null;
315
316                if (false !== strpos($subject, '<=')) {
317                    $operator = '<=';
318                }
319
320                if (false !== strpos($subject, '>=')) {
321                    $operator = '>=';
322                }
323
324                if (null === $operator) {
325                    $pattern = '#BETWEEN (?P<min>\d+\.?\d*) AND (?P<max>\d+\.?\d*)#';
326                    if (0 === preg_match($pattern, $subject, $matches)) {
327                        return '';
328                    }
329
330                    return sprintf('BETWEEN %f AND %f', $matches['min'], $matches['max']);
331                } else {
332                    $subjectWithoutOperator = str_replace($operator, '', $subject);
333
334                    $flag = FILTER_DEFAULT;
335                    if ($filter === FILTER_SANITIZE_NUMBER_FLOAT) {
336                        $flag = FILTER_FLAG_ALLOW_FRACTION;
337                    }
338
339                    $filteredSubjectWithoutOperator = filter_var($subjectWithoutOperator, $filter, $flag);
340                    if (!$filteredSubjectWithoutOperator) {
341                        $filteredSubjectWithoutOperator = 0;
342                    }
343
344                    return $operator . $filteredSubjectWithoutOperator;
345                }
346            };
347        };
348
349        return filter_var_array($filter, [
350            'filter_category' => FILTER_SANITIZE_NUMBER_INT,
351            'filter_column_id_product' => [
352                'filter' => FILTER_CALLBACK,
353                'options' => $filterMinMax(FILTER_SANITIZE_NUMBER_INT),
354            ],
355            'filter_column_name' => FILTER_SANITIZE_STRING,
356            'filter_column_reference' => FILTER_SANITIZE_STRING,
357            'filter_column_name_category' => FILTER_SANITIZE_STRING,
358            'filter_column_price' => [
359                'filter' => FILTER_CALLBACK,
360                'options' => $filterMinMax(FILTER_SANITIZE_NUMBER_FLOAT),
361            ],
362            'filter_column_sav_quantity' => [
363                'filter' => FILTER_CALLBACK,
364                'options' => $filterMinMax(FILTER_SANITIZE_NUMBER_INT),
365            ],
366            'filter_column_active' => FILTER_SANITIZE_NUMBER_INT,
367            'last_offset' => FILTER_SANITIZE_NUMBER_INT,
368            'last_limit' => FILTER_SANITIZE_NUMBER_INT,
369            'last_orderBy' => FILTER_SANITIZE_STRING,
370            'last_sortOrder' => FILTER_SANITIZE_STRING,
371        ]);
372    }
373}
374