cutelyst 4.8.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
dispatchtypepath.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "common.h"
6#include "controller.h"
7#include "dispatchtypepath_p.h"
8#include "utils.h"
9
10#include <QBuffer>
11#include <QDebug>
12#include <QRegularExpression>
13
14using namespace Cutelyst;
15using namespace Qt::Literals::StringLiterals;
16
19 , d_ptr(new DispatchTypePathPrivate)
20{
21}
22
24{
25 delete d_ptr;
26}
27
29{
30 Q_D(const DispatchTypePath);
31
32 const static QRegularExpression multipleSlashes(u"/{1,}"_s);
33
35
36 auto keys = d->paths.keys();
37
38 std::sort(keys.begin(), keys.end(), [](QStringView a, QStringView b) {
39 return a.compare(b, Qt::CaseInsensitive) < 0;
40 });
41 for (const auto &path : keys) {
42 const auto paths = d->paths.value(path);
43 for (Action *action : paths.actions) {
44 QString _path = u'/' + path;
45 if (action->attribute(u"Args"_s).isEmpty()) {
46 _path.append(u"/...");
47 } else {
48 for (int i = 0; i < action->numberOfArgs(); ++i) {
49 _path.append(u"/*");
50 }
51 }
52 _path.replace(multipleSlashes, u"/"_s);
53
54 QString privateName = action->reverse();
55 if (!privateName.startsWith(u'/')) {
56 privateName.prepend(u'/');
57 }
58
59 table.append({_path, privateName});
60 }
61 }
62
63 return Utils::buildTable(table, {u"Path"_s, u"Private"_s}, u"Loaded Path actions:"_s);
64}
65
68{
69 Q_D(const DispatchTypePath);
70
71 auto it = d->paths.constFind(path);
72 if (it == d->paths.constEnd()) {
73 return NoMatch;
74 }
75
76 MatchType ret = NoMatch;
77 int numberOfArgs = args.size();
78 for (Action *action : it->actions) {
79 // If the number of args is -1 (not defined)
80 // it will slurp all args so we don't care
81 // about how many args was passed
82 if (action->numberOfArgs() == numberOfArgs) {
83 Request *request = c->request();
84 request->setArguments(args);
85 request->setMatch(it->name);
86 setupMatchedAction(c, action);
87 return ExactMatch;
88 } else if (action->numberOfArgs() == -1 && !c->action()) {
89 // Only setup partial matches if no action is
90 // currently set
91 Request *request = c->request();
92 request->setArguments(args);
93 request->setMatch(it->name);
94 setupMatchedAction(c, action);
95 ret = PartialMatch;
96 }
97 }
98 return ret;
99}
100
102{
103 Q_D(DispatchTypePath);
104
105 bool ret = false;
106 const auto attributes = action->attributes();
107 const auto range = attributes.equal_range(u"Path"_s);
108 for (auto i = range.first; i != range.second; ++i) {
109 if (d->registerPath(*i, action)) {
110 ret = true;
111 }
112 }
113
114 // We always register valid actions
115 return ret;
116}
117
119{
120 Q_D(const DispatchTypePath);
121 return !d->paths.isEmpty();
122}
123
125{
126 QString ret;
127 if (captures.isEmpty()) {
128 const auto attributes = action->attributes();
129 auto it = attributes.constFind(u"Path"_s);
130 if (it != attributes.constEnd()) {
131 const QString &path = it.value();
132 if (path.isEmpty()) {
133 ret = u"/"_s;
134 } else if (!path.startsWith(u'/')) {
135 ret = u'/' + path;
136 } else {
137 ret = path;
138 }
139 }
140 }
141 return ret;
142}
143
144bool DispatchTypePathPrivate::registerPath(const QString &path, Action *action)
145{
146 QString _path = path;
147 // TODO see if we can make controllers fix this
148 if (_path.isEmpty()) {
149 _path = u"/"_s;
150 } else if (!_path.startsWith(u'/')) {
151 _path.prepend(u'/');
152 }
153
154 auto it = paths.find(_path);
155 if (it != paths.end()) {
156 int actionNumberOfArgs = action->numberOfArgs();
157 auto &actions = it->actions;
158 for (const Action *regAction : actions) {
159 if (regAction->numberOfArgs() == actionNumberOfArgs) {
160 qCCritical(CUTELYST_DISPATCHER_PATH)
161 << "Not registering Action" << action->name() << "of controller"
162 << action->controller()->objectName() << "because it conflicts with"
163 << regAction->name() << "of controller"
164 << regAction->controller()->objectName();
165 return false;
166 }
167 }
168
169 actions.push_back(action);
170 std::sort(actions.begin(), actions.end(), [](Action *a, Action *b) -> bool {
171 return a->numberOfArgs() < b->numberOfArgs();
172 });
173 } else {
174 paths.insert(_path, DispatchTypePathReplacement{_path, {action}});
175 }
176 return true;
177}
178
179#include "moc_dispatchtypepath.cpp"
This class represents a Cutelyst Action.
Definition action.h:35
virtual qint8 numberOfArgs() const
Definition action.cpp:125
ParamsMultiMap attributes() const noexcept
Definition action.cpp:69
Controller * controller() const noexcept
Definition action.cpp:93
QString attribute(const QString &name, const QString &defaultValue={}) const
Definition action.cpp:75
QString reverse() const noexcept
Definition component.cpp:45
QString name() const noexcept
Definition component.cpp:33
The Cutelyst Context.
Definition context.h:42
Request * request
Definition context.h:71
Action * action
Definition context.h:47
DispatchTypePath(QObject *parent=nullptr)
QByteArray list() const override
MatchType match(Context *c, QStringView path, const QStringList &args) const override
QString uriForAction(Action *action, const QStringList &captures) const override
bool registerAction(Action *action) override
DispatchType(QObject *parent=nullptr)
void setupMatchedAction(Context *c, Action *action) const
A request.
Definition request.h:42
void setArguments(const QStringList &arguments)
Definition request.cpp:156
void setMatch(const QString &match)
Definition request.cpp:144
The Cutelyst namespace holds all public Cutelyst API.
void append(QList< T > &&value)
bool isEmpty() const const
qsizetype size() const const
QMultiMap< Key, T >::const_iterator constFind(const Key &key) const const
std::pair< QMultiMap< Key, T >::iterator, QMultiMap< Key, T >::iterator > equal_range(const Key &key)
QObject(QObject *parent)
QObject * parent() const const
QString & append(QChar ch)
bool isEmpty() const const
QString & prepend(QChar ch)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const