Skip to content

Commit 835e3a8

Browse files
author
Fiete Börner
committed
Merge branch 'master' into aggregate-subdocument
2 parents ee73c96 + 78a5a05 commit 835e3a8

22 files changed

+180
-67
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,11 @@ And add a new mongodb connection:
116116
'driver' => 'mongodb',
117117
'host' => env('DB_HOST', 'localhost'),
118118
'port' => env('DB_PORT', 27017),
119-
'database' => env('DB_DATABASE', ''),
120-
'username' => env('DB_USERNAME', ''),
121-
'password' => env('DB_PASSWORD', ''),
119+
'database' => env('DB_DATABASE'),
120+
'username' => env('DB_USERNAME'),
121+
'password' => env('DB_PASSWORD'),
122122
'options' => [
123-
'db' => 'admin' // sets the authentication database required by mongo 3
123+
'database' => 'admin' // sets the authentication database required by mongo 3
124124
]
125125
],
126126
```
@@ -132,9 +132,9 @@ You can connect to multiple servers or replica sets with the following configura
132132
'driver' => 'mongodb',
133133
'host' => ['server1', 'server2'],
134134
'port' => env('DB_PORT', 27017),
135-
'database' => env('DB_DATABASE', ''),
136-
'username' => env('DB_USERNAME', ''),
137-
'password' => env('DB_PASSWORD', ''),
135+
'database' => env('DB_DATABASE'),
136+
'username' => env('DB_USERNAME'),
137+
'password' => env('DB_PASSWORD'),
138138
'options' => ['replicaSet' => 'replicaSetName']
139139
],
140140
```
@@ -620,7 +620,7 @@ class User extends Eloquent {
620620

621621
public function groups()
622622
{
623-
return $this->belongsToMany('Group', null, 'users', 'groups');
623+
return $this->belongsToMany('Group', null, 'user_ids', 'group_ids');
624624
}
625625

626626
}
@@ -804,7 +804,7 @@ class Message extends Eloquent {
804804
These expressions will be injected directly into the query.
805805

806806
```php
807-
User::whereRaw(['age' => array('$gt' => 30, '$lt' => 40]))->get();
807+
User::whereRaw(['age' => array('$gt' => 30, '$lt' => 40)])->get();
808808
```
809809

810810
You can also perform raw expressions on the internal MongoCollection object. If this is executed on the model class, it will return a collection of models. If this is executed on the query builder, it will return the original response.
File renamed without changes.

src/Jenssegers/Mongodb/Auth/DatabaseTokenRepository.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
use Illuminate\Auth\Passwords\DatabaseTokenRepository as BaseDatabaseTokenRepository;
44
use MongoDB\BSON\UTCDateTime;
5+
use DateTime;
6+
use DateTimeZone;
57

68
class DatabaseTokenRepository extends BaseDatabaseTokenRepository
79
{
@@ -28,11 +30,11 @@ protected function tokenExpired($token)
2830
// Convert UTCDateTime to a date string.
2931
if ($token['created_at'] instanceof UTCDateTime) {
3032
$date = $token['created_at']->toDateTime();
31-
$date->setTimezone(new \DateTimeZone(date_default_timezone_get()));
33+
$date->setTimezone(new DateTimeZone(date_default_timezone_get()));
3234
$token['created_at'] = $date->format('Y-m-d H:i:s');
3335
} elseif (is_array($token['created_at']) and isset($token['created_at']['date'])) {
3436
$date = new DateTime($token['created_at']['date'], new DateTimeZone(isset($token['created_at']['timezone']) ? $token['created_at']['timezone'] : 'UTC'));
35-
$date->setTimezone(date_default_timezone_get());
37+
$date->setTimezone(new DateTimeZone(date_default_timezone_get()));
3638
$token['created_at'] = $date->format('Y-m-d H:i:s');
3739
}
3840

src/Jenssegers/Mongodb/Collection.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Exception;
44
use MongoDB\Collection as MongoCollection;
5+
use MongoDB\BSON\ObjectID;
56

67
class Collection
78
{
@@ -48,7 +49,14 @@ public function __call($method, $parameters)
4849

4950
$query = [];
5051

51-
// Convert the query paramters to a json string.
52+
// Convert the query parameters to a json string.
53+
array_walk_recursive($parameters, function (&$item, $key) {
54+
if ($item instanceof ObjectID) {
55+
$item = (string) $item;
56+
}
57+
});
58+
59+
// Convert the query parameters to a json string.
5260
foreach ($parameters as $parameter) {
5361
try {
5462
$query[] = json_encode($parameter);

src/Jenssegers/Mongodb/Eloquent/Model.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
abstract class Model extends BaseModel
1616
{
17-
1817
use HybridRelations;
1918

2019
/**

src/Jenssegers/Mongodb/Eloquent/SoftDeletes.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
trait SoftDeletes
44
{
5-
65
use \Illuminate\Database\Eloquent\SoftDeletes;
76

87
/**

src/Jenssegers/Mongodb/Queue/MongoQueue.php

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,73 @@
22

33
use Carbon\Carbon;
44
use Illuminate\Queue\DatabaseQueue;
5+
use Illuminate\Queue\Jobs\DatabaseJob;
6+
use MongoDB\Operation\FindOneAndUpdate;
57

68
class MongoQueue extends DatabaseQueue
79
{
810
/**
9-
* Get the next available job for the queue.
11+
* Pop the next job off of the queue.
12+
*
13+
* @param string $queue
14+
* @return \Illuminate\Contracts\Queue\Job|null
15+
*/
16+
public function pop($queue = null)
17+
{
18+
$queue = $this->getQueue($queue);
19+
20+
if (!is_null($this->expire)) {
21+
$this->releaseJobsThatHaveBeenReservedTooLong($queue);
22+
}
23+
24+
if ($job = $this->getNextAvailableJobAndReserve($queue)) {
25+
return new DatabaseJob(
26+
$this->container, $this, $job, $queue
27+
);
28+
}
29+
}
30+
31+
/**
32+
* Get the next available job for the queue and mark it as reserved.
33+
*
34+
* When using multiple daemon queue listeners to process jobs there
35+
* is a possibility that multiple processes can end up reading the
36+
* same record before one has flagged it as reserved.
37+
*
38+
* This race condition can result in random jobs being run more then
39+
* once. To solve this we use findOneAndUpdate to lock the next jobs
40+
* record while flagging it as reserved at the same time.
41+
*
42+
* @param string|null $queue
1043
*
11-
* @param string|null $queue
1244
* @return \StdClass|null
1345
*/
14-
protected function getNextAvailableJob($queue)
46+
protected function getNextAvailableJobAndReserve($queue)
1547
{
16-
$job = $this->database->table($this->table)
17-
->lockForUpdate()
18-
->where('queue', $this->getQueue($queue))
19-
->where('reserved', 0)
20-
->where('available_at', '<=', $this->getTime())
21-
->orderBy('id', 'asc')
22-
->first();
48+
$job = $this->database->getCollection($this->table)->findOneAndUpdate(
49+
[
50+
'queue' => $this->getQueue($queue),
51+
'reserved' => 0,
52+
'available_at' => ['$lte' => $this->getTime()],
53+
54+
],
55+
[
56+
'$set' => [
57+
'reserved' => 1,
58+
'reserved_at' => $this->getTime(),
59+
],
60+
],
61+
[
62+
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
63+
'sort' => ['available_at' => 1],
64+
]
65+
);
2366

2467
if ($job) {
25-
$job = (object) $job;
2668
$job->id = $job->_id;
2769
}
2870

29-
return $job ?: null;
71+
return $job;
3072
}
3173

3274
/**
@@ -40,21 +82,21 @@ protected function releaseJobsThatHaveBeenReservedTooLong($queue)
4082
$expired = Carbon::now()->subSeconds($this->expire)->getTimestamp();
4183

4284
$reserved = $this->database->collection($this->table)
43-
->where('queue', $this->getQueue($queue))
44-
->where('reserved', 1)
45-
->where('reserved_at', '<=', $expired)->get();
85+
->where('queue', $this->getQueue($queue))
86+
->where('reserved', 1)
87+
->where('reserved_at', '<=', $expired)->get();
4688

4789
foreach ($reserved as $job) {
4890
$attempts = $job['attempts'] + 1;
4991
$this->releaseJob($job['_id'], $attempts);
5092
}
5193
}
52-
94+
5395
/**
5496
* Release the given job ID from reservation.
5597
*
5698
* @param string $id
57-
*
99+
* @param int $attempts
58100
* @return void
59101
*/
60102
protected function releaseJob($id, $attempts)
@@ -66,19 +108,6 @@ protected function releaseJob($id, $attempts)
66108
]);
67109
}
68110

69-
/**
70-
* Mark the given job ID as reserved.
71-
*
72-
* @param string $id
73-
* @return void
74-
*/
75-
protected function markJobAsReserved($id)
76-
{
77-
$this->database->collection($this->table)->where('_id', $id)->update([
78-
'reserved' => 1, 'reserved_at' => $this->getTime(),
79-
]);
80-
}
81-
82111
/**
83112
* Delete a reserved job from the queue.
84113
*
@@ -88,6 +117,6 @@ protected function markJobAsReserved($id)
88117
*/
89118
public function deleteReserved($queue, $id)
90119
{
91-
$this->database->table($this->table)->where('_id', $id)->delete();
120+
$this->database->collection($this->table)->where('_id', $id)->delete();
92121
}
93122
}

tests/AuthTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
class AuthTest extends TestCase
77
{
8-
98
public function tearDown()
109
{
1110
User::truncate();

tests/CollectionTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use Jenssegers\Mongodb\Connection;
4+
use Jenssegers\Mongodb\Collection;
5+
use MongoDB\Collection as MongoCollection;
6+
use MongoDB\BSON\ObjectID;
7+
8+
class CollectionTest extends TestCase
9+
{
10+
public function testExecuteMethodCall()
11+
{
12+
$return = ['foo' => 'bar'];
13+
$where = ['id' => new ObjectID('56f94800911dcc276b5723dd')];
14+
$time = 1.1;
15+
$queryString = 'name-collection.findOne({"id":"56f94800911dcc276b5723dd"})';
16+
17+
$mongoCollection = $this->getMockBuilder(MongoCollection::class)
18+
->disableOriginalConstructor()
19+
->getMock();
20+
21+
$mongoCollection->expects($this->once())->method('findOne')->with($where)->willReturn($return);
22+
$mongoCollection->expects($this->once())->method('getCollectionName')->willReturn('name-collection');
23+
24+
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
25+
$connection->expects($this->once())->method('logging')->willReturn(true);
26+
$connection->expects($this->once())->method('getElapsedTime')->willReturn($time);
27+
$connection->expects($this->once())->method('logQuery')->with($queryString, [], $time);
28+
29+
$collection = new Collection($connection, $mongoCollection);
30+
31+
$this->assertEquals($return, $collection->findOne($where));
32+
}
33+
}

tests/ConnectionTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
class ConnectionTest extends TestCase
44
{
5-
65
public function testConnection()
76
{
87
$connection = DB::connection('mongodb');

tests/EmbeddedRelationsTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
class EmbeddedRelationsTest extends TestCase
44
{
5-
65
public function tearDown()
76
{
87
Mockery::close();

tests/ModelTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
class ModelTest extends TestCase
44
{
5-
65
public function tearDown()
76
{
87
User::truncate();

tests/MysqlRelationsTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
class MysqlRelationsTest extends TestCase
44
{
5-
65
public function setUp()
76
{
87
parent::setUp();

tests/QueryBuilderTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
class QueryBuilderTest extends TestCase
77
{
8-
98
public function tearDown()
109
{
1110
DB::collection('users')->truncate();

tests/QueryTest.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
class QueryTest extends TestCase
44
{
5-
65
protected static $started = false;
76

87
public function setUp()
@@ -216,25 +215,25 @@ public function testExists()
216215
public function testSubquery()
217216
{
218217
$users = User::where('title', 'admin')->orWhere(function ($query) {
219-
$query->where('name', 'Tommy Toe')
218+
$query->where('name', 'Tommy Toe')
220219
->orWhere('name', 'Error');
221-
})
220+
})
222221
->get();
223222

224223
$this->assertEquals(5, count($users));
225224

226225
$users = User::where('title', 'user')->where(function ($query) {
227-
$query->where('age', 35)
226+
$query->where('age', 35)
228227
->orWhere('name', 'like', '%harry%');
229-
})
228+
})
230229
->get();
231230

232231
$this->assertEquals(2, count($users));
233232

234233
$users = User::where('age', 35)->orWhere(function ($query) {
235-
$query->where('title', 'admin')
234+
$query->where('title', 'admin')
236235
->orWhere('name', 'Error');
237-
})
236+
})
238237
->get();
239238

240239
$this->assertEquals(5, count($users));

0 commit comments

Comments
 (0)