From 4943bcccd0542eb244ca59c50dfadfba578081de Mon Sep 17 00:00:00 2001 From: Rea Rustagi <85902999+rustagir@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:49:34 -0400 Subject: [PATCH] DOCSP-41306: schema version trait (#3051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DOCSP-41306: schema version trait * MW PR fixes 1 * add test wip * add tests * apply phpcbf formatting * JM tech review 1 * error * comment style * Fix test, expose 2 models, lock laravel version to avoid breaking change * JM tech review 2 * fixes * revert database v * JM tech review 3 * JM tech review 4 --------- Co-authored-by: rustagir Co-authored-by: Jérôme Tamarelle --- docs/eloquent-models/model-class.txt | 101 +++++++++++++++++- .../eloquent-models/PlanetSchemaVersion1.php | 10 ++ .../eloquent-models/PlanetSchemaVersion2.php | 26 +++++ .../eloquent-models/SchemaVersionTest.php | 54 ++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 docs/includes/eloquent-models/PlanetSchemaVersion1.php create mode 100644 docs/includes/eloquent-models/PlanetSchemaVersion2.php create mode 100644 docs/includes/eloquent-models/SchemaVersionTest.php diff --git a/docs/eloquent-models/model-class.txt b/docs/eloquent-models/model-class.txt index f1d1fbdda..ad5565abe 100644 --- a/docs/eloquent-models/model-class.txt +++ b/docs/eloquent-models/model-class.txt @@ -33,6 +33,8 @@ to {+odm-short+} models: - :ref:`laravel-model-customize` explains several model class customizations. - :ref:`laravel-model-pruning` shows how to periodically remove models that you no longer need. +- :ref:`laravel-schema-versioning` shows how to implement model schema + versioning. .. _laravel-model-define: @@ -67,7 +69,6 @@ This model is stored in the ``planets`` MongoDB collection. To learn how to specify the database name that your Laravel application uses, :ref:`laravel-quick-start-connect-to-mongodb`. - .. _laravel-authenticatable-model: Extend the Authenticatable Model @@ -333,3 +334,101 @@ models that the prune action deletes: :emphasize-lines: 5,10,12 :dedent: +.. _laravel-schema-versioning: + +Create a Versioned Model Schema +------------------------------- + +You can implement a schema versioning pattern into your application by +using the ``HasSchemaVersion`` trait on an Eloquent model. You might +choose to implement a schema version to organize or standardize a +collection that contains data with different schemas. + +.. tip:: + + To learn more about schema versioning, see the :manual:`Model Data for + Schema Versioning ` + tutorial in the {+server-docs-name+}. + +To use this feature with models that use MongoDB as a database, add the +``MongoDB\Laravel\Eloquent\HasSchemaVersion`` import to your model. +Then, set the ``SCHEMA_VERSION`` constant to ``1`` to set the first +schema version on your collection. If your collection evolves to contain +multiple schemas, you can update the value of the ``SCHEMA_VERSION`` +constant in subsequent model classes. + +When creating your model, you can define the ``migrateSchema()`` method +to specify a migration to the current schema version upon retrieving a +model. In this method, you can specify the changes to make to an older +model to update it to match the current schema version. + +When you save a model that does not have a schema version +specified, the ``HasSchemaVersion`` trait assumes that it follows the +latest schema version. When you retrieve a model that does not contain +the ``schema_version`` field, the trait assumes that its schema version +is ``0`` and performs the migration. + +Schema Versioning Example +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this sample situation, you are working with a collection that was +first modeled by the following class: + +.. literalinclude:: /includes/eloquent-models/PlanetSchemaVersion1.php + :language: php + :dedent: + +Now, you want to implement a new schema version on the collection. +You can define the new model class with the following behavior: + +- Implements the ``HasSchemaVersion`` trait and sets the current + ``SCHEMA_VERSION`` to ``2`` + +- Defines the ``migrateSchema()`` method to migrate models in which the + schema version is less than ``2`` to have a ``galaxy`` field that has a value + of ``'Milky Way'`` + +.. literalinclude:: /includes/eloquent-models/PlanetSchemaVersion2.php + :language: php + :emphasize-lines: 10,12,20 + :dedent: + +In the ``"WASP-39 b"`` document in the following code, the +``schema_version`` field value is less than ``2``. When you retrieve the +document, {+odm-short+} adds the ``galaxy`` field and updates the schema +version to the current version, ``2``. + +The ``"Saturn"`` document does not contain the ``schema_version`` field, +so {+odm-short+} assigns it the current schema version upon saving. + +Finally, the code retrieves the models from the collection to +demonstrate the changes: + +.. io-code-block:: + :copyable: true + + .. input:: /includes/eloquent-models/SchemaVersionTest.php + :language: php + :dedent: + :start-after: begin-schema-version + :end-before: end-schema-version + + .. output:: + :language: none + :visible: false + + [ + { + "_id": ..., + "name": "WASP-39 b", + "type": "gas", + "galaxy": "Milky Way", + "schema_version": 2, + }, + { + "_id": ..., + "name": "Saturn", + "type": "gas", + "schema_version": 2, + } + ] diff --git a/docs/includes/eloquent-models/PlanetSchemaVersion1.php b/docs/includes/eloquent-models/PlanetSchemaVersion1.php new file mode 100644 index 000000000..d4cbff71b --- /dev/null +++ b/docs/includes/eloquent-models/PlanetSchemaVersion1.php @@ -0,0 +1,10 @@ +galaxy = 'Milky Way'; + } + } +} diff --git a/docs/includes/eloquent-models/SchemaVersionTest.php b/docs/includes/eloquent-models/SchemaVersionTest.php new file mode 100644 index 000000000..7bf54f679 --- /dev/null +++ b/docs/includes/eloquent-models/SchemaVersionTest.php @@ -0,0 +1,54 @@ + 'WASP-39 b', + 'type' => 'gas', + 'schema_version' => 1, + ], + ]); + + // Saves a document with no specified schema version + $saturn = Planet::create([ + 'name' => 'Saturn', + 'type' => 'gas', + ]); + + // Retrieves both models from the collection + $planets = Planet::where('type', 'gas') + ->get(); + // end-schema-version + + $this->assertCount(2, $planets); + + $p1 = Planet::where('name', 'Saturn')->first(); + + $this->assertEquals(2, $p1->schema_version); + + $p2 = Planet::where('name', 'WASP-39 b')->first(); + + $this->assertEquals(2, $p2->schema_version); + $this->assertEquals('Milky Way', $p2->galaxy); + } +}