Skip to content

Make extension compatible with TYPO3 10 #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\ReferenceIndex;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\CommandController;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
* Async Reference Index Commands
Expand All @@ -15,33 +19,48 @@
* based on the queue maintained by the DataHandler
* override shipped with this extension.
*/
class AsyncReferenceIndexCommandController extends CommandController
class AsyncReferenceIndexCommand extends Command
{
use ReferenceIndexQueueAware;

const LOCKFILE = 'typo3temp/var/reference-indexing-running.lock';

/**
* Configure the asynchronous reference indexing command
*/
protected function configure()
{
$this->setDescription('Update the reference index');
$this->addOption('force', 'f', InputOption::VALUE_NONE, 'Index directly to sys_refindex without asynchronous indexing');
$this->addOption('check', 'c', InputOption::VALUE_NONE, 'Check reference index without modification if indexing directly to sys_refindex');
$this->addOption('silent', 's', InputOption::VALUE_NONE, 'Suppress output if indexing directly to sys_refindex');
}

/**
* Update Reference Index
*
* Updates the reference index - if providing the -f parameter the
* indexing will index directly to sys_refindex - else the
* Updates the reference index - if providing the --force option the
* indexing will index directly to sys_refindex, additional --check
* option will only check sys_refindex without modification, --silent
* option will suppress output
*
* @param boolean $force
* @param boolean $check
* @param boolean $silent
* @param InputInterface $input
* @param OutputInterface $output
*
* @return void
*/
public function updateCommand($force = false, $check = false, $silent = false) {
if ($force) {
protected function execute(InputInterface $input, OutputInterface $output) {
if ($input->getOption('force')) {
AsyncReferenceIndex::captureReferenceIndex(false);
$refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
$refIndexObj->updateIndex($check, !$silent);
$refIndexObj->updateIndex($input->getOption('check'), !$input->getOption('silent'));
}
else {
$this->updateReferenceIndex();
$io = new SymfonyStyle($input, $output);
$io->title($this->getDescription());
$this->updateReferenceIndex($io);
}
return 0;
}

/**
Expand All @@ -51,27 +70,28 @@ public function updateCommand($force = false, $check = false, $silent = false) {
* processing the queue maintained by
* the overridden DataHandler class.
*
* @param SymfonyStyle $io
* @return void
*/
protected function updateReferenceIndex()
protected function updateReferenceIndex(SymfonyStyle $io)
{
$lockFile = GeneralUtility::getFileAbsFileName(static::LOCKFILE);
if (file_exists($lockFile)) {
$this->response->setContent('Another process is updating the reference index - skipping' . PHP_EOL);
$io->writeln('Another process is updating the reference index - skipping');
return;
}

$count = $this->performCount('tx_asyncreferenceindexing_queue');

if (!$count) {
$this->response->setContent('No reference indexing tasks queued - nothing to do.' . PHP_EOL);
$io->writeln('No reference indexing tasks queued - nothing to do.');
return;
}

$this->lock();

$this->response->setContent(
'Processing reference index for ' . $count . ' record(s)' . PHP_EOL
$io->writeln(
'Processing reference index for ' . $count . ' record(s)'
);

// Note about loop: a fresh instance of ReferenceIndex is *intentional*. The class mutates
Expand Down Expand Up @@ -102,12 +122,12 @@ protected function updateReferenceIndex()
);

}
$this->response->appendContent('Reference indexing complete!' . PHP_EOL);
$io->writeln('Reference indexing complete!');
$this->unlock();

} catch (\Exception $error) {

$this->response->appendContent('ERROR! ' . $error->getMessage() . ' (' . $error->getCode() . ')' . PHP_EOL);
$io->writeln('ERROR! ' . $error->getMessage() . ' (' . $error->getCode() . ')');
$this->unlock();

}
Expand Down
2 changes: 1 addition & 1 deletion Classes/DataHandling/DataHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* Override of core's DataHandler to remove capability to do on-the-fly
* reference indexing, instead delegating that task to the provided
* command controller. The command controller can be used directly from
* Symfony Console Command. The command can be used directly from
* CLI, put into crontab or via the Scheduler system extension.
*
* The runs can be scheduled as frequently as desired. Indexing will only
Expand Down
2 changes: 1 addition & 1 deletion Classes/Database/ReferenceIndex.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* Override of core's DataHandler to remove capability to do on-the-fly
* reference indexing, instead delegating that task to the provided
* command controller. The command controller can be used directly from
* Symfony Console Command. The command can be used directly from
* CLI, put into crontab or via the Scheduler system extension.
*
* The runs can be scheduled as frequently as desired. Indexing will only
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
namespace NamelessCoder\AsyncReferenceIndexing\EventListener;

use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;

/**
* Class IsTableExcludedFromReferenceIndexEventListener
*
*/
class IsTableExcludedFromReferenceIndexEventListener
{
public function __invoke(IsTableExcludedFromReferenceIndexEvent $event): void
{
if ($event->isTableExcluded()) {
return;
}
$excludeTablesFromReferenceIndexing = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('asynchronous_reference_indexing', 'excludeTablesFromReferenceIndexing');
if (empty($excludeTablesFromReferenceIndexing)) {
return;
}
$excludeTableArray = GeneralUtility::trimExplode(',', $excludeTablesFromReferenceIndexing);
if (in_array($event->getTable(), $excludeTableArray)) {
$event->markAsExcluded();
}
}
}
37 changes: 0 additions & 37 deletions Classes/Slot/ReferenceIndexSlot.php

This file was deleted.

6 changes: 6 additions & 0 deletions Configuration/Commands.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
return [
'asynchronous_reference_indexing:index' => [
'class' => \NamelessCoder\AsyncReferenceIndexing\Command\AsyncReferenceIndexCommand::class,
],
];
14 changes: 14 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

NamelessCoder\AsyncReferenceIndexing\:
resource: '../Classes/*'

NamelessCoder\AsyncReferenceIndexing\EventListener\IsTableExcludedFromReferenceIndexEventListener:
tags:
- name: event.listener
identifier: 'asynchronous_reference_indexing/IsTableExcludedFromReferenceIndexEventListener'
event: TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ Provides a couple of things:
* A similar override for the ReferenceIndex class which replaces methods called also outside
of DataHandler, to catch those cases.
* An SQL table storing queued reference index updates.
* A CommandController which can be executed via CLI to process queued reference indexing
* A Symfony Command which can be executed via CLI or scheduler to process queued reference indexing
without running into timeout or long wait issues.
* Provides option to exclude tables from reference indexing (only on TYPO3 8.6+). See extension configuration.
* Provides option to exclude tables from reference indexing. See extension configuration.

Depending on how often your editors perform record imports, copies, deletions etc. this can over
time save many, many hours of waiting for the TYPO3 backend to respond.

Expand All @@ -42,14 +42,14 @@ Word of warning

Failing to update the reference index can have negative effects on your site in some cases, both
in frontend and backend. You are advised to add a scheduler task or cronjob for the included
command controller *and set the frequency to a very low value such as once every minute*. The
controller maintains a lock file and prevents parallel executions, so frequent runs are safe.
Symfony Console Command *and set the frequency to a very low value such as once every minute*. The
command maintains a lock file and prevents parallel executions, so frequent runs are safe.

Note that this extension consistently captures all of the current reference indexing, including
that which you can trigger using the existing (non-Extbase) CLI command or via the "DB check"
backend module which is added when you install the `lowlevel` system extension. Using either of
these methods to force reference index updating will instead fill the queue for the command
controller included with *this* extension so that all existing records which have relations
included with *this* extension so that all existing records which have relations
will be processed on the next run.

Possible side effects
Expand All @@ -59,24 +59,24 @@ Delaying update of the reference index has one main side effect: if the editor t
record whose relations have not been indexed, an appropriate warning may not be shown.

Secondary side effect is in listing of relationships between records. Such information will be
updated only when the command controller runs.
updated only when the command runs.

Frontend rendering should not be affected negatively.

Usage
-----

To re-index a site from scratch you would normally execute the following command, if you have
a lot of garbage in the sys_refindex table you might wan't to truncate it before:
a lot of garbage in the sys_refindex table you might want to truncate it before:

```
TYPO3_PATH_ROOT=$PWD/web vendor/bin/typo3cms asyncreferenceindex:update --force 1
TYPO3_PATH_ROOT=$PWD/web vendor/bin/typo3cms asynchronous_reference_indexing:index --force
```

Afterwards you can update the sys_refindex by executing the command:

```
TYPO3_PATH_ROOT=$PWD/web vendor/bin/typo3cms asyncreferenceindex:update
TYPO3_PATH_ROOT=$PWD/web vendor/bin/typo3cms asynchronous_reference_indexing:index
```

Alternatively you can setup a Scheduler Task to execute the command at a certain interval.
Expand Down
19 changes: 3 additions & 16 deletions ext_emconf.php
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
<?php
$EM_CONF[$_EXTKEY] = [
'title' => 'Asynchronous Reference Indexing',
'description' => 'Delegates reference indexing to a command controller (scheduler compatible) to avoid major performance issues on very large setups or large database operations.',
'description' => 'Delegates reference indexing to a Symfony Console Command (scheduler compatible) to avoid major performance issues on very large setups or large database operations.',
'category' => 'misc',
'author' => 'Claus Due',
'author_email' => '[email protected]',
'author_company' => '',
'shy' => '',
'dependencies' => '',
'conflicts' => '',
'priority' => '',
'module' => '',
'state' => 'beta',
'internal' => '',
'uploadfolder' => 0,
'createDirs' => '',
'modify_tables' => '',
'clearCacheOnLoad' => 0,
'lockType' => '',
'version' => '2.1.0',
'constraints' => [
'depends' => [
'php' => '7.0.0-7.3.99',
'typo3' => '8.7.0-9.99.99',
'php' => '7.2.0-7.4.99',
'typo3' => '10.4.0-10.4.99',
],
'conflicts' => [],
'suggests' => [],
],
'suggests' => [],
'_md5_values_when_last_written' => '',
];
15 changes: 0 additions & 15 deletions ext_localconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,3 @@

$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Core\Database\ReferenceIndex::class]['className'] =
\NamelessCoder\AsyncReferenceIndexing\Database\ReferenceIndex::class;

$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] =
\NamelessCoder\AsyncReferenceIndexing\Command\AsyncReferenceIndexCommandController::class;

$_EXTCONF = unserialize($_EXTCONF);
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$_EXTKEY] = $_EXTCONF;

// Register signal
$dispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
$dispatcher->connect(
\TYPO3\CMS\Core\Database\ReferenceIndex::class,
'shouldExcludeTableFromReferenceIndex',
\NamelessCoder\AsyncReferenceIndexing\Slot\ReferenceIndexSlot::class,
'shouldExcludeTableFromReferenceIndex'
);