Completed
Push — master ( 57f196...fb64ee )
by
unknown
15:57
created

Sequenzer::getDefaultStartValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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