Skip to content

Feature/fix #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/App/Helper/ClassComparatorTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
namespace Yoanm\JsonRpcParamsSymfonyConstraintDoc\App\Helper;

/**
* Trait ClassComparatorTrait
*/
trait ClassComparatorTrait
{
/**
* @param $object
* @param array $classList
*
* @return string|null
*/
protected function getMatchingClassNameIn($object, array $classList) : ?string
{
$actualClassList = array_merge(
[get_class($object)],
class_implements($object),
class_uses($object)
);
$parentClass = get_parent_class($object);
while (false !== $parentClass) {
$actualClassList[] = $parentClass;
$parentClass = get_parent_class($parentClass);
}

$matchList = array_intersect($actualClassList, $classList);

return array_pop($matchList);
}
}
109 changes: 76 additions & 33 deletions src/App/Helper/DocTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ class DocTypeHelper
/** @var TypeGuesser */
private $typeGuesser;

const MANAGED_TYPE_CLASS_LIST = [
'scalar' => ScalarDoc::class,
'string' => StringDoc::class,
'bool' => BooleanDoc::class,
'boolean' => BooleanDoc::class,
'int' => IntegerDoc::class,
'integer' => IntegerDoc::class,
'float' => FloatDoc::class,
'long' => FloatDoc::class,
'double' => FloatDoc::class,
'real' => FloatDoc::class,
'numeric' => NumberDoc::class,
'array' => ArrayDoc::class,
'object' => ObjectDoc::class,
];

/**
* @param ConstraintPayloadDocHelper $constraintPayloadDocHelper
* @param TypeGuesser $typeGuesser
Expand Down Expand Up @@ -56,23 +72,7 @@ protected function getDocFromTypeConstraintOrPayloadDocIfExist(array $constraint
$doc = null;
// Check if a Type constraint exist or if a constraint have a type documentation
foreach ($constraintList as $constraint) {
if (null !== ($typeFromPayload = $this->constraintPayloadDocHelper->getTypeIfExist($constraint))) {
$doc = $this->normalizeType($typeFromPayload);
} elseif ($constraint instanceof Assert\Type) {
$doc = $this->normalizeType(strtolower($constraint->type));
} elseif ($constraint instanceof Assert\Existence && count($constraint->constraints) > 0) {
$doc = $this->guess($constraint->constraints);
} elseif ($constraint instanceof Assert\IdenticalTo) {
// Strict comparison so value define the type
$doc = $this->normalizeType(gettype($constraint->value));
} elseif ($constraint instanceof Assert\Callback) {
$callbackResult = call_user_func($constraint->callback);
$doc = $this->guess(
is_array($callbackResult)
? $callbackResult
: [$callbackResult]
);
}
$doc = $this->createDocFromConstraint($constraint);

if (null !== $doc) {
break;
Expand All @@ -89,24 +89,67 @@ protected function getDocFromTypeConstraintOrPayloadDocIfExist(array $constraint
*/
private function normalizeType(string $type) : ?TypeDoc
{
if ('scalar' === $type) {
return new ScalarDoc();
} elseif ('string' === $type) {
return new StringDoc();
} elseif (in_array($type, ['bool', 'boolean'])) {
return new BooleanDoc();
} elseif (in_array($type, ['int', 'integer'])) {
return new IntegerDoc();
} elseif (in_array($type, ['float', 'long', 'double', 'real'])) {
return new FloatDoc();
} elseif ('numeric' === $type) {
return new NumberDoc();
} elseif ('array' === $type) {
return new ArrayDoc();
} elseif ('object' === $type) {
return new ObjectDoc();
if (array_key_exists($type, self::MANAGED_TYPE_CLASS_LIST)) {
$class = self::MANAGED_TYPE_CLASS_LIST[$type];

return new $class();
}

return null;
}

/**
* @param Constraint $constraint
*
* @return TypeDoc|null
*/
private function createDocFromConstraint(Constraint $constraint) : ?TypeDoc
{
$doc = null;

if (null !== ($stringType = $this->getStringType($constraint))) {
$doc = $this->normalizeType($stringType);
} elseif ($constraint instanceof Assert\Callback) {
$doc = $this->getTypeFromCallbackConstraint($constraint);
} elseif ($constraint instanceof Assert\Existence && count($constraint->constraints) > 0) {
$doc = $this->guess($constraint->constraints);
}

return $doc;
}

/**
* @param Assert\Callback $constraint
*
* @return TypeDoc
*/
private function getTypeFromCallbackConstraint(Assert\Callback $constraint): TypeDoc
{
$callbackResult = call_user_func($constraint->callback);
$doc = $this->guess(
is_array($callbackResult)
? $callbackResult
: [$callbackResult]
);
return $doc;
}

/**
* @param Constraint $constraint
*
* @return string|null
*/
private function getStringType(Constraint $constraint) : ?string
{
$stringType = null;
if (null !== ($typeFromPayload = $this->constraintPayloadDocHelper->getTypeIfExist($constraint))) {
$stringType = $typeFromPayload;
} elseif ($constraint instanceof Assert\Type) {
$stringType = strtolower($constraint->type);
} elseif ($constraint instanceof Assert\IdenticalTo) {// Strict comparison so value define the type
$stringType = gettype($constraint->value);
}

return $stringType;
}
}
118 changes: 82 additions & 36 deletions src/App/Helper/MinMaxHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/
class MinMaxHelper
{
use ClassComparatorTrait;

/**
* @param TypeDoc $doc
* @param Constraint $constraint
Expand All @@ -34,20 +36,19 @@ public function append(TypeDoc $doc, Constraint $constraint) : void
*/
private function appendStringDoc(StringDoc $doc, Constraint $constraint) : void
{
$min = $max = null;
if ($constraint instanceof Assert\Length) {
if (null !== $constraint->min) {
$doc->setMinLength((int) $constraint->min);
}
if (null !== $constraint->max) {
$doc->setMaxLength((int) $constraint->max);
}
$min = $constraint->min;
$max = $constraint->max;
} elseif ($constraint instanceof Assert\NotBlank && null === $doc->getMinLength()) {
// Not blank so minimum 1 character
$doc->setMinLength(1);
$min = 1;
} elseif ($constraint instanceof Assert\Blank && null === $doc->getMaxLength()) {
// Blank so maximum 0 character
$doc->setMaxLength(0);
$max = 0;
}

$this->setMinMaxLengthIfNotNull($doc, $min, $max);
}

/**
Expand All @@ -71,21 +72,20 @@ private function appendNumberDoc(NumberDoc $doc, Constraint $constraint) : void
*/
private function appendCollectionDoc(CollectionDoc $doc, Constraint $constraint) : void
{
$min = $max = null;
if ($constraint instanceof Assert\Choice || $constraint instanceof Assert\Count) {
if (null !== $constraint->min) {
$doc->setMinItem((int) $constraint->min);
}
if (null !== $constraint->max) {
$doc->setMaxItem((int) $constraint->max);
}
$min = $constraint->min;
$max = $constraint->max;
} elseif ($constraint instanceof Assert\NotBlank && null === $doc->getMinItem()) {
// Not blank so minimum 1 item
$doc->setMinItem(1);
$min = 1;
} /* Documentation does not mention array, counter to NotBlank constraint
elseif ($constraint instanceof Assert\Blank && null === $doc->getMaxItem()) {
// Blank so maximum 0 item
$doc->setMaxItem(0);
$max = 0;
}*/

$this->setMinMaxItemIfNotNull($doc, $min, $max);
$this->appendLessGreaterThanMinMaxItem($doc, $constraint);
}

Expand All @@ -95,22 +95,21 @@ private function appendCollectionDoc(CollectionDoc $doc, Constraint $constraint)
*/
private function appendNumberMinMax(NumberDoc $doc, Constraint $constraint) : void
{
$min = $max = null;
if ($constraint instanceof Assert\Range) {
if (null !== $constraint->min) {
$doc->setMin($constraint->min);
}
if (null !== $constraint->max) {
$doc->setMax($constraint->max);
}
$min = $constraint->min;
$max = $constraint->max;
} elseif ($constraint instanceof Assert\LessThanOrEqual
|| $constraint instanceof Assert\LessThan
) {
$doc->setMax($constraint->value);
$max = $constraint->value;
} elseif ($constraint instanceof Assert\GreaterThanOrEqual
|| $constraint instanceof Assert\GreaterThan
) {
$doc->setMin($constraint->value);
$min = $constraint->value;
}

$this->setMinMaxIfNotNull($doc, $min, $max);
}

/**
Expand All @@ -119,18 +118,65 @@ private function appendNumberMinMax(NumberDoc $doc, Constraint $constraint) : vo
*/
private function appendLessGreaterThanMinMaxItem(CollectionDoc $doc, Constraint $constraint): void
{
if ($constraint instanceof Assert\GreaterThan || $constraint instanceof Assert\GreaterThanOrEqual) {
$doc->setMinItem(
$constraint instanceof Assert\GreaterThanOrEqual
? $constraint->value
: $constraint->value + 1
);
} elseif ($constraint instanceof Assert\LessThan || $constraint instanceof Assert\LessThanOrEqual) {
$doc->setMaxItem(
$constraint instanceof Assert\LessThanOrEqual
? $constraint->value
: $constraint->value - 1
);
$min = $max = null;
$gtConstraintList = [Assert\GreaterThan::class, Assert\GreaterThanOrEqual::class];
$ltConstraintList = [Assert\LessThan::class, Assert\LessThanOrEqual::class];
if (null !== ($match = $this->getMatchingClassNameIn($constraint, $gtConstraintList))) {
$min = ($match === Assert\GreaterThanOrEqual::class)
? $constraint->value
: $constraint->value + 1;
} elseif (null !== ($match = $this->getMatchingClassNameIn($constraint, $ltConstraintList))) {
$max = ($match === Assert\LessThanOrEqual::class)
? $constraint->value
: $constraint->value - 1
;
}

$this->setMinMaxItemIfNotNull($doc, $min, $max);
}

/**
* @param StringDoc $doc
* @param null|int|mixed $min
* @param null|int|mixed $max
*/
private function setMinMaxLengthIfNotNull(StringDoc $doc, $min, $max): void
{
if (null !== $min) {
$doc->setMinLength((int)$min);
}
if (null !== $max) {
$doc->setMaxLength((int)$max);
}
}

/**
* @param CollectionDoc $doc
* @param null|int|mixed $min
* @param null|int|mixed $max
*/
private function setMinMaxItemIfNotNull(CollectionDoc $doc, $min, $max): void
{
if (null !== $min) {
$doc->setMinItem((int) $min);
}
if (null !== $max) {
$doc->setMaxItem((int) $max);
}
}

/**
* @param NumberDoc $doc
* @param null|int|mixed $min
* @param null|int|mixed $max
*/
private function setMinMaxIfNotNull(NumberDoc $doc, $min, $max): void
{
if (null !== $min) {
$doc->setMin($min);
}
if (null !== $max) {
$doc->setMax($max);
}
}
}
Loading