function testPathsValid() { $ctx = new Context(); $ctx->push('a', 'a'); $ctx->push('a', 'a'); $ctx->push('a', 'a'); $ctx->pop('a'); $ctx->push('b', 'b'); $ctx->getNode()->valid = false; $ctx->pop('b'); $ctx->pop('a'); $ctx->push('b', 'b'); $ctx->getNode()->valid = false; $ctx->pop('b'); $ctx->push('c', 'c'); $ctx->pop('c'); $ctx->push('d', 'd'); $ctx->pop('d'); $ctx->pop('a'); $this->assertTrue($ctx->pathsValid([['a', 'c'], ['a', 'd']])); $this->assertFalse($ctx->pathsValid(['a', 'a', 'b'], ['a', 'c'])); $this->assertFalse($ctx->pathsValid(['a', 'a', 'a'], ['a', 'a', 'b'])); $this->assertFalse($ctx->pathsValid(['a', 'a', 'b'], ['a', 'b'])); }
protected function applyValue($input, Context $ctx) { if ($input === null) { return $input; } $properties = null; $isMapped = false; $modifiedProps = []; $unknown = []; list_properties: if (is_object($input)) { if ($this->mapper) { $properties = (array) $this->mapper->mapObjectToProperties($input); $isMapped = $properties !== null; } if ($properties === null) { $properties = []; foreach ($input as $k => &$v) { $properties[$k] =& $v; } } } elseif (is_array($input)) { $properties =& $input; } input_checks: if (!is_array($properties)) { $ctx->addReason($this, ['id' => 'schema.invalidType']); goto done; } prop_checks: $checkedProps = []; foreach ($this->props as $propId => $checks) { $name = null; $checkedProps[$propId] = true; if ($checks === true) { goto next_prop; } if ($checks instanceof \Fulfil\CheckInterface) { $checks = [$checks]; } foreach ($checks as $check) { if ($check->name()) { $name = $check->name(); break; } } $ctx->push($propId, $name); try { $value = array_key_exists($propId, $properties) ? $properties[$propId] : null; $modified = false; foreach ($checks as $check) { $value = $check->apply($value, $ctx); $modified |= $ctx->getChange() == true; } if ($modified) { $properties[$propId] = $value; $modifiedProps[$propId] = $value; } } finally { $ctx->pop($propId); } next_prop: } $unknown = array_keys(array_diff_key($properties, $checkedProps)); foreach ($unknown as $up) { foreach ($this->ignore as $pattern) { if (Func::userPatternMatch($pattern, $up)) { goto next_unknown; } } if ($this->filterUnknownProps) { // important: without this, if you attempt to repopulate an object with // the result later, you can run into errors. unset($properties[$up]); $ctx->setChange(Change::Internal); } $ctx->addReason($this, ['id' => 'schema.propUnknown', 'params' => ['prop' => $up]]); next_unknown: } rules: foreach ($this->rules as $rule) { $ruleProps = []; foreach ($rule->listProps() as $k => $p) { $ruleProps[$k] = isset($properties[$p]) ? $properties[$p] : null; } $rule->validate($ruleProps, $ctx); } done: if ($modifiedProps && $isMapped) { $this->mapper->populateObject($input, (object) $modifiedProps); } return $input; }