Skip to content

Commit 44a9d8a

Browse files
committed
Drop Nette/DI dependency
1 parent 4b33012 commit 44a9d8a

File tree

3 files changed

+229
-41
lines changed

3 files changed

+229
-41
lines changed

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
}
1313
],
1414
"require": {
15-
"mockery/mockery": "^1.0",
16-
"nette/di": "2.3.*"
15+
"mockery/mockery": "^1.0"
1716
},
1817
"require-dev": {
1918
"nette/tester": "2.1.0"

src/Spamer/DependencyMocker/Mocker.php

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
1-
<?php
1+
<?php declare(strict_types = 1);
22

33
namespace Spamer\DependencyMocker;
44

5-
use Nette;
6-
use Mockery;
75

86
class Mocker
97
{
10-
/** @var array */
8+
/**
9+
* @var array
10+
*/
1111
public static $bannedClasses = [];
1212

13-
/** @var \ReflectionClass */
13+
/**
14+
* @var \ReflectionClass
15+
*/
1416
private static $reflectedClass;
1517

16-
/** @var Mockery\Mock */
17-
private static $mockedClass;
18-
1918
/**
20-
* @param string $className
21-
* @return \ReflectionClass|\stdClass
19+
* @var \Mockery\Mock
2220
*/
23-
public static function mockClassDependencies($className)
21+
private static $mockedClass;
22+
23+
24+
public static function mockClassDependencies(
25+
string $className
26+
) : \Mockery\MockInterface
2427
{
2528
self::$reflectedClass = new \ReflectionClass($className);
26-
self::$mockedClass = Mockery::mock($className);
29+
self::$mockedClass = \Mockery::mock($className);
2730

2831
self::mockInjectedMethods($className);
2932
self::mockInjectedProperties();
@@ -33,32 +36,31 @@ public static function mockClassDependencies($className)
3336
}
3437

3538

36-
/**
37-
* @param string $className
38-
*/
39-
private static function mockInjectedMethods($className)
39+
private static function mockInjectedMethods(
40+
string $className
41+
) : void
4042
{
4143
foreach (self::$reflectedClass->getMethods() as $method) {
42-
if (substr($method->getName(), 0, 6) === 'inject') {
44+
if (\strpos($method->getName(), 'inject') === 0) {
4345
self::mockDependenciesFromMethod($className, $method->getName());
4446
}
4547
}
4648
}
4749

4850

49-
private static function mockInjectedProperties()
51+
private static function mockInjectedProperties() : void
5052
{
5153
/** @var \ReflectionProperty $property */
5254
foreach (self::$reflectedClass->getProperties() as $property) {
5355
if (
54-
Nette\DI\PhpReflection::parseAnnotation($property, 'inject') !== NULL
56+
ReflectionHelper::parseAnnotation($property, 'inject') !== NULL
5557
||
56-
Nette\DI\PhpReflection::parseAnnotation($property, 'autowire') !== NULL
58+
ReflectionHelper::parseAnnotation($property, 'autowire') !== NULL
5759
) {
58-
if ($mockedParameterClass = Nette\DI\PhpReflection::parseAnnotation($property, 'var')) {
59-
$mockedParameterClass = Nette\DI\PhpReflection::expandClassName(
60+
if ($mockedParameterClass = ReflectionHelper::parseAnnotation($property, 'var')) {
61+
$mockedParameterClass = ReflectionHelper::expandClassName(
6062
$mockedParameterClass,
61-
Nette\DI\PhpReflection::getDeclaringClass($property)
63+
ReflectionHelper::getDeclaringClass($property)
6264
);
6365
}
6466
self::setProperty($mockedParameterClass, $property);
@@ -67,22 +69,18 @@ private static function mockInjectedProperties()
6769
}
6870

6971

70-
/**
71-
* @param string $className
72-
*/
73-
private static function mockConstructorDependencies($className)
72+
private static function mockConstructorDependencies(string $className) : void
7473
{
7574
if (method_exists($className, '__construct')) {
7675
self::mockDependenciesFromMethod($className, '__construct');
7776
}
7877
}
7978

8079

81-
/**
82-
* @param string $className
83-
* @param string $methodName
84-
*/
85-
private static function mockDependenciesFromMethod($className, $methodName)
80+
private static function mockDependenciesFromMethod(
81+
string $className,
82+
string $methodName
83+
) : void
8684
{
8785
$reflectionMethod = new \ReflectionMethod($className, $methodName);
8886
$parameters = $reflectionMethod->getParameters();
@@ -97,10 +95,9 @@ private static function mockDependenciesFromMethod($className, $methodName)
9795
}
9896

9997

100-
/**
101-
* @param array $bannedClasses
102-
*/
103-
public static function setBannedClasses($bannedClasses)
98+
public static function setBannedClasses(
99+
array $bannedClasses
100+
) : void
104101
{
105102
self::$bannedClasses = $bannedClasses;
106103
}
@@ -109,11 +106,18 @@ public static function setBannedClasses($bannedClasses)
109106
/**
110107
* @param string $className
111108
* @param \ReflectionParameter|\ReflectionProperty $class
109+
* @throws \ReflectionException
112110
*/
113-
private static function setProperty($className, $class)
111+
private static function setProperty(
112+
string $className,
113+
$class
114+
) : void
114115
{
115-
if ( ! in_array($className, self::$bannedClasses) && $class->getDeclaringClass()->hasProperty($class->getName())) {
116-
$mockedParameter = Mockery::mock($className);
116+
if (
117+
! in_array($className, self::$bannedClasses, TRUE)
118+
&& $class->getDeclaringClass()->hasProperty($class->getName())
119+
) {
120+
$mockedParameter = \Mockery::mock($className);
117121
$property = new \ReflectionProperty($class->getDeclaringClass()->getName(), $class->getName());
118122
$property->setAccessible(TRUE);
119123
$property->setValue(self::$mockedClass, $mockedParameter);
@@ -126,6 +130,7 @@ private static function setProperty($className, $class)
126130
* @param string $property
127131
* @param object $object
128132
* @return mixed
133+
* @throws \ReflectionException
129134
*/
130135
public static function getProperty($class, $property, $object)
131136
{
@@ -142,6 +147,7 @@ public static function getProperty($class, $property, $object)
142147
* @param string $method
143148
* @param array $arguments
144149
* @return mixed
150+
* @throws \ReflectionException
145151
*/
146152
public static function callPrivateFunction($object, $method, $arguments = [])
147153
{
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Spamer\DependencyMocker;
4+
5+
6+
class ReflectionHelper
7+
{
8+
9+
/**
10+
* @var array
11+
*/
12+
private static $cache;
13+
14+
/**
15+
* @var array
16+
*/
17+
private static $builtinTypes = [
18+
'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
19+
'callable' => 1, 'iterable' => 1, 'void' => 1,
20+
];
21+
22+
23+
public static function parseAnnotation(
24+
\ReflectionProperty $ref,
25+
string $name
26+
) : string
27+
{
28+
if (preg_match("#[\\s*]@$name(?:\\s++([^@]\\S*)?|$)#", trim($ref->getDocComment(), '/*'), $m)) {
29+
return $m[1] ?? '';
30+
}
31+
32+
return '';
33+
}
34+
35+
36+
37+
public static function getDeclaringClass(
38+
\ReflectionProperty $prop
39+
) : \ReflectionClass
40+
{
41+
foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
42+
if ($trait->hasProperty($prop->getName())) {
43+
return self::getDeclaringClass($trait->getProperty($prop->getName()));
44+
}
45+
}
46+
47+
return $prop->getDeclaringClass();
48+
}
49+
50+
51+
public static function expandClassName(
52+
string $name,
53+
\ReflectionClass $rc
54+
) : string
55+
{
56+
$lower = strtolower($name);
57+
58+
if (self::isBuiltinType($lower)) {
59+
return $lower;
60+
61+
} elseif ($lower === 'self' || $lower === 'static' || $lower === '$this') {
62+
return $rc->getName();
63+
64+
} elseif ($name[0] === '\\') { // fully qualified name
65+
return ltrim($name, '\\');
66+
}
67+
68+
$uses = & self::$cache[$rc->getName()];
69+
if ($uses === NULL) {
70+
self::$cache = self::parseUseStatements(file_get_contents($rc->getFileName()), $rc->getName()) + self::$cache;
71+
$uses = & self::$cache[$rc->getName()];
72+
}
73+
$parts = explode('\\', $name, 2);
74+
if (isset($uses[$parts[0]])) {
75+
$parts[0] = $uses[$parts[0]];
76+
return implode('\\', $parts);
77+
78+
} elseif ($rc->inNamespace()) {
79+
return $rc->getNamespaceName() . '\\' . $name;
80+
81+
} else {
82+
return $name;
83+
}
84+
}
85+
86+
87+
public static function isBuiltinType(
88+
string $type
89+
) : bool
90+
{
91+
return isset(self::$builtinTypes[strtolower($type)]);
92+
}
93+
94+
95+
private static function parseUseStatements($code, $forClass = null)
96+
{
97+
$tokens = PHP_VERSION_ID >= 70000 ? token_get_all($code, TOKEN_PARSE) : token_get_all($code);
98+
$namespace = $class = $classLevel = $level = null;
99+
$res = $uses = [];
100+
101+
while ($token = current($tokens)) {
102+
next($tokens);
103+
switch (is_array($token) ? $token[0] : $token) {
104+
case T_NAMESPACE:
105+
$namespace = ltrim(self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
106+
$uses = [];
107+
break;
108+
109+
case T_CLASS:
110+
case T_INTERFACE:
111+
case T_TRAIT:
112+
if ($name = self::fetch($tokens, T_STRING)) {
113+
$class = $namespace . $name;
114+
$classLevel = $level + 1;
115+
$res[$class] = $uses;
116+
if ($class === $forClass) {
117+
return $res;
118+
}
119+
}
120+
break;
121+
122+
case T_USE:
123+
while (!$class && ($name = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]))) {
124+
$name = ltrim($name, '\\');
125+
if (self::fetch($tokens, '{')) {
126+
while ($suffix = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR])) {
127+
if (self::fetch($tokens, T_AS)) {
128+
$uses[self::fetch($tokens, T_STRING)] = $name . $suffix;
129+
} else {
130+
$tmp = explode('\\', $suffix);
131+
$uses[end($tmp)] = $name . $suffix;
132+
}
133+
if (!self::fetch($tokens, ',')) {
134+
break;
135+
}
136+
}
137+
138+
} elseif (self::fetch($tokens, T_AS)) {
139+
$uses[self::fetch($tokens, T_STRING)] = $name;
140+
141+
} else {
142+
$tmp = explode('\\', $name);
143+
$uses[end($tmp)] = $name;
144+
}
145+
if (!self::fetch($tokens, ',')) {
146+
break;
147+
}
148+
}
149+
break;
150+
151+
case T_CURLY_OPEN:
152+
case T_DOLLAR_OPEN_CURLY_BRACES:
153+
case '{':
154+
$level++;
155+
break;
156+
157+
case '}':
158+
if ($level === $classLevel) {
159+
$class = $classLevel = null;
160+
}
161+
$level--;
162+
}
163+
}
164+
165+
return $res;
166+
}
167+
168+
169+
private static function fetch(&$tokens, $take)
170+
{
171+
$res = null;
172+
while ($token = current($tokens)) {
173+
[$token, $s] = is_array($token) ? $token : [$token, $token];
174+
if (in_array($token, (array) $take, true)) {
175+
$res .= $s;
176+
} elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], true)) {
177+
break;
178+
}
179+
next($tokens);
180+
}
181+
return $res;
182+
}
183+
}

0 commit comments

Comments
 (0)