Making attributes work with any selector type.

Attributes work with all base selectors.
This commit is contained in:
mark_story 2012-01-23 22:35:54 -05:00
parent 9269a6dcde
commit 8ad4e66eba
2 changed files with 43 additions and 19 deletions

View file

@ -745,8 +745,25 @@ class Set2Test extends CakeTestCase {
public function testExtractAttributeComparison() { public function testExtractAttributeComparison() {
$data = self::articleData(); $data = self::articleData();
$result = Set2::extract($data, '{n}.Comment.{n}.[user_id > 2]'); $result = Set2::extract($data, '{n}.Comment.{n}[user_id > 2]');
$this->assertEquals($data[0]['Comment'][1], $result); $expected = array($data[0]['Comment'][1]);
$this->assertEquals($expected, $result);
$this->assertEquals(4, $expected[0]['user_id']);
$result = Set2::extract($data, '{n}.Comment.{n}[user_id >= 4]');
$expected = array($data[0]['Comment'][1]);
$this->assertEquals($expected, $result);
$this->assertEquals(4, $expected[0]['user_id']);
$result = Set2::extract($data, '{n}.Comment.{n}[user_id < 3]');
$expected = array($data[0]['Comment'][0]);
$this->assertEquals($expected, $result);
$this->assertEquals(2, $expected[0]['user_id']);
$result = Set2::extract($data, '{n}.Comment.{n}[user_id <= 2]');
$expected = array($data[0]['Comment'][0]);
$this->assertEquals($expected, $result);
$this->assertEquals(2, $expected[0]['user_id']);
} }
} }

View file

@ -125,6 +125,13 @@ class Set2 {
$token = array_shift($tokens); $token = array_shift($tokens);
$next = array(); $next = array();
$conditions = false;
$position = strpos($token, '[');
if ($position !== false) {
$conditions = substr($token, $position);
$token = substr($token, 0, $position);
}
foreach ($context[$_key] as $item) { foreach ($context[$_key] as $item) {
if ($token === '{n}') { if ($token === '{n}') {
// any numeric key // any numeric key
@ -147,7 +154,7 @@ class Set2 {
$next[] = $v; $next[] = $v;
} }
} }
} elseif (strpos($token, '[') === false) { } else {
// bare string key // bare string key
foreach ($item as $k => $v) { foreach ($item as $k => $v) {
// index or key match. // index or key match.
@ -155,16 +162,21 @@ class Set2 {
$next[] = $v; $next[] = $v;
} }
} }
} else { }
// attributes
foreach ($item as $k => $v) { }
debug(array($k => $v));
if (self::_matches(array($k => $v), $token)) { // Filter for attributes.
$next[] = $v; if ($conditions) {
} $filter = array();
foreach ($next as $item) {
if (self::_matches($item, $conditions)) {
$filter[] = $item;
} }
} }
$next = $filter;
} }
$context = array($_key => $next); $context = array($_key => $next);
} while (!empty($tokens)); } while (!empty($tokens));
@ -181,32 +193,27 @@ class Set2 {
*/ */
protected static function _matches(array $data, $selector) { protected static function _matches(array $data, $selector) {
preg_match_all( preg_match_all(
'/(?<key>[^\[]+?)? (\[ (?<attr>.+?) (?: \s* (?<op>[><!]?[=]) \s* (?<val>.*) )? \])+/x', '/(\[ (?<attr>.+?) (?: \s* (?<op>(?:[><!]?[=]|[><])) \s* (?<val>.*) )? \])+/x',
$selector, $selector,
$conditions, $conditions,
PREG_SET_ORDER PREG_SET_ORDER
); );
foreach ($conditions as $cond) { foreach ($conditions as $cond) {
$key = $cond['key'];
$attr = $cond['attr']; $attr = $cond['attr'];
$op = isset($cond['op']) ? $cond['op'] : null; $op = isset($cond['op']) ? $cond['op'] : null;
$val = isset($cond['val']) ? $cond['val'] : null; $val = isset($cond['val']) ? $cond['val'] : null;
if ($key && !isset($data[$key])) {
return false;
}
// Presence test. // Presence test.
if (empty($op) && empty($val)) { if (empty($op) && empty($val)) {
return isset($data[$key][$attr]); return isset($data[$attr]);
} }
// Empty attribute = fail. // Empty attribute = fail.
if (!isset($data[$key][$attr])) { if (!isset($data[$attr])) {
return false; return false;
} }
$prop = $data[$key][$attr]; $prop = $data[$attr];
if ($op === '=') { if ($op === '=') {
return $prop == $val; return $prop == $val;