EmbeddedRelationsTest.php 36.2 KB
Newer Older
1
<?php
Simon Schaufelberger's avatar
Simon Schaufelberger committed
2
declare(strict_types=1);
3

Jens Segers's avatar
Jens Segers committed
4 5 6 7
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Events\Dispatcher;
use MongoDB\BSON\ObjectId;

Jens Segers's avatar
Jens Segers committed
8 9
class EmbeddedRelationsTest extends TestCase
{
Stas's avatar
Stas committed
10
    public function tearDown(): void
11 12 13 14 15 16 17 18 19 20 21 22 23 24
    {
        Mockery::close();

        User::truncate();
        Book::truncate();
        Item::truncate();
        Role::truncate();
        Client::truncate();
        Group::truncate();
        Photo::truncate();
    }

    public function testEmbedsManySave()
    {
25 26
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'London']);
27

Jens Segers's avatar
Jens Segers committed
28
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
29
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
30 31 32 33 34 35 36 37
        $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);
Stas's avatar
Stas committed
38 39
        $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($address), $address);
        $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address);
40

41
        $address = $user->addresses()->save($address);
42
        $address->unsetEventDispatcher();
43

44
        $this->assertNotNull($user->addresses);
Simon Schaufelberger's avatar
Simon Schaufelberger committed
45
        $this->assertInstanceOf(\Illuminate\Database\Eloquent\Collection::class, $user->addresses);
Pooya Parsa's avatar
Pooya Parsa committed
46
        $this->assertEquals(['London'], $user->addresses->pluck('city')->all());
Jens Segers's avatar
Jens Segers committed
47 48
        $this->assertInstanceOf(DateTime::class, $address->created_at);
        $this->assertInstanceOf(DateTime::class, $address->updated_at);
49
        $this->assertNotNull($address->_id);
50
        $this->assertIsString($address->_id);
51 52

        $raw = $address->getAttributes();
Jens Segers's avatar
Jens Segers committed
53
        $this->assertInstanceOf(ObjectId::class, $raw['_id']);
54

55
        $address = $user->addresses()->save(new Address(['city' => 'Paris']));
56 57

        $user = User::find($user->_id);
Pooya Parsa's avatar
Pooya Parsa committed
58
        $this->assertEquals(['London', 'Paris'], $user->addresses->pluck('city')->all());
59

Jens Segers's avatar
Jens Segers committed
60
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
61
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
62 63 64 65 66 67 68 69
        $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);
Stas's avatar
Stas committed
70 71
        $events->shouldReceive('dispatch')->once()->with('eloquent.updated: ' . get_class($address), $address);
        $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address);
72

73 74
        $address->city = 'New York';
        $user->addresses()->save($address);
75
        $address->unsetEventDispatcher();
76

Gabriel Caruso's avatar
Gabriel Caruso committed
77 78
        $this->assertCount(2, $user->addresses);
        $this->assertCount(2, $user->addresses()->get());
79 80
        $this->assertEquals(2, $user->addresses->count());
        $this->assertEquals(2, $user->addresses()->count());
Pooya Parsa's avatar
Pooya Parsa committed
81
        $this->assertEquals(['London', 'New York'], $user->addresses->pluck('city')->all());
82 83

        $freshUser = User::find($user->_id);
Pooya Parsa's avatar
Pooya Parsa committed
84
        $this->assertEquals(['London', 'New York'], $freshUser->addresses->pluck('city')->all());
85 86 87

        $address = $user->addresses->first();
        $this->assertEquals('London', $address->city);
Jens Segers's avatar
Jens Segers committed
88 89 90
        $this->assertInstanceOf(DateTime::class, $address->created_at);
        $this->assertInstanceOf(DateTime::class, $address->updated_at);
        $this->assertInstanceOf(User::class, $address->user);
91 92 93
        $this->assertEmpty($address->relationsToArray()); // prevent infinite loop

        $user = User::find($user->_id);
94
        $user->addresses()->save(new Address(['city' => 'Bruxelles']));
Pooya Parsa's avatar
Pooya Parsa committed
95
        $this->assertEquals(['London', 'New York', 'Bruxelles'], $user->addresses->pluck('city')->all());
96

97 98 99
        $address = $user->addresses[1];
        $address->city = "Manhattan";
        $user->addresses()->save($address);
Pooya Parsa's avatar
Pooya Parsa committed
100
        $this->assertEquals(['London', 'Manhattan', 'Bruxelles'], $user->addresses->pluck('city')->all());
101 102

        $freshUser = User::find($user->_id);
Pooya Parsa's avatar
Pooya Parsa committed
103
        $this->assertEquals(['London', 'Manhattan', 'Bruxelles'], $freshUser->addresses->pluck('city')->all());
104 105
    }

106 107 108 109
    // public function testEmbedsManySaveModel()
    // {
    //     $user = User::create(['name' => 'John Doe']);
    //     $address = new Address(['city' => 'London']);
110

Simon Schaufelberger's avatar
Simon Schaufelberger committed
111
    //     $address->setEventDispatcher($events = Mockery::mock(\Illuminate\Events\Dispatcher::class));
112 113
    //     $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);
Stas's avatar
Stas committed
114 115
    //     $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($address), $address);
    //     $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address);
116

117
    //     $address->save();
118

Simon Schaufelberger's avatar
Simon Schaufelberger committed
119
    //     $address->setEventDispatcher($events = Mockery::mock(\Illuminate\Events\Dispatcher::class));
120 121
    //     $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);
Stas's avatar
Stas committed
122 123
    //     $events->shouldReceive('dispatch')->once()->with('eloquent.updated: ' . get_class($address), $address);
    //     $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($address), $address);
124

125 126 127
    //     $address->city = 'Paris';
    //     $address->save();
    // }
128

129 130
    public function testEmbedsToArray()
    {
131 132
        $user = User::create(['name' => 'John Doe']);
        $user->addresses()->saveMany([new Address(['city' => 'London']), new Address(['city' => 'Bristol'])]);
133 134

        $array = $user->toArray();
Gabriel Caruso's avatar
Gabriel Caruso committed
135 136
        $this->assertArrayNotHasKey('_addresses', $array);
        $this->assertArrayHasKey('addresses', $array);
137 138
    }

139 140
    public function testEmbedsManyAssociate()
    {
141 142
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'London']);
143

144
        $user->addresses()->associate($address);
Pooya Parsa's avatar
Pooya Parsa committed
145
        $this->assertEquals(['London'], $user->addresses->pluck('city')->all());
146 147 148
        $this->assertNotNull($address->_id);

        $freshUser = User::find($user->_id);
Pooya Parsa's avatar
Pooya Parsa committed
149
        $this->assertEquals([], $freshUser->addresses->pluck('city')->all());
150 151 152

        $address->city = 'Londinium';
        $user->addresses()->associate($address);
Pooya Parsa's avatar
Pooya Parsa committed
153
        $this->assertEquals(['Londinium'], $user->addresses->pluck('city')->all());
154 155

        $freshUser = User::find($user->_id);
Pooya Parsa's avatar
Pooya Parsa committed
156
        $this->assertEquals([], $freshUser->addresses->pluck('city')->all());
157 158 159 160
    }

    public function testEmbedsManySaveMany()
    {
161 162
        $user = User::create(['name' => 'John Doe']);
        $user->addresses()->saveMany([new Address(['city' => 'London']), new Address(['city' => 'Bristol'])]);
Pooya Parsa's avatar
Pooya Parsa committed
163
        $this->assertEquals(['London', 'Bristol'], $user->addresses->pluck('city')->all());
164 165

        $freshUser = User::find($user->id);
Pooya Parsa's avatar
Pooya Parsa committed
166
        $this->assertEquals(['London', 'Bristol'], $freshUser->addresses->pluck('city')->all());
167 168 169 170
    }

    public function testEmbedsManyDuplicate()
    {
171 172
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'London']);
173 174 175
        $user->addresses()->save($address);
        $user->addresses()->save($address);
        $this->assertEquals(1, $user->addresses->count());
Pooya Parsa's avatar
Pooya Parsa committed
176
        $this->assertEquals(['London'], $user->addresses->pluck('city')->all());
177 178 179 180 181 182 183

        $user = User::find($user->id);
        $this->assertEquals(1, $user->addresses->count());

        $address->city = 'Paris';
        $user->addresses()->save($address);
        $this->assertEquals(1, $user->addresses->count());
Pooya Parsa's avatar
Pooya Parsa committed
184
        $this->assertEquals(['Paris'], $user->addresses->pluck('city')->all());
185

186
        $user->addresses()->create(['_id' => $address->_id, 'city' => 'Bruxelles']);
187
        $this->assertEquals(1, $user->addresses->count());
Pooya Parsa's avatar
Pooya Parsa committed
188
        $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all());
189 190 191 192
    }

    public function testEmbedsManyCreate()
    {
193 194
        $user = User::create([]);
        $address = $user->addresses()->create(['city' => 'Bruxelles']);
Jens Segers's avatar
Jens Segers committed
195
        $this->assertInstanceOf(Address::class, $address);
196
        $this->assertIsString($address->_id);
Pooya Parsa's avatar
Pooya Parsa committed
197
        $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all());
198 199

        $raw = $address->getAttributes();
Jens Segers's avatar
Jens Segers committed
200
        $this->assertInstanceOf(ObjectId::class, $raw['_id']);
201 202

        $freshUser = User::find($user->id);
Pooya Parsa's avatar
Pooya Parsa committed
203
        $this->assertEquals(['Bruxelles'], $freshUser->addresses->pluck('city')->all());
204

205 206
        $user = User::create([]);
        $address = $user->addresses()->create(['_id' => '', 'city' => 'Bruxelles']);
207
        $this->assertIsString($address->_id);
208 209

        $raw = $address->getAttributes();
Jens Segers's avatar
Jens Segers committed
210
        $this->assertInstanceOf(ObjectId::class, $raw['_id']);
211 212 213 214
    }

    public function testEmbedsManyCreateMany()
    {
215 216
        $user = User::create([]);
        list($bruxelles, $paris) = $user->addresses()->createMany([['city' => 'Bruxelles'], ['city' => 'Paris']]);
Jens Segers's avatar
Jens Segers committed
217
        $this->assertInstanceOf(Address::class, $bruxelles);
218
        $this->assertEquals('Bruxelles', $bruxelles->city);
Pooya Parsa's avatar
Pooya Parsa committed
219
        $this->assertEquals(['Bruxelles', 'Paris'], $user->addresses->pluck('city')->all());
220 221

        $freshUser = User::find($user->id);
Pooya Parsa's avatar
Pooya Parsa committed
222
        $this->assertEquals(['Bruxelles', 'Paris'], $freshUser->addresses->pluck('city')->all());
223 224
    }

Jens Segers's avatar
Jens Segers committed
225
    public function testEmbedsManyDestroy()
226
    {
227
        $user = User::create(['name' => 'John Doe']);
Jens Segers's avatar
Jens Segers committed
228 229 230 231 232
        $user->addresses()->saveMany([
            new Address(['city' => 'London']),
            new Address(['city' => 'Bristol']),
            new Address(['city' => 'Bruxelles']),
        ]);
233 234 235

        $address = $user->addresses->first();

Jens Segers's avatar
Jens Segers committed
236
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
237
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
238 239 240 241 242 243 244
        $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));
245

246
        $user->addresses()->destroy($address->_id);
Pooya Parsa's avatar
Pooya Parsa committed
247
        $this->assertEquals(['Bristol', 'Bruxelles'], $user->addresses->pluck('city')->all());
248

249 250
        $address->unsetEventDispatcher();

251 252
        $address = $user->addresses->first();
        $user->addresses()->destroy($address);
Pooya Parsa's avatar
Pooya Parsa committed
253
        $this->assertEquals(['Bruxelles'], $user->addresses->pluck('city')->all());
254

255 256
        $user->addresses()->create(['city' => 'Paris']);
        $user->addresses()->create(['city' => 'San Francisco']);
257 258

        $freshUser = User::find($user->id);
Pooya Parsa's avatar
Pooya Parsa committed
259
        $this->assertEquals(['Bruxelles', 'Paris', 'San Francisco'], $freshUser->addresses->pluck('city')->all());
260

Pooya Parsa's avatar
Pooya Parsa committed
261
        $ids = $user->addresses->pluck('_id');
262
        $user->addresses()->destroy($ids);
Pooya Parsa's avatar
Pooya Parsa committed
263
        $this->assertEquals([], $user->addresses->pluck('city')->all());
264 265

        $freshUser = User::find($user->id);
Pooya Parsa's avatar
Pooya Parsa committed
266
        $this->assertEquals([], $freshUser->addresses->pluck('city')->all());
267

Jens Segers's avatar
Jens Segers committed
268 269 270 271 272
        list($london, $bristol, $bruxelles) = $user->addresses()->saveMany([
            new Address(['city' => 'London']),
            new Address(['city' => 'Bristol']),
            new Address(['city' => 'Bruxelles']),
        ]);
273
        $user->addresses()->destroy([$london, $bruxelles]);
Pooya Parsa's avatar
Pooya Parsa committed
274
        $this->assertEquals(['Bristol'], $user->addresses->pluck('city')->all());
Jens Segers's avatar
Jens Segers committed
275
    }
276

277 278
    public function testEmbedsManyDelete()
    {
279
        $user = User::create(['name' => 'John Doe']);
Jens Segers's avatar
Jens Segers committed
280 281 282 283 284
        $user->addresses()->saveMany([
            new Address(['city' => 'London']),
            new Address(['city' => 'Bristol']),
            new Address(['city' => 'Bruxelles']),
        ]);
285 286 287

        $address = $user->addresses->first();

Jens Segers's avatar
Jens Segers committed
288
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
289
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
290 291 292 293 294 295 296
        $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));
297

298 299 300 301 302
        $address->delete();

        $this->assertEquals(2, $user->addresses()->count());
        $this->assertEquals(2, $user->addresses->count());

303 304
        $address->unsetEventDispatcher();

305 306 307 308 309 310 311 312
        $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());
    }

313 314
    public function testEmbedsManyDissociate()
    {
315 316
        $user = User::create([]);
        $cordoba = $user->addresses()->create(['city' => 'Cordoba']);
317 318 319 320 321 322 323 324 325 326

        $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()
    {
327 328
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'London']);
329 330

        $address = $user->addresses()->attach($address);
Pooya Parsa's avatar
Pooya Parsa committed
331
        $this->assertEquals(['London'], $user->addresses->pluck('city')->all());
332 333

        $user->addresses()->detach($address);
Pooya Parsa's avatar
Pooya Parsa committed
334
        $this->assertEquals([], $user->addresses->pluck('city')->all());
335 336 337 338
    }

    public function testEmbedsManyCreatingEventReturnsFalse()
    {
339 340
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'London']);
341

Jens Segers's avatar
Jens Segers committed
342
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
343
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
344 345 346 347 348 349 350 351
        $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);
352 353

        $this->assertFalse($user->addresses()->save($address));
354
        $address->unsetEventDispatcher();
355 356 357 358
    }

    public function testEmbedsManySavingEventReturnsFalse()
    {
359 360
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'Paris']);
361 362
        $address->exists = true;

Jens Segers's avatar
Jens Segers committed
363
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
364
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
365 366 367 368
        $events->shouldReceive('until')
            ->once()
            ->with('eloquent.saving: ' . get_class($address), $address)
            ->andReturn(false);
369 370

        $this->assertFalse($user->addresses()->save($address));
371
        $address->unsetEventDispatcher();
372 373 374 375
    }

    public function testEmbedsManyUpdatingEventReturnsFalse()
    {
376 377
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'New York']);
378 379
        $user->addresses()->save($address);

Jens Segers's avatar
Jens Segers committed
380
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
381
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
382 383 384 385 386 387 388 389
        $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);
390 391 392 393

        $address->city = 'Warsaw';

        $this->assertFalse($user->addresses()->save($address));
394
        $address->unsetEventDispatcher();
395 396 397 398
    }

    public function testEmbedsManyDeletingEventReturnsFalse()
    {
399 400
        $user = User::create(['name' => 'John Doe']);
        $user->addresses()->save(new Address(['city' => 'New York']));
401 402 403

        $address = $user->addresses->first();

Jens Segers's avatar
Jens Segers committed
404
        $address->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
405
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($address), Mockery::any());
Jens Segers's avatar
Jens Segers committed
406 407 408 409
        $events->shouldReceive('until')
            ->once()
            ->with('eloquent.deleting: ' . get_class($address), Mockery::mustBe($address))
            ->andReturn(false);
410 411

        $this->assertEquals(0, $user->addresses()->destroy($address));
Pooya Parsa's avatar
Pooya Parsa committed
412
        $this->assertEquals(['New York'], $user->addresses->pluck('city')->all());
413 414

        $address->unsetEventDispatcher();
415 416 417 418
    }

    public function testEmbedsManyFindOrContains()
    {
419 420 421
        $user = User::create(['name' => 'John Doe']);
        $address1 = $user->addresses()->save(new Address(['city' => 'New York']));
        $address2 = $user->addresses()->save(new Address(['city' => 'Paris']));
422 423 424 425 426 427 428 429 430 431 432 433 434

        $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()
    {
435 436 437
        $user1 = User::create(['name' => 'John Doe']);
        $user1->addresses()->save(new Address(['city' => 'New York']));
        $user1->addresses()->save(new Address(['city' => 'Paris']));
438

439 440 441
        $user2 = User::create(['name' => 'Jane Doe']);
        $user2->addresses()->save(new Address(['city' => 'Berlin']));
        $user2->addresses()->save(new Address(['city' => 'Paris']));
442 443 444

        $user = User::find($user1->id);
        $relations = $user->getRelations();
Gabriel Caruso's avatar
Gabriel Caruso committed
445
        $this->assertArrayNotHasKey('addresses', $relations);
446
        $this->assertArrayHasKey('addresses', $user->toArray());
447
        $this->assertIsArray($user->toArray()['addresses']);
448 449 450

        $user = User::with('addresses')->get()->first();
        $relations = $user->getRelations();
Gabriel Caruso's avatar
Gabriel Caruso committed
451
        $this->assertArrayHasKey('addresses', $relations);
452
        $this->assertEquals(2, $relations['addresses']->count());
453
        $this->assertArrayHasKey('addresses', $user->toArray());
454
        $this->assertIsArray($user->toArray()['addresses']);
455 456
    }

457
    public function testEmbedsManyDeleteAll()
458
    {
459 460 461
        $user1 = User::create(['name' => 'John Doe']);
        $user1->addresses()->save(new Address(['city' => 'New York']));
        $user1->addresses()->save(new Address(['city' => 'Paris']));
462

463 464 465
        $user2 = User::create(['name' => 'Jane Doe']);
        $user2->addresses()->save(new Address(['city' => 'Berlin']));
        $user2->addresses()->save(new Address(['city' => 'Paris']));
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

        $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()
    {
483
        $user = User::create(['name' => 'John Doe']);
Jens Segers's avatar
Jens Segers committed
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
        $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'),
        ]));
508

Pooya Parsa's avatar
Pooya Parsa committed
509
        $this->assertEquals(['Paris', 'Bruges', 'Brussels', 'Ghent'], $user->addresses()->pluck('city')->all());
Jens Segers's avatar
Jens Segers committed
510 511 512 513
        $this->assertEquals(['Bruges', 'Brussels', 'Ghent', 'Paris'], $user->addresses()
            ->sortBy('city')
            ->pluck('city')
            ->all());
Pooya Parsa's avatar
Pooya Parsa committed
514
        $this->assertEquals([], $user->addresses()->where('city', 'New York')->pluck('city')->all());
Jens Segers's avatar
Jens Segers committed
515 516 517 518 519 520 521 522 523
        $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());
524

525
        $results = $user->addresses->first();
Jens Segers's avatar
Jens Segers committed
526
        $this->assertInstanceOf(Address::class, $results);
527

528
        $results = $user->addresses()->where('country', 'Belgium');
Jens Segers's avatar
Jens Segers committed
529
        $this->assertInstanceOf(Collection::class, $results);
530 531
        $this->assertEquals(3, $results->count());

532
        $results = $user->addresses()->whereIn('visited', [7, 13]);
533
        $this->assertEquals(2, $results->count());
534 535 536 537
    }

    public function testEmbedsOne()
    {
538 539
        $user = User::create(['name' => 'John Doe']);
        $father = new User(['name' => 'Mark Doe']);
540

Jens Segers's avatar
Jens Segers committed
541
        $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
542
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any());
Jens Segers's avatar
Jens Segers committed
543 544 545 546 547 548 549 550
        $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);
Stas's avatar
Stas committed
551 552
        $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($father), $father);
        $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father);
553

554
        $father = $user->father()->save($father);
555
        $father->unsetEventDispatcher();
556

557
        $this->assertNotNull($user->father);
558
        $this->assertEquals('Mark Doe', $user->father->name);
Jens Segers's avatar
Jens Segers committed
559 560
        $this->assertInstanceOf(DateTime::class, $father->created_at);
        $this->assertInstanceOf(DateTime::class, $father->updated_at);
561
        $this->assertNotNull($father->_id);
562
        $this->assertIsString($father->_id);
563 564

        $raw = $father->getAttributes();
Jens Segers's avatar
Jens Segers committed
565
        $this->assertInstanceOf(ObjectId::class, $raw['_id']);
566

Jens Segers's avatar
Jens Segers committed
567
        $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
568
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any());
Jens Segers's avatar
Jens Segers committed
569 570 571 572 573 574 575 576
        $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);
Stas's avatar
Stas committed
577 578
        $events->shouldReceive('dispatch')->once()->with('eloquent.updated: ' . get_class($father), $father);
        $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father);
579

580 581
        $father->name = 'Tom Doe';
        $user->father()->save($father);
582
        $father->unsetEventDispatcher();
583

584
        $this->assertNotNull($user->father);
585 586
        $this->assertEquals('Tom Doe', $user->father->name);

587
        $father = new User(['name' => 'Jim Doe']);
588

Jens Segers's avatar
Jens Segers committed
589
        $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
590
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any());
Jens Segers's avatar
Jens Segers committed
591 592 593 594 595 596 597 598
        $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);
Stas's avatar
Stas committed
599 600
        $events->shouldReceive('dispatch')->once()->with('eloquent.created: ' . get_class($father), $father);
        $events->shouldReceive('dispatch')->once()->with('eloquent.saved: ' . get_class($father), $father);
601

602
        $father = $user->father()->save($father);
603
        $father->unsetEventDispatcher();
604

605
        $this->assertNotNull($user->father);
606 607 608
        $this->assertEquals('Jim Doe', $user->father->name);
    }

609 610
    public function testEmbedsOneAssociate()
    {
611 612
        $user = User::create(['name' => 'John Doe']);
        $father = new User(['name' => 'Mark Doe']);
613

Jens Segers's avatar
Jens Segers committed
614
        $father->setEventDispatcher($events = Mockery::mock(Dispatcher::class));
Stas's avatar
Stas committed
615
        $events->shouldReceive('dispatch')->with('eloquent.retrieved: ' . get_class($father), Mockery::any());
616 617
        $events->shouldReceive('until')->times(0)->with('eloquent.saving: ' . get_class($father), $father);

618
        $father = $user->father()->associate($father);
619
        $father->unsetEventDispatcher();
620

621
        $this->assertNotNull($user->father);
622 623 624
        $this->assertEquals('Mark Doe', $user->father->name);
    }

Jens Segers's avatar
Jens Segers committed
625 626 627 628 629 630
    public function testEmbedsOneNullAssociation()
    {
        $user = User::create();
        $this->assertNull($user->father);
    }

631 632
    public function testEmbedsOneDelete()
    {
633 634
        $user = User::create(['name' => 'John Doe']);
        $father = $user->father()->save(new User(['name' => 'Mark Doe']));
635 636 637 638 639

        $user->father()->delete();
        $this->assertNull($user->father);
    }

640 641
    public function testEmbedsManyToArray()
    {
Simon Schaufelberger's avatar
Simon Schaufelberger committed
642
        /** @var User $user */
643 644 645 646
        $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']));
647 648

        $array = $user->toArray();
649
        $this->assertArrayHasKey('addresses', $array);
650
        $this->assertIsArray($array['addresses']);
651 652
    }

653 654
    public function testEmbeddedSave()
    {
Simon Schaufelberger's avatar
Simon Schaufelberger committed
655
        /** @var User $user */
656
        $user = User::create(['name' => 'John Doe']);
Simon Schaufelberger's avatar
Simon Schaufelberger committed
657
        /** @var \Address $address */
658 659
        $address = $user->addresses()->create(['city' => 'New York']);
        $father = $user->father()->create(['name' => 'Mark Doe']);
660 661 662 663 664 665 666 667 668 669 670 671 672

        $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);
Jens Segers's avatar
Jens Segers committed
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688

        $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);
689 690
    }

691 692
    public function testNestedEmbedsOne()
    {
693 694 695 696
        $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']);
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

        $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()
    {
721 722 723 724 725 726
        $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']);
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742

        $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()
    {
743 744 745 746
        $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']);
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763

        $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);
    }

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    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);
    }

Jens Segers's avatar
Jens Segers committed
814 815
    public function testDoubleAssociate()
    {
816 817
        $user = User::create(['name' => 'John Doe']);
        $address = new Address(['city' => 'Paris']);
Jens Segers's avatar
Jens Segers committed
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833

        $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());
    }

Jens Segers's avatar
Jens Segers committed
834 835
    public function testSaveEmptyModel()
    {
836
        $user = User::create(['name' => 'John Doe']);
Jens Segers's avatar
Jens Segers committed
837 838
        $user->addresses()->save(new Address);
        $this->assertNotNull($user->addresses);
Jens Segers's avatar
Jens Segers committed
839
        $this->assertEquals(1, $user->addresses()->count());
Jens Segers's avatar
Jens Segers committed
840 841
    }

Jens Segers's avatar
Jens Segers committed
842 843
    public function testIncrementEmbedded()
    {
844 845
        $user = User::create(['name' => 'John Doe']);
        $address = $user->addresses()->create(['city' => 'New York', 'visited' => 5]);
Jens Segers's avatar
Jens Segers committed
846 847 848 849 850 851 852

        $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);
853

854 855 856
        $user = User::where('name', 'John Doe')->first();
        $address = $user->addresses()->first();

857 858
        $address->decrement('visited');
        $this->assertEquals(5, $address->visited);
859
        $this->assertEquals(5, $user->addresses()->first()->visited);
860 861 862

        $user = User::where('name', 'John Doe')->first();
        $this->assertEquals(5, $user->addresses()->first()->visited);
Jens Segers's avatar
Jens Segers committed
863 864
    }

865 866
    public function testPaginateEmbedsMany()
    {
867 868 869 870
        $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']));
871 872 873

        $results = $user->addresses()->paginate(2);
        $this->assertEquals(2, $results->count());
874
        $this->assertEquals(3, $results->total());
875
    }
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

    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());
    }
895
}