Completed
Push — master ( 467596...f57d95 )
by Arne
02:35
created

Generator::processClass()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 10

Duplication

Lines 18
Ratio 100 %

Importance

Changes 0
Metric Value
dl 18
loc 18
c 0
b 0
f 0
rs 9.2
cc 4
eloc 10
nc 8
nop 1
1
<?php
2
/**
3
 * Copyright (c) 2010-2018 Arne Blankerts <[email protected]>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without modification,
7
 * are permitted provided that the following conditions are met:
8
 *
9
 *   * Redistributions of source code must retain the above copyright notice,
10
 *     this list of conditions and the following disclaimer.
11
 *
12
 *   * Redistributions in binary form must reproduce the above copyright notice,
13
 *     this list of conditions and the following disclaimer in the documentation
14
 *     and/or other materials provided with the distribution.
15
 *
16
 *   * Neither the name of Arne Blankerts nor the names of contributors
17
 *     may be used to endorse or promote products derived from this software
18
 *     without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  * NOT LIMITED TO,
22
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
24
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 * @package    phpDox
33
 * @author     Arne Blankerts <[email protected]>
34
 * @copyright  Arne Blankerts <[email protected]>, All rights reserved.
35
 * @license    BSD License
36
 */
37
namespace TheSeer\phpDox\Generator {
38
39
    use TheSeer\phpDox\Generator\Engine\EngineInterface;
40
    use TheSeer\phpDox\Generator\Engine\EventHandlerRegistry;
41
    use TheSeer\phpDox\Generator\Enricher\ClassEnricherInterface;
42
    use TheSeer\phpDox\Generator\Enricher\EndEnricherInterface;
43
    use TheSeer\phpDox\Generator\Enricher\EnricherInterface;
44
    use TheSeer\phpDox\Generator\Enricher\StartEnricherInterface;
45
    use TheSeer\phpDox\Generator\Enricher\InterfaceEnricherInterface;
46
    use TheSeer\phpDox\Generator\Enricher\TokenFileEnricherInterface;
47
    use TheSeer\phpDox\Generator\Enricher\TraitEnricherInterface;
48
    use TheSeer\phpDox\ProgressLogger;
49
50
    class Generator {
51
52
        /**
53
         * @var ProgressLogger
54
         */
55
        private $logger;
56
57
        /**
58
         * @var array
59
         */
60
        private $enrichers = array(
61
            'phpdox.start'       => array(),
62
            'class.start'        => array(),
63
            'trait.start'        => array(),
64
            'interface.start'    => array(),
65
            'token.file.start'   => array(),
66
            'phpdox.end'         => array()
67
        );
68
69
        /**
70
         * @var string
71
         */
72
        private $xmlDir;
73
74
        /**
75
         * @var Project
76
         */
77
        private $project;
78
79
        /**
80
         * Map of events with engines
81
         *
82
         * @var EventHandlerRegistry
83
         */
84
        private $handlerRegistry;
85
86
        /**
87
         * @param ProgressLogger       $logger
88
         * @param EventHandlerRegistry $registry
89
         */
90
        public function __construct(ProgressLogger $logger, EventHandlerRegistry $registry) {
91
            $this->logger = $logger;
92
            $this->handlerRegistry = $registry;
93
        }
94
95
        /**
96
         * @param EngineInterface $engine
97
         *
98
         * @throws
99
         * @throws GeneratorException
100
         */
101
        public function addEngine(EngineInterface $engine) {
102
            $engine->registerEventHandlers($this->handlerRegistry);
103
        }
104
105
        public function addEnricher(EnricherInterface $enricher) {
106
            if ($enricher instanceof StartEnricherInterface) {
107
                $this->enrichers['phpdox.start'][] = $enricher;
108
            }
109
            if ($enricher instanceof ClassEnricherInterface) {
110
                $this->enrichers['class.start'][] = $enricher;
111
            }
112
            if ($enricher instanceof InterfaceEnricherInterface) {
113
                $this->enrichers['interface.start'][] = $enricher;
114
            }
115
            if ($enricher instanceof TraitEnricherInterface) {
116
                $this->enrichers['trait.start'][] = $enricher;
117
            }
118
            if ($enricher instanceof TokenFileEnricherInterface) {
119
                $this->enrichers['token.file.start'][] = $enricher;
120
            }
121
            if ($enricher instanceof EndEnricherInterface) {
122
                $this->enrichers['phpdox.end'][] = $enricher;
123
            }
124
        }
125
126
        /**
127
         * @param Project $project
128
         * @param bool    $publicOnly
0 ignored issues
show
Bug introduced by Arne Blankerts
There is no parameter named $publicOnly. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
129
         */
130
        public function run(Project $project) {
131
            $this->xmlDir     = $project->getXmlDir();
132
            $this->project    = $project;
133
134
            $this->handleEvent(new PHPDoxStartEvent($project->getIndex(), $project->getSourceTree()));
135
            if ($this->project->hasNamespaces()) {
136
                $this->processWithNamespace();
137
            } else {
138
                $this->processGlobalOnly();
139
            }
140
            $this->processTokenFiles($project->getSourceTree());
141
            $this->handleEvent(new PHPDoxEndEvent($project->getIndex(), $project->getSourceTree()));
142
            $this->logger->completed();
143
144
        }
145
146
        private function processTokenFiles(SourceTree $sourceTree) {
147
            foreach($sourceTree as $tokenFile) {
148
                $this->handleEvent(new TokenFileStartEvent($tokenFile));
149
                foreach($tokenFile as $sourceLine) {
150
                    $this->handleEvent(new TokenLineStartEvent($tokenFile, $sourceLine));
0 ignored issues
show
Unused Code introduced by Arne Blankerts
The call to TokenLineStartEvent::__construct() has too many arguments starting with $tokenFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
151
                    foreach($sourceLine as $token) {
152
                        $this->handleEvent(new TokenEvent($sourceLine, $token));
0 ignored issues
show
Unused Code introduced by Arne Blankerts
The call to TokenEvent::__construct() has too many arguments starting with $sourceLine.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
153
                    }
154
                    $this->handleEvent(new TokenLineEndEvent($tokenFile, $sourceLine));
0 ignored issues
show
Unused Code introduced by Arne Blankerts
The call to TokenLineEndEvent::__construct() has too many arguments starting with $tokenFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
155
                }
156
                $this->handleEvent(new TokenFileEndEvent($tokenFile));
0 ignored issues
show
Unused Code introduced by Arne Blankerts
The call to TokenFileEndEvent::__construct() has too many arguments starting with $tokenFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
157
            }
158
        }
159
160
        /**
161
         * @param AbstractEvent $event
162
         * @param bool          $progress
163
         */
164
        private function handleEvent(AbstractEvent $event, $progress = TRUE) {
165
            $eventType = $event->getType();
166
            if (isset($this->enrichers[$eventType])) {
167
                foreach($this->enrichers[$eventType] as $enricher) {
168
                    switch($eventType) {
169
                        case 'phpdox.start': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
170
                            $enricher->enrichStart($event);
171
                            break;
172
                        }
173
                        case 'class.start': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
174
                            $enricher->enrichClass($event);
175
                            break;
176
                        }
177
                        case 'interface.start': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
178
                            $enricher->enrichInterface($event);
179
                            break;
180
                        }
181
                        case 'trait.start': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
182
                            $enricher->enrichTrait($event);
183
                            break;
184
                        }
185
                        case 'token.file.start': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
186
                            $enricher->enrichTokenFile($event);
187
                            break;
188
                        }
189
                        case 'phpdox.end': {
0 ignored issues
show
Coding Style introduced by Arne Blankerts
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
190
                            $enricher->enrichEnd($event);
191
                            break;
192
                        }
193
                    }
194
                }
195
            }
196
            foreach($this->handlerRegistry->getHandlersForEvent($event->getType()) as $callback) {
197
                call_user_func($callback, $event);
198
            }
199
            if ($progress) {
200
                $this->logger->progress('processed');
201
            }
202
    }
203
204
        /**
205
         *
206
         */
207
        private function processGlobalOnly() {
208
            $classes = $this->project->getClasses();
209
            $this->handleEvent(new PHPDoxClassesStartEvent($classes));
210
            foreach($classes as $class) {
211
                $this->processClass($class);
212
            }
213
            $this->handleEvent(new PHPDoxClassesEndEvent($classes));
214
215
            $traits = $this->project->getTraits();
216
            $this->handleEvent(new PHPDoxTraitsStartEvent($traits));
217
            foreach($traits as $trait) {
218
                $this->processTrait($trait);
219
            }
220
            $this->handleEvent(new PHPDoxTraitsEndEvent($traits));
221
222
            $interfaces = $this->project->getInterfaces();
223
            $this->handleEvent(new PHPDoxInterfacesStartEvent($interfaces));
224
            foreach($interfaces as $interface) {
225
                $this->processInterface($interface);
226
            }
227
            $this->handleEvent(new PHPDoxInterfacesEndEvent($interfaces));
228
        }
229
230
        /**
231
         *
232
         */
233
        private function processWithNamespace() {
234
            $namespaces = $this->project->getNamespaces();
235
            $this->handleEvent(new PHPDoxNamespacesStartEvent($namespaces));
236
237
            foreach($namespaces as $namespace) {
238
                $this->handleEvent(new NamespaceStartEvent($namespace));
239
240
                $classes = $namespace->getClasses();
241
                $this->handleEvent(new NamespaceClassesStartEvent($classes, $namespace));
242
                foreach($classes as $class) {
243
                    $this->processClass($class);
244
                }
245
                $this->handleEvent(new NamespaceClassesEndEvent($classes, $namespace));
246
247
                $traits = $namespace->getTraits();
248
                $this->handleEvent(new NamespaceTraitsStartEvent($traits, $namespace));
249
                foreach($traits as $trait) {
250
                    $this->processTrait($trait);
251
                }
252
                $this->handleEvent(new NamespaceTraitsEndEvent($traits, $namespace));
253
254
                $interfaces = $namespace->getInterfaces();
255
                $this->handleEvent(new NamespaceInterfacesStartEvent($interfaces, $namespace));
256
                foreach($interfaces as $interface) {
257
                    $this->processInterface($interface);
258
                }
259
                $this->handleEvent(new NamespaceInterfacesEndEvent($interfaces, $namespace));
260
261
                $this->handleEvent(new NamespaceEndEvent($namespace));
262
            }
263
            $this->handleEvent(new PHPDoxNamespacesEndEvent($namespaces));
264
        }
265
266
        /**
267
         * @param $class ClassEntry
268
         */
269 View Code Duplication
        private function processClass(ClassEntry $entry) {
270
            $class = $entry->getClassObject($this->xmlDir);
271
            $this->handleEvent(new ClassStartEvent($class));
272
273
            foreach($class->getConstants() as $constant) {
274
                $this->handleEvent(new ClassConstantEvent($constant, $class));
275
            }
276
277
            foreach($class->getMembers() as $member) {
278
                $this->handleEvent(new ClassMemberEvent($member, $class));
279
            }
280
281
            foreach($class->getMethods() as $method) {
282
                $this->handleEvent(new ClassMethodEvent($method, $class));
283
            }
284
            $this->handleEvent(new ClassEndEvent($class));
285
286
        }
287
288
        /**
289
         * @param TraitEntry $traitEntry
290
         */
291 View Code Duplication
        private function processTrait(TraitEntry $traitEntry) {
292
            $trait = $traitEntry->getTraitObject($this->xmlDir);
293
            $this->handleEvent(new TraitStartEvent($trait));
294
295
            foreach($trait->getConstants() as $constant) {
296
                $this->handleEvent(new TraitConstantEvent($constant, $trait));
297
            }
298
299
            foreach($trait->getMembers() as $member) {
300
                $this->handleEvent(new TraitMemberEvent($member, $trait));
301
            }
302
303
            foreach($trait->getMethods() as $method) {
304
                $this->handleEvent(new TraitMethodEvent($method, $trait));
305
            }
306
            $this->handleEvent(new TraitEndEvent($trait));
307
        }
308
309
        /**
310
         * @param InterfaceEntry $interface
0 ignored issues
show
Documentation introduced by Arne Blankerts
There is no parameter named $interface. Did you maybe mean $interfaceEntry?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
311
         */
312
        private function processInterface(InterfaceEntry $interfaceEntry) {
313
            $interface = $interfaceEntry->getInterfaceObject($this->xmlDir);
314
315
            $this->handleEvent(new InterfaceStartEvent($interface));
316
317
            foreach($interface->getConstants() as $constant) {
318
                $this->handleEvent(new InterfaceConstantEvent($constant, $interface));
319
            }
320
321
            foreach($interface->getMethods() as $method) {
322
                $this->handleEvent(new InterfaceMethodEvent($method, $interface));
323
            }
324
325
            $this->handleEvent(new InterfaceEndEvent($interface));
326
        }
327
328
    }
329
330
    class GeneratorException extends \Exception {
0 ignored issues
show
Coding Style Compatibility introduced by Arne Blankerts
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
331
        const UnknownEvent = 1;
332
        const AlreadyRegistered = 2;
333
    }
334
335
}
336