1<?php
2/*
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 *
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace Doctrine\ORM\Id;
21
22use Doctrine\ORM\EntityManager;
23use Serializable;
24
25/**
26 * Represents an ID generator that uses a database sequence.
27 *
28 * @since 2.0
29 * @author Roman Borschel <roman@code-factory.org>
30 */
31class SequenceGenerator extends AbstractIdGenerator implements Serializable
32{
33    /**
34     * The allocation size of the sequence.
35     *
36     * @var int
37     */
38    private $_allocationSize;
39
40    /**
41     * The name of the sequence.
42     *
43     * @var string
44     */
45    private $_sequenceName;
46
47    /**
48     * @var int
49     */
50    private $_nextValue = 0;
51
52    /**
53     * @var int|null
54     */
55    private $_maxValue = null;
56
57    /**
58     * Initializes a new sequence generator.
59     *
60     * @param string  $sequenceName   The name of the sequence.
61     * @param integer $allocationSize The allocation size of the sequence.
62     */
63    public function __construct($sequenceName, $allocationSize)
64    {
65        $this->_sequenceName = $sequenceName;
66        $this->_allocationSize = $allocationSize;
67    }
68
69    /**
70     * {@inheritDoc}
71     */
72    public function generate(EntityManager $em, $entity)
73    {
74        if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
75            // Allocate new values
76            $conn = $em->getConnection();
77            $sql  = $conn->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
78
79            // Using `query` to force usage of the master server in MasterSlaveConnection
80            $this->_nextValue = (int) $conn->query($sql)->fetchColumn();
81            $this->_maxValue  = $this->_nextValue + $this->_allocationSize;
82        }
83
84        return $this->_nextValue++;
85    }
86
87    /**
88     * Gets the maximum value of the currently allocated bag of values.
89     *
90     * @return integer|null
91     */
92    public function getCurrentMaxValue()
93    {
94        return $this->_maxValue;
95    }
96
97    /**
98     * Gets the next value that will be returned by generate().
99     *
100     * @return integer
101     */
102    public function getNextValue()
103    {
104        return $this->_nextValue;
105    }
106
107    /**
108     * @return string
109     */
110    public function serialize()
111    {
112        return serialize(
113            [
114            'allocationSize' => $this->_allocationSize,
115            'sequenceName'   => $this->_sequenceName
116            ]
117        );
118    }
119
120    /**
121     * @param string $serialized
122     *
123     * @return void
124     */
125    public function unserialize($serialized)
126    {
127        $array = unserialize($serialized);
128
129        $this->_sequenceName = $array['sequenceName'];
130        $this->_allocationSize = $array['allocationSize'];
131    }
132}
133