diff --git a/Classes/Command/CreateMappingsCommand.php b/Classes/Command/CreateMappingsCommand.php index e0697665..2929ad4c 100644 --- a/Classes/Command/CreateMappingsCommand.php +++ b/Classes/Command/CreateMappingsCommand.php @@ -38,11 +38,18 @@ public function execute(InputInterface $input, OutputInterface $output): int { $qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); $qb->getRestrictions()->removeAll(); - $result = $qb->select('uid', 'slug') + $result = $qb->select('uid', 'slug', 'sys_language_uid') ->from('pages') ->execute(); - $pages = $result->fetchAllAssociative(); + + $qb = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_redirect'); + $qb->getRestrictions()->removeAll(); + $result = $qb->select('uid', 'source_path', 'is_regexp') + ->from('sys_redirect') + ->execute(); + $redirects = $result->fetchAllAssociative(); + $mappingPaths = $this->mappingRepository->getAllNonRegexPaths(); $paths = $this->dataProviderService->readJsonData(); @@ -56,20 +63,48 @@ public function execute(InputInterface $input, OutputInterface $output): int continue; } - foreach ($pages as $page) { + foreach ($pages as $key2 => $page) { // no match if ($page['slug'] !== $pathData->data) { continue; } // create mapping - $data['tx_xmgoaccess_domain_model_mapping']['NEW' . $key] = [ + $data['tx_xmgoaccess_domain_model_mapping']['NEW' . $key . $key2] = [ 'pid' => 0, 'path' => $page['slug'], 'record_type' => 0, 'page' => $page['uid'], ]; } + + foreach ($redirects as $key2 => $redirect) { + if (!$redirect['source_path'] || !is_string($redirect['source_path'])) { + continue; + } + + // check regex + if ($redirect['is_regexp']) { + $matchResult = preg_match($redirect['source_path'], $pathData->data, $matches); + if ($matchResult === 0) { + continue; + } + } + + // no match + if (!$redirect['is_regexp'] && $redirect['source_path'] !== $pathData->data) { + continue; + } + + // create mapping + $data['tx_xmgoaccess_domain_model_mapping']['NEW' . $key . $key2] = [ + 'pid' => 0, + 'path' => $pathData->data, + 'record_type' => 3, + 'foreign_uid' => $redirect['uid'], + 'foreign_table' => 'sys_redirect', + ]; + } } if (!count($data['tx_xmgoaccess_domain_model_mapping'])) { diff --git a/Classes/Domain/Model/Dto/Demand.php b/Classes/Domain/Model/Dto/Demand.php index 58309fa0..4863e7eb 100644 --- a/Classes/Domain/Model/Dto/Demand.php +++ b/Classes/Domain/Model/Dto/Demand.php @@ -11,6 +11,7 @@ class Demand public bool $showPages = true; public bool $showActions = true; + public bool $showRedirects = false; public static function createFromRequest(Request $request): self { @@ -31,6 +32,10 @@ public static function createFromRequest(Request $request): self $demand->showActions = false; } + if (isset($postData['showRedirects']) && (int)$postData['showRedirects']) { + $demand->showRedirects = true; + } + return $demand; } } diff --git a/Classes/Service/DataProviderService.php b/Classes/Service/DataProviderService.php index e67150c7..338b41ca 100644 --- a/Classes/Service/DataProviderService.php +++ b/Classes/Service/DataProviderService.php @@ -79,8 +79,6 @@ public function getRequestList(?Demand $demand = null) { $goaccessData = $this->readJsonData(); - $this->mappings = $this->mappingRepository->findAll(); - $items = []; foreach ($goaccessData['requests']->data as $pathData) { @@ -90,18 +88,26 @@ public function getRequestList(?Demand $demand = null) 'hits' => $pathData->hits->count, 'visitors' => $pathData->visitors->count, 'path' => $path, - 'mapping' => $this->resolvePathMapping($path), + 'mappings' => $this->resolvePathMapping($path), ]; - if ($demand && $item['mapping']) { - if (!$demand->showPages && $item['mapping']->getRecordType() === 0) { - continue; + if (!$demand || empty($item['mappings'])) { + $items[] = $item; + continue; + } + + foreach ($item['mappings'] as $mapping) { + if (!$demand->showPages && $mapping->getRecordType() === 0) { + continue 2; } - if (!$demand->showActions && $item['mapping']->getRecordType() === 1) { - continue; + if (!$demand->showActions && $mapping->getRecordType() === 1) { + continue 2; } - if (!$demand->showIgnored && $item['mapping']->getRecordType() === 2) { - continue; + if (!$demand->showIgnored && $mapping->getRecordType() === 2) { + continue 2; + } + if (!$demand->showRedirects && $mapping->getRecordType() === 3) { + continue 2; } } @@ -136,27 +142,31 @@ public function readJsonData(): array return $content ? (array)json_decode($content) : []; } - private function resolvePathMapping(string $path): ?Mapping + /** + * @return Mapping[] + */ + private function resolvePathMapping(string $path): array { - foreach ($this->mappings as $mapping) { + $mappings = []; + foreach ($this->mappingRepository->findAll() as $mapping) { if ($mapping->isRegex()) { preg_match('/' . $mapping->getPath() . '/', $path, $matches); if ($matches) { $this->enrichMapping($mapping); - return $mapping; + $mappings[] = $mapping; } } if (!$mapping->isRegex() && $path === $mapping->getPath()) { $this->enrichMapping($mapping); - return $mapping; + $mappings[] = $mapping; } } - return null; + return $mappings; } - private function enrichMapping(Mapping &$mapping): void + private function enrichMapping(Mapping $mapping): void { if ($mapping->getRecordType() === 0 && $mapping->getPage()) { $pageRecord = BackendUtility::readPageAccess($mapping->getPage(), '1=1'); diff --git a/Configuration/TCA/tx_xmgoaccess_domain_model_mapping.php b/Configuration/TCA/tx_xmgoaccess_domain_model_mapping.php index 3661f262..afe00c2c 100644 --- a/Configuration/TCA/tx_xmgoaccess_domain_model_mapping.php +++ b/Configuration/TCA/tx_xmgoaccess_domain_model_mapping.php @@ -22,6 +22,9 @@ 2 => [ 'showitem' => '--palette--;;pathSettings, record_type', ], + 3 => [ + 'showitem' => '--palette--;;pathSettings, record_type, foreign_table, foreign_uid', + ], ], 'palettes' => [ 'pathSettings' => [ @@ -98,5 +101,17 @@ 'default' => 0, ], ], + 'foreign_uid' => [ + 'label' => 'Foreign UID', + 'config' => [ + 'type' => 'input', + ], + ], + 'foreign_table' => [ + 'label' => 'Foreign table', + 'config' => [ + 'type' => 'input', + ], + ], ], ]; diff --git a/Resources/Private/Templates/Backend/Mappings.html b/Resources/Private/Templates/Backend/Mappings.html index 831b4b24..ba31b568 100644 --- a/Resources/Private/Templates/Backend/Mappings.html +++ b/Resources/Private/Templates/Backend/Mappings.html @@ -1,102 +1,173 @@ -{namespace be=TYPO3\CMS\Backend\ViewHelpers}<h1>Request log</h1> +{namespace be=TYPO3\CMS\Backend\ViewHelpers}<h1>Request log ({requests->f:count()})</h1> <f:form object="{demand}" class="demand-form"> - <div class="d-flex flex-row gap-4 mb-3"> - <div class="form-check form-switch"> - <f:form.checkbox class="form-check-input" - name="showIgnored" - property="showIgnored" - value="1" - id="displayIgnored"/> - <label class="form-check-label" for="displayIgnored"> Show ignored paths</label></div> + <div class="d-flex flex-row gap-4 mb-3"> + <div class="form-check form-switch"> + <f:form.checkbox class="form-check-input" + name="showIgnored" + property="showIgnored" + value="1" + id="displayIgnored" /> + <label class="form-check-label" for="displayIgnored"> Show ignored paths</label> + </div> - <div class="form-check form-switch"> - <f:form.checkbox class="form-check-input" - name="showPages" - property="showPages" - value="1" - id="displayPages"/> - <label class="form-check-label" for="displayPages"> Show page mappings</label> - </div> + <div class="form-check form-switch"> + <f:form.checkbox class="form-check-input" + name="showPages" + property="showPages" + value="1" + id="displayPages" /> + <label class="form-check-label" for="displayPages"> Show page mappings</label> + </div> - <div class="form-check form-switch"> - <f:form.checkbox class="form-check-input" - name="showActions" - property="showActions" - value="1" - id="displayActions"/> - <label class="form-check-label" for="displayActions">Show action mappings </label> - </div> - </div> + <div class="form-check form-switch"> + <f:form.checkbox class="form-check-input" + name="showActions" + property="showActions" + value="1" + id="displayActions" /> + <label class="form-check-label" for="displayActions">Show action mappings</label> + </div> + + <div class="form-check form-switch"> + <f:form.checkbox class="form-check-input" + name="showRedirects" + property="showRedirects" + value="1" + id="displayRedirects" /> + <label class="form-check-label" for="displayRedirects">Show redirect mappings</label> + </div> + </div> </f:form> -<f:variable name="returnUrl" value="{f:be.uri(route: 'system_XmGoaccessGoaccess')}"/> +<f:variable name="returnUrl" value="{f:be.uri(route: 'system_XmGoaccessGoaccess')}" /> <table data-table="requests" class="table table-striped table-hover mb-0"> - <thead> - <tr> - <th>Besucher</th> - <th>Anfragen</th> - <th>Path</th> - <th>Mappings</th> - <th></th> - </tr> - </thead> - <tbody data-multi-record-selection-row-selection="true"> - <f:for each="{requests}" as="request"> - <tr> - <td>{request.visitors}</td> - <td>{request.hits}</td> - <td> - <f:if condition="{request.mapping}"> - <f:then> - <be:link.editRecord uid="{request.mapping.uid}" - table="tx_xmgoaccess_domain_model_mapping" - returnUrl="{returnUrl}"> - {request.path} - </be:link.editRecord> - </f:then> - <f:else> - <be:link.newRecord defaultValues="{tx_xmgoaccess_domain_model_mapping: {path:request.path}}" - table="tx_xmgoaccess_domain_model_mapping" - returnUrl="{returnUrl}">{request.path} - </be:link.newRecord> - </f:else> - </f:if> - </td> - <td class="nowrap"> - <f:if condition="{request.mapping}"> - <f:if condition="{request.mapping.iconMarkup}"> - {request.mapping.iconMarkup->f:format.raw()} - </f:if> - <f:if condition="{request.mapping.pagePath}"> - <f:be.link route="web_layout" parameters="{id: request.mapping.page}"> - {request.mapping.pagePath} - </f:be.link> - </f:if> - </f:if> - </td> - <td> - <f:if condition="{request.mapping}"> - <f:then> - <be:link.editRecord uid="{request.mapping.uid}" - table="tx_xmgoaccess_domain_model_mapping" - returnUrl="{returnUrl}" - class="btn btn-default btn-sm"> - <core:icon identifier="actions-open" size="small"/> - </be:link.editRecord> - </f:then> - <f:else> - <be:link.newRecord defaultValues="{tx_xmgoaccess_domain_model_mapping: {path:request.path}}" - table="tx_xmgoaccess_domain_model_mapping" - class="btn btn-default btn-sm" - returnUrl="{returnUrl}"> - <core:icon identifier="actions-add" size="small"/> - </be:link.newRecord> - </f:else> - </f:if> - </td> - </tr> - </f:for> - </tbody> + <thead> + <tr> + <th>Besucher</th> + <th>Anfragen</th> + <th>Path</th> + <f:if condition="{demand.showPages}"> + <th>Page</th> + </f:if> + <f:if condition="{demand.showRedirects}"> + <th>Redirect</th> + </f:if> + <f:if condition="{demand.showActions}"> + <th>Action</th> + </f:if> + <f:if condition="{demand.showIgnored}"> + <th>Ignored</th> + </f:if> + <th></th> + </tr> + </thead> + <tbody data-multi-record-selection-row-selection="true"> + <f:for each="{requests}" as="request"> + <tr> + <td>{request.visitors}</td> + <td>{request.hits}</td> + <td> + <f:if condition="{request.mapping}"> + <f:then> + <be:link.editRecord uid="{request.mapping.uid}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}"> + {request.path} + </be:link.editRecord> + </f:then> + <f:else> + <be:link.newRecord defaultValues="{tx_xmgoaccess_domain_model_mapping: {path:request.path}}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}">{request.path} + </be:link.newRecord> + </f:else> + </f:if> + </td> + <f:if condition="{demand.showPages}"> + <td class="nowrap"> + <f:for each="{request.mappings}" as="mapping"> + <f:if condition="{mapping.recordType} === 0"> + <be:link.editRecord uid="{mapping.uid}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}" + class="btn btn-default btn-sm"> + <f:if condition="{mapping.iconMarkup}"> + {mapping.iconMarkup->f:format.raw()} + </f:if> + <f:if condition="{mapping.pagePath}"> + {mapping.pagePath} + </f:if> + </be:link.editRecord> + <f:be.link route="web_layout" + parameters="{id: mapping.page}" + class="btn btn-default btn-sm"> + <core:icon identifier="actions-window-open" size="small" /> + </f:be.link> + </f:if> + </f:for> + </td> + </f:if> + <f:if condition="{demand.showRedirects}"> + <td class="nowrap"> + <f:for each="{request.mappings}" as="mapping"> + <f:if condition="{mapping.recordType} === 3"> + <be:link.editRecord uid="{mapping.uid}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}" + class="btn btn-default btn-sm"> + <core:icon identifier="mimetypes-x-sys_redirect" size="small" /> Redirect {mapping.uid} + </be:link.editRecord> + </f:if> + </f:for> + </td> + </f:if> + <f:if condition="{demand.showActions}"> + <td class="nowrap"> + <f:for each="{request.mappings}" as="mapping"> + <f:if condition="{mapping.recordType} === 1"> + <be:link.editRecord uid="{mapping.uid}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}" + class="btn btn-default btn-sm"> + <core:icon identifier="actions-bolt" /> + {mapping.title} + </be:link.editRecord> + </f:if> + </f:for> + </td> + </f:if> + <f:if condition="{demand.showIgnored}"> + <td class="nowrap"> + <f:for each="{request.mappings}" as="mapping"> + <f:if condition="{mapping.recordType} === 2"> + <core:icon identifier="apps-pagetree-drag-place-denied" size="small" /> + </f:if> + </f:for> + </td> + </f:if> + <td> + <f:if condition="{request.mapping}"> + <f:then> + <be:link.editRecord uid="{request.mapping.uid}" + table="tx_xmgoaccess_domain_model_mapping" + returnUrl="{returnUrl}" + class="btn btn-default btn-sm"> + <core:icon identifier="actions-open" size="small" /> + </be:link.editRecord> + </f:then> + <f:else> + <be:link.newRecord defaultValues="{tx_xmgoaccess_domain_model_mapping: {path:request.path}}" + table="tx_xmgoaccess_domain_model_mapping" + class="btn btn-default btn-sm" + returnUrl="{returnUrl}"> + <core:icon identifier="actions-add" size="small" /> + </be:link.newRecord> + </f:else> + </f:if> + </td> + </tr> + </f:for> + </tbody> </table> \ No newline at end of file diff --git a/ext_tables.sql b/ext_tables.sql index 73ba943a..038e6a97 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -2,6 +2,8 @@ create table tx_xmgoaccess_domain_model_mapping ( path varchar(255) not null default '', record_type int(11) unsigned default '0' not null, page int(11) unsigned default '0' not null, + foreign_uid int(11) unsigned default '0' not null, + foreign_table varchar(255) not null default '', regex tinyint(4) unsigned default '0' not null, title varchar(255) not null default '', );