-
Notifications
You must be signed in to change notification settings - Fork 1.5k
PHPORM-206 Add model schema version feature #3021
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
d04aa53
Add document version feature
florianJacques 22ff562
Add retrieved model migration and version helpers
florianJacques 32b7cfa
Add tests
florianJacques 8fb72e7
remove php doc
florianJacques cdbdb42
Fix version manually upgrade
florianJacques a224baa
Add document version setter, remove public property
florianJacques 733b6d5
Update src/Eloquent/HasDocumentVersion.php
florianJacques 3eeb991
Rename trait and refacto
florianJacques 9f2c49f
Typo fix, and rename classes
florianJacques ba0b900
Add upgrade schema function
florianJacques f9d785d
Remove spaces
florianJacques f406aea
Fix events
florianJacques 9e302b8
Update src/Eloquent/HasSchemaVersion.php
florianJacques a8ca8aa
Use a constant to store SCHEMA_VERSION
GromNaN File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MongoDB\Laravel\Eloquent; | ||
|
||
use Error; | ||
use LogicException; | ||
|
||
use function sprintf; | ||
|
||
/** | ||
* Use this trait to implement schema versioning in your models. The document | ||
* is updated automatically when its schema version retrieved from the database | ||
* is lower than the current schema version of the model. | ||
* | ||
* class MyVersionedModel extends Model | ||
* { | ||
* use HasSchemaVersion; | ||
* | ||
* public const int SCHEMA_VERSION = 1; | ||
* | ||
* public function migrateSchema(int $fromVersion): void | ||
* { | ||
* // Your logic to update the document to the current schema version | ||
* } | ||
* } | ||
* | ||
* @see https://www.mongodb.com/docs/manual/tutorial/model-data-for-schema-versioning/ | ||
* | ||
* Requires PHP 8.2+ | ||
*/ | ||
trait HasSchemaVersion | ||
{ | ||
/** | ||
* This method should be implemented in the model to migrate a document from | ||
* an older schema version to the current schema version. | ||
*/ | ||
public function migrateSchema(int $fromVersion): void | ||
{ | ||
} | ||
|
||
public static function bootHasSchemaVersion(): void | ||
{ | ||
static::saving(function ($model) { | ||
if ($model->getAttribute($model::getSchemaVersionKey()) === null) { | ||
$model->setAttribute($model::getSchemaVersionKey(), $model->getModelSchemaVersion()); | ||
} | ||
}); | ||
|
||
static::retrieved(function (self $model) { | ||
$version = $model->getSchemaVersion(); | ||
|
||
if ($version < $model->getModelSchemaVersion()) { | ||
$model->migrateSchema($version); | ||
$model->setAttribute($model::getSchemaVersionKey(), $model->getModelSchemaVersion()); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Get Current document version, fallback to 0 if not set | ||
*/ | ||
public function getSchemaVersion(): int | ||
{ | ||
return $this->{static::getSchemaVersionKey()} ?? 0; | ||
} | ||
|
||
protected static function getSchemaVersionKey(): string | ||
{ | ||
return 'schema_version'; | ||
} | ||
|
||
protected function getModelSchemaVersion(): int | ||
{ | ||
try { | ||
return $this::SCHEMA_VERSION; | ||
} catch (Error) { | ||
throw new LogicException(sprintf('Constant %s::SCHEMA_VERSION is required when using HasSchemaVersion', $this::class)); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MongoDB\Laravel\Tests\Models; | ||
|
||
use MongoDB\Laravel\Eloquent\HasSchemaVersion; | ||
use MongoDB\Laravel\Eloquent\Model as Eloquent; | ||
|
||
class SchemaVersion extends Eloquent | ||
{ | ||
use HasSchemaVersion; | ||
|
||
public const SCHEMA_VERSION = 2; | ||
|
||
protected $connection = 'mongodb'; | ||
protected $collection = 'documentVersion'; | ||
protected static $unguarded = true; | ||
|
||
public function migrateSchema(int $fromVersion): void | ||
{ | ||
if ($fromVersion < 2) { | ||
$this->age = 35; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MongoDB\Laravel\Tests; | ||
|
||
use Illuminate\Support\Facades\DB; | ||
use LogicException; | ||
use MongoDB\Laravel\Eloquent\HasSchemaVersion; | ||
use MongoDB\Laravel\Eloquent\Model; | ||
use MongoDB\Laravel\Tests\Models\SchemaVersion; | ||
|
||
class SchemaVersionTest extends TestCase | ||
{ | ||
public function tearDown(): void | ||
{ | ||
SchemaVersion::truncate(); | ||
} | ||
|
||
public function testWithBasicDocument() | ||
{ | ||
$document = new SchemaVersion(['name' => 'Luc']); | ||
$this->assertEmpty($document->getSchemaVersion()); | ||
$document->save(); | ||
|
||
// The current schema version of the model is stored by default | ||
$this->assertEquals(2, $document->getSchemaVersion()); | ||
|
||
// Test automatic migration | ||
SchemaVersion::insert([ | ||
['name' => 'Vador', 'schema_version' => 1], | ||
]); | ||
florianJacques marked this conversation as resolved.
Show resolved
Hide resolved
|
||
$document = SchemaVersion::where('name', 'Vador')->first(); | ||
$this->assertEquals(2, $document->getSchemaVersion()); | ||
$this->assertEquals(35, $document->age); | ||
|
||
$document->save(); | ||
|
||
// The migrated version is saved | ||
$data = DB::connection('mongodb') | ||
->collection('documentVersion') | ||
->where('name', 'Vador') | ||
->get(); | ||
|
||
$this->assertEquals(2, $data[0]['schema_version']); | ||
} | ||
|
||
public function testIncompleteImplementation(): void | ||
{ | ||
$this->expectException(LogicException::class); | ||
$this->expectExceptionMessage('::SCHEMA_VERSION is required when using HasSchemaVersion'); | ||
$document = new class extends Model { | ||
use HasSchemaVersion; | ||
}; | ||
|
||
$document->save(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.