Completed
Push — master ( 00dad4...34b351 )
by Aimeos
05:36
created

Router::process()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 27
Code Lines 14

Duplication

Lines 3
Ratio 11.11 %

Importance

Changes 0
Metric Value
dl 3
loc 27
rs 8.439
c 0
b 0
f 0
cc 6
eloc 14
nc 12
nop 2
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2016
6
 * @package Slim
7
 */
8
9
10
namespace Aimeos\Slim;
11
12
use InvalidArgumentException;
13
14
15
/**
16
 * Router
17
 *
18
 * This class organizes Slim application route objects. It is responsible
19
 * for registering route objects, assigning names to route objects,
20
 * finding routes that match the current HTTP request, and creating
21
 * URLs for a named route.
22
 */
23
class Router extends \Slim\Router
24
{
25
	/**
26
	 * Build the path for a named route excluding the base path
27
	 *
28
	 * @param string $name		Route name
29
	 * @param array  $data		Named argument replacement data
30
	 * @param array  $queryParams Optional query string parameters
31
	 *
32
	 * @return string
33
	 *
34
	 * @throws RuntimeException		 If named route does not exist
35
	 * @throws InvalidArgumentException If required data not provided
36
	 */
37
	public function relativePathFor($name, array $data = [], array $queryParams = [])
38
	{
39
		$route = $this->getNamedRoute($name);
40
		$pattern = $route->getPattern();
41
42
		$routeDatas = $this->routeParser->parse($pattern);
43
		// $routeDatas is an array of all possible routes that can be made. There is
44
		// one routedata for each optional parameter plus one for no optional parameters.
45
		//
46
		// The most specific is last, so we look for that first.
47
		$routeDatas = array_reverse($routeDatas);
48
49
		$segments = $segmentKeys = [];
50
		foreach ($routeDatas as $routeData) {
51
			foreach ($routeData as $item) {
52
				if (is_string($item)) {
53
					// this segment is a static string
54
					$segments[] = $item;
55
					continue;
56
				}
57
58
				// This segment has a parameter: first element is the name
59
				if (!array_key_exists($item[0], $data)) {
60
					// we don't have a data element for this segment: cancel
61
					// testing this routeData item, so that we can try a less
62
					// specific routeData item.
63
					$segments = [];
64
					$segmentName = $item[0];
65
					break;
66
				}
67
				$segments[] = $data[$item[0]];
68
				$segmentKeys[$item[0]] = true;
69
			}
70
			if (!empty($segments)) {
71
				// we found all the parameters for this route data, no need to check
72
				// less specific ones
73
				break;
74
			}
75
		}
76
77
		if (empty($segments)) {
78
			throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
79
		}
80
		$url = implode('', $segments);
81
82
		$params = array_merge(array_diff_key($data, $segmentKeys), $queryParams);
83
		if ($params) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
84
			$url .= '?' . http_build_query($params);
85
		}
86
87
		return $url;
88
	}
89
90
    /**
91
     * Pull route info for a request with a bad method to decide whether to
92
     * return a not-found error (default) or a bad-method error, then run
93
     * the handler for that error, returning the resulting response.
94
     *
95
     * Used for cases where an incoming request has an unrecognized method,
96
     * rather than throwing an exception and not catching it all the way up.
97
     *
98
     * @param ServerRequestInterface $request
99
     * @param ResponseInterface $response
100
     * @return ResponseInterface
101
     */
102
    protected function processInvalidMethod(ServerRequestInterface $request, ResponseInterface $response)
103
    {
104
        $router = $this->container->get('router');
105 View Code Duplication
        if (is_callable([$request->getUri(), 'getBaseUrl']) && is_callable([$router, 'getBaseUrl'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
            $router->setBasePath($request->getUri()->getBaseUrl());
107
        }
108
109
        $request = $this->dispatchRouterAndPrepareRoute($request, $router);
0 ignored issues
show
Bug introduced by
The method dispatchRouterAndPrepareRoute() does not exist on Aimeos\Slim\Router. Did you maybe mean dispatch()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
110
        $routeInfo = $request->getAttribute('routeInfo', [RouterInterface::DISPATCH_STATUS => Dispatcher::NOT_FOUND]);
111
112
        if ($routeInfo[RouterInterface::DISPATCH_STATUS] === Dispatcher::METHOD_NOT_ALLOWED) {
113
            return $this->handleException(
0 ignored issues
show
Bug introduced by
The method handleException() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
114
                new MethodNotAllowedException($request, $response, $routeInfo[RouterInterface::ALLOWED_METHODS]),
115
                $request,
116
                $response
117
            );
118
        }
119
120
        return $this->handleException(new NotFoundException($request, $response), $request, $response);
0 ignored issues
show
Bug introduced by
The method handleException() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
121
    }
122
123
    /**
124
     * Process a request
125
     *
126
     * This method traverses the application middleware stack and then returns the
127
     * resultant Response object.
128
     *
129
     * @param ServerRequestInterface $request
130
     * @param ResponseInterface $response
131
     * @return ResponseInterface
132
     *
133
     * @throws Exception
134
     * @throws MethodNotAllowedException
135
     * @throws NotFoundException
136
     */
137
    public function process(ServerRequestInterface $request, ResponseInterface $response)
138
    {
139
        // Ensure basePath is set
140
        $router = $this->container->get('router');
141 View Code Duplication
        if (is_callable([$request->getUri(), 'getBaseUrl']) && is_callable([$router, 'getBaseUrl'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
            $router->setBasePath($request->getUri()->getBaseUrl());
143
        }
144
145
        // Dispatch the Router first if the setting for this is on
146
        if ($this->container->get('settings')['determineRouteBeforeAppMiddleware'] === true) {
147
            // Dispatch router (note: you won't be able to alter routes after this)
148
            $request = $this->dispatchRouterAndPrepareRoute($request, $router);
0 ignored issues
show
Bug introduced by
The method dispatchRouterAndPrepareRoute() does not exist on Aimeos\Slim\Router. Did you maybe mean dispatch()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
149
        }
150
151
        // Traverse middleware stack
152
        try {
153
            $response = $this->callMiddlewareStack($request, $response);
0 ignored issues
show
Bug introduced by
The method callMiddlewareStack() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
154
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aimeos\Slim\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
155
            $response = $this->handleException($e, $request, $response);
0 ignored issues
show
Bug introduced by
The method handleException() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
156
        } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Aimeos\Slim\Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
157
            $response = $this->handlePhpError($e, $request, $response);
0 ignored issues
show
Bug introduced by
The method handlePhpError() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
158
        }
159
160
        $response = $this->finalize($response);
0 ignored issues
show
Bug introduced by
The method finalize() does not seem to exist on object<Aimeos\Slim\Router>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
162
        return $response;
163
    }
164
}
165