Browse code

Version 1.5 initial commit

Benjamin Roth authored on24/06/2024 12:06:17
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,284 @@
1
+<?php
2
+
3
+declare(strict_types=1);
4
+
5
+/*
6
+ * This file is part of Oveleon ContaoMemberExtension Bundle.
7
+ *
8
+ * @package     contao-member-extension-bundle
9
+ * @license     MIT
10
+ * @author      Sebastian Zoglowek     <https://github.com/zoglo>
11
+ * @author      Daniele Sciannimanica  <https://github.com/doishub>
12
+ * @author      Fabian Ekert           <https://github.com/eki89>
13
+ * @copyright   Oveleon                <https://www.oveleon.de/>
14
+ */
15
+
16
+namespace Oveleon\ContaoMemberExtensionBundle\Controller\FrontendModule;
17
+
18
+use Contao\Config;
19
+use Contao\Controller;
20
+use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
21
+use Contao\CoreBundle\Exception\PageNotFoundException;
22
+use Contao\Date;
23
+use Contao\Environment;
24
+use Contao\FrontendTemplate;
25
+use Contao\Input;
26
+use Contao\MemberModel;
27
+use Contao\Model\Collection;
28
+use Contao\ModuleModel;
29
+use Contao\Pagination;
30
+use Contao\StringUtil;
31
+use Contao\System;
32
+use Contao\Template;
33
+use Contao\Widget;
34
+use Symfony\Component\HttpFoundation\Request;
35
+use Symfony\Component\HttpFoundation\Response;
36
+
37
+#[AsFrontendModule(MemberListController::TYPE, category: 'user', template: 'mod_memberList')]
38
+class MemberListController extends MemberExtensionController
39
+{
40
+    const TYPE = 'memberList';
41
+    private ModuleModel $model;
42
+    private Template $template;
43
+
44
+    private array $memberFilter = [];
45
+
46
+    protected function getResponse(Template $template, ModuleModel $model, Request $request): Response
47
+    {
48
+        $this->model = $model;
49
+        $this->template = $template;
50
+
51
+        $limit = null;
52
+        $offset = 0;
53
+
54
+        $arrGroups = StringUtil::deserialize($model->ext_groups);
55
+
56
+        if (empty($arrGroups) || !\is_array($arrGroups))
57
+        {
58
+            $template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
59
+            $template->getResponse();
60
+        }
61
+
62
+        if ($this->model->ext_activateFilter)
63
+        {
64
+            $this->parseFilters();
65
+        }
66
+
67
+        $memberTemplate = new FrontendTemplate($model->memberListTpl ?: 'memberExtension_list_default');
68
+
69
+        if (
70
+            str_starts_with($this->template->getName(), 'mod_' . self::TYPE . '_table') &&
71
+            str_starts_with($memberTemplate->getName(), 'memberExtension_list_row')
72
+        ) {
73
+            $this->isTable = true;
74
+        }
75
+
76
+        $intTotal = 0;
77
+        $arrMembers = [];
78
+
79
+        if (null !== ($objMembers = $this->getMembers()))
80
+        {
81
+            foreach ($objMembers as $objMember)
82
+            {
83
+                if (
84
+                    !$this->checkMemberGroups($arrGroups, $objMember) ||
85
+                    ($this->model->ext_activateFilter && $this->excludeMember($objMember))
86
+                ) {
87
+                    continue;
88
+                }
89
+
90
+                $intTotal += 1;
91
+
92
+                $this->memberFields = StringUtil::deserialize($model->memberFields, true);
93
+                $memberTemplate->setData($objMember->row());
94
+
95
+                $arrMembers[] = $this->parseMemberTemplate($objMember, $memberTemplate, $model);
96
+            }
97
+        }
98
+
99
+        $total = $intTotal - $offset;
100
+
101
+        if ($model->numberOfItems > 0)
102
+        {
103
+            $limit = $model->numberOfItems;
104
+        }
105
+
106
+        if ($model->perPage > 0 && (!isset($limit) || $model->numberOfItems > $model->perPage) && !$this->isTable)
107
+        {
108
+            if (isset($limit))
109
+            {
110
+                $total = min($limit, $total);
111
+            }
112
+
113
+            $id = 'page_n' . $model->id;
114
+            $page = Input::get($id) ?? 1;
115
+
116
+            if ($page < 1 || $page > max(ceil($total/$model->perPage), 1))
117
+            {
118
+                throw new PageNotFoundException('Page not found: ' . Environment::get('uri'));
119
+            }
120
+
121
+            $limit = $model->perPage;
122
+            $offset += (max($page, 1) - 1) * $model->perPage;
123
+            $skip = 0;
124
+
125
+            if ($offset + $limit > $total + $skip)
126
+            {
127
+                $limit = $total + $skip - $offset;
128
+            }
129
+
130
+            $arrMembers = \array_slice($arrMembers, $offset, ((int) $limit ?: $intTotal), true);
131
+
132
+            $objPagination = new Pagination($total, $model->perPage, Config::get('maxPaginationLinks'), $id);
133
+            $template->pagination = $objPagination->generate("\n  ");
134
+        }
135
+
136
+        if (empty($arrMembers))
137
+        {
138
+            $template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList'];
139
+        }
140
+
141
+        $template->hasDetailPage = !!$model->jumpTo;
142
+
143
+        $template->total = $total;
144
+        $template->labels = $this->labels;
145
+        $template->members = $arrMembers;
146
+
147
+        return $template->getResponse();
148
+    }
149
+
150
+    private function checkMemberGroups(array $arrGroups, MemberModel $objMember): bool
151
+    {
152
+        if (empty($arrGroups))
153
+        {
154
+            return false;
155
+        }
156
+
157
+        $arrMemberGroups = StringUtil::deserialize($objMember->groups);
158
+
159
+        if (!\is_array($arrMemberGroups) || !\count(array_intersect($arrGroups, $arrMemberGroups)))
160
+        {
161
+            return false;
162
+        }
163
+
164
+        return true;
165
+    }
166
+
167
+    private function getMembers(): Collection|MemberModel|null
168
+    {
169
+        $t = MemberModel::getTable();
170
+        $time = Date::floorToMinute();
171
+
172
+        $arrColumns = ["$t.disable='' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time') "];
173
+        $arrOptions = [];
174
+
175
+        if (!!$orderField = $this->model->ext_orderField)
176
+        {
177
+            $arrOptions['order'] = "$t.$orderField ";
178
+        }
179
+
180
+        switch ($this->model->ext_order)
181
+        {
182
+            case 'order_random':
183
+                $arrOptions['order'] = "RAND()";
184
+
185
+                break;
186
+
187
+            case 'order_desc':
188
+                if (isset($arrOptions['order'])) {
189
+                    $arrOptions['order'] .= "DESC ";
190
+                }
191
+
192
+                break;
193
+
194
+            case 'order_asc':
195
+            default:
196
+                break;
197
+        }
198
+
199
+        // Hook modify the member results
200
+        if (isset($GLOBALS['TL_HOOKS']['getMembers']) && \is_array($GLOBALS['TL_HOOKS']['getMembers']))
201
+        {
202
+            foreach ($GLOBALS['TL_HOOKS']['getMembers'] as $callback)
203
+            {
204
+                System::importStatic($callback[0])->{$callback[1]}($arrColumns, $arrOptions, $this);
205
+            }
206
+        }
207
+
208
+        return MemberModel::findBy($arrColumns, null, $arrOptions);
209
+    }
210
+
211
+    private function excludeMember(MemberModel $member): bool
212
+    {
213
+        foreach ($this->memberFilter as $condition)
214
+        {
215
+            if ($member->$condition !== '1')
216
+            {
217
+                return true;
218
+            }
219
+        }
220
+
221
+        return false;
222
+    }
223
+
224
+    private function parseFilters(): void
225
+    {
226
+        Controller::loadDataContainer('tl_member');
227
+        System::loadLanguageFile('tl_member');
228
+
229
+        $filters = [];
230
+
231
+        foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] ?? [] as $fieldName => $fieldConfig)
232
+        {
233
+            $type = $fieldConfig['inputType'] ?? null;
234
+            $filterable = $fieldConfig['eval']['feFilterable'] ?? null;
235
+
236
+            if ('checkbox' === $type && $filterable)
237
+            {
238
+                $filters[] = $fieldName;
239
+            }
240
+        }
241
+
242
+        if (!empty($filters))
243
+        {
244
+            /** @var Widget $strClass */
245
+            if (null === ($strClass = $GLOBALS['TL_FFL']['checkbox'] ?? null))
246
+            {
247
+                return;
248
+            }
249
+
250
+            $formId = 'memberListFilter_' . $this->model->id;
251
+
252
+            $this->template->requestToken = System::getContainer()->get('contao.csrf.token_manager')->getDefaultTokenValue();
253
+            $this->template->filterFormId = $formId;
254
+
255
+            foreach ($filters as $key => $filter)
256
+            {
257
+                $objWidget = new $strClass([
258
+                    'type'      => 'checkbox',
259
+                    'name'      => $filter,
260
+                    'id'        => $filter . '_'. $this->model->id,
261
+                    'options'   => [[
262
+                        'default'=> '',
263
+                        'value' => '1',
264
+                        'label' => $GLOBALS['TL_LANG']['tl_member'][$filter][0] ?? $filters
265
+                    ]]
266
+                ]);
267
+
268
+                if (Input::post('FORM_SUBMIT') === $formId)
269
+                {
270
+                    $objWidget->validate();
271
+
272
+                    if (!!$objWidget->value)
273
+                    {
274
+                        $this->memberFilter[] = $objWidget->name;
275
+                    }
276
+                }
277
+
278
+                $filters[$key] = $objWidget->parse();
279
+            }
280
+        }
281
+
282
+        $this->template->filters = $filters;
283
+    }
284
+}