Skip to content

Commit 0667a41

Browse files
committed
- Improve OptimisticLock to work with 1 query
- Add orderBy param to findOneInternal method
1 parent 6e5824d commit 0667a41

File tree

5 files changed

+58
-29
lines changed

5 files changed

+58
-29
lines changed

src/AbstractTable.php

+38-26
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,23 @@ public function save(AbstractEntity &$entity): void
7373
$changedColumns['updated_at'] = DateTimeHelper::dateTimeToString($entity->updated_at);
7474
}
7575

76-
if ($this->config->hasOptimisticLock() && isset($entity->version)) {
77-
$currentVersion = $entity->version;
76+
77+
if ($this->config->hasOptimisticLock()
78+
&& method_exists($entity, 'getVersion')
79+
&& method_exists($entity, 'incrementVersion')) {
80+
$where['lock_version'] = $entity->getVersion();
81+
$entity->incrementVersion();
82+
$changedColumns['lock_version'] = $entity->getVersion();
83+
7884
try {
7985
$connection->beginTransaction();
80-
$connection->update(
86+
$versionUpdated = $connection->update(
8187
$this->getTableName(),
8288
$changedColumns,
8389
$where
8490
);
85-
$versionUpdated = $connection->update(
86-
$this->getTableName(),
87-
['version' => $currentVersion + 1],
88-
$where + ['version' => $currentVersion]
89-
);
9091
if (!$versionUpdated) {
91-
throw new DbException('Failed to update entity version, concurrency modification, rolling back.');
92+
throw new Exceptions\LockException('Failed to update entity version, concurrency modification, rolling back.');
9293
}
9394
$connection->commit();
9495
} catch (\Throwable $e) {
@@ -213,13 +214,15 @@ protected function findByPkInternal(mixed $pk): ?array
213214

214215
/**
215216
* @param array<string, mixed> $where
217+
* @param array<string, string>|string $orderBy
216218
* @return array<string, mixed>|null
217219
* @throws \Doctrine\DBAL\Exception
218220
*/
219-
protected function findOneInternal(array $where): ?array
221+
protected function findOneInternal(array $where, array|string $orderBy = []): ?array
220222
{
221223
$query = $this->select();
222224
$this->buildWhere($query, $where);
225+
$this->applyOrderBy($query, $orderBy);
223226
return $query->fetchAssociative() ?: null;
224227
}
225228

@@ -259,22 +262,7 @@ protected function findAllInternal(
259262
$query->setParameter($param, $value);
260263
}
261264
}
262-
if ($orderBy) {
263-
if (is_array($orderBy)) {
264-
foreach ($orderBy as $column => $direction) {
265-
$query->addOrderBy($column, $direction);
266-
}
267-
} else {
268-
foreach (explode(',', $orderBy) as $orderByPart) {
269-
$orderByPart = trim($orderByPart);
270-
if (preg_match('/(.+)\s(asc|desc)$/i', $orderByPart, $orderByPartMatch)) {
271-
$query->addOrderBy($orderByPartMatch[1], $orderByPartMatch[2]);
272-
} else {
273-
$query->addOrderBy($orderByPart);
274-
}
275-
}
276-
}
277-
}
265+
$this->applyOrderBy($query, $orderBy);
278266
if ($limit > 0) {
279267
$query->setMaxResults($limit);
280268
}
@@ -398,4 +386,28 @@ private function formatData(array $data): array
398386
}
399387
return $data;
400388
}
389+
390+
/**
391+
* @param array<string, string>|string $orderBy
392+
*/
393+
private function applyOrderBy(QueryBuilder $query, string|array $orderBy): void
394+
{
395+
if (!$orderBy) {
396+
return;
397+
}
398+
if (is_array($orderBy)) {
399+
foreach ($orderBy as $column => $direction) {
400+
$query->addOrderBy($column, $direction);
401+
}
402+
} else {
403+
foreach (explode(',', $orderBy) as $orderByPart) {
404+
$orderByPart = trim($orderByPart);
405+
if (preg_match('/(.+)\s(asc|desc)$/i', $orderByPart, $orderByPartMatch)) {
406+
$query->addOrderBy($orderByPartMatch[1], $orderByPartMatch[2]);
407+
} else {
408+
$query->addOrderBy($orderByPart);
409+
}
410+
}
411+
}
412+
}
401413
}

src/Exceptions/LockException.php

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Composite\DB\Exceptions;
4+
5+
class LockException extends DbException
6+
{
7+
}

src/Traits/OptimisticLock.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,15 @@
44

55
trait OptimisticLock
66
{
7-
public int $version = 1;
7+
protected int $lock_version = 1;
8+
9+
public function getVersion(): int
10+
{
11+
return $this->lock_version;
12+
}
13+
14+
public function incrementVersion(): void
15+
{
16+
$this->lock_version++;
17+
}
818
}

tests/TestStand/Tables/TestOptimisticLockTable.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function init(): bool
3232
(
3333
`id` INTEGER NOT NULL CONSTRAINT TestAutoincrement_pk PRIMARY KEY AUTOINCREMENT,
3434
`name` VARCHAR(255) NOT NULL,
35-
`version` INTEGER NOT NULL DEFAULT 1,
35+
`lock_version` INTEGER NOT NULL DEFAULT 1,
3636
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
3737
);
3838
"

tests/Traits/OptimisticLockTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function test_trait(): void
6060
$this->assertTrue($db->rollBack());
6161

6262
$olEntity3 = $olTable1->findByPk($olEntity1->id);
63-
$this->assertEquals(1, $olEntity3->version);
63+
$this->assertEquals(1, $olEntity3->getVersion());
6464
$this->assertEquals('John', $olEntity3->name);
6565
}
6666
}

0 commit comments

Comments
 (0)