cutelyst 3.9.1
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;
15
18 , d_ptr(new DispatchTypePathPrivate)
19{
20}
21
22DispatchTypePath::~DispatchTypePath()
23{
24 delete d_ptr;
25}
26
28{
29 Q_D(const DispatchTypePath);
30
31 QRegularExpression multipleSlashes(QLatin1String("/{1,}"));
32
34
35 QStringList keys = d->paths.keys();
37 for (const QString &path : keys) {
38 const auto paths = d->paths.value(path);
39 for (Action *action : paths) {
40 QString _path = QLatin1Char('/') + path;
41 if (action->attribute(QLatin1String("Args")).isEmpty()) {
42 _path.append(QLatin1String("/..."));
43 } else {
44 for (int i = 0; i < action->numberOfArgs(); ++i) {
45 _path.append(QLatin1String("/*"));
46 }
47 }
48 _path.replace(multipleSlashes, QLatin1String("/"));
49
50 QString privateName = action->reverse();
51 if (!privateName.startsWith(QLatin1Char('/'))) {
52 privateName.prepend(QLatin1Char('/'));
53 }
54
55 table.append({_path, privateName});
56 }
57 }
58
59 return Utils::buildTable(table,
60 {QLatin1String("Path"), QLatin1String("Private")},
61 QLatin1String("Loaded Path actions:"));
62}
63
65 DispatchTypePath::match(Context *c, const QString &path, const QStringList &args) const
66{
67 Q_D(const DispatchTypePath);
68
69 QString _path = path;
70 if (_path.isEmpty()) {
71 _path = QStringLiteral("/");
72 }
73
74 const auto it = d->paths.constFind(_path);
75 if (it == d->paths.constEnd()) {
76 return NoMatch;
77 }
78
79 MatchType ret = NoMatch;
80 int numberOfArgs = args.size();
81 for (Action *action : it.value()) {
82 // If the number of args is -1 (not defined)
83 // it will slurp all args so we don't care
84 // about how many args was passed
85 if (action->numberOfArgs() == numberOfArgs) {
86 Request *request = c->request();
87 request->setArguments(args);
88 request->setMatch(_path);
89 setupMatchedAction(c, action);
90 return ExactMatch;
91 } else if (action->numberOfArgs() == -1 && !c->action()) {
92 // Only setup partial matches if no action is
93 // currently set
94 Request *request = c->request();
95 request->setArguments(args);
96 request->setMatch(_path);
97 setupMatchedAction(c, action);
98 ret = PartialMatch;
99 }
100 }
101 return ret;
102}
103
105{
106 Q_D(DispatchTypePath);
107
108 bool ret = false;
109 const auto attributes = action->attributes();
110 const auto range = attributes.equal_range(QLatin1String("Path"));
111 for (auto i = range.first; i != range.second; ++i) {
112 if (d->registerPath(*i, action)) {
113 ret = true;
114 }
115 }
116
117 // We always register valid actions
118 return ret;
119}
120
122{
123 Q_D(const DispatchTypePath);
124 return !d->paths.isEmpty();
125}
126
128{
129 QString ret;
130 if (captures.isEmpty()) {
131 const auto attributes = action->attributes();
132 auto it = attributes.constFind(QStringLiteral("Path"));
133 if (it != attributes.constEnd()) {
134 const QString &path = it.value();
135 if (path.isEmpty()) {
136 ret = QStringLiteral("/");
137 } else if (!path.startsWith(QLatin1Char('/'))) {
138 ret = QLatin1Char('/') + path;
139 } else {
140 ret = path;
141 }
142 }
143 }
144 return ret;
145}
146
147bool DispatchTypePathPrivate::registerPath(const QString &path, Action *action)
148{
149 QString _path = path;
150 if (_path.startsWith(QLatin1Char('/')) && !_path.isEmpty()) {
151 _path.remove(0, 1);
152 }
153 if (_path.isEmpty()) {
154 _path = QStringLiteral("/");
155 }
156
157 auto it = paths.find(_path);
158 if (it != paths.end()) {
159 int actionNumberOfArgs = action->numberOfArgs();
160 for (const Action *regAction : it.value()) {
161 if (regAction->numberOfArgs() == actionNumberOfArgs) {
162 qCCritical(CUTELYST_DISPATCHER_PATH)
163 << "Not registering Action" << action->name() << "of controller"
164 << action->controller()->objectName() << "because it conflicts with"
165 << regAction->name() << "of controller"
166 << regAction->controller()->objectName();
167 return false;
168 }
169 }
170
171 it.value().push_back(action);
172 std::sort(it.value().begin(), it.value().end(), [](Action *a, Action *b) -> bool {
173 return a->numberOfArgs() < b->numberOfArgs();
174 });
175 } else {
176 paths.insert(_path, {action});
177 }
178 return true;
179}
180
181#include "moc_dispatchtypepath.cpp"
This class represents a Cutelyst Action.
Definition action.h:35
virtual qint8 numberOfArgs() const noexcept
Definition action.cpp:124
ParamsMultiMap attributes() const noexcept
Definition action.cpp:68
Controller * controller() const
Definition action.cpp:92
QString name() const
Definition component.cpp:33
The Cutelyst Context.
Definition context.h:39
virtual MatchType match(Context *c, const QString &path, const QStringList &args) const override
DispatchTypePath(QObject *parent=nullptr)
virtual QByteArray list() const override
list the registered actions To be implemented by subclasses
virtual bool inUse() override
virtual QString uriForAction(Action *action, const QStringList &captures) const override
virtual bool registerAction(Action *action) override
registerAction
DispatchType(QObject *parent=nullptr)
void setupMatchedAction(Context *c, Action *action) const
void setArguments(const QStringList &arguments)
Definition request.cpp:157
void setMatch(const QString &match)
Definition request.cpp:145
The Cutelyst namespace holds all public Cutelyst API.
Definition Mainpage.dox:8
bool isEmpty() const const
int size() const const
typename QMap< Key, T >::const_iterator constFind(const Key &key, const T &value) const const
QObject(QObject *parent)
QObject * parent() const const
QString & append(QChar ch)
bool isEmpty() const const
QString & prepend(QChar ch)
QString & remove(int position, int n)
QString & replace(int position, int n, QChar after)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void sort(Qt::CaseSensitivity cs)
CaseInsensitive
void append(const T &value)