From db450a96e95c35b9328e33bd992c1dcf5837ffb0 Mon Sep 17 00:00:00 2001 From: Guillaume Lafarge Date: Thu, 10 Apr 2014 20:19:32 +0200 Subject: [PATCH 1/2] Fix Hash type casting When using comparison with a boolean, as the filter is a string, we have to convert the data boolean to "boolean string" to avoid type-casting troubles. ## Example ```php $users = [ [ 'id' => 2, 'username' => 'johndoe', 'active' => true ], [ 'id' => 5, 'username' => 'kevin', 'active' => true ], [ 'id' => 9, 'username' => 'samantha', 'active' => false ], ]; $unactiveUsers = Hash::extract($users, '{n}[active=false]'); print_r($unactiveUsers); ``` This example returns the two unwanted active users because `"false"` is `true` but not `false` :) I think this pull request will fix this issue by converting true/false boolean to string (to match with our filter). --- lib/Cake/Utility/Hash.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Hash.php b/lib/Cake/Utility/Hash.php index 7c9b685f0..b35cad715 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -192,7 +192,7 @@ class Hash { return false; } - $prop = isset($data[$attr]) ? $data[$attr] : null; + $prop = isset($data[$attr]) ? ( is_bool($data[$attr]) ? (($data[$attr]) ? 'true' : 'false') : $data[$attr] ) : null; // Pattern matches and other operators. if ($op === '=' && $val && $val[0] === '/') { From c6173a0054ca61c2b05c1cd3d1ed6d651ce03618 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 10 Apr 2014 20:37:08 -0400 Subject: [PATCH 2/2] Add tests for #3288 and remove nested ternaries. Nested ternaries are complicated to maintain and hard to read. Break down the nested ternary into two conditionals. --- lib/Cake/Test/Case/Utility/HashTest.php | 33 +++++++++++++++++++++++++ lib/Cake/Utility/Hash.php | 8 +++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Utility/HashTest.php b/lib/Cake/Test/Case/Utility/HashTest.php index 037c6a2a7..65c1a0e39 100644 --- a/lib/Cake/Test/Case/Utility/HashTest.php +++ b/lib/Cake/Test/Case/Utility/HashTest.php @@ -831,6 +831,39 @@ class HashTest extends CakeTestCase { $this->assertEquals(5, $result[3]['id']); } +/** + * Test extracting based on attributes with boolean values. + * + * @return void + */ + public function testExtractAttributeBoolean() { + $users = array( + array( + 'id' => 2, + 'username' => 'johndoe', + 'active' => true + ), + array( + 'id' => 5, + 'username' => 'kevin', + 'active' => true + ), + array( + 'id' => 9, + 'username' => 'samantha', + 'active' => false + ), + ); + $result = Hash::extract($users, '{n}[active=false]'); + $this->assertCount(1, $result); + $this->assertEquals($users[2], $result[0]); + + $result = Hash::extract($users, '{n}[active=true]'); + $this->assertCount(2, $result); + $this->assertEquals($users[0], $result[0]); + $this->assertEquals($users[1], $result[1]); + } + /** * Test that attribute matchers don't cause errors on scalar data. * diff --git a/lib/Cake/Utility/Hash.php b/lib/Cake/Utility/Hash.php index b35cad715..fa22fe8d1 100644 --- a/lib/Cake/Utility/Hash.php +++ b/lib/Cake/Utility/Hash.php @@ -192,7 +192,13 @@ class Hash { return false; } - $prop = isset($data[$attr]) ? ( is_bool($data[$attr]) ? (($data[$attr]) ? 'true' : 'false') : $data[$attr] ) : null; + $prop = null; + if (isset($data[$attr])) { + $prop = $data[$attr]; + } + if ($prop === true || $prop === false) { + $prop = $prop ? 'true' : 'false'; + } // Pattern matches and other operators. if ($op === '=' && $val && $val[0] === '/') {