Skip to content

Commit 6254f61

Browse files
committed
Adding basic relations
1 parent a7ece36 commit 6254f61

File tree

15 files changed

+250
-22
lines changed

15 files changed

+250
-22
lines changed

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Laravel Eloquent MongoDB [![Build Status](https://travis-ci.org/jenssegers/Larav
33

44
An Eloquent model that supports MongoDB, inspired by LMongo, but using the original Eloquent methods.
55

6-
*This model extends the original Eloquent model, so it uses exactly the same methods. Some advanced Eloquent features may not be working, but feel free to report them or issue a pull request!*
6+
*This model extends the original Eloquent model, so it uses exactly the same methods.*
77

88
For more information about Eloquent, check http://laravel.com/docs/eloquent.
99

@@ -189,6 +189,38 @@ You may also specify additional columns to update:
189189
User::where('age', '29')->increment('age', 1, array('group' => 'thirty something'));
190190
User::where('bmi', 30)->decrement('bmi', 1, array('category' => 'overweight'));
191191

192+
**Relations**
193+
194+
Support relations are:
195+
196+
- hasOne
197+
- hasMany
198+
- belongsTo
199+
200+
Example:
201+
202+
class User extends Eloquent {
203+
204+
public function items()
205+
{
206+
return $this->hasMany('Item');
207+
}
208+
209+
}
210+
211+
And the inverse relation:
212+
213+
class Item extends Eloquent {
214+
215+
public function user()
216+
{
217+
return $this->belongsTo('User');
218+
}
219+
220+
}
221+
222+
Other relations are not yet supported, but may be added in the future. Read more about these relations on http://four.laravel.com/docs/eloquent#relationships
223+
192224
**Raw Expressions**
193225

194226
These expressions will be injected directly into the query.

src/Jenssegers/Mongodb/Builder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function getFresh($columns = array('*'))
6464
if (is_null($this->columns)) $this->columns = $columns;
6565

6666
// Drop all columns if * is present
67-
if (in_array('*', $this->columns))
67+
if (in_array('*', $this->columns))
6868
{
6969
$this->columns = array();
7070
}

src/Jenssegers/Mongodb/Model.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
<?php namespace Jenssegers\Mongodb;
22

33
use Illuminate\Database\Eloquent\Collection;
4+
use Illuminate\Database\Eloquent\Relations\HasOne;
5+
use Illuminate\Database\Eloquent\Relations\HasMany;
6+
47
use Jenssegers\Mongodb\DatabaseManager as Resolver;
58
use Jenssegers\Mongodb\Builder as QueryBuilder;
9+
use Jenssegers\Mongodb\Relations\BelongsTo;
610

711
use DateTime;
812
use MongoId;
@@ -107,6 +111,69 @@ public function getTable()
107111
return parent::getTable();
108112
}
109113

114+
/**
115+
* Define a one-to-one relationship.
116+
*
117+
* @param string $related
118+
* @param string $foreignKey
119+
* @return \Illuminate\Database\Eloquent\Relations\HasOne
120+
*/
121+
public function hasOne($related, $foreignKey = null)
122+
{
123+
$foreignKey = $foreignKey ?: $this->getForeignKey();
124+
125+
$instance = new $related;
126+
127+
return new HasOne($instance->newQuery(), $this, $foreignKey);
128+
}
129+
130+
/**
131+
* Define a one-to-many relationship.
132+
*
133+
* @param string $related
134+
* @param string $foreignKey
135+
* @return \Illuminate\Database\Eloquent\Relations\HasMany
136+
*/
137+
public function hasMany($related, $foreignKey = null)
138+
{
139+
$foreignKey = $foreignKey ?: $this->getForeignKey();
140+
141+
$instance = new $related;
142+
143+
return new HasMany($instance->newQuery(), $this, $foreignKey);
144+
}
145+
146+
/**
147+
* Define an inverse one-to-one or many relationship.
148+
*
149+
* @param string $related
150+
* @param string $foreignKey
151+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
152+
*/
153+
public function belongsTo($related, $foreignKey = null)
154+
{
155+
list(, $caller) = debug_backtrace(false);
156+
157+
// If no foreign key was supplied, we can use a backtrace to guess the proper
158+
// foreign key name by using the name of the relationship function, which
159+
// when combined with an "_id" should conventionally match the columns.
160+
$relation = $caller['function'];
161+
162+
if (is_null($foreignKey))
163+
{
164+
$foreignKey = snake_case($relation).'_id';
165+
}
166+
167+
// Once we have the foreign key names, we'll just create a new Eloquent query
168+
// for the related models and returns the relationship instance which will
169+
// actually be responsible for retrieving and hydrating every relations.
170+
$instance = new $related;
171+
172+
$query = $instance->newQuery();
173+
174+
return new BelongsTo($query, $this, $foreignKey, $relation);
175+
}
176+
110177
/**
111178
* Get a new query builder instance for the connection.
112179
*
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php namespace Jenssegers\Mongodb\Relations;
2+
3+
class BelongsTo extends \Illuminate\Database\Eloquent\Relations\BelongsTo {
4+
5+
/**
6+
* Set the base constraints on the relation query.
7+
*
8+
* @return void
9+
*/
10+
public function addConstraints()
11+
{
12+
// For belongs to relationships, which are essentially the inverse of has one
13+
// or has many relationships, we need to actually query on the primary key
14+
// of the related models matching on the foreign key that's on a parent.
15+
$key = $this->related->getKeyName();
16+
17+
$this->query->where($key, '=', $this->parent->{$this->foreignKey});
18+
}
19+
20+
/**
21+
* Set the constraints for an eager load of the relation.
22+
*
23+
* @param array $models
24+
* @return void
25+
*/
26+
public function addEagerConstraints(array $models)
27+
{
28+
// We'll grab the primary key name of the related models since it could be set to
29+
// a non-standard name and not "id". We will then construct the constraint for
30+
// our eagerly loading query so it returns the proper models from execution.
31+
$key = $this->related->getKeyName();
32+
33+
$this->query->whereIn($key, $this->getEagerModelKeys($models));
34+
}
35+
36+
}

tests/CacheTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
<?php
2-
require_once('vendor/autoload.php');
3-
require_once('models/User.php');
42
require_once('tests/app.php');
53

64
use Jenssegers\Mongodb\Facades\DB;

tests/ConnectionTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?php
2-
require_once('vendor/autoload.php');
32
require_once('tests/app.php');
43

54
use Jenssegers\Mongodb\Facades\DB;

tests/ModelQueryTest.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
<?php
2-
require_once('vendor/autoload.php');
3-
require_once('models/User.php');
42
require_once('tests/app.php');
53

6-
use Jenssegers\Mongodb\Connection;
7-
use Jenssegers\Mongodb\Model;
8-
use Jenssegers\Mongodb\DatabaseManager;
9-
104
class ModelQueryTest extends PHPUnit_Framework_TestCase {
115

126
public function setUp()

tests/ModelTest.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
<?php
2-
require_once('vendor/autoload.php');
3-
require_once('models/User.php');
4-
require_once('models/Soft.php');
5-
require_once('models/Book.php');
62
require_once('tests/app.php');
73

8-
use Jenssegers\Mongodb\Connection;
9-
use Jenssegers\Mongodb\Model;
10-
use Jenssegers\Mongodb\DatabaseManager;
11-
124
class ModelTest extends PHPUnit_Framework_TestCase {
135

146
public function setUp() {}

tests/QueryTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?php
2-
require_once('vendor/autoload.php');
32
require_once('tests/app.php');
43

54
use Jenssegers\Mongodb\Facades\DB;

tests/RelationsTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
require_once('tests/app.php');
3+
4+
class RelationsTest extends PHPUnit_Framework_TestCase {
5+
6+
public function setUp() {
7+
}
8+
9+
public function tearDown()
10+
{
11+
User::truncate();
12+
Book::truncate();
13+
Item::truncate();
14+
Role::truncate();
15+
}
16+
17+
public function testHasMany()
18+
{
19+
$author = User::create(array('name' => 'George R. R. Martin'));
20+
Book::create(array('title' => 'A Game of Thrones', 'author_id' => $author->_id));
21+
Book::create(array('title' => 'A Clash of Kings', 'author_id' => $author->_id));
22+
23+
$books = $author->books;
24+
$this->assertEquals(2, count($books));
25+
26+
$user = User::create(array('name' => 'John Doe'));
27+
Item::create(array('type' => 'knife', 'user_id' => $user->_id));
28+
Item::create(array('type' => 'shield', 'user_id' => $user->_id));
29+
Item::create(array('type' => 'sword', 'user_id' => $user->_id));
30+
Item::create(array('type' => 'bag', 'user_id' => null));
31+
32+
$items = $user->items;
33+
$this->assertEquals(3, count($items));
34+
}
35+
36+
public function testBelongsTo()
37+
{
38+
$user = User::create(array('name' => 'George R. R. Martin'));
39+
Book::create(array('title' => 'A Game of Thrones', 'author_id' => $user->_id));
40+
$book = Book::create(array('title' => 'A Clash of Kings', 'author_id' => $user->_id));
41+
42+
$author = $book->author;
43+
$this->assertEquals('George R. R. Martin', $author->name);
44+
45+
$user = User::create(array('name' => 'John Doe'));
46+
$item = Item::create(array('type' => 'sword', 'user_id' => $user->_id));
47+
48+
$owner = $item->user;
49+
$this->assertEquals('John Doe', $owner->name);
50+
}
51+
52+
public function testHasOne()
53+
{
54+
$user = User::create(array('name' => 'John Doe'));
55+
Role::create(array('type' => 'admin', 'user_id' => $user->_id));
56+
57+
$role = $user->role;
58+
$this->assertEquals('admin', $role->type);
59+
}
60+
61+
}

tests/app.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<?php
2+
$loader = require 'vendor/autoload.php';
3+
$loader->add('', 'tests/models');
4+
25
use Jenssegers\Mongodb\Connection;
36
use Jenssegers\Mongodb\Model;
47
use Jenssegers\Mongodb\DatabaseManager;

tests/models/Book.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@ class Book extends Eloquent {
99
protected static $unguarded = true;
1010

1111
protected $primaryKey = 'title';
12+
13+
public function author()
14+
{
15+
return $this->belongsTo('User', 'author_id');
16+
}
1217
}

tests/models/Item.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
use Jenssegers\Mongodb\Model as Eloquent;
4+
5+
class Item extends Eloquent {
6+
7+
protected $collection = 'roles';
8+
9+
protected static $unguarded = true;
10+
11+
public function user()
12+
{
13+
return $this->belongsTo('User');
14+
}
15+
16+
}

tests/models/Role.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
use Jenssegers\Mongodb\Model as Eloquent;
4+
5+
class Role extends Eloquent {
6+
7+
protected $collection = 'roles';
8+
9+
protected static $unguarded = true;
10+
11+
public function user()
12+
{
13+
return $this->belongsTo('User');
14+
}
15+
16+
}

tests/models/User.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@ class User extends Eloquent {
88

99
protected static $unguarded = true;
1010

11-
public function phone()
11+
public function books()
1212
{
13-
return $this->hasOne('Phone');
13+
return $this->hasMany('Book', 'author_id');
14+
}
15+
16+
public function items()
17+
{
18+
return $this->hasMany('Item');
19+
}
20+
21+
public function role()
22+
{
23+
return $this->hasOne('Role');
1424
}
1525

1626
}

0 commit comments

Comments
 (0)