/** * Check if the constraint is met. * * @param mixed $value * @param array $context * * @throws LackOfCoffeeException * @return mixed */ public function check($value, array $context = []) { $closure = $this->closure; $result = $closure($value, $context); if (!is_bool($result)) { throw new LackOfCoffeeException(vsprintf('Inner closure of constraint was expected to return a' . ' boolean value. Got %s instead.', [TypeHound::fetch($result)])); } return $result; }
/** * Concatenate the two provided values. * * @param string|array|Traversable $one * @param string|array|Traversable $other * * @throws MismatchedArgumentTypesException * @throws InvalidArgumentException * @return mixed */ public static function concat($one, $other) { Arguments::define(Boa::either(Boa::lst(), Boa::string()), Boa::either(Boa::lst(), Boa::string()))->check($one, $other); $oneType = TypeHound::fetch($one); $twoType = TypeHound::fetch($other); if ($oneType !== $twoType) { throw new MismatchedArgumentTypesException(__FUNCTION__, $one, $other); } if ($oneType === ScalarTypes::SCALAR_STRING) { return $one . $other; } return ArrayMap::of($one)->append(ArrayMap::of($other))->toArray(); }
/** * Escape the provided string. * * @param SafeHtmlWrapper|SafeHtmlProducerInterface|string $string * * @throws CoreException * @throws InvalidArgumentException * @return SafeHtmlWrapper|string */ public static function escape($string) { Arguments::define(Boa::either(Boa::either(Boa::instance(SafeHtmlWrapper::class), Boa::instance(SafeHtmlProducerInterface::class)), Boa::string()))->check($string); if ($string instanceof SafeHtmlWrapper) { return $string; } elseif ($string instanceof SafeHtmlProducerInterface) { $result = $string->getSafeHtml(); if ($result instanceof SafeHtmlWrapper) { return $result; } elseif ($result instanceof SafeHtmlProducerInterface) { return static::escape($result); } throw new CoreException(vsprintf('Object of class %s implements SafeHtmlProducerInterface' . ' but it returned an unsafe type: %s', [get_class($string), TypeHound::fetch($result)])); } return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); }
public function testIsKnown() { $this->assertEqualsMatrix([[true, TypeHound::isKnown(ScalarTypes::SCALAR_BOOLEAN)], [true, TypeHound::isKnown(ScalarTypes::SCALAR_FLOAT)], [true, TypeHound::isKnown(ScalarTypes::SCALAR_INTEGER)], [true, TypeHound::isKnown(ScalarTypes::SCALAR_STRING)], [true, TypeHound::isKnown(CompoundTypes::COMPOUND_ARRAY)], [true, TypeHound::isKnown(CompoundTypes::COMPOUND_OBJECT)], [true, TypeHound::isKnown(SpecialTypes::SPECIAL_NULL)], [true, TypeHound::isKnown(SpecialTypes::SPECIAL_RESOURCE)]]); }
/** * Check that the type matches. * * @param TypeHound $other * * @throws UnknownTypeException * @return bool */ public function matches(TypeHound $other) { return $this->resolve() === $other->resolve(); }
/** * Check if the constraint is met. * * @param mixed $value * @param array $context * * @throws UnknownTypeException * @return mixed */ public function check($value, array $context = []) { $hound = new TypeHound($value); return $this->expectedType === $hound->resolve(); }
/** * Construct an instance of a NodeChildRenderingException. * * @param mixed $content * @param int $code * @param Exception|null $previous */ public function __construct($content, $code = 0, Exception $previous = null) { parent::__construct(vsprintf('Unknown child content type: %s. ' . 'Node child item cannot be rendered.', [TypeHound::fetch($content)]), $code, $previous); $this->content = $content; }
/** * Get an instance of the model being generated. * * Note: The instance will be cached after being created for the first * time. * * @param bool $flush Remove old instance * * @throws LackOfCoffeeException * @return Model */ protected function getModelInstance($flush = false) { if ($this->modelInstance !== null && $flush === false) { return $this->modelInstance; } $model = new $this->model(); if (!$model instanceof Model) { throw new LackOfCoffeeException(vsprintf('ModelGenerator only supports generating instances of' . ' %s. Got %s', [Model::class, TypeHound::fetch($model)])); } $this->modelInstance = $model; return $model; }
/** * Construct an instance of a MismatchedArgumentTypesException. * * @param string $functionName * @param mixed $arguments */ public function __construct($functionName, ...$arguments) { parent::__construct(vsprintf('Argument type mismatch: %s for function %s', [ArrayList::of($arguments)->map(function ($item) { return TypeHound::fetch($item); })->join(', '), $functionName])); }
/** * Check that a certain input passes the spec. * * @param mixed $input * * @return SpecResult */ public function check(array $input) { $missing = []; $invalid = []; $check = function ($constraint, $key, $value, $input) use(&$missing, &$invalid) { if ($constraint instanceof AbstractConstraint) { if (!$constraint->check($value, $input)) { $invalid[$key][] = $constraint; } } elseif ($constraint instanceof CheckableInterface) { $result = $constraint->check($value); $missing = Std::concat($missing, array_map(function ($subKey) use($key) { return vsprintf('%s.%s', [$key, $subKey]); }, $result->getMissing())); foreach ($result->getFailed() as $failedField => $constraints) { $fullPath = vsprintf('%s.%s', [$key, $failedField]); if (array_key_exists($fullPath, $invalid)) { $invalid[$fullPath] = array_merge($invalid[$fullPath], $constraints); } else { $invalid[$fullPath] = $constraints; } } } else { throw new CoreException(vsprintf('Unexpected constraint type: %s.', [TypeHound::fetch($constraint)])); } }; $inputMap = ArrayMap::of($input); $this->annotations->each(function ($value, $key) use($check, $input, $inputMap, &$missing) { // If a field is required but not present, we should report it. if (Maybe::fromMaybe(false, $value->lookup(static::ANNOTATION_REQUIRED)) && $inputMap->member($key) === false) { $missing[] = $key; // There's no point on checking constraints on the field // since it is missing. return; } elseif ($inputMap->member($key) === false) { // There's no point on checking constraints on the field // since it is missing. return; } $fieldValue = Maybe::fromJust($inputMap->lookup($key)); $this->getInternalFieldConstraints($key)->each(function ($constraint) use($check, $key, $fieldValue, $input) { $check($constraint, $key, $fieldValue, $input); }); }); if (count($missing) === 0 && count($invalid) === 0) { return new SpecResult($missing, $invalid, SpecResult::STATUS_PASS); } return new SpecResult($missing, $invalid, SpecResult::STATUS_FAIL); }
/** * Set the expected class and the received value. * * @param string|object $expected * @param mixed $received */ public function setExpectedAndReceived($expected, $received) { $this->expected = is_string($expected) ? $expected : get_class($expected); $this->received = TypeHound::fetch($received); $this->message = vsprintf('An instance of a %s was expected but got %s', [$this->expected, $this->received]); }
/** * Validate and discover all the relationships on a model. * * @return Relation[] */ protected function discoverRelations() { if ($this->relations === null) { $this->relations = []; Std::each(function ($name) { // Check that the relationship method is there. if (!method_exists($this->model, $name)) { throw new LackOfCoffeeException(vsprintf('The model declares a relationship named "%s" but' . ' there is no method with that name.', [$name])); } $relationReflector = new ReflectionMethod($this->model, $name); if (!$relationReflector->isPublic()) { throw new LackOfCoffeeException(vsprintf('The method for the relationship named "%s" should' . ' be public.', [$name])); } $argumentCount = $relationReflector->getNumberOfParameters(); if ($argumentCount > 0) { throw new LackOfCoffeeException(vsprintf('The method for the relationship named "%s" should' . ' take 0 arguments. However, it requires %d.', [$name, $argumentCount])); } $relation = $this->model->{$name}(); if (!$relation instanceof Relation) { throw new LackOfCoffeeException(vsprintf('The method for the relationship named "%s" should' . ' return an instance of %s. Got %s.', [$name, Relation::class, TypeHound::fetch($relation)])); } $this->relations[$name] = $relation; }, $this->model->getRelated()); } return $this->relations; }
public function testCurry() { $rest = 0; $adder = function ($a, $b, $c, $d) { return $a + $b + $c + $d; }; $variadicAdder = function (...$args) { return Std::foldl(function ($acc, $cur) { return $acc + $cur; }, 0, $args); }; $partiallyVariadicAdder = function ($a, $b, $c, ...$args) use(&$rest) { $rest = Std::foldl(function ($acc, $cur) { return $acc + $cur; }, 0, $args); return $a + $b + $c; }; $one = Std::curry($adder, 2, 5); $two = $one(6); // Here we test adding one additional parameter that was not expected. // This should allow us to support partially variadic functions. $three = $two(10, 1000); $this->assertEquals(23, $three); // Variadic functions will return immediately since we can't determine // when they have been fulfilled. $four = Std::curry($variadicAdder, 2, 5); $this->assertEquals(ScalarTypes::SCALAR_INTEGER, TypeHound::fetch($four)); $this->assertEquals(7, $four); $seven = Std::curry($partiallyVariadicAdder, 8, 5); $eight = $seven(9, 102, 20); $this->assertEquals(ScalarTypes::SCALAR_INTEGER, TypeHound::fetch($eight)); $this->assertEquals(22, $eight); $this->assertEquals(122, $rest); }