Completed
Push — master ( 857ea9...f24760 )
by Fran
03:35
created

DocumentorService::getModules()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 18
rs 8.8571
1
<?php
2
    namespace PSFS\services;
3
4
    use PSFS\base\Service;
5
    use Symfony\Component\Finder\Finder;
6
7
    /**
8
     * Class DocumentorService
9
     * @package PSFS\services
10
     */
11
    class DocumentorService extends Service
12
    {
13
        /**
14
         * @Inyectable
15
         * @var \PSFS\base\Router route
16
         */
17
        protected $route;
18
19
        /**
20
         * Method that extract all modules
21
         * @return array
22
         */
23
        public function getModules()
24
        {
25
            $modules = [];
26
            $domains = $this->route->getDomains();
27
            if (count($domains)) {
28
                foreach (array_keys($domains) as $domain) {
29
                    try {
30
                        if (!preg_match('/^\@ROOT/i', $domain)) {
31
                            $modules[] = str_replace('/', '', str_replace('@', '', $domain));
32
                        }
33
                    } catch (\Exception $e) {
34
                        $modules[] = $e->getMessage();
35
                    }
36
                }
37
            }
38
39
            return $modules;
40
        }
41
42
        /**
43
         * Method that extract all endpoints for each module
44
         *
45
         * @param string $module
46
         *
47
         * @return array
48
         */
49
        public function extractApiEndpoints($module)
50
        {
51
            $module_path = CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . "Api";
52
            $endpoints = [];
53
            if (file_exists($module_path)) {
54
                $finder = new Finder();
55
                $finder->files()->depth('== 0')->in($module_path)->name('*.php');
56
                if (count($finder)) {
57
                    /** @var \SplFileInfo $file */
58
                    foreach ($finder as $file) {
59
                        $namespace = "\\{$module}\\Api\\" . str_replace('.php', '', $file->getFilename());
60
                        $endpoints[$namespace] = $this->extractApiInfo($namespace);
61
                    }
62
                }
63
            }
64
65
            return $endpoints;
66
        }
67
68
        /**
69
         * Method that extract all the endpoit information by reflection
70
         *
71
         * @param string $namespace
72
         *
73
         * @return array
74
         */
75
        public function extractApiInfo($namespace)
76
        {
77
            $info = [];
78
            $reflection = new \ReflectionClass($namespace);
79
            $publicMethods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
80
            if (count($publicMethods)) {
81
                /** @var \ReflectionMethod $method */
82
                foreach ($publicMethods as $method) {
83
                    $docComments = $method->getDocComment();
84
                    if (FALSE !== $docComments && preg_match('/\@route\ /i', $docComments)) {
85
                        $visibility = $this->extractVisibility($docComments);
86
                        $route = str_replace('{__API__}', $reflection->getShortName(), $this->extractRoute($docComments));
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
87
                        if ($visibility && preg_match('/^\/api\//i', $route)) {
88
                            $methodInfo = [
89
                                'url'         => $route,
90
                                'method'      => $this->extractMethod($docComments),
91
                                'description' => str_replace('{__API__}', $reflection->getShortName(), $this->extractDescription($docComments)),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 144 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
92
                            ];
93
                            if (in_array($methodInfo['method'], ['POST', 'PUT'])) {
94
                                $methodInfo['payload'] = $this->extractPayload(str_replace('Api', 'Models', $namespace), $docComments);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
95
                            }
96
                            $info[] = $methodInfo;
97
                        }
98
                    }
99
                }
100
            }
101
102
            return $info;
103
        }
104
105
        /**
106
         * Extract route from doc comments
107
         *
108
         * @param string $comments
109
         *
110
         * @return string
111
         */
112
        protected function extractRoute($comments = '')
113
        {
114
            $route = '';
115
            preg_match('/@route\ (.*)\n/i', $comments, $route);
116
117
            return $route[1];
118
        }
119
120
        /**
121
         * Extract method from doc comments
122
         *
123
         * @param string $comments
124
         *
125
         * @return string
126
         */
127
        protected function extractMethod($comments = '')
128
        {
129
            $method = 'GET';
130
            preg_match('/@(get|post|put|delete)\n/i', $comments, $method);
131
132
            return strtoupper($method[1]);
133
        }
134
135
        /**
136
         * Extract visibility from doc comments
137
         *
138
         * @param string $comments
139
         *
140
         * @return boolean
141
         */
142
        protected function extractVisibility($comments = '')
143
        {
144
            $visible = TRUE;
145
            preg_match('/@visible\ (true|false)\n/i', $comments, $visibility);
146
            if (count($visibility)) {
147
                $visible = !('false' == $visibility[1]);
148
            }
149
150
            return $visible;
151
        }
152
153
        /**
154
         * Method that extract the description for the endpoint
155
         *
156
         * @param string $comments
157
         *
158
         * @return string
159
         */
160
        protected function extractDescription($comments = '')
161
        {
162
            $description = '';
163
            $docs = explode("\n", $comments);
164
            if (count($docs)) {
165
                foreach ($docs as &$doc) {
166 View Code Duplication
                    if (!preg_match('/(\*\*|\@)/i', $doc) && preg_match('/\*\ /i', $doc)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
                        $doc = explode('* ', $doc);
168
                        $description = $doc[1];
169
                    }
170
                }
171
            }
172
173
            return $description;
174
        }
175
176
        /**
177
         * Method that extract the type of a variable
178
         * @param string $comments
179
         *
180
         * @return string
181
         */
182
        protected function extractVarType($comments = '')
183
        {
184
            $type = 'string';
185
            preg_match('/@var\ (.*)\n/i', $comments, $varType);
186
            if (count($varType)) {
187
                $type = str_replace(' ', '', $varType[1]);
188
            }
189
            return $type;
190
        }
191
192
        /**
193
         * Method that extract the payload for the endpoint
194
         *
195
         * @param string $model
196
         * @param string $comments
197
         *
198
         * @return array
199
         */
200
        protected function extractPayload($model, $comments = '')
201
        {
202
            $payload = [];
203
            preg_match('/@payload\ (.*)\n/i', $comments, $doc);
204
            if (count($doc)) {
205
                $namespace = str_replace('{__API__}', $model, $doc[1]);
206
                $reflector = new \ReflectionClass($namespace);
207
                if (null !== $reflector) {
208
                    $tableMap = $namespace::TABLE_MAP;
209
                    $fieldNames = $tableMap::getFieldNames();
210
                    if (count($fieldNames)) {
211
                        foreach($fieldNames as $field) {
212
                            $variable = $reflector->getProperty(strtolower($field));
213
                            $varDoc = $variable->getDocComment();
214
                            $payload[$field] = $this->extractVarType($varDoc);
215
                        }
216
                    }
217
                }
218
            }
219
            return $payload;
220
        }
221
    }