Completed
Pull Request — master (#263)
by Kévin
02:06
created

MagicCallPatch   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 6
Bugs 1 Features 1
Metric Value
wmc 10
c 6
b 1
f 1
lcom 1
cbo 5
dl 0
loc 77
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A supports() 0 4 1
C apply() 0 38 7
A getPriority() 0 4 1
1
<?php
2
3
/*
4
 * This file is part of the Prophecy.
5
 * (c) Konstantin Kudryashov <[email protected]>
6
 *     Marcello Duarte <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Prophecy\Doubler\ClassPatch;
13
14
use phpDocumentor\Reflection\DocBlock\Tags\Method;
15
use phpDocumentor\Reflection\DocBlockFactory;
16
use phpDocumentor\Reflection\DocBlockFactoryInterface;
17
use phpDocumentor\Reflection\Types\ContextFactory;
18
use Prophecy\Doubler\Generator\Node\ClassNode;
19
use Prophecy\Doubler\Generator\Node\MethodNode;
20
21
/**
22
 * Discover Magical API using "@method" PHPDoc format.
23
 *
24
 * @author Thomas Tourlourat <[email protected]>
25
 * @author Kévin Dunglas <[email protected]>
26
 */
27
class MagicCallPatch implements ClassPatchInterface
28
{
29
    private $docBlockFactory;
30
    private $contextFactory;
31
32
    public function __construct()
33
    {
34
        $this->docBlockFactory = DocBlockFactory::createInstance();
35
        $this->contextFactory = new ContextFactory();
36
    }
37
38
    /**
39
     * Support any class
40
     *
41
     * @param ClassNode $node
42
     *
43
     * @return boolean
44
     */
45
    public function supports(ClassNode $node)
46
    {
47
        return true;
48
    }
49
50
    /**
51
     * Discover Magical API
52
     *
53
     * @param ClassNode $node
54
     */
55
    public function apply(ClassNode $node)
56
    {
57
        $parentClass = $node->getParentClass();
58
        $reflectionClass = new \ReflectionClass($parentClass);
59
60
        try {
61
            $phpdoc = $this->docBlockFactory->create($reflectionClass, $this->contextFactory->createFromReflector($reflectionClass));
62
            $tagList = $phpdoc->getTagsByName('method');
63
        } catch (\InvalidArgumentException $e) {
64
            // No DocBlock
65
            $tagList = array();
66
        }
67
68
        $interfaces = $reflectionClass->getInterfaces();
69
        foreach($interfaces as $interface) {
70
            try {
71
                $phpdoc = $this->docBlockFactory->create($interface, $this->contextFactory->createFromReflector($interface));
72
                $tagList = array_merge($tagList, $phpdoc->getTagsByName('method'));
73
            } catch (\InvalidArgumentException $e) {
74
                // No DocBlock
75
            }
76
        }
77
78
        foreach($tagList as $tag) {
79
            $methodName = $tag->getMethodName();
80
81
            if (empty($methodName)) {
82
                continue;
83
            }
84
85
            if (!$reflectionClass->hasMethod($methodName)) {
86
                $methodNode = new MethodNode($tag->getMethodName());
87
                $methodNode->setStatic($tag->isStatic());
88
89
                $node->addMethod($methodNode);
90
            }
91
        }
92
    }
93
94
    /**
95
     * Returns patch priority, which determines when patch will be applied.
96
     *
97
     * @return integer Priority number (higher - earlier)
98
     */
99
    public function getPriority()
100
    {
101
        return 50;
102
    }
103
}
104
105