From f09ec5e7fdec082f79af30f2db9df4423ad267c0 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Tue, 30 Jul 2019 21:27:12 +0100 Subject: [PATCH 1/8] Docker Composer Windows Compat (cherry picked from commit d12bf6e54c248e302b1a6505fd8488f93c1c05fa) --- docker-compose.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..1626c4fb4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +version: '3' + +services: + tests: + container_name: tests + build: + context: . + dockerfile: Dockerfile + volumes: + - ./:/code + working_dir: /code + depends_on: + - mongodb + - mysql + + mysql: + container_name: mysql + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: + MYSQL_DATABASE: unittest + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + logging: + driver: none + + mongodb: + container_name: mongodb + image: mongo + ports: + - 27017:27017 + logging: + driver: none From f6cad4136f8886cb809fa88d4d913d35dc13b63f Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Tue, 30 Jul 2019 22:06:43 +0100 Subject: [PATCH 2/8] Added Attrs test (cherry picked from commit 7cb8fea3bba6d70d0944cdaad2407c6932118de7) --- tests/RelationsTest.php | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index 02449fcc3..e3306abde 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -277,6 +277,35 @@ public function testBelongsToManySync() $this->assertCount(1, $user->clients); } + public function testBelongsToManySyncAttrs() + { + // create test instances + /** @var User $user */ + $user = User::create(['name' => 'John Doe']); + $client1 = Client::create(['name' => 'Pork Pies Ltd.'])->_id; + $client2 = Client::create(['name' => 'Buffet Bar Inc.'])->_id; + + // Sync multiple + $user->clients()->sync([$client1 => ['fresh_client' => true], $client2 => ['fresh_client' => false]]); + + //Check Sync Success + $this->assertEquals($user->client_ids[0]['_id'], $client1); + $this->assertEquals($user->client_ids[1]['_id'], $client2); + + //Check reverse + $this->assertEquals($user->_id, Client::find($client1)->user_ids[0]['_id']); + $this->assertEquals($user->_id, Client::find($client2)->user_ids[0]['_id']); + + $clients = $user->clients; + $this->assertCount(2, $clients); + + foreach ($user->clients()->withPivot('fresh_client')->get() as $item) { + $this->assertIsArray($item->pivot->toArray()); + $this->assertEquals($item->_id == $client1, $item->pivot->fresh_client); + } + $this->assertTrue(true); + } + public function testBelongsToManyAttachArray() { $user = User::create(['name' => 'John Doe']); @@ -354,7 +383,7 @@ public function testMorph() $this->assertEquals($photo->imageable->name, $user->name); $user = User::with('photos')->find($user->_id); - $relations = $user->getRelations(); + $relations = $user->getRlations(); $this->assertTrue(array_key_exists('photos', $relations)); $this->assertEquals(1, $relations['photos']->count()); From fc6461026decde038edef7be3ae7e6fe171d6218 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Tue, 30 Jul 2019 22:07:08 +0100 Subject: [PATCH 3/8] Added Attrs Implementation (cherry picked from commit 4cabe86b0ce99c828855bd4117532a0dd2ff28f7) --- .../Mongodb/Relations/BelongsToMany.php | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/Jenssegers/Mongodb/Relations/BelongsToMany.php b/src/Jenssegers/Mongodb/Relations/BelongsToMany.php index 1b806a020..4a7c59072 100644 --- a/src/Jenssegers/Mongodb/Relations/BelongsToMany.php +++ b/src/Jenssegers/Mongodb/Relations/BelongsToMany.php @@ -2,9 +2,12 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\Model as EloquentModel; use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany; +use Illuminate\Support\Arr; -class BelongsToMany extends EloquentBelongsToMany { +class BelongsToMany extends EloquentBelongsToMany +{ /** * Hydrate the pivot table relationship on the models. @@ -14,7 +17,12 @@ class BelongsToMany extends EloquentBelongsToMany { */ protected function hydratePivotRelation(array $models) { - // Do nothing + foreach ($models as $model) { + $keyToUse = $this->getTable() == $model->getTable() ? $this->getForeignKey() : $this->getRelatedKey(); + $pcontent = $model->{$keyToUse}; + $model->setRelation($this->accessor, $this->newExistingPivot( + $pcontent[0] + )); } /** @@ -99,8 +107,16 @@ public function sync($ids, $detaching = true) // if they exist in the array of current ones, and if not we will insert. $current = $this->parent->{$this->otherKey} ?: []; - // See issue #256. - if ($current instanceof Collection) $current = $ids->modelKeys(); + // See issue #256. + if ($current instanceof Collection) { + $current = $ids->modelKeys(); + } elseif (is_array($current)) { + foreach ($current as $key => $value) { + if ($value['_id']) { + $current[$key] = $value['_id']; + } + } + } $records = $this->formatSyncList($ids); @@ -170,7 +186,7 @@ public function attach($id, array $attributes = [], $touch = true) if (isset($model)) { // Attach the new ids to the related model. - $model->push($this->foreignKey, $this->parent->getKey(), true); + $model->push($this->foreignKey, array_merge($attributes, ['_id' => $this->parent->getKey()]), true); } else { @@ -180,10 +196,21 @@ public function attach($id, array $attributes = [], $touch = true) $query->whereIn($this->related->getKeyName(), $ids); // Attach the new parent id to the related model. - $query->push($this->foreignKey, $this->parent->getKey(), true); + $query->push($this->foreignKey, array_merge($attributes, ['_id' => $this->parent->getKey()]), true); } - if ($touch) $this->touchIfTouching(); + //Pivot Collection + $pivot_x = []; + foreach ((array)$id as $item) { + $pivot_x[] = array_merge($attributes, ['_id' => $item]); + } + + // Attach the new ids to the parent model. + $this->parent->push($this->getRelatedKey(), $pivot_x, true); + + if ($touch) { + $this->touchIfTouching(); + } } /** @@ -205,7 +232,7 @@ public function detach($ids = [], $touch = true) $ids = (array) $ids; // Detach all ids from the parent model. - $this->parent->pull($this->otherKey, $ids); + $this->parent->pull($this->otherKey, ['_id'=>$ids]); // Prepare the query to select all related objects. if (count($ids) > 0) @@ -214,7 +241,7 @@ public function detach($ids = [], $touch = true) } // Remove the relation to the parent. - $query->pull($this->foreignKey, $this->parent->getKey()); + $query->pull($this->foreignKey, ['_id'=>$this->parent->getKey()]); if ($touch) $this->touchIfTouching(); From 7ccbc1cd29951a5bcf4eee9677c1081ebbf8e916 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Wed, 31 Jul 2019 13:49:40 +0100 Subject: [PATCH 4/8] Syncing (cherry picked from commit 8e57b37fe2e488fd3669942fee7ac6ffc99c79b3) --- .../Mongodb/Relations/BelongsTo.php | 35 ++++++++++++++++++- .../Mongodb/Relations/BelongsToMany.php | 23 +++++++----- src/Jenssegers/Mongodb/Relations/HasMany.php | 8 +++-- tests/RelationsTest.php | 17 ++++----- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/Jenssegers/Mongodb/Relations/BelongsTo.php b/src/Jenssegers/Mongodb/Relations/BelongsTo.php index 6cb924cb8..9da1739c8 100644 --- a/src/Jenssegers/Mongodb/Relations/BelongsTo.php +++ b/src/Jenssegers/Mongodb/Relations/BelongsTo.php @@ -1,5 +1,6 @@ query->where($this->otherKey, '=', $this->parent->{$this->foreignKey}); + $this->query + ->where($this->otherKey, '=', $this->parent->{$this->foreignKey}) + ->orWhere($this->getOwnerKey().'._id', '=', $this->parent->{$this->foreignKey}); } } @@ -36,4 +39,34 @@ public function addEagerConstraints(array $models) $this->query->whereIn($key, $this->getEagerModelKeys($models)); } + /** + * @inheritDoc + */ + public function match(array $models, Collection $results, $relation) + { + $foreign = $this->foreignKey; + + $owner = $this->ownerKey; + + // First we will get to build a dictionary of the child models by their primary + // key of the relationship, then we can easily match the children back onto + // the parents using that dictionary and the primary key of the children. + $dictionary = []; + + foreach ($results as $result) { + $dictionary[$result->getAttribute($owner)] = $result; + } + + // Once we have the dictionary constructed, we can loop through all the parents + // and match back onto their children using these keys of the dictionary and + // the primary key of the children to map them onto the correct instances. + foreach ($models as $model) { + if (isset($dictionary[(string)$model->{$foreign}])) { + $model->setRelation($relation, $dictionary[(string)$model->{$foreign}]); + } + } + + return $models; + } + } diff --git a/src/Jenssegers/Mongodb/Relations/BelongsToMany.php b/src/Jenssegers/Mongodb/Relations/BelongsToMany.php index 4a7c59072..d86d08070 100644 --- a/src/Jenssegers/Mongodb/Relations/BelongsToMany.php +++ b/src/Jenssegers/Mongodb/Relations/BelongsToMany.php @@ -23,6 +23,7 @@ protected function hydratePivotRelation(array $models) $model->setRelation($this->accessor, $this->newExistingPivot( $pcontent[0] )); + } } /** @@ -111,8 +112,9 @@ public function sync($ids, $detaching = true) if ($current instanceof Collection) { $current = $ids->modelKeys(); } elseif (is_array($current)) { + foreach ($current as $key => $value) { - if ($value['_id']) { + if (is_array($value) && $value['_id']) { $current[$key] = $value['_id']; } } @@ -186,17 +188,18 @@ public function attach($id, array $attributes = [], $touch = true) if (isset($model)) { // Attach the new ids to the related model. - $model->push($this->foreignKey, array_merge($attributes, ['_id' => $this->parent->getKey()]), true); + $model->push($this->foreignKey, [array_merge($attributes, ['_id' => $this->parent->getKey()])], true); } else { $query = $this->newRelatedQuery(); // Select related models. - $query->whereIn($this->related->getKeyName(), $ids); + $query->whereIn($this->related->getKeyName(), $ids) + ->orWhereIn($this->related->getKeyName().'._id', (array)$id); // Attach the new parent id to the related model. - $query->push($this->foreignKey, array_merge($attributes, ['_id' => $this->parent->getKey()]), true); + $query->push($this->foreignKey, [array_merge($attributes, ['_id' => $this->parent->getKey()])], true); } //Pivot Collection @@ -232,16 +235,20 @@ public function detach($ids = [], $touch = true) $ids = (array) $ids; // Detach all ids from the parent model. - $this->parent->pull($this->otherKey, ['_id'=>$ids]); + // Legacy Support + $this->parent->pull($this->getRelatedKey(), $ids); + $this->parent->pull($this->otherKey, ['_id'=>['$in'=>$ids]]); // Prepare the query to select all related objects. if (count($ids) > 0) { - $query->whereIn($this->related->getKeyName(), $ids); - } + $query->whereIn($this->related->getKeyName(), $ids) + ->orWhereIn($this->related->getKeyName().'._id', $ids); + } // Remove the relation to the parent. - $query->pull($this->foreignKey, ['_id'=>$this->parent->getKey()]); + $query->pull($this->foreignKey, $this->parent->getKey()); + $query->pull($this->foreignPivotKey, ['_id'=>$this->parent->getKey()]); if ($touch) $this->touchIfTouching(); diff --git a/src/Jenssegers/Mongodb/Relations/HasMany.php b/src/Jenssegers/Mongodb/Relations/HasMany.php index c59065639..399f1b98d 100644 --- a/src/Jenssegers/Mongodb/Relations/HasMany.php +++ b/src/Jenssegers/Mongodb/Relations/HasMany.php @@ -2,8 +2,10 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\HasMany as EloquentHasMany; +use Illuminate\Database\Eloquent\Model as EloquentModel; -class HasMany extends EloquentHasMany { +class HasMany extends EloquentHasMany +{ /** * Add the constraints for a relationship count query. @@ -16,7 +18,9 @@ public function getRelationCountQuery(Builder $query, Builder $parent) { $foreignKey = $this->getHasCompareKey(); - return $query->select($this->getHasCompareKey())->where($this->getHasCompareKey(), 'exists', true); + return $query->select($this->getHasCompareKey()) + ->where($this->getHasCompareKey(), 'exists', true) + ->orWhere($this->getHasCompareKey().'._id', 'exists', true); } /** diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index e3306abde..fc632f616 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -221,7 +221,7 @@ public function testBelongsToMany() public function testBelongsToManyAttachesExistingModels() { - $user = User::create(['name' => 'John Doe', 'client_ids' => ['1234523']]); + $user = User::create(['name' => 'John Doe', 'client_ids' => [['_id'=>'1234523']]]); $clients = [ Client::create(['name' => 'Pork Pies Ltd.'])->_id, @@ -236,7 +236,8 @@ public function testBelongsToManyAttachesExistingModels() // Sync multiple records $user->clients()->sync($clients); - $user = User::with('clients')->find($user->_id); +// $user = User::with('clients')->find($user->_id); + $user = User::find($user->_id); // Assert non attached ID's are detached succesfully $this->assertFalse(in_array('1234523', $user->client_ids)); @@ -531,21 +532,21 @@ public function testDoubleSaveManyToMany() $user->save(); $this->assertEquals(1, $user->clients()->count()); - $this->assertEquals([$user->_id], $client->user_ids); - $this->assertEquals([$client->_id], $user->client_ids); + $this->assertEquals([['_id' =>$user->_id]], $client->user_ids); + $this->assertEquals([['_id' => $client->_id]], $user->client_ids); $user = User::where('name', 'John Doe')->first(); $client = Client::where('name', 'Admins')->first(); $this->assertEquals(1, $user->clients()->count()); - $this->assertEquals([$user->_id], $client->user_ids); - $this->assertEquals([$client->_id], $user->client_ids); + $this->assertEquals([['_id' =>$user->_id]], $client->user_ids); + $this->assertEquals([['_id' => $client->_id]], $user->client_ids); $user->clients()->save($client); $user->clients()->save($client); $user->save(); $this->assertEquals(1, $user->clients()->count()); - $this->assertEquals([$user->_id], $client->user_ids); - $this->assertEquals([$client->_id], $user->client_ids); + $this->assertEquals([['_id' =>$user->_id]], $client->user_ids); + $this->assertEquals([['_id' => $client->_id]], $user->client_ids); } } From 3d933efe7f76a374464ca30a829189473cc988d9 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Wed, 31 Jul 2019 14:53:37 +0100 Subject: [PATCH 5/8] Added Dockerfile for Testing --- Dockerfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..41e755c8d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +ARG PHP_VERSION=7.1 +ARG COMPOSER_VERSION=1.8 + +FROM composer:${COMPOSER_VERSION} +FROM php:${PHP_VERSION}-cli + +RUN apt-get update && \ + apt-get install -y autoconf pkg-config libssl-dev git libzip-dev zlib1g-dev && \ + pecl install mongodb && docker-php-ext-enable mongodb && \ + pecl install xdebug && docker-php-ext-enable xdebug && \ + docker-php-ext-install -j$(nproc) pdo_mysql zip + +COPY --from=composer /usr/bin/composer /usr/local/bin/composer + +WORKDIR /code \ No newline at end of file From 64c594748cf55cda50e2798ca4ec9cd19cad4334 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Wed, 31 Jul 2019 20:46:45 +0100 Subject: [PATCH 6/8] Build Dist --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index aed627ce7..4162977d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: php - +dist: xenial php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 + - '5.4' + - '5.5' + - '5.6' + - '7.0' - hhvm matrix: @@ -14,7 +14,6 @@ matrix: - php: 7.0 sudo: false - services: mongodb before_script: From e5368bf9bc7ec2d3cdbafcb26918938f5594a44c Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Wed, 31 Jul 2019 20:48:39 +0100 Subject: [PATCH 7/8] Added MySql --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4162977d5..dad2aec06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,9 @@ matrix: - php: 7.0 sudo: false -services: mongodb +services: + - mongodb + - mysql before_script: - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 2c1ee1c6b3f8511b1a6090aeac2e30625efb8de3 Mon Sep 17 00:00:00 2001 From: Adam Allport Date: Wed, 31 Jul 2019 20:51:23 +0100 Subject: [PATCH 8/8] Switched to trusty --- .travis.yml | 2 +- Dockerfile | 4 ++-- composer.json | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dad2aec06..86ac0590e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: php -dist: xenial +dist: trusty php: - '5.4' - '5.5' diff --git a/Dockerfile b/Dockerfile index 41e755c8d..804708ee6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,10 @@ FROM composer:${COMPOSER_VERSION} FROM php:${PHP_VERSION}-cli RUN apt-get update && \ - apt-get install -y autoconf pkg-config libssl-dev git libzip-dev zlib1g-dev && \ + apt-get install -y autoconf pkg-config libssl-dev git libzip-dev zlib1g-dev unzip libmcrypt-dev && \ pecl install mongodb && docker-php-ext-enable mongodb && \ pecl install xdebug && docker-php-ext-enable xdebug && \ - docker-php-ext-install -j$(nproc) pdo_mysql zip + docker-php-ext-install -j$(nproc) pdo_mysql zip mcrypt COPY --from=composer /usr/bin/composer /usr/local/bin/composer diff --git a/composer.json b/composer.json index bd16472cd..4d304d4dd 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "require-dev": { "orchestra/testbench": "3.0.*", "mockery/mockery": "*", - "satooshi/php-coveralls": "*" + "satooshi/php-coveralls": "*", + "phpunit/phpunit": "6" }, "autoload": { "psr-0": {