Cutelyst  2.3.0
urifor.cpp
1 /*
2  * Copyright (C) 2017 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "urifor.h"
19 
20 #include <grantlee/exception.h>
21 #include <grantlee/parser.h>
22 
23 #include <Context>
24 #include <Cutelyst/Context>
25 #include <Cutelyst/ParamsMultiMap>
26 
27 #include <QDebug>
28 
29 UriFor::UriFor(const QString &path, const QStringList &args, Grantlee::Parser *parser) : Grantlee::Node(parser)
30  , m_path(path, parser)
31 {
32  bool foundQuery = false;
33  for (const QString &expression : args) {
34  // WE require the QUERY keyword to know when we are dealing with query values
35  if (expression == QLatin1String("QUERY")) {
36  foundQuery = true;
37  continue;
38  }
39 
40  if (foundQuery) {
41  m_queryExpressions.push_back(Grantlee::FilterExpression(expression, parser));
42  } else {
43  m_argsExpressions.push_back(Grantlee::FilterExpression(expression, parser));
44  }
45  }
46  std::reverse(m_queryExpressions.begin(), m_queryExpressions.end());
47 }
48 
49 std::pair<QString,QString> splitQuery(const QString &query)
50 {
51  std::pair<QString,QString> ret;
52 
53  ret.first = query.section(QLatin1Char('='), 0, 0);
54  ret.second = query.section(QLatin1Char('='), 1);
55 
56  return ret;
57 }
58 
59 void UriFor::render(Grantlee::OutputStream *stream, Grantlee::Context *gc) const
60 {
61  // In case cutelyst context is not set as "c"
62  auto c = gc->lookup(m_cutelystContext).value<Cutelyst::Context *>();
63  if (!c) {
64  const QVariantHash hash = gc->stackHash(0);
65  auto it = hash.constBegin();
66  while (it != hash.constEnd()) {
67  if (it.value().userType() == qMetaTypeId<Cutelyst::Context *>()) {
68  c = it.value().value<Cutelyst::Context *>();
69  if (c) {
70  m_cutelystContext = it.key();
71  break;
72  }
73  }
74  ++it;
75  }
76 
77  if (!c) {
78  return;
79  }
80  }
81 
82  QString path;
83  QStringList args;
84  Cutelyst::ParamsMultiMap queryValues;
85 
86  QVariant pathVar = m_path.resolve(gc);
87  if (pathVar.userType() == qMetaTypeId<Grantlee::SafeString>()) {
88  path = pathVar.value<Grantlee::SafeString>().get();
89  } else if (pathVar.type() == QVariant::String) {
90  path = pathVar.toString();
91  } else {
92  qWarning() << "c_uri_for PATH is not a valid type";
93  return;
94  }
95 
96  for (const Grantlee::FilterExpression &exp : m_argsExpressions) {
97  QVariant var = exp.resolve(gc);
98  if (var.userType() == qMetaTypeId<Grantlee::SafeString>()) {
99  args << var.value<Grantlee::SafeString>().get();
100  } else if (var.type() == QVariant::String) {
101  args << var.toString();
102  } else if (var.type() == QVariant::StringList) {
103  args << var.toStringList();
104  }
105  }
106 
107  for (const Grantlee::FilterExpression &exp : m_queryExpressions) {
108  QVariant var = exp.resolve(gc);
109  if (var.userType() == qMetaTypeId<Cutelyst::ParamsMultiMap>()) {
110  auto map = var.value<Cutelyst::ParamsMultiMap>();
111  queryValues.unite(map);
112  } else if (var.userType() == qMetaTypeId<Grantlee::SafeString>()) {
113  auto query = splitQuery(var.value<Grantlee::SafeString>().get());
114  queryValues.insertMulti(query.first, query.second);
115  } else if (var.type() == QVariant::String) {
116  auto query = splitQuery(var.toString());
117  queryValues.insertMulti(query.first, query.second);
118  } else if (var.type() == QVariant::StringList) {
119  const auto queries = var.toStringList();
120  for (const QString &str : queries) {
121  auto query = splitQuery(str);
122  queryValues.insertMulti(query.first, query.second);
123  }
124  }
125  }
126 
127  *stream << c->uriFor(path, args, queryValues).toString(QUrl::FullyEncoded);
128 }
129 
130 Grantlee::Node *UriForTag::getNode(const QString &tagContent, Grantlee::Parser *p) const
131 {
132  // You almost always want to use smartSplit.
133  QStringList parts = smartSplit(tagContent);
134 
135  parts.removeFirst(); // Not interested in the name of the tag.
136  if (parts.isEmpty()) {
137  throw Grantlee::Exception(Grantlee::TagSyntaxError, QStringLiteral("c_uri_for requires at least the path"));
138  }
139 
140  return new UriFor(parts.first(), parts.mid(1), p);
141 }
142 
143 #include "moc_urifor.cpp"
QMap< QString, QString > ParamsMultiMap
The Cutelyst Context.
Definition: context.h:50