From decbd999d8ff71d4dbc7f7c59aef562deb5b1e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 21 Feb 2024 15:08:20 +0100 Subject: [PATCH 01/30] PHPORM-152 Fix tests for Carbon 3 (#2733) --- tests/Query/BuilderTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 8f62583ce..6df0b1a42 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -564,7 +564,12 @@ function (Builder $builder) { yield 'whereBetween CarbonPeriod' => [ [ 'find' => [ - ['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], + [ + 'created_at' => [ + '$gte' => new UTCDateTime($period->getStartDate()), + '$lte' => new UTCDateTime($period->getEndDate()), + ], + ], [], // options ], ], From 9b72148d75de75b8a2d44ac759c6c11fa79cddf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 22 Feb 2024 11:04:10 +0100 Subject: [PATCH 02/30] PHPORM-150 Run CI on Laravel 11 (#2735) * Run CI on Laravel 11 * Fix inherited param type * Duplicate HasAttributes::getStorableEnumValue() to avoid BC break in method signature in Laravel 11 https://github.com/laravel/framework/commit/8647dcf18e6e315e97daea9ed60ef79b420ad327 --- .github/workflows/build-ci.yml | 11 ++++++++--- CHANGELOG.md | 1 + composer.json | 14 ++++++-------- src/Eloquent/Model.php | 23 ++++++++++++++++++++++- src/Query/Builder.php | 6 +----- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 55cf0f773..0895d7e8a 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -27,7 +27,10 @@ jobs: - php: "8.1" mongodb: "5.0" mode: "low-deps" - + # Laravel 11 + - php: "8.3" + mongodb: "7.0" + mode: "dev" steps: - uses: "actions/checkout@v4" @@ -70,8 +73,10 @@ jobs: restore-keys: "${{ matrix.os }}-composer-" - name: "Install dependencies" - run: composer update --no-interaction $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest --prefer-stable') - + run: | + composer update --no-interaction \ + $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest') \ + $([[ "${{ matrix.mode }}" != dev ]] && echo ' --prefer-stable') - name: "Run tests" run: "./vendor/bin/phpunit --coverage-clover coverage.xml" env: diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f745851..f25ab8c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. ## [unreleased] +* Add support for Laravel 11 by @GromNaN in [#2735](https://github.com/mongodb/laravel-mongodb/pull/2735) * Fix `Query\Builder::dump` and `dd` methods to dump the MongoDB query by @GromNaN in [#2727](https://github.com/mongodb/laravel-mongodb/pull/2727) and [#2730](https://github.com/mongodb/laravel-mongodb/pull/2730) ## [4.1.2] diff --git a/composer.json b/composer.json index 22b75f58f..d19c1149a 100644 --- a/composer.json +++ b/composer.json @@ -24,20 +24,21 @@ "require": { "php": "^8.1", "ext-mongodb": "^1.15", - "illuminate/support": "^10.0", - "illuminate/container": "^10.0", - "illuminate/database": "^10.30", - "illuminate/events": "^10.0", + "illuminate/support": "^10.0|^11", + "illuminate/container": "^10.0|^11", + "illuminate/database": "^10.30|^11", + "illuminate/events": "^10.0|^11", "mongodb/mongodb": "^1.15" }, "require-dev": { "phpunit/phpunit": "^10.3", - "orchestra/testbench": "^8.0", + "orchestra/testbench": "^8.0|^9.0", "mockery/mockery": "^1.4.4", "doctrine/coding-standard": "12.0.x-dev", "spatie/laravel-query-builder": "^5.6", "phpstan/phpstan": "^1.10" }, + "minimum-stability": "dev", "replace": { "jenssegers/mongodb": "self.version" }, @@ -66,9 +67,6 @@ "cs:fix": "phpcbf" }, "config": { - "platform": { - "php": "8.1" - }, "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true } diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 80a29e4fa..acf83247d 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Eloquent; +use BackedEnum; use Carbon\CarbonInterface; use DateTimeInterface; use Illuminate\Contracts\Queue\QueueableCollection; @@ -22,6 +23,7 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Laravel\Query\Builder as QueryBuilder; use Stringable; +use ValueError; use function array_key_exists; use function array_keys; @@ -38,10 +40,12 @@ use function is_string; use function ltrim; use function method_exists; +use function sprintf; use function str_contains; use function str_starts_with; use function strcmp; use function uniqid; +use function var_export; abstract class Model extends BaseModel { @@ -704,7 +708,7 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt } if ($this->isEnumCastable($key) && (! $castValue instanceof Arrayable)) { - $castValue = $castValue !== null ? $this->getStorableEnumValue($castValue) : null; + $castValue = $castValue !== null ? $this->getStorableEnumValueFromLaravel11($this->getCasts()[$key], $castValue) : null; } if ($castValue instanceof Arrayable) { @@ -717,6 +721,23 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt return $attributes; } + /** + * Duplicate of {@see HasAttributes::getStorableEnumValue()} for Laravel 11 as the signature of the method has + * changed in a non-backward compatible way. + * + * @todo Remove this method when support for Laravel 10 is dropped. + */ + private function getStorableEnumValueFromLaravel11($expectedEnum, $value) + { + if (! $value instanceof $expectedEnum) { + throw new ValueError(sprintf('Value [%s] is not of the expected enum type [%s].', var_export($value, true), $expectedEnum)); + } + + return $value instanceof BackedEnum + ? $value->value + : $value->name; + } + /** * Is a value a BSON type? * diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 98e6640df..4efa76252 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -614,11 +614,7 @@ public function orderBy($column, $direction = 'asc') return $this; } - /** - * @param list{mixed, mixed}|CarbonPeriod $values - * - * @inheritdoc - */ + /** @inheritdoc */ public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { $type = 'between'; From e08f5edf84f2e0ce0095d9d28129bdabf45c3c80 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Wed, 6 Mar 2024 13:46:49 -0500 Subject: [PATCH 03/30] DOCSP-37057: Eloquent schema builder --- docs/eloquent-models.txt | 520 +----------------------- docs/eloquent-models/schema-builder.txt | 43 ++ 2 files changed, 57 insertions(+), 506 deletions(-) create mode 100644 docs/eloquent-models/schema-builder.txt diff --git a/docs/eloquent-models.txt b/docs/eloquent-models.txt index 3ce32c124..7d32c476d 100644 --- a/docs/eloquent-models.txt +++ b/docs/eloquent-models.txt @@ -6,517 +6,25 @@ Eloquent Models .. facet:: :name: genre - :values: tutorial + :values: reference .. meta:: - :keywords: php framework, odm, code example + :keywords: php framework, odm -This package includes a MongoDB enabled Eloquent class that you can use to -define models for corresponding collections. +Eloquent models are part of the Laravel Eloquent object-relational +mapping (ORM) framework that enable you to work with a database by using +model classes. The {+odm-short+} extends this framework to use similar +syntax to work with MongoDB as a database. -Extending the base model -~~~~~~~~~~~~~~~~~~~~~~~~ +This section contains guidance on how to use Eloquent models in +{+odm-short+} to work with MongoDB in the following ways: -To get started, create a new model class in your ``app\Models\`` directory. +- :ref:`laravel-eloquent-model-relationships` shows how to add relationships + between models +- :ref:`laravel-schema-builder` shows how to manage indexes on your MongoDB + collections -.. code-block:: php +.. toctree:: - namespace App\Models; + Schema Builder - use MongoDB\Laravel\Eloquent\Model; - - class Book extends Model - { - // - } - -Just like a regular model, the MongoDB model class will know which collection -to use based on the model name. For ``Book``, the collection ``books`` will -be used. - -To change the collection, pass the ``$collection`` property: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Book extends Model - { - protected $collection = 'my_books_collection'; - } - -.. note:: - - MongoDB documents are automatically stored with a unique ID that is stored - in the ``_id`` property. If you wish to use your own ID, substitute the - ``$primaryKey`` property and set it to your own primary key attribute name. - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Book extends Model - { - protected $primaryKey = 'id'; - } - - // MongoDB will also create _id, but the 'id' property will be used for primary key actions like find(). - Book::create(['id' => 1, 'title' => 'The Fault in Our Stars']); - -Likewise, you may define a ``connection`` property to override the name of the -database connection to reference the model. - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Book extends Model - { - protected $connection = 'mongodb'; - } - -Soft Deletes -~~~~~~~~~~~~ - -When soft deleting a model, it is not actually removed from your database. -Instead, a ``deleted_at`` timestamp is set on the record. - -To enable soft delete for a model, apply the ``MongoDB\Laravel\Eloquent\SoftDeletes`` -Trait to the model: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\SoftDeletes; - - class User extends Model - { - use SoftDeletes; - } - -For more information check `Laravel Docs about Soft Deleting `__. - -Prunable -~~~~~~~~ - -``Prunable`` and ``MassPrunable`` traits are Laravel features to automatically -remove models from your database. You can use ``Illuminate\Database\Eloquent\Prunable`` -trait to remove models one by one. If you want to remove models in bulk, you -must use the ``MongoDB\Laravel\Eloquent\MassPrunable`` trait instead: it -will be more performant but can break links with other documents as it does -not load the models. - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - use MongoDB\Laravel\Eloquent\MassPrunable; - - class Book extends Model - { - use MassPrunable; - } - -For more information check `Laravel Docs about Pruning Models `__. - -Dates -~~~~~ - -Eloquent allows you to work with Carbon or DateTime objects instead of MongoDate objects. Internally, these dates will be converted to MongoDate objects when saved to the database. - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class User extends Model - { - protected $casts = ['birthday' => 'datetime']; - } - -This allows you to execute queries like this: - -.. code-block:: php - - $users = User::where( - 'birthday', '>', - new DateTime('-18 years') - )->get(); - -Extending the Authenticatable base model -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This package includes a MongoDB Authenticatable Eloquent class ``MongoDB\Laravel\Auth\User`` -that you can use to replace the default Authenticatable class ``Illuminate\Foundation\Auth\User`` -for your ``User`` model. - -.. code-block:: php - - use MongoDB\Laravel\Auth\User as Authenticatable; - - class User extends Authenticatable - { - - } - -Guarding attributes -~~~~~~~~~~~~~~~~~~~ - -When choosing between guarding attributes or marking some as fillable, Taylor -Otwell prefers the fillable route. This is in light of -`recent security issues described here `__. - -Keep in mind guarding still works, but you may experience unexpected behavior. - -Schema ------- - -The database driver also has (limited) schema builder support. You can -conveniently manipulate collections and set indexes. - -Basic Usage -~~~~~~~~~~~ - -.. code-block:: php - - Schema::create('users', function ($collection) { - $collection->index('name'); - $collection->unique('email'); - }); - -You can also pass all the parameters specified :manual:`in the MongoDB docs ` -to the ``$options`` parameter: - -.. code-block:: php - - Schema::create('users', function ($collection) { - $collection->index( - 'username', - null, - null, - [ - 'sparse' => true, - 'unique' => true, - 'background' => true, - ] - ); - }); - -Inherited operations: - - -* create and drop -* collection -* hasCollection -* index and dropIndex (compound indexes supported as well) -* unique - -MongoDB specific operations: - - -* background -* sparse -* expire -* geospatial - -All other (unsupported) operations are implemented as dummy pass-through -methods because MongoDB does not use a predefined schema. - -Read more about the schema builder on `Laravel Docs `__ - -Geospatial indexes -~~~~~~~~~~~~~~~~~~ - -Geospatial indexes can improve query performance of location-based documents. - -They come in two forms: ``2d`` and ``2dsphere``. Use the schema builder to add -these to a collection. - -.. code-block:: php - - Schema::create('bars', function ($collection) { - $collection->geospatial('location', '2d'); - }); - -To add a ``2dsphere`` index: - -.. code-block:: php - - Schema::create('bars', function ($collection) { - $collection->geospatial('location', '2dsphere'); - }); - -Relationships -------------- - -Basic Usage -~~~~~~~~~~~ - -The only available relationships are: - - -* hasOne -* hasMany -* belongsTo -* belongsToMany - -The MongoDB-specific relationships are: - - -* embedsOne -* embedsMany - -Here is a small example: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class User extends Model - { - public function items() - { - return $this->hasMany(Item::class); - } - } - -The inverse relation of ``hasMany`` is ``belongsTo``: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Item extends Model - { - public function user() - { - return $this->belongsTo(User::class); - } - } - -belongsToMany and pivots -~~~~~~~~~~~~~~~~~~~~~~~~ - -The belongsToMany relation will not use a pivot "table" but will push id's to -a **related_ids** attribute instead. This makes the second parameter for the -belongsToMany method useless. - -If you want to define custom keys for your relation, set it to ``null``: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class User extends Model - { - public function groups() - { - return $this->belongsToMany( - Group::class, null, 'user_ids', 'group_ids' - ); - } - } - -EmbedsMany Relationship -~~~~~~~~~~~~~~~~~~~~~~~ - -If you want to embed models, rather than referencing them, you can use the -``embedsMany`` relation. This relation is similar to the ``hasMany`` relation -but embeds the models inside the parent object. - -**REMEMBER**\ : These relations return Eloquent collections, they don't return -query builder objects! - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class User extends Model - { - public function books() - { - return $this->embedsMany(Book::class); - } - } - -You can access the embedded models through the dynamic property: - -.. code-block:: php - - $user = User::first(); - - foreach ($user->books as $book) { - // - } - -The inverse relation is auto *magically* available. You can omit the reverse -relation definition. - -.. code-block:: php - - $book = User::first()->books()->first(); - - $user = $book->user; - -Inserting and updating embedded models works similar to the ``hasMany`` relation: - -.. code-block:: php - - $book = $user->books()->save( - new Book(['title' => 'A Game of Thrones']) - ); - - // or - $book = - $user->books() - ->create(['title' => 'A Game of Thrones']); - -You can update embedded models using their ``save`` method (available since -release 2.0.0): - -.. code-block:: php - - $book = $user->books()->first(); - - $book->title = 'A Game of Thrones'; - $book->save(); - -You can remove an embedded model by using the ``destroy`` method on the -relation, or the ``delete`` method on the model (available since release 2.0.0): - -.. code-block:: php - - $book->delete(); - - // Similar operation - $user->books()->destroy($book); - -If you want to add or remove an embedded model, without touching the database, -you can use the ``associate`` and ``dissociate`` methods. - -To eventually write the changes to the database, save the parent object: - -.. code-block:: php - - $user->books()->associate($book); - $user->save(); - -Like other relations, embedsMany assumes the local key of the relationship -based on the model name. You can override the default local key by passing a -second argument to the embedsMany method: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class User extends Model - { - public function books() - { - return $this->embedsMany(Book::class, 'local_key'); - } - } - -Embedded relations will return a Collection of embedded items instead of a -query builder. Check out the available operations here: -`https://laravel.com/docs/master/collections `__ - -EmbedsOne Relationship -~~~~~~~~~~~~~~~~~~~~~~ - -The embedsOne relation is similar to the embedsMany relation, but only embeds a single model. - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Book extends Model - { - public function author() - { - return $this->embedsOne(Author::class); - } - } - -You can access the embedded models through the dynamic property: - -.. code-block:: php - - $book = Book::first(); - $author = $book->author; - -Inserting and updating embedded models works similar to the ``hasOne`` relation: - -.. code-block:: php - - $author = $book->author()->save( - new Author(['name' => 'John Doe']) - ); - - // Similar - $author = - $book->author() - ->create(['name' => 'John Doe']); - -You can update the embedded model using the ``save`` method (available since -release 2.0.0): - -.. code-block:: php - - $author = $book->author; - - $author->name = 'Jane Doe'; - $author->save(); - -You can replace the embedded model with a new model like this: - -.. code-block:: php - - $newAuthor = new Author(['name' => 'Jane Doe']); - - $book->author()->save($newAuthor); - -Cross-Database Relationships ----------------------------- - -If you're using a hybrid MongoDB and SQL setup, you can define relationships -across them. - -The model will automatically return a MongoDB-related or SQL-related relation -based on the type of the related model. - -If you want this functionality to work both ways, your SQL-models will need -to use the ``MongoDB\Laravel\Eloquent\HybridRelations`` trait. - -**This functionality only works for ``hasOne``, ``hasMany`` and ``belongsTo``.** - -The SQL model must use the ``HybridRelations`` trait: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\HybridRelations; - - class User extends Model - { - use HybridRelations; - - protected $connection = 'mysql'; - - public function messages() - { - return $this->hasMany(Message::class); - } - } - -Within your MongoDB model, you must define the following relationship: - -.. code-block:: php - - use MongoDB\Laravel\Eloquent\Model; - - class Message extends Model - { - protected $connection = 'mongodb'; - - public function user() - { - return $this->belongsTo(User::class); - } - } diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt new file mode 100644 index 000000000..1b85a460a --- /dev/null +++ b/docs/eloquent-models/schema-builder.txt @@ -0,0 +1,43 @@ +.. _laravel-eloquent-schema-builder: + +============== +Schema Builder +============== + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: php framework, odm, code example, entity relationship, eloquent + +Overview +-------- + +This page describes how to use schema builder functions in {+odm-short+} to +manage MongoDB collection indexes. + + + +Creation options + +https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/#options-for-all-index-types + + + + +This page will show how to use Laravel Schemas to manage indexes and show +examples of each of the following: + +- create and drop (is this different from index and dropIndex?) +- collection (what does this method do?) +- determining column existence + +It will also provide info on the MongoDB specific operations and +geospatial indexes. + +- background - what is this? Hasn't this been replaced by index behavior in 4.2? +- sparse https://www.mongodb.com/docs/manual/core/index-sparse/ +- expire is this a ttl index? https://www.mongodb.com/docs/manual/core/index-ttl/ +- geospatial https://www.mongodb.com/docs/manual/core/indexes/index-types/index-geospatial/ + From 963d01f1af6b1d54082399972523bde4abdf0788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 7 Mar 2024 10:30:11 +0100 Subject: [PATCH 04/30] Test Laravel 10 and 11 (#2746) --- .github/workflows/build-ci.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 8261f4514..c6a84e120 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -24,16 +24,17 @@ jobs: - "8.2" - "8.3" laravel: - - "10.*" + - "10.*" + - "11.*" include: - php: "8.1" laravel: "10.*" mongodb: "5.0" mode: "low-deps" - # Laravel 11 - - php: "8.3" - mongodb: "7.0" - mode: "dev" + exclude: + - php: "8.1" + laravel: "11.*" + steps: - uses: "actions/checkout@v4" @@ -79,10 +80,7 @@ jobs: restore-keys: "${{ matrix.os }}-composer-" - name: "Install dependencies" - run: | - composer update --no-interaction \ - $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest') \ - $([[ "${{ matrix.mode }}" != dev ]] && echo ' --prefer-stable') + run: composer update --no-interaction $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest') - name: "Run tests" run: "./vendor/bin/phpunit --coverage-clover coverage.xml" env: From 1004c3904479cfb1e89a15323ccc6629df5dc5bb Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 7 Mar 2024 12:40:46 -0500 Subject: [PATCH 05/30] wip --- docs/eloquent-models/schema-builder.txt | 54 ++++++++++++++++++++----- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 1b85a460a..80ba222b2 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -14,30 +14,62 @@ Schema Builder Overview -------- -This page describes how to use schema builder functions in {+odm-short+} to -manage MongoDB collection indexes. +Laravel provides a **facade** to access the schema builder, which lets you +create and modify tables. Facades are static interfaces to classes that make +the syntax more concise and improve testability. +Info here about how to use it +Although schemas are not required by MongoDB collections, you can use the +schema builder to manage collections and indexes. -Creation options +The following sections describe the Laravel schema builder and +MongoDB-specific functionality available in {+odm-short+} and shows +examples of how to use them: -https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/#options-for-all-index-types +List of sections here +- create and drop (is this different from index and dropIndex?) + Schema::create(, function ($collection) { + $collection->index(<>); + $collection->unique(<>); + Geospatial index +- collection (what does this method do?) + Schema::hasCollection(); check whether a collection exists +- determining column existence +- drop collection public function dropIfExists($table) + { + if ($this->hasCollection($table)) { + $this->drop($table); + } + } -This page will show how to use Laravel Schemas to manage indexes and show -examples of each of the following: +index($columns = null, $name = null, $algorithm = null, $options = []) +dropIndex($index = null) +public function dropIndexIfExists($indexOrColumns = null)\ + public function hasIndex($indexOrColumns = null) -- create and drop (is this different from index and dropIndex?) -- collection (what does this method do?) -- determining column existence + public function unique($columns = null, $name = null, $algorithm = null, $options = []) -It will also provide info on the MongoDB specific operations and -geospatial indexes. + +Creation options + +https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/#options-for-all-index-types - background - what is this? Hasn't this been replaced by index behavior in 4.2? - sparse https://www.mongodb.com/docs/manual/core/index-sparse/ - expire is this a ttl index? https://www.mongodb.com/docs/manual/core/index-ttl/ - geospatial https://www.mongodb.com/docs/manual/core/indexes/index-types/index-geospatial/ +.. note:: + + Although MongoDB collections can be schemaless, you can provide + schemas for data validation. The {+odm-short+} schema builder does not + currently offer methods to +- + + + + From 19fc80159fac77f964e34e271e522c256896a5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 11 Mar 2024 10:08:18 +0100 Subject: [PATCH 06/30] PHPORM-139 Implement `Model::createOrFirst()` using `findOneAndUpdate` operation (#2742) Use monitoring to track if model was created or found --- CHANGELOG.md | 1 + src/Eloquent/Builder.php | 38 ++++++++++++++++++ .../FindAndModifyCommandSubscriber.php | 34 ++++++++++++++++ tests/ModelTest.php | 39 +++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/Internal/FindAndModifyCommandSubscriber.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2263ac29d..a8c2cefc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [unreleased] * Add support for Laravel 11 by @GromNaN in [#2735](https://github.com/mongodb/laravel-mongodb/pull/2735) +* Implement Model::createOrFirst() using findOneAndUpdate operation by @GromNaN in [#2742](https://github.com/mongodb/laravel-mongodb/pull/2742) ## [4.1.3] - 2024-03-05 diff --git a/src/Eloquent/Builder.php b/src/Eloquent/Builder.php index b9005c442..6ef960456 100644 --- a/src/Eloquent/Builder.php +++ b/src/Eloquent/Builder.php @@ -7,9 +7,12 @@ use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use MongoDB\Driver\Cursor; +use MongoDB\Laravel\Collection; use MongoDB\Laravel\Helpers\QueriesRelationships; +use MongoDB\Laravel\Internal\FindAndModifyCommandSubscriber; use MongoDB\Model\BSONDocument; +use function array_intersect_key; use function array_key_exists; use function array_merge; use function collect; @@ -183,6 +186,41 @@ public function raw($value = null) return $results; } + /** + * Attempt to create the record if it does not exist with the matching attributes. + * If the record exists, it will be returned. + * + * @param array $attributes The attributes to check for duplicate records + * @param array $values The attributes to insert if no matching record is found + */ + public function createOrFirst(array $attributes = [], array $values = []): Model + { + // Apply casting and default values to the attributes + $instance = $this->newModelInstance($values + $attributes); + $values = $instance->getAttributes(); + $attributes = array_intersect_key($attributes, $values); + + return $this->raw(function (Collection $collection) use ($attributes, $values) { + $listener = new FindAndModifyCommandSubscriber(); + $collection->getManager()->addSubscriber($listener); + + try { + $document = $collection->findOneAndUpdate( + $attributes, + ['$setOnInsert' => $values], + ['upsert' => true, 'new' => true, 'typeMap' => ['root' => 'array', 'document' => 'array']], + ); + } finally { + $collection->getManager()->removeSubscriber($listener); + } + + $model = $this->model->newFromBuilder($document); + $model->wasRecentlyCreated = $listener->created; + + return $model; + }); + } + /** * Add the "updated at" column to an array of values. * TODO Remove if https://github.com/laravel/framework/commit/6484744326531829341e1ff886cc9b628b20d73e diff --git a/src/Internal/FindAndModifyCommandSubscriber.php b/src/Internal/FindAndModifyCommandSubscriber.php new file mode 100644 index 000000000..55b13436b --- /dev/null +++ b/src/Internal/FindAndModifyCommandSubscriber.php @@ -0,0 +1,34 @@ +created = ! $event->getReply()->lastErrorObject->updatedExisting; + } +} diff --git a/tests/ModelTest.php b/tests/ModelTest.php index ec1579869..f4d459422 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -1044,4 +1044,43 @@ public function testNumericFieldName(): void $this->assertInstanceOf(User::class, $found); $this->assertEquals([3 => 'two.three'], $found[2]); } + + public function testCreateOrFirst() + { + $user1 = User::createOrFirst(['email' => 'taylorotwell@gmail.com']); + + $this->assertSame('taylorotwell@gmail.com', $user1->email); + $this->assertNull($user1->name); + $this->assertTrue($user1->wasRecentlyCreated); + + $user2 = User::createOrFirst( + ['email' => 'taylorotwell@gmail.com'], + ['name' => 'Taylor Otwell', 'birthday' => new DateTime('1987-05-28')], + ); + + $this->assertEquals($user1->id, $user2->id); + $this->assertSame('taylorotwell@gmail.com', $user2->email); + $this->assertNull($user2->name); + $this->assertNull($user2->birthday); + $this->assertFalse($user2->wasRecentlyCreated); + + $user3 = User::createOrFirst( + ['email' => 'abigailotwell@gmail.com'], + ['name' => 'Abigail Otwell', 'birthday' => new DateTime('1987-05-28')], + ); + + $this->assertNotEquals($user3->id, $user1->id); + $this->assertSame('abigailotwell@gmail.com', $user3->email); + $this->assertSame('Abigail Otwell', $user3->name); + $this->assertEquals(new DateTime('1987-05-28'), $user3->birthday); + $this->assertTrue($user3->wasRecentlyCreated); + + $user4 = User::createOrFirst( + ['name' => 'Dries Vints'], + ['name' => 'Nuno Maduro', 'email' => 'nuno@laravel.com'], + ); + + $this->assertSame('Nuno Maduro', $user4->name); + $this->assertTrue($user4->wasRecentlyCreated); + } } From 4d71a0252ab9db1e44489354c8881acd23898d05 Mon Sep 17 00:00:00 2001 From: ccho-mongodb Date: Tue, 12 Mar 2024 14:18:34 +0000 Subject: [PATCH 07/30] apply phpcbf formatting --- src/Query/Builder.php | 5 ----- tests/Models/User.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 98e6640df..27e788db8 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -1158,11 +1158,6 @@ protected function compileWheres(): array return $compiled; } - /** - * @param array $where - * - * @return array - */ protected function compileWhereBasic(array $where): array { $column = $where['column']; diff --git a/tests/Models/User.php b/tests/Models/User.php index f2d2cf7cc..98f76d931 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -130,7 +130,7 @@ protected function username(): Attribute { return Attribute::make( get: fn ($value) => $value, - set: fn ($value) => Str::slug($value) + set: fn ($value) => Str::slug($value), ); } From 7f10e27e321059a39ac2607d0358553c3319fdb6 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Tue, 12 Mar 2024 17:06:11 -0400 Subject: [PATCH 08/30] wip --- docs/eloquent-models/schema-builder.txt | 127 ++++++++++++++---- .../schema-builder/astronauts_migration.php | 30 +++++ 2 files changed, 128 insertions(+), 29 deletions(-) create mode 100644 docs/includes/schema-builder/astronauts_migration.php diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 80ba222b2..23c13184e 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -9,50 +9,124 @@ Schema Builder :values: tutorial .. meta:: - :keywords: php framework, odm, code example, entity relationship, eloquent + :keywords: php framework, odm, code example, schema facade, php artisan, eloquent Overview -------- -Laravel provides a **facade** to access the schema builder, which lets you -create and modify tables. Facades are static interfaces to classes that make -the syntax more concise and improve testability. +Laravel provides a ``Schema`` **facade** to access the schema builder, which +lets you create and modify tables. Facades are static interfaces to classes +that make the syntax more concise and improve testability. -Info here about how to use it +{+odm-short+} supports index and collection management methods of the +Laravel ``Schema`` facade. -Although schemas are not required by MongoDB collections, you can use the -schema builder to manage collections and indexes. +To learn more about Laravel Facades, see `Facades `__ +in the Laravel documentation. -The following sections describe the Laravel schema builder and -MongoDB-specific functionality available in {+odm-short+} and shows -examples of how to use them: +The following sections describe the Laravel schema builder and functionality +available in {+odm-short+} and show examples of how to use them: -List of sections here +- :ref:`` +- :ref:`` +- :ref:`` +- :ref:`` + +.. _laravel-eloquent-migrations: + +Perform Laravel Migrations +-------------------------- + +Laravel lets you create and make modifications to your database schema by +running methods that call the ``Schema`` facade. The process of running this +logic is called a migration. + +You can generate the migration class files by using the ``php artisan make:migration`` +command. Make the following changes to the generated files to perform the +migration on your MongoDB database: + +- Replace the ``Illuminate\Database\Schema\Blueprint`` import with + ``MongoDB\Laravel\Schema\Blueprint`` +- Specify ``mongodb`` in the ``$connection`` field +- Use only commands and syntax supported by {+odm-short+} + +.. tip:: + + Make sure you set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration + file so that PHP artisan performs the migration on the correct database. + +To run the database migration from a class file, run the following PHP artisan +command: + +.. code-block:: bash + + php artisan migrate --path= + +This artisan command runs the ``up()`` method in the class file to create +the collection and index in the database specified in the ``config/database.php`` +file. + +To roll back the migration, run the following PHP artisan command: + +.. code-block:: bash + + php artisan migrate:rollback --path= + +This command runs the ``down()`` method in the class file to drop the +collection and related indexes. + +The following example migration class file that creates a collection and +index when you run the migration and drops it when you roll back the migration: + +.. literalinclude:: /includes/schema-builder/astronauts_migration.php + :language: php + +.. _laravel-eloquent-indexes: + +Manage Indexes +-------------- + +TODO + +.. _laravel-eloquent-collections: + +Manage Collections +------------------ + +TODO + +.. _laravel-eloquent-customize-collection: + +Customize Collection Creation +----------------------------- + +TODO + +Notes: - create and drop (is this different from index and dropIndex?) - Schema::create(, function ($collection) { - $collection->index(<>); - $collection->unique(<>); - Geospatial index + Schema::create(, function ($collection) { + $collection->index(<>); + $collection->unique(<>); + Geospatial index - collection (what does this method do?) - Schema::hasCollection(); check whether a collection exists + Schema::hasCollection(); check whether a collection exists - determining column existence - drop collection public function dropIfExists($table) - { - if ($this->hasCollection($table)) { - $this->drop($table); - } - } + { + if ($this->hasCollection($table)) { + $this->drop($table); + } + } index($columns = null, $name = null, $algorithm = null, $options = []) dropIndex($index = null) public function dropIndexIfExists($indexOrColumns = null)\ - public function hasIndex($indexOrColumns = null) - - public function unique($columns = null, $name = null, $algorithm = null, $options = []) +public function hasIndex($indexOrColumns = null) +public function unique($columns = null, $name = null, $algorithm = null, $options = []) Creation options @@ -68,8 +142,3 @@ https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/# Although MongoDB collections can be schemaless, you can provide schemas for data validation. The {+odm-short+} schema builder does not currently offer methods to -- - - - - diff --git a/docs/includes/schema-builder/astronauts_migration.php b/docs/includes/schema-builder/astronauts_migration.php new file mode 100644 index 000000000..a89cc50ca --- /dev/null +++ b/docs/includes/schema-builder/astronauts_migration.php @@ -0,0 +1,30 @@ +index('name'); + $collection->unique('email'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::drop('astronauts'); + } +}; From 7d1c13e42b4af6a964fc0d8232d3f8123a6f2c99 Mon Sep 17 00:00:00 2001 From: ccho-mongodb Date: Tue, 12 Mar 2024 21:08:31 +0000 Subject: [PATCH 09/30] apply phpcbf formatting --- src/Query/Builder.php | 5 ----- tests/Models/User.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 98e6640df..27e788db8 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -1158,11 +1158,6 @@ protected function compileWheres(): array return $compiled; } - /** - * @param array $where - * - * @return array - */ protected function compileWhereBasic(array $where): array { $column = $where['column']; diff --git a/tests/Models/User.php b/tests/Models/User.php index f2d2cf7cc..98f76d931 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -130,7 +130,7 @@ protected function username(): Attribute { return Attribute::make( get: fn ($value) => $value, - set: fn ($value) => Str::slug($value) + set: fn ($value) => Str::slug($value), ); } From 2c7c1a89ddabadc336f6c6d2683e9f7b219de484 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Tue, 12 Mar 2024 18:16:00 -0400 Subject: [PATCH 10/30] fix rst, organize sections --- docs/eloquent-models.txt | 2 - docs/eloquent-models/schema-builder.txt | 56 +++++++++++++++---------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/docs/eloquent-models.txt b/docs/eloquent-models.txt index 7d32c476d..f588d5e42 100644 --- a/docs/eloquent-models.txt +++ b/docs/eloquent-models.txt @@ -19,8 +19,6 @@ syntax to work with MongoDB as a database. This section contains guidance on how to use Eloquent models in {+odm-short+} to work with MongoDB in the following ways: -- :ref:`laravel-eloquent-model-relationships` shows how to add relationships - between models - :ref:`laravel-schema-builder` shows how to manage indexes on your MongoDB collections diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 23c13184e..bc8b32a54 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -1,4 +1,4 @@ -.. _laravel-eloquent-schema-builder: +.. _laravel-schema-builder: ============== Schema Builder @@ -14,14 +14,14 @@ Schema Builder Overview -------- -Laravel provides a ``Schema`` **facade** to access the schema builder, which -lets you create and modify tables. Facades are static interfaces to classes -that make the syntax more concise and improve testability. +Laravel provides a **facade** to access the schema builder class ``Schema``, +which lets you create and modify tables. Facades are static interfaces to +classes that make the syntax more concise and improve testability. -{+odm-short+} supports index and collection management methods of the -Laravel ``Schema`` facade. +{+odm-short+} supports a subset of the index and collection management methods +in the Laravel ``Schema`` facade. -To learn more about Laravel Facades, see `Facades `__ +To learn more about facades, see `Facades `__ in the Laravel documentation. The following sections describe the Laravel schema builder and functionality @@ -37,15 +37,19 @@ available in {+odm-short+} and show examples of how to use them: Perform Laravel Migrations -------------------------- -Laravel lets you create and make modifications to your database schema by -running methods that call the ``Schema`` facade. The process of running this -logic is called a migration. +Laravel migrations let you programmatically create, modify, and delete +your database schema by running methods included in the ``Schema`` facade. +The following sections explain how to author a migration class when you use +a MongoDB database and how to run them. -You can generate the migration class files by using the ``php artisan make:migration`` -command. Make the following changes to the generated files to perform the -migration on your MongoDB database: +Create a Migration Class +~~~~~~~~~~~~~~~~~~~~~~~~ -- Replace the ``Illuminate\Database\Schema\Blueprint`` import with +You can create migration classes manually or generate them by using the +``php artisan make:migration`` command. If you generate them, you must make the +following changes to perform the schema changes on your MongoDB database: + +- Replace the ``Illuminate\Database\Schema\Blueprint`` import with ``MongoDB\Laravel\Schema\Blueprint`` - Specify ``mongodb`` in the ``$connection`` field - Use only commands and syntax supported by {+odm-short+} @@ -55,6 +59,15 @@ migration on your MongoDB database: Make sure you set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file so that PHP artisan performs the migration on the correct database. +The following example migration class file that creates a collection and +index when you run the migration and drops it when you roll back the migration: + +.. literalinclude:: /includes/schema-builder/astronauts_migration.php + :language: php + +Run or Roll Back a Migration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + To run the database migration from a class file, run the following PHP artisan command: @@ -62,7 +75,7 @@ command: php artisan migrate --path= -This artisan command runs the ``up()`` method in the class file to create +This artisan command runs the ``up()`` function in the class file to create the collection and index in the database specified in the ``config/database.php`` file. @@ -72,14 +85,12 @@ To roll back the migration, run the following PHP artisan command: php artisan migrate:rollback --path= -This command runs the ``down()`` method in the class file to drop the +This command runs the ``down()`` function in the class file to drop the collection and related indexes. -The following example migration class file that creates a collection and -index when you run the migration and drops it when you roll back the migration: - -.. literalinclude:: /includes/schema-builder/astronauts_migration.php - :language: php +To learn more about Laravel migrations, see +`Database: Migrations `__ +in the Laravel documentation. .. _laravel-eloquent-indexes: @@ -95,6 +106,9 @@ Manage Collections TODO +Note that creating a collection is a noop unless it also creates an index +since MongoDB automatically creates collections when you first write to them. + .. _laravel-eloquent-customize-collection: Customize Collection Creation From cc1b370d931744619db26575e2334fd94091d7f2 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Tue, 12 Mar 2024 18:17:36 -0400 Subject: [PATCH 11/30] remove install toc entry --- docs/index.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.txt b/docs/index.txt index f22848b57..8ee11dbda 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -13,7 +13,6 @@ Laravel MongoDB :titlesonly: :maxdepth: 1 - /install /quick-start /retrieve /eloquent-models From c8fb0a00a32685271eea01d970db67c32d794ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 13 Mar 2024 15:53:09 +0100 Subject: [PATCH 12/30] PHPORM-159 Add tests on `whereAny` and `whereAll` (#2763) New tests require Laravel v10.47 --- tests/Query/BuilderTest.php | 139 ++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 6df0b1a42..4076b3028 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -23,6 +23,7 @@ use stdClass; use function collect; +use function method_exists; use function now; use function var_export; @@ -1157,6 +1158,144 @@ function (Builder $elemMatchQuery): void { }, ), ]; + + // Method added in Laravel v10.47.0 + if (method_exists(Builder::class, 'whereAll')) { + /** @see DatabaseQueryBuilderTest::testWhereAll */ + yield 'whereAll' => [ + [ + 'find' => [ + ['$and' => [['last_name' => 'Doe'], ['email' => 'Doe']]], + [], // options + ], + ], + fn(Builder $builder) => $builder->whereAll(['last_name', 'email'], 'Doe'), + ]; + + yield 'whereAll operator' => [ + [ + 'find' => [ + [ + '$and' => [ + ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder->whereAll(['last_name', 'email'], 'not like', '%Doe%'), + ]; + + /** @see DatabaseQueryBuilderTest::testOrWhereAll */ + yield 'orWhereAll' => [ + [ + 'find' => [ + [ + '$or' => [ + ['first_name' => 'John'], + ['$and' => [['last_name' => 'Doe'], ['email' => 'Doe']]], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder + ->where('first_name', 'John') + ->orWhereAll(['last_name', 'email'], 'Doe'), + ]; + + yield 'orWhereAll operator' => [ + [ + 'find' => [ + [ + '$or' => [ + ['first_name' => new Regex('^.*John.*$', 'i')], + [ + '$and' => [ + ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ], + ], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder + ->where('first_name', 'like', '%John%') + ->orWhereAll(['last_name', 'email'], 'not like', '%Doe%'), + ]; + } + + // Method added in Laravel v10.47.0 + if (method_exists(Builder::class, 'whereAny')) { + /** @see DatabaseQueryBuilderTest::testWhereAny */ + yield 'whereAny' => [ + [ + 'find' => [ + ['$or' => [['last_name' => 'Doe'], ['email' => 'Doe']]], + [], // options + ], + ], + fn(Builder $builder) => $builder->whereAny(['last_name', 'email'], 'Doe'), + ]; + + yield 'whereAny operator' => [ + [ + 'find' => [ + [ + '$or' => [ + ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder->whereAny(['last_name', 'email'], 'not like', '%Doe%'), + ]; + + /** @see DatabaseQueryBuilderTest::testOrWhereAny */ + yield 'orWhereAny' => [ + [ + 'find' => [ + [ + '$or' => [ + ['first_name' => 'John'], + ['$or' => [['last_name' => 'Doe'], ['email' => 'Doe']]], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder + ->where('first_name', 'John') + ->orWhereAny(['last_name', 'email'], 'Doe'), + ]; + + yield 'orWhereAny operator' => [ + [ + 'find' => [ + [ + '$or' => [ + ['first_name' => new Regex('^.*John.*$', 'i')], + [ + '$or' => [ + ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], + ], + ], + ], + ], + [], // options + ], + ], + fn(Builder $builder) => $builder + ->where('first_name', 'like', '%John%') + ->orWhereAny(['last_name', 'email'], 'not like', '%Doe%'), + ]; + } } /** @dataProvider provideExceptions */ From f5f86c83c301051c79b3b64742bde2fada4f8c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 13 Mar 2024 19:52:10 +0100 Subject: [PATCH 13/30] PHPORM-139 Improve `Model::createOrFirst()` tests and error checking (#2759) --- src/Eloquent/Builder.php | 17 +++++++++++++++-- tests/ModelTest.php | 32 ++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/Eloquent/Builder.php b/src/Eloquent/Builder.php index 6ef960456..7ea18dfa9 100644 --- a/src/Eloquent/Builder.php +++ b/src/Eloquent/Builder.php @@ -6,11 +6,13 @@ use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; +use InvalidArgumentException; use MongoDB\Driver\Cursor; use MongoDB\Laravel\Collection; use MongoDB\Laravel\Helpers\QueriesRelationships; use MongoDB\Laravel\Internal\FindAndModifyCommandSubscriber; use MongoDB\Model\BSONDocument; +use MongoDB\Operation\FindOneAndUpdate; use function array_intersect_key; use function array_key_exists; @@ -195,7 +197,12 @@ public function raw($value = null) */ public function createOrFirst(array $attributes = [], array $values = []): Model { + if ($attributes === []) { + throw new InvalidArgumentException('You must provide attributes to check for duplicates'); + } + // Apply casting and default values to the attributes + // In case of duplicate key between the attributes and the values, the values have priority $instance = $this->newModelInstance($values + $attributes); $values = $instance->getAttributes(); $attributes = array_intersect_key($attributes, $values); @@ -207,8 +214,14 @@ public function createOrFirst(array $attributes = [], array $values = []): Model try { $document = $collection->findOneAndUpdate( $attributes, - ['$setOnInsert' => $values], - ['upsert' => true, 'new' => true, 'typeMap' => ['root' => 'array', 'document' => 'array']], + // Before MongoDB 5.0, $setOnInsert requires a non-empty document. + // This is should not be an issue as $values includes the query filter. + ['$setOnInsert' => (object) $values], + [ + 'upsert' => true, + 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER, + 'typeMap' => ['root' => 'array', 'document' => 'array'], + ], ); } finally { $collection->getManager()->removeSubscriber($listener); diff --git a/tests/ModelTest.php b/tests/ModelTest.php index f4d459422..5ab6badee 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; +use InvalidArgumentException; use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectID; use MongoDB\BSON\UTCDateTime; @@ -1047,40 +1048,47 @@ public function testNumericFieldName(): void public function testCreateOrFirst() { - $user1 = User::createOrFirst(['email' => 'taylorotwell@gmail.com']); + $user1 = User::createOrFirst(['email' => 'john.doe@example.com']); - $this->assertSame('taylorotwell@gmail.com', $user1->email); + $this->assertSame('john.doe@example.com', $user1->email); $this->assertNull($user1->name); $this->assertTrue($user1->wasRecentlyCreated); $user2 = User::createOrFirst( - ['email' => 'taylorotwell@gmail.com'], - ['name' => 'Taylor Otwell', 'birthday' => new DateTime('1987-05-28')], + ['email' => 'john.doe@example.com'], + ['name' => 'John Doe', 'birthday' => new DateTime('1987-05-28')], ); $this->assertEquals($user1->id, $user2->id); - $this->assertSame('taylorotwell@gmail.com', $user2->email); + $this->assertSame('john.doe@example.com', $user2->email); $this->assertNull($user2->name); $this->assertNull($user2->birthday); $this->assertFalse($user2->wasRecentlyCreated); $user3 = User::createOrFirst( - ['email' => 'abigailotwell@gmail.com'], - ['name' => 'Abigail Otwell', 'birthday' => new DateTime('1987-05-28')], + ['email' => 'jane.doe@example.com'], + ['name' => 'Jane Doe', 'birthday' => new DateTime('1987-05-28')], ); $this->assertNotEquals($user3->id, $user1->id); - $this->assertSame('abigailotwell@gmail.com', $user3->email); - $this->assertSame('Abigail Otwell', $user3->name); + $this->assertSame('jane.doe@example.com', $user3->email); + $this->assertSame('Jane Doe', $user3->name); $this->assertEquals(new DateTime('1987-05-28'), $user3->birthday); $this->assertTrue($user3->wasRecentlyCreated); $user4 = User::createOrFirst( - ['name' => 'Dries Vints'], - ['name' => 'Nuno Maduro', 'email' => 'nuno@laravel.com'], + ['name' => 'Robert Doe'], + ['name' => 'Maria Doe', 'email' => 'maria.doe@example.com'], ); - $this->assertSame('Nuno Maduro', $user4->name); + $this->assertSame('Maria Doe', $user4->name); $this->assertTrue($user4->wasRecentlyCreated); } + + public function testCreateOrFirstRequiresFilter() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('You must provide attributes to check for duplicates'); + User::createOrFirst([]); + } } From 4aa33a016527f7911be8e261b836272ef291d8f1 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 14 Mar 2024 02:10:58 -0400 Subject: [PATCH 14/30] wip --- docs/eloquent-models/schema-builder.txt | 281 ++++++++++++++++-- .../schema-builder/astronauts_migration.php | 1 - .../schema-builder/flights_migration.php | 31 ++ .../schema-builder/passengers_migration.php | 26 ++ .../schema-builder/planets_migration.php | 26 ++ .../schema-builder/spaceports_migration.php | 32 ++ 6 files changed, 365 insertions(+), 32 deletions(-) create mode 100644 docs/includes/schema-builder/flights_migration.php create mode 100644 docs/includes/schema-builder/passengers_migration.php create mode 100644 docs/includes/schema-builder/planets_migration.php create mode 100644 docs/includes/schema-builder/spaceports_migration.php diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index bc8b32a54..97b91fd90 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -30,7 +30,6 @@ available in {+odm-short+} and show examples of how to use them: - :ref:`` - :ref:`` - :ref:`` -- :ref:`` .. _laravel-eloquent-migrations: @@ -50,7 +49,7 @@ You can create migration classes manually or generate them by using the following changes to perform the schema changes on your MongoDB database: - Replace the ``Illuminate\Database\Schema\Blueprint`` import with - ``MongoDB\Laravel\Schema\Blueprint`` + ``MongoDB\Laravel\Schema\Blueprint`` if it is referenced in your migration - Specify ``mongodb`` in the ``$connection`` field - Use only commands and syntax supported by {+odm-short+} @@ -60,10 +59,12 @@ following changes to perform the schema changes on your MongoDB database: file so that PHP artisan performs the migration on the correct database. The following example migration class file that creates a collection and -index when you run the migration and drops it when you roll back the migration: +index when you run the migration and drops it when you reverse, or roll back +the migration: .. literalinclude:: /includes/schema-builder/astronauts_migration.php :language: php + :emphasize-lines: 4, 10 Run or Roll Back a Migration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -97,33 +98,259 @@ in the Laravel documentation. Manage Indexes -------------- -TODO +MongoDB indexes are data structures that improve query efficiency by reducing +the number of documents needed to retrieve results of a query. Indexes such as +geospatial indexes extend the ways in which you can query the data. + + To improve query performance by using an index, make sure the query is +covered by the index. To learn more about indexes and query optimization, see +the following MongoDB server manual pages: + +- :manual:`Indexes ` +- :manual:`Query Optimization ` + +The following sections show how you can use the schema builder to create and +drop various types of indexes on a collection. + +Create an Index +~~~~~~~~~~~~~~~ + +To create indexes, call the ``create()`` method on the ``Schema`` facade +in your migration file. Pass ``create()`` the collection name and a callback +method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Specify the +index creation details on the ``Blueprint`` instance. + +The following example migration creates indexes on the following collection +fields: + +- Single field index on ``mission_type`` +- Compound index on ``launch_location`` and ``launch_date``, specifying a descending sort order on ``launch_date`` +- Unique index on the ``mission_id`` field, specifying the index name "unique_mission_id_idx" + +Click the :guilabel:`VIEW OUTPUT` button to see the indexes created by running +the migration, including the default index on the ``_id`` field: + + +.. io-code-block:: + + .. input:: /includes/schema-builder/flights_migration.php + :language: php + :dedent: + :start-after: begin create index + :end-before: end create index + + .. output:: + :language: json + :visible: false + + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { mission_type: 1 }, name: 'mission_type_1' }, + { + v: 2, + key: { launch_location: 1, launch_date: -1 }, + name: 'launch_location_1_launch_date_-1' + }, + { + v: 2, + key: { mission_id: 1 }, + name: 'unique_mission_id_idx', + unique: true + } + ] + + +Specify Index Options +~~~~~~~~~~~~~~~~~~~~~ + +MongoDB index options determine how the indexes are used and stored. +You can specify index options when calling an index creation method such +as ``index()`` on a ``Blueprint`` instance. + +The following migration code shows how to add a collation to an index as an +index option. Click the :guilabel:`VIEW OUTPUT` button to see the indexes +created by running the migration, including the default index on the ``_id`` +field: + +.. io-code-block:: + + .. input:: /includes/schema-builder/passengers_migration.php + :language: php + :dedent: + :start-after: begin create index + :end-before: end create index + + .. output: + :language: json + :visible: false + + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { + v: 2, + key: { last_name: 1 }, + name: 'passengers_collation_idx', + collation: { + locale: 'de@collation=phonebook', + caseLevel: false, + caseFirst: 'off', + strength: 3, + numericOrdering: true, + alternate: 'non-ignorable', + maxVariable: 'punct', + normalization: false, + backwards: false, + version: '57.1' + } + } + ] + + +To learn more about index options, see :manual:`Options for All Index Types ` +in the MongoDB server manual. + +Create Sparse, TTL, and Unique Indexes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use {+odm-short+} helper methods to create the following types of +indexes: + +- Sparse indexes which allow index entries only for documents that contain the + specified field +- Time-to-live (TTL) indexes which expire after a set amount of time +- Unique indexes which prevent inserting documents that contain duplicate + values for the indexed field + +To create these index types, call the ``create()`` method on the ``Schema`` facade +in your migration file. Pass ``create()`` the collection name and a callback +method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Call the +appropriate helper method on the ``Blueprint`` instance and pass the +index creation details. + +The following migration code shows how to create a sparse index and TTL index +by using the index helpers. Click the :guilabel:`VIEW OUTPUT` button to see +the indexes created by running the migration, including the default index on +the ``_id`` field: + +.. io-code-block:: + + .. input:: /includes/schema-builder/planets_migration.php + :language: php + :dedent: + :start-after: begin index helpers + :end-before: end index helpers + + .. output:: + :language: json + :visible: false + + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { rings: 1 }, name: 'rings_1', sparse: true }, + { + v: 2, + key: { last_visible_dt: 1 }, + name: 'last_visible_dt_1', + expireAfterSeconds: 86400 + } + ] + +You can specify sparse, TTL, and unique indexes on a single field or compound +index by specifying them in the index options. + +The following migration code shows how to create all three types of indexes +on a single field. Click the :guilabel:`VIEW OUTPUT` button to see the indexes +created by running the migration, including the default index on the ``_id`` +field: + +.. io-code-block:: + + .. input:: /includes/schema-builder/planets_migration.php + :language: php + :dedent: + :start-after: begin multi index helpers + :end-before: end multi index helpers + + .. output:: + :language: json + :visible: false + + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { + v: 2, + key: { last_visible_dt: 1 }, + name: 'last_visible_dt_1', + unique: true, + sparse: true, + expireAfterSeconds: 3600 + } + ] + + +To learn more about these indexes, see :manual:`Index Properties ` +in the MongoDB server manual. + +Create a Geospatial Index +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In MongoDB, geospatial indexes let you query geospatial coordinate data for +inclusion, intersection, and proximity. + +To create geospatial indexes, call the ``create()`` method on the ``Schema`` facade +in your migration file. Pass ``create()`` the collection name and a callback +method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Specify the +geospatial index creation details on the ``Blueprint`` instance. + +The following example migration creates a ``2d`` and ``2dsphere`` geospatial +index on the ``spaceports`` collection: + +.. literalinclude:: /includes/schema-builder/spaceports_migration.php + :language: php + :start-after: begin create geospatial index + :end-before: end create geospatial index + +To learn more about geospatial indexes, see +:manual:`Geospatial Indexes ` in +the MongoDB Server manual. + +Drop an Index +~~~~~~~~~~~~~ + +You can drop indexes from a collection when you no longer need them. + +When you no longer use an index, you can drop them + +When you drop a collection, MongoDB automatically drops all the indexes +associated with it. + +To drop an index, call the ``table()`` method on the ``Schema`` facade in your +migration file. + +you must reference it by name. + +The following example migration drops an index called ``unique_mission_id_idx`` +from the ``flights`` collection: + +.. literalinclude:: /includes/schema-builder/flights_migration.php + :language: php + :start-after: begin drop index + :end-before: end drop index .. _laravel-eloquent-collections: Manage Collections ------------------ +Check if a collection exists: Schema::hasCollection() + TODO Note that creating a collection is a noop unless it also creates an index since MongoDB automatically creates collections when you first write to them. -.. _laravel-eloquent-customize-collection: - -Customize Collection Creation ------------------------------ - -TODO - Notes: -- create and drop (is this different from index and dropIndex?) - Schema::create(, function ($collection) { - $collection->index(<>); - $collection->unique(<>); - Geospatial index - - collection (what does this method do?) Schema::hasCollection(); check whether a collection exists @@ -140,19 +367,11 @@ dropIndex($index = null) public function dropIndexIfExists($indexOrColumns = null)\ public function hasIndex($indexOrColumns = null) -public function unique($columns = null, $name = null, $algorithm = null, $options = []) - -Creation options - -https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/#options-for-all-index-types - -- background - what is this? Hasn't this been replaced by index behavior in 4.2? -- sparse https://www.mongodb.com/docs/manual/core/index-sparse/ -- expire is this a ttl index? https://www.mongodb.com/docs/manual/core/index-ttl/ -- geospatial https://www.mongodb.com/docs/manual/core/indexes/index-types/index-geospatial/ - .. note:: - Although MongoDB collections can be schemaless, you can provide - schemas for data validation. The {+odm-short+} schema builder does not - currently offer methods to + Although MongoDB collections can be schemaless, they can use JSON schemas + for data validation. The {+odm-short+} schema builder does not offer methods + for data validation schemas. To learn more about JSON schema validation, + see :manual:`Schema Validation ` in the + MongoDB server documentation. + diff --git a/docs/includes/schema-builder/astronauts_migration.php b/docs/includes/schema-builder/astronauts_migration.php index a89cc50ca..49a0b378e 100644 --- a/docs/includes/schema-builder/astronauts_migration.php +++ b/docs/includes/schema-builder/astronauts_migration.php @@ -16,7 +16,6 @@ public function up(): void { Schema::create('astronauts', function ($collection) { $collection->index('name'); - $collection->unique('email'); }); } diff --git a/docs/includes/schema-builder/flights_migration.php b/docs/includes/schema-builder/flights_migration.php new file mode 100644 index 000000000..0507a8b63 --- /dev/null +++ b/docs/includes/schema-builder/flights_migration.php @@ -0,0 +1,31 @@ +index('mission_type'); + $collection->index(['launch_location' => 1, 'launch_date' => -1]); + $collection->unique('mission_id', null, null, [ 'name' => 'unique_mission_id_idx']); + }); + // end create index + } + + public function down(): void + { + // begin drop index + Schema::table('flights', function (Blueprint $collection) { + $collection->dropIndex('unique_mission_id_idx'); + }); + // end drop index + } +}; diff --git a/docs/includes/schema-builder/passengers_migration.php b/docs/includes/schema-builder/passengers_migration.php new file mode 100644 index 000000000..c43341c3f --- /dev/null +++ b/docs/includes/schema-builder/passengers_migration.php @@ -0,0 +1,26 @@ +index('last_name', 'passengers_collation_idx', null, [ + 'collation' => [ 'locale' => 'de@collation=phonebook', 'numericOrdering' => true ]]); + }); + // end index options + } + + public function down(): void + { + Schema::drop('passengers'); + } +}; diff --git a/docs/includes/schema-builder/planets_migration.php b/docs/includes/schema-builder/planets_migration.php new file mode 100644 index 000000000..d4b705fae --- /dev/null +++ b/docs/includes/schema-builder/planets_migration.php @@ -0,0 +1,26 @@ +sparse('rings'); + $collection->expire('last_visible_dt', 86400); + }); + // end index helpers + } + + public function down(): void + { + Schema::drop('planets'); + } +}; diff --git a/docs/includes/schema-builder/spaceports_migration.php b/docs/includes/schema-builder/spaceports_migration.php new file mode 100644 index 000000000..49775eb08 --- /dev/null +++ b/docs/includes/schema-builder/spaceports_migration.php @@ -0,0 +1,32 @@ +geospatial('launchpad_location', '2dsphere'); + $collection->geospatial('runway_location', '2d'); + }); + // end create geospatial index + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::drop('spaceports'); + } +}; From f7e6f803a3c74ddac931cfc1c7cfb64a9defe9c3 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 14 Mar 2024 11:07:21 -0400 Subject: [PATCH 15/30] wip --- docs/eloquent-models/schema-builder.txt | 94 +++++++++++-------- .../schema-builder/flights_migration.php | 4 +- .../schema-builder/planets_migration.php | 6 ++ 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 97b91fd90..96ce23131 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -102,7 +102,7 @@ MongoDB indexes are data structures that improve query efficiency by reducing the number of documents needed to retrieve results of a query. Indexes such as geospatial indexes extend the ways in which you can query the data. - To improve query performance by using an index, make sure the query is +To improve query performance by using an index, make sure the query is covered by the index. To learn more about indexes and query optimization, see the following MongoDB server manual pages: @@ -116,7 +116,7 @@ Create an Index ~~~~~~~~~~~~~~~ To create indexes, call the ``create()`` method on the ``Schema`` facade -in your migration file. Pass ``create()`` the collection name and a callback +in your migration file. Pass it the collection name and a callback method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Specify the index creation details on the ``Blueprint`` instance. @@ -130,7 +130,6 @@ fields: Click the :guilabel:`VIEW OUTPUT` button to see the indexes created by running the migration, including the default index on the ``_id`` field: - .. io-code-block:: .. input:: /includes/schema-builder/flights_migration.php @@ -139,26 +138,25 @@ the migration, including the default index on the ``_id`` field: :start-after: begin create index :end-before: end create index - .. output:: - :language: json - :visible: false - - [ - { v: 2, key: { _id: 1 }, name: '_id_' }, - { v: 2, key: { mission_type: 1 }, name: 'mission_type_1' }, - { - v: 2, - key: { launch_location: 1, launch_date: -1 }, - name: 'launch_location_1_launch_date_-1' - }, - { - v: 2, - key: { mission_id: 1 }, - name: 'unique_mission_id_idx', - unique: true - } - ] + .. output:: + :language: json + :visible: false + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { mission_type: 1 }, name: 'mission_type_1' }, + { + v: 2, + key: { launch_location: 1, launch_date: -1 }, + name: 'launch_location_1_launch_date_-1' + }, + { + v: 2, + key: { mission_id: 1 }, + name: 'unique_mission_id_idx', + unique: true + } + ] Specify Index Options ~~~~~~~~~~~~~~~~~~~~~ @@ -177,8 +175,8 @@ field: .. input:: /includes/schema-builder/passengers_migration.php :language: php :dedent: - :start-after: begin create index - :end-before: end create index + :start-after: begin index options + :end-before: end index options .. output: :language: json @@ -287,7 +285,6 @@ field: } ] - To learn more about these indexes, see :manual:`Index Properties ` in the MongoDB server manual. @@ -303,12 +300,32 @@ method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Specify the geospatial index creation details on the ``Blueprint`` instance. The following example migration creates a ``2d`` and ``2dsphere`` geospatial -index on the ``spaceports`` collection: +index on the ``spaceports`` collection. Click the :guilabel:`VIEW OUTPUT` +button to see the indexes created by running the migration, including the +default index on the ``_id`` field: + +.. io-code-block:: + .. input:: /includes/schema-builder/spaceports_migration.php + :language: php + :dedent: + :start-after: begin create geospatial index + :end-before: end create geospatial index + + .. output:: + :language: json + :visible: false + + [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { + v: 2, + key: { launchpad_location: '2dsphere' }, + name: 'launchpad_location_2dsphere', + '2dsphereIndexVersion': 3 + }, + { v: 2, key: { runway_location: '2d' }, name: 'runway_location_2d' } + ] -.. literalinclude:: /includes/schema-builder/spaceports_migration.php - :language: php - :start-after: begin create geospatial index - :end-before: end create geospatial index To learn more about geospatial indexes, see :manual:`Geospatial Indexes ` in @@ -317,17 +334,16 @@ the MongoDB Server manual. Drop an Index ~~~~~~~~~~~~~ -You can drop indexes from a collection when you no longer need them. - -When you no longer use an index, you can drop them +To drop indexes from a collection, call the ``table()`` method on the +``Schema`` facade in your migration file. Pass it the table name and a +callback method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. +Call the ``dropIndex()`` method with the index name on the ``Blueprint`` +instance. -When you drop a collection, MongoDB automatically drops all the indexes -associated with it. - -To drop an index, call the ``table()`` method on the ``Schema`` facade in your -migration file. +.. note:: -you must reference it by name. + If you drop a collection, MongoDB automatically drops all the indexes + associated with it. The following example migration drops an index called ``unique_mission_id_idx`` from the ``flights`` collection: diff --git a/docs/includes/schema-builder/flights_migration.php b/docs/includes/schema-builder/flights_migration.php index 0507a8b63..6019e0fd7 100644 --- a/docs/includes/schema-builder/flights_migration.php +++ b/docs/includes/schema-builder/flights_migration.php @@ -3,7 +3,7 @@ use Illuminate\Database\Migrations\Migration; use MongoDB\Laravel\Schema\Blueprint; use Illuminate\Support\Facades\Schema; - + return new class extends Migration { @@ -19,7 +19,7 @@ public function up(): void }); // end create index } - + public function down(): void { // begin drop index diff --git a/docs/includes/schema-builder/planets_migration.php b/docs/includes/schema-builder/planets_migration.php index d4b705fae..e8df56f1f 100644 --- a/docs/includes/schema-builder/planets_migration.php +++ b/docs/includes/schema-builder/planets_migration.php @@ -17,6 +17,12 @@ public function up(): void $collection->expire('last_visible_dt', 86400); }); // end index helpers + + // begin multi index helpers + Schema::create('planet_systems', function (Blueprint $collection) { + $collection->index('last_visible_dt', null, null, [ 'sparse' => true, 'expireAfterSeconds' => 3600, 'unique' => true]); + }); + // end multi index helpers } public function down(): void From 265d29c1465d30e0f76d0875d6a0e0b9bd8c74d4 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 14 Mar 2024 14:46:13 -0400 Subject: [PATCH 16/30] grammar and spelling corrections --- docs/eloquent-models/schema-builder.txt | 93 ++++++++----------- .../schema-builder/stars_migration.php | 28 ++++++ 2 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 docs/includes/schema-builder/stars_migration.php diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 96ce23131..83bc0a36b 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -9,7 +9,7 @@ Schema Builder :values: tutorial .. meta:: - :keywords: php framework, odm, code example, schema facade, php artisan, eloquent + :keywords: php framework, odm, code example, schema facade, php artisan, eloquent, blueprint, artisan, migrate Overview -------- @@ -28,8 +28,15 @@ The following sections describe the Laravel schema builder and functionality available in {+odm-short+} and show examples of how to use them: - :ref:`` +- :ref:`` - :ref:`` -- :ref:`` + +.. note:: + + {+odm-short+} supports managing indexes and collection, but + excludes support for MongoDB JSON schemas for data validation. To learn + more about JSON schema validation, see :manual:`Schema Validation ` + in the MongoDB server manual. .. _laravel-eloquent-migrations: @@ -58,9 +65,8 @@ following changes to perform the schema changes on your MongoDB database: Make sure you set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file so that PHP artisan performs the migration on the correct database. -The following example migration class file that creates a collection and -index when you run the migration and drops it when you reverse, or roll back -the migration: +The following example migration creates a collection and index when you run +the migration and drops it when you roll back the migration: .. literalinclude:: /includes/schema-builder/astronauts_migration.php :language: php @@ -93,18 +99,35 @@ To learn more about Laravel migrations, see `Database: Migrations `__ in the Laravel documentation. +.. _laravel-eloquent-collection-exists: + +Check Whether a Collection Exists +--------------------------------- + +To check whether a collection exists, call the ``hasCollection()`` method on +the ``Schema`` facade in your migration file. You can use this to +perform migration logic conditionally. + +The following example migration creates a ``stars`` collection if a collection +named ``telescopes`` exists: + +.. literalinclude:: /includes/schema-builder/stars_migration.php + :language: php + :start-after: begin conditional create + :end-before: end conditional create + .. _laravel-eloquent-indexes: Manage Indexes -------------- MongoDB indexes are data structures that improve query efficiency by reducing -the number of documents needed to retrieve results of a query. Indexes such as -geospatial indexes extend the ways in which you can query the data. +the number of documents needed to retrieve query results. Indexes such as +geospatial indexes extend how you can query the data. -To improve query performance by using an index, make sure the query is -covered by the index. To learn more about indexes and query optimization, see -the following MongoDB server manual pages: +To improve query performance by using an index, make sure the index covers +the query. To learn more about indexes and query optimization, see the +following MongoDB server manual entries: - :manual:`Indexes ` - :manual:`Query Optimization ` @@ -203,7 +226,6 @@ field: } ] - To learn more about index options, see :manual:`Options for All Index Types ` in the MongoDB server manual. @@ -213,10 +235,10 @@ Create Sparse, TTL, and Unique Indexes You can use {+odm-short+} helper methods to create the following types of indexes: -- Sparse indexes which allow index entries only for documents that contain the +- Sparse indexes, which allow index entries only for documents that contain the specified field -- Time-to-live (TTL) indexes which expire after a set amount of time -- Unique indexes which prevent inserting documents that contain duplicate +- Time-to-live (TTL) indexes, which expire after a set amount of time +- Unique indexes, which prevent inserting documents that contain duplicate values for the indexed field To create these index types, call the ``create()`` method on the ``Schema`` facade @@ -225,7 +247,7 @@ method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Call the appropriate helper method on the ``Blueprint`` instance and pass the index creation details. -The following migration code shows how to create a sparse index and TTL index +The following migration code shows how to create a sparse and TTL index by using the index helpers. Click the :guilabel:`VIEW OUTPUT` button to see the indexes created by running the migration, including the default index on the ``_id`` field: @@ -253,8 +275,8 @@ the ``_id`` field: } ] -You can specify sparse, TTL, and unique indexes on a single field or compound -index by specifying them in the index options. +You can specify sparse, TTL, and unique indexes on either a single field or +compound index by specifying them in the index options. The following migration code shows how to create all three types of indexes on a single field. Click the :guilabel:`VIEW OUTPUT` button to see the indexes @@ -353,41 +375,4 @@ from the ``flights`` collection: :start-after: begin drop index :end-before: end drop index -.. _laravel-eloquent-collections: - -Manage Collections ------------------- - -Check if a collection exists: Schema::hasCollection() - -TODO - -Note that creating a collection is a noop unless it also creates an index -since MongoDB automatically creates collections when you first write to them. - -Notes: - -- collection (what does this method do?) - Schema::hasCollection(); check whether a collection exists - -- determining column existence -- drop collection public function dropIfExists($table) - { - if ($this->hasCollection($table)) { - $this->drop($table); - } - } - -index($columns = null, $name = null, $algorithm = null, $options = []) -dropIndex($index = null) -public function dropIndexIfExists($indexOrColumns = null)\ -public function hasIndex($indexOrColumns = null) - -.. note:: - - Although MongoDB collections can be schemaless, they can use JSON schemas - for data validation. The {+odm-short+} schema builder does not offer methods - for data validation schemas. To learn more about JSON schema validation, - see :manual:`Schema Validation ` in the - MongoDB server documentation. diff --git a/docs/includes/schema-builder/stars_migration.php b/docs/includes/schema-builder/stars_migration.php new file mode 100644 index 000000000..db01399b5 --- /dev/null +++ b/docs/includes/schema-builder/stars_migration.php @@ -0,0 +1,28 @@ + Date: Thu, 14 Mar 2024 14:52:41 -0400 Subject: [PATCH 17/30] fix rst --- docs/eloquent-models/schema-builder.txt | 2 +- docs/includes/schema-builder/stars_migration.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 83bc0a36b..ba6061c53 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -201,7 +201,7 @@ field: :start-after: begin index options :end-before: end index options - .. output: + .. output:: :language: json :visible: false diff --git a/docs/includes/schema-builder/stars_migration.php b/docs/includes/schema-builder/stars_migration.php index db01399b5..19681bf39 100644 --- a/docs/includes/schema-builder/stars_migration.php +++ b/docs/includes/schema-builder/stars_migration.php @@ -3,7 +3,7 @@ use Illuminate\Database\Migrations\Migration; use MongoDB\Laravel\Schema\Blueprint; use Illuminate\Support\Facades\Schema; - + return new class extends Migration { @@ -11,9 +11,9 @@ public function up(): void { - // start conditional create + // begin conditional create $hasCollection = Schema::hasCollection('stars'); - + if ($hasCollection) { Schema::create('telescopes'); } From 9719367e31f881d31c0fa0b04d664092e1bd77a8 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 14 Mar 2024 15:38:53 -0400 Subject: [PATCH 18/30] tweaks --- docs/eloquent-models/schema-builder.txt | 20 ++++++++++++++----- .../schema-builder/astronauts_migration.php | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index ba6061c53..1445032c7 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -11,6 +11,12 @@ Schema Builder .. meta:: :keywords: php framework, odm, code example, schema facade, php artisan, eloquent, blueprint, artisan, migrate +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + Overview -------- @@ -24,8 +30,8 @@ in the Laravel ``Schema`` facade. To learn more about facades, see `Facades `__ in the Laravel documentation. -The following sections describe the Laravel schema builder and functionality -available in {+odm-short+} and show examples of how to use them: +The following sections describe the Laravel schema builder features available +in {+odm-short+} and show examples of how to use them: - :ref:`` - :ref:`` @@ -66,9 +72,10 @@ following changes to perform the schema changes on your MongoDB database: file so that PHP artisan performs the migration on the correct database. The following example migration creates a collection and index when you run -the migration and drops it when you roll back the migration: +the migration and drops them when you roll back the migration: .. literalinclude:: /includes/schema-builder/astronauts_migration.php + :dedent: :language: php :emphasize-lines: 4, 10 @@ -76,7 +83,7 @@ Run or Roll Back a Migration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To run the database migration from a class file, run the following PHP artisan -command: +command after replacing the placeholder: .. code-block:: bash @@ -86,7 +93,8 @@ This artisan command runs the ``up()`` function in the class file to create the collection and index in the database specified in the ``config/database.php`` file. -To roll back the migration, run the following PHP artisan command: +To roll back the migration, run the following PHP artisan command after +replacing the placeholder: .. code-block:: bash @@ -113,6 +121,7 @@ named ``telescopes`` exists: .. literalinclude:: /includes/schema-builder/stars_migration.php :language: php + :dedent: :start-after: begin conditional create :end-before: end conditional create @@ -372,6 +381,7 @@ from the ``flights`` collection: .. literalinclude:: /includes/schema-builder/flights_migration.php :language: php + :dedent: :start-after: begin drop index :end-before: end drop index diff --git a/docs/includes/schema-builder/astronauts_migration.php b/docs/includes/schema-builder/astronauts_migration.php index 49a0b378e..208f3893c 100644 --- a/docs/includes/schema-builder/astronauts_migration.php +++ b/docs/includes/schema-builder/astronauts_migration.php @@ -14,7 +14,7 @@ */ public function up(): void { - Schema::create('astronauts', function ($collection) { + Schema::create('astronauts', function (Blueprint $collection) { $collection->index('name'); }); } From f4afab663e85861d9401d5a1806a6460c6e25151 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 14 Mar 2024 16:03:42 -0400 Subject: [PATCH 19/30] PHP code style updates --- docs/eloquent-models/schema-builder.txt | 2 +- .../schema-builder/astronauts_migration.php | 13 +++++++------ .../includes/schema-builder/flights_migration.php | 15 ++++++++------- .../schema-builder/passengers_migration.php | 12 +++++++----- .../includes/schema-builder/planets_migration.php | 9 +++++---- .../schema-builder/spaceports_migration.php | 7 ++++--- docs/includes/schema-builder/stars_migration.php | 7 +++---- 7 files changed, 35 insertions(+), 30 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 1445032c7..d012eb986 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -77,7 +77,7 @@ the migration and drops them when you roll back the migration: .. literalinclude:: /includes/schema-builder/astronauts_migration.php :dedent: :language: php - :emphasize-lines: 4, 10 + :emphasize-lines: 6, 11 Run or Roll Back a Migration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/includes/schema-builder/astronauts_migration.php b/docs/includes/schema-builder/astronauts_migration.php index 208f3893c..d3e81f108 100644 --- a/docs/includes/schema-builder/astronauts_migration.php +++ b/docs/includes/schema-builder/astronauts_migration.php @@ -1,12 +1,13 @@ index('name'); - }); + Schema::create('astronauts', function (Blueprint $collection) { + $collection->index('name'); + }); } /** diff --git a/docs/includes/schema-builder/flights_migration.php b/docs/includes/schema-builder/flights_migration.php index 6019e0fd7..d45170d72 100644 --- a/docs/includes/schema-builder/flights_migration.php +++ b/docs/includes/schema-builder/flights_migration.php @@ -1,22 +1,23 @@ index('mission_type'); - $collection->index(['launch_location' => 1, 'launch_date' => -1]); - $collection->unique('mission_id', null, null, [ 'name' => 'unique_mission_id_idx']); - }); + Schema::create('flights', function (Blueprint $collection) { + $collection->index('mission_type'); + $collection->index(['launch_location' => 1, 'launch_date' => -1]); + $collection->unique('mission_id', null, null, ['name' => 'unique_mission_id_idx']); + }); // end create index } diff --git a/docs/includes/schema-builder/passengers_migration.php b/docs/includes/schema-builder/passengers_migration.php index c43341c3f..3a13a87d9 100644 --- a/docs/includes/schema-builder/passengers_migration.php +++ b/docs/includes/schema-builder/passengers_migration.php @@ -1,20 +1,22 @@ index('last_name', 'passengers_collation_idx', null, [ - 'collation' => [ 'locale' => 'de@collation=phonebook', 'numericOrdering' => true ]]); + 'collation' => [ 'locale' => 'de@collation=phonebook', 'numericOrdering' => true ], + ]); }); // end index options } diff --git a/docs/includes/schema-builder/planets_migration.php b/docs/includes/schema-builder/planets_migration.php index e8df56f1f..83530d987 100644 --- a/docs/includes/schema-builder/planets_migration.php +++ b/docs/includes/schema-builder/planets_migration.php @@ -1,12 +1,13 @@ index('last_visible_dt', null, null, [ 'sparse' => true, 'expireAfterSeconds' => 3600, 'unique' => true]); + $collection->index('last_visible_dt', null, null, ['sparse' => true, 'expireAfterSeconds' => 3600, 'unique' => true]); }); // end multi index helpers } diff --git a/docs/includes/schema-builder/spaceports_migration.php b/docs/includes/schema-builder/spaceports_migration.php index 49775eb08..d0822d550 100644 --- a/docs/includes/schema-builder/spaceports_migration.php +++ b/docs/includes/schema-builder/spaceports_migration.php @@ -1,12 +1,13 @@ Date: Thu, 14 Mar 2024 16:14:49 -0400 Subject: [PATCH 20/30] DOCSP-37710: v4.2 updates (#2774) --- docs/includes/framework-compatibility-laravel.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/includes/framework-compatibility-laravel.rst b/docs/includes/framework-compatibility-laravel.rst index 9b39db4ea..1efdce964 100644 --- a/docs/includes/framework-compatibility-laravel.rst +++ b/docs/includes/framework-compatibility-laravel.rst @@ -3,14 +3,22 @@ :stub-columns: 1 * - {+odm-short+} Version + - Laravel 11.x - Laravel 10.x - Laravel 9.x + * - 4.2 + - ✓ + - ✓ + - + * - 4.1 + - - ✓ - * - 4.0 + - - ✓ - From b55393ca2cbd9eb68d934089e610390eb5147549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 15 Mar 2024 13:40:27 +0100 Subject: [PATCH 21/30] Set distinct version for error (#2779) --- src/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Connection.php b/src/Connection.php index a859bfa63..3f529cdea 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -328,7 +328,7 @@ private static function lookupVersion(): string try { return self::$version = InstalledVersions::getPrettyVersion('mongodb/laravel-mongodb'); } catch (Throwable) { - // Ignore exceptions and return unknown version + return self::$version = 'error'; } } From 39c0fd0a2e372b12a13917f6dfcde0b3ba050c0e Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Fri, 15 Mar 2024 16:59:46 -0400 Subject: [PATCH 22/30] PRR fixes --- docs/eloquent-models.txt | 4 ++-- docs/eloquent-models/schema-builder.txt | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/eloquent-models.txt b/docs/eloquent-models.txt index f588d5e42..c0f7cea57 100644 --- a/docs/eloquent-models.txt +++ b/docs/eloquent-models.txt @@ -13,14 +13,14 @@ Eloquent Models Eloquent models are part of the Laravel Eloquent object-relational mapping (ORM) framework that enable you to work with a database by using -model classes. The {+odm-short+} extends this framework to use similar +model classes. {+odm-short+} extends this framework to use similar syntax to work with MongoDB as a database. This section contains guidance on how to use Eloquent models in {+odm-short+} to work with MongoDB in the following ways: - :ref:`laravel-schema-builder` shows how to manage indexes on your MongoDB - collections + collections by using Laravel migrations .. toctree:: diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index d012eb986..72c5c2d5a 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -39,10 +39,10 @@ in {+odm-short+} and show examples of how to use them: .. note:: - {+odm-short+} supports managing indexes and collection, but + {+odm-short+} supports managing indexes and collections, but excludes support for MongoDB JSON schemas for data validation. To learn more about JSON schema validation, see :manual:`Schema Validation ` - in the MongoDB server manual. + in the {+server-docs-name+}. .. _laravel-eloquent-migrations: @@ -131,12 +131,12 @@ Manage Indexes -------------- MongoDB indexes are data structures that improve query efficiency by reducing -the number of documents needed to retrieve query results. Indexes such as -geospatial indexes extend how you can query the data. +the number of documents needed to retrieve query results. Certain indexes, such +as geospatial indexes, extend how you can query the data. To improve query performance by using an index, make sure the index covers the query. To learn more about indexes and query optimization, see the -following MongoDB server manual entries: +following {+server-docs-name+} entries: - :manual:`Indexes ` - :manual:`Query Optimization ` @@ -194,8 +194,8 @@ Specify Index Options ~~~~~~~~~~~~~~~~~~~~~ MongoDB index options determine how the indexes are used and stored. -You can specify index options when calling an index creation method such -as ``index()`` on a ``Blueprint`` instance. +You can specify index options when calling an index creation method, such +as ``index()``, on a ``Blueprint`` instance. The following migration code shows how to add a collation to an index as an index option. Click the :guilabel:`VIEW OUTPUT` button to see the indexes @@ -236,7 +236,7 @@ field: ] To learn more about index options, see :manual:`Options for All Index Types ` -in the MongoDB server manual. +in the {+server-docs-name+}. Create Sparse, TTL, and Unique Indexes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -256,7 +256,7 @@ method with a ``MongoDB\Laravel\Schema\Blueprint`` parameter. Call the appropriate helper method on the ``Blueprint`` instance and pass the index creation details. -The following migration code shows how to create a sparse and TTL index +The following migration code shows how to create a sparse and a TTL index by using the index helpers. Click the :guilabel:`VIEW OUTPUT` button to see the indexes created by running the migration, including the default index on the ``_id`` field: @@ -317,7 +317,7 @@ field: ] To learn more about these indexes, see :manual:`Index Properties ` -in the MongoDB server manual. +in the {+server-docs-name+}. Create a Geospatial Index ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -360,7 +360,7 @@ default index on the ``_id`` field: To learn more about geospatial indexes, see :manual:`Geospatial Indexes ` in -the MongoDB Server manual. +the {+server-docs-name+}. Drop an Index ~~~~~~~~~~~~~ From 205961b6edb877e776445eebbbaa7f34a56e2831 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Fri, 15 Mar 2024 17:21:43 -0400 Subject: [PATCH 23/30] PRR fixes 2 --- docs/eloquent-models/schema-builder.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 72c5c2d5a..72e09ed32 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -71,8 +71,10 @@ following changes to perform the schema changes on your MongoDB database: Make sure you set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file so that PHP artisan performs the migration on the correct database. -The following example migration creates a collection and index when you run -the migration and drops them when you roll back the migration: +The following example migration class contains the following methods: + +- ``up()``, which creates a collection and an index when you run the migration +- ``down()``, which drops the collection and all the indexes on it when you roll back the migration .. literalinclude:: /includes/schema-builder/astronauts_migration.php :dedent: From 7cec5b7c015b8f86ee151fe3e98cd09073dc0d56 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Mon, 18 Mar 2024 14:43:51 -0400 Subject: [PATCH 24/30] PRR fixes --- docs/eloquent-models/schema-builder.txt | 9 ++++++--- .../includes/schema-builder/astronauts_migration.php | 2 +- docs/includes/schema-builder/flights_migration.php | 4 ++-- .../includes/schema-builder/passengers_migration.php | 12 ++++++++---- docs/includes/schema-builder/planets_migration.php | 2 +- .../includes/schema-builder/spaceports_migration.php | 2 +- docs/includes/schema-builder/stars_migration.php | 2 +- 7 files changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 72e09ed32..5d59eb37a 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -63,13 +63,16 @@ following changes to perform the schema changes on your MongoDB database: - Replace the ``Illuminate\Database\Schema\Blueprint`` import with ``MongoDB\Laravel\Schema\Blueprint`` if it is referenced in your migration -- Specify ``mongodb`` in the ``$connection`` field - Use only commands and syntax supported by {+odm-short+} .. tip:: - Make sure you set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration - file so that PHP artisan performs the migration on the correct database. + If your default database connection is set to anything other than your + MongoDB database, update the following items so that PHP artisan performs + the migration on the correct database:: + + - Specify ``mongodb`` in the ``$connection`` field of your migration class + - Set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file The following example migration class contains the following methods: diff --git a/docs/includes/schema-builder/astronauts_migration.php b/docs/includes/schema-builder/astronauts_migration.php index d3e81f108..1fb7b76e4 100644 --- a/docs/includes/schema-builder/astronauts_migration.php +++ b/docs/includes/schema-builder/astronauts_migration.php @@ -8,7 +8,7 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; /** * Run the migrations. diff --git a/docs/includes/schema-builder/flights_migration.php b/docs/includes/schema-builder/flights_migration.php index d45170d72..463b94871 100644 --- a/docs/includes/schema-builder/flights_migration.php +++ b/docs/includes/schema-builder/flights_migration.php @@ -8,7 +8,7 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; public function up(): void { @@ -16,7 +16,7 @@ public function up(): void Schema::create('flights', function (Blueprint $collection) { $collection->index('mission_type'); $collection->index(['launch_location' => 1, 'launch_date' => -1]); - $collection->unique('mission_id', null, null, ['name' => 'unique_mission_id_idx']); + $collection->unique('mission_id', options: ['name' => 'unique_mission_id_idx']); }); // end create index } diff --git a/docs/includes/schema-builder/passengers_migration.php b/docs/includes/schema-builder/passengers_migration.php index 3a13a87d9..f0b498940 100644 --- a/docs/includes/schema-builder/passengers_migration.php +++ b/docs/includes/schema-builder/passengers_migration.php @@ -8,15 +8,19 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; public function up(): void { // begin index options Schema::create('passengers', function (Blueprint $collection) { - $collection->index('last_name', 'passengers_collation_idx', null, [ - 'collation' => [ 'locale' => 'de@collation=phonebook', 'numericOrdering' => true ], - ]); + $collection->index( + 'last_name', + name: 'passengers_collation_idx', + options: [ + 'collation' => [ 'locale' => 'de@collation=phonebook', 'numericOrdering' => true ], + ], + ); }); // end index options } diff --git a/docs/includes/schema-builder/planets_migration.php b/docs/includes/schema-builder/planets_migration.php index 83530d987..841d348d4 100644 --- a/docs/includes/schema-builder/planets_migration.php +++ b/docs/includes/schema-builder/planets_migration.php @@ -8,7 +8,7 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; public function up(): void { diff --git a/docs/includes/schema-builder/spaceports_migration.php b/docs/includes/schema-builder/spaceports_migration.php index d0822d550..ae96c6066 100644 --- a/docs/includes/schema-builder/spaceports_migration.php +++ b/docs/includes/schema-builder/spaceports_migration.php @@ -8,7 +8,7 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; /** * Run the migrations. diff --git a/docs/includes/schema-builder/stars_migration.php b/docs/includes/schema-builder/stars_migration.php index 4226b13ca..6249da3cd 100644 --- a/docs/includes/schema-builder/stars_migration.php +++ b/docs/includes/schema-builder/stars_migration.php @@ -7,7 +7,7 @@ return new class extends Migration { - protected $connect = 'mongodb'; + protected $connection = 'mongodb'; public function up(): void { From 7cdbf356dc0638beff1f1aea03baa6d62f82704e Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Mon, 18 Mar 2024 14:45:13 -0400 Subject: [PATCH 25/30] PRR fixes 2 --- docs/includes/schema-builder/planets_migration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/includes/schema-builder/planets_migration.php b/docs/includes/schema-builder/planets_migration.php index 841d348d4..90de5bd6e 100644 --- a/docs/includes/schema-builder/planets_migration.php +++ b/docs/includes/schema-builder/planets_migration.php @@ -21,7 +21,7 @@ public function up(): void // begin multi index helpers Schema::create('planet_systems', function (Blueprint $collection) { - $collection->index('last_visible_dt', null, null, ['sparse' => true, 'expireAfterSeconds' => 3600, 'unique' => true]); + $collection->index('last_visible_dt', options: ['sparse' => true, 'expireAfterSeconds' => 3600, 'unique' => true]); }); // end multi index helpers } From 26071ac5d87da9b3c3cfd788d92f7ce5bf2568b2 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Mon, 18 Mar 2024 14:50:41 -0400 Subject: [PATCH 26/30] fix rst --- docs/eloquent-models/schema-builder.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 5d59eb37a..b13870ca6 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -69,7 +69,7 @@ following changes to perform the schema changes on your MongoDB database: If your default database connection is set to anything other than your MongoDB database, update the following items so that PHP artisan performs - the migration on the correct database:: + the migration on the correct database: - Specify ``mongodb`` in the ``$connection`` field of your migration class - Set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file From e182c902ef4d5380663ef758abe17c3793bbaca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 19 Mar 2024 09:54:53 +0100 Subject: [PATCH 27/30] Update changelog for 4.2.0 (#2784) --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c2cefc4..6a1fe6c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. ## [unreleased] + +## [4.2.0] - 2024-12-14 + * Add support for Laravel 11 by @GromNaN in [#2735](https://github.com/mongodb/laravel-mongodb/pull/2735) * Implement Model::createOrFirst() using findOneAndUpdate operation by @GromNaN in [#2742](https://github.com/mongodb/laravel-mongodb/pull/2742) From ac4504c114de8c0b6bb6436697d39959da2a6306 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Tue, 19 Mar 2024 19:00:04 -0400 Subject: [PATCH 28/30] PRR fixes --- docs/eloquent-models/schema-builder.txt | 12 ++++++------ docs/includes/schema-builder/flights_migration.php | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index b13870ca6..735779705 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -9,7 +9,7 @@ Schema Builder :values: tutorial .. meta:: - :keywords: php framework, odm, code example, schema facade, php artisan, eloquent, blueprint, artisan, migrate + :keywords: php framework, odm, code example, schema facade, artisan, eloquent, blueprint, artisan, migrate .. contents:: On this page :local: @@ -68,7 +68,7 @@ following changes to perform the schema changes on your MongoDB database: .. tip:: If your default database connection is set to anything other than your - MongoDB database, update the following items so that PHP artisan performs + MongoDB database, update the following items so that Artisan performs the migration on the correct database: - Specify ``mongodb`` in the ``$connection`` field of your migration class @@ -87,18 +87,18 @@ The following example migration class contains the following methods: Run or Roll Back a Migration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To run the database migration from a class file, run the following PHP artisan +To run the database migration from a class file, run the following Artisan command after replacing the placeholder: .. code-block:: bash php artisan migrate --path= -This artisan command runs the ``up()`` function in the class file to create +This Artisan command runs the ``up()`` function in the class file to create the collection and index in the database specified in the ``config/database.php`` file. -To roll back the migration, run the following PHP artisan command after +To roll back the migration, run the following Artisan command after replacing the placeholder: .. code-block:: bash @@ -140,7 +140,7 @@ the number of documents needed to retrieve query results. Certain indexes, such as geospatial indexes, extend how you can query the data. To improve query performance by using an index, make sure the index covers -the query. To learn more about indexes and query optimization, see the +the query. To learn more about indexes and query optimization, see the following {+server-docs-name+} entries: - :manual:`Indexes ` diff --git a/docs/includes/schema-builder/flights_migration.php b/docs/includes/schema-builder/flights_migration.php index 463b94871..861c339ef 100644 --- a/docs/includes/schema-builder/flights_migration.php +++ b/docs/includes/schema-builder/flights_migration.php @@ -12,13 +12,13 @@ public function up(): void { - // begin create index + // begin create index Schema::create('flights', function (Blueprint $collection) { $collection->index('mission_type'); $collection->index(['launch_location' => 1, 'launch_date' => -1]); $collection->unique('mission_id', options: ['name' => 'unique_mission_id_idx']); }); - // end create index + // end create index } public function down(): void From 06dcdef824cf6d97e93b428b6e739e19d16d0712 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Wed, 20 Mar 2024 09:42:33 -0400 Subject: [PATCH 29/30] Revert "Merge branch 'mongodb:4.2' into DOCSP-37057-eloquent-schema-builder" This reverts commit 72221f51e167614f873611c9e3784095f964b7d3, reversing changes made to ac4504c114de8c0b6bb6436697d39959da2a6306. --- .github/workflows/build-ci.yml | 15 +- .github/workflows/merge-up.yml | 30 ---- CHANGELOG.md | 8 - composer.json | 14 +- docs/compatibility.txt | 2 +- .../framework-compatibility-laravel.rst | 8 - docs/index.txt | 61 +++++++- docs/issues-and-help.txt | 56 ------- docs/quick-start.txt | 2 +- docs/upgrade.txt | 124 ++++----------- src/Connection.php | 2 +- src/Eloquent/Builder.php | 51 ------ src/Eloquent/Model.php | 23 +-- .../FindAndModifyCommandSubscriber.php | 34 ---- src/Query/Builder.php | 6 +- tests/ModelTest.php | 47 ------ tests/Query/BuilderTest.php | 146 +----------------- 17 files changed, 101 insertions(+), 528 deletions(-) delete mode 100644 .github/workflows/merge-up.yml delete mode 100644 docs/issues-and-help.txt delete mode 100644 src/Internal/FindAndModifyCommandSubscriber.php diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index c6a84e120..55cf0f773 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: "${{ matrix.os }}" - name: "PHP ${{ matrix.php }} Laravel ${{ matrix.laravel }} MongoDB ${{ matrix.mongodb }} ${{ matrix.mode }}" + name: "PHP v${{ matrix.php }} with MongoDB ${{ matrix.mongodb }} ${{ matrix.mode }}" strategy: matrix: @@ -23,17 +23,10 @@ jobs: - "8.1" - "8.2" - "8.3" - laravel: - - "10.*" - - "11.*" include: - php: "8.1" - laravel: "10.*" mongodb: "5.0" mode: "low-deps" - exclude: - - php: "8.1" - laravel: "11.*" steps: - uses: "actions/checkout@v4" @@ -65,9 +58,6 @@ jobs: if: ${{ runner.debug }} run: "docker version && env" - - name: "Restrict Laravel version" - run: "composer require --dev --no-update 'laravel/framework:${{ matrix.laravel }}'" - - name: "Download Composer cache dependencies from cache" id: "composer-cache" run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT @@ -80,7 +70,8 @@ jobs: restore-keys: "${{ matrix.os }}-composer-" - name: "Install dependencies" - run: composer update --no-interaction $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest') + run: composer update --no-interaction $([[ "${{ matrix.mode }}" == low-deps ]] && echo ' --prefer-lowest --prefer-stable') + - name: "Run tests" run: "./vendor/bin/phpunit --coverage-clover coverage.xml" env: diff --git a/.github/workflows/merge-up.yml b/.github/workflows/merge-up.yml deleted file mode 100644 index 215c2d9ac..000000000 --- a/.github/workflows/merge-up.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Merge up - -on: - push: - branches: - - "[0-9]+.[0-9]+" - -env: - GH_TOKEN: ${{ secrets.MERGE_UP_TOKEN }} - -jobs: - merge-up: - name: Create merge up pull request - runs-on: ubuntu-latest - - steps: - - name: Checkout - id: checkout - uses: actions/checkout@v4 - with: - # fetch-depth 0 is required to fetch all branches, not just the branch being built - fetch-depth: 0 - token: ${{ secrets.MERGE_UP_TOKEN }} - - - name: Create pull request - id: create-pull-request - uses: alcaeus/automatic-merge-up-action@main - with: - ref: ${{ github.ref_name }} - branchNamePattern: '.' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a1fe6c95..56fe478d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,6 @@ # Changelog All notable changes to this project will be documented in this file. -## [unreleased] - - -## [4.2.0] - 2024-12-14 - -* Add support for Laravel 11 by @GromNaN in [#2735](https://github.com/mongodb/laravel-mongodb/pull/2735) -* Implement Model::createOrFirst() using findOneAndUpdate operation by @GromNaN in [#2742](https://github.com/mongodb/laravel-mongodb/pull/2742) - ## [4.1.3] - 2024-03-05 * Fix the timezone of `datetime` fields when they are read from the database. By @GromNaN in [#2739](https://github.com/mongodb/laravel-mongodb/pull/2739) diff --git a/composer.json b/composer.json index d19c1149a..22b75f58f 100644 --- a/composer.json +++ b/composer.json @@ -24,21 +24,20 @@ "require": { "php": "^8.1", "ext-mongodb": "^1.15", - "illuminate/support": "^10.0|^11", - "illuminate/container": "^10.0|^11", - "illuminate/database": "^10.30|^11", - "illuminate/events": "^10.0|^11", + "illuminate/support": "^10.0", + "illuminate/container": "^10.0", + "illuminate/database": "^10.30", + "illuminate/events": "^10.0", "mongodb/mongodb": "^1.15" }, "require-dev": { "phpunit/phpunit": "^10.3", - "orchestra/testbench": "^8.0|^9.0", + "orchestra/testbench": "^8.0", "mockery/mockery": "^1.4.4", "doctrine/coding-standard": "12.0.x-dev", "spatie/laravel-query-builder": "^5.6", "phpstan/phpstan": "^1.10" }, - "minimum-stability": "dev", "replace": { "jenssegers/mongodb": "self.version" }, @@ -67,6 +66,9 @@ "cs:fix": "phpcbf" }, "config": { + "platform": { + "php": "8.1" + }, "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true } diff --git a/docs/compatibility.txt b/docs/compatibility.txt index 1ab0f6c91..40ffef740 100644 --- a/docs/compatibility.txt +++ b/docs/compatibility.txt @@ -23,5 +23,5 @@ The following compatibility table specifies the versions of Laravel and .. include:: /includes/framework-compatibility-laravel.rst To find compatibility information for unmaintained versions of {+odm-short+}, -see `Laravel Version Compatibility <{+mongodb-laravel-gh+}/blob/3.9/README.md#installation>`__ +see `Laravel Version Compatibility `__ on GitHub. diff --git a/docs/includes/framework-compatibility-laravel.rst b/docs/includes/framework-compatibility-laravel.rst index 1efdce964..9b39db4ea 100644 --- a/docs/includes/framework-compatibility-laravel.rst +++ b/docs/includes/framework-compatibility-laravel.rst @@ -3,22 +3,14 @@ :stub-columns: 1 * - {+odm-short+} Version - - Laravel 11.x - Laravel 10.x - Laravel 9.x - * - 4.2 - - ✓ - - ✓ - - - * - 4.1 - - - ✓ - * - 4.0 - - - ✓ - diff --git a/docs/index.txt b/docs/index.txt index febdb9371..8ee11dbda 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -14,14 +14,12 @@ Laravel MongoDB :maxdepth: 1 /quick-start - Release Notes /retrieve /eloquent-models /query-builder /user-authentication /queues /transactions - /issues-and-help /compatibility /upgrade @@ -60,12 +58,6 @@ see the following content: - :ref:`laravel-queues` - :ref:`laravel-transactions` -Issues & Help -------------- - -Learn how to report bugs, contribute to the library, and find -more resources in the :ref:`laravel-issues-and-help` section. - Compatibility ------------- @@ -78,4 +70,57 @@ Upgrade Versions Learn what changes you might need to make to your application to upgrade versions in the :ref:`laravel-upgrading` section. +Reporting Issues +---------------- + +We are lucky to have a vibrant PHP community that includes users of varying +experience with MongoDB PHP Library and {+odm-short+}. To get support for +general questions, search or post in the +:community-forum:`MongoDB Community Forums <>`. + +To learn more about MongoDB support options, see the +`Technical Support `__ page. + + +Bugs / Feature Requests +----------------------- + +If you've found a bug or want to see a new feature in {+odm-short+}, +please report it in the GitHub issues section of the +`mongodb/laravel-mongodb `__ +repository. + +If you want to contribute code, see the following section for instructions on +submitting pull requests. + +To report a bug or request a new feature, perform the following steps: + +1. Visit the `GitHub issues `__ + section and search for any similar issues or bugs. +#. If you find a matching issue, you can reply to the thread to report that + you have a similar issue or request. +#. If you cannot find a matching issue, click :guilabel:`New issue` and select + the appropriate issue type. +#. If you selected "Bug report" or "Feature request", please provide as much + information as possible about the issue. Click :guilabel:`Submit new issue` + to complete your submission. + +If you've identified a security vulnerability in any official MongoDB +product, please report it according to the instructions found in the +:manual:`Create a Vulnerability Report page `. + +For general questions and support requests, please use one of MongoDB's +:manual:`Technical Support ` channels. + +Pull Requests +------------- + +We are happy to accept contributions to help improve the {+odm-short+}. + +We track current development in `PHPORM `__ +MongoDB JIRA project. + +To learn more about contributing to this project, see the +`CONTRIBUTING.md `__ +guide on GitHub. diff --git a/docs/issues-and-help.txt b/docs/issues-and-help.txt deleted file mode 100644 index ff4a1dbb9..000000000 --- a/docs/issues-and-help.txt +++ /dev/null @@ -1,56 +0,0 @@ -.. _laravel-issues-and-help: - -============= -Issues & Help -============= - -We are lucky to have a vibrant PHP community that includes users of varying -experience with MongoDB PHP Library and {+odm-short+}. To get support for -general questions, search or post in the -:community-forum:`MongoDB PHP Community Forums `. - -To learn more about MongoDB support options, see the -`Technical Support `__ page. - -Bugs / Feature Requests ------------------------ - -If you find a bug or want to see a new feature in {+odm-short+}, -please report it as a GitHub issue in the `mongodb/laravel-mongodb -<{+mongodb-laravel-gh+}>`__ repository. - -If you want to contribute code, see the :ref:`laravel-pull-requests` section -for instructions on submitting pull requests. - -To report a bug or request a new feature, perform the following steps: - -1. Review the `GitHub issues list <{+mongodb-laravel-gh+}/issues>`__ - in the source repository and search for any existing issues that address your concern. -#. If you find a matching issue, you can reply to the thread to report that - you have a similar issue or request. -#. If you cannot find a matching issue, click :guilabel:`New issue` and select - the appropriate issue type. -#. If you select "Bug report" or "Feature request" as the issue type, please provide as - much information as possible about the issue. Click :guilabel:`Submit new issue` - to complete your submission. - -If you've identified a security vulnerability in any official MongoDB -product, please report it according to the instructions found in the -:manual:`Create a Vulnerability Report page `. - -For general questions and support requests, please use one of MongoDB's -:manual:`Technical Support ` channels. - -.. _laravel-pull-requests: - -Pull Requests -------------- - -We are happy to accept contributions to help improve {+odm-short+}. - -We track current development in `PHPORM `__ -MongoDB JIRA project. - -To learn more about contributing to this project, see the -`CONTRIBUTING.md <{+mongodb-laravel-gh+}/blob/{+package-version+}/CONTRIBUTING.md>`__ -guide on GitHub. diff --git a/docs/quick-start.txt b/docs/quick-start.txt index d672f3e31..b5f9166ae 100644 --- a/docs/quick-start.txt +++ b/docs/quick-start.txt @@ -33,7 +33,7 @@ read and write operations on the data. You can learn how to set up a local Laravel development environment and perform CRUD operations by viewing the - :mdbu-course:`Getting Started with Laravel and MongoDB ` + :mdbu-course:`Getting Started with Laravel and MongoDB ` MongoDB University Learning Byte. If you prefer to connect to MongoDB by using the PHP Library driver without diff --git a/docs/upgrade.txt b/docs/upgrade.txt index 1aeba2be3..8148fbdfc 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -1,8 +1,8 @@ .. _laravel-upgrading: -======================= -Upgrade Library Version -======================= +========= +Upgrading +========= .. facet:: :name: genre @@ -11,109 +11,39 @@ Upgrade Library Version .. meta:: :keywords: php framework, odm, code example -.. contents:: On this page - :local: - :backlinks: none - :depth: 1 - :class: singlecol +The PHP library uses `semantic versioning `__. Upgrading +to a new major version may require changes to your application. -Overview --------- +Upgrading from version 3 to 4 +----------------------------- -On this page, you can learn how to upgrade {+odm-short+} to a new major version. -This page also includes the changes you must make to your application to upgrade -your object-document mapper (ODM) version without losing functionality, if applicable. +- Laravel 10.x is required -How to Upgrade --------------- +- Change dependency name in your composer.json to ``"mongodb/laravel-mongodb": "^4.0"`` + and run ``composer update`` -Before you upgrade, perform the following actions: +- Change namespace from ``Jenssegers\Mongodb\`` to ``MongoDB\Laravel\`` + in your models and config -- Ensure the new library version is compatible with the MongoDB Server version - your application connects to and the version of Laravel that your - application runs on. See the :ref:`` - page for this information. -- Address any breaking changes between the version of {+odm-short+} that - your application currently uses and your planned upgrade version in the - :ref:`` section of this guide. +- Remove support for non-Laravel projects -To upgrade your library version, run the following command in your application's -directory: +- Replace ``$dates`` with ``$casts`` in your models -.. code-block:: bash - - composer require mongodb/laravel-mongodb:{+package-version+} +- Call ``$model->save()`` after ``$model->unset('field')`` to persist the change -To upgrade to a different version of the library, replace the information after -``laravel-mongodb:`` with your preferred version number. +- Replace calls to ``Query\Builder::whereAll($column, $values)`` with + ``Query\Builder::where($column, 'all', $values)`` -.. _laravel-breaking-changes: +- ``Query\Builder::delete()`` doesn't accept ``limit()`` other than ``1`` or ``null``. -Breaking Changes ----------------- +- ``whereDate``, ``whereDay``, ``whereMonth``, ``whereYear``, ``whereTime`` + now use MongoDB operators on date fields -A breaking change is a modification in a convention or behavior in -a specific version of {+odm-short+} that might prevent your application -from working as expected. +- Replace ``Illuminate\Database\Eloquent\MassPrunable`` with ``MongoDB\Laravel\Eloquent\MassPrunable`` + in your models -The breaking changes in this section are categorized by the major -version releases that introduced them. When upgrading library versions, -address all the breaking changes between your current version and the -planned upgrade version. - -.. _laravel-breaking-changes-v4.x: - -Version 4.x Breaking Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This library version introduces the following breaking changes: - -- Minimum Laravel version is now 10.0. For instructions on upgrading your Laravel version, - see the `Upgrade Guide `__ in the Laravel - documentation. - -- Dependency name is now ``"mongodb/laravel-mongodb"``. Ensure that the dependency - name in your ``composer.json`` file is ``"mongodb/laravel-mongodb": "^4.0"``. Then, run - ``composer update``. - -- Namespace is now ``MongoDB\Laravel\``. Ensure that you change the namespace from ``Jenssegers\Mongodb\`` - to ``MongoDB\Laravel\`` in your models and config files. - -- Removes support for non-Laravel projects. - -- Removes support for the ``$dates`` property. Ensure that you change all instances of ``$dates`` - to ``$casts`` in your model files. - -- ``Model::unset($field)`` does not persist the change. Ensure that you follow all calls to - ``Model::unset($field)`` with ``Model::save()``. - -- Removes the ``Query\Builder::whereAll($column, $values)`` method. Ensure that you replace all calls - to ``Query\Builder::whereAll($column, $values)`` with ``Query\Builder::where($column, 'all', $values)``. - -- ``Query\Builder::delete()`` can delete one or all documents. Ensure that you pass only the values - ``1`` or ``null`` to ``limit()``. - -- ``whereDate()``, ``whereDay()``, ``whereMonth()``, ``whereYear()``, and ``whereTime()`` methods - now use MongoDB operators on date fields. - -- Adds the ``MongoDB\Laravel\Eloquent\MassPrunable`` trait. Ensure that you replace all instances of - ``Illuminate\Database\Eloquent\MassPrunable`` with ``MongoDB\Laravel\Eloquent\MassPrunable`` - in your models. - -- Removes support for the following ``Query\Builder`` methods: - - - ``toSql()`` - - ``toRawSql()`` - - ``whereColumn()`` - - ``whereFullText()`` - - ``groupByRaw()`` - - ``orderByRaw()`` - - ``unionAll()`` - - ``union()`` - - ``having()`` - - ``havingRaw()`` - - ``havingBetween()`` - - ``whereIntegerInRaw()`` - - ``orWhereIntegerInRaw()`` - - ``whereIntegerNotInRaw()`` - - ``orWhereIntegerNotInRaw()`` +- Remove calls to not-supported methods of ``Query\Builder``: ``toSql``, + ``toRawSql``, ``whereColumn``, ``whereFullText``, ``groupByRaw``, + ``orderByRaw``, ``unionAll``, ``union``, ``having``, ``havingRaw``, + ``havingBetween``, ``whereIntegerInRaw``, ``orWhereIntegerInRaw``, + ``whereIntegerNotInRaw``, ``orWhereIntegerNotInRaw``. diff --git a/src/Connection.php b/src/Connection.php index 3f529cdea..a859bfa63 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -328,7 +328,7 @@ private static function lookupVersion(): string try { return self::$version = InstalledVersions::getPrettyVersion('mongodb/laravel-mongodb'); } catch (Throwable) { - return self::$version = 'error'; + // Ignore exceptions and return unknown version } } diff --git a/src/Eloquent/Builder.php b/src/Eloquent/Builder.php index 7ea18dfa9..b9005c442 100644 --- a/src/Eloquent/Builder.php +++ b/src/Eloquent/Builder.php @@ -6,15 +6,10 @@ use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; -use InvalidArgumentException; use MongoDB\Driver\Cursor; -use MongoDB\Laravel\Collection; use MongoDB\Laravel\Helpers\QueriesRelationships; -use MongoDB\Laravel\Internal\FindAndModifyCommandSubscriber; use MongoDB\Model\BSONDocument; -use MongoDB\Operation\FindOneAndUpdate; -use function array_intersect_key; use function array_key_exists; use function array_merge; use function collect; @@ -188,52 +183,6 @@ public function raw($value = null) return $results; } - /** - * Attempt to create the record if it does not exist with the matching attributes. - * If the record exists, it will be returned. - * - * @param array $attributes The attributes to check for duplicate records - * @param array $values The attributes to insert if no matching record is found - */ - public function createOrFirst(array $attributes = [], array $values = []): Model - { - if ($attributes === []) { - throw new InvalidArgumentException('You must provide attributes to check for duplicates'); - } - - // Apply casting and default values to the attributes - // In case of duplicate key between the attributes and the values, the values have priority - $instance = $this->newModelInstance($values + $attributes); - $values = $instance->getAttributes(); - $attributes = array_intersect_key($attributes, $values); - - return $this->raw(function (Collection $collection) use ($attributes, $values) { - $listener = new FindAndModifyCommandSubscriber(); - $collection->getManager()->addSubscriber($listener); - - try { - $document = $collection->findOneAndUpdate( - $attributes, - // Before MongoDB 5.0, $setOnInsert requires a non-empty document. - // This is should not be an issue as $values includes the query filter. - ['$setOnInsert' => (object) $values], - [ - 'upsert' => true, - 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER, - 'typeMap' => ['root' => 'array', 'document' => 'array'], - ], - ); - } finally { - $collection->getManager()->removeSubscriber($listener); - } - - $model = $this->model->newFromBuilder($document); - $model->wasRecentlyCreated = $listener->created; - - return $model; - }); - } - /** * Add the "updated at" column to an array of values. * TODO Remove if https://github.com/laravel/framework/commit/6484744326531829341e1ff886cc9b628b20d73e diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 78999bce8..83239c8eb 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -4,7 +4,6 @@ namespace MongoDB\Laravel\Eloquent; -use BackedEnum; use Carbon\CarbonInterface; use DateTimeInterface; use DateTimeZone; @@ -24,7 +23,6 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Laravel\Query\Builder as QueryBuilder; use Stringable; -use ValueError; use function array_key_exists; use function array_keys; @@ -42,12 +40,10 @@ use function is_string; use function ltrim; use function method_exists; -use function sprintf; use function str_contains; use function str_starts_with; use function strcmp; use function uniqid; -use function var_export; abstract class Model extends BaseModel { @@ -699,7 +695,7 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt } if ($this->isEnumCastable($key) && (! $castValue instanceof Arrayable)) { - $castValue = $castValue !== null ? $this->getStorableEnumValueFromLaravel11($this->getCasts()[$key], $castValue) : null; + $castValue = $castValue !== null ? $this->getStorableEnumValue($castValue) : null; } if ($castValue instanceof Arrayable) { @@ -712,23 +708,6 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt return $attributes; } - /** - * Duplicate of {@see HasAttributes::getStorableEnumValue()} for Laravel 11 as the signature of the method has - * changed in a non-backward compatible way. - * - * @todo Remove this method when support for Laravel 10 is dropped. - */ - private function getStorableEnumValueFromLaravel11($expectedEnum, $value) - { - if (! $value instanceof $expectedEnum) { - throw new ValueError(sprintf('Value [%s] is not of the expected enum type [%s].', var_export($value, true), $expectedEnum)); - } - - return $value instanceof BackedEnum - ? $value->value - : $value->name; - } - /** * Is a value a BSON type? * diff --git a/src/Internal/FindAndModifyCommandSubscriber.php b/src/Internal/FindAndModifyCommandSubscriber.php deleted file mode 100644 index 55b13436b..000000000 --- a/src/Internal/FindAndModifyCommandSubscriber.php +++ /dev/null @@ -1,34 +0,0 @@ -created = ! $event->getReply()->lastErrorObject->updatedExisting; - } -} diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 0f05f4577..27e788db8 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -614,7 +614,11 @@ public function orderBy($column, $direction = 'asc') return $this; } - /** @inheritdoc */ + /** + * @param list{mixed, mixed}|CarbonPeriod $values + * + * @inheritdoc + */ public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { $type = 'between'; diff --git a/tests/ModelTest.php b/tests/ModelTest.php index 5ab6badee..ec1579869 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -11,7 +11,6 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Date; use Illuminate\Support\Str; -use InvalidArgumentException; use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectID; use MongoDB\BSON\UTCDateTime; @@ -1045,50 +1044,4 @@ public function testNumericFieldName(): void $this->assertInstanceOf(User::class, $found); $this->assertEquals([3 => 'two.three'], $found[2]); } - - public function testCreateOrFirst() - { - $user1 = User::createOrFirst(['email' => 'john.doe@example.com']); - - $this->assertSame('john.doe@example.com', $user1->email); - $this->assertNull($user1->name); - $this->assertTrue($user1->wasRecentlyCreated); - - $user2 = User::createOrFirst( - ['email' => 'john.doe@example.com'], - ['name' => 'John Doe', 'birthday' => new DateTime('1987-05-28')], - ); - - $this->assertEquals($user1->id, $user2->id); - $this->assertSame('john.doe@example.com', $user2->email); - $this->assertNull($user2->name); - $this->assertNull($user2->birthday); - $this->assertFalse($user2->wasRecentlyCreated); - - $user3 = User::createOrFirst( - ['email' => 'jane.doe@example.com'], - ['name' => 'Jane Doe', 'birthday' => new DateTime('1987-05-28')], - ); - - $this->assertNotEquals($user3->id, $user1->id); - $this->assertSame('jane.doe@example.com', $user3->email); - $this->assertSame('Jane Doe', $user3->name); - $this->assertEquals(new DateTime('1987-05-28'), $user3->birthday); - $this->assertTrue($user3->wasRecentlyCreated); - - $user4 = User::createOrFirst( - ['name' => 'Robert Doe'], - ['name' => 'Maria Doe', 'email' => 'maria.doe@example.com'], - ); - - $this->assertSame('Maria Doe', $user4->name); - $this->assertTrue($user4->wasRecentlyCreated); - } - - public function testCreateOrFirstRequiresFilter() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('You must provide attributes to check for duplicates'); - User::createOrFirst([]); - } } diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 4076b3028..8f62583ce 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -23,7 +23,6 @@ use stdClass; use function collect; -use function method_exists; use function now; use function var_export; @@ -565,12 +564,7 @@ function (Builder $builder) { yield 'whereBetween CarbonPeriod' => [ [ 'find' => [ - [ - 'created_at' => [ - '$gte' => new UTCDateTime($period->getStartDate()), - '$lte' => new UTCDateTime($period->getEndDate()), - ], - ], + ['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], [], // options ], ], @@ -1158,144 +1152,6 @@ function (Builder $elemMatchQuery): void { }, ), ]; - - // Method added in Laravel v10.47.0 - if (method_exists(Builder::class, 'whereAll')) { - /** @see DatabaseQueryBuilderTest::testWhereAll */ - yield 'whereAll' => [ - [ - 'find' => [ - ['$and' => [['last_name' => 'Doe'], ['email' => 'Doe']]], - [], // options - ], - ], - fn(Builder $builder) => $builder->whereAll(['last_name', 'email'], 'Doe'), - ]; - - yield 'whereAll operator' => [ - [ - 'find' => [ - [ - '$and' => [ - ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder->whereAll(['last_name', 'email'], 'not like', '%Doe%'), - ]; - - /** @see DatabaseQueryBuilderTest::testOrWhereAll */ - yield 'orWhereAll' => [ - [ - 'find' => [ - [ - '$or' => [ - ['first_name' => 'John'], - ['$and' => [['last_name' => 'Doe'], ['email' => 'Doe']]], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder - ->where('first_name', 'John') - ->orWhereAll(['last_name', 'email'], 'Doe'), - ]; - - yield 'orWhereAll operator' => [ - [ - 'find' => [ - [ - '$or' => [ - ['first_name' => new Regex('^.*John.*$', 'i')], - [ - '$and' => [ - ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ], - ], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder - ->where('first_name', 'like', '%John%') - ->orWhereAll(['last_name', 'email'], 'not like', '%Doe%'), - ]; - } - - // Method added in Laravel v10.47.0 - if (method_exists(Builder::class, 'whereAny')) { - /** @see DatabaseQueryBuilderTest::testWhereAny */ - yield 'whereAny' => [ - [ - 'find' => [ - ['$or' => [['last_name' => 'Doe'], ['email' => 'Doe']]], - [], // options - ], - ], - fn(Builder $builder) => $builder->whereAny(['last_name', 'email'], 'Doe'), - ]; - - yield 'whereAny operator' => [ - [ - 'find' => [ - [ - '$or' => [ - ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder->whereAny(['last_name', 'email'], 'not like', '%Doe%'), - ]; - - /** @see DatabaseQueryBuilderTest::testOrWhereAny */ - yield 'orWhereAny' => [ - [ - 'find' => [ - [ - '$or' => [ - ['first_name' => 'John'], - ['$or' => [['last_name' => 'Doe'], ['email' => 'Doe']]], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder - ->where('first_name', 'John') - ->orWhereAny(['last_name', 'email'], 'Doe'), - ]; - - yield 'orWhereAny operator' => [ - [ - 'find' => [ - [ - '$or' => [ - ['first_name' => new Regex('^.*John.*$', 'i')], - [ - '$or' => [ - ['last_name' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ['email' => ['$not' => new Regex('^.*Doe.*$', 'i')]], - ], - ], - ], - ], - [], // options - ], - ], - fn(Builder $builder) => $builder - ->where('first_name', 'like', '%John%') - ->orWhereAny(['last_name', 'email'], 'not like', '%Doe%'), - ]; - } } /** @dataProvider provideExceptions */ From 2465ad3c7130ab1d34b0e70d84e68101e9eff290 Mon Sep 17 00:00:00 2001 From: Chris Cho Date: Thu, 21 Mar 2024 11:15:36 -0400 Subject: [PATCH 30/30] PRR and branch fixes --- .github/workflows/build-ci.yml | 8 +- .github/workflows/merge-up.yml | 30 ++++++ docs/compatibility.txt | 2 +- docs/eloquent-models/schema-builder.txt | 18 ++-- docs/index.txt | 61 ++---------- docs/issues-and-help.txt | 56 +++++++++++ docs/quick-start.txt | 2 +- docs/upgrade.txt | 124 ++++++++++++++++++------ 8 files changed, 209 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/merge-up.yml create mode 100644 docs/issues-and-help.txt diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 55cf0f773..780f6cbcd 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: "${{ matrix.os }}" - name: "PHP v${{ matrix.php }} with MongoDB ${{ matrix.mongodb }} ${{ matrix.mode }}" + name: "PHP ${{ matrix.php }} Laravel ${{ matrix.laravel }} MongoDB ${{ matrix.mongodb }} ${{ matrix.mode }}" strategy: matrix: @@ -23,8 +23,11 @@ jobs: - "8.1" - "8.2" - "8.3" + laravel: + - "10.*" include: - php: "8.1" + laravel: "10.*" mongodb: "5.0" mode: "low-deps" @@ -58,6 +61,9 @@ jobs: if: ${{ runner.debug }} run: "docker version && env" + - name: "Restrict Laravel version" + run: "composer require --dev --no-update 'laravel/framework:${{ matrix.laravel }}'" + - name: "Download Composer cache dependencies from cache" id: "composer-cache" run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/merge-up.yml b/.github/workflows/merge-up.yml new file mode 100644 index 000000000..215c2d9ac --- /dev/null +++ b/.github/workflows/merge-up.yml @@ -0,0 +1,30 @@ +name: Merge up + +on: + push: + branches: + - "[0-9]+.[0-9]+" + +env: + GH_TOKEN: ${{ secrets.MERGE_UP_TOKEN }} + +jobs: + merge-up: + name: Create merge up pull request + runs-on: ubuntu-latest + + steps: + - name: Checkout + id: checkout + uses: actions/checkout@v4 + with: + # fetch-depth 0 is required to fetch all branches, not just the branch being built + fetch-depth: 0 + token: ${{ secrets.MERGE_UP_TOKEN }} + + - name: Create pull request + id: create-pull-request + uses: alcaeus/automatic-merge-up-action@main + with: + ref: ${{ github.ref_name }} + branchNamePattern: '.' diff --git a/docs/compatibility.txt b/docs/compatibility.txt index 40ffef740..1ab0f6c91 100644 --- a/docs/compatibility.txt +++ b/docs/compatibility.txt @@ -23,5 +23,5 @@ The following compatibility table specifies the versions of Laravel and .. include:: /includes/framework-compatibility-laravel.rst To find compatibility information for unmaintained versions of {+odm-short+}, -see `Laravel Version Compatibility `__ +see `Laravel Version Compatibility <{+mongodb-laravel-gh+}/blob/3.9/README.md#installation>`__ on GitHub. diff --git a/docs/eloquent-models/schema-builder.txt b/docs/eloquent-models/schema-builder.txt index 735779705..9fd845b55 100644 --- a/docs/eloquent-models/schema-builder.txt +++ b/docs/eloquent-models/schema-builder.txt @@ -9,7 +9,7 @@ Schema Builder :values: tutorial .. meta:: - :keywords: php framework, odm, code example, schema facade, artisan, eloquent, blueprint, artisan, migrate + :keywords: php framework, odm, code example, schema facade, eloquent, blueprint, artisan, migrate .. contents:: On this page :local: @@ -68,8 +68,8 @@ following changes to perform the schema changes on your MongoDB database: .. tip:: If your default database connection is set to anything other than your - MongoDB database, update the following items so that Artisan performs - the migration on the correct database: + MongoDB database, update the following setting to make sure the migration + specifies the correct database: - Specify ``mongodb`` in the ``$connection`` field of your migration class - Set ``DB_CONNECTION=mongodb`` in your ``.env`` configuration file @@ -87,19 +87,19 @@ The following example migration class contains the following methods: Run or Roll Back a Migration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To run the database migration from a class file, run the following Artisan -command after replacing the placeholder: +To run the database migration from a class file, run the following command +after replacing the placeholder: .. code-block:: bash php artisan migrate --path= -This Artisan command runs the ``up()`` function in the class file to create -the collection and index in the database specified in the ``config/database.php`` +This command runs the ``up()`` function in the class file to create the +collection and index in the database specified in the ``config/database.php`` file. -To roll back the migration, run the following Artisan command after -replacing the placeholder: +To roll back the migration, run the following command after replacing the +placeholder: .. code-block:: bash diff --git a/docs/index.txt b/docs/index.txt index 8ee11dbda..febdb9371 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -14,12 +14,14 @@ Laravel MongoDB :maxdepth: 1 /quick-start + Release Notes /retrieve /eloquent-models /query-builder /user-authentication /queues /transactions + /issues-and-help /compatibility /upgrade @@ -58,6 +60,12 @@ see the following content: - :ref:`laravel-queues` - :ref:`laravel-transactions` +Issues & Help +------------- + +Learn how to report bugs, contribute to the library, and find +more resources in the :ref:`laravel-issues-and-help` section. + Compatibility ------------- @@ -70,57 +78,4 @@ Upgrade Versions Learn what changes you might need to make to your application to upgrade versions in the :ref:`laravel-upgrading` section. -Reporting Issues ----------------- - -We are lucky to have a vibrant PHP community that includes users of varying -experience with MongoDB PHP Library and {+odm-short+}. To get support for -general questions, search or post in the -:community-forum:`MongoDB Community Forums <>`. - -To learn more about MongoDB support options, see the -`Technical Support `__ page. - - -Bugs / Feature Requests ------------------------ - -If you've found a bug or want to see a new feature in {+odm-short+}, -please report it in the GitHub issues section of the -`mongodb/laravel-mongodb `__ -repository. - -If you want to contribute code, see the following section for instructions on -submitting pull requests. - -To report a bug or request a new feature, perform the following steps: - -1. Visit the `GitHub issues `__ - section and search for any similar issues or bugs. -#. If you find a matching issue, you can reply to the thread to report that - you have a similar issue or request. -#. If you cannot find a matching issue, click :guilabel:`New issue` and select - the appropriate issue type. -#. If you selected "Bug report" or "Feature request", please provide as much - information as possible about the issue. Click :guilabel:`Submit new issue` - to complete your submission. - -If you've identified a security vulnerability in any official MongoDB -product, please report it according to the instructions found in the -:manual:`Create a Vulnerability Report page `. - -For general questions and support requests, please use one of MongoDB's -:manual:`Technical Support ` channels. - -Pull Requests -------------- - -We are happy to accept contributions to help improve the {+odm-short+}. - -We track current development in `PHPORM `__ -MongoDB JIRA project. - -To learn more about contributing to this project, see the -`CONTRIBUTING.md `__ -guide on GitHub. diff --git a/docs/issues-and-help.txt b/docs/issues-and-help.txt new file mode 100644 index 000000000..ff4a1dbb9 --- /dev/null +++ b/docs/issues-and-help.txt @@ -0,0 +1,56 @@ +.. _laravel-issues-and-help: + +============= +Issues & Help +============= + +We are lucky to have a vibrant PHP community that includes users of varying +experience with MongoDB PHP Library and {+odm-short+}. To get support for +general questions, search or post in the +:community-forum:`MongoDB PHP Community Forums `. + +To learn more about MongoDB support options, see the +`Technical Support `__ page. + +Bugs / Feature Requests +----------------------- + +If you find a bug or want to see a new feature in {+odm-short+}, +please report it as a GitHub issue in the `mongodb/laravel-mongodb +<{+mongodb-laravel-gh+}>`__ repository. + +If you want to contribute code, see the :ref:`laravel-pull-requests` section +for instructions on submitting pull requests. + +To report a bug or request a new feature, perform the following steps: + +1. Review the `GitHub issues list <{+mongodb-laravel-gh+}/issues>`__ + in the source repository and search for any existing issues that address your concern. +#. If you find a matching issue, you can reply to the thread to report that + you have a similar issue or request. +#. If you cannot find a matching issue, click :guilabel:`New issue` and select + the appropriate issue type. +#. If you select "Bug report" or "Feature request" as the issue type, please provide as + much information as possible about the issue. Click :guilabel:`Submit new issue` + to complete your submission. + +If you've identified a security vulnerability in any official MongoDB +product, please report it according to the instructions found in the +:manual:`Create a Vulnerability Report page `. + +For general questions and support requests, please use one of MongoDB's +:manual:`Technical Support ` channels. + +.. _laravel-pull-requests: + +Pull Requests +------------- + +We are happy to accept contributions to help improve {+odm-short+}. + +We track current development in `PHPORM `__ +MongoDB JIRA project. + +To learn more about contributing to this project, see the +`CONTRIBUTING.md <{+mongodb-laravel-gh+}/blob/{+package-version+}/CONTRIBUTING.md>`__ +guide on GitHub. diff --git a/docs/quick-start.txt b/docs/quick-start.txt index b5f9166ae..d672f3e31 100644 --- a/docs/quick-start.txt +++ b/docs/quick-start.txt @@ -33,7 +33,7 @@ read and write operations on the data. You can learn how to set up a local Laravel development environment and perform CRUD operations by viewing the - :mdbu-course:`Getting Started with Laravel and MongoDB ` + :mdbu-course:`Getting Started with Laravel and MongoDB ` MongoDB University Learning Byte. If you prefer to connect to MongoDB by using the PHP Library driver without diff --git a/docs/upgrade.txt b/docs/upgrade.txt index 8148fbdfc..1aeba2be3 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -1,8 +1,8 @@ .. _laravel-upgrading: -========= -Upgrading -========= +======================= +Upgrade Library Version +======================= .. facet:: :name: genre @@ -11,39 +11,109 @@ Upgrading .. meta:: :keywords: php framework, odm, code example -The PHP library uses `semantic versioning `__. Upgrading -to a new major version may require changes to your application. +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol -Upgrading from version 3 to 4 ------------------------------ +Overview +-------- -- Laravel 10.x is required +On this page, you can learn how to upgrade {+odm-short+} to a new major version. +This page also includes the changes you must make to your application to upgrade +your object-document mapper (ODM) version without losing functionality, if applicable. -- Change dependency name in your composer.json to ``"mongodb/laravel-mongodb": "^4.0"`` - and run ``composer update`` +How to Upgrade +-------------- -- Change namespace from ``Jenssegers\Mongodb\`` to ``MongoDB\Laravel\`` - in your models and config +Before you upgrade, perform the following actions: -- Remove support for non-Laravel projects +- Ensure the new library version is compatible with the MongoDB Server version + your application connects to and the version of Laravel that your + application runs on. See the :ref:`` + page for this information. +- Address any breaking changes between the version of {+odm-short+} that + your application currently uses and your planned upgrade version in the + :ref:`` section of this guide. -- Replace ``$dates`` with ``$casts`` in your models +To upgrade your library version, run the following command in your application's +directory: -- Call ``$model->save()`` after ``$model->unset('field')`` to persist the change +.. code-block:: bash + + composer require mongodb/laravel-mongodb:{+package-version+} -- Replace calls to ``Query\Builder::whereAll($column, $values)`` with - ``Query\Builder::where($column, 'all', $values)`` +To upgrade to a different version of the library, replace the information after +``laravel-mongodb:`` with your preferred version number. -- ``Query\Builder::delete()`` doesn't accept ``limit()`` other than ``1`` or ``null``. +.. _laravel-breaking-changes: -- ``whereDate``, ``whereDay``, ``whereMonth``, ``whereYear``, ``whereTime`` - now use MongoDB operators on date fields +Breaking Changes +---------------- -- Replace ``Illuminate\Database\Eloquent\MassPrunable`` with ``MongoDB\Laravel\Eloquent\MassPrunable`` - in your models +A breaking change is a modification in a convention or behavior in +a specific version of {+odm-short+} that might prevent your application +from working as expected. -- Remove calls to not-supported methods of ``Query\Builder``: ``toSql``, - ``toRawSql``, ``whereColumn``, ``whereFullText``, ``groupByRaw``, - ``orderByRaw``, ``unionAll``, ``union``, ``having``, ``havingRaw``, - ``havingBetween``, ``whereIntegerInRaw``, ``orWhereIntegerInRaw``, - ``whereIntegerNotInRaw``, ``orWhereIntegerNotInRaw``. +The breaking changes in this section are categorized by the major +version releases that introduced them. When upgrading library versions, +address all the breaking changes between your current version and the +planned upgrade version. + +.. _laravel-breaking-changes-v4.x: + +Version 4.x Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This library version introduces the following breaking changes: + +- Minimum Laravel version is now 10.0. For instructions on upgrading your Laravel version, + see the `Upgrade Guide `__ in the Laravel + documentation. + +- Dependency name is now ``"mongodb/laravel-mongodb"``. Ensure that the dependency + name in your ``composer.json`` file is ``"mongodb/laravel-mongodb": "^4.0"``. Then, run + ``composer update``. + +- Namespace is now ``MongoDB\Laravel\``. Ensure that you change the namespace from ``Jenssegers\Mongodb\`` + to ``MongoDB\Laravel\`` in your models and config files. + +- Removes support for non-Laravel projects. + +- Removes support for the ``$dates`` property. Ensure that you change all instances of ``$dates`` + to ``$casts`` in your model files. + +- ``Model::unset($field)`` does not persist the change. Ensure that you follow all calls to + ``Model::unset($field)`` with ``Model::save()``. + +- Removes the ``Query\Builder::whereAll($column, $values)`` method. Ensure that you replace all calls + to ``Query\Builder::whereAll($column, $values)`` with ``Query\Builder::where($column, 'all', $values)``. + +- ``Query\Builder::delete()`` can delete one or all documents. Ensure that you pass only the values + ``1`` or ``null`` to ``limit()``. + +- ``whereDate()``, ``whereDay()``, ``whereMonth()``, ``whereYear()``, and ``whereTime()`` methods + now use MongoDB operators on date fields. + +- Adds the ``MongoDB\Laravel\Eloquent\MassPrunable`` trait. Ensure that you replace all instances of + ``Illuminate\Database\Eloquent\MassPrunable`` with ``MongoDB\Laravel\Eloquent\MassPrunable`` + in your models. + +- Removes support for the following ``Query\Builder`` methods: + + - ``toSql()`` + - ``toRawSql()`` + - ``whereColumn()`` + - ``whereFullText()`` + - ``groupByRaw()`` + - ``orderByRaw()`` + - ``unionAll()`` + - ``union()`` + - ``having()`` + - ``havingRaw()`` + - ``havingBetween()`` + - ``whereIntegerInRaw()`` + - ``orWhereIntegerInRaw()`` + - ``whereIntegerNotInRaw()`` + - ``orWhereIntegerNotInRaw()``