Skip to content

Commit 0a25697

Browse files
committed
Merge pull request #279 from jenssegers/embedded-models
New v2 release
2 parents 7534e6f + 9431457 commit 0a25697

25 files changed

+1878
-592
lines changed

README.md

Lines changed: 120 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@ Laravel MongoDB
33

44
[![Latest Stable Version](http://img.shields.io/github/release/jenssegers/laravel-mongodb.svg)](https://packagist.org/packages/jenssegers/mongodb) [![Total Downloads](http://img.shields.io/packagist/dm/jenssegers/mongodb.svg)](https://packagist.org/packages/jenssegers/mongodb) [![Build Status](http://img.shields.io/travis/jenssegers/laravel-mongodb.svg)](https://travis-ci.org/jenssegers/laravel-mongodb) [![Coverage Status](http://img.shields.io/coveralls/jenssegers/laravel-mongodb.svg)](https://coveralls.io/r/jenssegers/laravel-mongodb?branch=master)
55

6-
An Eloquent model and Query builder with support for MongoDB, inspired by LMongo, but using the original Laravel methods. *This library extends the original Laravel classes, so it uses exactly the same methods.*
6+
An Eloquent model and Query builder with support for MongoDB, using the original Laravel API. *This library extends the original Laravel classes, so it uses exactly the same methods.*
7+
8+
### Upgrading from v1 to v2
9+
10+
In this new version, embedded documents are no longer saved to the parent model using an attribute with a leading underscore. If you have a relation like `embedsMany('Book')`, these books are now stored under `$model['books']` instead of `$model['_books']`. This was changed to make embedded relations less confusing for new developers.
11+
12+
If you want to upgrade to this new version without having to change all your existing database objects, you can modify your embedded relations to use a non-default local key including the underscore:
13+
14+
$this->embedsMany('Book', '_books');
15+
16+
Read the full changelog at https://github.com/jenssegers/laravel-mongodb/releases/tag/v2.0.0
717

818
Installation
919
------------
@@ -65,7 +75,7 @@ Tell your model to use the MongoDB model and set the collection (alias for table
6575

6676
}
6777

68-
If you are using a different database driver as the default one, you will need to specify the mongodb connection within your model by changing the `connection` property:
78+
If you are using a different database driver as the default one, you will need to specify the mongodb connection name within your model by changing the `connection` property:
6979

7080
use Jenssegers\Mongodb\Model as Eloquent;
7181

@@ -94,15 +104,15 @@ This will allow you to use your registered alias like:
94104
Query Builder
95105
-------------
96106

97-
The database driver plugs right into the original query builder. When using mongodb connections you will be able to build fluent queries to perform database operations. For your convenience, there is a `collection` alias for `table` as well as some additional mongodb specific operators/operations.
98-
99-
// With custom connection
100-
$user = DB::connection('mongodb')->collection('users')->get();
107+
The database driver plugs right into the original query builder. When using mongodb connections, you will be able to build fluent queries to perform database operations. For your convenience, there is a `collection` alias for `table` as well as some additional mongodb specific operators/operations.
101108

102-
// Using default connection
103109
$users = DB::collection('users')->get();
104110
$user = DB::collection('users')->where('name', 'John')->first();
105111

112+
If you did not change your default database connection, you will need to specify it when querying.
113+
114+
$user = DB::connection('mongodb')->collection('users')->get();
115+
106116
Read more about the query builder on http://laravel.com/docs/queries
107117

108118
Schema
@@ -170,7 +180,7 @@ Examples
170180
**And Statements**
171181

172182
$users = User::where('votes', '>', 100)->where('name', '=', 'John')->get();
173-
183+
174184
**Using Where In With An Array**
175185

176186
$users = User::whereIn('age', array(16, 18, 20))->get();
@@ -258,15 +268,15 @@ You may also specify additional columns to update:
258268

259269
When soft deleting a model, it is not actually removed from your database. Instead, a deleted_at timestamp is set on the record. To enable soft deletes for a model, apply the SoftDeletingTrait to the model:
260270

261-
use Jenssegers\Mongodb\Eloquent\SoftDeletingTrait;
271+
use Jenssegers\Mongodb\Eloquent\SoftDeletingTrait;
262272

263-
class User extends Eloquent {
273+
class User extends Eloquent {
264274

265-
use SoftDeletingTrait;
275+
use SoftDeletingTrait;
266276

267-
protected $dates = ['deleted_at'];
277+
protected $dates = ['deleted_at'];
268278

269-
}
279+
}
270280

271281
For more information check http://laravel.com/docs/eloquent#soft-deleting
272282

@@ -314,7 +324,40 @@ Matches documents that satisfy a JavaScript expression. For more information che
314324

315325
### Inserts, updates and deletes
316326

317-
All basic insert, update, delete and select methods should be implemented.
327+
Inserting, updating and deleting records works just like the original Eloquent.
328+
329+
**Saving a new model**
330+
331+
$user = new User;
332+
$user->name = 'John';
333+
$user->save();
334+
335+
You may also use the create method to save a new model in a single line:
336+
337+
User::create(array('name' => 'John'));
338+
339+
**Updating a model**
340+
341+
o update a model, you may retrieve it, change an attribute, and use the save method.
342+
343+
$user = User::first();
344+
$user->email = '[email protected]';
345+
$user->save();
346+
347+
*There is also support for upsert operations, check https://github.com/jenssegers/laravel-mongodb#mongodb-specific-operations*
348+
349+
**Deleting a model**
350+
351+
To delete a model, simply call the delete method on the instance:
352+
353+
$user = User::first();
354+
$user->delete();
355+
356+
Or deleting a model by its key:
357+
358+
User::destroy('517c43667db388101e00000f');
359+
360+
For more information about model manipulation, check http://laravel.com/docs/eloquent#insert-update-delete
318361

319362
### Dates
320363

@@ -386,7 +429,7 @@ Other relations are not yet supported, but may be added in the future. Read more
386429

387430
### EmbedsMany Relations
388431

389-
If you want to embed documents, rather than referencing them, you can use the `embedsMany` relation:
432+
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.
390433

391434
use Jenssegers\Mongodb\Model as Eloquent;
392435

@@ -399,52 +442,71 @@ If you want to embed documents, rather than referencing them, you can use the `e
399442

400443
}
401444

402-
Now we can access the user's books through the dynamic property:
445+
You access the embedded models through the dynamic property:
403446

404447
$books = User::first()->books;
405448

406-
When using embedded documents, there will also be an inverse relation available:
449+
The inverse relation is auto*magically* available, you don't need to define this reverse relation.
407450

408451
$user = $book->user;
409452

410-
Inserting and updating embedded documents works just like the `belongsTo` relation:
453+
Inserting and updating embedded models works similar to the `hasMany` relation:
411454

412455
$book = new Book(array('title' => 'A Game of Thrones'));
413456

414457
$user = User::first();
415458

416459
$book = $user->books()->save($book);
460+
// or
461+
$book = $user->books()->create(array('title' => 'A Game of Thrones'))
417462

418-
You can remove an embedded document by using the `destroy()` method:
463+
You can update embedded models using their `save` method (available since release 2.0.0):
419464

420465
$book = $user->books()->first();
421466

422-
$user->books()->destroy($book->_id);
467+
$book->title = 'A Game of Thrones';
468+
469+
$book->save();
470+
471+
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):
472+
473+
$book = $user->books()->first();
474+
475+
$book->delete();
423476
// or
424477
$user->books()->destroy($book);
425478

426-
If you want to add or remove embedded documents, without persistence, you can use the `associate` and `dissociate` methods. To write the changes to the database, save the parent object:
479+
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:
427480

428481
$user->books()->associate($book);
482+
429483
$user->save();
430484

431-
Again, you may override the conventional local key by passing a second argument to the embedsMany method:
485+
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:
432486

433487
return $this->embedsMany('Book', 'local_key');
434488

435-
When using embedded documents, they will be stored in a _relation attribute of the parent document. This attribute is hidden by default when using `toArray` or `toJson`. If you want the attribute to be exposed, add it to `$exposed` property definition to your model:
489+
Embedded relations will return a Collection of embedded items instead of a query builder. To allow a more query-like behavior, embedded relations will return a modified version of the Collection class with support for the following **additional** operations:
436490

437-
use Jenssegers\Mongodb\Model as Eloquent;
491+
- where($key, $operator, $value)
492+
- whereIn($key, $values) and whereNotIn($key, $values)
493+
- whereBetween($key, $values) and whereNotBetween($key, $values)
494+
- whereNull($key) and whereNotNull($key)
495+
- orderBy($key, $direction)
496+
- oldest() and latest()
497+
- limit($value)
498+
- offset($value)
499+
- skip($value)
438500

439-
class User extends Eloquent {
501+
This allows you to execute simple queries on the collection results:
440502

441-
protected $exposed = array('_books');
503+
$books = $user->books()->where('rating', '>', 5)->orderBy('title')->get();
442504

443-
}
505+
**Note:** Because embedded models are not stored in a separate collection, you can not query all of embedded models. You will always have to access them through the parent model.
444506

445507
### EmbedsOne Relations
446508

447-
There is also an EmbedsOne relation, which works similar to the EmbedsMany relation, but only stores one embedded model.
509+
The embedsOne relation is similar to the EmbedsMany relation, but only embeds a single model.
448510

449511
use Jenssegers\Mongodb\Model as Eloquent;
450512

@@ -457,17 +519,31 @@ There is also an EmbedsOne relation, which works similar to the EmbedsMany relat
457519

458520
}
459521

460-
Now we can access the book's author through the dynamic property:
522+
You access the embedded models through the dynamic property:
461523

462524
$author = Book::first()->author;
463525

464-
Inserting and updating embedded documents works just like the `embedsMany` relation:
526+
Inserting and updating embedded models works similar to the `hasOne` relation:
465527

466528
$author = new Author(array('name' => 'John Doe'));
467529

468530
$book = Books::first();
469531

470-
$author = $user->author()->save($author);
532+
$author = $book->author()->save($author);
533+
// or
534+
$author = $book->author()->create(array('name' => 'John Doe'));
535+
536+
You can update the embedded model using the `save` method (available since release 2.0.0):
537+
538+
$author = $book->author;
539+
540+
$author->name = 'Jane Doe';
541+
$author->save();
542+
543+
You can replace the embedded model with a new model like this:
544+
545+
$newAuthor = new Author(array('name' => 'Jane Doe'));
546+
$book->author()->save($newAuthor);
471547

472548
### MySQL Relations
473549

@@ -527,20 +603,32 @@ Optional: if you don't pass a closure to the raw method, the internal MongoColle
527603

528604
$model = User::raw()->findOne(array('age' => array('$lt' => 18)));
529605

530-
The MongoClient and MongoDB objects can be accessed like this:
606+
The internal MongoClient and MongoDB objects can be accessed like this:
531607

532608
$client = DB::getMongoClient();
533609
$db = DB::getMongoDB();
534610

535611
### MongoDB specific operations
536612

613+
**Cursor timeout**
614+
615+
To prevent MongoCursorTimeout exceptions, you can manually set a timeout value that will be applied to the cursor:
616+
617+
DB::collection('users')->timeout(-1)->get();
618+
537619
**Upsert**
538620

539621
Update or insert a document. Additional options for the update method are passed directly to the native update method.
540622

541623
DB::collection('users')->where('name', 'John')
542624
->update($data, array('upsert' => true));
543625

626+
**Projections**
627+
628+
You can apply projections to your queries using the `project` method.
629+
630+
DB::collection('items')->project(array('tags' => array('$slice' => 1)))->get();
631+
544632
**Push**
545633

546634
Add an items to an array.

src/Jenssegers/Mongodb/Auth/DatabaseReminderRepository.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
<?php namespace Jenssegers\Mongodb\Auth;
22

3+
use DateTime;
4+
use MongoDate;
5+
36
class DatabaseReminderRepository extends \Illuminate\Auth\Reminders\DatabaseReminderRepository {
47

8+
/**
9+
* Build the record payload for the table.
10+
*
11+
* @param string $email
12+
* @param string $token
13+
* @return array
14+
*/
15+
protected function getPayload($email, $token)
16+
{
17+
return array('email' => $email, 'token' => $token, 'created_at' => new MongoDate);
18+
}
19+
520
/**
621
* Determine if the reminder has expired.
722
*
@@ -10,16 +25,22 @@ class DatabaseReminderRepository extends \Illuminate\Auth\Reminders\DatabaseRemi
1025
*/
1126
protected function reminderExpired($reminder)
1227
{
13-
// Convert to array so that we can pass it to the parent method
14-
if (is_object($reminder))
28+
// Convert MongoDate to a date string.
29+
if ($reminder['created_at'] instanceof MongoDate)
1530
{
16-
$reminder = (array) $reminder;
31+
$date = new DateTime;
32+
33+
$date->setTimestamp($reminder['created_at']->sec);
34+
35+
$reminder['created_at'] = $date->format('Y-m-d H:i:s');
1736
}
1837

19-
// Convert the DateTime object that got saved to MongoDB
20-
if (is_array($reminder['created_at']))
38+
// Convert DateTime to a date string (backwards compatibility).
39+
elseif (is_array($reminder['created_at']))
2140
{
22-
$reminder['created_at'] = $reminder['created_at']['date'] + $reminder['created_at']['timezone'];
41+
$date = DateTime::__set_state($reminder['created_at']);
42+
43+
$reminder['created_at'] = $date->format('Y-m-d H:i:s');
2344
}
2445

2546
return parent::reminderExpired($reminder);

src/Jenssegers/Mongodb/Collection.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Collection {
2626
public function __construct(Connection $connection, MongoCollection $collection)
2727
{
2828
$this->connection = $connection;
29+
2930
$this->collection = $collection;
3031
}
3132

@@ -38,29 +39,34 @@ public function __construct(Connection $connection, MongoCollection $collection)
3839
*/
3940
public function __call($method, $parameters)
4041
{
42+
$query = array();
43+
4144
// Build the query string.
42-
$query = $parameters;
43-
foreach ($query as &$param)
45+
foreach ($parameters as $parameter)
4446
{
4547
try
4648
{
47-
$param = json_encode($param);
49+
$query[] = json_encode($parameter);
4850
}
4951
catch (Exception $e)
5052
{
51-
$param = '{...}';
53+
$query[] = '{...}';
5254
}
5355
}
5456

5557
$start = microtime(true);
5658

57-
// Execute the query.
5859
$result = call_user_func_array(array($this->collection, $method), $parameters);
5960

60-
// Log the query.
61-
$this->connection->logQuery(
62-
$this->collection->getName() . '.' . $method . '(' . join(',', $query) . ')',
63-
array(), $this->connection->getElapsedTime($start));
61+
// Once we have run the query we will calculate the time that it took to run and
62+
// then log the query, bindings, and execution time so we will report them on
63+
// the event that the developer needs them. We'll log time in milliseconds.
64+
$time = $this->connection->getElapsedTime($start);
65+
66+
// Convert the query to a readable string.
67+
$queryString = $this->collection->getName() . '.' . $method . '(' . join(',', $query) . ')';
68+
69+
$this->connection->logQuery($queryString, array(), $time);
6470

6571
return $result;
6672
}

0 commit comments

Comments
 (0)