Completed
Push — 5.3 ( d18aef...16c32d )
by Jeroen
15:04 queued 08:59
created

Kunstmaan/RedirectBundle/Router/RedirectRouter.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\RedirectBundle\Router;
4
5
use Doctrine\Common\Persistence\ObjectRepository;
6
use Kunstmaan\AdminBundle\Helper\DomainConfigurationInterface;
7
use Kunstmaan\RedirectBundle\Entity\Redirect;
8
use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher;
9
use Symfony\Component\Routing\Exception\RouteNotFoundException;
10
use Symfony\Component\Routing\RequestContext;
11
use Symfony\Component\Routing\Route;
12
use Symfony\Component\Routing\RouteCollection;
13
use Symfony\Component\Routing\RouterInterface;
14
15
class RedirectRouter implements RouterInterface
16
{
17
    /** @var RequestContext */
18
    private $context;
19
20
    /** @var RouteCollection */
21
    private $routeCollection = null;
22
23
    /** @var ObjectRepository */
24
    private $redirectRepository;
25
26
    /** @var DomainConfigurationInterface */
27
    private $domainConfiguration;
28
29
    /**
30
     * @param ObjectRepository             $redirectRepository
31
     * @param DomainConfigurationInterface $domainConfiguration
32
     */
33 5
    public function __construct(ObjectRepository $redirectRepository, DomainConfigurationInterface $domainConfiguration)
34
    {
35 5
        $this->redirectRepository = $redirectRepository;
36 5
        $this->domainConfiguration = $domainConfiguration;
37 5
        $this->context = new RequestContext();
38 5
    }
39
40
    /**
41
     * Generates a URL or path for a specific route based on the given parameters.
42
     *
43
     * Parameters that reference placeholders in the route pattern will substitute them in the
44
     * path or host. Extra params are added as query string to the URL.
45
     *
46
     * When the passed reference type cannot be generated for the route because it requires a different
47
     * host or scheme than the current one, the method will return a more comprehensive reference
48
     * that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
49
     * but the route requires the https scheme whereas the current scheme is http, it will instead return an
50
     * ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
51
     * the route in any case.
52
     *
53
     * If there is no route with the given name, the generator must throw the RouteNotFoundException.
54
     *
55
     * @param string      $name          The name of the route
56
     * @param mixed       $parameters    An array of parameters
57
     * @param bool|string $referenceType The type of reference to be generated (one of the constants)
58
     *
59
     * @return string The generated URL
60
     *
61
     * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException              If the named route doesn't exist
62
     * @throws \Symfony\Component\Routing\Exception\MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
63
     * @throws \Symfony\Component\Routing\Exception\InvalidParameterException           When a parameter value for a placeholder is not correct because
64
     *                                                                                  it does not match the requirement
65
     *
66
     * @api
67
     */
68 1
    public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
69
    {
70 1
        throw new RouteNotFoundException('You cannot generate a url from a redirect');
71
    }
72
73
    /**
74
     * Tries to match a URL path with a set of routes.
75
     *
76
     * If the matcher can not find information, it must throw one of the exceptions documented
77
     * below.
78
     *
79
     * @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
80
     *
81
     * @return array An array of parameters
82
     *
83
     * @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException If the resource could not be found
84
     * @throws \Symfony\Component\Routing\Exception\MethodNotAllowedException If the resource was found but the request method is not allowed
85
     *
86
     * @api
87
     */
88 1
    public function match($pathinfo)
89
    {
90 1
        $urlMatcher = new RedirectableUrlMatcher($this->getRouteCollection(), $this->getContext());
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...\RedirectableUrlMatcher has been deprecated with message: since Symfony 4.3

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
91 1
        $result = $urlMatcher->match($pathinfo);
92
93 1
        return $result;
94
    }
95
96
    /**
97
     * Gets the RouteCollection instance associated with this Router.
98
     *
99
     * @return \Symfony\Component\Routing\RouteCollection A RouteCollection instance
100
     */
101 3
    public function getRouteCollection()
102
    {
103 3
        if (is_null($this->routeCollection)) {
104 3
            $this->routeCollection = new RouteCollection();
105 3
            $this->initRoutes();
106
        }
107
108 3
        return $this->routeCollection;
109
    }
110
111 3
    private function initRoutes()
112
    {
113 3
        $redirects = $this->redirectRepository->findAll();
114 3
        $domain = $this->domainConfiguration->getHost();
115
116
        /** @var Redirect $redirect */
117 3
        foreach ($redirects as $redirect) {
118
            // Check for wildcard routing and adjust as required
119 3
            if ($this->isWildcardRedirect($redirect)) {
120
                $route = $this->createWildcardRoute($redirect);
121
            } else {
122 3
                $route = $this->createRoute($redirect);
123
            }
124
125
            // Only add the route when the domain matches or the domain is empty
126 3
            if ($redirect->getDomain() == $domain || !$redirect->getDomain()) {
127 3
                $this->routeCollection->add(
128 3
                    '_redirect_route_' . $redirect->getId(),
129 3
                    $route
130
                );
131
            }
132
        }
133 3
    }
134
135
    /**
136
     * @param Redirect $redirect
137
     *
138
     * @return bool
139
     */
140 3
    private function isWildcardRedirect(Redirect $redirect)
141
    {
142 3
        $origin = $redirect->getOrigin();
143 3
        $matchSegment = substr($origin, 0, -1);
144 3
        if (substr($origin, -2) == '/*') {
145
            return $this->isPathInfoWildcardMatch($matchSegment);
146
        }
147
148 3
        return false;
149
    }
150
151
    private function isPathInfoWildcardMatch($matchSegment)
152
    {
153
        $path = $this->context->getPathInfo();
154
155
        return strstr($path, $matchSegment);
156
    }
157
158
    /**
159
     * @param Redirect $redirect
160
     *
161
     * @return Route
162
     */
163 3
    private function createRoute(Redirect $redirect)
164
    {
165 3
        $needsUtf8 = preg_match('/[\x80-\xFF]/', $redirect->getTarget());
166
167 3
        return new Route(
168 3
            $redirect->getOrigin(), [
169 3
                '_controller' => 'FrameworkBundle:Redirect:urlRedirect',
170 3
                'path' => $redirect->getTarget(),
171 3
                'permanent' => $redirect->isPermanent(),
172 3
            ], [], ['utf8' => $needsUtf8]);
173
    }
174
175
    /**
176
     * @param Redirect $redirect
177
     *
178
     * @return Route
179
     */
180
    private function createWildcardRoute(Redirect $redirect)
181
    {
182
        $origin = $redirect->getOrigin();
183
        $target = $redirect->getTarget();
184
        $url = $this->context->getPathInfo();
185
        $needsUtf8 = preg_match('/[\x80-\xFF]/', $redirect->getTarget());
186
187
        $origin = substr($origin, 0, -1);
188
        $target = substr($target, 0, -1);
189
        $pathInfo = str_replace($origin, $target, $url);
190
191
        $this->context->setPathInfo($pathInfo);
192
193
        return new Route($url, [
194
            '_controller' => 'FrameworkBundle:Redirect:urlRedirect',
195
            'path' => $url,
196
            'permanent' => $redirect->isPermanent(),
197
        ], [], ['utf8' => $needsUtf8]);
198
    }
199
200
    /**
201
     * Gets the request context.
202
     *
203
     * @return \Symfony\Component\Routing\RequestContext The context
204
     *
205
     * @api
206
     */
207 2
    public function getContext()
208
    {
209 2
        return $this->context;
210
    }
211
212
    /**
213
     * Sets the request context.
214
     *
215
     * @param RequestContext $context The context
216
     *
217
     * @api
218
     */
219 1
    public function setContext(RequestContext $context)
220
    {
221 1
        $this->context = $context;
222 1
    }
223
}
224