Mocktainer::create()   B
last analyzed

Complexity

Conditions 6
Paths 9

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 8.8657
c 0
b 0
f 0
cc 6
nc 9
nop 2
1
<?php declare(strict_types = 1);
2
3
namespace Mocktainer;
4
5
class Mocktainer
6
{
7
8
	/** @var \PHPUnit\Framework\TestCase */
9
	private $testCase;
10
11
	public function __construct(\PHPUnit\Framework\TestCase $testCase)
12
	{
13
		$this->testCase = $testCase;
14
	}
15
16
	/**
17
	 * @param string $className
18
	 * @param mixed[] $constructorArguments
19
	 * @return mixed
20
	 */
21
	public function create(string $className, array $constructorArguments = [])
22
	{
23
		if (!class_exists($className)) {
24
			throw new \Mocktainer\ClassNotFoundException($className);
25
		}
26
27
		$classReflection = new \ReflectionClass($className);
28
		$constructorReflection = $classReflection->getConstructor();
29
		$constructorArgumentsToCall = [];
30
31
		foreach ($this->getConstructorParameters($constructorReflection) as $name => $parameter) {
32
			if (isset($constructorArguments[$name])) {
33
				$constructorArgumentsToCall[] = $constructorArguments[$name];
34
				unset($constructorArguments[$name]);
35
			} elseif ($parameter->isDefaultValueAvailable()) {
36
				$constructorArgumentsToCall[] = $parameter->getDefaultValue();
37
			} else {
38
				$constructorArgumentsToCall[] = $this->getArgumentMock($className, $name, $parameter);
39
			}
40
		}
41
42
		if (count($constructorArguments) > 0) {
43
			throw new \Mocktainer\UnknownConstructorArgumentsException($className, $constructorArguments);
44
		}
45
46
		return $classReflection->newInstanceArgs($constructorArgumentsToCall);
47
	}
48
49
	/**
50
	 * @param string $className
51
	 * @param string $argumentName
52
	 * @param \ReflectionParameter $parameter
53
	 * @return mixed
54
	 */
55
	private function getArgumentMock(string $className, string $argumentName, \ReflectionParameter $parameter)
56
	{
57
		if ($parameter->getClass() !== null) {
58
			return $this->testCase->getMockBuilder($parameter->getClass()->name)
59
				->disableOriginalConstructor()
60
				->getMock();
61
		}
62
63
		throw new \Mocktainer\UnmockableConstructorArgumentException($className, $argumentName);
64
	}
65
66
	/**
67
	 * @param \ReflectionMethod $constructorReflection
68
	 * @return \ReflectionParameter[]
69
	 */
70
	private function getConstructorParameters(\ReflectionMethod $constructorReflection): array
71
	{
72
		$parameters = [];
73
		foreach ($constructorReflection->getParameters() as $parameter) {
74
			$parameters[$parameter->name] = $parameter;
75
		}
76
77
		return $parameters;
78
	}
79
80
}
81