TableGenerator.php
66 lines
| 1 | <?php |
| 2 | namespace MailPoetVendor\Doctrine\DBAL\Id; |
| 3 | if (!defined('ABSPATH')) exit; |
| 4 | use MailPoetVendor\Doctrine\DBAL\Connection; |
| 5 | use MailPoetVendor\Doctrine\DBAL\Driver; |
| 6 | use MailPoetVendor\Doctrine\DBAL\DriverManager; |
| 7 | use MailPoetVendor\Doctrine\DBAL\Exception; |
| 8 | use MailPoetVendor\Doctrine\Deprecations\Deprecation; |
| 9 | use Throwable; |
| 10 | use function array_change_key_case; |
| 11 | use function assert; |
| 12 | use function is_int; |
| 13 | use const CASE_LOWER; |
| 14 | class TableGenerator |
| 15 | { |
| 16 | private Connection $conn; |
| 17 | private $generatorTableName; |
| 18 | private array $sequences = []; |
| 19 | public function __construct(Connection $conn, $generatorTableName = 'sequences') |
| 20 | { |
| 21 | Deprecation::trigger('doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4681', 'The TableGenerator class is is deprecated.'); |
| 22 | if ($conn->getDriver() instanceof Driver\PDO\SQLite\Driver) { |
| 23 | throw new Exception('Cannot use TableGenerator with SQLite.'); |
| 24 | } |
| 25 | $this->conn = DriverManager::getConnection($conn->getParams(), $conn->getConfiguration(), $conn->getEventManager()); |
| 26 | $this->generatorTableName = $generatorTableName; |
| 27 | } |
| 28 | public function nextValue($sequence) |
| 29 | { |
| 30 | if (isset($this->sequences[$sequence])) { |
| 31 | $value = $this->sequences[$sequence]['value']; |
| 32 | $this->sequences[$sequence]['value']++; |
| 33 | if ($this->sequences[$sequence]['value'] >= $this->sequences[$sequence]['max']) { |
| 34 | unset($this->sequences[$sequence]); |
| 35 | } |
| 36 | return $value; |
| 37 | } |
| 38 | $this->conn->beginTransaction(); |
| 39 | try { |
| 40 | $row = $this->conn->createQueryBuilder()->select('sequence_value', 'sequence_increment_by')->from($this->generatorTableName)->where('sequence_name = ?')->forUpdate()->setParameter(1, $sequence)->fetchAssociative(); |
| 41 | if ($row !== \false) { |
| 42 | $row = array_change_key_case($row, CASE_LOWER); |
| 43 | $value = $row['sequence_value']; |
| 44 | $value++; |
| 45 | assert(is_int($value)); |
| 46 | if ($row['sequence_increment_by'] > 1) { |
| 47 | $this->sequences[$sequence] = ['value' => $value, 'max' => $row['sequence_value'] + $row['sequence_increment_by']]; |
| 48 | } |
| 49 | $sql = 'UPDATE ' . $this->generatorTableName . ' ' . 'SET sequence_value = sequence_value + sequence_increment_by ' . 'WHERE sequence_name = ? AND sequence_value = ?'; |
| 50 | $rows = $this->conn->executeStatement($sql, [$sequence, $row['sequence_value']]); |
| 51 | if ($rows !== 1) { |
| 52 | throw new Exception('Race-condition detected while updating sequence. Aborting generation'); |
| 53 | } |
| 54 | } else { |
| 55 | $this->conn->insert($this->generatorTableName, ['sequence_name' => $sequence, 'sequence_value' => 1, 'sequence_increment_by' => 1]); |
| 56 | $value = 1; |
| 57 | } |
| 58 | $this->conn->commit(); |
| 59 | } catch (Throwable $e) { |
| 60 | $this->conn->rollBack(); |
| 61 | throw new Exception('Error occurred while generating ID with TableGenerator, aborted generation: ' . $e->getMessage(), 0, $e); |
| 62 | } |
| 63 | return $value; |
| 64 | } |
| 65 | } |
| 66 |