Преглед изворни кода

setup route indexing commands and basic resolver

Olivier Massot пре 4 година
родитељ
комит
e3ca61abcc

+ 103 - 0
ot_admin/Classes/Command/UpdateRoutingIndexCommand.php

@@ -0,0 +1,103 @@
+<?php
+
+namespace Opentalent\OtAdmin\Command;
+
+
+use Opentalent\OtAdmin\Controller\SiteController;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+
+/**
+ * This CLI command updates the routing index for the given website
+ *
+ * @package Opentalent\OtAdmin\Command
+ */
+class UpdateRoutingIndexCommand extends Command
+{
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * Allows to configure the command.
+     * Allows to add a description, a help text, and / or define arguments.
+     *
+     */
+    protected function configure()
+    {
+        $this
+            ->setName("ot:site:index")
+            ->setDescription("Update the routes index for the given website(s)")
+            ->setHelp("This CLI command updates the routing index for the given website")
+            ->addOption(
+                'all',
+                null,
+                InputOption::VALUE_NONE,
+                "Update all of the organization websites"
+            )
+            ->addArgument(
+                'organization-id',
+                InputArgument::OPTIONAL,
+                "The organization's id in the opentalent DB"
+            );
+    }
+
+    /**
+     * -- This method is expected by Typo3, do not rename ou remove --
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @throws \Exception
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $org_id = $input->getArgument('organization-id');
+        $all = $input->getOption('all');
+
+        if ($all && $org_id) {
+            throw new \InvalidArgumentException("You can not pass both an organization id and the --all option");
+        }
+        if (!$all && !$org_id) {
+            throw new \InvalidArgumentException("You shall either pass an organization id or use the --all option");
+        }
+
+        $io = new SymfonyStyle($input, $output);
+
+        $siteController = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
+
+        if ($all) {
+            $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
+            $queryBuilder = $connectionPool->getQueryBuilderForTable('pages');
+            $sites = $queryBuilder
+                ->select('tx_opentalent_structure_id')
+                ->from('pages')
+                ->where('is_siteroot=1')
+                ->andWhere($queryBuilder->expr()->gt('tx_opentalent_structure_id', 0))
+                ->execute()
+                ->fetchAll();
+
+            $io->progressStart(count($sites));
+
+            foreach ($sites as $site) {
+                $org_id = $site['tx_opentalent_structure_id'];
+                try {
+                    $siteController->updateRoutingIndexAction($org_id);
+                } catch (\Throwable $e) {
+                    $io->error('Organization Id: ' . $org_id . ' - ' . $e->getMessage());
+                }
+                $io->progressAdvance(1);
+            }
+            $io->progressFinish();
+
+            $io->success(sprintf("The routing index has all been fully updated"));
+        } else {
+            $rootUid = $siteController->updateRoutingIndexAction($org_id);
+            $io->success(sprintf("The website with root uid " . $rootUid . " routing index has been updated"));
+        }
+    }
+}

+ 17 - 1
ot_admin/Classes/Controller/SiteController.php

@@ -13,6 +13,7 @@ use Opentalent\OtCore\Domain\Model\Organization;
 use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
 use Opentalent\OtCore\Exception\ApiRequestException;
 use Opentalent\OtCore\Utility\FileUtility;
+use Opentalent\OtRouter\Routing\Indexer;
 use PDO;
 use Symfony\Component\Yaml\Yaml;
 use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
@@ -691,7 +692,8 @@ class SiteController extends ActionController
             }
 
             // ## Reset the routing index
-            // TODO: complete
+            $routingIndexer = GeneralUtility::makeInstance(ObjectManager::class)->get(Indexer::class);
+            $routingIndexer->indexRoutesForWebsite($rootUid);
 
             // Try to commit the result
             $commitSuccess = $this->connectionPool->getConnectionByName('Default')->commit();
@@ -1683,6 +1685,20 @@ class SiteController extends ActionController
         }
     }
 
+    /**
+     * Update the routing index for the given website
+     *
+     * @param int $organizationId
+     * @throws NoSuchWebsiteException
+     */
+    public function updateRoutingIndexAction(int $organizationId)
+    {
+        $rootUid = $this->findRootUidFor($organizationId);
+
+        $routingIndexer = GeneralUtility::makeInstance(ObjectManager::class)->get(Indexer::class);
+        $routingIndexer->indexRoutesForWebsite($rootUid);
+    }
+
     /**
      * Retrieve the Organization object from the repository and then,
      * from the Opentalent API

+ 28 - 1
ot_admin/Classes/Http/ApiController.php

@@ -298,7 +298,6 @@ class ApiController implements LoggerAwareInterface
         );
     }
 
-
     /**
      * -- Target of the route 'site_resetperms' --
      * >> Requires a query param named 'organization-id' (int)
@@ -327,6 +326,34 @@ class ApiController implements LoggerAwareInterface
         );
     }
 
+    /**
+     * -- Target of the route 'site_reindex' --
+     * >> Requires a query param named 'organization-id' (int)
+     *
+     * Update the routing index for the given website
+     *
+     * @param ServerRequest $request
+     * @return JsonResponse
+     * @throws \Exception
+     */
+    public function updateRoutingIndexAction(ServerRequest $request): JsonResponse
+    {
+        $this->assertIpAllowed();
+
+        $organizationId = $this->getOrganizationId($request);
+
+        $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
+        $rootUid = $controller->updateRoutingIndexAction($organizationId);
+
+        return new JsonResponse(
+            [
+                'organization_id' => $organizationId,
+                'msg' => "The website with root uid " . $rootUid . " routing index has been updated",
+                'root_uid' => $rootUid
+            ]
+        );
+    }
+
     /**
      * -- Target of the route 'site_status' --
      * >> Requires a query param named 'organization-id' (int)

+ 5 - 0
ot_admin/Configuration/Backend/Routes.php

@@ -42,6 +42,11 @@ return [
         'target' => ApiController::class . '::resetBeUserPermsAction',
         'access' => 'public'
     ],
+    'site_index' => [
+        'path' => '/otadmin/site/index',
+        'target' => ApiController::class . '::updateRoutingIndexAction',
+        'access' => 'public'
+    ],
     'site_status' => [
         'path' => '/otadmin/site/status',
         'target' => ApiController::class . '::getSiteStatusAction',

+ 3 - 0
ot_admin/Configuration/Commands.php

@@ -31,6 +31,9 @@ return [
     'ot:site:reset-perms' => [
         'class' => Opentalent\OtAdmin\Command\ResetBeUserPermsCommand::class
     ],
+    'ot:site:index' => [
+        'class' => Opentalent\OtAdmin\Command\UpdateRoutingIndexCommand::class
+    ],
     'ot:site:status' => [
         'class' => Opentalent\OtAdmin\Command\GetSiteStatusCommand::class
     ],

+ 6 - 0
ot_admin/Configuration/Services.yaml

@@ -43,6 +43,12 @@ services:
         command: 'ot:site:reset-perms'
         schedulable: true
 
+  Opentalent\OtAdmin\Command\UpdateRoutingIndexCommand:
+    tags:
+      - name: 'ot:site:index'
+        command: 'ot:site:index'
+        schedulable: true
+
   Opentalent\OtAdmin\Command\GetSiteStatusCommand:
     tags:
       - name: 'ot:site:status'

+ 3 - 1
ot_admin/Readme.md

@@ -9,7 +9,9 @@ This extension provides commands available by the API, CLI, or a dedicated admin
 | Vendor | Opentalent |
 | Nom | OtAdmin |
 
-> Warning: this extension depends on the ot_templating extension
+**IMPORTANT**:
+
+* Cette extension dépend de l'extension OtRouter
 
 ## CLI
 

+ 0 - 2
ot_core/Readme.md

@@ -15,8 +15,6 @@ Cette extension fournit de nombreuses classes et ressources communes aux autres
 
 * Cette extension ne doit dépendre d'aucune autre pour fonctionner, c'est à dire que son fonctionnement ne doit 
 pas être modifié si aucune autre extension n'est installée
-* Cette extension est aussi la seule dont les autres extensions doivent pouvoir dépendre
-
 
 ### Pour lancer les tests unitaires:
 

+ 0 - 58
ot_router/Classes/Indexer/RoutingIndexer.php

@@ -1,58 +0,0 @@
-<?php
-
-namespace Opentalent\OtRouter\Controller;
-
-use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
-use Opentalent\OtCore\Page\OtPageRepository;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-
-/**
- * Provides methods to index the Typo3 pages and populate the routing db table
- *
- * @package Opentalent\OtRouter\Controller
- */
-class RoutingIndexer
-{
-    const INDEX_TABLENAME = 'tx_opentalent_router';
-
-    /**
-     * @var ConnectionPool
-     */
-    private ConnectionPool $connectionPool;
-
-    public function injectConnectionPool(ConnectionPool $connectionPool)
-    {
-        $this->connectionPool = $connectionPool;
-    }
-
-    /**
-     * @var OtPageRepository
-     */
-    protected OtPageRepository $otPageRepository;
-
-    public function injectOtPageRepository(OtPageRepository $otPageRepository) {
-        $this->otPageRepository = $otPageRepository;
-    }
-
-    protected OrganizationRepository $organizationRepository;
-
-    public function injectOrganizationRepository(OrganizationRepository $organizationRepository) {
-        $this->organizationRepository = $organizationRepository;
-    }
-
-    /**
-     * Clear then repopulate the whole index
-     */
-    public function indexAllRoutes() {
-
-    }
-
-    /**
-     * Clear and recreate the index entry for the target website organization
-     *
-     * @param int $organizationId
-     */
-    public function indexRoutesFor(int $organizationId) {
-
-    }
-}

+ 9 - 2
ot_router/Classes/Middleware/Router.php

@@ -1,11 +1,13 @@
 <?php
 namespace Opentalent\OtRouter\Middleware;
 
+use Opentalent\OtRouter\Routing\Resolver;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
-use TYPO3\CMS\Core\Http\RedirectResponse;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
 
 /**
  * Hooks into the frontend request and use the index table to resolve a page uid
@@ -24,7 +26,12 @@ class Router implements MiddlewareInterface
     {
         $uri = $request->getUri();
 
-        
+        $resolver = GeneralUtility::makeInstance(ObjectManager::class)->get(Resolver::class);
+
+        $pageUid = $resolver->getPageUid(
+            $uri->getHost(),
+            $uri->getPath(),
+        );
 
         // just pass the plate to the next middleware...
         return $handler->handle($request);

+ 106 - 0
ot_router/Classes/Routing/Indexer.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace Opentalent\OtRouter\Routing;
+
+use Opentalent\OtCore\Page\OtPageRepository;
+use Opentalent\OtRouter\Utility\RouteNormalizer;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+
+/**
+ * Provides methods to index the Typo3 pages and populate the routing db table
+ *
+ * @package Opentalent\OtRouter\Routing
+ */
+class Indexer
+{
+    const INDEX_TABLENAME = 'tx_opentalent_router';
+
+    /**
+     * @var ConnectionPool
+     */
+    private ConnectionPool $connectionPool;
+
+    public function injectConnectionPool(ConnectionPool $connectionPool)
+    {
+        $this->connectionPool = $connectionPool;
+    }
+
+    /**
+     * @var OtPageRepository
+     */
+    protected OtPageRepository $otPageRepository;
+
+    public function injectOtPageRepository(OtPageRepository $otPageRepository) {
+        $this->otPageRepository = $otPageRepository;
+    }
+
+    /**
+     * Clear then repopulate the whole index
+     */
+    public function indexAllRoutes() {
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable('pages');
+        $rootPages = $queryBuilder
+            ->select('uid')
+            ->from('pages')
+            ->where($queryBuilder->expr()->eq('is_siteroot', 1))
+            ->execute()
+            ->fetchAll();
+
+        foreach ($rootPages as $rootPage) {
+            $this->indexRoutesForWebsite($rootPage);
+        }
+    }
+
+    /**
+     * Clear and recreate the index entry for the target website
+     *
+     * @param int $rootUid
+     */
+    public function indexRoutesForWebsite(int $rootUid) {
+        foreach ($this->otPageRepository->getAllSitePages($rootUid) as $page) {
+            $this->registerIndexEntry(
+                $page['uid'],
+                $page['tx_opentalent_structure_domain'],
+                $page['slug'],
+                $rootUid
+            );
+        }
+    }
+
+    public function indexRouteForPage(int $pageUid) {
+        $page = $this->otPageRepository->getPage($pageUid);
+        $rootPage = $this->otPageRepository->getRootPageFor($pageUid);
+
+        $this->registerIndexEntry(
+            $page['uid'],
+            $page['tx_opentalent_structure_domain'],
+            $page['slug'],
+            $rootPage['uid']
+        );
+    }
+
+    private function registerIndexEntry(int $pageUid,
+                                      string $domain,
+                                      string $slug,
+                                      ?int $rootUid = null) {
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::INDEX_TABLENAME);
+        $queryBuilder
+            ->delete(self::INDEX_TABLENAME)
+            ->where($queryBuilder->expr()->eq('page_uid', $pageUid))
+            ->execute();
+
+        $entry = [
+            'domain' => RouteNormalizer::normalizeDomain($domain),
+            'root_uid' => $rootUid,
+            'slug' => RouteNormalizer::normalizeSlug($slug),
+            'page_uid' => $pageUid,
+            'last_update' => date('Y-m-d H:i:s')
+        ];
+
+        $queryBuilder = $this->connectionPool->getQueryBuilderForTable(self::INDEX_TABLENAME);
+        $queryBuilder
+            ->insert(self::INDEX_TABLENAME)
+            ->values($entry)
+            ->execute();
+    }
+}

+ 0 - 3
ot_router/Readme.md

@@ -8,9 +8,6 @@ Bypass the builtin Typo3 routing with dedicated router adapted to a large amount
 | Vendor | Opentalent |
 | Nom | OtRouter |
 
-> **IMPORTANT**: This extension only aims to improve performances. **If disabled, it shall not 
-> cause anything else than performances losses**. We need to be able to disable it anytime without other consequences.
-
 Cette extension implémente un système de routing basé sur un index des pages sous forme de table additionnelle dans la
 base de données.
 

+ 4 - 4
ot_router/composer.json

@@ -13,16 +13,16 @@
     },
     "autoload": {
         "psr-4": {
-            "Opentalent\\OtOptimizer\\": "Classes"
+            "Opentalent\\OtRouter\\": "Classes"
         }
     },
     "autoload-dev": {
         "psr-4": {
-            "Opentalent\\OtOptimizer\\Tests\\": "Tests"
+            "Opentalent\\OtRouter\\Tests\\": "Tests"
         }
     },
     "replace": {
-        "ot_optimizer": "self.version",
-        "typo3-ter/ot-optimizer": "self.version"
+        "ot_router": "self.version",
+        "typo3-ter/ot-router": "self.version"
     }
 }

+ 2 - 2
ot_router/ext_tables.sql

@@ -4,12 +4,12 @@
 # Table structure for table 'tx_opentalent_router'
 #
 CREATE TABLE tx_opentalent_router (
-    uid INT UNSIGNED NOT NULL,
+    uid INT UNSIGNED NOT NULL AUTO_INCREMENT,
     domain VARCHAR(2048) NOT NULL,
     root_uid INT UNSIGNED NOT NULL,
-    structure_id INT UNSIGNED NOT NULL,
     slug VARCHAR(2048) NOT NULL,
     page_uid INT UNSIGNED NOT NULL,
     last_update DATETIME NOT NULL,
     PRIMARY KEY (uid)
 );
+