Completed
Push — 1.x ( ed8928...51f4d3 )
by Akihito
06:08 queued 04:26
created

OptionsMethods::getParameterMetas()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 9
nop 3
crap 5
1
<?php
2
/**
3
 * This file is part of the BEAR.Resource package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Resource;
8
9
use BEAR\Resource\Annotation\ResourceParam;
10
use Doctrine\Common\Annotations\Reader;
11
use phpDocumentor\Reflection\DocBlockFactory;
12
use Ray\Di\Di\Assisted;
13
use Ray\WebContextParam\Annotation\AbstractWebContextParam;
14
use Ray\WebContextParam\Annotation\CookieParam;
15
use Ray\WebContextParam\Annotation\EnvParam;
16
use Ray\WebContextParam\Annotation\FormParam;
17
use Ray\WebContextParam\Annotation\QueryParam;
18
use Ray\WebContextParam\Annotation\ServerParam;
19
20
final class OptionsMethods
21
{
22
    /**
23
     * Constants for annotation name and "in" name
24
     *
25
     * @var array
26
     */
27
    private $webContextName = [
28
        CookieParam::class => 'cookie',
29
        EnvParam::class => 'env',
30
        FormParam::class => 'formData',
31
        QueryParam::class => 'query',
32
        ServerParam::class => 'server'
33
    ];
34
    private $reader;
35
36 85
    public function __construct(Reader $reader)
37
    {
38 85
        $this->reader = $reader;
39 85
    }
40
41
    /**
42
     * @param ResourceObject $ro
43
     * @param string         $requestMethod
44
     *
45
     * @return array
46
     */
47 5
    public function __invoke(ResourceObject $ro, $requestMethod)
48
    {
49 5
        $method = new \ReflectionMethod($ro, 'on' . $requestMethod);
50 5
        $ins = $this->getInMap($method);
51 5
        $docComment = $method->getDocComment();
52 5
        $doc = $paramDoc = [];
53 5
        if ($docComment) {
54 5
            list($doc, $paramDoc) = $this->docBlock($docComment);
55
        }
56 5
        $parameters = $method->getParameters();
57 5
        list($paramDoc, $required) = $this->getParameterMetas($parameters, $paramDoc, $ins);
58 5
        $paramMetas = [];
59 5
        if ((bool) $paramDoc) {
60 5
            $paramMetas['parameters'] = $paramDoc;
61
        }
62 5
        if ((bool) $required) {
63 5
            $paramMetas['required'] = $required;
64
        }
65 5
        $paramMetas = $this->ignoreAnnotatedPrameter($method, $paramMetas);
66
67 5
        return $doc + $paramMetas;
68
    }
69
70 5
    private function getInMap(\ReflectionMethod $method)
71
    {
72 5
        $ins = [];
73 5
        $annotations = $this->reader->getMethodAnnotations($method);
74 5
        foreach ($annotations as $annotation) {
75 3
            if ($annotation instanceof AbstractWebContextParam) {
76 2
                $ins[$annotation->param] = $this->webContextName[get_class($annotation)];
77
            }
78
        }
79
80 5
        return $ins;
81
    }
82
83
    /**
84
     * @param string $docComment
85
     *
86
     * @return array [$docs, $params]
87
     */
88 5
    private function docBlock($docComment)
89
    {
90 5
        $factory = DocBlockFactory::createInstance();
91 5
        $docblock = $factory->create($docComment);
92 5
        $summary = $docblock->getSummary();
93 5
        $docs = $params = [];
94 5
        if ($summary) {
95 1
            $docs['summary'] = $summary;
96
        }
97 5
        $description = (string) $docblock->getDescription();
98 5
        if ($description) {
99 1
            $docs['description'] = $description;
100
        }
101 5
        $tags = $docblock->getTagsByName('param');
102 5
        $params = $this->docBlogTags($tags, $params);
103
104 5
        return [$docs, $params];
105
    }
106
107
    /**
108
     * @param \ReflectionParameter $parameter
109
     * @param array                $paramDoc
110
     * @param string               $name
111
     *
112
     * @return string|null
113
     */
114 5
    private function getParameterType(\ReflectionParameter $parameter, array $paramDoc, $name)
115
    {
116 5
        $hasType = method_exists($parameter, 'getType') && $parameter->getType();
117 5
        if ($hasType) {
118 1
            return $this->getType($parameter);
119
        }
120 5
        if (isset($paramDoc[$name]['type'])) {
121 2
            return $paramDoc[$name]['type'];
122
        }
123 3
    }
124
125
    /**
126
     * @param \ReflectionParameter[] $parameters
127
     * @param array                  $paramDoc
128
     *
129
     * @return array [$paramDoc, $required]
130
     */
131 5
    private function getParameterMetas(array $parameters, array $paramDoc, array $ins)
132
    {
133 5
        $required = [];
134 5
        foreach ($parameters as $parameter) {
135 5
            if (isset($ins[$parameter->name])) {
136 2
                $paramDoc[$parameter->name]['in'] = $ins[$parameter->name];
137
            }
138 5
            if (! isset($paramDoc[$parameter->name])) {
139 3
                $paramDoc[$parameter->name] = [];
140
            }
141 5
            $paramDoc = $this->paramType($paramDoc, $parameter);
142 5
            if (! $parameter->isOptional()) {
143 5
                $required[] = $parameter->name;
144
            }
145 5
            $paramDoc = $this->paramDefault($paramDoc, $parameter);
146
        }
147
148 5
        return [$paramDoc, $required];
149
    }
150
151
    /**
152
     * @return array
153
     */
154 5
    private function paramDefault(array $paramDoc, \ReflectionParameter $parameter)
155
    {
156 5
        $hasDefault = $parameter->isDefaultValueAvailable() && $parameter->getDefaultValue() !== null;
157 5
        if ($hasDefault) {
158 2
            $paramDoc[$parameter->name]['default'] = (string) $parameter->getDefaultValue();
159
        }
160
161 5
        return $paramDoc;
162
    }
163
164
    /**
165
     * @return array
166
     */
167 5
    private function paramType(array $paramDoc, \ReflectionParameter $parameter)
168
    {
169 5
        $type = $this->getParameterType($parameter, $paramDoc, $parameter->name);
170 5
        if (is_string($type)) {
171 2
            $paramDoc[$parameter->name]['type'] = $type;
172
        }
173
174 5
        return $paramDoc;
175
    }
176
177
    /**
178
     * @param \ReflectionParameter $parameter
179
     *
180
     * @return string
181
     */
182 1
    private function getType(\ReflectionParameter $parameter)
183
    {
184 1
        $type = (string) $parameter->getType();
185 1
        if ($type === 'int') {
186 1
            $type = 'integer';
187
        }
188
189 1
        return $type;
190
    }
191
192
    /**
193
     * @return array
194
     */
195 5
    private function docBlogTags(array $tags, array $params)
196
    {
197 5
        foreach ($tags as $tag) {
198
            /* @var $tag \phpDocumentor\Reflection\DocBlock\Tags\Param */
199 2
            $varName = $tag->getVariableName();
200 2
            $tagType = (string) $tag->getType();
201 2
            $type = $tagType === 'int' ? 'integer' : $tagType;
202 2
            $params[$varName] = [
203 2
                'type' => $type
204
            ];
205 2
            $description = (string) $tag->getDescription();
206 2
            if ($description) {
207 2
                $params[$varName]['description'] = $description;
208
            }
209
        }
210
211 5
        return $params;
212
    }
213
214
    /**
215
     * Ignore @ Assisted @ ResourceParam parameter
216
     *
217
     * @return array
218
     */
219 5
    private function ignoreAnnotatedPrameter(\ReflectionMethod $method, array $paramMetas)
220
    {
221 5
        $annotations = $this->reader->getMethodAnnotations($method);
222 5
        foreach ($annotations as $annotation) {
223 3
            if ($annotation instanceof ResourceParam) {
224 1
                unset($paramMetas['parameters'][$annotation->param]);
225 1
                $paramMetas['required'] = array_values(array_diff($paramMetas['required'], [$annotation->param]));
226
            }
227 3
            if ($annotation instanceof Assisted) {
228 1
                $paramMetas = $this->ignorreAssisted($paramMetas, $annotation);
229
            }
230
        }
231
232 5
        return $paramMetas;
233
    }
234
235
    /**
236
     * Ignore @ Assisted parameter
237
     *
238
     * @return array
239
     */
240 1
    private function ignorreAssisted(array $paramMetas, Assisted $annotation)
241
    {
242 1
        $paramMetas['required'] = array_values(array_diff($paramMetas['required'], $annotation->values));
243 1
        foreach ($annotation->values as $varName) {
244 1
            unset($paramMetas['parameters'][$varName]);
245
        }
246
247 1
        return $paramMetas;
248
    }
249
}
250