Completed
Push — master ( 15303a...d72fea )
by Tim
02:12
created

IndexRepository::findBySearch()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 40
rs 8.6577
c 0
b 0
f 0
cc 6
nc 8
nop 4
1
<?php
2
3
/**
4
 * Index repository.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Calendarize\Domain\Repository;
9
10
use Exception;
11
use HDNET\Calendarize\Domain\Model\Index;
12
use HDNET\Calendarize\Utility\DateTimeUtility;
13
use HDNET\Calendarize\Utility\ExtensionConfigurationUtility;
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
use TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager;
16
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
17
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
18
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
19
20
/**
21
 * Index repository.
22
 */
23
class IndexRepository extends AbstractRepository
24
{
25
    /**
26
     * Default orderings for index records.
27
     *
28
     * @var array
29
     */
30
    protected $defaultOrderings = [
31
        'start_date' => QueryInterface::ORDER_ASCENDING,
32
        'start_time' => QueryInterface::ORDER_ASCENDING,
33
    ];
34
35
    /**
36
     * Index types for selection.
37
     *
38
     * @var array
39
     */
40
    protected $indexTypes = [];
41
42
    /**
43
     * Override page ids.
44
     *
45
     * @var array
46
     */
47
    protected $overridePageIds = [];
48
49
    /**
50
     * Set the index types.
51
     *
52
     * @param array $types
53
     */
54
    public function setIndexTypes(array $types)
55
    {
56
        $this->indexTypes = $types;
57
    }
58
59
    /**
60
     * Override page IDs.
61
     *
62
     * @param array $overridePageIds
63
     */
64
    public function setOverridePageIds($overridePageIds)
65
    {
66
        $this->overridePageIds = $overridePageIds;
67
    }
68
69
    /**
70
     * Find List.
71
     *
72
     * @param int        $limit
73
     * @param int|string $listStartTime
74
     * @param int        $startOffsetHours
75
     * @param int        $overrideStartDate
76
     * @param int        $overrideEndDate
77
     *
78
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
79
     */
80
    public function findList(
81
        $limit = 0,
82
        $listStartTime = 0,
83
        $startOffsetHours = 0,
84
        $overrideStartDate = 0,
85
        $overrideEndDate = 0
86
    ) {
87
        if ($overrideStartDate > 0) {
88
            $startTimestamp = $overrideStartDate;
89
        } else {
90
            $now = DateTimeUtility::getNow();
91
            if ('now' !== $listStartTime) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of 'now' (string) and $listStartTime (integer) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
92
                $now->setTime(0, 0, 0);
93
            }
94
            $now->modify($startOffsetHours . ' hours');
95
            $startTimestamp = $now->getTimestamp();
96
        }
97
        $endTimestamp = null;
98
        if ($overrideEndDate > 0) {
99
            $endTimestamp = $overrideEndDate;
100
        }
101
102
        $result = $this->findByTimeSlot($startTimestamp, $endTimestamp);
103
        if ($limit > 0) {
104
            $query = $result->getQuery();
105
            $query->setLimit($limit);
106
            $result = $query->execute();
107
        }
108
109
        return $result;
110
    }
111
112
    /**
113
     * Find by custom search.
114
     *
115
     * @param \DateTime $startDate
116
     * @param \DateTime $endDate
117
     * @param array $customSearch
118
     * @param int $limit
119
     *
120
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
121
     */
122
    public function findBySearch(\DateTime $startDate = null, \DateTime $endDate = null, array $customSearch = [], int $limit = 0)
123
    {
124
        $arguments = [
125
            'indexIds' => [],
126
            'startDate' => $startDate,
127
            'endDate' => $endDate,
128
            'customSearch' => $customSearch,
129
            'indexTypes' => $this->indexTypes,
130
            'emptyPreResult' => false,
131
        ];
132
        $arguments = $this->callSignal(__CLASS__, __FUNCTION__ . 'Pre', $arguments);
133
134
        $query = $this->createQuery();
135
        $constraints = $this->getDefaultConstraints($query);
136
137
        if($limit > 0) {
138
            $query->setLimit($limit);
139
        }
140
141
        $this->addTimeFrameConstraints(
142
            $constraints,
143
            $query,
144
            $arguments['startDate'] instanceof \DateTime ? DateTimeUtility::getDayStart($arguments['startDate']) : null,
0 ignored issues
show
Bug introduced by
It seems like $arguments['startDate'] ...ts['startDate']) : null can also be of type object<DateTime>; however, HDNET\Calendarize\Domain...dTimeFrameConstraints() does only seem to accept integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
145
            $arguments['endDate'] instanceof \DateTime ? DateTimeUtility::getDayEnd($arguments['endDate']) : null
0 ignored issues
show
Bug introduced by
It seems like $arguments['endDate'] in...ents['endDate']) : null can also be of type object<DateTime>; however, HDNET\Calendarize\Domain...dTimeFrameConstraints() does only seem to accept integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
146
        );
147
148
        if ($arguments['indexIds']) {
149
            $constraints[] = $query->in('foreign_uid', $arguments['indexIds']);
150
        }
151
        if ($arguments['emptyPreResult']) {
152
            $constraints[] = $query->equals('uid', '-1');
153
        }
154
        $result = [
155
            'result' => $this->matchAndExecute($query, $constraints),
156
        ];
157
158
        $result = $this->callSignal(__CLASS__, __FUNCTION__ . 'Post', $result);
159
160
        return $result['result'];
161
    }
162
163
    /**
164
     * Find Past Events.
165
     *
166
     * @param int    $limit
167
     * @param string $sort
168
     *
169
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
170
     */
171
    public function findByPast(
172
        $limit,
173
        $sort
174
    ) {
175
        //create Query
176
        $query = $this->createQuery();
177
        //Get actual datetime
178
        $now = DateTimeUtility::getNow()->getTimestamp();
179
180
        $constraints = $this->getDefaultConstraints($query);
181
        $constraints[] = $query->lessThanOrEqual('startDate', $now);
182
        $sort = QueryInterface::ORDER_ASCENDING === $sort ? QueryInterface::ORDER_ASCENDING : QueryInterface::ORDER_DESCENDING;
183
        $query->setOrderings($this->getSorting($sort));
184
        $query->setLimit($limit);
185
186
        return $this->matchAndExecute($query, $constraints);
187
    }
188
189
    /**
190
     * Find by traversing information.
191
     *
192
     * @param Index      $index
193
     * @param bool|true  $future
194
     * @param bool|false $past
195
     * @param int        $limit
196
     * @param string     $sort
197
     * @param bool       $useIndexTime
198
     *
199
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
200
     */
201
    public function findByTraversing(
202
        Index $index,
203
        $future = true,
204
        $past = false,
205
        $limit = 100,
206
        $sort = QueryInterface::ORDER_ASCENDING,
207
        $useIndexTime = false
208
    ) {
209
        if (!$future && !$past) {
210
            return [];
211
        }
212
        $query = $this->createQuery();
213
214
        $now = DateTimeUtility::getNow()
215
            ->getTimestamp();
216
        if ($useIndexTime) {
217
            $now = $index->getStartDate()->getTimestamp();
218
        }
219
220
        $constraints = [];
221
        $constraints[] = $query->logicalNot($query->equals('uid', $index->getUid()));
222
        $constraints[] = $query->equals('foreignTable', $index->getForeignTable());
223
        $constraints[] = $query->equals('foreignUid', $index->getForeignUid());
224
        if (!$future) {
225
            $constraints[] = $query->lessThanOrEqual('startDate', $now);
226
        }
227
        if (!$past) {
228
            $constraints[] = $query->greaterThanOrEqual('startDate', $now);
229
        }
230
231
        $query->setLimit($limit);
232
        $sort = QueryInterface::ORDER_ASCENDING === $sort ? QueryInterface::ORDER_ASCENDING : QueryInterface::ORDER_DESCENDING;
233
        $query->setOrderings($this->getSorting($sort));
234
235
        return $this->matchAndExecute($query, $constraints);
236
    }
237
238
    /**
239
     * Find by traversing information.
240
     *
241
     * @param DomainObjectInterface $event
242
     * @param bool|true             $future
243
     * @param bool|false            $past
244
     * @param int                   $limit
245
     * @param string                $sort
246
     *
247
     * @throws Exception
248
     *
249
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
250
     */
251
    public function findByEventTraversing(
252
        DomainObjectInterface $event,
253
        $future = true,
254
        $past = false,
255
        $limit = 100,
256
        $sort = QueryInterface::ORDER_ASCENDING
257
    ) {
258
        if (!$future && !$past) {
259
            return [];
260
        }
261
        $query = $this->createQuery();
262
263
        $uniqueRegisterKey = ExtensionConfigurationUtility::getUniqueRegisterKeyForModel($event);
264
265
        $this->setIndexTypes([$uniqueRegisterKey]);
266
267
        $now = DateTimeUtility::getNow()
268
            ->getTimestamp();
269
270
        $constraints = [];
271
272
        $constraints[] = $query->equals('foreignUid', $event->getUid());
273
        if (!$future) {
274
            $constraints[] = $query->lessThanOrEqual('startDate', $now);
275
        }
276
        if (!$past) {
277
            $constraints[] = $query->greaterThanOrEqual('startDate', $now);
278
        }
279
280
        $query->setLimit($limit);
281
        $sort = QueryInterface::ORDER_ASCENDING === $sort ? QueryInterface::ORDER_ASCENDING : QueryInterface::ORDER_DESCENDING;
282
        $query->setOrderings($this->getSorting($sort));
283
284
        return $this->matchAndExecute($query, $constraints);
285
    }
286
287
    /**
288
     * find Year.
289
     *
290
     * @param int $year
291
     *
292
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
293
     */
294
    public function findYear(int $year)
295
    {
296
        return $this->findByTimeSlot(\mktime(0, 0, 0, 1, 1, $year), \mktime(0, 0, 0, 1, 1, $year + 1) - 1);
297
    }
298
299
    /**
300
     * find Month.
301
     *
302
     * @param int $year
303
     * @param int $month
304
     *
305
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
306
     */
307
    public function findMonth(int $year, int $month)
308
    {
309
        $startTime = \mktime(0, 0, 0, $month, 1, $year);
310
        $endTime = \mktime(0, 0, 0, $month + 1, 1, $year) - 1;
311
312
        return $this->findByTimeSlot($startTime, $endTime);
313
    }
314
315
    /**
316
     * find Week.
317
     *
318
     * @param int $year
319
     * @param int $week
320
     * @param int $weekStart See documentation for settings.weekStart
321
     *
322
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
323
     */
324
    public function findWeek($year, $week, $weekStart = 1)
325
    {
326
        $weekStart = (int) $weekStart;
327
        $daysShift = DateTimeUtility::SECONDS_DAY * ($weekStart - 1);
328
        $firstDay = DateTimeUtility::convertWeekYear2DayMonthYear($week, $year);
329
        $timezone = DateTimeUtility::getTimeZone();
330
        $firstDay->setTimezone($timezone);
331
        $timeStampStart = $firstDay->getTimestamp() + $daysShift;
332
333
        return $this->findByTimeSlot($timeStampStart, $timeStampStart + DateTimeUtility::SECONDS_WEEK - 1);
334
    }
335
336
    /**
337
     * Find different types and locations
338
     *
339
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
340
     */
341
    public function findDifferentTypesAndLocations()
342
    {
343
        $query = $this->createQuery();
344
        return $query
0 ignored issues
show
Bug introduced by
The method statement() does not exist on TYPO3\CMS\Extbase\Persistence\QueryInterface. Did you maybe mean getStatement()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
345
            ->statement('SELECT *'
346
                . 'FROM tx_calendarize_domain_model_index '
347
                . 'GROUP BY pid,foreign_table')
348
            ->execute();
349
    }
350
351
    /**
352
     * find day.
353
     *
354
     * @param int $year
355
     * @param int $month
356
     * @param int $day
357
     *
358
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
359
     */
360
    public function findDay(int $year, int $month, int $day)
361
    {
362
        $startTime = \mktime(0, 0, 0, $month, $day, $year);
363
364
        return $this->findByTimeSlot($startTime, $startTime + DateTimeUtility::SECONDS_DAY - 1);
365
    }
366
367
    /**
368
     * Set the default sorting direction.
369
     *
370
     * @param string $direction
371
     * @param string $field
372
     */
373
    public function setDefaultSortingDirection($direction, $field = '')
374
    {
375
        $this->defaultOrderings = $this->getSorting($direction, $field);
376
    }
377
378
    /**
379
     * Find by time slot.
380
     *
381
     * @param int      $startTime
382
     * @param int|null $endTime   null means open end
383
     *
384
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
385
     */
386
    public function findByTimeSlot($startTime, $endTime = null)
387
    {
388
        $query = $this->createQuery();
389
        $constraints = $this->getDefaultConstraints($query);
390
        $this->addTimeFrameConstraints($constraints, $query, $startTime, $endTime);
391
392
        return $this->matchAndExecute($query, $constraints);
393
    }
394
395
    /**
396
     * Find all indices by the given Event model.
397
     *
398
     * @param DomainObjectInterface $event
399
     *
400
     * @throws Exception
401
     *
402
     * @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
403
     */
404
    public function findByEvent(DomainObjectInterface $event)
405
    {
406
        $query = $this->createQuery();
407
408
        $uniqueRegisterKey = ExtensionConfigurationUtility::getUniqueRegisterKeyForModel($event);
409
410
        $this->setIndexTypes([$uniqueRegisterKey]);
411
        $constraints = $this->getDefaultConstraints($query);
412
        $constraints[] = $query->equals('foreignUid', $event->getUid());
413
        $query->matching($query->logicalAnd($constraints));
414
415
        return $query->execute();
416
    }
417
418
    /**
419
     * storage page selection.
420
     *
421
     * @return array
422
     */
423
    protected function getStoragePageIds()
424
    {
425
        if (!empty($this->overridePageIds)) {
426
            return $this->overridePageIds;
427
        }
428
429
        $configurationManager = $this->objectManager->get(ConfigurationManagerInterface::class);
430
        $frameworkConfig = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
431
        $storagePages = isset($frameworkConfig['persistence']['storagePid']) ? GeneralUtility::intExplode(
432
            ',',
433
            $frameworkConfig['persistence']['storagePid']
434
        ) : [];
435
        if (!empty($storagePages)) {
436
            return $storagePages;
437
        }
438
        if ($frameworkConfig instanceof BackendConfigurationManager) {
439
            return GeneralUtility::trimExplode(',', $frameworkConfig->getDefaultBackendStoragePid(), true);
440
        }
441
442
        return $storagePages;
443
    }
444
445
    /**
446
     * Get the default constraint for the queries.
447
     *
448
     * @param QueryInterface $query
449
     *
450
     * @return array
451
     */
452
    protected function getDefaultConstraints(QueryInterface $query)
453
    {
454
        $constraints = [];
455
        if (!empty($this->indexTypes)) {
456
            $indexTypes = $this->indexTypes;
457
            $constraints[] = $query->in('uniqueRegisterKey', $indexTypes);
458
        }
459
460
        $storagePages = $this->getStoragePageIds();
461
        if (!empty($storagePages)) {
462
            $constraints[] = $query->in('pid', $storagePages);
463
        }
464
465
        $arguments = [
466
            'indexIds' => [],
467
            'indexTypes' => $this->indexTypes,
468
        ];
469
        $arguments = $this->callSignal(__CLASS__, __FUNCTION__, $arguments);
470
471
        if ($arguments['indexIds']) {
472
            $constraints[] = $query->in('foreign_uid', $arguments['indexIds']);
473
        }
474
475
        return $constraints;
476
    }
477
478
    /**
479
     * Add time frame related queries.
480
     *
481
     * @param array          $constraints
482
     * @param QueryInterface $query
483
     * @param int            $startTime
484
     * @param int|null       $endTime
485
     *
486
     * @see IndexUtility::isIndexInRange
487
     */
488
    protected function addTimeFrameConstraints(&$constraints, QueryInterface $query, $startTime = null, $endTime = null)
489
    {
490
        $arguments = [
491
            'constraints' => &$constraints,
492
            'query' => $query,
493
            'startTime' => $startTime,
494
            'endTime' => $endTime,
495
        ];
496
        $arguments = $this->callSignal(__CLASS__, __FUNCTION__, $arguments);
497
498
        if (null === $arguments['startTime'] && null === $arguments['endTime']) {
499
            return;
500
        }
501
        if (null === $arguments['startTime']) {
502
            // Simulate start time
503
            $arguments['startTime'] = DateTimeUtility::getNow()->getTimestamp() - DateTimeUtility::SECONDS_DECADE;
504
        } elseif (null === $arguments['endTime']) {
505
            // Simulate end time
506
            $arguments['endTime'] = DateTimeUtility::getNow()->getTimestamp() + DateTimeUtility::SECONDS_DECADE;
507
        }
508
509
        $orConstraint = [];
510
511
        // before - in
512
        $beforeIn = [
513
            $query->lessThan('start_date', $arguments['startTime']),
514
            $query->greaterThanOrEqual('end_date', $arguments['startTime']),
515
            $query->lessThan('end_date', $arguments['endTime']),
516
        ];
517
        $orConstraint[] = $query->logicalAnd($beforeIn);
518
519
        // in - in
520
        $inIn = [
521
            $query->greaterThanOrEqual('start_date', $arguments['startTime']),
522
            $query->lessThan('end_date', $arguments['endTime']),
523
        ];
524
        $orConstraint[] = $query->logicalAnd($inIn);
525
526
        // in - after
527
        $inAfter = [
528
            $query->greaterThanOrEqual('start_date', $arguments['startTime']),
529
            $query->lessThan('start_date', $arguments['endTime']),
530
            $query->greaterThanOrEqual('end_date', $arguments['endTime']),
531
        ];
532
        $orConstraint[] = $query->logicalAnd($inAfter);
533
534
        // before - after
535
        $beforeAfter = [
536
            $query->lessThan('start_date', $arguments['startTime']),
537
            $query->greaterThan('end_date', $arguments['endTime']),
538
        ];
539
        $orConstraint[] = $query->logicalAnd($beforeAfter);
540
541
        // finish
542
        $constraints[] = $query->logicalOr($orConstraint);
543
    }
544
545
    /**
546
     * Get the sorting.
547
     *
548
     * @param string $direction
549
     * @param string $field
550
     *
551
     * @return array
552
     */
553
    protected function getSorting($direction, $field = '')
554
    {
555
        if ('end' !== $field) {
556
            $field = 'start';
557
        }
558
559
        return [
560
            $field . '_date' => $direction,
561
            $field . '_time' => $direction,
562
        ];
563
    }
564
}
565