Completed
Branch TYPO3V8 (1e9d52)
by Tomas Norre
12:04
created

Sequenzer::escapeString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
namespace Aoe\AoeDbSequenzer;
4
5
use Doctrine\DBAL\Types\Type;
6
use TYPO3\CMS\Core\Database\Connection;
7
use TYPO3\CMS\Core\Database\ConnectionPool;
8
use TYPO3\CMS\Core\Utility\GeneralUtility;
9
10
/***************************************************************
11
 *  Copyright notice
12
 *
13
 *  (c) 2017 AOE GmbH ([email protected])
14
 *  All rights reserved
15
 *
16
 *  This script is part of the TYPO3 project. The TYPO3 project is
17
 *  free software; you can redistribute it and/or modify
18
 *  it under the terms of the GNU General Public License as published by
19
 *  the Free Software Foundation; either version 2 of the License, or
20
 *  (at your option) any later version.
21
 *
22
 *  The GNU General Public License can be found at
23
 *  http://www.gnu.org/copyleft/gpl.html.
24
 *
25
 *  This script is distributed in the hope that it will be useful,
26
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 *  GNU General Public License for more details.
29
 *
30
 *  This copyright notice MUST APPEAR in all copies of the script!
31
 ***************************************************************/
32
33
/**
34
 * Sequenzer is used to generate system wide independent IDs
35
 *
36
 * @package Aoe\AoeDbSequenzer
37
 */
38
class Sequenzer
39
{
40
    /**
41
     * @var string
42
     */
43
    const SEQUENZER_TABLE = 'tx_aoedbsequenzer_sequenz';
44
45
    /**
46
     * @var integer
47
     */
48
    private $defaultStart = 0;
49
50
    /**
51
     * @var integer
52
     */
53
    private $defaultOffset = 1;
54
55
    /**
56
     * @var integer in seconds
57
     */
58
    private $checkInterval = 120;
59
60
    /**
61
     * @param integer $defaultStart to set
62
     */
63
    public function setDefaultStart($defaultStart)
64
    {
65
        $this->defaultStart = $defaultStart;
66
    }
67
68
    /**
69
     * @param integer $defaultOffset to set
70
     */
71
    public function setDefaultOffset($defaultOffset)
72
    {
73
        $this->defaultOffset = $defaultOffset;
74
    }
75
76
    /**
77
     * returns next free id in the sequenz of the table
78
     *
79
     * @param     $table
80
     * @param int $depth
81
     *
82
     * @return int
83
     * @throws \Exception
84
     */
85
    public function getNextIdForTable($table, $depth = 0)
86
    {
87
        if ($depth > 99) {
88
            throw new \Exception(
89
                'The sequenzer cannot return IDs for this table -' . $table . ' Too many recursions - maybe to much load?',
90
                1512378158
91
            );
92
        }
93
        /** @var Connection $databaseConnection */
94
        $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::SEQUENZER_TABLE);
95
        $row = $databaseConnection->select(['*'], self::SEQUENZER_TABLE, ['tablename' => $table])->fetch();
96
97
        if (!isset($row['current'])) {
98
            $this->initSequenzerForTable($table);
99
100
            return $this->getNextIdForTable($table, ++$depth);
101
        } elseif ($row['timestamp'] + $this->checkInterval < $GLOBALS['EXEC_TIME']) {
102
            $defaultStartValue = $this->getDefaultStartValue($table);
103
            $isValueOutdated = ($row['current'] < $defaultStartValue);
104
            $isOffsetChanged = ($row['offset'] != $this->defaultOffset);
105
            $isStartChanged = ($row['current'] % $this->defaultOffset != $this->defaultStart);
106
            if ($isValueOutdated || $isOffsetChanged || $isStartChanged) {
107
                $row['current'] = $defaultStartValue;
108
            }
109
        }
110
111
        $new = $row['current'] + $row['offset'];
112
        $updateTimeStamp = $GLOBALS['EXEC_TIME'];
113
        $updateResult = $databaseConnection->update(
114
            self::SEQUENZER_TABLE,
115
            ['current' => $new, 'timestamp' => $updateTimeStamp],
116
            ['timestamp' => $row['timestamp'], 'tablename' => $table]
117
        );
118
119
        if ($updateResult > 0) {
120
            return $new;
121
        } else {
122
            return $this->getNextIdForTable($table, ++$depth);
123
        }
124
    }
125
126
    /**
127
     * Gets the default start value for a given table.
128
     *
129
     * @param $table
130
     *
131
     * @return int
132
     * @throws \Exception
133
     */
134
    private function getDefaultStartValue($table)
135
    {
136
        /** @var Connection $databaseConnection */
137
        $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::SEQUENZER_TABLE);
138
        $row = $databaseConnection->select(['uid'], $table, [], [], ['uid' => 'DESC'], 1)->fetch();
139
        $currentMax = $row['uid'] + 1;
140
        $start = $this->defaultStart + ($this->defaultOffset * ceil($currentMax / $this->defaultOffset));
141
142
        return $start;
143
    }
144
145
    /**
146
     * if no scheduler entry for the table yet exists, this method initialises the sequenzer to fit offest and start and current max value
147
     * in the table
148
     *
149
     * @param string $table
150
     *
151
     * @throws \Exception
152
     */
153
    private function initSequenzerForTable($table)
154
    {
155
        $start = $this->getDefaultStartValue($table);
156
157
        /** @var Connection $databaseConnection */
158
        $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::SEQUENZER_TABLE);
159
        $databaseConnection->insert(
160
            self::SEQUENZER_TABLE,
161
            ['tablename' => $table, 'current' => $start, 'offset' => $this->defaultOffset, 'timestamp' => $GLOBALS['EXEC_TIME']],
162
            [Type::STRING, Type::INTEGER, Type::INTEGER, Type::STRING]
163
        );
164
    }
165
}
166