diff --git a/CHANGELOG.md b/CHANGELOG.md index c85e5efa3..160b0b927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,5 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Removed +- EmbedsOne and EmbedsMany relations by [@divine](https://github.com/divine). diff --git a/README.md b/README.md index 91bfa8c6f..4f1359972 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,6 @@ This package adds functionalities to the Eloquent model and Query builder for Mo - [Relationships](#relationships) - [Basic Usage](#basic-usage-1) - [belongsToMany and pivots](#belongstomany-and-pivots) - - [EmbedsMany Relationship](#embedsmany-relationship) - - [EmbedsOne Relationship](#embedsone-relationship) - [Query Builder](#query-builder) - [Basic Usage](#basic-usage-2) - [Available operations](#available-operations) @@ -419,7 +417,7 @@ Aggregations can be also used on sub-documents: $total = Order::max('suborder.price'); ``` -**NOTE**: This aggregation only works with single sub-documents (like `EmbedsOne`) not subdocument arrays (like `EmbedsMany`). +**NOTE**: This aggregation only works with single sub-documents not arrays. **Incrementing/Decrementing the value of a column** @@ -712,10 +710,6 @@ The only available relationships are: - belongsTo - belongsToMany -The MongoDB-specific relationships are: - - embedsOne - - embedsMany - Here is a small example: ```php @@ -764,152 +758,6 @@ class User extends Model } ``` -### 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! - -```php -use Jenssegers\Mongodb\Eloquent\Model; - -class User extends Model -{ - public function books() - { - return $this->embedsMany(Book::class); - } -} -``` - -You can access the embedded models through the dynamic property: - -```php -$user = User::first(); - -foreach ($user->books as $book) { - // -} -``` - -The inverse relation is auto*magically* available. You don't need to define this reverse relation. - -```php -$book = Book::first(); - -$user = $book->user; -``` - -Inserting and updating embedded models works similar to the `hasMany` relation: - -```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): - -```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): - -```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: - -```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: - -```php -use Jenssegers\Mongodb\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. - -```php -use Jenssegers\Mongodb\Eloquent\Model; - -class Book extends Model -{ - public function author() - { - return $this->embedsOne(Author::class); - } -} -``` - -You can access the embedded models through the dynamic property: - -```php -$book = Book::first(); -$author = $book->author; -``` - -Inserting and updating embedded models works similar to the `hasOne` relation: - -```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): - -```php -$author = $book->author; - -$author->name = 'Jane Doe'; -$author->save(); -``` - -You can replace the embedded model with a new model like this: - -```php -$newAuthor = new Author(['name' => 'Jane Doe']); - -$book->author()->save($newAuthor); -``` - Query Builder ------------- @@ -1098,39 +946,10 @@ Jenssegers\Mongodb\MongodbQueueServiceProvider::class, Upgrading --------- -#### Upgrading from version 2 to 3 - -In this new major release which supports the new MongoDB PHP extension, we also moved the location of the Model class and replaced the MySQL model class with a trait. +#### Upgrading from version 3 to 4 -Please change all `Jenssegers\Mongodb\Model` references to `Jenssegers\Mongodb\Eloquent\Model` either at the top of your model files or your registered alias. +This new major release contains breaking changes which is listed below: -```php -use Jenssegers\Mongodb\Eloquent\Model; +- EmbedsOne and EmbedsMany relations has been removed completely. See explanation [here](https://github.com/jenssegers/laravel-mongodb/issues/1974#issuecomment-592859508) -class User extends Model -{ - // -} -``` - -If you are using hybrid relations, your MySQL classes should now extend the original Eloquent model class `Illuminate\Database\Eloquent\Model` instead of the removed `Jenssegers\Eloquent\Model`. - -Instead use the new `Jenssegers\Mongodb\Eloquent\HybridRelations` trait. This should make things more clear as there is only one single model class in this package. - -```php -use Jenssegers\Mongodb\Eloquent\HybridRelations; - -class User extends Model -{ - - use HybridRelations; - - protected $connection = 'mysql'; -} -``` - -Embedded relations now return an `Illuminate\Database\Eloquent\Collection` rather than a custom Collection class. If you were using one of the special methods that were available, convert them to Collection operations. - -```php -$books = $user->books()->sortBy('title')->get(); -``` +For any other minor changes, please take a look at our [changelog](CHANGELOG.md) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4da34b41d..865f8bcd5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -31,7 +31,6 @@ tests/RelationsTest.php - tests/EmbeddedRelationsTest.php tests/RelationsTest.php diff --git a/src/Jenssegers/Mongodb/Eloquent/Builder.php b/src/Jenssegers/Mongodb/Eloquent/Builder.php index 90b58484f..89206c0d6 100644 --- a/src/Jenssegers/Mongodb/Eloquent/Builder.php +++ b/src/Jenssegers/Mongodb/Eloquent/Builder.php @@ -35,14 +35,6 @@ class Builder extends EloquentBuilder */ public function update(array $values, array $options = []) { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $relation->performUpdate($this->model, $values); - - return 1; - } - return $this->toBase()->update($this->addUpdatedAtColumn($values), $options); } @@ -51,14 +43,6 @@ public function update(array $values, array $options = []) */ public function insert(array $values) { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $relation->performInsert($this->model, $values); - - return true; - } - return parent::insert($values); } @@ -67,14 +51,6 @@ public function insert(array $values) */ public function insertGetId(array $values, $sequence = null) { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $relation->performInsert($this->model, $values); - - return $this->model->getKey(); - } - return parent::insertGetId($values, $sequence); } @@ -83,14 +59,6 @@ public function insertGetId(array $values, $sequence = null) */ public function delete() { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $relation->performDelete($this->model); - - return $this->model->getKey(); - } - return parent::delete(); } @@ -99,23 +67,6 @@ public function delete() */ public function increment($column, $amount = 1, array $extra = []) { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $value = $this->model->{$column}; - - // When doing increment and decrements, Eloquent will automatically - // sync the original attributes. We need to change the attribute - // temporary in order to trigger an update query. - $this->model->{$column} = null; - - $this->model->syncOriginalAttribute($column); - - $result = $this->model->update([$column => $value]); - - return $result; - } - return parent::increment($column, $amount, $extra); } @@ -124,21 +75,6 @@ public function increment($column, $amount = 1, array $extra = []) */ public function decrement($column, $amount = 1, array $extra = []) { - // Intercept operations on embedded models and delegate logic - // to the parent relation instance. - if ($relation = $this->model->getParentRelation()) { - $value = $this->model->{$column}; - - // When doing increment and decrements, Eloquent will automatically - // sync the original attributes. We need to change the attribute - // temporary in order to trigger an update query. - $this->model->{$column} = null; - - $this->model->syncOriginalAttribute($column); - - return $this->model->update([$column => $value]); - } - return parent::decrement($column, $amount, $extra); } diff --git a/src/Jenssegers/Mongodb/Eloquent/EmbedsRelations.php b/src/Jenssegers/Mongodb/Eloquent/EmbedsRelations.php deleted file mode 100644 index caef0e693..000000000 --- a/src/Jenssegers/Mongodb/Eloquent/EmbedsRelations.php +++ /dev/null @@ -1,78 +0,0 @@ -newQuery(); - - $instance = new $related; - - return new EmbedsMany($query, $this, $instance, $localKey, $foreignKey, $relation); - } - - /** - * Define an embedded one-to-many relationship. - * @param string $related - * @param string $localKey - * @param string $foreignKey - * @param string $relation - * @return \Jenssegers\Mongodb\Relations\EmbedsOne - */ - protected function embedsOne($related, $localKey = null, $foreignKey = null, $relation = null) - { - // If no relation name was given, we will use this debug backtrace to extract - // the calling method's name and use that as the relationship name as most - // of the time this will be what we desire to use for the relationships. - if ($relation === null) { - list(, $caller) = debug_backtrace(false); - - $relation = $caller['function']; - } - - if ($localKey === null) { - $localKey = $relation; - } - - if ($foreignKey === null) { - $foreignKey = Str::snake(class_basename($this)); - } - - $query = $this->newQuery(); - - $instance = new $related; - - return new EmbedsOne($query, $this, $instance, $localKey, $foreignKey, $relation); - } -} diff --git a/src/Jenssegers/Mongodb/Eloquent/Model.php b/src/Jenssegers/Mongodb/Eloquent/Model.php index 54ef5129b..27e0228fe 100644 --- a/src/Jenssegers/Mongodb/Eloquent/Model.php +++ b/src/Jenssegers/Mongodb/Eloquent/Model.php @@ -17,7 +17,7 @@ abstract class Model extends BaseModel { - use HybridRelations, EmbedsRelations; + use HybridRelations; /** * The collection associated with the model. @@ -143,11 +143,6 @@ public function getAttribute($key) return $this->getAttributeValue($key); } - // This checks for embedded relation support. - if (method_exists($this, $key) && !method_exists(self::class, $key)) { - return $this->getRelationValue($key); - } - return parent::getAttribute($key); } diff --git a/src/Jenssegers/Mongodb/Relations/EmbedsMany.php b/src/Jenssegers/Mongodb/Relations/EmbedsMany.php deleted file mode 100644 index eda777e8d..000000000 --- a/src/Jenssegers/Mongodb/Relations/EmbedsMany.php +++ /dev/null @@ -1,342 +0,0 @@ -setRelation($relation, $this->related->newCollection()); - } - - return $models; - } - - /** - * @inheritdoc - */ - public function getResults() - { - return $this->toCollection($this->getEmbedded()); - } - - /** - * Save a new model and attach it to the parent model. - * @param Model $model - * @return Model|bool - */ - public function performInsert(Model $model) - { - // Generate a new key if needed. - if ($model->getKeyName() == '_id' && !$model->getKey()) { - $model->setAttribute('_id', new ObjectID); - } - - // For deeply nested documents, let the parent handle the changes. - if ($this->isNested()) { - $this->associate($model); - return $this->parent->save() ? $model : false; - } - - // Push the new model to the database. - $result = $this->getBaseQuery()->push($this->localKey, $model->getAttributes(), true); - - // Attach the model to its parent. - if ($result) { - $this->associate($model); - } - - return $result ? $model : false; - } - - /** - * Save an existing model and attach it to the parent model. - * @param Model $model - * @return Model|bool - */ - public function performUpdate(Model $model) - { - // For deeply nested documents, let the parent handle the changes. - if ($this->isNested()) { - $this->associate($model); - - return $this->parent->save(); - } - - // Get the correct foreign key value. - $foreignKey = $this->getForeignKeyValue($model); - - $values = $this->getUpdateValues($model->getDirty(), $this->localKey . '.$.'); - - // Update document in database. - $result = $this->getBaseQuery()->where($this->localKey . '.' . $model->getKeyName(), $foreignKey) - ->update($values); - - // Attach the model to its parent. - if ($result) { - $this->associate($model); - } - - return $result ? $model : false; - } - - /** - * Delete an existing model and detach it from the parent model. - * @param Model $model - * @return int - */ - public function performDelete(Model $model) - { - // For deeply nested documents, let the parent handle the changes. - if ($this->isNested()) { - $this->dissociate($model); - - return $this->parent->save(); - } - - // Get the correct foreign key value. - $foreignKey = $this->getForeignKeyValue($model); - - $result = $this->getBaseQuery()->pull($this->localKey, [$model->getKeyName() => $foreignKey]); - - if ($result) { - $this->dissociate($model); - } - - return $result; - } - - /** - * Associate the model instance to the given parent, without saving it to the database. - * @param Model $model - * @return Model - */ - public function associate(Model $model) - { - if (!$this->contains($model)) { - return $this->associateNew($model); - } - - return $this->associateExisting($model); - } - - /** - * Dissociate the model instance from the given parent, without saving it to the database. - * @param mixed $ids - * @return int - */ - public function dissociate($ids = []) - { - $ids = $this->getIdsArrayFrom($ids); - - $records = $this->getEmbedded(); - - $primaryKey = $this->related->getKeyName(); - - // Remove the document from the parent model. - foreach ($records as $i => $record) { - if (in_array($record[$primaryKey], $ids)) { - unset($records[$i]); - } - } - - $this->setEmbedded($records); - - // We return the total number of deletes for the operation. The developers - // can then check this number as a boolean type value or get this total count - // of records deleted for logging, etc. - return count($ids); - } - - /** - * Destroy the embedded models for the given IDs. - * @param mixed $ids - * @return int - */ - public function destroy($ids = []) - { - $count = 0; - - $ids = $this->getIdsArrayFrom($ids); - - // Get all models matching the given ids. - $models = $this->getResults()->only($ids); - - // Pull the documents from the database. - foreach ($models as $model) { - if ($model->delete()) { - $count++; - } - } - - return $count; - } - - /** - * Delete all embedded models. - * @return int - */ - public function delete() - { - // Overwrite the local key with an empty array. - $result = $this->query->update([$this->localKey => []]); - - if ($result) { - $this->setEmbedded([]); - } - - return $result; - } - - /** - * Destroy alias. - * @param mixed $ids - * @return int - */ - public function detach($ids = []) - { - return $this->destroy($ids); - } - - /** - * Save alias. - * @param Model $model - * @return Model - */ - public function attach(Model $model) - { - return $this->save($model); - } - - /** - * Associate a new model instance to the given parent, without saving it to the database. - * @param Model $model - * @return Model - */ - protected function associateNew($model) - { - // Create a new key if needed. - if ($model->getKeyName() === '_id' && !$model->getAttribute('_id')) { - $model->setAttribute('_id', new ObjectID); - } - - $records = $this->getEmbedded(); - - // Add the new model to the embedded documents. - $records[] = $model->getAttributes(); - - return $this->setEmbedded($records); - } - - /** - * Associate an existing model instance to the given parent, without saving it to the database. - * @param Model $model - * @return Model - */ - protected function associateExisting($model) - { - // Get existing embedded documents. - $records = $this->getEmbedded(); - - $primaryKey = $this->related->getKeyName(); - - $key = $model->getKey(); - - // Replace the document in the parent model. - foreach ($records as &$record) { - if ($record[$primaryKey] == $key) { - $record = $model->getAttributes(); - break; - } - } - - return $this->setEmbedded($records); - } - - /** - * @param null $perPage - * @param array $columns - * @param string $pageName - * @param null $page - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator - */ - public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null) - { - $page = $page ?: Paginator::resolveCurrentPage($pageName); - $perPage = $perPage ?: $this->related->getPerPage(); - - $results = $this->getEmbedded(); - $results = $this->toCollection($results); - $total = $results->count(); - $start = ($page - 1) * $perPage; - - $sliced = $results->slice( - $start, - $perPage - ); - - return new LengthAwarePaginator( - $sliced, - $total, - $perPage, - $page, - [ - 'path' => Paginator::resolveCurrentPath() - ] - ); - } - - /** - * @inheritdoc - */ - protected function getEmbedded() - { - return parent::getEmbedded() ?: []; - } - - /** - * @inheritdoc - */ - protected function setEmbedded($models) - { - if (!is_array($models)) { - $models = [$models]; - } - - return parent::setEmbedded(array_values($models)); - } - - /** - * @inheritdoc - */ - public function __call($method, $parameters) - { - if (method_exists(Collection::class, $method)) { - return call_user_func_array([$this->getResults(), $method], $parameters); - } - - return parent::__call($method, $parameters); - } - - /** - * Get the name of the "where in" method for eager loading. - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @return string - */ - protected function whereInMethod(EloquentModel $model, $key) - { - return 'whereIn'; - } -} diff --git a/src/Jenssegers/Mongodb/Relations/EmbedsOne.php b/src/Jenssegers/Mongodb/Relations/EmbedsOne.php deleted file mode 100644 index a0e713bc1..000000000 --- a/src/Jenssegers/Mongodb/Relations/EmbedsOne.php +++ /dev/null @@ -1,145 +0,0 @@ -setRelation($relation, null); - } - - return $models; - } - - /** - * @inheritdoc - */ - public function getResults() - { - return $this->toModel($this->getEmbedded()); - } - - /** - * Save a new model and attach it to the parent model. - * @param Model $model - * @return Model|bool - */ - public function performInsert(Model $model) - { - // Generate a new key if needed. - if ($model->getKeyName() == '_id' && !$model->getKey()) { - $model->setAttribute('_id', new ObjectID); - } - - // For deeply nested documents, let the parent handle the changes. - if ($this->isNested()) { - $this->associate($model); - return $this->parent->save() ? $model : false; - } - - $result = $this->getBaseQuery()->update([$this->localKey => $model->getAttributes()]); - - // Attach the model to its parent. - if ($result) { - $this->associate($model); - } - - return $result ? $model : false; - } - - /** - * Save an existing model and attach it to the parent model. - * @param Model $model - * @return Model|bool - */ - public function performUpdate(Model $model) - { - if ($this->isNested()) { - $this->associate($model); - - return $this->parent->save(); - } - - $values = $this->getUpdateValues($model->getDirty(), $this->localKey . '.'); - - $result = $this->getBaseQuery()->update($values); - - // Attach the model to its parent. - if ($result) { - $this->associate($model); - } - - return $result ? $model : false; - } - - /** - * Delete an existing model and detach it from the parent model. - * @return int - */ - public function performDelete() - { - // For deeply nested documents, let the parent handle the changes. - if ($this->isNested()) { - $this->dissociate(); - return $this->parent->save(); - } - - // Overwrite the local key with an empty array. - $result = $this->getBaseQuery()->update([$this->localKey => null]); - - // Detach the model from its parent. - if ($result) { - $this->dissociate(); - } - - return $result; - } - - /** - * Attach the model to its parent. - * @param Model $model - * @return Model - */ - public function associate(Model $model) - { - return $this->setEmbedded($model->getAttributes()); - } - - /** - * Detach the model from its parent. - * @return Model - */ - public function dissociate() - { - return $this->setEmbedded(null); - } - - /** - * Delete all embedded models. - * @return int - */ - public function delete() - { - return $this->performDelete(); - } - - /** - * Get the name of the "where in" method for eager loading. - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @return string - */ - protected function whereInMethod(EloquentModel $model, $key) - { - return 'whereIn'; - } -} diff --git a/src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php b/src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php deleted file mode 100644 index 5a7f636e7..000000000 --- a/src/Jenssegers/Mongodb/Relations/EmbedsOneOrMany.php +++ /dev/null @@ -1,397 +0,0 @@ -query = $query; - $this->parent = $parent; - $this->related = $related; - $this->localKey = $localKey; - $this->foreignKey = $foreignKey; - $this->relation = $relation; - - // If this is a nested relation, we need to get the parent query instead. - if ($parentRelation = $this->getParentRelation()) { - $this->query = $parentRelation->getQuery(); - } - - $this->addConstraints(); - } - - /** - * @inheritdoc - */ - public function addConstraints() - { - if (static::$constraints) { - $this->query->where($this->getQualifiedParentKeyName(), '=', $this->getParentKey()); - } - } - - /** - * @inheritdoc - */ - public function addEagerConstraints(array $models) - { - // There are no eager loading constraints. - } - - /** - * @inheritdoc - */ - public function match(array $models, Collection $results, $relation) - { - foreach ($models as $model) { - $results = $model->$relation()->getResults(); - - $model->setParentRelation($this); - - $model->setRelation($relation, $results); - } - - return $models; - } - - /** - * Shorthand to get the results of the relationship. - * @param array $columns - * @return Collection - */ - public function get($columns = ['*']) - { - return $this->getResults(); - } - - /** - * Get the number of embedded models. - * @return int - */ - public function count() - { - return count($this->getEmbedded()); - } - - /** - * Attach a model instance to the parent model. - * @param Model $model - * @return Model|bool - */ - public function save(Model $model) - { - $model->setParentRelation($this); - - return $model->save() ? $model : false; - } - - /** - * Attach a collection of models to the parent instance. - * @param Collection|array $models - * @return Collection|array - */ - public function saveMany($models) - { - foreach ($models as $model) { - $this->save($model); - } - - return $models; - } - - /** - * Create a new instance of the related model. - * @param array $attributes - * @return Model - */ - public function create(array $attributes = []) - { - // Here we will set the raw attributes to avoid hitting the "fill" method so - // that we do not have to worry about a mass accessor rules blocking sets - // on the models. Otherwise, some of these attributes will not get set. - $instance = $this->related->newInstance($attributes); - - $instance->setParentRelation($this); - - $instance->save(); - - return $instance; - } - - /** - * Create an array of new instances of the related model. - * @param array $records - * @return array - */ - public function createMany(array $records) - { - $instances = []; - - foreach ($records as $record) { - $instances[] = $this->create($record); - } - - return $instances; - } - - /** - * Transform single ID, single Model or array of Models into an array of IDs. - * @param mixed $ids - * @return array - */ - protected function getIdsArrayFrom($ids) - { - if ($ids instanceof \Illuminate\Support\Collection) { - $ids = $ids->all(); - } - - if (!is_array($ids)) { - $ids = [$ids]; - } - - foreach ($ids as &$id) { - if ($id instanceof Model) { - $id = $id->getKey(); - } - } - - return $ids; - } - - /** - * @inheritdoc - */ - protected function getEmbedded() - { - // Get raw attributes to skip relations and accessors. - $attributes = $this->parent->getAttributes(); - - // Get embedded models form parent attributes. - $embedded = isset($attributes[$this->localKey]) ? (array) $attributes[$this->localKey] : null; - - return $embedded; - } - - /** - * @inheritdoc - */ - protected function setEmbedded($records) - { - // Assign models to parent attributes array. - $attributes = $this->parent->getAttributes(); - $attributes[$this->localKey] = $records; - - // Set raw attributes to skip mutators. - $this->parent->setRawAttributes($attributes); - - // Set the relation on the parent. - return $this->parent->setRelation($this->relation, $records === null ? null : $this->getResults()); - } - - /** - * Get the foreign key value for the relation. - * @param mixed $id - * @return mixed - */ - protected function getForeignKeyValue($id) - { - if ($id instanceof Model) { - $id = $id->getKey(); - } - - // Convert the id to MongoId if necessary. - return $this->getBaseQuery()->convertKey($id); - } - - /** - * Convert an array of records to a Collection. - * @param array $records - * @return Collection - */ - protected function toCollection(array $records = []) - { - $models = []; - - foreach ($records as $attributes) { - $models[] = $this->toModel($attributes); - } - - if (count($models) > 0) { - $models = $this->eagerLoadRelations($models); - } - - return $this->related->newCollection($models); - } - - /** - * Create a related model instanced. - * @param array $attributes - * @return Model - */ - protected function toModel($attributes = []) - { - if ($attributes === null) { - return; - } - - $connection = $this->related->getConnection(); - - $model = $this->related->newFromBuilder( - (array) $attributes, - $connection ? $connection->getName() : null - ); - - $model->setParentRelation($this); - - $model->setRelation($this->foreignKey, $this->parent); - - // If you remove this, you will get segmentation faults! - $model->setHidden(array_merge($model->getHidden(), [$this->foreignKey])); - - return $model; - } - - /** - * Get the relation instance of the parent. - * @return Relation - */ - protected function getParentRelation() - { - return $this->parent->getParentRelation(); - } - - /** - * @inheritdoc - */ - public function getQuery() - { - // Because we are sharing this relation instance to models, we need - // to make sure we use separate query instances. - return clone $this->query; - } - - /** - * @inheritdoc - */ - public function getBaseQuery() - { - // Because we are sharing this relation instance to models, we need - // to make sure we use separate query instances. - return clone $this->query->getQuery(); - } - - /** - * Check if this relation is nested in another relation. - * @return bool - */ - protected function isNested() - { - return $this->getParentRelation() != null; - } - - /** - * Get the fully qualified local key name. - * @param string $glue - * @return string - */ - protected function getPathHierarchy($glue = '.') - { - if ($parentRelation = $this->getParentRelation()) { - return $parentRelation->getPathHierarchy($glue) . $glue . $this->localKey; - } - - return $this->localKey; - } - - /** - * @inheritdoc - */ - public function getQualifiedParentKeyName() - { - if ($parentRelation = $this->getParentRelation()) { - return $parentRelation->getPathHierarchy() . '.' . $this->parent->getKeyName(); - } - - return $this->parent->getKeyName(); - } - - /** - * Get the primary key value of the parent. - * @return string - */ - protected function getParentKey() - { - return $this->parent->getKey(); - } - - /** - * Return update values - * @param $array - * @param string $prepend - * @return array - */ - public static function getUpdateValues($array, $prepend = '') - { - $results = []; - - foreach ($array as $key => $value) { - $results[$prepend . $key] = $value; - } - - return $results; - } - - /** - * Get the foreign key for the relationship. - * @return string - */ - public function getQualifiedForeignKeyName() - { - return $this->foreignKey; - } - - /** - * Get the name of the "where in" method for eager loading. - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @return string - */ - protected function whereInMethod(EloquentModel $model, $key) - { - return 'whereIn'; - } -} diff --git a/tests/EmbeddedRelationsTest.php b/tests/EmbeddedRelationsTest.php deleted file mode 100644 index 23e2fae03..000000000 --- a/tests/EmbeddedRelationsTest.php +++ /dev/null @@ -1,872 +0,0 @@ - 'John Doe']); - $address = new Address(['city' => 'London']); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.creating: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($address), $address); - $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address); - - $address = $user->addresses()->save($address); - $address->unsetEventDispatcher(); - - $this->assertNotNull($user->addresses); - $this->assertInstanceOf(Collection::class, $user->addresses); - $this->assertEquals(['London'], $user->addresses->pluck('city')->all()); - $this->assertInstanceOf(DateTime::class, $address->created_at); - $this->assertInstanceOf(DateTime::class, $address->updated_at); - $this->assertNotNull($address->_id); - $this->assertIsString($address->_id); - - $raw = $address->getAttributes(); - $this->assertInstanceOf(ObjectId::class, $raw['_id']); - - $address = $user->addresses()->save(new Address(['city' => 'Paris'])); - - $user = User::find($user->_id); - $this->assertEquals(['London', 'Paris'], $user->addresses->pluck('city')->all()); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.updating: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('dispatch')->once()->with('eloquent.updated: ' . get_class($address), $address); - $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address); - - $address->city = 'New York'; - $user->addresses()->save($address); - $address->unsetEventDispatcher(); - - $this->assertCount(2, $user->addresses); - $this->assertCount(2, $user->addresses()->get()); - $this->assertEquals(2, $user->addresses->count()); - $this->assertEquals(2, $user->addresses()->count()); - $this->assertEquals(['London', 'New York'], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->_id); - $this->assertEquals(['London', 'New York'], $freshUser->addresses->pluck('city')->all()); - - $address = $user->addresses->first(); - $this->assertEquals('London', $address->city); - $this->assertInstanceOf(DateTime::class, $address->created_at); - $this->assertInstanceOf(DateTime::class, $address->updated_at); - $this->assertInstanceOf(User::class, $address->user); - $this->assertEmpty($address->relationsToArray()); // prevent infinite loop - - $user = User::find($user->_id); - $user->addresses()->save(new Address(['city' => 'Bruxelles'])); - $this->assertEquals(['London', 'New York', 'Bruxelles'], $user->addresses->pluck('city')->all()); - - $address = $user->addresses[1]; - $address->city = "Manhattan"; - $user->addresses()->save($address); - $this->assertEquals(['London', 'Manhattan', 'Bruxelles'], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->_id); - $this->assertEquals(['London', 'Manhattan', 'Bruxelles'], $freshUser->addresses->pluck('city')->all()); - } - - public function testEmbedsToArray() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->saveMany([new Address(['city' => 'London']), new Address(['city' => 'Bristol'])]); - - $array = $user->toArray(); - $this->assertArrayNotHasKey('_addresses', $array); - $this->assertArrayHasKey('addresses', $array); - } - - public function testEmbedsManyAssociate() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'London']); - - $user->addresses()->associate($address); - $this->assertEquals(['London'], $user->addresses->pluck('city')->all()); - $this->assertNotNull($address->_id); - - $freshUser = User::find($user->_id); - $this->assertEquals([], $freshUser->addresses->pluck('city')->all()); - - $address->city = 'Londinium'; - $user->addresses()->associate($address); - $this->assertEquals(['Londinium'], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->_id); - $this->assertEquals([], $freshUser->addresses->pluck('city')->all()); - } - - public function testEmbedsManySaveMany() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->saveMany([new Address(['city' => 'London']), new Address(['city' => 'Bristol'])]); - $this->assertEquals(['London', 'Bristol'], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->id); - $this->assertEquals(['London', 'Bristol'], $freshUser->addresses->pluck('city')->all()); - } - - public function testEmbedsManyDuplicate() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'London']); - $user->addresses()->save($address); - $user->addresses()->save($address); - $this->assertEquals(1, $user->addresses->count()); - $this->assertEquals(['London'], $user->addresses->pluck('city')->all()); - - $user = User::find($user->id); - $this->assertEquals(1, $user->addresses->count()); - - $address->city = 'Paris'; - $user->addresses()->save($address); - $this->assertEquals(1, $user->addresses->count()); - $this->assertEquals(['Paris'], $user->addresses->pluck('city')->all()); - - $user->addresses()->create(['_id' => $address->_id, 'city' => 'Bruxelles']); - $this->assertEquals(1, $user->addresses->count()); - $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all()); - } - - public function testEmbedsManyCreate() - { - $user = User::create([]); - $address = $user->addresses()->create(['city' => 'Bruxelles']); - $this->assertInstanceOf(Address::class, $address); - $this->assertIsString($address->_id); - $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all()); - - $raw = $address->getAttributes(); - $this->assertInstanceOf(ObjectId::class, $raw['_id']); - - $freshUser = User::find($user->id); - $this->assertEquals(['Bruxelles'], $freshUser->addresses->pluck('city')->all()); - - $user = User::create([]); - $address = $user->addresses()->create(['_id' => '', 'city' => 'Bruxelles']); - $this->assertIsString($address->_id); - - $raw = $address->getAttributes(); - $this->assertInstanceOf(ObjectId::class, $raw['_id']); - } - - public function testEmbedsManyCreateMany() - { - $user = User::create([]); - list($bruxelles, $paris) = $user->addresses()->createMany([['city' => 'Bruxelles'], ['city' => 'Paris']]); - $this->assertInstanceOf(Address::class, $bruxelles); - $this->assertEquals('Bruxelles', $bruxelles->city); - $this->assertEquals(['Bruxelles', 'Paris'], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->id); - $this->assertEquals(['Bruxelles', 'Paris'], $freshUser->addresses->pluck('city')->all()); - } - - public function testEmbedsManyDestroy() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->saveMany([ - new Address(['city' => 'London']), - new Address(['city' => 'Bristol']), - new Address(['city' => 'Bruxelles']), - ]); - - $address = $user->addresses->first(); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.deleting: ' . get_class($address), Mockery::type(Address::class)) - ->andReturn(true); - $events->shouldReceive('dispatch') - ->once() - ->with('eloquent.deleted: ' . get_class($address), Mockery::type(Address::class)); - - $user->addresses()->destroy($address->_id); - $this->assertEquals(['Bristol', 'Bruxelles'], $user->addresses->pluck('city')->all()); - - $address->unsetEventDispatcher(); - - $address = $user->addresses->first(); - $user->addresses()->destroy($address); - $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all()); - - $user->addresses()->create(['city' => 'Paris']); - $user->addresses()->create(['city' => 'San Francisco']); - - $freshUser = User::find($user->id); - $this->assertEquals(['Bruxelles', 'Paris', 'San Francisco'], $freshUser->addresses->pluck('city')->all()); - - $ids = $user->addresses->pluck('_id'); - $user->addresses()->destroy($ids); - $this->assertEquals([], $user->addresses->pluck('city')->all()); - - $freshUser = User::find($user->id); - $this->assertEquals([], $freshUser->addresses->pluck('city')->all()); - - list($london, $bristol, $bruxelles) = $user->addresses()->saveMany([ - new Address(['city' => 'London']), - new Address(['city' => 'Bristol']), - new Address(['city' => 'Bruxelles']), - ]); - $user->addresses()->destroy([$london, $bruxelles]); - $this->assertEquals(['Bristol'], $user->addresses->pluck('city')->all()); - } - - public function testEmbedsManyDelete() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->saveMany([ - new Address(['city' => 'London']), - new Address(['city' => 'Bristol']), - new Address(['city' => 'Bruxelles']), - ]); - - $address = $user->addresses->first(); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.deleting: ' . get_class($address), Mockery::type(Address::class)) - ->andReturn(true); - $events->shouldReceive('dispatch') - ->once() - ->with('eloquent.deleted: ' . get_class($address), Mockery::type(Address::class)); - - $address->delete(); - - $this->assertEquals(2, $user->addresses()->count()); - $this->assertEquals(2, $user->addresses->count()); - - $address->unsetEventDispatcher(); - - $address = $user->addresses->first(); - $address->delete(); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(1, $user->addresses()->count()); - $this->assertEquals(1, $user->addresses->count()); - } - - public function testEmbedsManyDissociate() - { - $user = User::create([]); - $cordoba = $user->addresses()->create(['city' => 'Cordoba']); - - $user->addresses()->dissociate($cordoba->id); - - $freshUser = User::find($user->id); - $this->assertEquals(0, $user->addresses->count()); - $this->assertEquals(1, $freshUser->addresses->count()); - } - - public function testEmbedsManyAliases() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'London']); - - $address = $user->addresses()->attach($address); - $this->assertEquals(['London'], $user->addresses->pluck('city')->all()); - - $user->addresses()->detach($address); - $this->assertEquals([], $user->addresses->pluck('city')->all()); - } - - public function testEmbedsManyCreatingEventReturnsFalse() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'London']); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.creating: ' . get_class($address), $address) - ->andReturn(false); - - $this->assertFalse($user->addresses()->save($address)); - $address->unsetEventDispatcher(); - } - - public function testEmbedsManySavingEventReturnsFalse() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'Paris']); - $address->exists = true; - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($address), $address) - ->andReturn(false); - - $this->assertFalse($user->addresses()->save($address)); - $address->unsetEventDispatcher(); - } - - public function testEmbedsManyUpdatingEventReturnsFalse() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'New York']); - $user->addresses()->save($address); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($address), $address) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.updating: ' . get_class($address), $address) - ->andReturn(false); - - $address->city = 'Warsaw'; - - $this->assertFalse($user->addresses()->save($address)); - $address->unsetEventDispatcher(); - } - - public function testEmbedsManyDeletingEventReturnsFalse() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address(['city' => 'New York'])); - - $address = $user->addresses->first(); - - $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.deleting: ' . get_class($address), Mockery::mustBe($address)) - ->andReturn(false); - - $this->assertEquals(0, $user->addresses()->destroy($address)); - $this->assertEquals(['New York'], $user->addresses->pluck('city')->all()); - - $address->unsetEventDispatcher(); - } - - public function testEmbedsManyFindOrContains() - { - $user = User::create(['name' => 'John Doe']); - $address1 = $user->addresses()->save(new Address(['city' => 'New York'])); - $address2 = $user->addresses()->save(new Address(['city' => 'Paris'])); - - $address = $user->addresses()->find($address1->_id); - $this->assertEquals($address->city, $address1->city); - - $address = $user->addresses()->find($address2->_id); - $this->assertEquals($address->city, $address2->city); - - $this->assertTrue($user->addresses()->contains($address2->_id)); - $this->assertFalse($user->addresses()->contains('123')); - } - - public function testEmbedsManyEagerLoading() - { - $user1 = User::create(['name' => 'John Doe']); - $user1->addresses()->save(new Address(['city' => 'New York'])); - $user1->addresses()->save(new Address(['city' => 'Paris'])); - - $user2 = User::create(['name' => 'Jane Doe']); - $user2->addresses()->save(new Address(['city' => 'Berlin'])); - $user2->addresses()->save(new Address(['city' => 'Paris'])); - - $user = User::find($user1->id); - $relations = $user->getRelations(); - $this->assertArrayNotHasKey('addresses', $relations); - $this->assertArrayHasKey('addresses', $user->toArray()); - $this->assertIsArray($user->toArray()['addresses']); - - $user = User::with('addresses')->get()->first(); - $relations = $user->getRelations(); - $this->assertArrayHasKey('addresses', $relations); - $this->assertEquals(2, $relations['addresses']->count()); - $this->assertArrayHasKey('addresses', $user->toArray()); - $this->assertIsArray($user->toArray()['addresses']); - } - - public function testEmbedsManyDeleteAll() - { - $user1 = User::create(['name' => 'John Doe']); - $user1->addresses()->save(new Address(['city' => 'New York'])); - $user1->addresses()->save(new Address(['city' => 'Paris'])); - - $user2 = User::create(['name' => 'Jane Doe']); - $user2->addresses()->save(new Address(['city' => 'Berlin'])); - $user2->addresses()->save(new Address(['city' => 'Paris'])); - - $user1->addresses()->delete(); - $this->assertEquals(0, $user1->addresses()->count()); - $this->assertEquals(0, $user1->addresses->count()); - $this->assertEquals(2, $user2->addresses()->count()); - $this->assertEquals(2, $user2->addresses->count()); - - $user1 = User::find($user1->id); - $user2 = User::find($user2->id); - $this->assertEquals(0, $user1->addresses()->count()); - $this->assertEquals(0, $user1->addresses->count()); - $this->assertEquals(2, $user2->addresses()->count()); - $this->assertEquals(2, $user2->addresses->count()); - } - - public function testEmbedsManyCollectionMethods() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address([ - 'city' => 'Paris', - 'country' => 'France', - 'visited' => 4, - 'created_at' => new DateTime('3 days ago'), - ])); - $user->addresses()->save(new Address([ - 'city' => 'Bruges', - 'country' => 'Belgium', - 'visited' => 7, - 'created_at' => new DateTime('5 days ago'), - ])); - $user->addresses()->save(new Address([ - 'city' => 'Brussels', - 'country' => 'Belgium', - 'visited' => 2, - 'created_at' => new DateTime('4 days ago'), - ])); - $user->addresses()->save(new Address([ - 'city' => 'Ghent', - 'country' => 'Belgium', - 'visited' => 13, - 'created_at' => new DateTime('2 days ago'), - ])); - - $this->assertEquals(['Paris', 'Bruges', 'Brussels', 'Ghent'], $user->addresses()->pluck('city')->all()); - $this->assertEquals(['Bruges', 'Brussels', 'Ghent', 'Paris'], $user->addresses() - ->sortBy('city') - ->pluck('city') - ->all()); - $this->assertEquals([], $user->addresses()->where('city', 'New York')->pluck('city')->all()); - $this->assertEquals(['Bruges', 'Brussels', 'Ghent'], $user->addresses() - ->where('country', 'Belgium') - ->pluck('city') - ->all()); - $this->assertEquals(['Bruges', 'Brussels', 'Ghent'], $user->addresses() - ->where('country', 'Belgium') - ->sortBy('city') - ->pluck('city') - ->all()); - - $results = $user->addresses->first(); - $this->assertInstanceOf(Address::class, $results); - - $results = $user->addresses()->where('country', 'Belgium'); - $this->assertInstanceOf(Collection::class, $results); - $this->assertEquals(3, $results->count()); - - $results = $user->addresses()->whereIn('visited', [7, 13]); - $this->assertEquals(2, $results->count()); - } - - public function testEmbedsOne() - { - $user = User::create(['name' => 'John Doe']); - $father = new User(['name' => 'Mark Doe']); - - $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.creating: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($father), $father); - $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father); - - $father = $user->father()->save($father); - $father->unsetEventDispatcher(); - - $this->assertNotNull($user->father); - $this->assertEquals('Mark Doe', $user->father->name); - $this->assertInstanceOf(DateTime::class, $father->created_at); - $this->assertInstanceOf(DateTime::class, $father->updated_at); - $this->assertNotNull($father->_id); - $this->assertIsString($father->_id); - - $raw = $father->getAttributes(); - $this->assertInstanceOf(ObjectId::class, $raw['_id']); - - $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.updating: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('dispatch')->once()->with('eloquent.updated: ' . get_class($father), $father); - $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father); - - $father->name = 'Tom Doe'; - $user->father()->save($father); - $father->unsetEventDispatcher(); - - $this->assertNotNull($user->father); - $this->assertEquals('Tom Doe', $user->father->name); - - $father = new User(['name' => 'Jim Doe']); - - $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any()); - $events->shouldReceive('until') - ->once() - ->with('eloquent.saving: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('until') - ->once() - ->with('eloquent.creating: ' . get_class($father), $father) - ->andReturn(true); - $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($father), $father); - $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father); - - $father = $user->father()->save($father); - $father->unsetEventDispatcher(); - - $this->assertNotNull($user->father); - $this->assertEquals('Jim Doe', $user->father->name); - } - - public function testEmbedsOneAssociate() - { - $user = User::create(['name' => 'John Doe']); - $father = new User(['name' => 'Mark Doe']); - - $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class)); - $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any()); - $events->shouldReceive('until')->times(0)->with('eloquent.saving: ' . get_class($father), $father); - - $father = $user->father()->associate($father); - $father->unsetEventDispatcher(); - - $this->assertNotNull($user->father); - $this->assertEquals('Mark Doe', $user->father->name); - } - - public function testEmbedsOneNullAssociation() - { - $user = User::create(); - $this->assertNull($user->father); - } - - public function testEmbedsOneDelete() - { - $user = User::create(['name' => 'John Doe']); - $father = $user->father()->save(new User(['name' => 'Mark Doe'])); - - $user->father()->delete(); - $this->assertNull($user->father); - } - - public function testEmbedsManyToArray() - { - /** @var User $user */ - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address(['city' => 'New York'])); - $user->addresses()->save(new Address(['city' => 'Paris'])); - $user->addresses()->save(new Address(['city' => 'Brussels'])); - - $array = $user->toArray(); - $this->assertArrayHasKey('addresses', $array); - $this->assertIsArray($array['addresses']); - } - - public function testEmbeddedSave() - { - /** @var User $user */ - $user = User::create(['name' => 'John Doe']); - /** @var \Address $address */ - $address = $user->addresses()->create(['city' => 'New York']); - $father = $user->father()->create(['name' => 'Mark Doe']); - - $address->city = 'Paris'; - $address->save(); - - $father->name = 'Steve Doe'; - $father->save(); - - $this->assertEquals('Paris', $user->addresses->first()->city); - $this->assertEquals('Steve Doe', $user->father->name); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals('Paris', $user->addresses->first()->city); - $this->assertEquals('Steve Doe', $user->father->name); - - $address = $user->addresses()->first(); - $father = $user->father; - - $address->city = 'Ghent'; - $address->save(); - - $father->name = 'Mark Doe'; - $father->save(); - - $this->assertEquals('Ghent', $user->addresses->first()->city); - $this->assertEquals('Mark Doe', $user->father->name); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals('Ghent', $user->addresses->first()->city); - $this->assertEquals('Mark Doe', $user->father->name); - } - - public function testNestedEmbedsOne() - { - $user = User::create(['name' => 'John Doe']); - $father = $user->father()->create(['name' => 'Mark Doe']); - $grandfather = $father->father()->create(['name' => 'Steve Doe']); - $greatgrandfather = $grandfather->father()->create(['name' => 'Tom Doe']); - - $user->name = 'Tim Doe'; - $user->save(); - - $father->name = 'Sven Doe'; - $father->save(); - - $greatgrandfather->name = 'Ron Doe'; - $greatgrandfather->save(); - - $this->assertEquals('Tim Doe', $user->name); - $this->assertEquals('Sven Doe', $user->father->name); - $this->assertEquals('Steve Doe', $user->father->father->name); - $this->assertEquals('Ron Doe', $user->father->father->father->name); - - $user = User::where('name', 'Tim Doe')->first(); - $this->assertEquals('Tim Doe', $user->name); - $this->assertEquals('Sven Doe', $user->father->name); - $this->assertEquals('Steve Doe', $user->father->father->name); - $this->assertEquals('Ron Doe', $user->father->father->father->name); - } - - public function testNestedEmbedsMany() - { - $user = User::create(['name' => 'John Doe']); - $country1 = $user->addresses()->create(['country' => 'France']); - $country2 = $user->addresses()->create(['country' => 'Belgium']); - $city1 = $country1->addresses()->create(['city' => 'Paris']); - $city2 = $country2->addresses()->create(['city' => 'Ghent']); - $city3 = $country2->addresses()->create(['city' => 'Brussels']); - - $city3->city = 'Bruges'; - $city3->save(); - - $this->assertEquals(2, $user->addresses()->count()); - $this->assertEquals(1, $user->addresses()->first()->addresses()->count()); - $this->assertEquals(2, $user->addresses()->last()->addresses()->count()); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(2, $user->addresses()->count()); - $this->assertEquals(1, $user->addresses()->first()->addresses()->count()); - $this->assertEquals(2, $user->addresses()->last()->addresses()->count()); - } - - public function testNestedMixedEmbeds() - { - $user = User::create(['name' => 'John Doe']); - $father = $user->father()->create(['name' => 'Mark Doe']); - $country1 = $father->addresses()->create(['country' => 'France']); - $country2 = $father->addresses()->create(['country' => 'Belgium']); - - $country2->country = 'England'; - $country2->save(); - - $father->name = 'Steve Doe'; - $father->save(); - - $this->assertEquals('France', $user->father->addresses()->first()->country); - $this->assertEquals('England', $user->father->addresses()->last()->country); - $this->assertEquals('Steve Doe', $user->father->name); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals('France', $user->father->addresses()->first()->country); - $this->assertEquals('England', $user->father->addresses()->last()->country); - $this->assertEquals('Steve Doe', $user->father->name); - } - - public function testNestedEmbedsOneDelete() - { - $user = User::create(['name' => 'John Doe']); - $father = $user->father()->create(['name' => 'Mark Doe']); - $grandfather = $father->father()->create(['name' => 'Steve Doe']); - $greatgrandfather = $grandfather->father()->create(['name' => 'Tom Doe']); - - $grandfather->delete(); - - $this->assertNull($user->father->father); - - $user = User::where(['name' => 'John Doe'])->first(); - $this->assertNull($user->father->father); - } - - public function testNestedEmbedsManyDelete() - { - $user = User::create(['name' => 'John Doe']); - $country = $user->addresses()->create(['country' => 'France']); - $city1 = $country->addresses()->create(['city' => 'Paris']); - $city2 = $country->addresses()->create(['city' => 'Nice']); - $city3 = $country->addresses()->create(['city' => 'Lyon']); - - $city2->delete(); - - $this->assertEquals(2, $user->addresses()->first()->addresses()->count()); - $this->assertEquals('Lyon', $country->addresses()->last()->city); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(2, $user->addresses()->first()->addresses()->count()); - $this->assertEquals('Lyon', $country->addresses()->last()->city); - } - - public function testNestedMixedEmbedsDelete() - { - $user = User::create(['name' => 'John Doe']); - $father = $user->father()->create(['name' => 'Mark Doe']); - $country1 = $father->addresses()->create(['country' => 'France']); - $country2 = $father->addresses()->create(['country' => 'Belgium']); - - $country1->delete(); - - $this->assertEquals(1, $user->father->addresses()->count()); - $this->assertEquals('Belgium', $user->father->addresses()->last()->country); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(1, $user->father->addresses()->count()); - $this->assertEquals('Belgium', $user->father->addresses()->last()->country); - } - - public function testDoubleAssociate() - { - $user = User::create(['name' => 'John Doe']); - $address = new Address(['city' => 'Paris']); - - $user->addresses()->associate($address); - $user->addresses()->associate($address); - $address = $user->addresses()->first(); - $user->addresses()->associate($address); - $this->assertEquals(1, $user->addresses()->count()); - - $user = User::where('name', 'John Doe')->first(); - $user->addresses()->associate($address); - $this->assertEquals(1, $user->addresses()->count()); - - $user->save(); - $user->addresses()->associate($address); - $this->assertEquals(1, $user->addresses()->count()); - } - - public function testSaveEmptyModel() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address); - $this->assertNotNull($user->addresses); - $this->assertEquals(1, $user->addresses()->count()); - } - - public function testIncrementEmbedded() - { - $user = User::create(['name' => 'John Doe']); - $address = $user->addresses()->create(['city' => 'New York', 'visited' => 5]); - - $address->increment('visited'); - $this->assertEquals(6, $address->visited); - $this->assertEquals(6, $user->addresses()->first()->visited); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(6, $user->addresses()->first()->visited); - - $user = User::where('name', 'John Doe')->first(); - $address = $user->addresses()->first(); - - $address->decrement('visited'); - $this->assertEquals(5, $address->visited); - $this->assertEquals(5, $user->addresses()->first()->visited); - - $user = User::where('name', 'John Doe')->first(); - $this->assertEquals(5, $user->addresses()->first()->visited); - } - - public function testPaginateEmbedsMany() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address(['city' => 'New York'])); - $user->addresses()->save(new Address(['city' => 'Paris'])); - $user->addresses()->save(new Address(['city' => 'Brussels'])); - - $results = $user->addresses()->paginate(2); - $this->assertEquals(2, $results->count()); - $this->assertEquals(3, $results->total()); - } - - public function testGetQueueableRelationsEmbedsMany() - { - $user = User::create(['name' => 'John Doe']); - $user->addresses()->save(new Address(['city' => 'New York'])); - $user->addresses()->save(new Address(['city' => 'Paris'])); - - $this->assertEquals(['addresses'], $user->getQueueableRelations()); - $this->assertEquals([], $user->addresses->getQueueableRelations()); - } - - public function testGetQueueableRelationsEmbedsOne() - { - $user = User::create(['name' => 'John Doe']); - $user->father()->save(new User(['name' => 'Mark Doe'])); - - $this->assertEquals(['father'], $user->getQueueableRelations()); - $this->assertEquals([], $user->father->getQueueableRelations()); - } -} diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 6588be159..8c737d859 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -639,27 +639,6 @@ public function testOperators() $results = DB::collection('users')->where('name', 'not regexp', '/.*doe/i')->get(); $this->assertCount(1, $results); - - DB::collection('users')->insert([ - [ - 'name' => 'John Doe', - 'addresses' => [ - ['city' => 'Ghent'], - ['city' => 'Paris'], - ], - ], - [ - 'name' => 'Jane Doe', - 'addresses' => [ - ['city' => 'Brussels'], - ['city' => 'Paris'], - ], - ], - ]); - - $users = DB::collection('users')->where('addresses', 'elemMatch', ['city' => 'Brussels'])->get(); - $this->assertCount(1, $users); - $this->assertEquals('Jane Doe', $users[0]['name']); } public function testIncrement() diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php index 86065aac3..31692b0fe 100644 --- a/tests/RelationsTest.php +++ b/tests/RelationsTest.php @@ -337,8 +337,6 @@ public function testBelongsToManyCustom(): void $this->assertArrayHasKey('groups', $user->getAttributes()); // Assert they are attached - $this->assertContains($group->_id, $user->groups->pluck('_id')->toArray()); - $this->assertContains($user->_id, $group->users->pluck('_id')->toArray()); $this->assertEquals($group->_id, $user->groups()->first()->_id); $this->assertEquals($user->_id, $group->users()->first()->_id); } diff --git a/tests/models/Address.php b/tests/models/Address.php index 9d094cfcd..d59f946ea 100644 --- a/tests/models/Address.php +++ b/tests/models/Address.php @@ -2,15 +2,9 @@ declare(strict_types=1); use Jenssegers\Mongodb\Eloquent\Model as Eloquent; -use Jenssegers\Mongodb\Relations\EmbedsMany; class Address extends Eloquent { protected $connection = 'mongodb'; protected static $unguarded = true; - - public function addresses(): EmbedsMany - { - return $this->embedsMany('Address'); - } } diff --git a/tests/models/User.php b/tests/models/User.php index 1217af762..93dc3e52a 100644 --- a/tests/models/User.php +++ b/tests/models/User.php @@ -67,16 +67,6 @@ public function photos() return $this->morphMany('Photo', 'imageable'); } - public function addresses() - { - return $this->embedsMany('Address'); - } - - public function father() - { - return $this->embedsOne('User'); - } - public function getDateFormat() { return 'l jS \of F Y h:i:s A';