diff --git a/.travis.yml b/.travis.yml index aed627ce7..86ac0590e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: php - +dist: trusty php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 + - '5.4' + - '5.5' + - '5.6' + - '7.0' - hhvm matrix: @@ -14,8 +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 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..804708ee6 --- /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 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 mcrypt + +COPY --from=composer /usr/bin/composer /usr/local/bin/composer + +WORKDIR /code \ No newline at end of file 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": { 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 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 1b806a020..d86d08070 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,13 @@ 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 +108,17 @@ 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 (is_array($value) && $value['_id']) { + $current[$key] = $value['_id']; + } + } + } $records = $this->formatSyncList($ids); @@ -170,20 +188,32 @@ 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 { $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, $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,16 +235,20 @@ public function detach($ids = [], $touch = true) $ids = (array) $ids; // Detach all ids from the parent model. - $this->parent->pull($this->otherKey, $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, $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 02449fcc3..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)); @@ -277,6 +278,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 +384,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()); @@ -502,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); } }