Skip to content

Commit e255785

Browse files
dritterfranmomu
andauthored
[Sortable] Resolve Column Type when fetching Max Position from Database (#2462)
* Resolve Column Type when fetching Max Position from Database In SQLite it makes a difference if date columns are queried with '00:00:00' as timestring or without. MySQL seems to ignore the time completely. Unfortunately there is an asymmetry between SQL Types and PHP Objects: 'date' and 'datetime' Column point both to a DateTime Object in PHP. Therefore, we cannot derive the column type from the PHP Object. Luckily we can ask the ClassMetadata in Doctrine for the right type. * Fix CS * Update tests/Gedmo/Sortable/Fixture/ItemWithDateColumn.php Co-authored-by: Fran Moreno <[email protected]> * Update tests/Gedmo/Sortable/Fixture/ItemWithDateColumn.php Co-authored-by: Fran Moreno <[email protected]> * Update tests/Gedmo/Sortable/Fixture/ItemWithDateColumn.php Co-authored-by: Fran Moreno <[email protected]> * Update tests/Gedmo/Sortable/Fixture/ItemWithDateColumn.php Co-authored-by: Fran Moreno <[email protected]> * Update tests/Gedmo/Sortable/Fixture/ItemWithDateColumn.php Co-authored-by: Fran Moreno <[email protected]> * Add Type Hints * Add Changelog entry * Update tests/Gedmo/Sortable/SortableGroupTest.php Co-authored-by: Fran Moreno <[email protected]> * Save some CPU cycles by reducing amount of generated test data * Simplify Test by removing unnecessary Group Members Co-authored-by: Fran Moreno <[email protected]>
1 parent 501f1a1 commit e255785

File tree

4 files changed

+122
-3
lines changed

4 files changed

+122
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ a release.
2424
- [NestedSet] childrenQueryBuilder() to allow specifying sort order separately for each field
2525
- [NestedSet] Added option to reorder only direct children in reorder() method
2626

27+
### Sortable
28+
#### Fixed
29+
- [SortableGroup] Fix sorting date columns in SQLite (#2462).
30+
2731
## [3.7.0] - 2022-05-17
2832
## Added
2933
- Add support for doctrine/persistence 3

src/Sortable/Mapping/Event/Adapter/ORM.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function getMaxPosition(array $config, $meta, $groups)
3535
$qb = $em->createQueryBuilder();
3636
$qb->select('MAX(n.'.$config['position'].')')
3737
->from($config['useObjectClass'], 'n');
38-
$this->addGroupWhere($qb, $groups);
38+
$this->addGroupWhere($qb, $meta, $groups);
3939
$query = $qb->getQuery();
4040
$query->useQueryCache(false);
4141
$query->disableResultCache();
@@ -108,15 +108,15 @@ public function updatePositions($relocation, $delta, $config)
108108
$q->getSingleScalarResult();
109109
}
110110

111-
private function addGroupWhere(QueryBuilder $qb, iterable $groups): void
111+
private function addGroupWhere(QueryBuilder $qb, ClassMetadata $metadata, iterable $groups): void
112112
{
113113
$i = 1;
114114
foreach ($groups as $group => $value) {
115115
if (null === $value) {
116116
$qb->andWhere($qb->expr()->isNull('n.'.$group));
117117
} else {
118118
$qb->andWhere('n.'.$group.' = :group__'.$i);
119-
$qb->setParameter('group__'.$i, $value);
119+
$qb->setParameter('group__'.$i, $value, $metadata->getTypeOfField($group));
120120
}
121121
++$i;
122122
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Doctrine Behavioral Extensions package.
5+
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
namespace Gedmo\Tests\Sortable\Fixture;
11+
12+
use Doctrine\DBAL\Types\Types;
13+
use Doctrine\ORM\Mapping as ORM;
14+
use Gedmo\Mapping\Annotation as Gedmo;
15+
use Gedmo\Sortable\Entity\Repository\SortableRepository;
16+
17+
/**
18+
* @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
19+
*/
20+
#[ORM\Entity(repositoryClass: SortableRepository::class)]
21+
class ItemWithDateColumn
22+
{
23+
/**
24+
* @var int|null
25+
*
26+
* @ORM\Id
27+
* @ORM\GeneratedValue
28+
* @ORM\Column(type="integer")
29+
*/
30+
#[ORM\Id]
31+
#[ORM\GeneratedValue]
32+
#[ORM\Column(type: Types::INTEGER)]
33+
private $id;
34+
35+
/**
36+
* @var int
37+
*
38+
* @Gedmo\SortablePosition
39+
* @ORM\Column(type="integer")
40+
*/
41+
#[Gedmo\SortablePosition]
42+
#[ORM\Column(type: Types::INTEGER)]
43+
private $position = 0;
44+
45+
/**
46+
* @var \DateTime|null
47+
*
48+
* @Gedmo\SortableGroup
49+
* @ORM\Column(type="date")
50+
*/
51+
#[Gedmo\SortableGroup]
52+
#[ORM\Column(type: Types::DATE_MUTABLE)]
53+
private $date;
54+
55+
public function getId(): ?int
56+
{
57+
return $this->id;
58+
}
59+
60+
public function setId(?int $id): void
61+
{
62+
$this->id = $id;
63+
}
64+
65+
public function getPosition(): int
66+
{
67+
return $this->position;
68+
}
69+
70+
public function setPosition(int $position): void
71+
{
72+
$this->position = $position;
73+
}
74+
75+
public function getDate(): ?\DateTime
76+
{
77+
return $this->date;
78+
}
79+
80+
public function setDate(?\DateTime $date): void
81+
{
82+
$this->date = $date;
83+
}
84+
}

tests/Gedmo/Sortable/SortableGroupTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Gedmo\Sortable\SortableListener;
1616
use Gedmo\Tests\Sortable\Fixture\Category;
1717
use Gedmo\Tests\Sortable\Fixture\Item;
18+
use Gedmo\Tests\Sortable\Fixture\ItemWithDateColumn;
1819
use Gedmo\Tests\Sortable\Fixture\Transport\Bus;
1920
use Gedmo\Tests\Sortable\Fixture\Transport\Car;
2021
use Gedmo\Tests\Sortable\Fixture\Transport\Engine;
@@ -36,6 +37,7 @@ final class SortableGroupTest extends BaseTestCaseORM
3637
public const RESERVATION = Reservation::class;
3738
public const ITEM = Item::class;
3839
public const CATEGORY = Category::class;
40+
public const ITEM_WITH_DATE_COLUMN = ItemWithDateColumn::class;
3941

4042
public const SEATS = 3;
4143

@@ -239,6 +241,34 @@ public function testShouldBeAbleToChangeGroupAndPosition(): void
239241
static::assertSame(30, $position);
240242
}
241243

244+
public function testChangePositionWithDateColumn(): void
245+
{
246+
for ($i = 0; $i < 6; ++$i) {
247+
$object = new ItemWithDateColumn();
248+
$today = new \DateTime('2022-05-22');
249+
$object->setDate($today);
250+
$object->setPosition($i);
251+
$this->em->persist($object);
252+
}
253+
$this->em->flush();
254+
255+
$repo = $this->em->getRepository(self::ITEM_WITH_DATE_COLUMN);
256+
257+
/** @var ItemWithDateColumn $testItem */
258+
$testItem = $repo->findOneBy(['id' => 5]);
259+
$testItem->setPosition(1);
260+
261+
$this->em->persist($testItem);
262+
$this->em->flush();
263+
264+
/** @var ItemWithDateColumn $freshItem */
265+
$freshItem = $repo->findOneBy(['id' => 5]);
266+
/** @var ItemWithDateColumn $freshPreviousItem */
267+
$freshPreviousItem = $repo->findOneBy(['id' => 2]);
268+
static::assertSame(1, $freshItem->getPosition());
269+
static::assertSame(2, $freshPreviousItem->getPosition());
270+
}
271+
242272
protected function getUsedEntityFixtures(): array
243273
{
244274
return [
@@ -249,6 +279,7 @@ protected function getUsedEntityFixtures(): array
249279
self::RESERVATION,
250280
self::ITEM,
251281
self::CATEGORY,
282+
self::ITEM_WITH_DATE_COLUMN,
252283
];
253284
}
254285

0 commit comments

Comments
 (0)