/**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_string($value) && !\is_int($value) && !\is_float($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'string'));
     }
     return ConversionResult::value((string) $value);
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_array($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'array'));
     }
     $errors = [];
     if ($typeParams) {
         $type = $typeParams[0];
         $coerced = [];
         $idx = 0;
         foreach ($value as $v) {
             $result = $ctx->coerce($v, $type);
             if ($result->getErrors()) {
                 $errors = \array_merge($errors, $result->errorsInIdx($idx));
                 if ($result->getValue() === null) {
                     return ConversionResult::errors($errors);
                 }
             }
             $coerced[] = $result->getValue();
             ++$idx;
         }
         $value = $coerced;
     } else {
         $value = \array_values($value);
     }
     return ConversionResult::errors($errors, $value);
 }
 /**
  * @param array $request
  * @param \ReflectionClass $class
  * @param callable $nameMangling
  *
  * @return ConversionResult
  */
 public function convert(array $request, \ReflectionClass $class, callable $nameMangling)
 {
     $ctx = new Context($this, $this->coercer, $nameMangling);
     $object = $this->instance($class);
     $setter = $this->setter($object);
     $errors = [];
     foreach ($class->getProperties() as $prop) {
         $name = $nameMangling($prop->getName());
         if (!isset($request[$name]) && !$this->reader->getPropertyAnnotation($prop, Optional::class)) {
             $errors[] = new MissingFieldError($name);
             continue;
         } elseif (!\array_key_exists($name, $request)) {
             continue;
         }
         $value = $request[$name];
         $typeAnnotation = $this->reader->getPropertyAnnotation($prop, Type::class);
         if ($value !== null && $typeAnnotation instanceof Type) {
             try {
                 $result = $this->coercer->coerce($value, $typeAnnotation->type, $ctx);
             } catch (CoercionException $e) {
                 throw ConverterException::in($class->getName(), $prop->getName(), $e);
             }
             $value = $result->getValue();
             $errors = \array_merge($errors, $result->errorsInField($name));
             $setter->set($prop->getName(), $value);
         } elseif ($value === null) {
             $setter->set($prop->getName(), null);
         }
     }
     return ConversionResult::errors($errors, $object);
 }
 /**
  * @param mixed $value
  * @param string $type
  * @param Context $ctx
  *
  * @return ConversionResult
  * @throws NoTypeException
  * @throws InvalidTypeException
  */
 public function coerce($value, $type, Context $ctx)
 {
     if ($value === null) {
         return ConversionResult::value(null);
     }
     list($coerceType, $parameters) = $this->parseType($type);
     return $this->getCoercer($coerceType, $type)->coerce($value, $type, $parameters, $ctx);
 }
 public function testPassthrough()
 {
     $input = ["a" => 1, "b" => 2];
     $output = (object) $input;
     $coercer = new ObjectCoercer();
     $this->ctx->expects($this->once())->method("convert")->with($input, $this->equalTo(new \ReflectionClass("stdClass")))->willReturn(ConversionResult::value($output));
     $this->assertConvertedValue($output, $coercer->coerce($input, "object<stdClass>", ["stdClass"], $this->ctx));
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_array($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'object'));
     }
     $class = new \ReflectionClass($typeParams[0]);
     return $ctx->convert($value, $class);
 }
 public function testTerminalError()
 {
     $coercer = new ArrayCoercer();
     $this->ctx->expects($this->exactly(2))->method("coerce")->withConsecutive([1, "int"], [2, "int"])->willReturnOnConsecutiveCalls(ConversionResult::value(1), ConversionResult::error(new MissingFieldError()));
     $result = $coercer->coerce([1, 2, 3], "array<int>", ["int"], $this->ctx);
     $this->assertNull($result->getValue());
     $this->assertCount(1, $result->getErrors());
     $this->assertInstanceOf(MissingFieldError::class, $result->getErrors()[0]);
     $this->assertSame("[1]", $result->getErrors()[0]->getField());
 }
 public function testTypedKeyValueTerminalError()
 {
     $coercer = new MapCoercer();
     $this->ctx->expects($this->exactly(2))->method("coerce")->withConsecutive([2, "int"], ["a", "string"])->willReturnOnConsecutiveCalls(ConversionResult::value(2), ConversionResult::error(new TypeError("object", "int")));
     $result = $coercer->coerce(["a" => 2, "b" => 6, "c" => 9, "d" => 15], "map<string, int>", ["string", "int"], $this->ctx);
     $this->assertNull($result->getValue());
     $this->assertCount(1, $result->getErrors());
     $this->assertInstanceOf(TypeError::class, $result->getErrors()[0]);
     $this->assertSame("a", $result->getErrors()[0]->getField());
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!$typeParams || !\preg_match('!^[^<]+\\<(.+)\\>$!', $origType, $formatMatch)) {
         throw new InvalidTypeException("DateTime type expects format to be provided");
     }
     $format = $formatMatch[1];
     $date = \DateTime::createFromFormat($format, $value, $this->timezone);
     if (!$date) {
         return ConversionResult::error(new InvalidDateFormatError($value, $format));
     }
     return ConversionResult::value($date);
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_int($value) && !\is_string($value) && !\is_float($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'int'));
     }
     if (\is_string($value) || \is_float($value)) {
         $value = \filter_var((string) $value, FILTER_VALIDATE_INT);
         if ($value === false) {
             return ConversionResult::error(new UncoercibleValueError('string', 'int'));
         }
     }
     return ConversionResult::value($value);
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_array($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'object'));
     }
     $errors = [];
     if (\count($typeParams) === 1) {
         // coerced values
         $type = $typeParams[0];
         $coerced = [];
         foreach ($value as $k => $v) {
             $result = $ctx->coerce($v, $type);
             if ($result->getErrors()) {
                 $errors = array_merge($errors, $result->errorsInField($k));
                 if ($result->getValue() === null) {
                     return ConversionResult::errors($errors);
                 }
             }
             $coerced[$k] = $result->getValue();
         }
         $value = $coerced;
     } elseif (\count($typeParams) === 2) {
         // coerced keys and values
         list($keyT, $valueT) = $typeParams;
         if ($keyT !== "string" && $keyT !== "int") {
             throw InvalidTypeException::from("Map<{$keyT}, {$valueT}>");
         }
         $coerced = [];
         foreach ($value as $key => $val) {
             $v = $ctx->coerce($val, $valueT);
             $k = $ctx->coerce($key, $keyT);
             if ($v->getErrors() || $k->getErrors()) {
                 $errors = array_merge($errors, $v->errorsInField($key), $k->errorsInField($key));
                 if ($v->getValue() === null || $k->getValue() === null) {
                     return ConversionResult::errors($errors);
                 }
             }
             $coerced[$k->getValue()] = $v->getValue();
         }
         $value = $coerced;
     }
     return ConversionResult::errors($errors, $value);
 }
 /**
  * @inheritdoc
  */
 public function coerce($value, $origType, array $typeParams, Context $ctx)
 {
     if (!\is_bool($value) && !\is_int($value) && !\is_string($value) && !\is_float($value)) {
         return ConversionResult::error(new TypeError(\gettype($value), 'bool'));
     }
     if (\is_string($value)) {
         $value = trim($value);
         if (\is_numeric($value)) {
             $value = (bool) (int) $value;
         } elseif (\in_array($value, $this->false, true)) {
             $value = false;
         } elseif (\in_array($value, $this->true, true)) {
             $value = true;
         } else {
             $value = (bool) $value;
         }
     } else {
         $value = (bool) $value;
     }
     return ConversionResult::value($value);
 }
 public function assertConvertedValue($expected, ConversionResult $result)
 {
     $this->assertEmpty($result->getErrors());
     $this->assertSame($expected, $result->getValue());
 }