From 2e46a6d800ecd1ae97b0b8a6d567de5faae95bbb Mon Sep 17 00:00:00 2001 From: shamaseen Date: Fri, 18 Aug 2023 21:27:23 +0300 Subject: [PATCH 01/21] use laravel get attribute --- src/Eloquent/Model.php | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 2d938b745..b5a210658 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -148,28 +148,28 @@ public function getTable() /** * @inheritdoc */ - public function getAttribute($key) - { - if (! $key) { - return; - } - - // Dot notation support. - if (Str::contains($key, '.') && Arr::has($this->attributes, $key)) { - return $this->getAttributeValue($key); - } - - // This checks for embedded relation support. - if ( - method_exists($this, $key) - && ! method_exists(self::class, $key) - && ! $this->hasAttributeGetMutator($key) - ) { - return $this->getRelationValue($key); - } - - return parent::getAttribute($key); - } +// public function getAttribute($key) +// { +// if (! $key) { +// return; +// } +// +// // Dot notation support. +// if (Str::contains($key, '.') && Arr::has($this->attributes, $key)) { +// return $this->getAttributeValue($key); +// } +// +// // This checks for embedded relation support. +// if ( +// method_exists($this, $key) +// && ! method_exists(self::class, $key) +// && ! $this->hasAttributeGetMutator($key) +// ) { +// return $this->getRelationValue($key); +// } +// +// return parent::getAttribute($key); +// } /** * @inheritdoc From 29935f2902bb55502e77d502af374ec2a67cc491 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sat, 19 Aug 2023 19:26:06 +0300 Subject: [PATCH 02/21] update docker --- .github/workflows/build-ci.yml | 4 +++- Dockerfile | 9 +++------ docker-compose.yml | 14 ++++++++++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index c3e22c23f..dac1aab2f 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -40,12 +40,14 @@ jobs: - '4.2' - '4.4' - '5.0' + - '6.0' + - '7.0' php: - '8.1' - '8.2' services: mysql: - image: mysql:5.7 + image: mysql:8.0 ports: - 3307:3306 env: diff --git a/Dockerfile b/Dockerfile index bd7e03a14..a40ab72c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG PHP_VERSION=8.1 -ARG COMPOSER_VERSION=2.5.4 + FROM php:${PHP_VERSION}-cli @@ -9,14 +9,11 @@ RUN apt-get update && \ pecl install xdebug && docker-php-ext-enable xdebug && \ docker-php-ext-install -j$(nproc) pdo_mysql zip -COPY --from=composer:${COMPOSER_VERSION} /usr/bin/composer /usr/local/bin/composer +# Copy the Composer binary from the specified stage +COPY --from=composer:2.5.4 /usr/bin/composer /usr/local/bin/composer WORKDIR /code -COPY composer.* ./ - -RUN composer install - COPY ./ ./ RUN composer install diff --git a/docker-compose.yml b/docker-compose.yml index dab907abe..8f242a2f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: '3.5' services: tests: @@ -11,9 +11,10 @@ services: - .:/code working_dir: /code depends_on: - - mongodb - - mysql - + mongodb: + condition: service_healthy + mysql: + condition: service_started mysql: container_name: mysql image: mysql:8.0 @@ -29,3 +30,8 @@ services: image: mongo:latest ports: - "27017:27017" + healthcheck: + test: echo 'db.runCommand("ping").ok' | mongosh mongodb:27017 --quiet + interval: 10s + timeout: 10s + retries: 5 From a091681827953879c75f06a4485f8184bdb6375e Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 12:16:26 +0300 Subject: [PATCH 03/21] update docker --- .github/workflows/build-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index dac1aab2f..e697ed076 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -2,9 +2,10 @@ name: CI on: push: - branches: + branches: [ "master" ] tags: pull_request: + branches: [ "master" ] jobs: php-cs-fixer: From 9430d08a0d95268cca4e56176f843e82dded11b0 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 12:42:34 +0300 Subject: [PATCH 04/21] remove mongo db < 5 support --- .github/workflows/build-ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index e697ed076..7a1e69457 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -37,9 +37,6 @@ jobs: os: - ubuntu-latest mongodb: - - '4.0' - - '4.2' - - '4.4' - '5.0' - '6.0' - '7.0' From 77dc9be897ad83676209d60fe98475d72a2752d7 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 13:00:51 +0300 Subject: [PATCH 05/21] replace mongod with mongosh --- .github/workflows/build-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 7a1e69457..21973b84e 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -3,7 +3,6 @@ name: CI on: push: branches: [ "master" ] - tags: pull_request: branches: [ "master" ] @@ -57,7 +56,7 @@ jobs: - uses: actions/checkout@v3 - name: Create MongoDB Replica Set run: | - docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongosh --replSet rs --setParameter transactionLifetimeLimitSeconds=5 until docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done From 80527f5cbf58b27ef1c84690b5cb6b4eea0c31f6 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 13:41:02 +0300 Subject: [PATCH 06/21] replace mongod with mongosh --- .github/workflows/build-ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 21973b84e..e5fe411b9 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -30,6 +30,7 @@ jobs: build: runs-on: ${{ matrix.os }} + timeout-minutes: 10 name: PHP v${{ matrix.php }} with MongoDB ${{ matrix.mongodb }} strategy: matrix: @@ -57,13 +58,13 @@ jobs: - name: Create MongoDB Replica Set run: | docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongosh --replSet rs --setParameter transactionLifetimeLimitSeconds=5 - until docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done - sudo docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + sudo docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" - name: Show MongoDB server status run: | - docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ serverStatus: 1 })" + docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ serverStatus: 1 })" - name: "Installing php" uses: shivammathur/setup-php@v2 with: From e4fbb8d962514693747fc7075369b260500c0a47 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 13:46:57 +0300 Subject: [PATCH 07/21] replace mongod with mongosh --- .github/workflows/build-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index e5fe411b9..3bdf8ef5d 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v3 - name: Create MongoDB Replica Set run: | - docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongosh --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest mongo:${{ matrix.mongodb }} mongosh --replSet rs --setParameter transactionLifetimeLimitSeconds=5 until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done From 87b6453f167683f2ea8e4e5ecd28b1a2cbeaeb7d Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 14:55:57 +0300 Subject: [PATCH 08/21] replace mongod with mongosh --- .github/workflows/build-ci.yml | 2 +- .gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 3bdf8ef5d..feb17323f 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v3 - name: Create MongoDB Replica Set run: | - docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest mongo:${{ matrix.mongodb }} mongosh --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done diff --git a/.gitignore b/.gitignore index 8a586f33b..b1d2281bb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ composer.lock composer.phar phpunit.phar phpunit.xml +test.sh From 0a73a11212955faa68e0a0e6b9d7c9d1ac710eec Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 15:28:40 +0300 Subject: [PATCH 09/21] detach --- .github/workflows/build-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index feb17323f..cc013949b 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@v3 - name: Create MongoDB Replica Set run: | - docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done From 5385aa445f9a332799e5292935b4738fe5b182ff Mon Sep 17 00:00:00 2001 From: shamaseen Date: Sun, 20 Aug 2023 15:43:21 +0300 Subject: [PATCH 10/21] remove mongo version 7 support as it is so new and yield to some errors --- .github/workflows/build-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index cc013949b..e1af62ae0 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -39,7 +39,6 @@ jobs: mongodb: - '5.0' - '6.0' - - '7.0' php: - '8.1' - '8.2' From 21fac7de01cd5d4572954f7e9030827ee97701bb Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 15:32:32 +0300 Subject: [PATCH 11/21] BelongsToMany relation now can't use the same relation name as column name --- src/Eloquent/Model.php | 77 ++++++++++++++++++++++++----------- tests/HybridRelationsTest.php | 12 ++++++ tests/ModelTest.php | 7 ++++ tests/RelationsTest.php | 4 +- tests/models/Group.php | 2 +- tests/models/MysqlGroup.php | 48 ++++++++++++++++++++++ tests/models/MysqlUser.php | 11 ++++- tests/models/User.php | 25 +++++++++--- 8 files changed, 151 insertions(+), 35 deletions(-) create mode 100644 tests/models/MysqlGroup.php diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index b5a210658..4c21f655c 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -2,6 +2,11 @@ namespace Jenssegers\Mongodb\Eloquent; +use Jenssegers\Mongodb\Relations\EmbedsMany; +use Jenssegers\Mongodb\Relations\EmbedsOne; +use ReflectionException; +use ReflectionMethod; +use ReflectionNamedType; use function array_key_exists; use DateTimeInterface; use function explode; @@ -24,6 +29,8 @@ abstract class Model extends BaseModel { use HybridRelations, EmbedsRelations; + public static array $embeddedCache = []; + /** * The collection associated with the model. * @@ -148,28 +155,50 @@ public function getTable() /** * @inheritdoc */ -// public function getAttribute($key) -// { -// if (! $key) { -// return; -// } -// -// // Dot notation support. -// if (Str::contains($key, '.') && Arr::has($this->attributes, $key)) { -// return $this->getAttributeValue($key); -// } -// -// // This checks for embedded relation support. -// if ( -// method_exists($this, $key) -// && ! method_exists(self::class, $key) -// && ! $this->hasAttributeGetMutator($key) -// ) { -// return $this->getRelationValue($key); -// } -// -// return parent::getAttribute($key); -// } + public function getAttribute($key) + { + if (! $key) { + return; + } + + // Dot notation support. + if (Str::contains($key, '.') && Arr::has($this->attributes, $key)) { + return $this->getAttributeValue($key); + } + + // This checks for embedded relation support. + if ( + $this->hasEmbeddedRelation($key) + ) { + return $this->getRelationValue($key); + } + + return parent::getAttribute($key); + } + + /** + * Determine if an attribute is an embedded relation. + * + * @param string $key + * @return bool + * @throws ReflectionException + */ + public function hasEmbeddedRelation(string $key): bool + { + if (! method_exists($this, $method = Str::camel($key))) { + return false; + } + + if (isset(static::$embeddedCache[get_class($this)][$key])) { + return static::$embeddedCache[get_class($this)][$key]; + } + + $returnType = (new ReflectionMethod($this, $method))->getReturnType(); + + return $returnType && static::$embeddedCache[get_class($this)][$key] = + $returnType instanceof ReflectionNamedType && + $returnType->getName() === EmbedsOne::class || $returnType->getName() === EmbedsMany::class; + } /** * @inheritdoc @@ -401,7 +430,7 @@ public function getForeignKey() /** * Set the parent relation. * - * @param \Illuminate\Database\Eloquent\Relations\Relation $relation + * @param Relation $relation */ public function setParentRelation(Relation $relation) { @@ -411,7 +440,7 @@ public function setParentRelation(Relation $relation) /** * Get the parent relation. * - * @return \Illuminate\Database\Eloquent\Relations\Relation + * @return Relation */ public function getParentRelation() { diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 7b4e7cdad..0c401ae35 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -13,6 +13,7 @@ public function setUp(): void MysqlUser::executeSchema(); MysqlBook::executeSchema(); MysqlRole::executeSchema(); +// MysqlGroup::executeSchema(); } public function tearDown(): void @@ -20,8 +21,19 @@ public function tearDown(): void MysqlUser::truncate(); MysqlBook::truncate(); MysqlRole::truncate(); +// MysqlGroup::truncate(); } +// public function testMysqlGroups() +// { +// $user = new MysqlUser; +// $user->name = 'John Doe'; +// $user->save(); +// $this->assertIsInt($user->id); +// +// $group = $user->groups()->create(['name' => 'test']); +// } + public function testMysqlRelations() { $user = new MysqlUser; diff --git a/tests/ModelTest.php b/tests/ModelTest.php index e4eeefbb4..a24d27ce9 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -801,4 +801,11 @@ public function testEnumCast(): void $this->assertSame(MemberStatus::Member->value, $check->getRawOriginal('member_status')); $this->assertSame(MemberStatus::Member, $check->member_status); } + + public function testGetFooAttributeAccessor() + { + $user = new User(); + + $this->assertSame('normal attribute', $user->foo); + } } diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index b1b73e6cc..15be46fa9 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -334,8 +334,8 @@ public function testBelongsToManyCustom(): void $group = Group::find($group->_id); // Check for custom relation attributes - $this->assertArrayHasKey('users', $group->getAttributes()); - $this->assertArrayHasKey('groups', $user->getAttributes()); + $this->assertArrayHasKey('user_ids', $group->getAttributes()); + $this->assertArrayHasKey('group_ids', $user->getAttributes()); // Assert they are attached $this->assertContains($group->_id, $user->groups->pluck('_id')->toArray()); diff --git a/tests/models/Group.php b/tests/models/Group.php index bf4edd9bc..7b005703a 100644 --- a/tests/models/Group.php +++ b/tests/models/Group.php @@ -13,6 +13,6 @@ class Group extends Eloquent public function users(): BelongsToMany { - return $this->belongsToMany('User', 'users', 'groups', 'users', '_id', '_id', 'users'); + return $this->belongsToMany('User'); } } diff --git a/tests/models/MysqlGroup.php b/tests/models/MysqlGroup.php new file mode 100644 index 000000000..d56a60a64 --- /dev/null +++ b/tests/models/MysqlGroup.php @@ -0,0 +1,48 @@ +belongsToMany(MysqlUser::class); + } + + /** + * Check if we need to run the schema. + */ + public static function executeSchema(): void + { + /** @var MySqlBuilder $schema */ + $schema = Schema::connection('mysql'); + + if (!$schema->hasTable('groups')) { + Schema::connection('mysql')->create('groups', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->timestamps(); + }); + } + + if (!$schema->hasTable('group_user')) { + Schema::connection('mysql')->create('group_user', function (Blueprint $table) { + $table->foreignId('user_id')->constrained('users')->cascadeOnUpdate()->cascadeOnDelete(); + $table->foreignId('group_id')->constrained('groups')->cascadeOnUpdate()->cascadeOnDelete(); + }); + } + } +} diff --git a/tests/models/MysqlUser.php b/tests/models/MysqlUser.php index 8c1393fd5..ddd2142ad 100644 --- a/tests/models/MysqlUser.php +++ b/tests/models/MysqlUser.php @@ -2,9 +2,11 @@ declare(strict_types=1); +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\MySqlBuilder; use Illuminate\Support\Facades\Schema; use Jenssegers\Mongodb\Eloquent\HybridRelations; @@ -31,17 +33,22 @@ public function mysqlBooks(): HasMany return $this->hasMany(MysqlBook::class); } + public function groups(): BelongsToMany + { + return $this->belongsToMany(MysqlGroup::class, 'group_user', 'user_id', 'group_id'); + } + /** * Check if we need to run the schema. */ public static function executeSchema(): void { - /** @var \Illuminate\Database\Schema\MySqlBuilder $schema */ + /** @var MySqlBuilder $schema */ $schema = Schema::connection('mysql'); if (! $schema->hasTable('users')) { Schema::connection('mysql')->create('users', function (Blueprint $table) { - $table->increments('id'); + $table->id(); $table->string('name'); $table->timestamps(); }); diff --git a/tests/models/User.php b/tests/models/User.php index d32d1f8b4..430e5a06a 100644 --- a/tests/models/User.php +++ b/tests/models/User.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Carbon\Carbon; use Illuminate\Auth\Authenticatable; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; @@ -11,6 +12,8 @@ use Illuminate\Support\Str; use Jenssegers\Mongodb\Eloquent\HybridRelations; use Jenssegers\Mongodb\Eloquent\Model as Eloquent; +use Jenssegers\Mongodb\Relations\EmbedsMany; +use Jenssegers\Mongodb\Relations\EmbedsOne; /** * Class User. @@ -20,9 +23,9 @@ * @property string $email * @property string $title * @property int $age - * @property \Carbon\Carbon $birthday - * @property \Carbon\Carbon $created_at - * @property \Carbon\Carbon $updated_at + * @property Carbon $birthday + * @property Carbon $created_at + * @property Carbon $updated_at * @property string $username * @property MemberStatus member_status */ @@ -73,7 +76,7 @@ public function clients() public function groups() { - return $this->belongsToMany('Group', 'groups', 'users', 'groups', '_id', '_id', 'groups'); + return $this->belongsToMany('Group'); } public function photos() @@ -81,12 +84,12 @@ public function photos() return $this->morphMany('Photo', 'has_image'); } - public function addresses() + public function addresses(): EmbedsMany { return $this->embedsMany('Address'); } - public function father() + public function father(): EmbedsOne { return $this->embedsOne('User'); } @@ -103,4 +106,14 @@ protected function username(): Attribute set: fn ($value) => Str::slug($value) ); } + + public function getFooAttribute() + { + return 'normal attribute'; + } + + public function foo() + { + return 'normal function'; + } } From d0666b63b79eb4114a4cf1400ea7e1266ee4b5cd Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 16:08:12 +0300 Subject: [PATCH 12/21] update documentation --- .github/FUNDING.yml | 2 -- CHANGELOG.md | 21 ++++++++++++++++++++- README.md | 14 +++++++++++--- src/Eloquent/Model.php | 10 +++++----- tests/models/MysqlGroup.php | 4 ++-- 5 files changed, 38 insertions(+), 13 deletions(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 6136cca0a..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: jenssegers -tidelift: "packagist/jenssegers/mongodb" diff --git a/CHANGELOG.md b/CHANGELOG.md index b1018c1cb..d7088af6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,29 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +None yet. + +## [10.0] - 2023-08-22 + +### Added +- MongoDB v6.0 supports and tests +- use Mongosh in tests instead of the old Mongo +- Mysql 8 Hybrid relation tests + +### Removed +- MongoDB v4.* support was dropped + +### Fixed +- Fixing the priority between attributes and relations dynamic property call to be the same as Laravel, that mean attribute first then relation (previous it was relation then attribute) +- using function names that exist as attribute accessor/caster: previously if you use a function name that has an accessor; say u use foo() and you have getFooAttribute, calling $model->foo will always fail as the function is called before the accessor, this has been fixed. + +### Breaking +- EmbedsOne and EmbedsMany now require return type to work (Example in the documentation has been updated) +- You can't have the belongsToMany foreign key to be the same as the relation name (check documentation for more details) ## [3.9.2] - 2022-09-01 -### Addded +### Addded - Add single word name mutators [#2438](https://github.com/jenssegers/laravel-mongodb/pull/2438) by [@RosemaryOrchard](https://github.com/RosemaryOrchard) & [@mrneatly](https://github.com/mrneatly). ### Fixed diff --git a/README.md b/README.md index 6a6752575..0d2926e34 100644 --- a/README.md +++ b/README.md @@ -839,6 +839,7 @@ class User extends Model } } ``` +**Warning:** naming the foreign key same as the relation name will prevent the relation for being called on dynamic property, i.e. in the example above if you replaced `group_ids` with `groups` calling `$user->groups` will return the column instead of the relation. ### EmbedsMany Relationship @@ -846,12 +847,15 @@ If you want to embed models, rather than referencing them, you can use the `embe **REMEMBER**: These relations return Eloquent collections, they don't return query builder objects! +**Breaking changes** starting from v10.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work + ```php use Jenssegers\Mongodb\Eloquent\Model; +use Jenssegers\Mongodb\Relations\EmbedsMany; class User extends Model { - public function books() + public function books(): EmbedsMany { return $this->embedsMany(Book::class); } @@ -920,10 +924,11 @@ Like other relations, embedsMany assumes the local key of the relationship based ```php use Jenssegers\Mongodb\Eloquent\Model; +use Jenssegers\Mongodb\Relations\EmbedsMany; class User extends Model { - public function books() + public function books(): EmbedsMany { return $this->embedsMany(Book::class, 'local_key'); } @@ -936,12 +941,15 @@ Embedded relations will return a Collection of embedded items instead of a query The embedsOne relation is similar to the embedsMany relation, but only embeds a single model. +**Breaking changes** starting from v10.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work + ```php use Jenssegers\Mongodb\Eloquent\Model; +use Jenssegers\Mongodb\Relations\EmbedsOne; class Book extends Model { - public function author() + public function author(): EmbedsOne { return $this->embedsOne(Author::class); } diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 4c21f655c..08d810df2 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -2,11 +2,6 @@ namespace Jenssegers\Mongodb\Eloquent; -use Jenssegers\Mongodb\Relations\EmbedsMany; -use Jenssegers\Mongodb\Relations\EmbedsOne; -use ReflectionException; -use ReflectionMethod; -use ReflectionNamedType; use function array_key_exists; use DateTimeInterface; use function explode; @@ -20,9 +15,14 @@ use Illuminate\Support\Str; use function in_array; use Jenssegers\Mongodb\Query\Builder as QueryBuilder; +use Jenssegers\Mongodb\Relations\EmbedsMany; +use Jenssegers\Mongodb\Relations\EmbedsOne; use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectID; use MongoDB\BSON\UTCDateTime; +use ReflectionException; +use ReflectionMethod; +use ReflectionNamedType; use function uniqid; abstract class Model extends BaseModel diff --git a/tests/models/MysqlGroup.php b/tests/models/MysqlGroup.php index d56a60a64..5efd20e47 100644 --- a/tests/models/MysqlGroup.php +++ b/tests/models/MysqlGroup.php @@ -30,7 +30,7 @@ public static function executeSchema(): void /** @var MySqlBuilder $schema */ $schema = Schema::connection('mysql'); - if (!$schema->hasTable('groups')) { + if (! $schema->hasTable('groups')) { Schema::connection('mysql')->create('groups', function (Blueprint $table) { $table->id(); $table->string('name'); @@ -38,7 +38,7 @@ public static function executeSchema(): void }); } - if (!$schema->hasTable('group_user')) { + if (! $schema->hasTable('group_user')) { Schema::connection('mysql')->create('group_user', function (Blueprint $table) { $table->foreignId('user_id')->constrained('users')->cascadeOnUpdate()->cascadeOnDelete(); $table->foreignId('group_id')->constrained('groups')->cascadeOnUpdate()->cascadeOnDelete(); From 61842f5c2df5e57e6068c4919df0210c20ab60c0 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 17:09:11 +0300 Subject: [PATCH 13/21] update readme --- README.md | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6a6752575..d322da784 100644 --- a/README.md +++ b/README.md @@ -60,21 +60,12 @@ Make sure you have the MongoDB PHP driver installed. You can find installation i ### Laravel version Compatibility | Laravel | Package | Maintained | -| :------ | :------------- | :----------------- | +|:--------|:---------------|:-------------------| +| 10.x | 10.x | :white_check_mark: | | 9.x | 3.9.x | :white_check_mark: | -| 8.x | 3.8.x | :white_check_mark: | +| 8.x | 3.8.x | :x: | | 7.x | 3.7.x | :x: | | 6.x | 3.6.x | :x: | -| 5.8.x | 3.5.x | :x: | -| 5.7.x | 3.4.x | :x: | -| 5.6.x | 3.4.x | :x: | -| 5.5.x | 3.3.x | :x: | -| 5.4.x | 3.2.x | :x: | -| 5.3.x | 3.1.x or 3.2.x | :x: | -| 5.2.x | 2.3.x or 3.0.x | :x: | -| 5.1.x | 2.2.x or 3.0.x | :x: | -| 5.0.x | 2.1.x | :x: | -| 4.2.x | 2.0.x | :x: | Install the package via Composer: From f18bf7889ac0c4ac25775af95771702ce6b8296e Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 17:18:12 +0300 Subject: [PATCH 14/21] change package name for it to work with packagist --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b2dba6529..98b972e11 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "jenssegers/mongodb", + "name": "mshamaseen/mongodb", "description": "A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)", "keywords": [ "laravel", From c0e1ee36d6cbdc27955543f19c3c23f8b62af4ea Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 17:20:31 +0300 Subject: [PATCH 15/21] change package name for it to work with packagist --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 98b972e11..d1143d905 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "mshamaseen/mongodb", + "name": "mshamaseen/laravel-mongodb", "description": "A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)", "keywords": [ "laravel", From 7a1fb9803b24b951699cffeae56e6f02c54116cf Mon Sep 17 00:00:00 2001 From: shamaseen Date: Mon, 21 Aug 2023 17:23:54 +0300 Subject: [PATCH 16/21] add packagist using new package name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9ec85ba9..977528d4e 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Make sure you have the MongoDB PHP driver installed. You can find installation i Install the package via Composer: ```bash -$ composer require jenssegers/mongodb +$ composer require mshamaseen/laravel-mongodb ``` ### Laravel From 815f37e83d50dc5c5a5a8af85fcec6b58a66df3b Mon Sep 17 00:00:00 2001 From: shamaseen Date: Wed, 23 Aug 2023 00:59:50 +0300 Subject: [PATCH 17/21] prepare for mering with upstream --- .github/workflows/build-ci.yml | 5 ++--- .gitignore | 1 - README.md | 21 +++++++++++++++------ composer.json | 2 +- tests/HybridRelationsTest.php | 12 ------------ tests/Models/MysqlGroup.php | 0 6 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 tests/Models/MysqlGroup.php diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index e1af62ae0..9566bbe8a 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ "master" ] + branches: + tags: pull_request: - branches: [ "master" ] jobs: php-cs-fixer: @@ -30,7 +30,6 @@ jobs: build: runs-on: ${{ matrix.os }} - timeout-minutes: 10 name: PHP v${{ matrix.php }} with MongoDB ${{ matrix.mongodb }} strategy: matrix: diff --git a/.gitignore b/.gitignore index b1d2281bb..8a586f33b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,3 @@ composer.lock composer.phar phpunit.phar phpunit.xml -test.sh diff --git a/README.md b/README.md index 702cb7060..f53dfa6b1 100644 --- a/README.md +++ b/README.md @@ -60,17 +60,26 @@ Make sure you have the MongoDB PHP driver installed. You can find installation i ### Laravel version Compatibility | Laravel | Package | Maintained | -|:--------|:---------------|:-------------------| -| 10.x | 10.x | :white_check_mark: | +| :------ | :------------- | :----------------- | | 9.x | 3.9.x | :white_check_mark: | -| 8.x | 3.8.x | :x: | +| 8.x | 3.8.x | :white_check_mark: | | 7.x | 3.7.x | :x: | | 6.x | 3.6.x | :x: | +| 5.8.x | 3.5.x | :x: | +| 5.7.x | 3.4.x | :x: | +| 5.6.x | 3.4.x | :x: | +| 5.5.x | 3.3.x | :x: | +| 5.4.x | 3.2.x | :x: | +| 5.3.x | 3.1.x or 3.2.x | :x: | +| 5.2.x | 2.3.x or 3.0.x | :x: | +| 5.1.x | 2.2.x or 3.0.x | :x: | +| 5.0.x | 2.1.x | :x: | +| 4.2.x | 2.0.x | :x: | Install the package via Composer: ```bash -$ composer require mshamaseen/laravel-mongodb +$ composer require jenssegers/mongodb ``` ### Laravel @@ -855,7 +864,7 @@ If you want to embed models, rather than referencing them, you can use the `embe **REMEMBER**: These relations return Eloquent collections, they don't return query builder objects! -**Breaking changes** starting from v10.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work +**Breaking changes** starting from v4.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work ```php use Jenssegers\Mongodb\Eloquent\Model; @@ -949,7 +958,7 @@ Embedded relations will return a Collection of embedded items instead of a query The embedsOne relation is similar to the embedsMany relation, but only embeds a single model. -**Breaking changes** starting from v10.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work +**Breaking changes** starting from v4.0 you need to define the return type of EmbedsOne and EmbedsMany relation for it to work ```php use Jenssegers\Mongodb\Eloquent\Model; diff --git a/composer.json b/composer.json index 833454469..c628175f8 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "mshamaseen/laravel-mongodb", + "name": "jenssegers/mongodb", "description": "A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)", "keywords": [ "laravel", diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index f22957358..aa3a402b7 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -31,7 +31,6 @@ public function setUp(): void MysqlUser::executeSchema(); MysqlBook::executeSchema(); MysqlRole::executeSchema(); -// MysqlGroup::executeSchema(); } public function tearDown(): void @@ -39,19 +38,8 @@ public function tearDown(): void MysqlUser::truncate(); MysqlBook::truncate(); MysqlRole::truncate(); -// MysqlGroup::truncate(); } -// public function testMysqlGroups() -// { -// $user = new MysqlUser; -// $user->name = 'John Doe'; -// $user->save(); -// $this->assertIsInt($user->id); -// -// $group = $user->groups()->create(['name' => 'test']); -// } - public function testMysqlRelations() { $user = new MysqlUser; diff --git a/tests/Models/MysqlGroup.php b/tests/Models/MysqlGroup.php deleted file mode 100644 index e69de29bb..000000000 From 21a46e1dcd2aa11e1de30bb58f7768349a14b806 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Wed, 23 Aug 2023 01:34:07 +0300 Subject: [PATCH 18/21] return FUNDING.yml --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..6136cca0a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: jenssegers +tidelift: "packagist/jenssegers/mongodb" From cc1631eb7d350596b62587769f4809b262b5401a Mon Sep 17 00:00:00 2001 From: shamaseen Date: Thu, 24 Aug 2023 15:02:18 +0300 Subject: [PATCH 19/21] fix php cs fixer --- tests/Models/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Models/User.php b/tests/Models/User.php index faf44bc3d..36d6d19ff 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -4,8 +4,8 @@ namespace Jenssegers\Mongodb\Tests\Models; -use DateTimeInterface; use Carbon\Carbon; +use DateTimeInterface; use Illuminate\Auth\Authenticatable; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; From ed45cf73d646124a4004dcef7313cea205f4b438 Mon Sep 17 00:00:00 2001 From: shamaseen Date: Thu, 24 Aug 2023 15:14:02 +0300 Subject: [PATCH 20/21] revision updates --- src/Eloquent/Model.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 6dc2c6e7d..9fc8f0b2b 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -154,6 +154,7 @@ public function getTable() /** * @inheritdoc + * @throws ReflectionException */ public function getAttribute($key) { @@ -183,7 +184,7 @@ public function getAttribute($key) * @return bool * @throws ReflectionException */ - public function hasEmbeddedRelation(string $key): bool + private function hasEmbeddedRelation(string $key): bool { if (! method_exists($this, $method = Str::camel($key))) { return false; @@ -195,7 +196,7 @@ public function hasEmbeddedRelation(string $key): bool $returnType = (new ReflectionMethod($this, $method))->getReturnType(); - return $returnType && static::$embeddedCache[get_class($this)][$key] = + return $returnType && static::$embeddedCache[static::class][$key] = $returnType instanceof ReflectionNamedType && $returnType->getName() === EmbedsOne::class || $returnType->getName() === EmbedsMany::class; } From e3330aee4835f78c684bd6a5fd63657bd097062d Mon Sep 17 00:00:00 2001 From: shamaseen Date: Thu, 24 Aug 2023 23:13:09 +0300 Subject: [PATCH 21/21] revert extra --- .github/workflows/build-ci.yml | 12 +++++++----- Dockerfile | 9 ++++++--- docker-compose.yml | 14 ++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 9566bbe8a..c3e22c23f 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -36,14 +36,16 @@ jobs: os: - ubuntu-latest mongodb: + - '4.0' + - '4.2' + - '4.4' - '5.0' - - '6.0' php: - '8.1' - '8.2' services: mysql: - image: mysql:8.0 + image: mysql:5.7 ports: - 3307:3306 env: @@ -56,13 +58,13 @@ jobs: - name: Create MongoDB Replica Set run: | docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${{ matrix.mongodb }} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 - until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + until docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done - sudo docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + sudo docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" - name: Show MongoDB server status run: | - docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ serverStatus: 1 })" + docker exec --tty mongodb mongo 127.0.0.1:27017 --eval "db.runCommand({ serverStatus: 1 })" - name: "Installing php" uses: shivammathur/setup-php@v2 with: diff --git a/Dockerfile b/Dockerfile index a40ab72c6..bd7e03a14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG PHP_VERSION=8.1 - +ARG COMPOSER_VERSION=2.5.4 FROM php:${PHP_VERSION}-cli @@ -9,11 +9,14 @@ RUN apt-get update && \ pecl install xdebug && docker-php-ext-enable xdebug && \ docker-php-ext-install -j$(nproc) pdo_mysql zip -# Copy the Composer binary from the specified stage -COPY --from=composer:2.5.4 /usr/bin/composer /usr/local/bin/composer +COPY --from=composer:${COMPOSER_VERSION} /usr/bin/composer /usr/local/bin/composer WORKDIR /code +COPY composer.* ./ + +RUN composer install + COPY ./ ./ RUN composer install diff --git a/docker-compose.yml b/docker-compose.yml index 8f242a2f9..dab907abe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3.5' +version: '3' services: tests: @@ -11,10 +11,9 @@ services: - .:/code working_dir: /code depends_on: - mongodb: - condition: service_healthy - mysql: - condition: service_started + - mongodb + - mysql + mysql: container_name: mysql image: mysql:8.0 @@ -30,8 +29,3 @@ services: image: mongo:latest ports: - "27017:27017" - healthcheck: - test: echo 'db.runCommand("ping").ok' | mongosh mongodb:27017 --quiet - interval: 10s - timeout: 10s - retries: 5