Completed
Push — master ( 26f174...a0e62f )
by Joas
14:52 queued 05:17
created

SimpleContainer::resolve()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
nc 5
nop 1
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bernhard Posselt <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Morris Jobke <[email protected]>
9
 * @author Robin McCorkell <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\AppFramework\Utility;
29
30
use ReflectionClass;
31
use ReflectionException;
32
use Closure;
33
use Pimple\Container;
34
use OCP\AppFramework\QueryException;
35
use OCP\IContainer;
36
37
/**
38
 * Class SimpleContainer
39
 *
40
 * SimpleContainer is a simple implementation of IContainer on basis of Pimple
41
 */
42
class SimpleContainer extends Container implements IContainer {
43
44
45
	/**
46
	 * @param ReflectionClass $class the class to instantiate
47
	 * @return \stdClass the created class
48
	 */
49
	private function buildClass(ReflectionClass $class) {
50
		$constructor = $class->getConstructor();
51
		if ($constructor === null) {
52
			return $class->newInstance();
53
		} else {
54
			$parameters = [];
55
			foreach ($constructor->getParameters() as $parameter) {
56
				$parameterClass = $parameter->getClass();
57
58
				// try to find out if it is a class or a simple parameter
59
				if ($parameterClass === null) {
60
					$resolveName = $parameter->getName();
61
				} else {
62
					$resolveName = $parameterClass->name;
63
				}
64
65
				try {
66
					$parameters[] = $this->query($resolveName);
67
				} catch (\Exception $e) {
68
					// Service not found, use the default value when available
69
					if ($parameter->isDefaultValueAvailable()) {
70
						$parameters[] = $parameter->getDefaultValue();
71
					} else {
72
						throw $e;
73
					}
74
				}
75
			}
76
			return $class->newInstanceArgs($parameters);
77
		}
78
	}
79
80
81
	/**
82
	 * If a parameter is not registered in the container try to instantiate it
83
	 * by using reflection to find out how to build the class
84
	 * @param string $name the class name to resolve
85
	 * @return \stdClass
86
	 * @throws QueryException if the class could not be found or instantiated
87
	 */
88
	public function resolve($name) {
89
		$baseMsg = 'Could not resolve ' . $name . '!';
90
		try {
91
			$class = new ReflectionClass($name);
92
			if ($class->isInstantiable()) {
93
				return $this->buildClass($class);
94
			} else {
95
				throw new QueryException($baseMsg .
96
					' Class can not be instantiated');
97
			}
98
		} catch(ReflectionException $e) {
99
			throw new QueryException($baseMsg . ' ' . $e->getMessage());
100
		}
101
	}
102
103
104
	/**
105
	 * @param string $name name of the service to query for
106
	 * @return mixed registered service for the given $name
107
	 * @throws QueryException if the query could not be resolved
108
	 */
109
	public function query($name) {
110
		$name = $this->sanitizeName($name);
111
		if ($this->offsetExists($name)) {
112
			return $this->offsetGet($name);
113
		} else {
114
			$object = $this->resolve($name);
115
			$this->registerService($name, function () use ($object) {
116
				return $object;
117
			});
118
			return $object;
119
		}
120
	}
121
122
	/**
123
	 * @param string $name
124
	 * @param mixed $value
125
	 */
126
	public function registerParameter($name, $value) {
127
		$this[$name] = $value;
128
	}
129
130
	/**
131
	 * The given closure is call the first time the given service is queried.
132
	 * The closure has to return the instance for the given service.
133
	 * Created instance will be cached in case $shared is true.
134
	 *
135
	 * @param string $name name of the service to register another backend for
136
	 * @param Closure $closure the closure to be called on service creation
137
	 * @param bool $shared
138
	 */
139
	public function registerService($name, Closure $closure, $shared = true) {
140
		$name = $this->sanitizeName($name);
141
		if (isset($this[$name]))  {
142
			unset($this[$name]);
143
		}
144
		if ($shared) {
145
			$this[$name] = $closure;
146
		} else {
147
			$this[$name] = parent::factory($closure);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (factory() instead of registerService()). Are you sure this is correct? If so, you might want to change this to $this->factory().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
148
		}
149
	}
150
151
	/**
152
	 * Shortcut for returning a service from a service under a different key,
153
	 * e.g. to tell the container to return a class when queried for an
154
	 * interface
155
	 * @param string $alias the alias that should be registered
156
	 * @param string $target the target that should be resolved instead
157
	 */
158
	public function registerAlias($alias, $target) {
159
		$this->registerService($alias, function (IContainer $container) use ($target) {
160
			return $container->query($target);
161
		}, false);
162
	}
163
164
	/*
165
	 * @param string $name
166
	 * @return string
167
	 */
168
	protected function sanitizeName($name) {
169
		return ltrim($name, '\\');
170
	}
171
172
}
173