Completed
Pull Request — master (#439)
by
unknown
01:56
created

CleanupCommandController::execute()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 59
rs 8.5833
c 0
b 0
f 0
cc 5
nc 5
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Cleanup the event models.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Calendarize\Command;
9
10
use HDNET\Calendarize\Domain\Model\Event;
11
use HDNET\Calendarize\Domain\Repository\EventRepository;
12
use HDNET\Calendarize\Service\IndexerService;
13
use HDNET\Calendarize\Utility\DateTimeUtility;
14
use HDNET\Calendarize\Utility\HelperUtility;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Input\InputOption;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Style\SymfonyStyle;
20
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
21
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
24
25
/**
26
 * Cleanup the event models.
27
 */
28
class CleanupCommandController extends Command
29
{
30
    const MODUS_HIDDEN = 'hide';
31
    const MODUS_DELETED = 'delete';
32
    const DEFAULT_WAIT_PERIOD = 14;
33
    const DEFAULT_CLEANUP_REPOSITORY = 'HDNET\\Calendarize\\Domain\\Repository\\EventRepository';
34
35
    protected function configure()
36
    {
37
        $this->setDescription('Remove outdated events to keep a small footprint')
38
            ->addOption(
39
                'repositoryName',
40
                null,
41
                InputOption::VALUE_OPTIONAL,
42
                'The repository of the event to clean up',
43
                self::DEFAULT_CLEANUP_REPOSITORY
44
            )
45
            ->addOption(
46
                'modus',
47
                null,
48
                InputOption::VALUE_OPTIONAL,
49
                'What to do with cleaned Events? Set them \'hide\' or \'delete\'',
50
                self::MODUS_HIDDEN
51
            )
52
            ->addOption(
53
                'waitingPeriod',
54
                null,
55
                InputOption::VALUE_OPTIONAL,
56
                'how many days to wait after ending the Event before \'hide/delete\' it',
57
                self::DEFAULT_WAIT_PERIOD
58
            );
59
    }
60
61
    /**
62
     * Cleanup the event models.
63
     * Remove outdated events to keep a small footprint. This gain maybe a little more performance.
64
     *
65
     * @param InputInterface $input
66
     * @param OutputInterface $output
67
     * @return int 0 if everything went fine, or an exit code
68
     */
69
    protected function execute(InputInterface $input, OutputInterface $output)
70
    {
71
        $io = new SymfonyStyle($input, $output);
72
73
        $repositoryName = $input->getOption('repositoryName');
74
        $modus = $input->getOption('modus');
75
        $waitingPeriod = $input->getOption('waitingPeriod');
76
77
        /** @var EventRepository $repository */
78
        $repository = GeneralUtility::makeInstance($repositoryName);
79
80
        if (!($repository instanceof EventRepository)) {
81
            return 1;
82
        }
83
84
        $io->section('Reindex all events');
85
        // Index all events to start on a clean slate
86
        $this->reIndex();
87
88
        // get tablename from repository, works only with the extended EventRepository
89
        $tableName = $repository->getTableName();
90
91
        if (!$tableName) {
92
            $io->error('No tablename found on your given Repository! [' . $repositoryName . ']');
93
94
            return 2;
95
        }
96
97
        $io->text('Tablename ' . $tableName);
98
99
        $io->section('Find outdated events');
100
        // events uid, to be precise
101
        $events = $this->findOutdatedEvents($tableName, $waitingPeriod);
102
103
        $io->text('Just found ' . \count($events) . ' Events ready to process.');
104
105
        // climb thru the events and hide/delete them
106
        foreach ($events as $event) {
107
            $uid = (int)$event['foreign_uid'];
108
109
            $model = $repository->findByUid($uid);
110
111
            if (!($model instanceof Event)) {
112
                $io->error('Object with uid [' . $uid . '] is not an instance of the event base model.');
113
                continue;
114
            }
115
116
            $this->processEvent($repository, $model, $modus);
117
        }
118
119
        // persist the modified events
120
        // HelperUtility::persistAll(); @todo handle via DI
121
122
        $io->section('Reindex all events');
123
        // after all this deleting ... reindex!
124
        $this->reIndex();
125
126
        return 0;
127
    }
128
129
    /**
130
     * Process the found Event and delete or hide it.
131
     *
132
     * @param EventRepository $repository
133
     * @param Event           $model
134
     * @param string          $modus
135
     */
136
    protected function processEvent(EventRepository $repository, Event $model, $modus)
137
    {
138
        // define the function for the delete-modus.
139
        $delete = function ($repository, $model) {
140
            $repository->remove($model);
141
        };
142
143
        // define the function for the hide-modus.
144
        $hide = function ($repository, $model) {
145
            $model->setHidden(true);
146
            $repository->update($model);
147
        };
148
149
        if (self::MODUS_DELETED === $modus) {
150
            $function = $delete;
151
        } else {
152
            $function = $hide;
153
        }
154
155
        // dispatch variables
156
        // use function to write your own reaction
157
        $variables = [
158
            'modus' => $modus,
159
            'repository' => $repository,
160
            'model' => $model,
161
            'function' => $function,
162
        ];
163
164
        $dispatcher = GeneralUtility::makeInstance(Dispatcher::class);
165
        $variables = $dispatcher->dispatch(__CLASS__, __FUNCTION__, $variables);
166
167
        $myFunction = $variables['function'];
168
        $myFunction($repository, $model);
169
    }
170
171
    /**
172
     * Find outdated events.
173
     *
174
     * @param string $tableName
175
     * @param int    $waitingPeriod
176
     *
177
     * @throws \Exception
178
     *
179
     * @return array
180
     */
181
    protected function findOutdatedEvents($tableName, $waitingPeriod): array
182
    {
183
        // calculate the waiting time
184
        $interval = 'P' . (int)$waitingPeriod . 'D';
185
        $now = DateTimeUtility::getNow();
186
        $now->sub(new \DateInterval($interval));
187
188
        // search for outdated events
189
        $table = IndexerService::TABLE_NAME;
190
191
        $q = HelperUtility::getDatabaseConnection($table)->createQueryBuilder();
192
        $q->getRestrictions()
193
            ->removeAll()
194
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
195
            ->add(GeneralUtility::makeInstance(HiddenRestriction::class));
196
197
        $foreignUids = $q->select('foreign_uid')
198
            ->from($table)
199
            ->where($q->expr()
200
                ->gt('end_date', $q->createNamedParameter($now->getTimestamp())))
201
            ->andWhere($q->expr()
202
                ->eq('foreign_table', $q->createNamedParameter($tableName)))
203
            ->execute()
204
            ->fetchAll();
205
206
        $foreignUids = \array_map(function ($item) {
207
            return (int)$item['foreign_uid'];
208
        }, $foreignUids);
209
210
        $q->select('foreign_uid')
211
            ->from($table)
212
            ->where($q->expr()
213
                ->andX($q->expr()
214
                    ->lt('end_date', $q->createNamedParameter($now->getTimestamp())), $q->expr()
215
                    ->eq('foreign_table', $q->createNamedParameter($tableName)), $q->expr()
216
                    ->notIn('foreign_uid', $foreignUids)));
217
218
        $rows = $q->execute()->fetchAll();
219
220
        return $rows;
221
    }
222
223
    /**
224
     * Reindex the Events.
225
     * This may take some time.
226
     */
227
    protected function reIndex()
228
    {
229
        $indexer = GeneralUtility::makeInstance(IndexerService::class);
230
        $indexer->reindexAll();
231
    }
232
}
233