Commit ae46e016 authored by Jens Segers's avatar Jens Segers

Merge pull request #153 from neoxia/master-associate-dissociate-embeds-many

Add associate and dissociate methods to EmbedsMany (#151)
parents cbb5273d 0caeeb9f
......@@ -140,6 +140,8 @@ class EmbedsMany extends Relation {
*/
public function save(Model $model)
{
$this->updateTimestamps($model);
// Insert a new document.
if ( ! $model->exists)
{
......@@ -154,34 +156,40 @@ class EmbedsMany extends Relation {
}
/**
* Perform a model insert operation.
* Attach a model instance to the parent model without persistence.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function performInsert(Model $model)
public function associate(Model $model)
{
// Create a new key.
if ( ! $model->getAttribute('_id'))
// Insert the related model in the parent instance
if ( ! $model->exists)
{
$model->setAttribute('_id', new MongoId);
return $this->associateNew($model);
}
// Update timestamps.
$this->updateTimestamps($model);
// Push the document to the database.
$result = $this->query->push($this->localKey, $model->getAttributes(), true);
$documents = $this->getEmbeddedRecords();
// Update the related model in the parent instance
else
{
return $this->associateExisting($model);
}
// Add the document to the parent model.
$documents[] = $model->getAttributes();
}
$this->setEmbeddedRecords($documents);
/**
* Perform a model insert operation.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function performInsert(Model $model)
{
// Insert the related model in the parent instance
$this->associateNew($model);
// Mark the model as existing.
$model->exists = true;
// Push the document to the database.
$result = $this->query->push($this->localKey, $model->getAttributes(), true);
return $result ? $model : false;
}
......@@ -194,8 +202,8 @@ class EmbedsMany extends Relation {
*/
protected function performUpdate(Model $model)
{
// Update timestamps.
$this->updateTimestamps($model);
// Update the related model in the parent instance
$this->associateExisting($model);
// Get the correct foreign key value.
$id = $this->getForeignKeyValue($model->getKey());
......@@ -204,6 +212,44 @@ class EmbedsMany extends Relation {
$result = $this->query->where($this->localKey . '.' . $model->getKeyName(), $id)
->update(array($this->localKey . '.$' => $model->getAttributes()));
return $result ? $model : false;
}
/**
* Attach a new model without persistence
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function associateNew($model)
{
// Create a new key.
if ( ! $model->getAttribute('_id'))
{
$model->setAttribute('_id', new MongoId);
}
$documents = $this->getEmbeddedRecords();
// Add the document to the parent model.
$documents[] = $model->getAttributes();
$this->setEmbeddedRecords($documents);
// Mark the model as existing.
$model->exists = true;
return $model;
}
/**
* Update an existing model without persistence
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
protected function associateExisting($model)
{
// Get existing embedded documents.
$documents = $this->getEmbeddedRecords();
......@@ -212,18 +258,18 @@ class EmbedsMany extends Relation {
$key = $model->getKey();
// Replace the document in the parent model.
foreach ($documents as $i => $document)
foreach ($documents as &$document)
{
if ($document[$primaryKey] == $key)
{
$documents[$i] = $model->getAttributes();
$document = $model->getAttributes();
break;
}
}
$this->setEmbeddedRecords($documents);
return $result ? $model : false;
return $model;
}
/**
......@@ -273,22 +319,12 @@ class EmbedsMany extends Relation {
/**
* Destroy the embedded models for the given IDs.
*
* @param array|int $ids
* @param mixed $ids
* @return int
*/
public function destroy($ids = array())
{
// We'll initialize a count here so we will return the total number of deletes
// for the operation. The developers can then check this number as a boolean
// type value or get this total count of records deleted for logging, etc.
$count = 0;
if ($ids instanceof Model) $ids = (array) $ids->getKey();
// If associated IDs were passed to the method we will only delete those
// associations, otherwise all of the association ties will be broken.
// We'll return the numbers of affected rows when we do the deletes.
$ids = (array) $ids;
$ids = $this->getIdsArrayFrom($ids);
$primaryKey = $this->related->getKeyName();
......@@ -296,9 +332,23 @@ class EmbedsMany extends Relation {
foreach ($ids as $id)
{
$this->query->pull($this->localKey, array($primaryKey => $this->getForeignKeyValue($id)));
$count++;
}
return $this->dissociate($ids);
}
/**
* Dissociate the embedded models for the given IDs without persistence.
*
* @param mixed $ids
* @return int
*/
public function dissociate($ids = array())
{
$ids = $this->getIdsArrayFrom($ids);
$primaryKey = $this->related->getKeyName();
// Get existing embedded documents.
$documents = $this->getEmbeddedRecords();
......@@ -313,7 +363,28 @@ class EmbedsMany extends Relation {
$this->setEmbeddedRecords($documents);
return $count;
// We return the total number of deletes for the operation. The developers
// can then check this number as a boolean type value or get this total count
// of records deleted for logging, etc.
return count($ids);
}
/**
* Transform single ID, single Model or array of Models into an array of IDs
*
* @param mixed $ids
* @return int
*/
protected function getIdsArrayFrom($ids)
{
if (! is_array($ids)) $ids = array($ids);
foreach ($ids as &$id)
{
if ($id instanceof Model) $id = $id->getKey();
}
return $ids;
}
/**
......
......@@ -329,6 +329,27 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
$this->assertEquals(array('London', 'Manhattan', 'Bruxelles'), $freshUser->addresses->lists('city'));
}
public function testEmbedsManyAssociate()
{
$user = User::create(array('name' => 'John Doe'));
$address = new Address(array('city' => 'London'));
$address = $user->addresses()->associate($address);
$this->assertNotNull($user->_addresses);
$this->assertEquals(array('London'), $user->addresses->lists('city'));
$this->assertNotNull($address->_id);
$freshUser = User::find($user->_id);
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
$address->city = 'Londinium';
$user->addresses()->associate($address);
$this->assertEquals(array('Londinium'), $user->addresses->lists('city'));
$freshUser = User::find($user->_id);
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
}
public function testEmbedsManySaveMany()
{
$user = User::create(array('name' => 'John Doe'));
......@@ -383,8 +404,8 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
$user->addresses()->create(array('city' => 'Paris'));
$user->addresses()->create(array('city' => 'San Francisco'));
$user = User::find($user->id);
$this->assertEquals(array('Bruxelles', 'Paris', 'San Francisco'), $user->addresses->lists('city'));
$freshUser = User::find($user->id);
$this->assertEquals(array('Bruxelles', 'Paris', 'San Francisco'), $freshUser->addresses->lists('city'));
$ids = $user->addresses->lists('_id');
$user->addresses()->destroy($ids);
......@@ -392,6 +413,22 @@ class RelationsTest extends PHPUnit_Framework_TestCase {
$freshUser = User::find($user->id);
$this->assertEquals(array(), $freshUser->addresses->lists('city'));
list($london, $bristol, $bruxelles) = $user->addresses()->saveMany(array(new Address(array('city' => 'London')), new Address(array('city' => 'Bristol')), new Address(array('city' => 'Bruxelles'))));
$user->addresses()->destroy(array($london, $bruxelles));
$this->assertEquals(array('Bristol'), $user->addresses->lists('city'));
}
public function testEmbedsManyDissociate()
{
$user = User::create(array());
$cordoba = $user->addresses()->create(array('city' => 'Cordoba'));
$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()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment