-
-
Notifications
You must be signed in to change notification settings - Fork 116
Expand file tree
/
Copy pathLinkGenerator.php
More file actions
109 lines (88 loc) · 2.84 KB
/
LinkGenerator.php
File metadata and controls
109 lines (88 loc) · 2.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Application;
use Nette;
use Nette\Http\UrlScript;
use Nette\Routing\Router;
/**
* Link generator.
*/
final class LinkGenerator
{
use Nette\SmartObject;
/** @var Router */
private $router;
/** @var UrlScript */
private $refUrl;
/** @var IPresenterFactory|null */
private $presenterFactory;
public function __construct(Router $router, UrlScript $refUrl, IPresenterFactory $presenterFactory = null)
{
$this->router = $router;
$this->refUrl = $refUrl;
$this->presenterFactory = $presenterFactory;
}
/**
* Generates URL to presenter.
* @param string $dest in format "[[[module:]presenter:]action] [#fragment]"
* @throws UI\InvalidLinkException
*/
public function link(string $dest, array $params = []): string
{
if (!preg_match('~^([\w:]+):(\w*+)(#.*)?()$~D', $dest, $m)) {
throw new UI\InvalidLinkException("Invalid link destination '$dest'.");
}
[, $presenter, $action, $frag] = $m;
if ($presenter[0] === ':') { // absolute
$presenter = substr($presenter, 1);
if (!$presenter) {
throw new UI\InvalidLinkException("Missing presenter name in '$dest'.");
}
}
try {
$class = $this->presenterFactory ? $this->presenterFactory->getPresenterClass($presenter) : null;
} catch (InvalidPresenterException $e) {
throw new UI\InvalidLinkException($e->getMessage(), 0, $e);
}
if (is_subclass_of($class, UI\Presenter::class)) {
if ($action === '') {
$action = UI\Presenter::DEFAULT_ACTION;
}
if (
method_exists($class, $method = $class::formatActionMethod($action))
|| method_exists($class, $method = $class::formatRenderMethod($action))
) {
UI\Presenter::argsToParams($class, $method, $params, [], $missing);
if ($missing) {
$rp = $missing[0];
throw new UI\InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()");
}
} elseif (array_key_exists(0, $params)) {
throw new UI\InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method.");
}
}
if ($action !== '') {
$params[UI\Presenter::ACTION_KEY] = $action;
}
$params[UI\Presenter::PRESENTER_KEY] = $presenter;
$url = $this->router->constructUrl($params, $this->refUrl);
if ($url === null) {
unset($params[UI\Presenter::ACTION_KEY], $params[UI\Presenter::PRESENTER_KEY]);
$params = urldecode(http_build_query($params, '', ', '));
throw new UI\InvalidLinkException("No route for $dest($params)");
}
return $url . $frag;
}
public function withReferenceUrl(string $url): self
{
return new self(
$this->router,
new UrlScript($url),
$this->presenterFactory
);
}
}