- '/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=/lithium/i]': Selects the all comments that have
a text matching the regex /lithium/i.
- '/Comment/@*': Selects all key names of all comments.
/** * returns rendered content * * @param string $content input content * @param string $data field to retrieve from configuration * @param array $options an array with additional options * @return string content as given * @filter */ public function get($content, $data = null, array $options = array()) { $defaults = array('default' => null, 'flat' => false); $options += $defaults; $params = compact('content', 'data', 'options'); return $this->_filter(__METHOD__, $params, function ($self, $params) { extract($params); try { $config = IniFormat::parse($content); } catch (IniFormatException $e) { return $options['default']; } catch (Exception $e) { return $options['default']; } if (empty($data)) { return $options['flat'] ? Set::flatten($config) : $config; } if (is_scalar($data) && isset($config[$data])) { return $config[$data]; } $data = '/' . str_replace('.', '/', (string) $data) . '/.'; $result = current(Set::extract((array) $config, $data)); if (!empty($result)) { return $result; } return $options['default']; }); }
/** * parses an ini-style string into an array * * when entering data into ini-style input fields, make sure, that you comply with the following * rules (read up on http://php.net/parse_ini_string): * * There are reserved words which must not be used as keys for ini files. These include: * * `null`, `yes`, `no`, `true`, `false`, `on`, `off` and `none` * * Values `null`, `no` and `false` results in "", `yes` and `true` results in "1". * Characters ?{}|&~![()^" must not be used anywhere in the key and have a special meaning * in the value. So better not use them. * * @see http://php.net/parse_ini_string * @see lithium\util\Set::expand() * @param string|array $data the string to be parsed, or an array thereof * @param array $options an array of options currently supported are * - `default` : what to return, if nothing is found, defaults to an empty array * - `process_sections` : to enable process_sections, defaults to true * - `scanner_mode` : set scanner_mode to something different than INI_SCANNER_NORMAL * @return array an associative, eventually multidimensional array or the `default` option. */ public static function parse($data = null, array $options = array()) { $defaults = array('default' => array(), 'scanner_mode' => INI_SCANNER_NORMAL, 'process_sections' => true); $options += $defaults; if (empty($data)) { return $options['default']; } if (is_array($data)) { foreach ($data as $key => $value) { $data[$key] = static::parse($value, $options); } return $data; } $raw = parse_ini_string(static::filter($data), $options['process_sections'], $options['scanner_mode']); if (empty($raw)) { return $options['default']; } try { $result = Set::expand($raw); } catch (Exception $e) { $error = $e->getMessage(); $e = new IniFormatException(sprintf('IniFormat Error: %s', $error)); $e->setData(compact('data', 'raw', 'options')); throw $e; } return $result; }
/** * Magic method to make Controller callable. * * @see lithium\action\Dispatcher::_callable() * @param \lithium\action\Request $request * @param array $dispatchParams Array of params after being parsed by router. * @param array $options Some basic options for this controller. * @return string * @filter */ public function __invoke($request, $dispatchParams, array $options = array()) { $dispatchParamsDefaults = array('args' => array()); $dispatchParams += $dispatchParamsDefaults; $defaults = array('format' => 'html', 'timeout' => 0); $options += (array) $request->query + $defaults; $params = compact('request', 'dispatchParams', 'options'); return $this->_filter(__METHOD__, $params, function ($self, $params) { $request = $params['request']; $options = $params['options']; $params = $params['dispatchParams']; set_time_limit((int) $options['timeout']); $group = join('\\', (array) $params['args']); if ($group === "all") { $group = Group::all(); $options['title'] = 'All Tests'; } $self->invokeMethod('_saveCtrlContext'); $report = Dispatcher::run($group, $options); $self->invokeMethod('_restoreCtrlContext'); $filters = Libraries::locate('test.filter'); $menu = Libraries::locate('tests', null, array('filter' => '/cases|integration|functional/', 'exclude' => '/mocks/')); sort($menu); $menu = Set::expand(array_combine($menu, $menu), array('separator' => "\\")); $result = compact('request', 'report', 'filters', 'menu'); return $report->render('layout', $result); }); }
/** * returns rendered content * * @param string $content input content * @param string $data field to retrieve from configuration * @param array $options an array with additional options * @return string content as given * @filter */ public function get($content, $data = null, array $options = array()) { $defaults = array('default' => array(), 'flat' => false); $options += $defaults; $params = compact('content', 'data', 'options'); return $this->_filter(__METHOD__, $params, function ($self, $params) { extract($params); try { $config = NeonFormatter::decode($content); } catch (NeonException $e) { return $options['default']; } catch (Exception $e) { return $options['default']; } if (!empty($data) && is_scalar($data)) { if (array_key_exists($data, (array) $config)) { return $config[$data]; } } if ($data) { $data = '/' . str_replace('.', '/', $data) . '/.'; $result = current(Set::extract((array) $config, $data)); return !empty($result) ? $result : null; } return $options['flat'] ? Set::flatten($config) : $config; }); }
public static function find(array $options = array()) { $defaults = array('collect' => true); $options += $defaults; $data = array(); $libs = Libraries::get(null, 'path'); $recursive = true; foreach ($libs as $lib => $path) { $result = array(); $path .= '/views/widgets'; $files = StaticContents::available(compact('path', 'recursive')); if (!$files) { continue; } $temp = array_keys(Set::flatten($files, array('separator' => '/'))); foreach ($temp as $key => $value) { if (strpos($value, 'admin.') !== false) { continue; } if (strpos($value, 'inc.') !== false) { continue; } $result[$key] = str_replace('.html.php', '', $value); } $data[$lib] = $result; } return $data; }
/** * Object constructor. * Instantiates the Memcached object, adds appropriate servers to the pool, * and configures any optional settings passed. * * @see lithium\storage\Cache::config() * @param array $config Configuration parameters for this cache adapter. * These settings are indexed by name and queryable * through `Cache::config('name')`. * @return void */ public function __construct(array $config = array()) { $defaults = array('prefix' => '', 'expiry' => '+1 hour', 'servers' => array(array('127.0.0.1', 11211, 100))); if (is_null(static::$connection)) { static::$connection = new \Memcached(); } $configuration = Set::merge($defaults, $config); parent::__construct($configuration); static::$connection->addServers($this->_config['servers']); }
public function testArrayConfiguration() { $result = Configurations::create(Set::merge($this->_default, array('type' => 'array', 'value' => 'foo=bar'))); $this->assertEqual(array('foo' => 'bar'), $result->val()); $this->assertEqual('bar', $result->val('foo')); $result = Configurations::create(Set::merge($this->_default, array('type' => 'array', 'value' => "foo.bar=baz\nfoo.baz=bar"))); $this->assertEqual(array('foo' => array('bar' => 'baz', 'baz' => 'bar')), $result->val()); $this->assertEqual(array('bar' => 'baz', 'baz' => 'bar'), $result->val('foo')); $this->assertEqual('baz', $result->val('foo.bar')); }
/** * Parses an associative array into an array, containing one * array for each row, that has 'key' and 'value' filled * as expected. That makes rendering of arbitrary meta-data * much simpler, e.g. if you do not know, what data you are * about to retrieve. * * @param array $data an associative array containing mixed data * @return array an numerical indexed array with arrays for each * item in $data, having 'key' and 'value' set accordingly */ public function data(array $data = array(), array $options = array()) { $defaults = array('flatten' => true); $options += $defaults; if ($options['flatten']) { $data = Set::flatten($this->_extract($data)); } return array_map(function ($key, $value) { return compact('key', 'value'); }, array_keys($data), $data); }
/** * Initializes the record set and uses the database connection to get the column list contained * in the query that created this object. * * @see lithium\data\collection\RecordSet::$_columns * @return void * @todo The part that uses _handle->schema() should be rewritten so that the column list * is coming from the query object. */ protected function _init() { parent::_init(); if ($this->_result) { $this->_columns = $this->_columnMap(); if ($this->_query) { $columns = array_filter(array_keys($this->_columns)); $this->_dependencies = Set::expand(Set::normalize($columns)); $this->_keyIndex = $this->_keyIndex(''); } } }
public function connections() { $data = Connections::get(); $connections = new Collection(compact('data')); if (true || $this->request->is('json')) { $connections->each(function ($name) { $config = Connections::get($name, array('config' => true)); unset($config['object']); return array_merge(compact('name'), Set::flatten($config)); }); } return compact('connections'); }
/** * Create `RecaptchaOptions` javascript object if you have additional options configured * @param array $options `'key' => 'value'` pairs to be converted to javascript * object as `RecaptchaOptions` * @see https://developers.google.com/recaptcha/docs/customization * @return null|string Return null if you don't have additional options * or script with `RecaptchaOptions` object */ protected function _recaptchaOptions(array $options = array()) { $defaults = Libraries::get('li3_recaptcha', 'options'); if ($defaults) { $options = Set::merge($defaults, $options); } if (empty($options)) { return null; } $script = '<script type="text/javascript">'; $script .= 'var RecaptchaOptions = ' . json_encode($options) . ';'; $script .= '</script>'; return $script; }
/** * Initializes the record set and uses the database connection to get the column list contained * in the query that created this object. * * @see lithium\data\collection\RecordSet::$_columns * @return void * @todo The part that uses _handle->schema() should be rewritten so that the column list * is coming from the query object. */ protected function _init() { parent::_init(); if (!$this->_result) { return; } $this->_columns = $this->_columnMap(); if (!$this->_query) { return; } $this->_keyIndex = $this->_keyIndex(); $this->_dependencies = Set::expand(Set::normalize(array_filter(array_keys($this->_columns)))); $this->_relationships = $this->_query->relationships(); }
/** * Runs a test group or a specific test file based on the passed * parameters. * * @param string $group If set, this test group is run. If not set, a group test may * also be run by passing the 'group' option to the $options parameter. * @param array $options Options array for the test run. Valid options are: * - 'case': The fully namespaced test case to be run. * - 'group': The fully namespaced test group to be run. * - 'filters': An array of filters that the test output should be run through. * @return array A compact array of the title, an array of the results, as well * as an additional array of the results after the $options['filters'] * have been applied. */ public static function run($group = null, $options = array()) { $defaults = array('title' => $group, 'filters' => array(), 'reporter' => 'text'); $options += $defaults; $items = (array) $group; $isCase = preg_match('/Test$/', $group); if ($isCase) { $items = array(new $group()); } $options['filters'] = Set::normalize($options['filters']); $group = static::_group($items); $report = static::_report($group, $options); $report->run(); return $report; }
public static function parse($conditions, $data, array $options = array()) { $params = compact('conditions', 'data', 'options'); return static::_filter(__METHOD__, $params, function ($self, $params) { extract($params); $defaults = array(); $options += $defaults; $check = String::insert($conditions, Set::flatten($data)); if (strpbrk($check, '&|')) { return eval("return (boolean)({$check});"); } // TODO: take care, that spaces are around operator return $self::invokeMethod('compare', explode(" ", $check, 3)); }); }
/** * Runs a test group or a specific test file based on the passed * parameters. * * @param string $group If set, this test group is run. If not set, a group test may * also be run by passing the 'group' option to the $options parameter. * @param array $options Options array for the test run. Valid options are: * - 'case': The fully namespaced test case to be run. * - 'group': The fully namespaced test group to be run. * - 'filters': An array of filters that the test output should be run through. * @return array A compact array of the title, an array of the results, as well * as an additional array of the results after the $options['filters'] * have been applied. * @filter */ public static function run($group = null, array $options = array()) { $defaults = array('title' => $group, 'filters' => array(), 'reporter' => 'text'); $options += $defaults; $isCase = is_string($group) && preg_match('/Test$/', $group); $items = $isCase ? array(new $group()) : (array) $group; $options['filters'] = Set::normalize($options['filters']); $group = static::_group($items); $report = static::_report($group, $options); return static::_filter(__FUNCTION__, compact('report'), function ($self, $params, $chain) { $environment = Environment::get(); Environment::set('test'); $params['report']->run(); Environment::set($environment); return $params['report']; }); }
/** * Renders `$data` into an easier to understand, or flat, array. * * @param array $data Data to traverse. * @return array */ protected function _toString($data) { foreach ($data as $key => $val) { switch (true) { case is_object($val) && !$val instanceof Closure: try { $data[$key] = (string) $val; } catch (Exception $e) { $data[$key] = ''; } break; case is_array($val): $data = array_merge($data, Set::flatten($val)); break; } } return $data; }
public function loadMetadataForClass($className, ClassMetadataInfo $metadata) { if (!$metadata->reflClass instanceof SchemaReflection) { $metadata->reflClass = new SchemaReflection(get_class($metadata)); } $metadata->primaryTable['name'] = $className::meta('source'); $primaryKey = $className::meta('key'); $bindings = static::bindings($className); $relations = array(); if (!empty($bindings)) { foreach ($bindings as $type => $set) { foreach ($set as $key => $relation) { $mapping = array('fetch' => \Doctrine\ORM\Mapping\AssociationMapping::FETCH_EAGER, 'fieldName' => $relation['fieldName'], 'sourceEntity' => $className, 'targetEntity' => $relation['class'], 'mappedBy' => null, 'cascade' => !empty($relation['dependent']) ? array('remove') : array(), 'optional' => $type != 'belongsTo'); if (in_array($type, array('hasOne', 'hasMany'))) { $inverse = $type == 'belongsTo'; $mapping['joinColumns'][] = array('fieldName' => !$inverse ? $relation['key'] : $relation['fieldName'], 'name' => !$inverse ? $relation['fieldName'] : $relation['key'], 'referencedColumnName' => $relation['class']::meta('key')); } if (in_array($type, array('belongsTo', 'hasOne', 'hasMany'))) { $mapping['mappedBy'] = static::_fieldName($mapping); } $relations[$type][$key] = $mapping; } } } $schema = (array) $className::schema(); $metadata->reflClass->setRelations($relations); $metadata->reflClass->setSchema($schema); $belongsToFields = !empty($bindings['belongsTo']) ? Set::combine(array_values($bindings['belongsTo']), '/key', '/fieldName') : array(); foreach ($schema as $field => $column) { $mapping = array_merge(array('id' => $field == $primaryKey, 'fieldName' => !empty($belongsToFields[$field]) ? $belongsToFields[$field] : $field, 'columnName' => $field), (array) $column); $metadata->mapField($mapping); if ($mapping['id']) { $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_AUTO); } } foreach ($relations as $type => $set) { foreach ($set as $key => $mapping) { $metadata->{static::$_bindingMapping[$type]}($mapping); $mapping = $metadata->associationMappings[$mapping['fieldName']]; } } }
public function run($id = null) { $id = !is_null($id) ? $id : $this->request->id; $model = $this->scaffold['model']; $object = $model::first($id); if (!$object) { $url = array('action' => 'index'); return $this->redirect($url); } list($temp, $options) = Set::slice($this->request->data, array('validate', 'strict')); switch ($this->request->data['mode']) { case 'keep': $options['overwrite'] = false; break; case 'remove': $options['prune'] = true; break; } $result = $object->run($options); $url = array('action' => 'view', 'args' => array((string) $object->{$model::key()})); return $this->redirect($url); }
/** * Pulls request data from superglobals. * * @return void */ protected function _init() { parent::_init(); $mobile = array('iPhone', 'MIDP', 'AvantGo', 'BlackBerry', 'J2ME', 'Opera Mini', 'DoCoMo', 'NetFront', 'Nokia', 'PalmOS', 'PalmSource', 'portalmmm', 'Plucker', 'ReqwirelessWeb', 'iPod', 'SonyEricsson', 'Symbian', 'UP\\.Browser', 'Windows CE', 'Xiino', 'Android'); if (!empty($this->_config['detectors']['mobile'][1])) { $mobile = array_merge($mobile, (array) $this->_config['detectors']['mobile'][1]); } $this->_detectors['mobile'][1] = $mobile; $this->_env += (array) $_SERVER + (array) $_ENV + array('REQUEST_METHOD' => 'GET'); $envs = array('isapi' => 'IIS', 'cgi' => 'CGI', 'cgi-fcgi' => 'CGI'); $this->_env['PLATFORM'] = isset($envs[PHP_SAPI]) ? $envs[PHP_SAPI] : null; $this->_base = isset($this->_base) ? $this->_base : $this->_base(); $this->url = '/'; if (isset($this->_config['url'])) { $this->url = rtrim($this->_config['url'], '/'); } elseif (!empty($_GET['url'])) { $this->url = rtrim($_GET['url'], '/'); unset($_GET['url']); } if (!empty($this->_config['query'])) { $this->query = $this->_config['query']; } if (isset($_GET)) { $this->query += $_GET; } if (!empty($this->_config['data'])) { $this->data = $this->_config['data']; } elseif (isset($_POST)) { $this->data += $_POST; } if (isset($this->data['_method'])) { $this->_env['HTTP_X_HTTP_METHOD_OVERRIDE'] = strtoupper($this->data['_method']); unset($this->data['_method']); } if (!empty($this->_env['HTTP_X_HTTP_METHOD_OVERRIDE'])) { $this->_env['REQUEST_METHOD'] = $this->_env['HTTP_X_HTTP_METHOD_OVERRIDE']; } $method = strtoupper($this->_env['REQUEST_METHOD']); if (($method == 'POST' || $method == 'PUT') && !$this->data) { if (($type = $this->type()) && $type !== 'html') { $this->_stream = $this->_stream ?: fopen('php://input', 'r'); $media = $this->_classes['media']; $this->data = (array) $media::decode($type, stream_get_contents($this->_stream)); fclose($this->_stream); } } if (isset($_FILES) && $_FILES) { $result = array(); $normalize = function ($key, $value) use($result, &$normalize) { foreach ($value as $param => $content) { foreach ($content as $num => $val) { if (is_numeric($num)) { $result[$key][$num][$param] = $val; continue; } if (is_array($val)) { foreach ($val as $next => $one) { $result[$key][$num][$next][$param] = $one; } continue; } $result[$key][$num][$param] = $val; } } return $result; }; foreach ($_FILES as $key => $value) { if (isset($value['name'])) { if (is_string($value['name'])) { $result[$key] = $value; continue; } if (is_array($value['name'])) { $result += $normalize($key, $value); } } } $this->data = Set::merge((array) $this->data, $result); } }
protected static function _prepareMatchParams($parameters) { foreach (Set::normalize($parameters) as $token => $scope) { if (strpos($token, 'T_') !== 0) { unset($parameters[$token]); foreach (array('before', 'after') as $key) { if (!isset($scope[$key])) { continue; } $items = array(); foreach ((array) $scope[$key] as $item) { $items[] = strpos($item, 'T_') !== 0 ? static::token($item) : $item; } $scope[$key] = $items; } $parameters[static::token($token)] = $scope; } } return $parameters; }
/** * Adds an Access rule. This works much like the Validator class. * All rules should be anonymous functions and will be passed * $user, $request, and $options which will contain the entire * rule array which contains its own name plus other data that * could be used to determine access. * * @param string $name The rule name. * @param function $rule The closure for the rule, which has to return true or false. */ public function add($name, $rule = null) { $this->_rules = Set::merge($this->_rules, is_array($name) ? $name : array($name => $rule)); }
/** * Checks a single-use hash key against the session token that generated it, using * a cryptographically-secure verification method. Accepts either the request key as a string, * or a `Request` object with a `$data` property containing a `['security']['token']` key. * * For example, the following two controller code samples are equivalent: * * {{{ * $key = $this->request->data['security']['token']; * * if (!RequestToken::check($key)) { * // Handle invalid request... * } * }}} * * {{{ * if (!RequestToken::check($this->request)) { * // Handle invalid request... * } * }}} * * @param mixed $key Either the actual key as a string, or a `Request` object containing the * key. * @param array $options The options to use when matching the key to the token: * - `'sessionKey'` _string_: The key used when reading the token from the session. * @return boolean Returns `true` if the hash key is a cryptographic match to the stored * session token. Returns `false` on failure, which indicates a forged request attempt. */ public static function check($key, array $options = array()) { $defaults = array('sessionKey' => 'security.token'); $options += $defaults; $session = static::$_classes['session']; if (is_object($key) && isset($key->data)) { $result = Set::extract($key->data, '/security/token'); $key = $result ? $result[0] : null; } return Password::check($session::read($options['sessionKey']), (string) $key); }
/** * Delete value from the session * * @param string $key The key to be deleted * @param array $options Options array. Not used for this adapter method. * @return closure Function returning boolean `true` if the key no longer exists * in the session, `false` otherwise */ public static function delete($key, array $options = array()) { if (!static::isStarted() && !static::_start()) { throw new RuntimeException("Could not start session."); } $class = __CLASS__; return function ($self, $params) use($class) { $key = $params['key']; $class::overwrite($_SESSION, Set::remove($_SESSION, $key)); return !Set::check($_SESSION, $key); }; }
/** * Iterates through relationship types to construct relation map. * * @return void * @todo See if this can be rewritten to be lazy. */ protected static function _relationsToLoad() { try { if (!static::connection()) { return; } } catch (ConfigExcepton $e) { return; } $self = static::_object(); foreach ($self->_relationTypes as $type) { $self->{$type} = Set::normalize($self->{$type}); foreach ($self->{$type} as $name => $config) { $self->_relationsToLoad[$name] = $type; } } }
/** * Allows you to configure a default set of options which are included on a per-method basis, * and configure method template overrides. * * To force all `<label />` elements to have a default `class` attribute value of `"foo"`, * simply do the following: * * {{{ * $this->form->config(array('label' => array('class' => 'foo'))); * }}} * * @param array $config An associative array where the keys are `Form` method names, and the * values are arrays of configuration options to be included in the `$options` * parameter of each method specified. * @return array Returns an array containing the currently set per-method configurations, and * an array of the currently set template overrides (in the `'templates'` array key). * @see lithium\template\helper\Form::$_templateMap */ public function config($config = array()) { if (empty($config)) { return array('templates' => $this->_templateMap) + array_intersect_key($this->_config, array('base' => '', 'text' => '', 'textarea' => '')); } if (isset($config['templates'])) { $this->_templateMap = $config['templates'] + $this->_templateMap; unset($config['templates']); } return ($this->_config = Set::merge($this->_config, $config)) + array('templates' => $this->_templateMap); }
public function testMixedKeyNormalization() { $input = array('"string"' => array('before' => '=>'), 1 => array('before' => '=>')); $result = Set::normalize($input); $this->assertEqual($input, $result); $input = 'Foo,Bar,Baz'; $result = Set::normalize($input); $this->assertEqual(array('Foo' => null, 'Bar' => null, 'Baz' => null), $result); $input = array('baz' => 'foo', 'bar'); $result = Set::normalize($input, false); $this->assertEqual(array('baz' => 'foo', 'bar' => null), $result); }
/** * Handles appending nested objects to document changesets. * * @param array $changes The full set of changes to be made to the database. * @param string $key The key of the field to append, which may be a dot-separated path if the * value is or is contained within a nested object. * @param mixed $value The value to append to the changeset. Can be a scalar value, array, a * nested object, or part of a nested object. * @param string $change The type of change, as to whether update/remove or rename etc. * @return array Returns the value of `$changes`, with any new changed values appended. */ protected static function _append($changes, $key, $value, $change) { $options = array('finalize' => false); if (!is_object($value) || !method_exists($value, 'export')) { $changes[$change][$key] = $change == 'update' ? $value : true; return $changes; } if ($value->exists()) { if ($change == 'update') { $export = $value->export(); $export['key'] = $key; return Set::merge($changes, static::_update($export)); } $children = static::_update($value->export()); if (!empty($children)) { return Set::merge($changes, $children); } $changes[$change][$key] = true; return $changes; } $changes['update'][$key] = static::_create($value->export(), $options); return $changes; }
/** * Delete value from the cookie * * @param string $key The key to be deleted * @param array $options Options array * @return boolean True on successful delete, false otherwise */ public function delete($key, $options = array()) { $config = $options + $this->_config; return function ($self, $params, $chain) use(&$config) { extract($params); $key = is_array($key) ? Set::flatten($key) : array($key); foreach ($key as $name) { $name = explode('.', $name); $name = $config['name'] ? array_merge(array($config['name']), $name) : $name; if (count($name) == 1) { $name = current($name); } else { $name = array_shift($name) . '[' . join('][', $name) . ']'; } setcookie($name, "", time() - 1, $config['path'], $config['domain'], $config['secure'], $config['httponly']); } }; }
/** * Adds to or replaces built-in validation rules specified in `Validator::$_rules`. Any new * validation rules created are automatically callable as validation methods. * * For example: * {{{ * Validator::add('zeroToNine', '/^[0-9]$/'); * $isValid = Validator::isZeroToNine("5"); // true * $isValid = Validator::isZeroToNine("20"); // false * }}} * * Alternatively, the first parameter may be an array of rules expressed as key/value pairs, * as in the following: * {{{ * Validator::add(array( * 'zeroToNine' => '/^[0-9]$/', * 'tenToNineteen' => '/^1[0-9]$/', * )); * }}} * * In addition to regular expressions, validation rules can also be defined as full anonymous * functions: * {{{ * use app\models\Account; * * Validator::add('accountActive', function($value) { * $value = is_int($value) ? Account::find($value) : $value; * return (boolean) $value->is_active; * }); * * $testAccount = Account::create(array('is_active' => false)); * Validator::isAccountActive($testAccount); // returns false * }}} * * These functions can take up to 3 parameters: * - `$value` _mixed_: This is the actual value to be validated (as in the above example). * - `$format` _string_: Often, validation rules come in multiple "formats", for example: * postal codes, which vary by country or region. Defining multiple formats allows you to * retian flexibility in how you validate data. In cases where a user's country of origin * is known, the appropriate validation rule may be selected. In cases where it is not * known, the value of `$format` may be `'any'`, which should pass if any format matches. * In cases where validation rule formats are not mutually exclusive, the value may be * `'all'`, in which case all must match. * - `$options` _array_: This parameter allows a validation rule to implement custom * options. * * @see lithium\util\Validator::$_rules * @param mixed $name The name of the validation rule (string), or an array of key/value pairs * of names and rules. * @param string $rule If $name is a string, this should be a string regular expression, or a * closure that returns a boolean indicating success. Should be left blank if * `$name` is an array. * @param array $options The default options for validating this rule. An option which applies * to all regular expression rules is `'contains'` which, if set to true, allows * validated values to simply _contain_ a match to a rule, rather than exactly * matching it in whole. * @return void */ public static function add($name, $rule = null, array $options = array()) { if (!is_array($name)) { $name = array($name => $rule); } static::$_rules = Set::merge(static::$_rules, $name); if (!empty($options)) { $options = array_combine(array_keys($name), array_fill(0, count($name), $options)); static::$_options = Set::merge(static::$_options, $options); } }
public function testNodeWithNonStrictMode() { Fixtures::save('db'); extract($this->_models); $result = Set::extract(Aco::node('root/printers/refill/unexisting', false), '/id'); $expected = ['9', '6', '1']; $this->assertEqual($expected, $result); }