cutelyst 5.1.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
action.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "action_p.h"
6#include "common.h"
7#include "context.h"
8#include "controller.h"
9
10using namespace Cutelyst;
11using namespace Qt::Literals::StringLiterals;
12
14 : Component(new ActionPrivate, parent)
15{
16}
17
18Action::Action(ActionPrivate *ptr, QObject *parent)
19 : Component(ptr, parent)
20{
21}
22
23Component::Modifiers Action::modifiers() const
24{
25 return Component::OnlyExecute;
26}
27
28void Action::setMethod(const QMetaMethod &method)
29{
30 Q_D(Action);
31 d->method = method;
32 if (method.returnType() == QMetaType::Bool) {
33 d->evaluateBool = true;
34 }
35
36 if (method.parameterCount() == 2 && method.parameterType(1) == QMetaType::QStringList) {
37 d->listSignature = true;
38 }
39}
40
42{
43 Q_D(Action);
44 d->controller = controller;
45}
46
47void Action::setupAction(const QVariantHash &args, Application *app)
48{
49 Q_D(Action);
50
51 init(app, args);
52
53 d->ns = args.value(u"namespace"_s).toString();
54
55 d->attributes = args.value(u"attributes"_s).value<ParamsMultiMap>();
56
57 const QString argsAttr = d->attributes.value(u"Args"_s);
58 if (!argsAttr.isEmpty()) {
59 d->numberOfArgs = qint8(argsAttr.toInt());
60 }
61
62 const QString capturesAttr = d->attributes.value(u"CaptureArgs"_s);
63 if (!capturesAttr.isEmpty()) {
64 d->numberOfCaptures = qint8(capturesAttr.toInt());
65 }
66}
67
69{
70 Q_D(const Action);
71 return d->attributes;
72}
73
74QString Action::attribute(const QString &name, const QString &defaultValue) const
75{
76 Q_D(const Action);
77 return d->attributes.value(name, defaultValue);
78}
79
81{
82 Q_D(Action);
83 d->attributes = attributes;
84}
85
86QString Action::className() const noexcept
87{
88 Q_D(const Action);
89 return d->controller->objectName();
90}
91
93{
94 Q_D(const Action);
95 return d->controller;
96}
97
98bool Action::match(int numberOfArgs) const noexcept
99{
100 Q_D(const Action);
101 // If the number of args is -1 (not defined)
102 // it will slurp all args so we don't care
103 // about how many args was passed, otherwise
104 // count them
105 return d->numberOfArgs == -1 || d->numberOfArgs == numberOfArgs;
106}
107
108bool Action::matchCaptures(int numberOfCaptures) const noexcept
109{
110 Q_D(const Action);
111 // If the number of capture args is -1 (not defined)
112 // it will slurp all args so we don't care
113 // about how many args was passed, otherwise
114 // count them
115 return d->numberOfCaptures == -1 || d->numberOfCaptures == numberOfCaptures;
116}
117
118QString Action::ns() const noexcept
119{
120 Q_D(const Action);
121 return d->ns;
122}
123
125{
126 Q_D(const Action);
127 return d->numberOfArgs;
128}
129
131{
132 Q_D(const Action);
133 return d->numberOfCaptures;
134}
135
137{
138 Q_D(const Action);
139 if (c->detached()) {
140 return false;
141 }
142
143 bool ret;
144
145 /*
146 * Qt 6.5 introduced a new variadic version of QMetaMethod::invoke() that
147 * does not work with our current implementation above. The following code
148 * is a fast fix to use the new version but there might be better / more elegant
149 * approaches.
150 *
151 * See: https://codereview.qt-project.org/c/qt/qtbase/+/422745
152 *
153 * TODO: check for more flexible implementation
154 */
155
156 const QStringList args = c->request()->args();
157
158 if (d->evaluateBool) {
159 bool methodRet;
160
161 if (d->listSignature) {
162 ret = d->method.invoke(
163 d->controller, Qt::DirectConnection, qReturnArg(methodRet), c, args);
164 } else {
165 switch (d->method.parameterCount()) {
166 case 0:
167 ret = d->method.invoke(d->controller, Qt::DirectConnection, qReturnArg(methodRet));
168 break;
169 case 1:
170 ret =
171 d->method.invoke(d->controller, Qt::DirectConnection, qReturnArg(methodRet), c);
172 break;
173 case 2:
174 ret = d->method.invoke(
175 d->controller, Qt::DirectConnection, qReturnArg(methodRet), c, args.value(0));
176 break;
177 case 3:
178 ret = d->method.invoke(d->controller,
180 qReturnArg(methodRet),
181 c,
182 args.value(0),
183 args.value(1));
184 break;
185 case 4:
186 ret = d->method.invoke(d->controller,
188 qReturnArg(methodRet),
189 c,
190 args.value(0),
191 args.value(1),
192 args.value(2));
193 break;
194 case 5:
195 ret = d->method.invoke(d->controller,
197 qReturnArg(methodRet),
198 c,
199 args.value(0),
200 args.value(1),
201 args.value(2),
202 args.value(3));
203 break;
204 case 6:
205 ret = d->method.invoke(d->controller,
207 qReturnArg(methodRet),
208 c,
209 args.value(0),
210 args.value(1),
211 args.value(2),
212 args.value(3),
213 args.value(4));
214 break;
215 case 7:
216 ret = d->method.invoke(d->controller,
218 qReturnArg(methodRet),
219 c,
220 args.value(0),
221 args.value(1),
222 args.value(2),
223 args.value(3),
224 args.value(4),
225 args.value(5));
226 break;
227 case 8:
228 ret = d->method.invoke(d->controller,
230 qReturnArg(methodRet),
231 c,
232 args.value(0),
233 args.value(1),
234 args.value(2),
235 args.value(3),
236 args.value(4),
237 args.value(5),
238 args.value(6));
239 break;
240 case 9:
241 ret = d->method.invoke(d->controller,
243 qReturnArg(methodRet),
244 c,
245 args.value(0),
246 args.value(1),
247 args.value(2),
248 args.value(3),
249 args.value(4),
250 args.value(5),
251 args.value(6),
252 args.value(7));
253 break;
254 default:
255 ret = d->method.invoke(d->controller,
257 qReturnArg(methodRet),
258 c,
259 args.value(0),
260 args.value(1),
261 args.value(2),
262 args.value(3),
263 args.value(4),
264 args.value(5),
265 args.value(6),
266 args.value(7),
267 args.value(8));
268 break;
269 }
270 }
271
272 if (ret) {
273 c->setState(methodRet);
274 return methodRet;
275 }
276
277 // The method failed to be called which means we should detach
278 c->detach();
279 c->setState(false);
280
281 return false;
282 } else {
283 if (d->listSignature) {
284 ret = d->method.invoke(d->controller, Qt::DirectConnection, c, args);
285 } else {
286 switch (d->method.parameterCount()) {
287 case 0:
288 ret = d->method.invoke(d->controller, Qt::DirectConnection);
289 break;
290 case 1:
291 ret = d->method.invoke(d->controller, Qt::DirectConnection, c);
292 break;
293 case 2:
294 ret = d->method.invoke(d->controller, Qt::DirectConnection, c, args.value(0));
295 break;
296 case 3:
297 ret = d->method.invoke(
298 d->controller, Qt::DirectConnection, c, args.value(0), args.value(1));
299 break;
300 case 4:
301 ret = d->method.invoke(d->controller,
303 c,
304 args.value(0),
305 args.value(1),
306 args.value(2));
307 break;
308 case 5:
309 ret = d->method.invoke(d->controller,
311 c,
312 args.value(0),
313 args.value(1),
314 args.value(2),
315 args.value(3));
316 break;
317 case 6:
318 ret = d->method.invoke(d->controller,
320 c,
321 args.value(0),
322 args.value(1),
323 args.value(2),
324 args.value(3),
325 args.value(4));
326 break;
327 case 7:
328 ret = d->method.invoke(d->controller,
330 c,
331 args.value(0),
332 args.value(1),
333 args.value(2),
334 args.value(3),
335 args.value(4),
336 args.value(5));
337 break;
338 case 8:
339 ret = d->method.invoke(d->controller,
341 c,
342 args.value(0),
343 args.value(1),
344 args.value(2),
345 args.value(3),
346 args.value(4),
347 args.value(5),
348 args.value(6));
349 break;
350 case 9:
351 ret = d->method.invoke(d->controller,
353 c,
354 args.value(0),
355 args.value(1),
356 args.value(2),
357 args.value(3),
358 args.value(4),
359 args.value(5),
360 args.value(6),
361 args.value(7));
362 break;
363 default:
364 ret = d->method.invoke(d->controller,
366 c,
367 args.value(0),
368 args.value(1),
369 args.value(2),
370 args.value(3),
371 args.value(4),
372 args.value(5),
373 args.value(6),
374 args.value(7),
375 args.value(8));
376 break;
377 }
378 }
379 c->setState(ret);
380 return ret;
381 }
382}
383
384#include "moc_action.cpp"
This class represents a Cutelyst Action.
Definition action.h:35
void setAttributes(const ParamsMultiMap &attributes)
Definition action.cpp:80
void setupAction(const QVariantHash &args, Application *app)
Definition action.cpp:47
QString ns() const noexcept
Definition action.cpp:118
virtual qint8 numberOfArgs() const
Definition action.cpp:124
bool doExecute(Context *c) override
Definition action.cpp:136
virtual bool match(int numberOfArgs) const noexcept
Definition action.cpp:98
void setMethod(const QMetaMethod &method)
Definition action.cpp:28
QString className() const noexcept
Definition action.cpp:86
Action(QObject *parent=nullptr)
Definition action.cpp:13
virtual qint8 numberOfCaptures() const
Definition action.cpp:130
virtual Modifiers modifiers() const override
Definition action.cpp:23
virtual bool matchCaptures(int numberOfCaptures) const noexcept
Definition action.cpp:108
ParamsMultiMap attributes() const noexcept
Definition action.cpp:68
Controller * controller() const noexcept
Definition action.cpp:92
void setController(Controller *controller)
Definition action.cpp:41
QString attribute(const QString &name, const QString &defaultValue={}) const
Definition action.cpp:74
The Cutelyst application.
Definition application.h:66
The Cutelyst Component base class.
Definition component.h:30
virtual bool init(Application *application, const QVariantHash &args)
Definition component.cpp:57
QString name() const noexcept
Definition component.cpp:33
The Cutelyst Context.
Definition context.h:42
void detach(Action *action=nullptr)
Definition context.cpp:338
void setState(bool state) noexcept
Definition context.cpp:80
Request * request
Definition context.h:71
bool detached() const noexcept
Definition context.cpp:332
Cutelyst Controller base class.
Definition controller.h:56
The Cutelyst namespace holds all public Cutelyst API.
T value(qsizetype i) const const
int parameterCount() const const
int parameterType(int index) const const
int returnType() const const
bool isEmpty() const const
int toInt(bool *ok, int base) const const
DirectConnection