Skip to content

Commit f249b3b

Browse files
committed
Merge pull request #164 from duxet/embedded-events
Trigger events in embedded models
2 parents d7ac7b0 + 21d973a commit f249b3b

File tree

4 files changed

+176
-5
lines changed

4 files changed

+176
-5
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ before_script:
1818
- mysql -e 'create database unittest;'
1919
- composer self-update
2020
- composer require satooshi/php-coveralls:dev-master
21+
- composer require mockery/mockery:dev-master
2122
- composer install --dev --no-interaction
2223

2324
script:

src/Jenssegers/Mongodb/Connection.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ public function getElapsedTime($start)
173173
return parent::getElapsedTime($start);
174174
}
175175

176+
/**
177+
* Get the PDO driver name.
178+
*
179+
* @return string
180+
*/
181+
public function getDriverName()
182+
{
183+
return '';
184+
}
185+
176186
/**
177187
* Dynamically pass methods to the connection.
178188
*

src/Jenssegers/Mongodb/Relations/EmbedsMany.php

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,24 @@ public function get()
133133
return $this->getResults();
134134
}
135135

136+
/**
137+
* Get the results with given ids.
138+
*
139+
* @param array $ids
140+
* @return \Illuminate\Database\Eloquent\Collection
141+
*/
142+
public function find(array $ids)
143+
{
144+
$documents = $this->getEmbeddedRecords();
145+
$primaryKey = $this->related->getKeyName();
146+
147+
$documents = array_filter($documents, function ($document) use($primaryKey, $ids) {
148+
return in_array($document[$primaryKey], $ids);
149+
});
150+
151+
return $this->toCollection($documents);
152+
}
153+
136154
/**
137155
* Attach a model instance to the parent model.
138156
*
@@ -141,19 +159,29 @@ public function get()
141159
*/
142160
public function save(Model $model)
143161
{
162+
if ($this->fireModelEvent($model, 'saving') === false) return false;
163+
144164
$this->updateTimestamps($model);
145165

146166
// Insert a new document.
147167
if ( ! $model->exists)
148168
{
149-
return $this->performInsert($model);
169+
$result = $this->performInsert($model);
150170
}
151171

152172
// Update an existing document.
153173
else
154174
{
155-
return $this->performUpdate($model);
175+
$result = $this->performUpdate($model);
156176
}
177+
178+
if ($result)
179+
{
180+
$this->fireModelEvent($result, 'saved', false);
181+
return $result;
182+
}
183+
184+
return false;
157185
}
158186

159187
/**
@@ -186,13 +214,21 @@ public function associate(Model $model)
186214
*/
187215
protected function performInsert(Model $model)
188216
{
217+
if ($this->fireModelEvent($model, 'creating') === false) return false;
218+
189219
// Insert the related model in the parent instance
190220
$this->associateNew($model);
191221

192222
// Push the document to the database.
193223
$result = $this->query->push($this->localKey, $model->getAttributes(), true);
194224

195-
return $result ? $model : false;
225+
if ($result)
226+
{
227+
$this->fireModelEvent($model, 'created', false);
228+
return $model;
229+
}
230+
231+
return false;
196232
}
197233

198234
/**
@@ -203,6 +239,8 @@ protected function performInsert(Model $model)
203239
*/
204240
protected function performUpdate(Model $model)
205241
{
242+
if ($this->fireModelEvent($model, 'updating') === false) return false;
243+
206244
// Update the related model in the parent instance
207245
$this->associateExisting($model);
208246

@@ -213,7 +251,13 @@ protected function performUpdate(Model $model)
213251
$result = $this->query->where($this->localKey . '.' . $model->getKeyName(), $id)
214252
->update(array($this->localKey . '.$' => $model->getAttributes()));
215253

216-
return $result ? $model : false;
254+
if ($result)
255+
{
256+
$this->fireModelEvent($model, 'updated', false);
257+
return $model;
258+
}
259+
260+
return false;
217261
}
218262

219263
/**
@@ -327,12 +371,23 @@ public function destroy($ids = array())
327371
{
328372
$ids = $this->getIdsArrayFrom($ids);
329373

374+
$models = $this->find($ids);
375+
376+
$ids = array();
377+
330378
$primaryKey = $this->related->getKeyName();
331379

332380
// Pull the documents from the database.
333-
foreach ($ids as $id)
381+
foreach ($models as $model)
334382
{
383+
if ($this->fireModelEvent($model, 'deleting') === false) continue;
384+
385+
$id = $model->getKey();
335386
$this->query->pull($this->localKey, array($primaryKey => $this->getForeignKeyValue($id)));
387+
388+
$ids[] = $id;
389+
390+
$this->fireModelEvent($model, 'deleted', false);
336391
}
337392

338393
return $this->dissociate($ids);
@@ -511,4 +566,27 @@ protected function getForeignKeyValue($id)
511566
return $this->getBaseQuery()->convertKey($id);
512567
}
513568

569+
/**
570+
* Fire the given event for the given model.
571+
*
572+
* @param string $event
573+
* @param bool $halt
574+
* @return mixed
575+
*/
576+
protected function fireModelEvent(Model $model, $event, $halt = true)
577+
{
578+
$dispatcher = $model->getEventDispatcher();
579+
580+
if ( is_null($dispatcher)) return true;
581+
582+
// We will append the names of the class to the event to distinguish it from
583+
// other model events that are fired, allowing us to listen on each model
584+
// event set individually instead of catching event for all the models.
585+
$event = "eloquent.{$event}: ".get_class($model);
586+
587+
$method = $halt ? 'until' : 'fire';
588+
589+
return $dispatcher->$method($event, $model);
590+
}
591+
514592
}

tests/RelationsTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ public function setUp() {
99

1010
public function tearDown()
1111
{
12+
Mockery::close();
13+
1214
User::truncate();
1315
Book::truncate();
1416
Item::truncate();
@@ -297,7 +299,15 @@ public function testEmbedsManySave()
297299
$user = User::create(array('name' => 'John Doe'));
298300
$address = new Address(array('city' => 'London'));
299301

302+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
303+
$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($address), $address)->andReturn(true);
304+
$events->shouldReceive('until')->once()->with('eloquent.creating: '.get_class($address), $address)->andReturn(true);
305+
$events->shouldReceive('fire')->once()->with('eloquent.created: '.get_class($address), $address);
306+
$events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($address), $address);
307+
300308
$address = $user->addresses()->save($address);
309+
$address->unsetEventDispatcher();
310+
301311
$this->assertNotNull($user->_addresses);
302312
$this->assertEquals(array('London'), $user->addresses->lists('city'));
303313
$this->assertInstanceOf('DateTime', $address->created_at);
@@ -309,8 +319,15 @@ public function testEmbedsManySave()
309319
$user = User::find($user->_id);
310320
$this->assertEquals(array('London', 'Paris'), $user->addresses->lists('city'));
311321

322+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
323+
$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($address), $address)->andReturn(true);
324+
$events->shouldReceive('until')->once()->with('eloquent.updating: '.get_class($address), $address)->andReturn(true);
325+
$events->shouldReceive('fire')->once()->with('eloquent.updated: '.get_class($address), $address);
326+
$events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($address), $address);
327+
312328
$address->city = 'New York';
313329
$user->addresses()->save($address);
330+
$address->unsetEventDispatcher();
314331

315332
$this->assertEquals(2, count($user->addresses));
316333
$this->assertEquals(2, count($user->addresses()->get()));
@@ -403,9 +420,16 @@ public function testEmbedsManyDestroy()
403420
$user->addresses()->saveMany(array(new Address(array('city' => 'London')), new Address(array('city' => 'Bristol')), new Address(array('city' => 'Bruxelles'))));
404421

405422
$address = $user->addresses->first();
423+
424+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
425+
$events->shouldReceive('until')->once()->with('eloquent.deleting: '.get_class($address), Mockery::mustBe($address))->andReturn(true);
426+
$events->shouldReceive('fire')->once()->with('eloquent.deleted: '.get_class($address), Mockery::mustBe($address));
427+
406428
$user->addresses()->destroy($address->_id);
407429
$this->assertEquals(array('Bristol', 'Bruxelles'), $user->addresses->lists('city'));
408430

431+
$address->unsetEventDispatcher();
432+
409433
$address = $user->addresses->first();
410434
$user->addresses()->destroy($address);
411435
$this->assertEquals(array('Bruxelles'), $user->addresses->lists('city'));
@@ -452,4 +476,62 @@ public function testEmbedsManyAliases()
452476
$this->assertEquals(array(), $user->addresses->lists('city'));
453477
}
454478

479+
public function testEmbedsManyCreatingEventReturnsFalse()
480+
{
481+
$user = User::create(array('name' => 'John Doe'));
482+
$address = new Address(array('city' => 'London'));
483+
484+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
485+
$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($address), $address)->andReturn(true);
486+
$events->shouldReceive('until')->once()->with('eloquent.creating: '.get_class($address), $address)->andReturn(false);
487+
488+
$this->assertFalse($user->addresses()->save($address));
489+
$address->unsetEventDispatcher();
490+
}
491+
492+
public function testEmbedsManySavingEventReturnsFalse()
493+
{
494+
$user = User::create(array('name' => 'John Doe'));
495+
$address = new Address(array('city' => 'Paris'));
496+
$address->exists = true;
497+
498+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
499+
$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($address), $address)->andReturn(false);
500+
501+
$this->assertFalse($user->addresses()->save($address));
502+
$address->unsetEventDispatcher();
503+
}
504+
505+
public function testEmbedsManyUpdatingEventReturnsFalse()
506+
{
507+
$user = User::create(array('name' => 'John Doe'));
508+
$address = new Address(array('city' => 'New York'));
509+
$address->exists = true;
510+
511+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
512+
$events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($address), $address)->andReturn(true);
513+
$events->shouldReceive('until')->once()->with('eloquent.updating: '.get_class($address), $address)->andReturn(false);
514+
515+
$address->city = 'Warsaw';
516+
517+
$this->assertFalse($user->addresses()->save($address));
518+
$address->unsetEventDispatcher();
519+
}
520+
521+
public function testEmbedsManyDeletingEventReturnsFalse()
522+
{
523+
$user = User::create(array('name' => 'John Doe'));
524+
$user->addresses()->save(new Address(array('city' => 'New York')));
525+
526+
$address = $user->addresses->first();
527+
528+
$address->setEventDispatcher($events = Mockery::mock('Illuminate\Events\Dispatcher'));
529+
$events->shouldReceive('until')->once()->with('eloquent.deleting: '.get_class($address), Mockery::mustBe($address))->andReturn(false);
530+
531+
$this->assertEquals(0, $user->addresses()->destroy($address));
532+
$this->assertEquals(array('New York'), $user->addresses->lists('city'));
533+
534+
$address->unsetEventDispatcher();
535+
}
536+
455537
}

0 commit comments

Comments
 (0)