Passed
Push — master ( d8fa97...555fd2 )
by Yo
01:32
created

getDocFromTypeConstraintOrPayloadDocIfExist()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 0
loc 13
ccs 7
cts 7
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Yoanm\JsonRpcParamsSymfonyConstraintDoc\App\Helper;
3
4
use Symfony\Component\Validator\Constraint;
5
use Symfony\Component\Validator\Constraints as Assert;
6
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\ArrayDoc;
7
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\BooleanDoc;
8
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\FloatDoc;
9
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\IntegerDoc;
10
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\NumberDoc;
11
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\ObjectDoc;
12
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\ScalarDoc;
13
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\StringDoc;
14
use Yoanm\JsonRpcServerDoc\Domain\Model\Type\TypeDoc;
15
16
/**
17
 * Class DocTypeHelper
18
 */
19
class DocTypeHelper
20
{
21
    /** @var ConstraintPayloadDocHelper */
22
    private $constraintPayloadDocHelper;
23
    /** @var TypeGuesser */
24
    private $typeGuesser;
25
26
    const MANAGED_TYPE_CLASS_LIST = [
27
        'scalar' => ScalarDoc::class,
28
        'string' => StringDoc::class,
29
        'bool' => BooleanDoc::class,
30
        'boolean' => BooleanDoc::class,
31
        'int' => IntegerDoc::class,
32
        'integer' => IntegerDoc::class,
33
        'float' => FloatDoc::class,
34
        'long' => FloatDoc::class,
35
        'double' => FloatDoc::class,
36
        'real' => FloatDoc::class,
37
        'numeric' => NumberDoc::class,
38
        'array' => ArrayDoc::class,
39
        'object' => ObjectDoc::class,
40
    ];
41
42
    /**
43
     * @param ConstraintPayloadDocHelper $constraintPayloadDocHelper
44
     * @param TypeGuesser                $typeGuesser
45
     */
46 25
    public function __construct(ConstraintPayloadDocHelper $constraintPayloadDocHelper, TypeGuesser $typeGuesser)
47
    {
48 25
        $this->constraintPayloadDocHelper = $constraintPayloadDocHelper;
49 25
        $this->typeGuesser = $typeGuesser;
50 25
    }
51
52
    /**
53
     * @param Constraint[] $constraintList
54
     *
55
     * @return TypeDoc
56
     */
57 25
    public function guess(array $constraintList) : TypeDoc
58
    {
59 25
        return $this->getDocFromTypeConstraintOrPayloadDocIfExist($constraintList)
60 3
            ?? $this->typeGuesser->guessTypeFromConstraintList($constraintList)
61 25
            ?? new TypeDoc()
62
        ;
63
    }
64
65
    /**
66
     * @param Constraint[] $constraintList
67
     *
68
     * @return TypeDoc|null
69
     */
70 25
    protected function getDocFromTypeConstraintOrPayloadDocIfExist(array $constraintList) : ?TypeDoc
71
    {
72 25
        $doc = null;
73
        // Check if a Type constraint exist or if a constraint have a type documentation
74 25
        foreach ($constraintList as $constraint) {
75 24
            $doc = $this->createDocFromConstraint($constraint);
76
77 24
            if (null !== $doc) {
78 24
                break;
79
            }
80
        }
81
82 25
        return $doc;
83
    }
84
85
    /**
86
     * @param string $type
87
     *
88
     * @return TypeDoc|null
89
     */
90 23
    private function normalizeType(string $type) : ?TypeDoc
91
    {
92 23
        if (array_key_exists($type, self::MANAGED_TYPE_CLASS_LIST)) {
93 22
            $class = self::MANAGED_TYPE_CLASS_LIST[$type];
94
95 22
            return new $class();
96
        }
97
98 1
        return null;
99
    }
100
101
    /**
102
     * @param Constraint $constraint
103
     *
104
     * @return TypeDoc|null
105
     */
106 24
    private function createDocFromConstraint(Constraint $constraint) : ?TypeDoc
107
    {
108 24
        $doc = null;
109
110 24
        if (null !== ($stringType = $this->getStringType($constraint))) {
111 23
            $doc = $this->normalizeType($stringType);
112 5
        } elseif ($constraint instanceof Assert\Callback) {
113 2
            $doc = $this->getTypeFromCallbackConstraint($constraint);
114 3
        } elseif ($constraint instanceof Assert\Existence && count($constraint->constraints) > 0) {
115 2
            $doc = $this->guess($constraint->constraints);
116
        }
117
118 24
        return $doc;
119
    }
120
121
    /**
122
     * @param Assert\Callback $constraint
123
     *
124
     * @return TypeDoc
125
     */
126 2
    private function getTypeFromCallbackConstraint(Assert\Callback $constraint): TypeDoc
127
    {
128 2
        $callbackResult = call_user_func($constraint->callback);
129 2
        $doc = $this->guess(
130 2
            is_array($callbackResult)
131 1
                ? $callbackResult
132 2
                : [$callbackResult]
133
        );
134 2
        return $doc;
135
    }
136
137
    /**
138
     * @param Constraint $constraint
139
     *
140
     * @return string|null
141
     */
142 24
    private function getStringType(Constraint $constraint) : ?string
143
    {
144 24
        $stringType = null;
145 24
        if (null !== ($typeFromPayload = $this->constraintPayloadDocHelper->getTypeIfExist($constraint))) {
146 1
            $stringType = $typeFromPayload;
147 23
        } elseif ($constraint instanceof Assert\Type) {
148 18
            $stringType = strtolower($constraint->type);
149 9
        } elseif ($constraint instanceof Assert\IdenticalTo) {// Strict comparison so value define the type
150 4
            $stringType = gettype($constraint->value);
151
        }
152
153 24
        return $stringType;
154
    }
155
}
156