use zend router
[GitHub/Stricted/Domain-Control-Panel.git] / vendor / Zend / Mvc / View / Http / InjectTemplateListener.php
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10 namespace Zend\Mvc\View\Http;
11
12 use Zend\EventManager\AbstractListenerAggregate;
13 use Zend\EventManager\EventManagerInterface as Events;
14 use Zend\Filter\Word\CamelCaseToDash as CamelCaseToDashFilter;
15 use Zend\Mvc\MvcEvent;
16 use Zend\Mvc\ModuleRouteListener;
17 use Zend\View\Model\ModelInterface as ViewModel;
18
19 class InjectTemplateListener extends AbstractListenerAggregate
20 {
21 /**
22 * FilterInterface/inflector used to normalize names for use as template identifiers
23 *
24 * @var mixed
25 */
26 protected $inflector;
27
28 /**
29 * Array of controller namespace -> template mappings
30 *
31 * @var array
32 */
33 protected $controllerMap = [];
34
35 /**
36 * Flag to force the use of the route match controller param
37 *
38 * @var boolean
39 */
40 protected $preferRouteMatchController = false;
41
42 /**
43 * {@inheritDoc}
44 */
45 public function attach(Events $events, $priority = 1)
46 {
47 $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'injectTemplate'], -90);
48 }
49
50 /**
51 * Inject a template into the view model, if none present
52 *
53 * Template is derived from the controller found in the route match, and,
54 * optionally, the action, if present.
55 *
56 * @param MvcEvent $e
57 * @return void
58 */
59 public function injectTemplate(MvcEvent $e)
60 {
61 $model = $e->getResult();
62 if (!$model instanceof ViewModel) {
63 return;
64 }
65
66 $template = $model->getTemplate();
67 if (!empty($template)) {
68 return;
69 }
70
71 $routeMatch = $e->getRouteMatch();
72 $controller = $e->getTarget();
73 if (is_object($controller)) {
74 $controller = get_class($controller);
75 }
76
77 $routeMatchController = $routeMatch->getParam('controller', '');
78 if (!$controller || ($this->preferRouteMatchController && $routeMatchController)) {
79 $controller = $routeMatchController;
80 }
81
82 $template = $this->mapController($controller);
83 if (!$template) {
84 $module = $this->deriveModuleNamespace($controller);
85
86 if ($namespace = $routeMatch->getParam(ModuleRouteListener::MODULE_NAMESPACE)) {
87 $controllerSubNs = $this->deriveControllerSubNamespace($namespace);
88 if (!empty($controllerSubNs)) {
89 if (!empty($module)) {
90 $module .= '/' . $controllerSubNs;
91 } else {
92 $module = $controllerSubNs;
93 }
94 }
95 }
96
97 $controller = $this->deriveControllerClass($controller);
98 $template = $this->inflectName($module);
99
100 if (!empty($template)) {
101 $template .= '/';
102 }
103 $template .= $this->inflectName($controller);
104 }
105
106 $action = $routeMatch->getParam('action');
107 if (null !== $action) {
108 $template .= '/' . $this->inflectName($action);
109 }
110 $model->setTemplate($template);
111 }
112
113 /**
114 * Set map of controller namespace -> template pairs
115 *
116 * @param array $map
117 * @return self
118 */
119 public function setControllerMap(array $map)
120 {
121 krsort($map);
122 $this->controllerMap = $map;
123 return $this;
124 }
125
126 /**
127 * Maps controller to template if controller namespace is whitelisted or mapped
128 *
129 * @param string $controller controller FQCN
130 * @return string|false template name or false if controller was not matched
131 */
132 public function mapController($controller)
133 {
134 if (! is_string($controller)) {
135 return false;
136 }
137
138 foreach ($this->controllerMap as $namespace => $replacement) {
139 if (// Allow disabling rule by setting value to false since config
140 // merging have no feature to remove entries
141 false == $replacement
142 // Match full class or full namespace
143 || !($controller === $namespace || strpos($controller, $namespace . '\\') === 0)
144 ) {
145 continue;
146 }
147
148 $map = '';
149 // Map namespace to $replacement if its value is string
150 if (is_string($replacement)) {
151 $map = rtrim($replacement, '/') . '/';
152 $controller = substr($controller, strlen($namespace) + 1) ?: '';
153 }
154
155 //strip Controller namespace(s) (but not classname)
156 $parts = explode('\\', $controller);
157 array_pop($parts);
158 $parts = array_diff($parts, ['Controller']);
159 //strip trailing Controller in class name
160 $parts[] = $this->deriveControllerClass($controller);
161 $controller = implode('/', $parts);
162
163 $template = trim($map . $controller, '/');
164
165 //inflect CamelCase to dash
166 return $this->inflectName($template);
167 }
168 return false;
169 }
170
171 /**
172 * Inflect a name to a normalized value
173 *
174 * @param string $name
175 * @return string
176 */
177 protected function inflectName($name)
178 {
179 if (!$this->inflector) {
180 $this->inflector = new CamelCaseToDashFilter();
181 }
182 $name = $this->inflector->filter($name);
183 return strtolower($name);
184 }
185
186 /**
187 * Determine the top-level namespace of the controller
188 *
189 * @param string $controller
190 * @return string
191 */
192 protected function deriveModuleNamespace($controller)
193 {
194 if (!strstr($controller, '\\')) {
195 return '';
196 }
197 $module = substr($controller, 0, strpos($controller, '\\'));
198 return $module;
199 }
200
201 /**
202 * @param $namespace
203 * @return string
204 */
205 protected function deriveControllerSubNamespace($namespace)
206 {
207 if (!strstr($namespace, '\\')) {
208 return '';
209 }
210 $nsArray = explode('\\', $namespace);
211
212 // Remove the first two elements representing the module and controller directory.
213 $subNsArray = array_slice($nsArray, 2);
214 if (empty($subNsArray)) {
215 return '';
216 }
217 return implode('/', $subNsArray);
218 }
219
220 /**
221 * Determine the name of the controller
222 *
223 * Strip the namespace, and the suffix "Controller" if present.
224 *
225 * @param string $controller
226 * @return string
227 */
228 protected function deriveControllerClass($controller)
229 {
230 if (strstr($controller, '\\')) {
231 $controller = substr($controller, strrpos($controller, '\\') + 1);
232 }
233
234 if ((10 < strlen($controller))
235 && ('Controller' == substr($controller, -10))
236 ) {
237 $controller = substr($controller, 0, -10);
238 }
239
240 return $controller;
241 }
242
243 /**
244 * Sets the flag to instruct the listener to prefer the route match controller param
245 * over the class name
246 *
247 * @param boolean $preferRouteMatchController
248 */
249 public function setPreferRouteMatchController($preferRouteMatchController)
250 {
251 $this->preferRouteMatchController = (bool) $preferRouteMatchController;
252 }
253
254 /**
255 * @return boolean
256 */
257 public function isPreferRouteMatchController()
258 {
259 return $this->preferRouteMatchController;
260 }
261 }