Skip to content

Commit ae46e01

Browse files
committed
Merge pull request #153 from neoxia/master-associate-dissociate-embeds-many
Add associate and dissociate methods to EmbedsMany (#151)
2 parents cbb5273 + 0caeeb9 commit ae46e01

File tree

2 files changed

+146
-38
lines changed

2 files changed

+146
-38
lines changed

src/Jenssegers/Mongodb/Relations/EmbedsMany.php

Lines changed: 107 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public function get()
140140
*/
141141
public function save(Model $model)
142142
{
143+
$this->updateTimestamps($model);
144+
143145
// Insert a new document.
144146
if ( ! $model->exists)
145147
{
@@ -154,34 +156,40 @@ public function save(Model $model)
154156
}
155157

156158
/**
157-
* Perform a model insert operation.
159+
* Attach a model instance to the parent model without persistence.
158160
*
159161
* @param \Illuminate\Database\Eloquent\Model $model
160162
* @return \Illuminate\Database\Eloquent\Model
161163
*/
162-
protected function performInsert(Model $model)
164+
public function associate(Model $model)
163165
{
164-
// Create a new key.
165-
if ( ! $model->getAttribute('_id'))
166+
// Insert the related model in the parent instance
167+
if ( ! $model->exists)
166168
{
167-
$model->setAttribute('_id', new MongoId);
169+
return $this->associateNew($model);
168170
}
169171

170-
// Update timestamps.
171-
$this->updateTimestamps($model);
172-
173-
// Push the document to the database.
174-
$result = $this->query->push($this->localKey, $model->getAttributes(), true);
175-
176-
$documents = $this->getEmbeddedRecords();
172+
// Update the related model in the parent instance
173+
else
174+
{
175+
return $this->associateExisting($model);
176+
}
177177

178-
// Add the document to the parent model.
179-
$documents[] = $model->getAttributes();
178+
}
180179

181-
$this->setEmbeddedRecords($documents);
180+
/**
181+
* Perform a model insert operation.
182+
*
183+
* @param \Illuminate\Database\Eloquent\Model $model
184+
* @return \Illuminate\Database\Eloquent\Model
185+
*/
186+
protected function performInsert(Model $model)
187+
{
188+
// Insert the related model in the parent instance
189+
$this->associateNew($model);
182190

183-
// Mark the model as existing.
184-
$model->exists = true;
191+
// Push the document to the database.
192+
$result = $this->query->push($this->localKey, $model->getAttributes(), true);
185193

186194
return $result ? $model : false;
187195
}
@@ -194,8 +202,8 @@ protected function performInsert(Model $model)
194202
*/
195203
protected function performUpdate(Model $model)
196204
{
197-
// Update timestamps.
198-
$this->updateTimestamps($model);
205+
// Update the related model in the parent instance
206+
$this->associateExisting($model);
199207

200208
// Get the correct foreign key value.
201209
$id = $this->getForeignKeyValue($model->getKey());
@@ -204,6 +212,44 @@ protected function performUpdate(Model $model)
204212
$result = $this->query->where($this->localKey . '.' . $model->getKeyName(), $id)
205213
->update(array($this->localKey . '.$' => $model->getAttributes()));
206214

215+
return $result ? $model : false;
216+
}
217+
218+
/**
219+
* Attach a new model without persistence
220+
*
221+
* @param \Illuminate\Database\Eloquent\Model $model
222+
* @return \Illuminate\Database\Eloquent\Model
223+
*/
224+
protected function associateNew($model)
225+
{
226+
// Create a new key.
227+
if ( ! $model->getAttribute('_id'))
228+
{
229+
$model->setAttribute('_id', new MongoId);
230+
}
231+
232+
$documents = $this->getEmbeddedRecords();
233+
234+
// Add the document to the parent model.
235+
$documents[] = $model->getAttributes();
236+
237+
$this->setEmbeddedRecords($documents);
238+
239+
// Mark the model as existing.
240+
$model->exists = true;
241+
242+
return $model;
243+
}
244+
245+
/**
246+
* Update an existing model without persistence
247+
*
248+
* @param \Illuminate\Database\Eloquent\Model $model
249+
* @return \Illuminate\Database\Eloquent\Model
250+
*/
251+
protected function associateExisting($model)
252+
{
207253
// Get existing embedded documents.
208254
$documents = $this->getEmbeddedRecords();
209255

@@ -212,18 +258,18 @@ protected function performUpdate(Model $model)
212258
$key = $model->getKey();
213259

214260
// Replace the document in the parent model.
215-
foreach ($documents as $i => $document)
261+
foreach ($documents as &$document)
216262
{
217263
if ($document[$primaryKey] == $key)
218264
{
219-
$documents[$i] = $model->getAttributes();
265+
$document = $model->getAttributes();
220266
break;
221267
}
222268
}
223269

224270
$this->setEmbeddedRecords($documents);
225271

226-
return $result ? $model : false;
272+
return $model;
227273
}
228274

229275
/**
@@ -273,32 +319,36 @@ public function createMany(array $records)
273319
/**
274320
* Destroy the embedded models for the given IDs.
275321
*
276-
* @param array|int $ids
322+
* @param mixed $ids
277323
* @return int
278324
*/
279325
public function destroy($ids = array())
280326
{
281-
// We'll initialize a count here so we will return the total number of deletes
282-
// for the operation. The developers can then check this number as a boolean
283-
// type value or get this total count of records deleted for logging, etc.
284-
$count = 0;
285-
286-
if ($ids instanceof Model) $ids = (array) $ids->getKey();
287-
288-
// If associated IDs were passed to the method we will only delete those
289-
// associations, otherwise all of the association ties will be broken.
290-
// We'll return the numbers of affected rows when we do the deletes.
291-
$ids = (array) $ids;
327+
$ids = $this->getIdsArrayFrom($ids);
292328

293329
$primaryKey = $this->related->getKeyName();
294330

295331
// Pull the documents from the database.
296332
foreach ($ids as $id)
297333
{
298334
$this->query->pull($this->localKey, array($primaryKey => $this->getForeignKeyValue($id)));
299-
$count++;
300335
}
301336

337+
return $this->dissociate($ids);
338+
}
339+
340+
/**
341+
* Dissociate the embedded models for the given IDs without persistence.
342+
*
343+
* @param mixed $ids
344+
* @return int
345+
*/
346+
public function dissociate($ids = array())
347+
{
348+
$ids = $this->getIdsArrayFrom($ids);
349+
350+
$primaryKey = $this->related->getKeyName();
351+
302352
// Get existing embedded documents.
303353
$documents = $this->getEmbeddedRecords();
304354

@@ -313,7 +363,28 @@ public function destroy($ids = array())
313363

314364
$this->setEmbeddedRecords($documents);
315365

316-
return $count;
366+
// We return the total number of deletes for the operation. The developers
367+
// can then check this number as a boolean type value or get this total count
368+
// of records deleted for logging, etc.
369+
return count($ids);
370+
}
371+
372+
/**
373+
* Transform single ID, single Model or array of Models into an array of IDs
374+
*
375+
* @param mixed $ids
376+
* @return int
377+
*/
378+
protected function getIdsArrayFrom($ids)
379+
{
380+
if (! is_array($ids)) $ids = array($ids);
381+
382+
foreach ($ids as &$id)
383+
{
384+
if ($id instanceof Model) $id = $id->getKey();
385+
}
386+
387+
return $ids;
317388
}
318389

319390
/**

tests/RelationsTest.php

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,27 @@ public function testEmbedsManySave()
329329
$this->assertEquals(array('London', 'Manhattan', 'Bruxelles'), $freshUser->addresses->lists('city'));
330330
}
331331

332+
public function testEmbedsManyAssociate()
333+
{
334+
$user = User::create(array('name' => 'John Doe'));
335+
$address = new Address(array('city' => 'London'));
336+
337+
$address = $user->addresses()->associate($address);
338+
$this->assertNotNull($user->_addresses);
339+
$this->assertEquals(array('London'), $user->addresses->lists('city'));
340+
$this->assertNotNull($address->_id);
341+
342+
$freshUser = User::find($user->_id);
343+
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
344+
345+
$address->city = 'Londinium';
346+
$user->addresses()->associate($address);
347+
$this->assertEquals(array('Londinium'), $user->addresses->lists('city'));
348+
349+
$freshUser = User::find($user->_id);
350+
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
351+
}
352+
332353
public function testEmbedsManySaveMany()
333354
{
334355
$user = User::create(array('name' => 'John Doe'));
@@ -383,15 +404,31 @@ public function testEmbedsManyDestroy()
383404
$user->addresses()->create(array('city' => 'Paris'));
384405
$user->addresses()->create(array('city' => 'San Francisco'));
385406

386-
$user = User::find($user->id);
387-
$this->assertEquals(array('Bruxelles', 'Paris', 'San Francisco'), $user->addresses->lists('city'));
407+
$freshUser = User::find($user->id);
408+
$this->assertEquals(array('Bruxelles', 'Paris', 'San Francisco'), $freshUser->addresses->lists('city'));
388409

389410
$ids = $user->addresses->lists('_id');
390411
$user->addresses()->destroy($ids);
391412
$this->assertEquals(array(), $user->addresses->lists('city'));
392413

393414
$freshUser = User::find($user->id);
394415
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
416+
417+
list($london, $bristol, $bruxelles) = $user->addresses()->saveMany(array(new Address(array('city' => 'London')), new Address(array('city' => 'Bristol')), new Address(array('city' => 'Bruxelles'))));
418+
$user->addresses()->destroy(array($london, $bruxelles));
419+
$this->assertEquals(array('Bristol'), $user->addresses->lists('city'));
420+
}
421+
422+
public function testEmbedsManyDissociate()
423+
{
424+
$user = User::create(array());
425+
$cordoba = $user->addresses()->create(array('city' => 'Cordoba'));
426+
427+
$user->addresses()->dissociate($cordoba->id);
428+
429+
$freshUser = User::find($user->id);
430+
$this->assertEquals(0, $user->addresses->count());
431+
$this->assertEquals(1, $freshUser->addresses->count());
395432
}
396433

397434
public function testEmbedsManyAliases()

0 commit comments

Comments
 (0)