Commit | Line | Data |
---|---|---|
44d399bc S |
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\Router\Http; | |
11 | ||
12 | use ArrayObject; | |
13 | use Traversable; | |
14 | use Zend\Mvc\Router\Exception; | |
15 | use Zend\Mvc\Router\PriorityList; | |
16 | use Zend\Mvc\Router\RoutePluginManager; | |
17 | use Zend\Stdlib\ArrayUtils; | |
18 | use Zend\Stdlib\RequestInterface as Request; | |
19 | ||
20 | /** | |
21 | * Chain route. | |
22 | */ | |
23 | class Chain extends TreeRouteStack implements RouteInterface | |
24 | { | |
25 | /** | |
26 | * Chain routes. | |
27 | * | |
28 | * @var array | |
29 | */ | |
30 | protected $chainRoutes; | |
31 | ||
32 | /** | |
33 | * List of assembled parameters. | |
34 | * | |
35 | * @var array | |
36 | */ | |
37 | protected $assembledParams = []; | |
38 | ||
39 | /** | |
40 | * Create a new part route. | |
41 | * | |
42 | * @param array $routes | |
43 | * @param RoutePluginManager $routePlugins | |
44 | * @param ArrayObject|null $prototypes | |
45 | */ | |
46 | public function __construct(array $routes, RoutePluginManager $routePlugins, ArrayObject $prototypes = null) | |
47 | { | |
48 | $this->chainRoutes = array_reverse($routes); | |
49 | $this->routePluginManager = $routePlugins; | |
50 | $this->routes = new PriorityList(); | |
51 | $this->prototypes = $prototypes; | |
52 | } | |
53 | ||
54 | /** | |
55 | * factory(): defined by RouteInterface interface. | |
56 | * | |
57 | * @see \Zend\Mvc\Router\RouteInterface::factory() | |
58 | * @param mixed $options | |
59 | * @throws Exception\InvalidArgumentException | |
60 | * @return Part | |
61 | */ | |
62 | public static function factory($options = []) | |
63 | { | |
64 | if ($options instanceof Traversable) { | |
65 | $options = ArrayUtils::iteratorToArray($options); | |
66 | } elseif (!is_array($options)) { | |
67 | throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options'); | |
68 | } | |
69 | ||
70 | if (!isset($options['routes'])) { | |
71 | throw new Exception\InvalidArgumentException('Missing "routes" in options array'); | |
72 | } | |
73 | ||
74 | if (!isset($options['prototypes'])) { | |
75 | $options['prototypes'] = null; | |
76 | } | |
77 | ||
78 | if ($options['routes'] instanceof Traversable) { | |
79 | $options['routes'] = ArrayUtils::iteratorToArray($options['child_routes']); | |
80 | } | |
81 | ||
82 | if (!isset($options['route_plugins'])) { | |
83 | throw new Exception\InvalidArgumentException('Missing "route_plugins" in options array'); | |
84 | } | |
85 | ||
86 | return new static( | |
87 | $options['routes'], | |
88 | $options['route_plugins'], | |
89 | $options['prototypes'] | |
90 | ); | |
91 | } | |
92 | ||
93 | /** | |
94 | * match(): defined by RouteInterface interface. | |
95 | * | |
96 | * @see \Zend\Mvc\Router\RouteInterface::match() | |
97 | * @param Request $request | |
98 | * @param int|null $pathOffset | |
99 | * @param array $options | |
100 | * @return RouteMatch|null | |
101 | */ | |
102 | public function match(Request $request, $pathOffset = null, array $options = []) | |
103 | { | |
104 | if (!method_exists($request, 'getUri')) { | |
105 | return; | |
106 | } | |
107 | ||
108 | if ($pathOffset === null) { | |
109 | $mustTerminate = true; | |
110 | $pathOffset = 0; | |
111 | } else { | |
112 | $mustTerminate = false; | |
113 | } | |
114 | ||
115 | if ($this->chainRoutes !== null) { | |
116 | $this->addRoutes($this->chainRoutes); | |
117 | $this->chainRoutes = null; | |
118 | } | |
119 | ||
120 | $match = new RouteMatch([]); | |
121 | $uri = $request->getUri(); | |
122 | $pathLength = strlen($uri->getPath()); | |
123 | ||
124 | foreach ($this->routes as $route) { | |
125 | $subMatch = $route->match($request, $pathOffset, $options); | |
126 | ||
127 | if ($subMatch === null) { | |
128 | return; | |
129 | } | |
130 | ||
131 | $match->merge($subMatch); | |
132 | $pathOffset += $subMatch->getLength(); | |
133 | } | |
134 | ||
135 | if ($mustTerminate && $pathOffset !== $pathLength) { | |
136 | return; | |
137 | } | |
138 | ||
139 | return $match; | |
140 | } | |
141 | ||
142 | /** | |
143 | * assemble(): Defined by RouteInterface interface. | |
144 | * | |
145 | * @see \Zend\Mvc\Router\RouteInterface::assemble() | |
146 | * @param array $params | |
147 | * @param array $options | |
148 | * @return mixed | |
149 | */ | |
150 | public function assemble(array $params = [], array $options = []) | |
151 | { | |
152 | if ($this->chainRoutes !== null) { | |
153 | $this->addRoutes($this->chainRoutes); | |
154 | $this->chainRoutes = null; | |
155 | } | |
156 | ||
157 | $this->assembledParams = []; | |
158 | ||
159 | $routes = ArrayUtils::iteratorToArray($this->routes); | |
160 | ||
161 | end($routes); | |
162 | $lastRouteKey = key($routes); | |
163 | $path = ''; | |
164 | ||
165 | foreach ($routes as $key => $route) { | |
166 | $chainOptions = $options; | |
167 | $hasChild = isset($options['has_child']) ? $options['has_child'] : false; | |
168 | ||
169 | $chainOptions['has_child'] = ($hasChild || $key !== $lastRouteKey); | |
170 | ||
171 | $path .= $route->assemble($params, $chainOptions); | |
172 | $params = array_diff_key($params, array_flip($route->getAssembledParams())); | |
173 | ||
174 | $this->assembledParams += $route->getAssembledParams(); | |
175 | } | |
176 | ||
177 | return $path; | |
178 | } | |
179 | ||
180 | /** | |
181 | * getAssembledParams(): defined by RouteInterface interface. | |
182 | * | |
183 | * @see RouteInterface::getAssembledParams | |
184 | * @return array | |
185 | */ | |
186 | public function getAssembledParams() | |
187 | { | |
188 | return $this->assembledParams; | |
189 | } | |
190 | } |