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