Completed
Pull Request — master (#631)
by Dave
03:16
created

MethodDefinitionPass   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 160
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 98.02%

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 3
dl 0
loc 160
ccs 99
cts 101
cp 0.9802
rs 9.8
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
D renderParams() 0 31 9
A appendToClass() 0 6 1
B apply() 0 27 6
A renderReturnType() 0 5 2
B renderTypeHint() 0 27 5
B renderMethodBody() 0 56 8
1
<?php
2
/**
3
 * Mockery
4
 *
5
 * LICENSE
6
 *
7
 * This source file is subject to the new BSD license that is bundled
8
 * with this package in the file LICENSE.txt.
9
 * It is also available through the world-wide-web at this URL:
10
 * http://github.com/padraic/mockery/blob/master/LICENSE
11
 * If you did not receive a copy of the license and are unable to
12
 * obtain it through the world-wide-web, please send an email
13
 * to [email protected] so we can send you a copy immediately.
14
 *
15
 * @category   Mockery
16
 * @package    Mockery
17
 * @copyright  Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
18
 * @license    http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
19
 */
20
21
namespace Mockery\Generator\StringManipulation\Pass;
22
23
use Mockery\Generator\Method;
24
use Mockery\Generator\Parameter;
25
use Mockery\Generator\MockConfiguration;
26
27
class MethodDefinitionPass implements Pass
28
{
29 400
    public function apply($code, MockConfiguration $config)
30
    {
31 400
        foreach ($config->getMethodsToMock() as $method) {
32 116
            if ($method->isPublic()) {
33 112
                $methodDef = 'public';
34 116
            } elseif ($method->isProtected()) {
35 12
                $methodDef = 'protected';
36 12
            } else {
37 2
                $methodDef = 'private';
38
            }
39
40 116
            if ($method->isStatic()) {
41 9
                $methodDef .= ' static';
42 9
            }
43
44 116
            $methodDef .= ' function ';
45 116
            $methodDef .= $method->returnsReference() ? ' & ' : '';
46 116
            $methodDef .= $method->getName();
47 116
            $methodDef .= $this->renderParams($method, $config);
48 116
            $methodDef .= $this->renderReturnType($method);
49 116
            $methodDef .= $this->renderMethodBody($method, $config);
50
51 116
            $code = $this->appendToClass($code, $methodDef);
52 400
        }
53
54 400
        return $code;
55
    }
56
57 116
    protected function renderParams(Method $method, $config)
58
    {
59 116
        $class = $method->getDeclaringClass();
60 116
        if ($class->isInternal()) {
61 24
            $overrides = $config->getParameterOverrides();
62
63 24
            if (isset($overrides[strtolower($class->getName())][$method->getName()])) {
64 3
                return '(' . implode(',', $overrides[strtolower($class->getName())][$method->getName()]) . ')';
65
            }
66 24
        }
67
68 116
        $methodParams = array();
69 116
        $params = $method->getParameters();
70 116
        foreach ($params as $param) {
71 52
            $paramDef = $this->renderTypeHint($param);
72 52
            $paramDef .= $param->isPassedByReference() ? '&' : '';
73 52
            $paramDef .= $param->isVariadic() ? '...' : '';
74 52
            $paramDef .= '$' . $param->getName();
75
76 52
            if (!$param->isVariadic()) {
77 51
                if (false !== $param->isDefaultValueAvailable()) {
78 5
                    $paramDef .= ' = ' . var_export($param->getDefaultValue(), true);
79 51
                } elseif ($param->isOptional()) {
80 14
                    $paramDef .= ' = null';
81 14
                }
82 51
            }
83
84 52
            $methodParams[] = $paramDef;
85 116
        }
86 116
        return '(' . implode(', ', $methodParams) . ')';
87
    }
88
89 116
    protected function renderReturnType(Method $method)
90
    {
91 116
        $type = $method->getReturnType();
92 116
        return $type ? sprintf(': %s', $type) : '';
93
    }
94
95 116
    protected function appendToClass($class, $code)
96
    {
97 116
        $lastBrace = strrpos($class, "}");
98 116
        $class = substr($class, 0, $lastBrace) . $code . "\n    }\n";
99 116
        return $class;
100
    }
101
102 52
    protected function renderTypeHint(Parameter $param)
103
    {
104
        $languageTypeHints = array(
105 52
            'self',
106 52
            'array',
107 52
            'callable',
108
            // Up to php 7
109 52
            'bool',
110 52
            'float',
111 52
            'int',
112
            'string'
113 52
        );
114 52
        $typeHint = trim($param->getTypeHintAsString());
115
116 52
        if (!empty($typeHint)) {
117
           
118 10
            if (!in_array($typeHint, $languageTypeHints)) {
119 8
                $typeHint = '\\'.$typeHint;
120 8
            }
121
122 10
            if (version_compare(PHP_VERSION, '7.1.0-dev') >= 0 && $param->allowsNull()) {
0 ignored issues
show
Documentation Bug introduced by
The method allowsNull does not exist on object<Mockery\Generator\Parameter>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
123
                $typeHint = "?".$typeHint;
124
            }
125 10
        }
126
127 52
        return $typeHint .= ' ';
128
    }
129
130 116
    private function renderMethodBody($method, $config)
131
    {
132 116
        $invoke = $method->isStatic() ? 'static::_mockery_handleStaticMethodCall' : '$this->_mockery_handleMethodCall';
133
        $body = <<<BODY
134
{
135
\$argc = func_num_args();
136
\$argv = func_get_args();
137
138 116
BODY;
139
140
        // Fix up known parameters by reference - used func_get_args() above
141
        // in case more parameters are passed in than the function definition
142
        // says - eg varargs.
143 116
        $class = $method->getDeclaringClass();
144 116
        $class_name = strtolower($class->getName());
145 116
        $overrides = $config->getParameterOverrides();
146 116
        if (isset($overrides[$class_name][$method->getName()])) {
147 3
            $params = array_values($overrides[$class_name][$method->getName()]);
148 3
            $paramCount = count($params);
149 3
            for ($i = 0; $i < $paramCount; ++$i) {
150 3
                $param = $params[$i];
151 3
                if (strpos($param, '&') !== false) {
152
                    $body .= <<<BODY
153
if (\$argc > $i) {
154 3
    \$argv[$i] = {$param};
155
}
156
157 3
BODY;
158 3
                }
159 3
            }
160 3
        } else {
161 116
            $params = array_values($method->getParameters());
162 116
            $paramCount = count($params);
163 116
            for ($i = 0; $i < $paramCount; ++$i) {
164 52
                $param = $params[$i];
165 52
                if (!$param->isPassedByReference()) {
166 50
                    continue;
167
                }
168
                $body .= <<<BODY
169
if (\$argc > $i) {
170 6
    \$argv[$i] =& \${$param->getName()};
171
}
172
173 6
BODY;
174 6
            }
175
        }
176
177 116
        $body .= "\$ret = {$invoke}(__FUNCTION__, \$argv);\n";
178
179 116
        if ($method->getReturnType() !== "void") {
180 116
            $body .= "return \$ret;\n";
181 116
        }
182
183 116
        $body .= "}\n";
184 116
        return $body;
185
    }
186
}
187