Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
83.33% |
35 / 42 |
|
33.33% |
1 / 3 |
CRAP | |
0.00% |
0 / 1 |
resolver | |
83.33% |
35 / 42 |
|
33.33% |
1 / 3 |
19.50 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getController | |
60.00% |
9 / 15 |
|
0.00% |
0 / 1 |
10.14 | |||
getArguments | |
95.65% |
22 / 23 |
|
0.00% |
0 / 1 |
10 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\controller; |
15 | |
16 | use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; |
17 | use Symfony\Component\DependencyInjection\ContainerInterface; |
18 | use Symfony\Component\HttpFoundation\Request; |
19 | |
20 | /** |
21 | * Controller manager class |
22 | */ |
23 | class resolver implements ControllerResolverInterface |
24 | { |
25 | /** |
26 | * ContainerInterface object |
27 | * @var ContainerInterface |
28 | */ |
29 | protected $container; |
30 | |
31 | /** |
32 | * phpbb\template\template object |
33 | * @var \phpbb\template\template|null |
34 | */ |
35 | protected $template; |
36 | |
37 | /** |
38 | * Request type cast helper object |
39 | * @var \phpbb\request\type_cast_helper |
40 | */ |
41 | protected $type_cast_helper; |
42 | |
43 | /** |
44 | * phpBB root path |
45 | * @var string |
46 | */ |
47 | protected $phpbb_root_path; |
48 | |
49 | /** |
50 | * Construct method |
51 | * |
52 | * @param ContainerInterface $container ContainerInterface object |
53 | * @param string $phpbb_root_path Relative path to phpBB root |
54 | * @param \phpbb\template\template|null $template |
55 | */ |
56 | public function __construct(ContainerInterface $container, $phpbb_root_path, \phpbb\template\template $template = null) |
57 | { |
58 | $this->container = $container; |
59 | $this->template = $template; |
60 | $this->type_cast_helper = new \phpbb\request\type_cast_helper(); |
61 | $this->phpbb_root_path = $phpbb_root_path; |
62 | } |
63 | |
64 | /** |
65 | * Load a controller callable |
66 | * |
67 | * @param Request $request Symfony Request object |
68 | * @return callable|false Callable or false |
69 | * @throws \phpbb\controller\exception |
70 | */ |
71 | public function getController(Request $request): callable|false |
72 | { |
73 | $controller = $request->attributes->get('_controller'); |
74 | |
75 | if (!$controller) |
76 | { |
77 | throw new \phpbb\controller\exception('CONTROLLER_NOT_SPECIFIED'); |
78 | } |
79 | |
80 | // Require a method name along with the service name |
81 | if (stripos($controller, ':') === false) |
82 | { |
83 | throw new \phpbb\controller\exception('CONTROLLER_METHOD_NOT_SPECIFIED'); |
84 | } |
85 | |
86 | list($service, $method) = explode(':', $controller); |
87 | |
88 | if (!$this->container->has($service)) |
89 | { |
90 | throw new \phpbb\controller\exception('CONTROLLER_SERVICE_UNDEFINED', array($service)); |
91 | } |
92 | |
93 | $controller_object = $this->container->get($service); |
94 | |
95 | /* |
96 | * If this is an extension controller, we'll try to automatically set |
97 | * the style paths for the extension (the ext author can change them |
98 | * if necessary). |
99 | */ |
100 | $controller_dir = explode('\\', get_class($controller_object)); |
101 | |
102 | // 0 vendor, 1 extension name, ... |
103 | if (!is_null($this->template) && isset($controller_dir[1])) |
104 | { |
105 | $controller_style_dir = 'ext/' . $controller_dir[0] . '/' . $controller_dir[1] . '/styles'; |
106 | |
107 | if (is_dir($this->phpbb_root_path . $controller_style_dir)) |
108 | { |
109 | $this->template->set_style(array($controller_style_dir, 'styles')); |
110 | } |
111 | } |
112 | |
113 | return array($controller_object, $method); |
114 | } |
115 | |
116 | /** |
117 | * Dependencies should be specified in the service definition and can be |
118 | * then accessed in __construct(). Arguments are sent through the URL path |
119 | * and should match the parameters of the method you are using as your |
120 | * controller. |
121 | * |
122 | * @param Request $request Symfony Request object |
123 | * @param mixed $controller A callable (controller class, method) |
124 | * @return array An array of arguments to pass to the controller |
125 | * @throws \phpbb\controller\exception |
126 | */ |
127 | public function getArguments(Request $request, $controller) |
128 | { |
129 | // At this point, $controller should be a callable |
130 | if (is_array($controller)) |
131 | { |
132 | list($object, $method) = $controller; |
133 | $mirror = new \ReflectionMethod($object, $method); |
134 | } |
135 | else if (is_object($controller) && !$controller instanceof \Closure) |
136 | { |
137 | $mirror = new \ReflectionObject($controller); |
138 | $mirror = $mirror->getMethod('__invoke'); |
139 | } |
140 | else |
141 | { |
142 | $mirror = new \ReflectionFunction($controller); |
143 | } |
144 | |
145 | $arguments = array(); |
146 | $parameters = $mirror->getParameters(); |
147 | $attributes = $request->attributes->all(); |
148 | foreach ($parameters as $param) |
149 | { |
150 | if (array_key_exists($param->name, $attributes)) |
151 | { |
152 | if (is_string($attributes[$param->name])) |
153 | { |
154 | $value = $attributes[$param->name]; |
155 | $this->type_cast_helper->set_var($value, $attributes[$param->name], 'string', true, false); |
156 | $arguments[] = $value; |
157 | } |
158 | else |
159 | { |
160 | $arguments[] = $attributes[$param->name]; |
161 | } |
162 | } |
163 | else if ($param->getType() && $param->getType() instanceof $request) |
164 | { |
165 | $arguments[] = $request; |
166 | } |
167 | else if ($param->isDefaultValueAvailable()) |
168 | { |
169 | $arguments[] = $param->getDefaultValue(); |
170 | } |
171 | else |
172 | { |
173 | throw new \phpbb\controller\exception('CONTROLLER_ARGUMENT_VALUE_MISSING', array($param->getPosition() + 1, get_class($object) . ':' . $method, $param->name)); |
174 | } |
175 | } |
176 | |
177 | return $arguments; |
178 | } |
179 | } |