diff --git a/src/Storm/Model/Loader.php b/src/Storm/Model/Loader.php index 87ab35cbb7f8ffcff56cdf2fb4a67c713dc43a2a..962d2a127e51f4c13a7810e2573d698fdbbf5664 100644 --- a/src/Storm/Model/Loader.php +++ b/src/Storm/Model/Loader.php @@ -397,7 +397,9 @@ class Storm_Model_Loader { * Book::getLoader()->findAllBy(array( * 'order' => 'creation_date desc', * 'limit' => 10, - * 'where' => 'note>2' + * 'where' => 'note>2', + * 'title like' => '%apple%', + * 'left(isbn, 3) => '978', * 'tag' => null, * 'limitPage' => array($page_number, $items_by_page) * )); diff --git a/src/Storm/Model/PersistenceStrategy/Db.php b/src/Storm/Model/PersistenceStrategy/Db.php index e771b73ddc6f229739aed03dd7ff3b26168b44f9..c68c7eb2ac7e770820e218e53502a207950f3eea 100644 --- a/src/Storm/Model/PersistenceStrategy/Db.php +++ b/src/Storm/Model/PersistenceStrategy/Db.php @@ -183,6 +183,13 @@ class Storm_Model_PersistenceStrategy_Db extends Storm_Model_PersistenceStrategy continue; } + + if (' like' == substr($field, -5)) { + $select->where($field . ' ?', $value); + continue; + } + + $negated = (' not' == substr($field, -4)); $field = $negated ? substr($field, 0, strlen($field) - 4): $field; diff --git a/src/Storm/Model/PersistenceStrategy/Volatile.php b/src/Storm/Model/PersistenceStrategy/Volatile.php index 0cea7806d0dfda9a1a7e898588220f332d13344e..33d80f5ded48bb95ae36314020bfdf0be765182a 100644 --- a/src/Storm/Model/PersistenceStrategy/Volatile.php +++ b/src/Storm/Model/PersistenceStrategy/Volatile.php @@ -63,9 +63,10 @@ class Storm_Model_PersistenceStrategy_Volatile extends Storm_Model_PersistenceS unset($filtered_select[$field]); $negations = []; + foreach($filtered_select as $k => $v) { - if (' not' == substr($k, -4)) { - $negations[substr($k, 0, strlen($k) -4)] = $v; + if (false !== strpos($k, ' not')) { + $negations[str_replace(' not', '', $k)] = $v; unset($filtered_select[$k]); } } @@ -222,6 +223,11 @@ class Storm_Model_PersistenceStrategy_Volatile extends Storm_Model_PersistenceS $left_len = (int)$matches[2]; } + if (preg_match('/(.+)( not)? like/', $key, $matches)) { + $key = trim($matches[1]); + $like = '/^' . str_replace('%', '.*', $value) . '$/i'; + } + if (!array_key_exists($key, $model)) return false; @@ -237,6 +243,9 @@ class Storm_Model_PersistenceStrategy_Volatile extends Storm_Model_PersistenceS && substr($model[$key], 0, $left_len) === substr($value, 0, $left_len)) return true; + if (isset($like)) + return preg_match($like, $model[$key]); + return $model[$key] == $value; } diff --git a/tests/Storm/Test/LoaderTest.php b/tests/Storm/Test/LoaderTest.php index 14feb604b628d215b14ea29878e32a2f053ac189..f2d4fe78bf353caa6ec50663bb5092af13c47f5b 100644 --- a/tests/Storm/Test/LoaderTest.php +++ b/tests/Storm/Test/LoaderTest.php @@ -149,8 +149,23 @@ class Storm_Test_LoaderTest extends Storm_Test_ModelTestCase { } - /** @test */ - public function findAllByNegatedValueShouldGenerateNegatedClauses() { + public function findAllByGeneratedSelects() { + return + [ + [ ['name not' => 'Harlock'] , ['name!=?', 'Harlock'] ], + [ ['name not' => ['Harlock', 'Nausicaa']] , ['name not in (?)', ['Harlock', 'Nausicaa']] ], + [ ['name not' => null] , ['name is not null'] ], + [ ['login like' => '%aus%'] , ['login like ?', '%aus%'] ], + [ ['login not like' => '%aus%'] , ['login not like ?', '%aus%'] ] + ]; + } + + + /** + * @dataProvider findAllByGeneratedSelects + * @test + */ + public function withFindAllParamsLoaderShouldTransformWhereParamsToZendDb($find_all_by_param, $expected_where) { $this->_table ->whenCalled('select')->answers($select = $this->mock()) ->whenCalled('fetchAll')->with($select) @@ -158,15 +173,8 @@ class Storm_Test_LoaderTest extends Storm_Test_ModelTestCase { $select->whenCalled('where')->answers($select); - $this->_loader->findAllBy(['name not' => 'Harlock']); - $this->assertEquals(['name!=?', 'Harlock'], $select->getAttributesForLastCallOn('where')); - - $this->_loader->findAllBy(['name not' => ['Harlock', 'Nausicaa']]); - $this->assertEquals(['name not in (?)', ['Harlock', 'Nausicaa']], - $select->getAttributesForLastCallOn('where')); - - $this->_loader->findAllBy(['name not' => null]); - $this->assertEquals(['name is not null'], + $this->_loader->findAllBy($find_all_by_param); + $this->assertEquals($expected_where, $select->getAttributesForLastCallOn('where')); } diff --git a/tests/Storm/Test/LoaderVolatileTest.php b/tests/Storm/Test/LoaderVolatileTest.php index 851f5af2cdf1639ed4328f194f2d21d1f207143d..92d242b1afd5709f2745fc20275c273d23ebe4a8 100644 --- a/tests/Storm/Test/LoaderVolatileTest.php +++ b/tests/Storm/Test/LoaderVolatileTest.php @@ -74,7 +74,7 @@ class Storm_Test_VolatileCat extends Storm_Model_Abstract { $_table_name = 'cats', $_default_attribute_values = ['name' => ''], - $_belongs_to = ['master' => ['model' => 'Storm_Test_VolatileUser']]; + $_belongs_to = ['master' => ['model' => Storm_Test_VolatileUser::class]]; } @@ -98,7 +98,7 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { Storm_Test_VolatileMouth::beVolatile(); - $this->albert = $this->fixture('Storm_Test_VolatileUser', + $this->albert = $this->fixture(Storm_Test_VolatileUser::class, ['id' => 1, 'login' => 'albert', 'foo' => 'bar', @@ -106,7 +106,7 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { 'brain' => (new Storm_Test_VolatileBrain())->setWeight(100), 'mouth' => (new Storm_Test_VolatileMouth())]); - $this->hubert = $this->fixture('Storm_Test_VolatileUser', + $this->hubert = $this->fixture(Storm_Test_VolatileUser::class, ['id' => 2, 'login' => 'hubert', 'level' => 'invite', @@ -119,7 +119,7 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { 'weight' => 155]); - $this->zoe = $this->fixture('Storm_Test_VolatileUser', + $this->zoe = $this->fixture(Storm_Test_VolatileUser::class, ['id' => 3, 'login' => 'zoe', 'level' => 'admin', @@ -415,6 +415,13 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { } + /** @test */ + public function findAllByLevelNotInviteShouldReturnAlbertAndZoe() { + $this->assertEquals([ $this->albert, $this->zoe], + Storm_Test_VolatileUser::findAll(['level not'=> 'invite'])); + } + + /** @test */ public function selectInvitesBySelectorNameShouldReturnHubert() { $users = new Storm_Model_Collection(Storm_Test_VolatileUser::findAll()); @@ -691,4 +698,40 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { Storm_Test_VolatileUser::basicDeleteBy('login = "albert"'); $this->assertEquals(3, Storm_Test_VolatileUser::count()); } + + + /** @test */ + public function findAllByLoginLikePercentBertShouldAnswerAlbertHubert() { + $this->assertEquals([ $this->albert, $this->hubert ], + Storm_Test_VolatileUser::findAllBy(['login like' => '%bert'])); + } + + + /** @test */ + public function findAllByLoginNotLikePercentBertShouldAnswerZoe() { + $this->assertEquals([ $this->zoe ], + Storm_Test_VolatileUser::findAllBy(['login not like' => '%bert'])); + } + + + /** @test */ + public function findAllByLoginLikePercentPouetShouldBeEmpty() { + $this->assertEquals([], + Storm_Test_VolatileUser::findAllBy(['login like' => 'pouet'])); + } + + + /** @test */ + public function findAllByLoginLike_aLb_PercentShouldAnswerAlbert() { + $this->assertEquals([$this->albert], + Storm_Test_VolatileUser::findAllBy(['login like' => 'aLb%'])); + } + + + /** @test */ + public function findAllByLoginLikePercentAlbertPercentShouldAnswerAlbert() { + $this->assertEquals([$this->albert], + Storm_Test_VolatileUser::findAllBy(['login like' => '%albert%'])); + } } +?>