-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrouting.html
More file actions
201 lines (192 loc) · 9.35 KB
/
routing.html
File metadata and controls
201 lines (192 loc) · 9.35 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<html>
<head>
<title>Routing</title>
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<header>
<div class="container">
<div class="row">
<div class="prev col-md-3">
<label for="">Prev</label>
<a href="/domain.html">Domain Design</a> </div>
<div class="current col-md-6">
<h3 class="title">
3. Routing </h3>
<small class="parent">Radar for PHP</small>
</div>
<div class="next col-md-3">
<label for="">Next</label>
<a href="/middleware.html">Middleware</a> </div>
<div class="clearfix"></div>
</div>
</div>
</header>
<section id="content">
<div class="container">
<div class="row">
<div class="col-md-12">
<h1 id="3">3. Routing</h1>
<p>Before continuing, remove the default <code>Hello</code> route from the <code>web/index.php</code>
file. It looks like this:</p>
<pre><code class="language-php">$adr->get('Hello', '/{name}?', function (array $input) {
$payload = new \Aura\Payload\Payload();
return $payload
->setStatus($payload::SUCCESS)
->setOutput([
'phrase' => 'Hello ' . $input['name']
]);
})
->defaults(['name' => 'world']);
</code></pre>
<p>That will prepare your project for real use.</p>
<h2 id="3-1">3.1. Adding A Route</h2>
<p>The Radar routing system is based on
<a href="https://github.com/auraphp/Aura.Router">Aura.Router</a>, with some details
modified specifically for Radar.</p>
<p>In other frameworks, a route points an incoming request to a particular
controller class and action method. In Radar, every action is identical, in the
sense that it receives input, invokes a domain element, and passes the domain
output to a responder. This means that a Radar route does not point to an action
per se, but to a trio of action-related elements: an input handler, a domain
element, and a responder.</p>
<p>Let's add an HTTP PATCH route. In <code>web/index.php</code>, call <code>$adr->patch()</code> with a
route name and URL path, and a <em>Domain</em> specification.</p>
<pre><code class="language-php">$adr->patch('Todo\EditItem', '/todo/{id}', 'Domain\Todo\ApplicationService\EditItem');
</code></pre>
<p>The route name doubles as a class name prefix for optional <em>Input</em> and
<em>Responder</em> classes. We will talk more about that later.</p>
<p>The path is typical for routing systems, using placeholder tokens for route
attribute values.</p>
<p>The <em>Domain</em> specification is a string or an array:</p>
<ul>
<li>
<p>If a string, Radar will instantiate this class using the internal dependency
injection container and call its <code>__invoke()</code> method with the user input from
the HTTP request.</p>
</li>
<li>
<p>If an array in the format <code>['ClassName', 'method']</code>, the dependency injection
container will instantiate the specfied class name, and then call the specified
method with the user input from the HTTP request.</p>
</li>
</ul>
<h2 id="3-2">3.2. Manually Specifying A Custom Input Class</h2>
<p>By default, each Radar route uses the <em>Radar\Adr\Input</em> class to collect user
input and use it for parameters to the <em>Domain</em> call. Essentially, the input-collection
logic looks like this:</p>
<pre><code class="language-php"> public function __invoke(ServerRequestInterface $request)
{
return [
array_merge(
(array) $request->getQueryParams(),
(array) $request->getAttributes(),
(array) $request->getParsedBody(),
(array) $request->getUploadedFiles()
)
];
}
</code></pre>
<p>This means the <em>Domain</em> element has to receive a single <code>$input</code> array as its
only parameter. The <code>$input</code> is merged from a list of sources, with later
sources overriding earlier ones. This is naive but useful as a default case.</p>
<p>For more serious and useful input collection,
you can write a callable class that mimics the above <code>__invoke()</code> signature, and have it
return the parameters to pass to the <em>Domain</em> element. For example, if your
<em>Domain</em> call takes an <code>$id</code> and a <code>$data</code> array as its parameters, you might do this:</p>
<pre><code class="language-php">use Psr\Http\Message\ServerRequestInterface;
class GenericIdAndDataInput
{
public function __invoke(ServerRequestInterface $request)
{
$id = $request->getAttribute('id');
$data = $request->getParsedBody();
return [$id, $data];
}
}
</code></pre>
<p>You can then specify this class as the input callable to be used for your route
by calling <code>input()</code> on the route object:</p>
<pre><code class="language-php">$adr->patch('Todo\EditItem', '/todo/{id}', 'Domain\Todo\ApplicationService\EditItem')
->input('GenericIdAndDataInput');
</code></pre>
<p>If you want to set your own default input class instead of the Radar one,
call <code>$adr->input()</code> directly instead of as part of a route specification:</p>
<pre><code class="language-php">$adr->input('MyDefaultInputClass');
</code></pre>
<p>That class will be used as the default input callable for all route actions.</p>
<h2 id="3-3">3.3. Manually Specifying A Custom Responder Class</h2>
<p>By default, each Radar route uses the <em>Radar\Adr\Responder\Responder</em> class to
build the HTTP response. Because presentation work is so dependent on the
domain elements being presented, it is difficult to outline how Responders work
in detail; please examine the <em>Responder</em> class to get a good handle on what's
going on there.</p>
<p>In the mean time, let it suffice to say that you are almost certain to want to
build your own <em>Responder</em> classes, and then specify them as the responder callable
for one or more of your routes. To
do so, call <code>responder()</code> on the route, and pass the responder class name:</p>
<pre><code class="language-php">$adr->patch('Todo\EditItem', '/todo/{id}', 'Domain\Todo\ApplicationService\EditItem')
->responder('MyTodoResponder');
</code></pre>
<p>If you want to set your own default responder class instead of the Radar one,
call <code>$adr->responder()</code> directly instead of as part of a route specification:</p>
<pre><code class="language-php">$adr->responder('MyDefaultResponderClass');
</code></pre>
<blockquote>
<p>N.b.: As a side note, if your responder class implements
<em>Radar\Adr\Responder\ResponderAcceptsInterface</em>, the route will automatically
apply an <code>accepts()</code> pre-filter to help with content negotiation. This is not
content-negotiation proper, only a filter to make sure the responder can handle
at least one of the content types acceptable by the client.</p>
</blockquote>
<h2 id="3-4">3.4. Automatic Input And Responder Discovery</h2>
<p>Earlier, we noted that the route name doubles as a class name prefix for
optional <em>Input</em> and <em>Responder</em> classes. This means that if you name your
classes according to a Radar convention, the route will automatically pick up on
those classes and use them for <code>input()</code> and <code>responder()</code> on the route.</p>
<p>For example, given a route named <code>Todo\EditItem</code>, you could create a
<code>Todo\EditItem\Input</code> class and/or a <code>Todo\EditItem\Responder</code> class. If they
exist, the route will use them automatically. Of course, you can still manually
specify an <code>input()</code> and <code>responder()</code> value, and those will be used instead.</p>
<h2 id="3-5">3.5. Other Route Specifications</h2>
<p>The <code>$adr</code> object acts as a proxy for the underlying <em>Aura\Router\Map</em> instance,
so all the <em>Map</em> methods are also available on the <code>$adr</code> object for defining
your routes. Please see the Aura.Router
<a href="https://github.com/auraphp/Aura.Router/blob/3.x/docs/index.md">Map</a>
documentation for more information.</p>
</div>
</div>
</div>
</section>
<footer>
<section id="links">
<div class="container">
<div class="row">
<div class="prev col-md-3">
<label for="">Prev</label>
<a href="/domain.html">2. Domain Design</a> </div>
<div class="parent col-md-6">
<label for="">Up</label>
<a href="/">Radar for PHP</a> </div>
<div class="next col-md-3">
<label for="">Next</label>
<a href="/middleware.html">4. Middleware</a> </div>
<div class="clearfix"></div>
</div>
</div>
</section>
<section id="copyright">
<div class="container">
<div class="row">
<div class="col-md-12">
<span>
Powered by <a href="">Bookdown.io</a> | Designed by <a href="">yuripertamax</a>
</span>
</div>
</div>
</div>
</section>
</footer>
</body>
</html>