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()
46 bool instanceUsed =
false;
47 const auto actions = controller->actions();
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)) {
69 d->actions.insert(name, {name, action});
70 d->actionContainer[action->ns()] << action;
71 registeredActions.
append(action);
74 qCDebug(CUTELYST_DISPATCHER)
75 <<
"The action" << action->name() <<
"of" << action->controller()->objectName()
76 <<
"controller was not registered in any dispatcher."
77 " If you still want to access it internally (via actionFor())"
78 " you may make it's method private.";
83 d->controllers.insert(controller->objectName(), controller);
95 controller->d_ptr->setupFinished();
102 if (!type->
inUse()) {
103 d->dispatchers.removeAt(i);
112 qCDebug(CUTELYST_DISPATCHER) <<
dispatch->list().constData();
119 Action *action = c->action();
123 const QString path = c->req()->path();
125 c->
error(c->
translate(
"Cutelyst::Dispatcher",
"No default action defined"));
127 c->
error(c->
translate(
"Cutelyst::Dispatcher",
"Unknown resource '%1'.").
arg(path));
145 Action *action = d->command2Action(c, opname, c->request()->args());
150 qCCritical(CUTELYST_DISPATCHER) <<
"Action not found" << opname << c->request()->args();
158 Request *request = c->request();
159 d->prepareAction(c, request->path());
161 static const auto &log = CUTELYST_DISPATCHER();
162 if (log.isDebugEnabled()) {
163 if (!request->match().
isEmpty()) {
164 qCDebug(log) <<
"Path is" << request->match();
167 if (!request->args().
isEmpty()) {
168 qCDebug(log) <<
"Arguments are" << request->args().
join(
QLatin1Char(
'/'));
173void DispatcherPrivate::prepareAction(
Context *c,
const QString &requestPath)
const
175 QString path = normalizePath(requestPath);
187 if (type->match(c, path, args) == DispatchType::ExactMatch) {
199 const QString arg = path.
mid(pos + 1);
215 const QString normName = u
'/' + name;
216 return d->actions.value(normName).action;
219 const QString ns = DispatcherPrivate::cleanNamespace(nameSpace);
228 int slashes = _path.
count(u
'/');
231 }
else if (_path.
startsWith(u
'/') && slashes != 1) {
234 return d->actions.value(_path).action;
247 const QString ns = DispatcherPrivate::cleanNamespace(nameSpace);
248 const ActionList containers = d->getContainers(ns);
249 auto rIt = containers.
rbegin();
250 while (rIt != containers.
rend()) {
251 if ((*rIt)->name() == name) {
262 return d->controllers;
270 ret =
dispatch->uriForAction(action, captures);
273 ret = QStringLiteral(
"/");
286 if (expandedAction) {
287 return expandedAction;
296 return d->dispatchers;
302 bool lastWasSlash =
true;
303 int nsSize = ns.
size();
304 for (
int i = 0; i < nsSize; ++i) {
309 if (ret.
at(i) == u
'/') {
317 lastWasSlash =
false;
323QString DispatcherPrivate::normalizePath(
const QString &path)
326 bool lastSlash =
true;
328 while (i < ret.
size()) {
329 if (ret.
at(i) == u
'/') {
347void DispatcherPrivate::printActions()
const
349 QVector<QStringList> table;
351 auto keys = actions.keys();
352 std::sort(keys.begin(), keys.end());
353 for (
const auto &key : keys) {
354 Action *action = actions.value(key).action;
355 QString path = key.toString();
367 qCDebug(CUTELYST_DISPATCHER) << Utils::buildTable(table,
368 {QLatin1String(
"Private"),
369 QLatin1String(
"Class"),
370 QLatin1String(
"Method")},
371 QLatin1String(
"Loaded Private actions:"))
375ActionList DispatcherPrivate::getContainers(
const QString &ns)
const
384 ret.
append(actionContainer.value(ns.
mid(0, pos)));
395 const QString &command,
396 const QStringList &args)
const
398 auto it = actions.constFind(command);
399 if (it != actions.constEnd()) {
400 return it.value().action;
403 return invokeAsPath(c, command, args);
407 const QString &relativePath,
408 const QStringList &args)
const
414 QString path = DispatcherPrivate::actionRel2Abs(c, relativePath);
417 int lastPos = path.
size();
420 ret = q->getAction(path, QString());
425 const QString name = path.
mid(pos + 1, lastPos);
426 path = path.
mid(0, pos);
427 ret = q->getAction(name, path);
434 pos = path.
indexOf(QLatin1Char(
'/'), pos - 1);
440QString DispatcherPrivate::actionRel2Abs(
Context *c,
const QString &path)
448 const QString ns = qobject_cast<Action *>(c->
stack().constLast())->ns();
452 ret = ns + QLatin1Char(
'/') + path;
457#include "moc_dispatcher.cpp"
This class represents a Cutelyst Action.
bool dispatch(Context *c)
QString className() const
Controller * controller() const
The Cutelyst Component base class.
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)
bool error() const noexcept
Returns true if an error was set.
bool _DISPATCH(Context *c)
QMap< QString, Controller * > controllers() const
void setupActions(const QVector< Controller * > &controllers, const QVector< DispatchType * > &dispatchers, bool printActions)
Action * getAction(const QString &name, const QString &nameSpace=QString()) const
QVector< DispatchType * > dispatchers() const
Action * getActionByPath(const QString &path) const
QString uriForAction(Action *action, const QStringList &captures) const
bool forward(Context *c, Component *component)
Dispatcher(QObject *parent=nullptr)
ActionList getActions(const QString &name, const QString &nameSpace) 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
void append(const T &value)
bool isEmpty() const const
void prepend(const T &value)
QObject * parent() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString mid(int position, int n) const const
QString & prepend(QChar ch)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString join(const QString &separator) const const
void append(const T &value)
reverse_iterator rbegin()