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 
10 using namespace Cutelyst;
11 using namespace Qt::Literals::StringLiterals;
12 
14  : Component(new ActionPrivate, parent)
15 {
16 }
17 
18 Action::Action(ActionPrivate *ptr, QObject *parent)
19  : Component(ptr, parent)
20 {
21 }
22 
23 Component::Modifiers Action::modifiers() const
24 {
25  return Component::OnlyExecute;
26 }
27 
28 void 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 
47 void 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 
74 QString Action::attribute(const QString &name, const QString &defaultValue) const
75 {
76  Q_D(const Action);
77  return d->attributes.value(name, defaultValue);
78 }
79 
80 void Action::setAttributes(const ParamsMultiMap &attributes)
81 {
82  Q_D(Action);
83  d->attributes = attributes;
84 }
85 
86 QString Action::className() const noexcept
87 {
88  Q_D(const Action);
89  return d->controller->objectName();
90 }
91 
92 Controller *Action::controller() const noexcept
93 {
94  Q_D(const Action);
95  return d->controller;
96 }
97 
98 bool 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 
108 bool 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 
118 QString Action::ns() const noexcept
119 {
120  Q_D(const Action);
121  return d->ns;
122 }
123 
124 qint8 Action::numberOfArgs() const
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"
Controller * controller() const noexcept
Definition: action.cpp:92
ParamsMultiMap attributes() const noexcept
Definition: action.cpp:68
Request request
Definition: context.h:72
bool doExecute(Context *c) override
Definition: action.cpp:136
virtual qint8 numberOfCaptures() const
Definition: action.cpp:130
void detach(Action *action=nullptr)
Definition: context.cpp:338
The Cutelyst Component base class.
Definition: component.h:30
virtual bool matchCaptures(int numberOfCaptures) const noexcept
Definition: action.cpp:108
This class represents a Cutelyst Action.
Definition: action.h:34
T value(qsizetype i) const const
The Cutelyst Context.
Definition: context.h:42
Cutelyst Controller base class.
Definition: controller.h:55
bool detached() const noexcept
Definition: context.cpp:332
void setAttributes(const ParamsMultiMap &attributes)
Definition: action.cpp:80
int toInt(bool *ok, int base) const const
bool isEmpty() const const
int parameterCount() const const
QString name() const noexcept
Definition: component.cpp:33
virtual bool init(Application *application, const QVariantHash &args)
Definition: component.cpp:57
The Cutelyst namespace holds all public Cutelyst API.
int parameterType(int index) const const
Action(QObject *parent=nullptr)
Definition: action.cpp:13
QString ns() const noexcept
Definition: action.cpp:118
virtual Modifiers modifiers() const override
Definition: action.cpp:23
void setController(Controller *controller)
Definition: action.cpp:41
int returnType() const const
void setupAction(const QVariantHash &args, Application *app)
Definition: action.cpp:47
virtual bool match(int numberOfArgs) const noexcept
Definition: action.cpp:98
The Cutelyst application.
Definition: application.h:72
void setMethod(const QMetaMethod &method)
Definition: action.cpp:28
void setState(bool state) noexcept
Definition: context.cpp:80
virtual qint8 numberOfArgs() const
Definition: action.cpp:124
QString attribute(const QString &name, const QString &defaultValue={}) const
Definition: action.cpp:74
DirectConnection
QString className() const noexcept
Definition: action.cpp:86