<?php declare(strict_types=1); /* * This file is part of Oveleon ContaoMemberExtension Bundle. * * @package contao-member-extension-bundle * @license MIT * @author Sebastian Zoglowek <https://github.com/zoglo> * @author Daniele Sciannimanica <https://github.com/doishub> * @author Fabian Ekert <https://github.com/eki89> * @copyright Oveleon <https://www.oveleon.de/> */ namespace Oveleon\ContaoMemberExtensionBundle\Controller\FrontendModule; use Contao\Config; use Contao\Controller; use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule; use Contao\CoreBundle\Exception\PageNotFoundException; use Contao\Date; use Contao\Environment; use Contao\FrontendTemplate; use Contao\Input; use Contao\MemberModel; use Contao\Model\Collection; use Contao\ModuleModel; use Contao\Pagination; use Contao\StringUtil; use Contao\System; use Contao\Template; use Contao\Widget; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; #[AsFrontendModule(MemberListController::TYPE, category: 'user', template: 'mod_memberList')] class MemberListController extends MemberExtensionController { const TYPE = 'memberList'; private ModuleModel $model; private Template $template; private array $memberFilter = []; protected function getResponse(Template $template, ModuleModel $model, Request $request): Response { $this->model = $model; $this->template = $template; $limit = null; $offset = 0; $arrGroups = StringUtil::deserialize($model->ext_groups); if (empty($arrGroups) || !\is_array($arrGroups)) { $template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList']; $template->getResponse(); } if ($this->model->ext_activateFilter) { $this->parseFilters(); } $memberTemplate = new FrontendTemplate($model->memberListTpl ?: 'memberExtension_list_default'); if ( str_starts_with($this->template->getName(), 'mod_' . self::TYPE . '_table') && str_starts_with($memberTemplate->getName(), 'memberExtension_list_row') ) { $this->isTable = true; } $intTotal = 0; $arrMembers = []; if (null !== ($objMembers = $this->getMembers())) { foreach ($objMembers as $objMember) { if ( !$this->checkMemberGroups($arrGroups, $objMember) || ($this->model->ext_activateFilter && $this->excludeMember($objMember)) ) { continue; } $intTotal += 1; $this->memberFields = StringUtil::deserialize($model->memberFields, true); $memberTemplate->setData($objMember->row()); $arrMembers[] = $this->parseMemberTemplate($objMember, $memberTemplate, $model); } } $total = $intTotal - $offset; if ($model->numberOfItems > 0) { $limit = $model->numberOfItems; } if ($model->perPage > 0 && (!isset($limit) || $model->numberOfItems > $model->perPage) && !$this->isTable) { if (isset($limit)) { $total = min($limit, $total); } $id = 'page_n' . $model->id; $page = Input::get($id) ?? 1; if ($page < 1 || $page > max(ceil($total/$model->perPage), 1)) { throw new PageNotFoundException('Page not found: ' . Environment::get('uri')); } $limit = $model->perPage; $offset += (max($page, 1) - 1) * $model->perPage; $skip = 0; if ($offset + $limit > $total + $skip) { $limit = $total + $skip - $offset; } $arrMembers = \array_slice($arrMembers, $offset, ((int) $limit ?: $intTotal), true); $objPagination = new Pagination($total, $model->perPage, Config::get('maxPaginationLinks'), $id); $template->pagination = $objPagination->generate("\n "); } if (empty($arrMembers)) { $template->empty = $GLOBALS['TL_LANG']['MSC']['emptyMemberList']; } $template->hasDetailPage = !!$model->jumpTo; $template->total = $total; $template->labels = $this->labels; $template->members = $arrMembers; return $template->getResponse(); } private function checkMemberGroups(array $arrGroups, MemberModel $objMember): bool { if (empty($arrGroups)) { return false; } $arrMemberGroups = StringUtil::deserialize($objMember->groups); if (!\is_array($arrMemberGroups) || !\count(array_intersect($arrGroups, $arrMemberGroups))) { return false; } return true; } private function getMembers(): Collection|MemberModel|null { $t = MemberModel::getTable(); $time = Date::floorToMinute(); $arrColumns = ["$t.disable='' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time') "]; $arrOptions = []; if (!!$orderField = $this->model->ext_orderField) { $arrOptions['order'] = "$t.$orderField "; } switch ($this->model->ext_order) { case 'order_random': $arrOptions['order'] = "RAND()"; break; case 'order_desc': if (isset($arrOptions['order'])) { $arrOptions['order'] .= "DESC "; } break; case 'order_asc': default: break; } // Hook modify the member results if (isset($GLOBALS['TL_HOOKS']['getMembers']) && \is_array($GLOBALS['TL_HOOKS']['getMembers'])) { foreach ($GLOBALS['TL_HOOKS']['getMembers'] as $callback) { System::importStatic($callback[0])->{$callback[1]}($arrColumns, $arrOptions, $this); } } return MemberModel::findBy($arrColumns, null, $arrOptions); } private function excludeMember(MemberModel $member): bool { foreach ($this->memberFilter as $condition) { if ($member->$condition !== '1') { return true; } } return false; } private function parseFilters(): void { Controller::loadDataContainer('tl_member'); System::loadLanguageFile('tl_member'); $filters = []; foreach ($GLOBALS['TL_DCA']['tl_member']['fields'] ?? [] as $fieldName => $fieldConfig) { $type = $fieldConfig['inputType'] ?? null; $filterable = $fieldConfig['eval']['feFilterable'] ?? null; if ('checkbox' === $type && $filterable) { $filters[] = $fieldName; } } if (!empty($filters)) { /** @var Widget $strClass */ if (null === ($strClass = $GLOBALS['TL_FFL']['checkbox'] ?? null)) { return; } $formId = 'memberListFilter_' . $this->model->id; $this->template->requestToken = System::getContainer()->get('contao.csrf.token_manager')->getDefaultTokenValue(); $this->template->filterFormId = $formId; foreach ($filters as $key => $filter) { $objWidget = new $strClass([ 'type' => 'checkbox', 'name' => $filter, 'id' => $filter . '_'. $this->model->id, 'options' => [[ 'default'=> '', 'value' => '1', 'label' => $GLOBALS['TL_LANG']['tl_member'][$filter][0] ?? $filters ]] ]); if (Input::post('FORM_SUBMIT') === $formId) { $objWidget->validate(); if (!!$objWidget->value) { $this->memberFilter[] = $objWidget->name; } } $filters[$key] = $objWidget->parse(); } } $this->template->filters = $filters; } }