Completed
Push — master ( 17edcb...7372de )
by Torben
06:23
created

PageCache::getFirstTimeValueForEvent()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 63
rs 8.185
c 0
b 0
f 0
cc 6
nc 4
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
5
 *
6
 * For the full copyright and license information, please read the
7
 * LICENSE.txt file that was distributed with this source code.
8
 */
9
10
namespace DERHANSEN\SfEventMgt\Hooks;
11
12
use TYPO3\CMS\Core\Database\ConnectionPool;
13
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
14
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
15
use TYPO3\CMS\Core\Utility\GeneralUtility;
16
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
17
18
/**
19
 * PageCache class which implementes the TYPO3 Core hook:
20
 * $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout']
21
 */
22
class PageCache
23
{
24
    /**
25
     * Calculates the page cache timeout for configured pages with event records. Pages must be configured in TypoScript
26
     * using cache.config (similar to starttime/endtime cache handling)
27
     *
28
     * Example: config.cache.3 = tx_sfeventmgt_domain_model_event:2
29
     *
30
     * The cache for PID 3 will respect registration_startdate/registration_deadline of event record in PID 2
31
     *
32
     * @param array $params
33
     * @param TypoScriptFrontendController $pObj
34
     * @return int|mixed
35
     */
36
    public function getCacheTimeout(array $params, TypoScriptFrontendController $pObj)
37
    {
38
        $eventBasedCacheTimeout = $this->calculatePageCacheTimeout($pObj);
39
        if ($eventBasedCacheTimeout === PHP_INT_MAX || $eventBasedCacheTimeout >= $params['cacheTimeout']) {
40
            // Return previous calculated timeout, since event based cache timeout is either not determined or larger
41
            return $params['cacheTimeout'];
42
        }
43
        return $eventBasedCacheTimeout;
44
    }
45
46
    /**
47
     * Calculates page cache timeout according to the events with registration_startdate/registration_deadline
48
     * on the page.
49
     *
50
     * Nearly similar to TypoScriptFrontendController::calculatePageCacheTimeout()
51
     *
52
     * @return int Page cache timeout or PHP_INT_MAX if cannot be determined
53
     */
54
    protected function calculatePageCacheTimeout(TypoScriptFrontendController $pObj)
55
    {
56
        $result = PHP_INT_MAX;
57
        $tablesToConsider = $this->getCurrentPageCacheConfiguration($pObj);
58
59
        if (empty($tablesToConsider)) {
60
            return $result;
61
        }
62
63
        $now = $GLOBALS['ACCESS_TIME'];
64
65
        foreach ($tablesToConsider as $tableDef) {
66
            $result = min($result, $this->getFirstTimeValueForEvent($tableDef, $now));
67
        }
68
69
        return $result === PHP_INT_MAX ? PHP_INT_MAX : $result - $now + 1;
70
    }
71
72
    /**
73
     * Nearly similar to TypoScriptFrontendController::getCurrentPageCacheConfiguration, but only returns
74
     * entries that are relevant for sf_event_mgt
75
     *
76
     * @return array
77
     */
78
    protected function getCurrentPageCacheConfiguration(TypoScriptFrontendController $pObj): array
79
    {
80
        $tables = ['tt_content:' . $pObj->id];
81
        if (isset($pObj->config['config']['cache.'][$pObj->id])) {
82
            $cacheConfig = str_replace(':current', ':' . $pObj->id, $pObj->config['config']['cache.'][$pObj->id]);
83
            $tables = array_merge($tables, GeneralUtility::trimExplode(',', $cacheConfig));
84
        }
85
        if (isset($pObj->config['config']['cache.']['all'])) {
86
            $cacheConfig = str_replace(':current', ':' . $pObj->id, $pObj->config['config']['cache.']['all']);
87
            $tables = array_merge($tables, GeneralUtility::trimExplode(',', $cacheConfig));
88
        }
89
        $tables = array_unique($tables);
90
91
        $result = [];
92
        foreach ($tables as $table) {
93
            if (strpos($table, 'tx_sfeventmgt_domain_model_event') !== false) {
94
                $result[] = $table;
95
            }
96
        }
97
98
        return $result;
99
    }
100
101
    /**
102
     * Nearly similar to TypoScriptFrontendController::getFirstTimeValueForRecord but only considers event fields
103
     * registration_startdate and registration_deadline.
104
     *
105
     * @param string $tableDef Table definition (format tablename:pid)
106
     * @param int $now "Now" time value
107
     * @return int Value of the next registration_startdate/registration_deadline time or PHP_INT_MAX if not found
108
     */
109
    protected function getFirstTimeValueForEvent(string $tableDef, int $now): int
110
    {
111
        $result = PHP_INT_MAX;
112
        [$tableName, $pid] = GeneralUtility::trimExplode(':', $tableDef);
0 ignored issues
show
Bug introduced by
The variable $tableName does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $pid does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
113
114
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
115
            ->getQueryBuilderForTable($tableName);
116
        $queryBuilder->getRestrictions()
117
            ->removeByType(StartTimeRestriction::class)
118
            ->removeByType(EndTimeRestriction::class);
119
        $timeFields = ['registration_startdate', 'registration_deadline'];
120
        $timeConditions = $queryBuilder->expr()->orX();
121
        foreach ($timeFields as $field) {
122
            $queryBuilder->addSelectLiteral(
123
                'MIN('
124
                . 'CASE WHEN '
125
                . $queryBuilder->expr()->lte(
126
                    $field,
127
                    $queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
128
                )
129
                . ' THEN NULL ELSE ' . $queryBuilder->quoteIdentifier($field) . ' END'
130
                . ') AS ' . $queryBuilder->quoteIdentifier($field)
131
            );
132
            $timeConditions->add(
133
                $queryBuilder->expr()->gt(
134
                    $field,
135
                    $queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
136
                )
137
            );
138
        }
139
140
        // Only consider events where registration is enabled and that have not started yet.
141
        // Also include PID and timeConditions
142
        $row = $queryBuilder
143
            ->from($tableName)
144
            ->where(
145
                $queryBuilder->expr()->eq(
146
                    'pid',
147
                    $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)
148
                ),
149
                $queryBuilder->expr()->eq(
150
                    'enable_registration',
151
                    $queryBuilder->createNamedParameter(1, \PDO::PARAM_INT)
152
                ),
153
                $queryBuilder->expr()->gt(
154
                    'startdate',
155
                    $queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
156
                ),
157
                $timeConditions
158
            )
159
            ->execute()
160
            ->fetch();
161
162
        if ($row) {
163
            foreach ($timeFields as $timeField) {
164
                if ($row[$timeField] !== null && (int)$row[$timeField] > $now) {
165
                    $result = min($result, (int)$row[$timeField]);
166
                }
167
            }
168
        }
169
170
        return $result;
171
    }
172
}
173