function testRelatedFind() { $result = $this->TestRegion->find('all', array('contain' => 'Country')); $this->assertTrue(Set::matches('/TestRegion[title=Sydney]/../Country[title=Australia]', $result)); $this->assertFalse(Set::matches('/TestRegion[title=Sydney]/../Country[title=United States]', $result)); $this->assertTrue(Set::matches('/TestRegion[title=New York]/../Country[title=United States]', $result)); }
function testFindScoped() { $this->User->Behaviors->attach('Scope.Scope', array('field' => 'site_id', 'value' => 1)); $result = $this->User->find('all'); $expected = array('*****@*****.**', '*****@*****.**', '*****@*****.**'); $this->assertEqual($expected, Set::extract('/User/email', $result)); $result = $this->User->find('all', array('conditions' => array('User.email' => '*****@*****.**', 'User.site_id' => 2))); $this->assertTrue(Set::matches('/User[id=1]', $result)); }
function testFind() { $Model =& ClassRegistry::init('Song'); $Model->Behaviors->attach('Media.Coupler', $this->_behaviorSettings); $result = $Model->find('all'); $this->assertEqual(count($result), 4); /* Virtual */ $result = $Model->findById(1); $this->assertTrue(Set::matches('/Song/file', $result)); $this->assertEqual($result['Song']['file'], $this->file0); }
function testFind() { $Model =& ClassRegistry::init('Song'); $Model->Behaviors->attach('Media.Media', $this->_behaviorSettings); $result = $Model->find('all'); $this->assertEqual(count($result), 3); /* Virtual */ $result = $Model->findById(1); $this->assertTrue(Set::matches('/Song/size', $result)); $this->assertTrue(Set::matches('/Song/mime_type', $result)); }
public function testFind() { $Model = ClassRegistry::init('Song'); $Model->Behaviors->load('Media.Coupler', $this->behaviorSettings['Coupler']); $Model->Behaviors->load('Media.Meta', $this->behaviorSettings['Meta']); $result = $Model->find('all'); $this->assertEqual(count($result), 4); /* Virtual */ $result = $Model->findById(1); $this->assertTrue(Set::matches('/Song/size', $result)); $this->assertTrue(Set::matches('/Song/mime_type', $result)); }
public function testFind() { $Model = ClassRegistry::init('Song'); $Model->Behaviors->load('Media.Coupler', $this->behaviorSettings); $result = $Model->find('all'); $this->assertEqual(count($result), 4); $file = $this->Data->getFile(array('image-png.png' => $this->Data->settings['static'] . 'img/image-png.png')); /* Virtual */ $result = $Model->findById(1); $this->assertTrue(Set::matches('/Song/file', $result)); $this->assertEqual($result['Song']['file'], $file); }
function afterFind(&$Model, $results, $primary) { extract($this->settings[$Model->alias]); if (!Set::matches('/' . $with, $results)) { return; } foreach ($results as $i => $item) { foreach ($item[$with] as $field) { $results[$i][$Model->alias][$field['key']] = $field['val']; } } return $results; }
function testSave() { $this->File->id = 1; $this->File->set('colors', 16); $this->File->save(); $r = $this->File->find('first'); $this->assertTrue(Set::matches('/FileTestModel[1]/.[colors=16]', $r)); $this->assertTrue(Set::matches('/FileTestModel[1]/.[page_id=1]', $r)); $this->File->id = 2; $this->File->set('width', 640); $this->File->set('height', 480); $this->File->save(); $r = $this->File->find('first'); $this->assertTrue(Set::matches('/FileTestModel[1]/.[width=640]', $r)); $this->assertTrue(Set::matches('/FileTestModel[1]/.[height=480]', $r)); }
/** * @param $filter * @param $value * @param $element * @param string $path * @return array|mixed */ protected function _recursiveFilter($filter, $value, $element, $path = '') { if (is_array($value)) { $cleanValues = array(); $parent = $path; foreach ($value as $k => $v) { $path = $parent !== '' ? $parent . '.' . $k : $k; $cleanValues[$k] = $this->_recursiveFilter($filter, $v, $element, $path); } return $cleanValues; } else { if ($element === '__ALL__' || $element === $path || Set::matches($element, Set::expand(array($path => '')))) { return call_user_func($filter, $value); } else { return $value; } } }
/** * after a find this will join on the extra fields to the array so * they are available in the view. * * @var $Model object the model that did the find * @var $results array what was found * @var $primary if its the main model doing the call * * @return array the modified find data */ public function afterFind(&$Model, $results, $primary) { extract($this->settings[$Model->alias]); if (!Set::matches('/' . $with, $results)) { return; } foreach ($results as $i => $item) { $done = false; $keys = array_keys($item); foreach ($keys as $key) { if (strstr($key, 'Attribute')) { $item[$Model->alias][$item[$key]['key']] = $item[$key]['val']; $done = true; } } if ($done) { continue; } foreach ($item[$with] as $field) { $results[$i][$Model->alias][$field['key']] = $field['val']; } } return $results; }
/** * Private helper method to check conditions. * * @param array $record * @param array $conditions * @return bool */ private function __checkConditions($record, $conditions, $model) { $result = true; foreach ($conditions as $name => $value) { $alias = $model->alias; if (strpos($name, '.') !== false) { list($alias, $name) = explode('.', $name); } if (strtolower($name) === 'or') { $cond = $value; $result = false; foreach ($cond as $name => $value) { if (Set::matches($this->__createRule($name, $value), $record[$alias])) { return true; } } } else { if (!Set::matches($this->__createRule($name, $value), $record[$alias])) { return false; } } } return $result; }
/** * testMatches method * * @access public * @return void */ function testMatches() { $a = array(array('Article' => array('id' => 1, 'title' => 'Article 1')), array('Article' => array('id' => 2, 'title' => 'Article 2')), array('Article' => array('id' => 3, 'title' => 'Article 3'))); $this->assertTrue(Set::matches(array('id=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id>2'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id>=3'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id<=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id<2'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>1'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>1', 'id<3', 'id!=0'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('3'), null, 3)); $this->assertTrue(Set::matches(array('5'), null, 5)); $this->assertTrue(Set::matches(array('id'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id', 'title'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('non-existant'), $a[1]['Article'])); $this->assertTrue(Set::matches('/Article[id=2]', $a)); $this->assertFalse(Set::matches('/Article[id=4]', $a)); $this->assertTrue(Set::matches(array(), $a)); }
function beforeFind(&$Model, $query) { if (isset($query['nofilter']) && $query['nofilter'] === true) { return $query; } if (method_exists($Model, 'beforeDataFilter')) { $callbackOptions['values'] = $this->_filterValues[$Model->alias]; $callbackOptions['settings'] = $this->settings[$Model->alias]; if (!$Model->beforeDataFilter($query, $callbackOptions)) { return $query; } } if (!isset($this->settings[$Model->alias])) { return $query; } $settings = $this->settings[$Model->alias]; $values = $this->_filterValues[$Model->alias]; foreach ($settings as $field => $options) { $fieldModelName = $Model->alias; $fieldName = $field; if (strpos($field, '.') !== false) { list($fieldModelName, $fieldName) = explode('.', $field); } if (!isset($values[$fieldModelName][$fieldName]) && isset($options['default'])) { $values[$fieldModelName][$fieldName] = $options['default']; } if ($options['required'] && !isset($values[$fieldModelName][$fieldName])) { // TODO: implement a bit of a user friendly handling of this scenario.. trigger_error(__('No value present for required field %s and default value not present', $field)); return; } if (!isset($values[$fieldModelName][$fieldName]) || is_null($values[$fieldModelName][$fieldName])) { // no value to filter with, just skip this field continue; } // the value we get as condition and where it comes from is not the same as the // model and field we're using to filter the data $filterByField = $fieldName; $filterByModel = $Model->alias; $relationType = null; if ($fieldModelName != $Model->name) { $relationTypes = array('hasMany', 'hasOne'); foreach ($relationTypes as $type) { if (isset($Model->{$type}) && isset($Model->{$type}[$fieldModelName])) { $filterByModel = 'Filter' . $fieldModelName; $relationType = $type; break; } } } if (isset($options['filterField'])) { if (strpos($options['filterField'], '.') !== false) { list($tmpFieldModel, $tmpFieldName) = explode('.', $options['filterField']); $filterByField = $tmpFieldName; } else { $filterByField = $options['filterField']; } } $realFilterField = sprintf('%s.%s', $filterByModel, $filterByField); if (isset($Model->{$relationType}) && isset($Model->{$relationType}[$fieldModelName])) { $relatedModel = $Model->{$fieldModelName}; $relatedModelAlias = 'Filter' . $relatedModel->alias; if (!Set::matches(sprintf('/joins[alias=%s]', $relatedModelAlias), $query)) { $conditions = array(); if (isset($Model->{$relationType}[$fieldModelName]['foreignKey']) && $Model->{$relationType}[$fieldModelName]['foreignKey']) { $conditions[] = sprintf('%s.%s = %s.%s', $Model->alias, $Model->primaryKey, $relatedModelAlias, $Model->{$relationType}[$fieldModelName]['foreignKey']); } // merge any custom conditions from the relation, but change // the alias to our $relatedModelAlias if (isset($Model->{$relationType}[$fieldModelName]['conditions']) && !empty($Model->{$relationType}[$fieldModelName]['conditions'])) { $customConditions = $Model->{$relationType}[$fieldModelName]['conditions']; if (!is_array($Model->{$relationType}[$fieldModelName]['conditions'])) { $customConditions = array($customConditions); } $filterConditions = preg_replace(sprintf('#(?<![A-Za-z])%s(?![A-Za-z])#', $relatedModel->alias), $relatedModelAlias, $customConditions); $conditions = array_merge($conditions, $filterConditions); } $query['joins'][] = array('table' => $relatedModel->table, 'alias' => $relatedModelAlias, 'type' => 'INNER', 'conditions' => $conditions); } } // TODO: handle NULLs? switch ($options['type']) { case 'text': if (strlen(trim(strval($values[$fieldModelName][$fieldName]))) == 0) { continue; } switch ($options['condition']) { case 'like': case 'contains': $query['conditions'][$realFilterField . ' like'] = '%' . $values[$fieldModelName][$fieldName] . '%'; break; case 'startswith': $query['conditions'][$realFilterField . ' like'] = $values[$fieldModelName][$fieldName] . '%'; break; case 'endswith': $query['conditions'][$realFilterField . ' like'] = '%' . $values[$fieldModelName][$fieldName]; break; case '=': $query['conditions'][$realFilterField] = $values[$fieldModelName][$fieldName]; break; default: $query['conditions'][$realFilterField . ' ' . $options['condition']] = $values[$fieldModelName][$fieldName]; break; } break; case 'select': if (strlen(trim(strval($values[$fieldModelName][$fieldName]))) == 0) { continue; } $query['conditions'][$realFilterField] = $values[$fieldModelName][$fieldName]; break; case 'checkbox': $query['conditions'][$realFilterField] = $values[$fieldModelName][$fieldName]; break; } } if (method_exists($Model, 'afterDataFilter')) { $callbackOptions['values'] = $this->_filterValues[$Model->alias]; $callbackOptions['settings'] = $this->settings[$Model->alias]; $result = $Model->afterDataFilter($query, $callbackOptions); if (is_array($result)) { $query = $result; } } return $query; }
/** * Convenience function to assert Matches using Set::matches * * @param string $pattern * @param string $object * @param string $message * @return void */ private function __assertMatches($pattern, $object, $message = '') { return $this->assertTrue(Set::matches($pattern, $object), $message); return true; return $this->assert(new TrueExpectation(), Set::matches($pattern, $object), $message); }
/** * Standard afterFind() callback * Inject the expandable data (as fields) * * @param object Model $Model * @param mixed $results * @param boolean $primary * * @return mixed $results */ public function afterFind(Model $Model, $results, $primary) { $settings = $this->settings[$Model->alias]; if (!empty($settings['with'])) { $with = $settings['with']; if (!Set::matches('/' . $with, $results)) { return; } foreach (array_keys($results) as $i) { foreach (array_keys($results[$i][$with]) as $j) { $key = $results[$i][$with][$j]['key']; $value = $results[$i][$with][$j]['value']; $results[$i][$Model->alias][$key] = $value; } } } return $results; }
/** * Implements partial support for XPath 2.0. If $path does not contain a '/' the call * is delegated to Set::classicExtract(). Also the $path and $data arguments are * reversible. * * #### Currently implemented selectors: * * - /User/id (similar to the classic {n}.User.id) * - /User[2]/name (selects the name of the second User) * - /User[id>2] (selects all Users with an id > 2) * - /User[id>2][<5] (selects all Users with an id > 2 but < 5) * - /Post/Comment[author_name=john]/../name (Selects the name of all Posts that have at least one Comment written by john) * - /Posts[name] (Selects all Posts that have a 'name' key) * - /Comment/.[1] (Selects the contents of the first comment) * - /Comment/.[:last] (Selects the last comment) * - /Comment/.[:first] (Selects the first comment) * - /Comment[text=/cakephp/i] (Selects the all comments that have a text matching the regex /cakephp/i) * - /Comment/@* (Selects the all key names of all comments) * * #### Other limitations: * * - Only absolute paths starting with a single '/' are supported right now * * **Warning**: Even so it has plenty of unit tests the XPath support has not gone through a lot of * real-world testing. Please report Bugs as you find them. Suggestions for additional features to * implement are also very welcome! * * @param string $path An absolute XPath 2.0 path * @param array $data An array of data to extract from * @param array $options Currently only supports 'flatten' which can be disabled for higher XPath-ness * @return array An array of matched items * @link http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::extract */ public static function extract($path, $data = null, $options = array()) { if (is_string($data)) { $tmp = $data; $data = $path; $path = $tmp; } if (strpos($path, '/') === false) { return Set::classicExtract($data, $path); } if (empty($data)) { return array(); } if ($path === '/') { return $data; } $contexts = $data; $options = array_merge(array('flatten' => true), $options); if (!isset($contexts[0])) { $current = current($data); if (is_array($current) && count($data) < 1 || !is_array($current) || !Set::numeric(array_keys($data))) { $contexts = array($data); } } $tokens = array_slice(preg_split('/(?<!=|\\\\)\\/(?![a-z-\\s]*\\])/', $path), 1); do { $token = array_shift($tokens); $conditions = false; if (preg_match_all('/\\[([^=]+=\\/[^\\/]+\\/|[^\\]]+)\\]/', $token, $m)) { $conditions = $m[1]; $token = substr($token, 0, strpos($token, '[')); } $matches = array(); foreach ($contexts as $key => $context) { if (!isset($context['trace'])) { $context = array('trace' => array(null), 'item' => $context, 'key' => $key); } if ($token === '..') { if (count($context['trace']) == 1) { $context['trace'][] = $context['key']; } $parent = implode('/', $context['trace']) . '/.'; $context['item'] = Set::extract($parent, $data); $context['key'] = array_pop($context['trace']); if (isset($context['trace'][1]) && $context['trace'][1] > 0) { $context['item'] = $context['item'][0]; } elseif (!empty($context['item'][$key])) { $context['item'] = $context['item'][$key]; } else { $context['item'] = array_shift($context['item']); } $matches[] = $context; continue; } if ($token === '@*' && is_array($context['item'])) { $matches[] = array('trace' => array_merge($context['trace'], (array) $key), 'key' => $key, 'item' => array_keys($context['item'])); } elseif (is_array($context['item']) && array_key_exists($token, $context['item']) && !(strval($key) === strval($token) && count($tokens) == 1 && $tokens[0] === '.')) { $items = $context['item'][$token]; if (!is_array($items)) { $items = array($items); } elseif (!isset($items[0])) { $current = current($items); $currentKey = key($items); if (!is_array($current) || is_array($current) && count($items) <= 1 && !is_numeric($currentKey)) { $items = array($items); } } foreach ($items as $key => $item) { $ctext = array($context['key']); if (!is_numeric($key)) { $ctext[] = $token; $tok = array_shift($tokens); if (isset($items[$tok])) { $ctext[] = $tok; $item = $items[$tok]; $matches[] = array('trace' => array_merge($context['trace'], $ctext), 'key' => $tok, 'item' => $item); break; } elseif ($tok !== null) { array_unshift($tokens, $tok); } } else { $key = $token; } $matches[] = array('trace' => array_merge($context['trace'], $ctext), 'key' => $key, 'item' => $item); } } elseif ($key === $token || ctype_digit($token) && $key == $token || $token === '.') { $context['trace'][] = $key; $matches[] = array('trace' => $context['trace'], 'key' => $key, 'item' => $context['item']); } } if ($conditions) { foreach ($conditions as $condition) { $filtered = array(); $length = count($matches); foreach ($matches as $i => $match) { if (Set::matches(array($condition), $match['item'], $i + 1, $length)) { $filtered[$i] = $match; } } $matches = $filtered; } } $contexts = $matches; if (empty($tokens)) { break; } } while (1); $r = array(); foreach ($matches as $match) { if ((!$options['flatten'] || is_array($match['item'])) && !is_int($match['key'])) { $r[] = array($match['key'] => $match['item']); } else { $r[] = $match['item']; } } return $r; }
/** * testMatches method * * @return void */ public function testMatches() { $a = array(array('Article' => array('id' => 1, 'title' => 'Article 1')), array('Article' => array('id' => 2, 'title' => 'Article 2')), array('Article' => array('id' => 3, 'title' => 'Article 3'))); $this->assertTrue(Set::matches(array('id=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id>2'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id>=3'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id<=2'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('id<2'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>1'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id>1', 'id<3', 'id!=0'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('3'), NULL, 3)); $this->assertTrue(Set::matches(array('5'), NULL, 5)); $this->assertTrue(Set::matches(array('id'), $a[1]['Article'])); $this->assertTrue(Set::matches(array('id', 'title'), $a[1]['Article'])); $this->assertFalse(Set::matches(array('non-existant'), $a[1]['Article'])); $this->assertTrue(Set::matches('/Article[id=2]', $a)); $this->assertFalse(Set::matches('/Article[id=4]', $a)); $this->assertTrue(Set::matches(array(), $a)); $r = array('Attachment' => array('keep' => array()), 'Comment' => array('keep' => array('Attachment' => array('fields' => array(0 => 'attachment')))), 'User' => array('keep' => array()), 'Article' => array('keep' => array('Comment' => array('fields' => array(0 => 'comment', 1 => 'published')), 'User' => array('fields' => array(0 => 'user'))))); $this->assertTrue(Set::matches('/Article/keep/Comment', $r)); $this->assertEquals(array('comment', 'published'), Set::extract('/Article/keep/Comment/fields', $r)); $this->assertEquals(array('user'), Set::extract('/Article/keep/User/fields', $r)); }
/** * testOriginalAssociations method * * @return void */ public function testOriginalAssociations() { $this->Article->Comment->Behaviors->attach('Containable'); $options = array('conditions' => array('Comment.published' => 'Y'), 'contain' => 'User', 'recursive' => 1); $firstResult = $this->Article->Comment->find('all', $options); $this->Article->Comment->find('all', array('conditions' => array('User.user' => 'mariano'), 'fields' => array('User.password'), 'contain' => array('User.password'))); $result = $this->Article->Comment->find('all', $options); $this->assertEquals($firstResult, $result); $this->Article->unbindModel(array('hasMany' => array('Comment'), 'belongsTo' => array('User'), 'hasAndBelongsToMany' => array('Tag')), false); $this->Article->bindModel(array('hasMany' => array('Comment'), 'belongsTo' => array('User')), false); $r = $this->Article->find('all', array('contain' => array('Comment(comment)', 'User(user)'), 'fields' => array('title'))); $this->assertTrue(Set::matches('/Article[id=1]', $r)); $this->assertTrue(Set::matches('/User[id=1]', $r)); $this->assertTrue(Set::matches('/Comment[article_id=1]', $r)); $this->assertFalse(Set::matches('/Comment[id=1]', $r)); $r = $this->Article->find('all'); $this->assertTrue(Set::matches('/Article[id=1]', $r)); $this->assertTrue(Set::matches('/User[id=1]', $r)); $this->assertTrue(Set::matches('/Comment[article_id=1]', $r)); $this->assertTrue(Set::matches('/Comment[id=1]', $r)); $this->Article->bindModel(array('hasAndBelongsToMany' => array('Tag')), false); $this->Article->contain(false, array('User(id,user)', 'Comment' => array('fields' => array('comment'), 'conditions' => array('created >=' => '2007-03-18 10:49')))); $result = $this->Article->find('all', array('fields' => array('title'), 'limit' => 1, 'page' => 1, 'order' => 'Article.id ASC')); $expected = array(array('Article' => array('id' => 1, 'title' => 'First Article'), 'User' => array('id' => 1, 'user' => 'mariano'), 'Comment' => array(array('comment' => 'Third Comment for First Article', 'article_id' => 1), array('comment' => 'Fourth Comment for First Article', 'article_id' => 1)))); $this->assertEquals($expected, $result); $result = $this->Article->find('all', array('fields' => array('title', 'User.id', 'User.user'), 'limit' => 1, 'page' => 2, 'order' => 'Article.id ASC')); $expected = array(array('Article' => array('id' => 2, 'title' => 'Second Article'), 'User' => array('id' => 3, 'user' => 'larry'), 'Comment' => array(array('comment' => 'First Comment for Second Article', 'article_id' => 2), array('comment' => 'Second Comment for Second Article', 'article_id' => 2)))); $this->assertEquals($expected, $result); $result = $this->Article->find('all', array('fields' => array('title', 'User.id', 'User.user'), 'limit' => 1, 'page' => 3, 'order' => 'Article.id ASC')); $expected = array(array('Article' => array('id' => 3, 'title' => 'Third Article'), 'User' => array('id' => 1, 'user' => 'mariano'), 'Comment' => array())); $this->assertEquals($expected, $result); $this->Article->contain(false, array('User' => array('fields' => 'user'), 'Comment')); $result = $this->Article->find('all'); $this->assertTrue(Set::matches('/Article[id=1]', $result)); $this->assertTrue(Set::matches('/User[user=mariano]', $result)); $this->assertTrue(Set::matches('/Comment[article_id=1]', $result)); $this->Article->resetBindings(); $this->Article->contain(false, array('User' => array('fields' => array('user')), 'Comment')); $result = $this->Article->find('all'); $this->assertTrue(Set::matches('/Article[id=1]', $result)); $this->assertTrue(Set::matches('/User[user=mariano]', $result)); $this->assertTrue(Set::matches('/Comment[article_id=1]', $result)); $this->Article->resetBindings(); }
/** * Implements partial support for XPath 2.0. If $path is an array or $data is empty it the call is delegated to Set::classicExtract. * * Currently implemented selectors: * - /User/id (similar to the classic {n}.User.id) * - /User[2]/name (selects the name of the second User) * - /User[id>2] (selects all Users with an id > 2) * - /User[id>2][<5] (selects all Users with an id > 2 but < 5) * - /Post/Comment[author_name=john]/../name (Selects the name of all Posts that have at least one Comment written by john) * - /Posts[title] (Selects all Posts that have a 'name' key) * - /Comment/.[1] (Selects the contents of the first comment) * - /Comment/.[:last] (Selects the last comment) * - /Comment/.[:first] (Selects the first comment) * - /Comment[text=/cakephp/i] (Selects the all comments that have a text matching the regex /cakephp/i) * - /Comment/@* (Selects the all key names of all comments) * * Other limitations: * - Only absolute paths starting with a single '/' are supported right now * * Warning: Even so it has plenty of unit tests the XPath support has not gone through a lot of real-world testing. Please report * Bugs as you find them. Suggestions for additional features to imlement are also very welcome! * * @param string $path An absolute XPath 2.0 path * @param string $data An array of data to extract from * @param string $options Currently only supports 'flatten' which can be disabled for higher XPath-ness * @return array An array of matched items * @access public */ function extract($path, $data = null, $options = array()) { if (empty($data) && is_string($path) && $path[0] == '/') { return array(); } if (is_string($data) && $data[0] == '/') { $tmp = $path; $path = $data; $data = $tmp; } if (is_array($path) || empty($data) || is_object($path) || empty($path)) { return Set::classicExtract($path, $data); } if ($path == '/') { return $data; } $contexts = $data; $options = am(array('flatten' => true), $options); if (!isset($contexts[0])) { $contexts = array($data); } $tokens = array_slice(preg_split('/(?<!=)\\/(?![a-z]*\\])/', $path), 1); do { $token = array_shift($tokens); $conditions = false; if (preg_match_all('/\\[([^\\]]+)\\]/', $token, $m)) { $conditions = $m[1]; $token = substr($token, 0, strpos($token, '[')); } $matches = array(); $i = 0; $contextsCount = count($contexts); foreach ($contexts as $key => $context) { $i++; if (!isset($context['trace'])) { $context = array('trace' => array(), 'item' => $context, 'key' => null); } if ($token == '..') { $context['item'] = Set::extract(join('/', $context['trace']), $data); $context['key'] = array_pop($context['trace']); $context['item'] = $context['item'][0][$context['key']]; $matches[] = $context; continue; } $match = false; if ($token == '@*' && is_array($context['item'])) { $matches[] = array('trace' => am($context['trace'], $key), 'key' => $key, 'item' => array_keys($context['item'])); } elseif (is_array($context['item']) && array_key_exists($token, $context['item'])) { $items = $context['item'][$token]; if (!is_array($items) || !isset($items[0])) { $items = array($items); } foreach ($items as $item) { $matches[] = array('trace' => am($context['trace'], $context['key']), 'key' => $token, 'item' => $item); } } elseif ($key === $token || ctype_digit($token) && $key == $token || $token === '.') { $matches[] = array('trace' => am($context['trace'], $key), 'key' => $key, 'item' => $context['item']); } } if ($conditions) { foreach ($conditions as $condition) { $filtered = array(); $length = count($matches); foreach ($matches as $i => $match) { if (Set::matches(array($condition), $match['item'], $i + 1, $length)) { $filtered[] = $match; } } $matches = $filtered; } } $contexts = $matches; if (empty($tokens)) { break; } } while (1); $r = array(); foreach ($matches as $match) { if ((!$options['flatten'] || is_array($match['item'])) && !is_int($match['key'])) { $r[] = array($match['key'] => $match['item']); } else { $r[] = $match['item']; } } return $r; }
/** * ensure beforeFind supports inverse bit queries via 'bitmask' key * * @return void */ public function testBeforeFindAllowsFilteringByInverseBit() { $alias = $this->BitmaskedThing->getBitmaskedBitAlias(); $result1 = $this->BitmaskedThing->find('all', array('bitmask' => '~1')); $this->assertEmpty(Set::matches("/{$alias}[bits=1]", $result1), "Expect no results with bitmask value of 1"); }
function testMethodScopedWithoutSettings() { $this->User->Behaviors->attach('NamedScope', array('active')); $r = $this->User->active('all'); $this->assertTrue(Set::matches('/User[id=5]', $r)); $this->assertEqual(count($r), 5); }
/** * testSaveAllValidation method * * @access public * @return void */ function testSaveAllValidation() { $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment'); $TestModel =& new Post(); $data = array(array('id' => '1', 'title' => 'Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N'), array('id' => '2', 'title' => 'Just update the title'), array('title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'author_id' => 2)); $this->assertTrue($TestModel->saveAll($data)); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $ts = date('Y-m-d H:i:s'); $expected = array(array('Post' => array('id' => '1', 'author_id' => '1', 'title' => 'Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N', 'created' => '2007-03-18 10:39:23', 'updated' => $ts)), array('Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Just update the title', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23', 'updated' => $ts)), array('Post' => array('id' => '3', 'author_id' => '1', 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31')), array('Post' => array('id' => '4', 'author_id' => '2', 'title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'published' => 'N', 'created' => $ts, 'updated' => $ts))); $this->assertEqual($result, $expected); $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric'); $data = array(array('id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $result = $TestModel->saveAll($data); $this->assertEqual($result, false); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $errors = array(1 => array('title' => 'This field cannot be left blank')); $transactionWorked = Set::matches('/Post[1][title=Baleeted First Post]', $result); if (!$transactionWorked) { $this->assertTrue(Set::matches('/Post[1][title=Un-Baleeted First Post]', $result)); $this->assertTrue(Set::matches('/Post[2][title=Just update the title]', $result)); } $this->assertEqual($TestModel->validationErrors, $errors); $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric'); $data = array(array('id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $result = $TestModel->saveAll($data, array('atomic' => false)); $this->assertEqual($result, array(true, false)); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $errors = array(1 => array('title' => 'This field cannot be left blank')); $newTs = date('Y-m-d H:i:s'); $expected = array(array('Post' => array('id' => '1', 'author_id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => $newTs)), array('Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Just update the title', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23', 'updated' => $ts)), array('Post' => array('id' => '3', 'author_id' => '1', 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31')), array('Post' => array('id' => '4', 'author_id' => '2', 'title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'published' => 'N', 'created' => $ts, 'updated' => $ts))); $this->assertEqual($result, $expected); $this->assertEqual($TestModel->validationErrors, $errors); $data = array(array('id' => '1', 'title' => 'Re-Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $this->assertFalse($TestModel->saveAll($data, array('validate' => 'first'))); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $this->assertEqual($result, $expected); $this->assertEqual($TestModel->validationErrors, $errors); $data = array(array('title' => 'First new post', 'body' => 'Woohoo!', 'published' => 'Y'), array('title' => 'Empty body', 'body' => '')); $TestModel->validate['body'] = 'notEmpty'; }
protected function addFieldToFilter(&$Model, &$query, $settings, $values, $field, $field_options) { $configurationModelName = $Model->alias; $configurationFieldName = $field; if (strpos($field, '.') !== false) { list($configurationModelName, $configurationFieldName) = explode('.', $field); } if (!isset($values[$configurationModelName][$configurationFieldName]) && isset($field_options['default'])) { $values[$configurationModelName][$configurationFieldName] = $field_options['default']; } if ($field_options['required'] && !isset($values[$configurationModelName][$configurationFieldName])) { // TODO: implement a bit of a user friendly handling of this scenario.. trigger_error(__('No value present for required field %s and default value not present', $field)); return; } if (!isset($values[$configurationModelName][$configurationFieldName]) || empty($values[$configurationModelName][$configurationFieldName]) && $values[$configurationModelName][$configurationFieldName] != 0) { // no value to filter with, just skip this field return; } // the value we get as condition and where it comes from is not the same as the // model and field we're using to filter the data $filterFieldName = $configurationFieldName; $filterModelName = $configurationModelName; $relationType = null; if ($configurationModelName != $Model->alias) { $relationTypes = array('hasMany', 'hasOne', 'belongsTo'); foreach ($relationTypes as $type) { if (isset($Model->{$type}) && isset($Model->{$type}[$configurationModelName])) { $filterModelName = 'Filter' . $configurationModelName; $relationType = $type; break; } } } if (isset($field_options['filterField'])) { if (strpos($field_options['filterField'], '.') !== false) { list($filterModelName, $filterFieldName) = explode('.', $field_options['filterField']); if ($filterModelName != $Model->alias) { $filterModelName = 'Filter' . $filterModelName; } } else { $filterModelName = $Model->alias; $filterFieldName = $field_options['filterField']; } } $realFilterField = sprintf('%s.%s', $filterModelName, $filterFieldName); if (isset($Model->{$relationType}) && isset($Model->{$relationType}[$configurationModelName])) { $relatedModel = $Model->{$configurationModelName}; $relatedModelAlias = 'Filter' . $relatedModel->alias; if (!Set::matches(sprintf('/joins[alias=%s]', $relatedModelAlias), $query)) { $joinStatement = $this->buildFilterJoin($Model, $relatedModel); $query['joins'][] = $joinStatement; } } $this->buildFilterConditions($query, $realFilterField, $field_options, $values[$configurationModelName][$configurationFieldName]); }
function testComplexRevision() { // load fixtures $this->loadFixtures('MrlUser', 'MrlArticle', 'MrlComment', 'MrlTag', 'MrlArticlesMrlTag'); // load revision fixtures $this->loadFixtures('MrlArticlesRev', 'MrlCommentsRev', 'MrlTagsRev'); // set user id to pretend REAL login $user_id = 2; // find the time created of the comment above; ie "last known action of real user" $this->User->Article->Comment->id = 4; $newest = $this->User->Article->Comment->newest(); $version_created = $newest['Comment']['version_created']; // time to return to // inspect user and user data to set expected for last check; ie "are we back to this point" $result = $this->User->find('first', array('conditions' => array('User.id' => $user_id), 'contain' => array('Article' => array('Tag' => array(), 'Comment' => array()), 'Comment' => array()))); $this->assertTrue(Set::matches('/User', $result)); $this->assertTrue(Set::matches('/Article', $result)); $this->assertEqual(sizeof($result['Article']), 4); $this->assertTrue(Set::matches('/Article/Tag', $result)); $this->assertEqual(sizeof($result['Article'][0]['Tag']), 3); $this->assertEqual(sizeof($result['Article'][1]['Tag']), 2); $this->assertTrue(Set::matches('/Article/Comment', $result)); $this->assertEqual(sizeof($result['Article'][0]['Comment']), 3); $this->assertEqual(sizeof($result['Article'][1]['Comment']), 1); $this->assertTrue(Set::matches('/Comment', $result)); $this->assertEqual(sizeof($result['Comment']), 3); $this->assertFalse(Set::matches('/Comment/Article', $result)); $this->assertFalse(Set::matches('/Comment/User', $result)); $original_state = $result; $this->User->lang('es-es'); $original_spanish_state = $this->User->find('first', array('conditions' => array('User.id' => $user_id), 'contain' => array('Article' => array('Tag' => array(), 'Comment' => array()), 'Comment' => array()))); $this->User->lang(); // assume now logged in as hijacker // delete an article $this->assertTrue($this->User->Article->delete(4)); // edit and change tags a 2nd article $this->assertTrue($this->User->Article->save(array('Article' => array('id' => 1, 'title' => 'haha', 'content' => 'you been had!'), 'Tag' => array('Tag' => array(1, 4))))); // add tags $this->assertTrue($this->User->Article->save(array('Article' => array('id' => 1), 'Tag' => array('Tag' => array(1, 2, 3, 4))))); // create a 4th article $this->User->Article->create(array('title' => 'spam', 'content' => 'spam', 'user_id' => $user_id)); $this->assertTrue($this->User->Article->save()); // translate an article $this->User->lang('es-es'); $this->User->Article->save(array('Article' => array('id' => 1, 'title' => 'edited spanish title', 'content' => 'edited spanish content'))); $this->User->lang(); // create many comments on 2nd, 3rd, 4th and a 5th article $spam_comment = array('user_id' => $user_id, 'article_id' => 2, 'content' => 'spam'); $this->User->Article->Comment->create($spam_comment); $this->assertTrue($this->User->Article->Comment->save()); $this->User->Article->Comment->create($spam_comment); $this->assertTrue($this->User->Article->Comment->save()); $spam_comment['article_id'] = 1; $this->User->Article->Comment->create($spam_comment); $this->assertTrue($this->User->Article->Comment->save()); $this->User->lang('es-es'); // translate a comment $this->User->Article->Comment->save(array('Comment' => array('id' => 3, 'content' => 'spanish comment content added'))); // delete comments on a translated article $this->User->Article->Comment->delete(2); // edit a translation $this->User->Article->Comment->save(array('Comment' => array('id' => 1, 'content' => 'edited spanish comment content'))); $this->User->lang(); // create comments on an article not made by this user $spam_comment['article_id'] = 3; $this->User->Article->Comment->create($spam_comment); $this->assertTrue($this->User->Article->Comment->save()); // add a tag and add it to all user's articles $this->User->Article->Tag->create(array('title' => 'SPAM')); $this->assertTrue($this->User->Article->Tag->save()); $this->User->Article->Tag->save(array('Tag' => array('id' => $this->User->Article->Tag->id), 'Article' => array('Article' => array(1, 2, 3, 5, 6)))); // pretend hijacker log out // inspect user and user data to verify that all illegal activity is in database; ie start != now $result = $this->User->find('first', array('conditions' => array('User.id' => $user_id), 'contain' => array('Article' => array('Tag' => array(), 'Comment' => array()), 'Comment' => array()))); $this->assertTrue(Set::matches('/User', $result)); $this->assertTrue(Set::matches('/Article', $result)); $this->assertEqual(sizeof($result['Article']), 4); $this->assertTrue(Set::matches('/Article/Tag', $result)); $this->assertEqual(sizeof($result['Article'][0]['Tag']), 5); $this->assertEqual($result['Article'][0]['Tag'][4]['title'], 'SPAM'); $this->assertEqual(sizeof($result['Article'][1]['Tag']), 3); $this->assertEqual(sizeof($result['Article'][2]['Tag']), 1); $this->assertEqual(sizeof($result['Article'][3]['Tag']), 1); $this->assertEqual($result['Article'][3]['Tag'][0]['title'], 'SPAM'); $this->assertTrue(Set::matches('/Article/Comment', $result)); $this->assertEqual(sizeof($result['Article'][0]['Comment']), 4); $this->assertEqual($result['Article'][0]['Comment'][3]['content'], 'spam'); $this->assertEqual(sizeof($result['Article'][1]['Comment']), 3); $this->assertTrue(Set::matches('/Comment', $result)); $this->assertEqual(sizeof($result['Comment']), 7); $this->assertFalse(Set::matches('/Comment/Article', $result)); $this->assertFalse(Set::matches('/Comment/User', $result)); // inspect log to verify that hijacked activity is all logged // identify the "last known action of real user" comment and // revert to this datetime, cascading to all users articles and comments $this->User->id = $user_id; $this->assertTrue($this->User->revertToDate($version_created, true, true), 'revertToDate returns false! : %s'); // verify that start == now $result = $this->User->find('first', array('conditions' => array('User.id' => $user_id), 'contain' => array('Article' => array('Tag' => array(), 'Comment' => array()), 'Comment' => array()))); $this->assertEqual($original_state['User'], $result['User'], 'Revert of User failed : %s'); $this->assertEqual($original_state['Article'], $result['Article'], 'Revert of Article failed : %s'); $this->assertEqual(sizeof($original_state['Article']), sizeof($result['Article']), 'Wrong number of articles : %s'); $this->assertEqual($original_state['Article'][0]['Tag'], $result['Article'][0]['Tag'], 'Revert of Tag failed : %s'); $this->assertEqual($original_state['Article'][0]['Comment'], $result['Article'][0]['Comment'], 'Revert of Tag failed : %s'); $this->assertEqual($original_state['Comment'], $result['Comment'], 'Revert of Comment failed : %s'); $this->assertEqual(sizeof($original_state['Comment']), sizeof($result['Comment']), 'Wrong number of comments : %s'); $this->User->lang('es-es'); $reverted_spanish_state = $this->User->find('first', array('conditions' => array('User.id' => $user_id), 'contain' => array('Article' => array('Tag' => array(), 'Comment' => array()), 'Comment' => array()))); $this->assertEqual($original_spanish_state, $reverted_spanish_state); }
/** * Test getPermission() * * @return void */ public function testGetPermission() { Permissionable::setUserId(2); Permissionable::setGroupId(2); Permissionable::setGroupIds(array(2, 3, 4)); $this->Thing->create(); $this->Thing->save(array('Thing' => array('name' => 'Baz', 'desc' => 'Baz is a Thing'), 'Permissionable' => array('perms' => 480))); $result1 = $this->Thing->getPermission(); $this->assertTrue($result1); $this->assertTrue(Set::matches('/ThingPermissionBit[perms=480]', $result1)); $this->Thing->id = null; $result2 = $this->Thing->getPermission(); $this->assertFalse($result2); }
/** * Checks a specific rule * * @param string $name Rule * @param string $value Rule value * @param string $record * @return bool */ protected function _checkRule($name, $value, $record) { if (strpos($name, ' LIKE') !== false) { $name = str_replace(' LIKE', '', $name); return preg_match('~' . str_replace('%', '.?', $value) . '~', $record[$name]) === 1; } return Set::matches($this->_createRule($name, $value), $record); }
/** * testRealQueries method * * @access public * @return void */ function testRealQueries() { $this->loadFixtures('Apple', 'Article', 'User', 'Comment', 'Tag'); $Apple =& ClassRegistry::init('Apple'); $Article =& ClassRegistry::init('Article'); $result = $this->db->rawQuery('SELECT color, name FROM ' . $this->db->fullTableName('apples')); $this->assertTrue(!empty($result)); $result = $this->db->fetchRow($result); $expected = array($this->db->fullTableName('apples', false) => array('color' => 'Red 1', 'name' => 'Red Apple 1')); $this->assertEqual($result, $expected); $result = $this->db->fetchAll('SELECT name FROM ' . $this->testDb->fullTableName('apples') . ' ORDER BY id'); $expected = array(array($this->db->fullTableName('apples', false) => array('name' => 'Red Apple 1')), array($this->db->fullTableName('apples', false) => array('name' => 'Bright Red Apple')), array($this->db->fullTableName('apples', false) => array('name' => 'green blue')), array($this->db->fullTableName('apples', false) => array('name' => 'Test Name')), array($this->db->fullTableName('apples', false) => array('name' => 'Blue Green')), array($this->db->fullTableName('apples', false) => array('name' => 'My new apple')), array($this->db->fullTableName('apples', false) => array('name' => 'Some odd color'))); $this->assertEqual($result, $expected); $result = $this->db->field($this->testDb->fullTableName('apples', false), 'SELECT color, name FROM ' . $this->testDb->fullTableName('apples') . ' ORDER BY id'); $expected = array('color' => 'Red 1', 'name' => 'Red Apple 1'); $this->assertEqual($result, $expected); $Apple->unbindModel(array(), false); $result = $this->db->read($Apple, array('fields' => array($Apple->escapeField('name')), 'conditions' => null, 'recursive' => -1)); $expected = array(array('Apple' => array('name' => 'Red Apple 1')), array('Apple' => array('name' => 'Bright Red Apple')), array('Apple' => array('name' => 'green blue')), array('Apple' => array('name' => 'Test Name')), array('Apple' => array('name' => 'Blue Green')), array('Apple' => array('name' => 'My new apple')), array('Apple' => array('name' => 'Some odd color'))); $this->assertEqual($result, $expected); $result = $this->db->read($Article, array('fields' => array('id', 'user_id', 'title'), 'conditions' => null, 'recursive' => 1)); $this->assertTrue(Set::matches('/Article[id=1]', $result)); $this->assertTrue(Set::matches('/Comment[id=1]', $result)); $this->assertTrue(Set::matches('/Comment[id=2]', $result)); $this->assertFalse(Set::matches('/Comment[id=10]', $result)); }
/** * Private helper method to check conditions. * * @param array $record * @param array $conditions * @return bool * @access private */ function __checkConditions($record, $conditions) { $result = true; foreach ($conditions as $name => $value) { if (strtolower($name) === 'or') { $cond = $value; $result = false; foreach ($cond as $name => $value) { if (Set::matches($this->__createRule($name, $value), $record)) { return true; } } } else { if (!Set::matches($this->__createRule($name, $value), $record)) { return false; } } } return $result; }
/** * testSaveManyValidation method * * @return void */ public function testSaveManyValidation() { $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment'); $TestModel = new Post(); $data = array(array('id' => '1', 'title' => 'Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N'), array('id' => '2', 'title' => 'Just update the title'), array('title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'author_id' => 2)); $this->assertTrue($TestModel->saveMany($data)); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $expected = array(array('Post' => array('id' => '1', 'author_id' => '1', 'title' => 'Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N', 'created' => '2007-03-18 10:39:23')), array('Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Just update the title', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23')), array('Post' => array('id' => '3', 'author_id' => '1', 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31')), array('Post' => array('id' => '4', 'author_id' => '2', 'title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'published' => 'N'))); $this->assertEquals(self::date(), $result[0]['Post']['updated']); $this->assertEquals(self::date(), $result[1]['Post']['updated']); $this->assertEquals(self::date(), $result[3]['Post']['created']); $this->assertEquals(self::date(), $result[3]['Post']['updated']); unset($result[0]['Post']['updated'], $result[1]['Post']['updated']); unset($result[3]['Post']['created'], $result[3]['Post']['updated']); $this->assertEquals($expected, $result); $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric'); $data = array(array('id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $result = $TestModel->saveMany($data); $this->assertFalse($result); $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC')); $errors = array(1 => array('title' => array('This field cannot be left blank'))); $transactionWorked = Set::matches('/Post[1][title=Baleeted First Post]', $result); if (!$transactionWorked) { $this->assertTrue(Set::matches('/Post[1][title=Un-Baleeted First Post]', $result)); $this->assertTrue(Set::matches('/Post[2][title=Just update the title]', $result)); } $this->assertEquals($errors, $TestModel->validationErrors); $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric'); $data = array(array('id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $result = $TestModel->saveMany($data, array('validate' => true, 'atomic' => false)); $this->assertEquals(array(true, false), $result); $result = $TestModel->find('all', array('fields' => array('id', 'author_id', 'title', 'body', 'published'), 'recursive' => -1, 'order' => 'Post.id ASC')); $errors = array(1 => array('title' => array('This field cannot be left blank'))); $expected = array(array('Post' => array('id' => '1', 'author_id' => '1', 'title' => 'Un-Baleeted First Post', 'body' => 'Not Baleeted!', 'published' => 'Y')), array('Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Just update the title', 'body' => 'Second Post Body', 'published' => 'Y')), array('Post' => array('id' => '3', 'author_id' => '1', 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y')), array('Post' => array('id' => '4', 'author_id' => '2', 'title' => 'Creating a fourth post', 'body' => 'Fourth post body', 'published' => 'N'))); $this->assertEquals($expected, $result); $this->assertEquals($errors, $TestModel->validationErrors); $data = array(array('id' => '1', 'title' => 'Re-Baleeted First Post', 'body' => 'Baleeted!', 'published' => 'N'), array('id' => '2', 'title' => '', 'body' => 'Trying to get away with an empty title')); $this->assertFalse($TestModel->saveMany($data, array('validate' => 'first'))); $result = $TestModel->find('all', array('fields' => array('id', 'author_id', 'title', 'body', 'published'), 'recursive' => -1, 'order' => 'Post.id ASC')); $this->assertEquals($expected, $result); $this->assertEquals($errors, $TestModel->validationErrors); }
/** * @brief hack to get the attributes for comments * * @todo this is a hack to get the atributes in the comment, this should * be handled in the attributes behavior but cake does not do model callbacks * 3 relations deep * * @param array $results the data found * @param bool $primary is this the primary model doing the find * @access public * * @return array the results after bing formatted */ public function afterFind($results, $primary) { if ($this->findQueryType == 'linkedComments') { return $results; } if (isset($results[0][0]['count'])) { return $results; } $base = array_merge(array('schema' => $this->schema()), array('with' => 'InfinitasCommentAttribute', 'foreignKey' => $this->hasMany['InfinitasCommentAttribute']['foreignKey'])); if (!Set::matches('/' . $base['with'], $results)) { return $results; } if (isset($results[0]) || $primary) { foreach ($results as $k => $item) { foreach ($item[$base['with']] as $field) { $results[$k][$field['key']] = $field['val']; } unset($results[$k][$base['with']]); } } else { foreach ($results[$base['with']] as $field) { $results[$field['key']] = $field['val']; } } return $results; }