Passed
Push — develop ( b2d169...d716f5 )
by Torben
03:51
created

EventRepository::findDemanded()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 37
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 27
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 37
rs 9.488
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace DERHANSEN\SfEventMgt\Domain\Repository;
13
14
use DERHANSEN\SfEventMgt\Domain\Model\Dto\EventDemand;
15
use DERHANSEN\SfEventMgt\Event\ModifyEventQueryConstraintsEvent;
16
use DERHANSEN\SfEventMgt\Service\CategoryService;
17
use Psr\EventDispatcher\EventDispatcherInterface;
18
use TYPO3\CMS\Core\Utility\GeneralUtility;
19
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface;
20
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
21
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
22
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
23
use TYPO3\CMS\Extbase\Persistence\Repository;
24
25
/**
26
 * The repository for Events
27
 */
28
class EventRepository extends Repository
29
{
30
    protected $defaultOrderings = [
31
        'startdate' => QueryInterface::ORDER_ASCENDING,
32
    ];
33
34
    protected EventDispatcherInterface $eventDispatcher;
35
36
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher)
37
    {
38
        $this->eventDispatcher = $eventDispatcher;
39
    }
40
41
    /**
42
     * Disable the use of storage records, because the StoragePage can be set
43
     * in the plugin
44
     */
45
    public function initializeObject()
46
    {
47
        $this->defaultQuerySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class);
48
        $this->defaultQuerySettings->setRespectStoragePage(false);
49
    }
50
51
    /**
52
     * Returns the objects of this repository matching the given demand
53
     *
54
     * @param EventDemand $eventDemand EventDemand
55
     *
56
     * @return array|QueryResultInterface QueryResultInterface
57
     */
58
    public function findDemanded(EventDemand $eventDemand)
59
    {
60
        $constraints = [];
61
        $query = $this->createQuery();
62
        $query->getQuerySettings()->setIgnoreEnableFields($eventDemand->getIgnoreEnableFields());
63
64
        $this->setStoragePageConstraint($query, $eventDemand, $constraints);
65
        $this->setDisplayModeConstraint($query, $eventDemand, $constraints);
66
        $this->setCategoryConstraint($query, $eventDemand, $constraints);
67
        $this->setLocationConstraint($query, $eventDemand, $constraints);
68
        $this->setLocationCityConstraint($query, $eventDemand, $constraints);
69
        $this->setLocationCountryConstraint($query, $eventDemand, $constraints);
70
        $this->setSpeakerConstraint($query, $eventDemand, $constraints);
71
        $this->setOrganisatorConstraint($query, $eventDemand, $constraints);
72
        $this->setStartEndDateConstraint($query, $eventDemand, $constraints);
73
        $this->setSearchConstraint($query, $eventDemand, $constraints);
74
        $this->setTopEventConstraint($query, $eventDemand, $constraints);
75
        $this->setYearMonthDayRestriction($query, $eventDemand, $constraints);
76
77
        $modifyEventQueryConstraintsEvent = new ModifyEventQueryConstraintsEvent(
78
            $constraints,
79
            $query,
80
            $eventDemand,
81
            $this
82
        );
83
        $this->eventDispatcher->dispatch($modifyEventQueryConstraintsEvent);
84
        $constraints = $modifyEventQueryConstraintsEvent->getConstraints();
85
86
        $this->setOrderingsFromDemand($query, $eventDemand);
87
88
        if (count($constraints) > 0) {
89
            $query->matching($query->logicalAnd($constraints));
90
        }
91
92
        $this->setQueryLimitFromDemand($query, $eventDemand);
93
94
        return $query->execute();
95
    }
96
97
    /**
98
     * Returns the event with the given UID and also respects the hidden state
99
     *
100
     * @param int $uid
101
     * @return object
102
     */
103
    public function findByUidIncludeHidden(int $uid): object
104
    {
105
        $query = $this->createQuery();
106
        $query->getQuerySettings()->setIgnoreEnableFields(true);
107
        $query->matching($query->equals('uid', $uid));
108
        return $query->execute()->getFirst();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->execute()->getFirst() could return the type null which is incompatible with the type-hinted return object. Consider adding an additional type-check to rule them out.
Loading history...
109
    }
110
111
    /**
112
     * Sets a query limit to the given query for the given demand
113
     *
114
     * @param QueryInterface $query Query
115
     * @param EventDemand $eventDemand EventDemand
116
     */
117
    protected function setQueryLimitFromDemand(QueryInterface $query, EventDemand $eventDemand): void
118
    {
119
        if ($eventDemand->getQueryLimit() > 0) {
120
            $query->setLimit($eventDemand->getQueryLimit());
121
        }
122
    }
123
124
    /**
125
     * Sets the ordering to the given query for the given demand
126
     *
127
     * @param QueryInterface $query Query
128
     * @param EventDemand $eventDemand EventDemand
129
     */
130
    protected function setOrderingsFromDemand(QueryInterface $query, EventDemand $eventDemand): void
131
    {
132
        $orderings = [];
133
        $orderFieldAllowed = GeneralUtility::trimExplode(',', $eventDemand->getOrderFieldAllowed(), true);
134
        if ($eventDemand->getOrderField() != '' && $eventDemand->getOrderDirection() != '' &&
135
            !empty($orderFieldAllowed) && in_array($eventDemand->getOrderField(), $orderFieldAllowed, true)) {
136
            $orderings[$eventDemand->getOrderField()] = ((strtolower($eventDemand->getOrderDirection()) == 'desc') ?
137
                QueryInterface::ORDER_DESCENDING :
138
                QueryInterface::ORDER_ASCENDING);
139
            $query->setOrderings($orderings);
140
        }
141
    }
142
143
    /**
144
     * Sets the storagePage constraint to the given constraints array
145
     *
146
     * @param QueryInterface $query Query
147
     * @param EventDemand $eventDemand EventDemand
148
     * @param array $constraints Constraints
149
     */
150
    protected function setStoragePageConstraint(
151
        QueryInterface $query,
152
        EventDemand $eventDemand,
153
        array &$constraints
154
    ): void {
155
        if ($eventDemand->getStoragePage() !== '') {
156
            $pidList = GeneralUtility::intExplode(',', $eventDemand->getStoragePage(), true);
157
            $constraints['storagePage'] = $query->in('pid', $pidList);
158
        }
159
    }
160
161
    /**
162
     * Sets the displayMode constraint to the given constraints array
163
     *
164
     * @param QueryInterface $query Query
165
     * @param EventDemand $eventDemand EventDemand
166
     * @param array $constraints Constraints
167
     */
168
    protected function setDisplayModeConstraint(
169
        QueryInterface $query,
170
        EventDemand $eventDemand,
171
        array &$constraints
172
    ): void {
173
        switch ($eventDemand->getDisplayMode()) {
174
            case 'future':
175
                $constraints['displayMode'] = $query->greaterThan('startdate', $eventDemand->getCurrentDateTime());
176
                break;
177
            case 'current_future':
178
                $constraints['displayMode'] = $query->logicalOr([
179
                    $query->greaterThan('startdate', $eventDemand->getCurrentDateTime()),
180
                    $query->logicalAnd([
181
                        $query->greaterThanOrEqual('enddate', $eventDemand->getCurrentDateTime()),
182
                        $query->lessThanOrEqual('startdate', $eventDemand->getCurrentDateTime()),
183
                    ]),
184
                ]);
185
                break;
186
            case 'past':
187
                $constraints['displayMode'] = $query->lessThanOrEqual('enddate', $eventDemand->getCurrentDateTime());
188
                break;
189
            case 'time_restriction':
190
                $includeCurrentConstraint = null;
191
                if (!empty($eventDemand->getTimeRestrictionLow())) {
192
                    $timeRestriction = strtotime($eventDemand->getTimeRestrictionLow());
193
                    $timeRestrictionConstraints['timeRestrictionLow'] = $query->greaterThanOrEqual('startdate', $timeRestriction);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$timeRestrictionConstraints was never initialized. Although not strictly required by PHP, it is generally a good practice to add $timeRestrictionConstraints = array(); before regardless.
Loading history...
194
195
                    if ($eventDemand->getIncludeCurrent()) {
196
                        $includeCurrentConstraint = $query->logicalAnd([
197
                            $query->lessThan('startdate', $timeRestriction),
198
                            $query->greaterThan('enddate', $timeRestriction),
199
                        ]);
200
                    }
201
                }
202
                if (!empty($eventDemand->getTimeRestrictionHigh())) {
203
                    $timeRestrictionHigh = strtotime($eventDemand->getTimeRestrictionHigh());
204
                    $timeRestrictionConstraints['timeRestrictionHigh'] = $query->lessThanOrEqual('startdate', $timeRestrictionHigh);
205
                }
206
                if (isset($timeRestrictionConstraints)) {
207
                    if ($eventDemand->getIncludeCurrent() && $includeCurrentConstraint) {
208
                        $constraints['displayMode'] = $query->logicalOr([
209
                            $includeCurrentConstraint,
210
                            $query->logicalAnd($timeRestrictionConstraints),
211
                        ]);
212
                    } else {
213
                        $constraints['displayMode'] = $query->logicalAnd($timeRestrictionConstraints);
214
                    }
215
                }
216
                break;
217
            default:
218
        }
219
    }
220
221
    /**
222
     * Sets the category constraint to the given constraints array
223
     *
224
     * @param QueryInterface $query Query
225
     * @param EventDemand $eventDemand EventDemand
226
     * @param array $constraints Constraints
227
     */
228
    protected function setCategoryConstraint(QueryInterface $query, EventDemand $eventDemand, array &$constraints): void
229
    {
230
        // If no category constraint is set, categories should not be respected in the query
231
        if ($eventDemand->getCategoryConjunction() === '') {
232
            return;
233
        }
234
235
        if ($eventDemand->getCategory() != '') {
236
            $categoryConstraints = [];
237
            if ($eventDemand->getIncludeSubcategories()) {
238
                $categoryList = CategoryService::getCategoryListWithChilds($eventDemand->getCategory());
239
                $categories = GeneralUtility::intExplode(',', $categoryList, true);
240
            } else {
241
                $categories = GeneralUtility::intExplode(',', $eventDemand->getCategory(), true);
242
            }
243
            foreach ($categories as $category) {
244
                $categoryConstraints[] = $query->contains('category', $category);
245
            }
246
            if (count($categoryConstraints) > 0) {
247
                $constraints['category'] = $this->getCategoryConstraint($query, $eventDemand, $categoryConstraints);
248
            }
249
        }
250
    }
251
252
    /**
253
     * Returns the category constraint depending on the category conjunction configured in eventDemand
254
     *
255
     * @param QueryInterface $query
256
     * @param EventDemand $eventDemand
257
     * @param array $categoryConstraints
258
     * @return ConstraintInterface
259
     */
260
    public function getCategoryConstraint(
261
        QueryInterface $query,
262
        EventDemand $eventDemand,
263
        array $categoryConstraints
264
    ): ConstraintInterface {
265
        switch (strtolower($eventDemand->getCategoryConjunction())) {
266
            case 'and':
267
                $constraint = $query->logicalAnd($categoryConstraints);
268
                break;
269
            case 'notor':
270
                $constraint = $query->logicalNot($query->logicalOr($categoryConstraints));
271
                break;
272
            case 'notand':
273
                $constraint = $query->logicalNot($query->logicalAnd($categoryConstraints));
274
                break;
275
            case 'or':
276
            default:
277
                $constraint = $query->logicalOr($categoryConstraints);
278
        }
279
280
        return $constraint;
281
    }
282
283
    /**
284
     * Sets the location constraint to the given constraints array
285
     *
286
     * @param QueryInterface $query Query
287
     * @param EventDemand $eventDemand EventDemand
288
     * @param array $constraints Constraints
289
     */
290
    protected function setLocationConstraint($query, $eventDemand, &$constraints)
291
    {
292
        if ($eventDemand->getLocation() !== null && $eventDemand->getLocation() != '') {
293
            $constraints['location'] = $query->equals('location', $eventDemand->getLocation());
294
        }
295
    }
296
297
    /**
298
     * Sets the location.city constraint to the given constraints array
299
     *
300
     * @param QueryInterface $query Query
301
     * @param EventDemand $eventDemand EventDemand
302
     * @param array $constraints Constraints
303
     */
304
    protected function setLocationCityConstraint(
305
        QueryInterface $query,
306
        EventDemand $eventDemand,
307
        array &$constraints
308
    ): void {
309
        if ($eventDemand->getLocationCity() !== null && $eventDemand->getLocationCity() != '') {
310
            $constraints['locationCity'] = $query->equals('location.city', $eventDemand->getLocationCity());
311
        }
312
    }
313
314
    /**
315
     * Sets the location.country constraint to the given constraints array
316
     *
317
     * @param QueryInterface $query Query
318
     * @param EventDemand $eventDemand EventDemand
319
     * @param array $constraints Constraints
320
     */
321
    protected function setLocationCountryConstraint(
322
        QueryInterface $query,
323
        EventDemand $eventDemand,
324
        array &$constraints
325
    ): void {
326
        if ($eventDemand->getLocationCountry() !== null && $eventDemand->getLocationCountry() != '') {
327
            $constraints['locationCountry'] = $query->equals('location.country', $eventDemand->getLocationCountry());
328
        }
329
    }
330
331
    /**
332
     * Sets the speaker constraint to the given constraints array
333
     *
334
     * @param QueryInterface $query Query
335
     * @param EventDemand $eventDemand EventDemand
336
     * @param array $constraints Constraints
337
     */
338
    protected function setSpeakerConstraint(QueryInterface $query, EventDemand $eventDemand, array &$constraints): void
339
    {
340
        if ($eventDemand->getSpeaker() !== null && $eventDemand->getSpeaker() != '') {
341
            $constraints['speaker'] = $query->contains('speaker', $eventDemand->getSpeaker());
342
        }
343
    }
344
345
    /**
346
     * Sets the organisator constraint to the given constraints array
347
     *
348
     * @param QueryInterface $query Query
349
     * @param EventDemand $eventDemand EventDemand
350
     * @param array $constraints Constraints
351
     */
352
    protected function setOrganisatorConstraint(
353
        QueryInterface $query,
354
        EventDemand $eventDemand,
355
        array &$constraints
356
    ): void {
357
        if ($eventDemand->getOrganisator() !== null && $eventDemand->getOrganisator() != '') {
358
            $constraints['organisator'] = $query->equals('organisator', $eventDemand->getOrganisator());
359
        }
360
    }
361
362
    /**
363
     * Sets the start- and enddate constraint to the given constraints array
364
     *
365
     * @param QueryInterface $query Query
366
     * @param EventDemand $eventDemand EventDemand
367
     * @param array $constraints Constraints
368
     */
369
    protected function setStartEndDateConstraint(
370
        QueryInterface $query,
371
        EventDemand $eventDemand,
372
        array &$constraints
373
    ): void {
374
        if ($eventDemand->getSearchDemand() && $eventDemand->getSearchDemand()->getStartDate() !== null &&
375
            $eventDemand->getSearchDemand()->getEndDate() !== null
376
        ) {
377
            /* StartDate and EndDate  - Search for events between two given dates */
378
            $begin = $eventDemand->getSearchDemand()->getStartDate();
379
            $end = $eventDemand->getSearchDemand()->getEndDate();
380
            $constraints['startEndDate'] = $query->logicalOr([
381
                $query->between('startdate', $begin, $end),
0 ignored issues
show
Bug introduced by
The method between() does not exist on TYPO3\CMS\Extbase\Persistence\QueryInterface. It seems like you code against a sub-type of said class. However, the method does not exist in TYPO3\CMS\Extbase\Persis...ompatibleQueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

381
                $query->/** @scrutinizer ignore-call */ 
382
                        between('startdate', $begin, $end),
Loading history...
382
                $query->between('enddate', $begin, $end),
383
                $query->logicalAnd([
384
                    $query->greaterThanOrEqual('enddate', $begin),
385
                    $query->lessThanOrEqual('startdate', $begin),
386
                ]),
387
            ]);
388
        } elseif ($eventDemand->getSearchDemand() && $eventDemand->getSearchDemand()->getStartDate() !== null) {
389
            /* StartDate - Search for events beginning at a given date */
390
            $constraints['startDate'] = $query->greaterThanOrEqual('startdate', $eventDemand->getSearchDemand()->getStartDate());
391
        } elseif ($eventDemand->getSearchDemand() && $eventDemand->getSearchDemand()->getEndDate() !== null) {
392
            /* EndDate - Search for events ending on a given date */
393
            $constraints['endDate'] = $query->lessThanOrEqual('enddate', $eventDemand->getSearchDemand()->getEndDate());
394
        }
395
    }
396
397
    /**
398
     * Sets the search constraint to the given constraints array
399
     *
400
     * @param QueryInterface $query Query
401
     * @param EventDemand $eventDemand EventDemand
402
     * @param array $constraints Constraints
403
     */
404
    protected function setSearchConstraint(QueryInterface $query, EventDemand $eventDemand, array &$constraints): void
405
    {
406
        if ($eventDemand->getSearchDemand() &&
407
            $eventDemand->getSearchDemand()->getSearch() !== null &&
408
            $eventDemand->getSearchDemand()->getSearch() !== ''
409
        ) {
410
            $searchFields = GeneralUtility::trimExplode(',', $eventDemand->getSearchDemand()->getFields(), true);
411
            $searchConstraints = [];
412
413
            if (count($searchFields) === 0) {
414
                throw new \UnexpectedValueException('No search fields defined', 1318497755);
415
            }
416
417
            $searchSubject = $eventDemand->getSearchDemand()->getSearch();
418
            foreach ($searchFields as $field) {
419
                $searchConstraints[] = $query->like($field, '%' . addcslashes($searchSubject, '_%') . '%');
420
            }
421
422
            $constraints['search'] = $query->logicalOr($searchConstraints);
423
        }
424
    }
425
426
    /**
427
     * Sets the topEvent constraint to the given constraints array
428
     *
429
     * @param QueryInterface $query Query
430
     * @param EventDemand $eventDemand EventDemand
431
     * @param array $constraints Constraints
432
     */
433
    protected function setTopEventConstraint(QueryInterface $query, EventDemand $eventDemand, array &$constraints): void
434
    {
435
        if ($eventDemand->getTopEventRestriction() > 0) {
436
            $constraints['topEvent'] = $query->equals('topEvent', (bool)($eventDemand->getTopEventRestriction() - 1));
437
        }
438
    }
439
440
    /**
441
     * Sets the restriction for year, year/month or year/month/day to the given constraints array
442
     *
443
     * @param QueryInterface $query
444
     * @param EventDemand $eventDemand
445
     * @param array $constraints
446
     */
447
    protected function setYearMonthDayRestriction(
448
        QueryInterface $query,
449
        EventDemand $eventDemand,
450
        array &$constraints
451
    ): void {
452
        if ($eventDemand->getYear() > 0) {
453
            if ($eventDemand->getMonth() > 0) {
454
                if ($eventDemand->getDay() > 0) {
455
                    $begin = mktime(0, 0, 0, $eventDemand->getMonth(), $eventDemand->getDay(), $eventDemand->getYear());
456
                    $end = mktime(23, 59, 59, $eventDemand->getMonth(), $eventDemand->getDay(), $eventDemand->getYear());
457
                } else {
458
                    $begin = mktime(0, 0, 0, $eventDemand->getMonth(), 1, $eventDemand->getYear());
459
                    $end = mktime(23, 59, 59, ($eventDemand->getMonth() + 1), 0, $eventDemand->getYear());
460
                }
461
            } else {
462
                $begin = mktime(0, 0, 0, 1, 1, $eventDemand->getYear());
463
                $end = mktime(23, 59, 59, 12, 31, $eventDemand->getYear());
464
            }
465
            $constraints['yearMonthDay'] = $query->logicalOr([
466
                $query->between('startdate', $begin, $end),
467
                $query->between('enddate', $begin, $end),
468
                $query->logicalAnd([
469
                    $query->greaterThanOrEqual('enddate', $begin),
470
                    $query->lessThanOrEqual('startdate', $begin),
471
                ]),
472
            ]);
473
        }
474
    }
475
}
476