Skip to content

Commit

Permalink
Handle date_immutable in versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
malarzm committed Nov 23, 2019
1 parent 9615f20 commit 6fd291e
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 20 deletions.
2 changes: 1 addition & 1 deletion lib/Doctrine/ODM/MongoDB/LockException.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ public static function invalidLockFieldType(string $type) : self

public static function invalidVersionFieldType(string $type) : self
{
return new self('Invalid version field type ' . $type . '. Version field must be int or date.');
return new self('Invalid version field type ' . $type . '. Version field must be int, integer, date or date_immutable.');
}
}
2 changes: 1 addition & 1 deletion lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -1653,7 +1653,7 @@ public function isIdGeneratorNone() : bool
*/
public function setVersionMapping(array &$mapping) : void
{
if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
if (! in_array($mapping['type'], [Type::INT, Type::INTEGER, Type::DATE, Type::DATE_IMMUTABLE], true)) {
throw LockException::invalidVersionFieldType($mapping['type']);
}

Expand Down
19 changes: 10 additions & 9 deletions lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use BadMethodCallException;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Hydrator\HydratorException;
Expand Down Expand Up @@ -211,11 +212,11 @@ public function executeInserts(array $options = []) : void
if ($this->class->isVersioned) {
$versionMapping = $this->class->fieldMappings[$this->class->versionField];
$nextVersion = null;
if ($versionMapping['type'] === 'int') {
if ($versionMapping['type'] === Type::INT || $versionMapping['type'] === Type::INTEGER) {
$nextVersion = max(1, (int) $this->class->reflFields[$this->class->versionField]->getValue($document));
$this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersion);
} elseif ($versionMapping['type'] === 'date') {
$nextVersionDateTime = new DateTime();
} elseif ($versionMapping['type'] === Type::DATE || $versionMapping['type'] === Type::DATE_IMMUTABLE) {
$nextVersionDateTime = $versionMapping['type'] === Type::DATE ? new DateTime() : new DateTimeImmutable();
$nextVersion = Type::convertPHPToDatabaseValue($nextVersionDateTime);
$this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersionDateTime);
}
Expand Down Expand Up @@ -286,11 +287,11 @@ private function executeUpsert(object $document, array $options) : void
if ($this->class->isVersioned) {
$versionMapping = $this->class->fieldMappings[$this->class->versionField];
$nextVersion = null;
if ($versionMapping['type'] === 'int') {
if ($versionMapping['type'] === Type::INT || $versionMapping === Type::INTEGER) {
$nextVersion = max(1, (int) $this->class->reflFields[$this->class->versionField]->getValue($document));
$this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersion);
} elseif ($versionMapping['type'] === 'date') {
$nextVersionDateTime = new DateTime();
} elseif ($versionMapping['type'] === Type::DATE || $versionMapping['type'] === Type::DATE_IMMUTABLE) {
$nextVersionDateTime = $versionMapping['type'] === Type::DATE ? new DateTime() : new DateTimeImmutable();
$nextVersion = Type::convertPHPToDatabaseValue($nextVersionDateTime);
$this->class->reflFields[$this->class->versionField]->setValue($document, $nextVersionDateTime);
}
Expand Down Expand Up @@ -371,12 +372,12 @@ public function update(object $document, array $options = []) : void
if ($this->class->isVersioned) {
$versionMapping = $this->class->fieldMappings[$this->class->versionField];
$currentVersion = $this->class->reflFields[$this->class->versionField]->getValue($document);
if ($versionMapping['type'] === 'int') {
if ($versionMapping['type'] === Type::INT || $versionMapping['type'] === Type::INTEGER) {
$nextVersion = $currentVersion + 1;
$update['$inc'][$versionMapping['name']] = 1;
$query[$versionMapping['name']] = $currentVersion;
} elseif ($versionMapping['type'] === 'date') {
$nextVersion = new DateTime();
} elseif ($versionMapping['type'] === Type::DATE || $versionMapping['type'] === Type::DATE_IMMUTABLE) {
$nextVersion = $versionMapping['type'] === Type::DATE ? new DateTime() : new DateTimeImmutable();
$update['$set'][$versionMapping['name']] = Type::convertPHPToDatabaseValue($nextVersion);
$query[$versionMapping['name']] = Type::convertPHPToDatabaseValue($currentVersion);
}
Expand Down
90 changes: 81 additions & 9 deletions tests/Doctrine/ODM/MongoDB/Tests/Functional/LockTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ public function testMultipleFlushesDoIncrementalUpdates()
$this->dm->persist($test);
$this->dm->flush();

$this->assertIsInt($test->getVersion());
$this->assertInternalType('int', $test->getVersion());
$this->assertEquals($i + 1, $test->getVersion());
}
}

public function testLockTimestampSetsDefaultValue()
public function testLockDateSetsDefaultValue()
{
$test = new LockTimestamp();
$test = new LockDate();
$test->title = 'Testing';

$this->assertNull($test->version, 'Pre-Condition');
Expand All @@ -106,11 +106,33 @@ public function testLockTimestampSetsDefaultValue()
return $test;
}

public function testLockTimestampSetsDefaultValueOnUpsert()
public function testLockDateImmutableSetsDefaultValue()
{
$test = new LockDateImmutable();
$test->title = 'Testing';

$this->assertNull($test->version, 'Pre-Condition');

$this->dm->persist($test);
$this->dm->flush();

$date1 = $test->version;

$this->assertInstanceOf('DateTimeImmutable', $date1);

$test->title = 'changed';
$this->dm->flush();

$this->assertNotSame($date1, $test->version);

return $test;
}

public function testLockDateSetsDefaultValueOnUpsert()
{
$id = new ObjectId();

$test = new LockTimestamp();
$test = new LockDate();
$test->title = 'Testing';
$test->id = $id;

Expand All @@ -132,9 +154,52 @@ public function testLockTimestampSetsDefaultValueOnUpsert()
return $test;
}

public function testLockTimestampThrowsException()
public function testLockDateImmutableSetsDefaultValueOnUpsert()
{
$id = new ObjectId();

$test = new LockDateImmutable();
$test->title = 'Testing';
$test->id = $id;

$this->assertNull($test->version, 'Pre-Condition');

$this->dm->persist($test);
$this->dm->flush();

$date1 = $test->version;

$this->assertSame($id, $test->id);
$this->assertInstanceOf('DateTimeImmutable', $date1);

$test->title = 'changed';
$this->dm->flush();

$this->assertNotSame($date1, $test->version);

return $test;
}

public function testLockDateThrowsException()
{
$article = new LockTimestamp('Test LockInt');
$article = new LockDate('Test LockInt');
$this->dm->persist($article);
$this->dm->flush();

// Manually change the version so the next code will cause an exception
$this->dm->getDocumentCollection(get_class($article))->updateOne(['_id' => new ObjectId($article->id)], ['$set' => ['version' => new UTCDateTime(time() * 1000 + 600)]]);

// Now lets change a property and try and save it again
$article->title = 'ok';

$this->expectException(LockException::class);

$this->dm->flush();
}

public function testLockDateImmutableThrowsException()
{
$article = new LockDateImmutable('Test LockInt');
$this->dm->persist($article);
$this->dm->flush();

Expand Down Expand Up @@ -382,7 +447,7 @@ public function testInvalidLockDocument()
public function testInvalidVersionDocument()
{
$this->expectException(MongoDBException::class);
$this->expectExceptionMessage('Invalid version field type string. Version field must be int or date.');
$this->expectExceptionMessage('Invalid version field type string. Version field must be int, integer, date or date_immutable.');
$this->dm->getClassMetadata(InvalidVersionDocument::class);
}

Expand Down Expand Up @@ -468,12 +533,19 @@ class LockInt extends AbstractVersionBase
}

/** @ODM\Document */
class LockTimestamp extends AbstractVersionBase
class LockDate extends AbstractVersionBase
{
/** @ODM\Version @ODM\Field(type="date") */
public $version;
}

/** @ODM\Document */
class LockDateImmutable extends AbstractVersionBase
{
/** @ODM\Version @ODM\Field(type="date_immutable") */
public $version;
}

/** @ODM\Document */
class InvalidLockDocument
{
Expand Down

0 comments on commit 6fd291e

Please sign in to comment.