diff --git a/classes/Repository.php b/classes/Repository.php index 059914f..0d8241a 100644 --- a/classes/Repository.php +++ b/classes/Repository.php @@ -48,6 +48,12 @@ class Repository extends Object { */ protected $created = array(); + /** + * References to instances that have been deleted + * @var array + */ + protected $deleted = array(); + /** * The unique identifier of this repository * @var string @@ -513,6 +519,19 @@ function resolveProperties($instance, $options = array()) { */ function delete($model, $mixed) { $config = $this->_getConfig($model); + if (isset($this->deleted[$model])) { + $isDeleted = false; + if (is_object($mixed)) { + $isDeleted = collection($this->deleted[$model])->find($mixed, true); + } else { // $mixed is an id + $index = $this->resolveIndex($mixed, $config); + $isDeleted = isset($this->deleted[$model][$index]); + } + if ($isDeleted) { +// notice('Already deleted'); + return; + } + } $index = $this->resolveIndex($mixed, $config); $object = @$this->objects[$model][$index]; if ($object === null) { @@ -550,7 +569,22 @@ function delete($model, $mixed) { unset($instance->$property); } } - // @todo Unload the hasMany objects from memory, they might have been deleted through an CASCADE relation in MySQL. + // Remove the instances from connected collections + foreach ($this->configs as $connectedConfig) { + foreach ($connectedConfig->hasMany as $hasManyPath => $hasManyConfig) { + if ($hasManyConfig['model'] === $model && isset($this->objects[$connectedConfig->name])) { + foreach ($this->objects[$connectedConfig->name] as $connectedObject) { + $collection = PropertyPath::get($hasManyPath, $connectedObject['instance']); + if ($collection instanceof Collection) { + $collection->remove($instance, true); // Remove the item from the collection (if it's there) + } + // @todo Remove the reference from $connectedObject['hadMany'][$hasManyPath]? Could cause issues with many2many relations? + } + } + } + // @todo Set the belongsTo to null? + } + $this->deleted[$model][$index] = $instance; // Register as deleted unset($this->objects[$model][$index]); // Remove the object from the repository } diff --git a/tests/RepositoryTest.php b/tests/RepositoryTest.php index 6d358b7..751e50f 100644 --- a/tests/RepositoryTest.php +++ b/tests/RepositoryTest.php @@ -245,7 +245,7 @@ function test_hasManyArrayAccessInterface() { $this->assertEquals(count($c2->orders), 1, 'Unset by array offset'); $this->assertInstanceOf('Sledgehammer\Collection', $c2->orders, 'The orders property should be replaced with an Collection'); - // $this->setExpectedException('PHPUnit_Framework_Error_Notice', 'This placeholder is already replaced'); + // $this->setExpectedException('PHPUnit_Framework_Error_Notice', 'This placeholder is already replaced'); // $this->assertEquals($clone->orders[1]->product, 'Spycam'); // $this->fail('clone doesn\'t work with PlaceHolders, but the placeholder should complain'); } @@ -264,14 +264,22 @@ function test_removeWildcard() { $repo = new RepositoryTester(); $repo->registerBackend(new DatabaseRepositoryBackend($this->dbLink)); - $order1 = $repo->getOrder(1); - // remove by instance - $repo->deleteOrder($order1); - $this->assertRelativeQueryCount(2); - $this->assertLastQuery('DELETE FROM orders WHERE id = 1'); // remove by id $repo->deleteOrder('2'); $this->assertLastQuery('DELETE FROM orders WHERE id = 2'); + $this->assertRelativeQueryCount(1); + + // remove by instance + $order1 = $repo->getOrder(1); + $this->assertCount(1, $order1->customer->orders->toArray()); + $customer = $order1->customer; + $this->assertRelativeQueryCount(4, 'Sanity check'); + $repo->deleteOrder($order1); + $this->assertRelativeQueryCount(5); + $this->assertLastQuery('DELETE FROM orders WHERE id = 1'); + $this->assertCount(0, $customer->orders->toArray()); + $repo->saveCustomer($customer); + $this->assertRelativeQueryCount(5, 'Saving a connected item should not trigger another DELETE query'); } function test_saveWildcard() {