diff --git a/src/Storm/Model/Loader.php b/src/Storm/Model/Loader.php index f2da4f6eae5c4852a5bfab10183673f7f34245fe..87ab35cbb7f8ffcff56cdf2fb4a67c713dc43a2a 100644 --- a/src/Storm/Model/Loader.php +++ b/src/Storm/Model/Loader.php @@ -361,6 +361,16 @@ class Storm_Model_Loader { } + /** + * This delete operation totally ignore hooks and cascading. + * But this is faster. Use with caution + * @param Array + */ + public function basicDeleteBy($clauses) { + return $this->getPersistenceStrategy()->deleteBy($clauses); + } + + /** * @param string $field * @return string diff --git a/src/Storm/Model/PersistenceStrategy/Db.php b/src/Storm/Model/PersistenceStrategy/Db.php index b9536d75923e307557298020c71a6569c409e057..59bebfba1f89abbdf39ded75ee235c63ff460a0c 100644 --- a/src/Storm/Model/PersistenceStrategy/Db.php +++ b/src/Storm/Model/PersistenceStrategy/Db.php @@ -69,8 +69,28 @@ class Storm_Model_PersistenceStrategy_Db extends Storm_Model_PersistenceStrategy public function delete($model) { - return $this->getTable() - ->delete($this->_loader->getIdField() . "='" . $model->getId() . "'"); + return $this->deleteBy([$this->_loader->getIdField() => $model->getId()]); + } + + + public function deleteBy($clauses) { + $where = []; + foreach($clauses as $key => $value) { + $where []= $this->_generateWhereClauseForKeyAndValue($key, $value); + } + + return $this->getTable()->delete(implode(' and ', $where)); + } + + + protected function _generateWhereClauseForKeyAndValue($key, $value_or_array) { + if (!is_array($value_or_array)) + return $key ."='" . $value_or_array . "'"; + + foreach ($value_or_array as &$value) + $value = '\'' . addslashes($value) . '\''; + + return $key . ' in (' . implode(',', $value_or_array) . ')'; } @@ -187,4 +207,4 @@ class Storm_Model_PersistenceStrategy_Db extends Storm_Model_PersistenceStrategy $select->where($scope_field . '=?', $scope_value); } } -?> \ No newline at end of file +?> diff --git a/src/Storm/Model/PersistenceStrategy/Volatile.php b/src/Storm/Model/PersistenceStrategy/Volatile.php index ebba35465ff51ed80bf8c635539d6fff33f38b7f..6b1ed40c2df31b50a1a143cf7afeacf081bfa4f9 100644 --- a/src/Storm/Model/PersistenceStrategy/Volatile.php +++ b/src/Storm/Model/PersistenceStrategy/Volatile.php @@ -283,6 +283,22 @@ class Storm_Model_PersistenceStrategy_Volatile extends Storm_Model_PersistenceS return true; } + + public function deleteBy($clauses) { + $delete_count = 0; + + foreach($this->getInstancesArray() as $id => $model) { + if ($this->containsAllAttributes($model, $clauses)) { + unset($this->_instances[$model['id']]); + $delete_count += 1; + } + } + + + return $delete_count; + } + + public function countBy($args) { return sizeof($this->findAll($args)); } @@ -292,4 +308,4 @@ class Storm_Model_PersistenceStrategy_Volatile extends Storm_Model_PersistenceS } } -?> \ No newline at end of file +?> diff --git a/tests/Storm/Test/LoaderTest.php b/tests/Storm/Test/LoaderTest.php index 439be199feeeca87a1a967ef83d14074e15b942d..b28631379fb2cc54ae46fd0ff0cb30dc5149187d 100644 --- a/tests/Storm/Test/LoaderTest.php +++ b/tests/Storm/Test/LoaderTest.php @@ -158,4 +158,28 @@ class Storm_Test_LoaderTest extends Storm_Test_ModelTestCase { $this->assertEquals(['name is not null'], $select->getAttributesForLastCallOn('where')); } -} \ No newline at end of file + + + /** @test */ + public function basicDeleteWithNomBondPrenomJamesShouldExpectationSetWhereClauseInDelete() { + $this->_table + ->whenCalled('delete') + ->with('nom=\'bond\' and prenom=\'james\'') + ->answers(10) + ->beStrict(); + $this->assertEquals(10, $this->_loader->basicDeleteBy(['nom' => 'bond', + 'prenom' => 'james'])); + } + + + /** @test */ + public function basicDeleteWithNomArrayBondLQuoteupinShouldExpectationSetWhereNomInClauseInDelete() { + $this->_table + ->whenCalled('delete') + ->with("nom in ('bond','l\'upin')") + ->answers(2) + ->beStrict(); + $this->assertEquals(2, $this->_loader->basicDeleteBy(['nom' => ['bond', + 'l\'upin']])); + } +} diff --git a/tests/Storm/Test/LoaderVolatileTest.php b/tests/Storm/Test/LoaderVolatileTest.php index 3bd28352907d34b6eaf2500efbcc48e5ddaa08cc..6ba6fb01d2f70e174af4ce3accd9f576f33be8de 100644 --- a/tests/Storm/Test/LoaderVolatileTest.php +++ b/tests/Storm/Test/LoaderVolatileTest.php @@ -1,26 +1,26 @@ <?php /* -STORM is under the MIT License (MIT) + STORM is under the MIT License (MIT) -Copyright (c) 2010-2011 Agence Française Informatique http://www.afi-sa.fr + Copyright (c) 2010-2011 Agence Française Informatique http://www.afi-sa.fr -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ @@ -43,28 +43,28 @@ class Storm_Test_VolatileUser extends Storm_Model_Abstract { } - public function describeAssociationsOn($associations) { - $associations - ->add(new Storm_Model_Association_HasOne('brain', ['model' => 'Storm_Test_VolatileBrain', - 'referenced_in' => 'brain_id'])) + public function describeAssociationsOn($associations) { + $associations + ->add(new Storm_Model_Association_HasOne('brain', ['model' => 'Storm_Test_VolatileBrain', + 'referenced_in' => 'brain_id'])) - ->add(new Storm_Model_Association_HasOne('mouth', ['model' => 'Storm_Test_VolatileMouth', - 'referenced_in' => 'id_mouth'])); - } + ->add(new Storm_Model_Association_HasOne('mouth', ['model' => 'Storm_Test_VolatileMouth', + 'referenced_in' => 'id_mouth'])); + } } class Storm_Test_VolatileBrain extends Storm_Model_Abstract { - protected - $_table_name = 'brains', - $_default_attribute_values = ['weight' => 0]; + protected + $_table_name = 'brains', + $_default_attribute_values = ['weight' => 0]; } class Storm_Test_VolatileMouth extends Storm_Model_Abstract { - protected - $_table_name = 'mouths'; + protected + $_table_name = 'mouths'; } @@ -72,7 +72,7 @@ class Storm_Test_VolatileMouth extends Storm_Model_Abstract { class Storm_Test_VolatileCat extends Storm_Model_Abstract { protected $_table_name = 'cats', - $_default_attribute_values = ['name' => ''], + $_default_attribute_values = ['name' => ''], $_belongs_to = ['master' => ['model' => 'Storm_Test_VolatileUser']]; } @@ -94,36 +94,36 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { public function setUp() { parent::setUp(); - Storm_Test_VolatileBrain::beVolatile(); - Storm_Test_VolatileMouth::beVolatile(); + Storm_Test_VolatileBrain::beVolatile(); + Storm_Test_VolatileMouth::beVolatile(); $this->albert = $this->fixture('Storm_Test_VolatileUser', ['id' => 1, 'login' => 'albert', - 'foo' => 'bar', + 'foo' => 'bar', 'a_start_one_letter_field' => 'value', - 'brain' => (new Storm_Test_VolatileBrain())->setWeight(100), - 'mouth' => (new Storm_Test_VolatileMouth())]); + 'brain' => (new Storm_Test_VolatileBrain())->setWeight(100), + 'mouth' => (new Storm_Test_VolatileMouth())]); $this->hubert = $this->fixture('Storm_Test_VolatileUser', ['id' => 2, 'login' => 'hubert', 'level' => 'invite', - 'foo' => 'snafu', + 'foo' => 'snafu', 'option' => 'set', - 'brain_id' => 2]); + 'brain_id' => 2]); - $this->hubert_brain = $this->fixture('Storm_Test_VolatileBrain', - ['id' => 2, - 'weight' => 155]); + $this->hubert_brain = $this->fixture('Storm_Test_VolatileBrain', + ['id' => 2, + 'weight' => 155]); $this->zoe = $this->fixture('Storm_Test_VolatileUser', ['id' => 3, 'login' => 'zoe', 'level' => 'admin', - 'foo' => 'snafu', + 'foo' => 'snafu', 'cats' => [ $this->fixture('Storm_Test_VolatileCat', ['id' => 3, @@ -147,28 +147,28 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { } - /** @test */ - public function albertShouldHaveABrain() { - $this->assertNotNull($this->albert->getBrain()); - } + /** @test */ + public function albertShouldHaveABrain() { + $this->assertNotNull($this->albert->getBrain()); + } - /** @test */ - public function mouthWithIdOneShouldHaveBeenSaved() { - $this->assertNotNull(Storm_Test_VolatileMouth::find(1)); - } + /** @test */ + public function mouthWithIdOneShouldHaveBeenSaved() { + $this->assertNotNull(Storm_Test_VolatileMouth::find(1)); + } - /** @test */ - public function albertBrainWeightShouldBe100() { - $this->assertEquals(100, $this->albert->getBrain()->getWeight()); - } + /** @test */ + public function albertBrainWeightShouldBe100() { + $this->assertEquals(100, $this->albert->getBrain()->getWeight()); + } - /** @test */ - public function albertBrainIdShouldBeOne() { - $this->assertEquals(1, $this->albert->getBrainId()); - } + /** @test */ + public function albertBrainIdShouldBeOne() { + $this->assertEquals(1, $this->albert->getBrainId()); + } /** @test */ @@ -180,33 +180,33 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { } - /** @test */ - public function hubertBrainWeightShouldBe155() { - $this->assertEquals(155, $this->hubert->getBrain()->getWeight()); - } + /** @test */ + public function hubertBrainWeightShouldBe155() { + $this->assertEquals(155, $this->hubert->getBrain()->getWeight()); + } - /** @test */ - public function brainWithIdOneShouldHaveBeenSaved() { - $this->assertEquals(100, Storm_Test_VolatileBrain::find(1)->getWeight()); - } + /** @test */ + public function brainWithIdOneShouldHaveBeenSaved() { + $this->assertEquals(100, Storm_Test_VolatileBrain::find(1)->getWeight()); + } - /** @test */ - public function deletingAlbertShouldDeleteItsBrain() { - $this->albert->delete(); - Storm_Test_VolatileBrain::clearCache(); - $this->assertEmpty(Storm_Test_VolatileBrain::find(1)); - } + /** @test */ + public function deletingAlbertShouldDeleteItsBrain() { + $this->albert->delete(); + Storm_Test_VolatileBrain::clearCache(); + $this->assertEmpty(Storm_Test_VolatileBrain::find(1)); + } - /** @test */ - public function deletingAlbertWithoutCacheShouldAlsoDeleteItsBrain() { - Storm_Test_VolatileBrain::clearCache(); - Storm_Test_VolatileUser::clearCache(); + /** @test */ + public function deletingAlbertWithoutCacheShouldAlsoDeleteItsBrain() { + Storm_Test_VolatileBrain::clearCache(); + Storm_Test_VolatileUser::clearCache(); Storm_Test_VolatileUser::find(1)->delete(); - $this->assertEmpty(Storm_Test_VolatileBrain::find(1)); - } + $this->assertEmpty(Storm_Test_VolatileBrain::find(1)); + } /** @test */ @@ -265,7 +265,7 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { ->getCats() ->injectInto('', function($str, $cat) { - return $str.$cat->getName().','; + return $str.$cat->getName().','; })); } @@ -549,7 +549,7 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { public function deleteHubertFindAllShouldReturnAlbertAndZoe(){ $this->hubert->delete(); $this->assertEquals([ $this->albert,$this->zoe], - Storm_Test_VolatileUser::findAll()); + Storm_Test_VolatileUser::findAll()); } @@ -579,78 +579,100 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { } - /** @test */ - public function limitOneTwoShouldReturnTwo() { - $this->assertEquals(2, count(Storm_Test_VolatileUser::findAllBy(['limit' => '1, 2']))); + /** @test */ + public function limitOneTwoShouldReturnTwo() { + $this->assertEquals(2, count(Storm_Test_VolatileUser::findAllBy(['limit' => '1, 2']))); + } + + + /** @test */ + public function deleteByLevelInviteShouldDeleteHubertAndMax() { + Storm_Test_VolatileUser::deleteBy(['level' => 'invite']); + $this->assertEquals(2, count(Storm_Test_VolatileUser::findAll())); + } + + + /** @test */ + public function deleteByLevelInviteShouldRemoveHubertFromCache() { + Storm_Test_VolatileUser::deleteBy(['level' => 'invite']); + $this->assertNull(Storm_Test_VolatileUser::find($this->hubert->getId())); + } + + + /** @test */ + public function deleteByShouldPaginateAndDeleteAll() { + Storm_Test_VolatileUser::deleteBy([], 1); + $this->assertEquals(0, count(Storm_Test_VolatileUser::findAll())); } - /** @test */ - public function deleteByLevelInviteShouldDeleteHubertAndMax() { - Storm_Test_VolatileUser::deleteBy(['level' => 'invite']); - $this->assertEquals(2, count(Storm_Test_VolatileUser::findAll())); - } + /** @test */ + public function savingAndLoadingFromPersistenceShouldSetId() { + Storm_Test_VolatileUser::clearCache(); + $hubert = Storm_Test_VolatileUser::find(2); + $this->assertEquals(2, $hubert->getId()); + } - /** @test */ - public function deleteByLevelInviteShouldRemoveHubertFromCache() { - Storm_Test_VolatileUser::deleteBy(['level' => 'invite']); - $this->assertNull(Storm_Test_VolatileUser::find($this->hubert->getId())); - } + /** @test */ + public function limitPageShouldPaginate() { + $this->assertEquals([ $this->albert, $this->hubert ], + Storm_Test_VolatileUser::findAll(['limitPage' => [0, 2]])); + $this->assertEquals([ $this->albert, $this->hubert ], + Storm_Test_VolatileUser::findAll(['limitPage' => [1, 2]])); + $this->assertEquals([ $this->zoe ], + Storm_Test_VolatileUser::findAll(['limitPage' => [2, 2]])); + } - /** @test */ - public function deleteByShouldPaginateAndDeleteAll() { - Storm_Test_VolatileUser::deleteBy([], 1); - $this->assertEquals(0, count(Storm_Test_VolatileUser::findAll())); - } + /** @test */ + public function limitPageAndAttributeShouldWork() { + $this->assertEquals([ $this->hubert, $this->zoe ], + Storm_Test_VolatileUser::findAllBy(['foo' => 'snafu', 'limitPage' => [1, 2]])); + } - /** @test */ - public function savingAndLoadingFromPersistenceShouldSetId() { - Storm_Test_VolatileUser::clearCache(); - $hubert = Storm_Test_VolatileUser::find(2); - $this->assertEquals(2, $hubert->getId()); - } + /** @test */ + public function memoryReportShouldPrintThreeUsers() { + $this->assertContains("Storm_Test_VolatileUser: 3", + Storm_MemoryReport::renderText()); + } - /** @test */ - public function limitPageShouldPaginate() { - $this->assertEquals([ $this->albert, $this->hubert ], - Storm_Test_VolatileUser::findAll(['limitPage' => [0, 2]])); - $this->assertEquals([ $this->albert, $this->hubert ], - Storm_Test_VolatileUser::findAll(['limitPage' => [1, 2]])); - $this->assertEquals([ $this->zoe ], - Storm_Test_VolatileUser::findAll(['limitPage' => [2, 2]])); - } + /** @test */ + public function findAllByLeftLogin2ZoShouldAnswersZoe() { + $this->assertEquals([ $this->zoe ], + Storm_Test_VolatileUser::findAllBy(['left(login,2)' => 'zo'])); + } - /** @test */ - public function limitPageAndAttributeShouldWork() { - $this->assertEquals([ $this->hubert, $this->zoe ], - Storm_Test_VolatileUser::findAllBy(['foo' => 'snafu', 'limitPage' => [1, 2]])); - } + /** @test */ + public function findAllByLeftLogin10HubertShouldAnswersHubert() { + $this->assertEquals([ $this->hubert ], + Storm_Test_VolatileUser::findAllBy(['left( login , 10 )' => 'hubert'])); + } - /** @test */ - public function memoryReportShouldPrintThreeUsers() { - $this->assertContains("Storm_Test_VolatileUser: 3", - Storm_MemoryReport::renderText()); - } + /** @test */ + public function basicDeleteByFooSnafuShouldDeleteZoeAndHubert() { + Storm_Test_VolatileUser::basicDeleteBy(['foo' => 'snafu']); + $this->assertEquals([ $this->albert ], + Storm_Test_VolatileUser::findAll()); + } - /** @test */ - public function findAllByLeftLogin2ZoShouldAnswersZoe() { - $this->assertEquals([ $this->zoe ], - Storm_Test_VolatileUser::findAllBy(['left(login,2)' => 'zo'])); - } + /** @test */ + public function basicDeleteByFooSnafuShouldDeleteZoeAndHubertAndAnswerTwo() { + $this->assertSame(2, Storm_Test_VolatileUser::basicDeleteBy(['foo' => 'snafu'])); + } - /** @test */ - public function findAllByLeftLogin10HubertShouldAnswersHubert() { - $this->assertEquals([ $this->hubert ], - Storm_Test_VolatileUser::findAllBy(['left( login , 10 )' => 'hubert'])); - } + /** @test */ + public function basicDeleteByLoginArrayAlbertHubertShouldDeleteAlbertAndHubert() { + Storm_Test_VolatileUser::basicDeleteBy(['login' => ['albert', 'hubert']]); + $this->assertEquals([ $this->zoe ], + Storm_Test_VolatileUser::findAll()); + } } -?> \ No newline at end of file +?>