Skip to content

Commit c0207f6

Browse files
committed
* Bugfix: related model was loaded into current model attributes array. Now it loads into current model relations array.
* PHPUnit tests added.
1 parent 684fc68 commit c0207f6

File tree

7 files changed

+333
-2
lines changed

7 files changed

+333
-2
lines changed

CHANGELOG

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
2014-11-13, v1.0.2
5+
------------------
6+
7+
* Bugfix: related model was loaded into current model attributes array. Now it loads into current model relations array.
8+
* PHPUnit tests added.
9+
410
2014-11-13, v1.0.1
511
------------------
612

composer.json

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"php": ">=5.4.0",
2020
"illuminate/support": "4.2.*"
2121
},
22+
"require-dev": {
23+
"illuminate/database": "4.2.*"
24+
},
2225
"autoload": {
2326
"psr-0": {
2427
"SleepingOwl\\WithJoin": "src/"

src/SleepingOwl/WithJoin/WithJoinTrait.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ public function newFromBuilder($attributes = [])
2424
Arr::set($foreignData, $key, $value);
2525
}
2626
}
27+
$instance = parent::newFromBuilder($attributes);
2728
foreach ($foreignData as $relation => $data)
2829
{
2930
/** @var BelongsTo $relationInstance */
3031
$relationInstance = $this->$relation();
3132
$foreign = $relationInstance->getRelated()->newFromBuilder($data);
32-
$attributes[$relation] = $foreign;
33+
$instance->setRelation($relation, $foreign);
3334
}
34-
return parent::newFromBuilder($attributes);
35+
return $instance;
3536
}
3637

3738
/**

tests/TestCase.php

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
use Illuminate\Database\Capsule\Manager as Capsule;
4+
5+
abstract class TestCase extends PHPUnit_Framework_TestCase
6+
{
7+
/**
8+
* @var Capsule
9+
*/
10+
protected $capsule;
11+
12+
protected function setUp()
13+
{
14+
parent::setUp();
15+
$this->createConnection();
16+
$this->fillWithData();
17+
$this->capsule->getConnection()->flushQueryLog();
18+
}
19+
20+
protected function tearDown()
21+
{
22+
//var_dump($this->capsule->getConnection()->getQueryLog());
23+
parent::tearDown();
24+
$this->eraseData();
25+
}
26+
27+
protected function fillWithData()
28+
{
29+
$foos = [
30+
'First Foo',
31+
'Second Foo',
32+
'Third Foo'
33+
];
34+
foreach ($foos as $foo)
35+
{
36+
Foo::create([
37+
'title' => $foo
38+
]);
39+
}
40+
41+
$bazs = [
42+
'First Baz',
43+
'Second Baz',
44+
'Third Baz'
45+
];
46+
foreach ($bazs as $baz)
47+
{
48+
Baz::create([
49+
'title' => $baz
50+
]);
51+
}
52+
53+
$bars = [
54+
[
55+
'foo_id' => 1,
56+
'baz_id' => 1,
57+
'title' => 'First Foo First Baz Bar'
58+
],
59+
[
60+
'foo_id' => 1,
61+
'baz_id' => 2,
62+
'title' => 'First Foo Second Baz Bar'
63+
]
64+
];
65+
foreach ($bars as $bar)
66+
{
67+
Bar::create($bar);
68+
}
69+
70+
$boms = [
71+
[
72+
'bar_id' => 1,
73+
'title' => 'First Bar Bom'
74+
],
75+
[
76+
'bar_id' => 2,
77+
'title' => 'Second Bar Bom'
78+
]
79+
];
80+
foreach ($boms as $bom)
81+
{
82+
Bom::create($bom);
83+
}
84+
85+
}
86+
87+
protected function eraseData()
88+
{
89+
Foo::truncate();
90+
Bar::truncate();
91+
Baz::truncate();
92+
Bom::truncate();
93+
}
94+
95+
protected function createConnection()
96+
{
97+
$this->capsule = new Capsule;
98+
99+
$this->capsule->addConnection([
100+
'driver' => 'sqlite',
101+
'database' => __DIR__ . '/db/testing.sqlite',
102+
'prefix' => '',
103+
]);
104+
105+
$this->capsule->setFetchMode(PDO::FETCH_CLASS);
106+
107+
$this->capsule->setAsGlobal();
108+
109+
$this->capsule->bootEloquent();
110+
}
111+
112+
protected function assertQuery($query)
113+
{
114+
$log = $this->capsule->getConnection()->getQueryLog();
115+
116+
foreach ($log as $logEntry)
117+
{
118+
if ($logEntry['query'] === $query)
119+
{
120+
$this->assertTrue(true);
121+
return;
122+
}
123+
}
124+
$this->assertTrue(false, 'Query [' . $query . '] wasn`t called');
125+
}
126+
127+
protected function assertQueryCount($expectedCount)
128+
{
129+
$log = $this->capsule->getConnection()->getQueryLog();
130+
$this->assertEquals($expectedCount, count($log), 'Expected ' . $expectedCount . ' queries, got ' . count($log));
131+
}
132+
133+
}
134+
135+
class Cache
136+
{
137+
138+
public static function get($key)
139+
{
140+
$filepath = __DIR__ . '/db/columns.dat';
141+
$cache = [];
142+
if (file_exists($filepath))
143+
{
144+
$cache = unserialize(file_get_contents($filepath));
145+
}
146+
if (isset($cache[$key]))
147+
{
148+
return $cache[$key];
149+
}
150+
return null;
151+
}
152+
153+
public static function put($key, $data)
154+
{
155+
$filepath = __DIR__ . '/db/columns.dat';
156+
$cache = [];
157+
if (file_exists($filepath))
158+
{
159+
$cache = unserialize(file_get_contents($filepath));
160+
}
161+
$cache[$key] = $data;
162+
file_put_contents($filepath, serialize($cache));
163+
}
164+
}

tests/WithJoinEloquentBuilderTest.php

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?php
2+
3+
class Foo extends \Illuminate\Database\Eloquent\Model
4+
{
5+
protected $fillable = [
6+
'title'
7+
];
8+
}
9+
10+
class Baz extends \Illuminate\Database\Eloquent\Model
11+
{
12+
protected $fillable = [
13+
'title'
14+
];
15+
}
16+
17+
class Bar extends \Illuminate\Database\Eloquent\Model
18+
{
19+
use \SleepingOwl\WithJoin\WithJoinTrait;
20+
21+
protected $fillable = [
22+
'title',
23+
'foo_id',
24+
'baz_id'
25+
];
26+
27+
public function foo()
28+
{
29+
return $this->belongsTo('Foo');
30+
}
31+
32+
public function baz()
33+
{
34+
return $this->belongsTo('Baz');
35+
}
36+
37+
}
38+
39+
class Bom extends \Illuminate\Database\Eloquent\Model
40+
{
41+
use \SleepingOwl\WithJoin\WithJoinTrait;
42+
43+
protected $fillable = [
44+
'title',
45+
'bar_id'
46+
];
47+
48+
public function bar()
49+
{
50+
return $this->belongsTo('Bar');
51+
}
52+
53+
}
54+
55+
class WithJoinTest extends TestCase
56+
{
57+
58+
/** @test */
59+
public function it_doesnt_break_default_behaviour()
60+
{
61+
$bar = Bar::with('foo')->find(1);
62+
$this->assertEquals('First Foo First Baz Bar', $bar->title);
63+
$this->assertEquals('First Foo', $bar->foo->title);
64+
65+
$this->assertQuery('select "bars".* from "bars" where "bars"."id" = ? limit 1');
66+
$this->assertQuery('select * from "foos" where "foos"."id" in (?)');
67+
68+
$this->assertQueryCount(2);
69+
}
70+
71+
/** @test */
72+
public function it_replaces_subqueries_with_left_join_using_references()
73+
{
74+
$bar = Bar::with('foo')->references('foo')->find(1);
75+
$this->assertEquals('First Foo First Baz Bar', $bar->title);
76+
$this->assertEquals('First Foo', $bar->foo->title);
77+
78+
$this->assertQuery('select "foo"."id" as "__f__foo.id", "foo"."title" as "__f__foo.title", "foo"."created_at" as "__f__foo.created_at", "foo"."updated_at" as "__f__foo.updated_at", "bars".* from "bars" left join "foos" as "foo" on "foo"."id" = "bars"."foo_id" where "bars"."id" = ? limit 1');
79+
80+
$this->assertQueryCount(1);
81+
}
82+
83+
/** @test */
84+
public function it_replaces_subqueries_with_left_join_using_includes()
85+
{
86+
$bar = Bar::includes('foo')->find(1);
87+
$this->assertEquals('First Foo First Baz Bar', $bar->title);
88+
$this->assertEquals('First Foo', $bar->foo->title);
89+
90+
$this->assertQuery('select "foo"."id" as "__f__foo.id", "foo"."title" as "__f__foo.title", "foo"."created_at" as "__f__foo.created_at", "foo"."updated_at" as "__f__foo.updated_at", "bars".* from "bars" left join "foos" as "foo" on "foo"."id" = "bars"."foo_id" where "bars"."id" = ? limit 1');
91+
92+
$this->assertQueryCount(1);
93+
}
94+
95+
/** @test */
96+
public function it_joins_table_by_relation_name_as_alias()
97+
{
98+
$bar = Bar::includes('foo')->where('foo.id', '=', 1)->first();
99+
$this->assertEquals('First Foo First Baz Bar', $bar->title);
100+
$this->assertEquals('First Foo', $bar->foo->title);
101+
102+
$this->assertQuery('select "foo"."id" as "__f__foo.id", "foo"."title" as "__f__foo.title", "foo"."created_at" as "__f__foo.created_at", "foo"."updated_at" as "__f__foo.updated_at", "bars".* from "bars" left join "foos" as "foo" on "foo"."id" = "bars"."foo_id" where "foo"."id" = ? limit 1');
103+
104+
$this->assertQueryCount(1);
105+
}
106+
107+
/** @test */
108+
public function it_support_multiple_flat_joins()
109+
{
110+
$bar = Bar::includes('foo', 'baz')->where('foo.id', '=', 1)->where('baz.id', '=', 2)->first();
111+
$this->assertEquals('First Foo Second Baz Bar', $bar->title);
112+
$this->assertEquals('First Foo', $bar->foo->title);
113+
$this->assertEquals('Second Baz', $bar->baz->title);
114+
115+
$this->assertQuery('select "foo"."id" as "__f__foo.id", "foo"."title" as "__f__foo.title", "foo"."created_at" as "__f__foo.created_at", "foo"."updated_at" as "__f__foo.updated_at", "baz"."id" as "__f__baz.id", "baz"."title" as "__f__baz.title", "baz"."created_at" as "__f__baz.created_at", "baz"."updated_at" as "__f__baz.updated_at", "bars".* from "bars" left join "foos" as "foo" on "foo"."id" = "bars"."foo_id" left join "bazs" as "baz" on "baz"."id" = "bars"."baz_id" where "foo"."id" = ? and "baz"."id" = ? limit 1');
116+
117+
$this->assertQueryCount(1);
118+
}
119+
120+
/** @test */
121+
public function it_can_combine_with_and_joins()
122+
{
123+
$bar = Bar::with('foo', 'baz')->references('baz')->where('baz.id', '=', 2)->first();
124+
$this->assertEquals('First Foo Second Baz Bar', $bar->title);
125+
$this->assertEquals('First Foo', $bar->foo->title);
126+
$this->assertEquals('Second Baz', $bar->baz->title);
127+
128+
$this->assertQuery('select "baz"."id" as "__f__baz.id", "baz"."title" as "__f__baz.title", "baz"."created_at" as "__f__baz.created_at", "baz"."updated_at" as "__f__baz.updated_at", "bars".* from "bars" left join "bazs" as "baz" on "baz"."id" = "bars"."baz_id" where "baz"."id" = ? limit 1');
129+
$this->assertQuery('select * from "foos" where "foos"."id" in (?)');
130+
131+
$this->assertQueryCount(2);
132+
}
133+
134+
/** @test */
135+
public function it_supports_nested_relations()
136+
{
137+
$bom = Bom::includes('bar.foo')->where('foo.id', '=', 1)->first();
138+
$this->assertEquals('First Bar Bom', $bom->title);
139+
$this->assertEquals('First Foo First Baz Bar', $bom->bar->title);
140+
$this->assertEquals('First Foo', $bom->bar->foo->title);
141+
142+
$this->assertQuery('select "bar"."id" as "__f__bar.id", "bar"."title" as "__f__bar.title", "bar"."foo_id" as "__f__bar.foo_id", "bar"."created_at" as "__f__bar.created_at", "bar"."updated_at" as "__f__bar.updated_at", "bar"."baz_id" as "__f__bar.baz_id", "foo"."id" as "__f__bar.__f__foo.id", "foo"."title" as "__f__bar.__f__foo.title", "foo"."created_at" as "__f__bar.__f__foo.created_at", "foo"."updated_at" as "__f__bar.__f__foo.updated_at", "boms".* from "boms" left join "bars" as "bar" on "bar"."id" = "boms"."bar_id" left join "foos" as "foo" on "foo"."id" = "bar"."foo_id" where "foo"."id" = ? limit 1');
143+
144+
$this->assertQueryCount(1);
145+
}
146+
147+
/** @test */
148+
public function it_stores_related_model_in_relations_field()
149+
{
150+
$bom = Bom::includes('bar')->where('bar.id', '=', 1)->first();
151+
$this->assertArrayNotHasKey('bar', $bom->attributesToArray());
152+
$this->assertInstanceOf('Bar', $bom->getRelation('bar'));
153+
}
154+
155+
}
156+

tests/db/columns.dat

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a:3:{s:13:"_columns_foos";a:4:{i:0;s:2:"id";i:1;s:5:"title";i:2;s:10:"created_at";i:3;s:10:"updated_at";}s:13:"_columns_bazs";a:4:{i:0;s:2:"id";i:1;s:5:"title";i:2;s:10:"created_at";i:3;s:10:"updated_at";}s:13:"_columns_bars";a:6:{i:0;s:2:"id";i:1;s:5:"title";i:2;s:6:"foo_id";i:3;s:10:"created_at";i:4;s:10:"updated_at";i:5;s:6:"baz_id";}}

tests/db/testing.sqlite

6 KB
Binary file not shown.

0 commit comments

Comments
 (0)