Bläddra i källkod

add the ot_optimizer extension

Olivier Massot 5 år sedan
förälder
incheckning
5cafd117a1

+ 213 - 0
ot_optimizer/Classes/Routing/OtPageRouter.php

@@ -0,0 +1,213 @@
+<?php
+namespace Opentalent\OtOptimizer\Routing;
+
+use Doctrine\DBAL\Connection;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction;
+use TYPO3\CMS\Core\Exception\SiteNotFoundException;
+use TYPO3\CMS\Core\Routing\PageRouter;
+use TYPO3\CMS\Core\Routing\SiteMatcher;
+use TYPO3\CMS\Core\Site\Entity\Site;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Page\PageRepository;
+
+/**
+ * Override the default core PageRouter of typo3 to exclude the pages
+ * which do not belong to the current website
+ *
+ * @see https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Xclasses/Index.html
+ * @package Opentalent\OtOptimizer\Routing
+ */
+class OtPageRouter extends PageRouter
+{
+    /**
+     * special: patch 2020-09-22 by Opentalent, for performances reason
+     * Returns an array containing all the subpages'uids, including the given $pageId
+     * >> made for typo3 v9.5
+     *
+     * @param int $pageId
+     * @return array|int[]
+     */
+    private function getAllSubpagesUidFor(int $pageId) {
+        $subpages = [$pageId];
+
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
+        $queryBuilder
+            ->getRestrictions()
+            ->removeAll()
+            ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+
+        $queryBuilder
+            ->select('uid')
+            ->from('pages')
+            ->where(
+                $queryBuilder->expr()->eq('pid', (int)$pageId)
+            );
+
+        $statement = $queryBuilder->execute();
+
+        while ($row = $statement->fetch()) {
+            $subpages = array_merge($subpages, $this->getAllSubpagesUidFor($row['uid']));
+        }
+
+        return $subpages;
+    }
+
+    /**
+     * -- Override the original method from the typo3 PageRouter --
+     * Check for records in the database which matches one of the slug candidates.
+     *
+     * @param array $slugCandidates
+     * @param int $languageId
+     * @param array $excludeUids when called recursively this is the mountpoint parameter of the original prefix
+     * @return array
+     */
+    protected function getPagesFromDatabaseForCandidates(array $slugCandidates, int $languageId, array $excludeUids = []): array
+    {
+        $context = GeneralUtility::makeInstance(Context::class);
+        $searchLiveRecordsOnly = $context->getPropertyFromAspect('workspace', 'isLive');
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable('pages');
+        $queryBuilder
+            ->getRestrictions()
+            ->removeAll()
+            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
+            ->add(GeneralUtility::makeInstance(FrontendWorkspaceRestriction::class, null, null, $searchLiveRecordsOnly));
+
+        $statement = $queryBuilder
+            ->select('uid', 'l10n_parent', 'pid', 'slug', 'mount_pid', 'mount_pid_ol', 't3ver_state', 'doktype', 't3ver_wsid', 't3ver_oid')
+            ->from('pages')
+            ->where(
+                $queryBuilder->expr()->eq(
+                    'sys_language_uid',
+                    $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
+                ),
+                $queryBuilder->expr()->in(
+                    'slug',
+                    $queryBuilder->createNamedParameter(
+                        $slugCandidates,
+                        Connection::PARAM_STR_ARRAY
+                    )
+                )
+            )
+            // Exact match will be first, that's important
+            ->orderBy('slug', 'desc')
+            // Sort pages that are not MountPoint pages before mount points
+            ->addOrderBy('mount_pid_ol', 'asc')
+            ->addOrderBy('mount_pid', 'asc')
+            ->execute();
+        $isRecursiveCall = !empty($excludeUids);
+
+        $pages = [];
+        $siteMatcher = GeneralUtility::makeInstance(SiteMatcher::class);
+        $pageRepository = GeneralUtility::makeInstance(PageRepository::class, $context);
+
+        // <----
+        // special: patch 2020-09-22 by Opentalent, for performances reason
+        // >> made for typo3 v10.4.8
+        $siteRootPageUid = $this->site->getRootPageId();
+        $sitePages = $this->getAllSubpagesUidFor($siteRootPageUid);
+        // ---->
+
+        while ($row = $statement->fetch()) {
+            $mountPageInformation = null;
+            $pageRepository->fixVersioningPid('pages', $row);
+            $pageIdInDefaultLanguage = (int)($languageId > 0 ? $row['l10n_parent'] : $row['uid']);
+            // When this page was added before via recursion, this page should be skipped
+            if (in_array($pageIdInDefaultLanguage, $excludeUids, true)) {
+                continue;
+            }
+
+            // <----
+            // special: patch 2020-09-22 by Opentalent, for performances reason
+            // >> made for typo3 v10.4.8
+            if (!in_array($pageIdInDefaultLanguage, $sitePages)) {
+                continue;
+            }
+            // ---->
+
+            try {
+                $isOnSameSite = $siteMatcher->matchByPageId($pageIdInDefaultLanguage)->getRootPageId() === $this->site->getRootPageId();
+            } catch (SiteNotFoundException $e) {
+                // Page is not in a site, so it's not considered
+                $isOnSameSite = false;
+            }
+
+            // If a MountPoint is found on the current site, and it hasn't been added yet by some other iteration
+            // (see below "findPageCandidatesOfMountPoint"), then let's resolve the MountPoint information now
+            if (!$isOnSameSite && $isRecursiveCall) {
+                // Not in the same site, and called recursive, should be skipped
+                continue;
+            }
+            $mountPageInformation = $pageRepository->getMountPointInfo($pageIdInDefaultLanguage, $row);
+            // Mount Point Pages which are not on the same site (when not called on the first level) should be skipped
+            // As they just clutter up the queries.
+            if (!$isOnSameSite && !$isRecursiveCall && $mountPageInformation) {
+                continue;
+            }
+            $mountedPage = null;
+            if ($mountPageInformation) {
+                // Add the MPvar to the row, so it can be used later-on in the PageRouter / PageArguments
+                $row['MPvar'] = $mountPageInformation['MPvar'];
+                $mountedPage = $pageRepository->getPage_noCheck($mountPageInformation['mount_pid_rec']['uid']);
+                // Ensure to fetch the slug in the translated page
+                $mountedPage = $pageRepository->getPageOverlay($mountedPage, $languageId);
+                // Mount wasn't connected properly, so it is skipped
+                if (!$mountedPage) {
+                    continue;
+                }
+                // If the page is a MountPoint which should be overlaid with the contents of the mounted page,
+                // it must never be accessible directly, but only in the MountPoint context. Therefore we change
+                // the current ID and slug.
+                // This needs to happen before the regular case, as the $pageToAdd contains the MPvar information
+                if (PageRepository::DOKTYPE_MOUNTPOINT === (int)$row['doktype'] && $row['mount_pid_ol']) {
+                    // If the mounted page was already added from above, this should not be added again (to include
+                    // the mount point parameter).
+                    if (in_array((int)$mountedPage['uid'], $excludeUids, true)) {
+                        continue;
+                    }
+                    $pageToAdd = $mountedPage;
+                    // Make sure target page "/about-us" is replaced by "/global-site/about-us" so router works
+                    $pageToAdd['MPvar'] = $mountPageInformation['MPvar'];
+                    $pageToAdd['slug'] = $row['slug'];
+                    $pages[] = $pageToAdd;
+                    $excludeUids[] = (int)$pageToAdd['uid'];
+                    $excludeUids[] = $pageIdInDefaultLanguage;
+                }
+            }
+
+            // This is the regular "non-MountPoint page" case (must happen after the if condition so MountPoint
+            // pages that have been replaced by the Mounted Page will not be added again.
+            if ($isOnSameSite && !in_array($pageIdInDefaultLanguage, $excludeUids, true)) {
+                $pages[] = $row;
+                $excludeUids[] = $pageIdInDefaultLanguage;
+            }
+
+            // Add possible sub-pages prepended with the MountPoint page slug
+            if ($mountPageInformation) {
+                $siteOfMountedPage = $siteMatcher->matchByPageId((int)$mountedPage['uid']);
+                if ($siteOfMountedPage instanceof Site) {
+                    $morePageCandidates = $this->findPageCandidatesOfMountPoint(
+                        $row,
+                        $mountedPage,
+                        $siteOfMountedPage,
+                        $languageId,
+                        $slugCandidates,
+                        $context
+                    );
+                    foreach ($morePageCandidates as $candidate) {
+                        // When called previously this MountPoint page should be skipped
+                        if (in_array((int)$candidate['uid'], $excludeUids, true)) {
+                            continue;
+                        }
+                        $pages[] = $candidate;
+                    }
+                }
+            }
+        }
+        return $pages;
+    }
+
+}

+ 6 - 0
ot_optimizer/Readme.md

@@ -0,0 +1,6 @@
+# OtOptimizer
+
+Optimize the Typo3 FE and BE behaviour for large amounts of sites
+
+> IMPORTANT: This extension only aims to improve performances. If disabled, it shall not 
+> cause more than performances losses. We need to be able to disable it anytime without other consequences.

BIN
ot_optimizer/Resources/Public/Icons/Extension.png


+ 28 - 0
ot_optimizer/composer.json

@@ -0,0 +1,28 @@
+{
+    "name": "opentalent/ot-optimizer",
+    "type": "typo3-cms-extension",
+    "description": "Optimize the Typo3 FE and BE behaviour for large amount of sites",
+    "authors": [
+        {
+            "name": "Olivier Massot",
+            "role": "Developer"
+        }
+    ],
+    "require": {
+        "typo3/cms-core": "^9.5"
+    },
+    "autoload": {
+        "psr-4": {
+            "Opentalent\\OtOptimizer\\": "Classes"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Opentalent\\OtOptimizer\\Tests\\": "Tests"
+        }
+    },
+    "replace": {
+        "ot_connect": "self.version",
+        "typo3-ter/ot-optimize": "self.version"
+    }
+}

+ 29 - 0
ot_optimizer/ext_emconf.php

@@ -0,0 +1,29 @@
+<?php
+
+/***************************************************************
+ * Extension Manager/Repository config file for ext: "ot_optimizer"
+ *
+ * Manual updates:
+ * Only the data in the array - anything else is removed by next write.
+ * "version" and "dependencies" must not be touched!
+ ***************************************************************/
+
+$EM_CONF[$_EXTKEY] = [
+    'title' => 'Optimizer',
+    'description' => 'Optimize the Typo3 FE and BE behaviour for large amount of sites',
+    'category' => 'services',
+    'author' => 'Olivier Massot',
+    'author_email' => 'olivier.massot@2iopenservice.fr',
+    'state' => 'alpha',
+    'uploadfolder' => 0,
+    'createDirs' => '',
+    'clearCacheOnLoad' => 0,
+    'version' => '0.1.0',
+    'constraints' => [
+        'depends' => [
+            'typo3' => '8.7.0-10.4.99',
+        ],
+        'conflicts' => [],
+        'suggests' => [],
+    ],
+];

+ 6 - 0
ot_optimizer/ext_localconf.php

@@ -0,0 +1,6 @@
+<?php
+defined('TYPO3_MODE') || die();
+
+$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][TYPO3\CMS\Core\Routing\PageRouter::class] = [
+    'className' => Opentalent\OtOptimizer\Routing\OtPageRouter::class
+];