6#include "application.h"
10#include "controller_p.h"
11#include "dispatcher_p.h"
12#include "dispatchtypechained.h"
13#include "dispatchtypepath.h"
25 , d_ptr(new DispatcherPrivate(this))
31Dispatcher::~Dispatcher()
37 const QVector<Cutelyst::DispatchType *> &dispatchers,
46 bool instanceUsed =
false;
48 for (
Action *action : actions) {
49 bool registered =
false;
50 if (!d->actions.contains(action->reverse())) {
51 if (!action->attributes().contains(QStringLiteral(
"Private"))) {
54 if (
dispatch->registerAction(action)) {
68 const QString name = action->ns() + QLatin1Char(
'/') + action->name();
69 d->actions.insert(name, {name, action});
70 auto it = d->actionContainer.find(action->ns());
71 if (it != d->actionContainer.end()) {
72 it->actions << action;
74 d->actionContainer.insert(action->ns(), {action->ns(), {action}});
77 registeredActions.append(action);
80 qCDebug(CUTELYST_DISPATCHER)
81 <<
"The action" << action->name() <<
"of" << action->controller()->objectName()
82 <<
"controller was not registered in any dispatcher."
83 " If you still want to access it internally (via actionFor())"
84 " you may make it's method private.";
89 d->controllers.insert(
controller->objectName(), {controller->objectName(), controller});
98 d->rootActions = d->actionContainer.value(u
"").actions;
101 controller->d_ptr->setupFinished();
106 while (i < d->dispatchers.size()) {
108 if (!type->
inUse()) {
109 d->dispatchers.removeAt(i);
118 qCDebug(CUTELYST_DISPATCHER) << dispatch->
list().constData();
125 Action *action = c->action();
129 const QString path = c->req()->path();
130 if (path.isEmpty()) {
134 c->
translate(
"Cutelyst::Dispatcher",
"Unknown resource '%1'.").arg(path));
152 Action *action = d->command2Action(c, opname, c->request()->args());
157 qCCritical(CUTELYST_DISPATCHER) <<
"Action not found" << opname << c->request()->args();
165 Request *request = c->request();
166 d->prepareAction(c, request->path());
168 static const bool log = CUTELYST_DISPATCHER().isDebugEnabled();
170 if (!request->match().isEmpty()) {
171 qCDebug(CUTELYST_DISPATCHER) <<
"Path is" << request->match();
174 if (!request->args().isEmpty()) {
175 qCDebug(CUTELYST_DISPATCHER) <<
"Arguments are" << request->args().join(u
'/');
180void DispatcherPrivate::prepareAction(
Context *c, QStringView path)
const
193 if (type->
match(c, path, args) == DispatchType::ExactMatch) {
199 if (path.isEmpty()) {
203 int pos = path.lastIndexOf(u
'/');
205 args.emplaceFront(path.mid(pos + 1).toString());
215 if (name.isEmpty()) {
219 if (nameSpace.isEmpty()) {
220 const QString normName = u
'/' + name;
221 return d->actions.value(normName).action;
231 int slashes = path.count(u
'/');
233 return d->actions.value(QString{u
'/' + path}).action;
234 }
else if (path.startsWith(u
'/') && slashes != 1) {
235 return d->actions.value(path.mid(1)).action;
237 return d->actions.value(path).action;
246 if (name.isEmpty()) {
250 const ActionList containers = d->getContainers(nameSpace);
251 auto rIt = containers.rbegin();
252 while (rIt != containers.rend()) {
253 if ((*rIt)->name() == name) {
264 return d->controllers.value(name).controller;
270 QList<Controller *> ret;
271 for (
const auto &value : d->controllers) {
272 ret.append(value.controller);
281 if (Q_UNLIKELY(action ==
nullptr)) {
282 qCCritical(CUTELYST_DISPATCHER) <<
"Dispatcher::uriForAction called with null action";
286 ret =
dispatch->uriForAction(action, captures);
303 if (expandedAction) {
304 return expandedAction;
313 return d->dispatchers;
316void DispatcherPrivate::printActions()
const
318 QVector<QStringList> table;
320 auto keys = actions.keys();
321 std::sort(keys.begin(), keys.end());
322 for (
const auto &key : keys) {
323 Action *action = actions.value(key).action;
324 QString path = key.toString();
325 if (!path.startsWith(u
'/')) {
332 row.append(action->
name());
336 qCDebug(CUTELYST_DISPATCHER) << Utils::buildTable(table,
337 {QLatin1String(
"Private"),
338 QLatin1String(
"Class"),
339 QLatin1String(
"Method")},
340 QLatin1String(
"Loaded Private actions:"))
344ActionList DispatcherPrivate::getContainers(QStringView ns)
const
348 if (ns.compare(u
"/") != 0) {
353 ret.append(actionContainer.value(ns.mid(0, pos)).actions);
354 pos = ns.lastIndexOf(u
'/', pos - 1);
358 ret.append(rootActions);
365 const QStringList &args)
const
367 auto it = actions.constFind(command);
368 if (it != actions.constEnd()) {
369 return it.value().action;
372 return invokeAsPath(c, command, args);
376 QStringView relativePath,
377 const QStringList &args)
const
383 const QString path = DispatcherPrivate::actionRel2Abs(c, relativePath);
384 QStringView pathView{path};
386 int pos = pathView.lastIndexOf(u
'/');
387 int lastPos = pathView.size();
390 ret = q->getAction(pathView);
395 const auto name = pathView.mid(pos + 1, lastPos);
396 pathView = pathView.mid(0, pos);
397 ret = q->getAction(name, pathView);
404 pos = pathView.indexOf(u
'/', pos - 1);
410QString DispatcherPrivate::actionRel2Abs(
Context *c, QStringView path)
413 if (path.startsWith(u
'/')) {
414 ret = path.mid(1).toString();
418 const QString ns = qobject_cast<Action *>(c->
stack().constLast())->
ns();
420 ret = path.toString();
422 ret = ns + QLatin1Char(
'/') + path;
427#include "moc_dispatcher.cpp"
This class represents a Cutelyst Action.
QString ns() const noexcept
bool dispatch(Context *c)
QString className() const noexcept
Controller * controller() const noexcept
The Cutelyst Component base class.
QString name() const noexcept
QStack< Component * > stack() const noexcept
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
bool execute(Component *code)
void appendError(const QString &error)
Sets an error string and try to stop.
Cutelyst Controller base class
ActionList actions() const noexcept
bool _DISPATCH(Context *c)
virtual QByteArray list() const =0
list the registered actions To be implemented by subclasses
virtual MatchType match(Context *c, QStringView path, const QStringList &args) const =0
Action * getAction(QStringView name, QStringView nameSpace={}) const
void setupActions(const QVector< Controller * > &controllers, const QVector< DispatchType * > &dispatchers, bool printActions)
QVector< DispatchType * > dispatchers() const
QString uriForAction(Action *action, const QStringList &captures) const
ActionList getActions(QStringView name, QStringView nameSpace) const
bool forward(Context *c, Component *component)
Controller * controller(QStringView name) const
Dispatcher(QObject *parent=nullptr)
Action * getActionByPath(QStringView path) const
QList< Controller * > controllers() const
void prepareAction(Context *c)
bool dispatch(Context *c)
Action * expandAction(const Context *c, Action *action) const
The Cutelyst namespace holds all public Cutelyst API.
QVector< Action * > ActionList