‪TYPO3CMS  ‪main
ValidatorTask.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
22 use Symfony\Component\Mime\Address;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
37 
43 {
47  protected ‪$sleepTime;
48 
52  protected ‪$sleepAfterFinish;
53 
57  protected ‪$countInARun;
58 
64  protected ‪$configuration = '';
65 
71  protected ‪$emailTemplateName = '';
72 
76  protected int ‪$depth = 0;
77 
81  protected int ‪$page = 0;
82 
88  protected ‪$languages = '';
89 
95  protected ‪$email = '';
96 
100  protected bool ‪$emailOnBrokenLinkOnly = true;
101 
107  protected ‪$languageFile = 'LLL:EXT:linkvalidator/Resources/Private/Language/locallang.xlf';
108 
114  protected ‪$modTSconfig = [];
115 
121  protected ‪$taskNeedsUpdate = false;
122 
128  public function ‪getEmail(): string
129  {
130  return ‪$this->email;
131  }
132 
138  public function ‪setEmail(string ‪$email): self
139  {
140  $this->email = ‪$email;
141  return $this;
142  }
143 
149  public function ‪getEmailOnBrokenLinkOnly(): bool
150  {
152  }
153 
159  public function ‪setEmailOnBrokenLinkOnly(bool ‪$emailOnBrokenLinkOnly): self
160  {
161  $this->emailOnBrokenLinkOnly = ‪$emailOnBrokenLinkOnly;
162  return $this;
163  }
164 
170  public function ‪getPage(): int
171  {
172  return ‪$this->page;
173  }
174 
180  public function ‪setPage(int ‪$page): self
181  {
182  $this->page = ‪$page;
183  return $this;
184  }
185 
191  public function ‪getLanguages(): string
192  {
193  return ‪$this->languages;
194  }
195 
201  public function ‪setLanguages(string ‪$languages): self
202  {
203  $this->languages = ‪$languages;
204  return $this;
205  }
206 
212  public function ‪getDepth(): int
213  {
214  return ‪$this->depth;
215  }
216 
222  public function ‪setDepth(int ‪$depth): self
223  {
224  $this->depth = ‪$depth;
225  return $this;
226  }
227 
233  public function ‪getEmailTemplateName(): string
234  {
236  }
237 
243  public function ‪setEmailTemplateName(string ‪$emailTemplateName): self
244  {
245  $this->emailTemplateName = ‪$emailTemplateName;
246  return $this;
247  }
248 
254  public function ‪getConfiguration(): string
255  {
257  }
258 
264  public function ‪setConfiguration(string ‪$configuration): self
265  {
266  $this->configuration = ‪$configuration;
267  return $this;
268  }
269 
275  public function ‪execute(): bool
276  {
277  if ($this->page === 0) {
278  return false;
279  }
280 
281  $this->‪setCliArguments()->loadModTSconfig();
282 
283  $successfullyExecuted = true;
284  $linkAnalyzerResult = $this->‪getLinkAnalyzerResult();
285 
286  if ($this->‪getEmail() !== '' &&
287  $linkAnalyzerResult->getTotalBrokenLinksCount() > 0
288  && (!$this->emailOnBrokenLinkOnly || $linkAnalyzerResult->isDifferentToLastResult())
289  ) {
290  $successfullyExecuted = $this->reportEmail($linkAnalyzerResult);
291  }
292 
293  if ($this->taskNeedsUpdate) {
294  $this->taskNeedsUpdate = false;
295  GeneralUtility::makeInstance(SchedulerTaskRepository::class)->update($this);
296  }
297 
298  return $successfullyExecuted;
299  }
300 
305  protected function ‪getLinkAnalyzerResult(): LinkAnalyzerResult
306  {
307  $pageRow = BackendUtility::getRecord('pages', $this->page, '*', '', false);
308  if ($pageRow === null) {
309  throw new \InvalidArgumentException(
310  sprintf($this->‪getLanguageService()->sL($this->languageFile . ':tasks.error.invalidPageUid'), $this->page),
311  1502800555
312  );
313  }
314 
315  return GeneralUtility::makeInstance(LinkAnalyzerResult::class)
316  ->getResultForTask(
317  $this->page,
318  $this->depth,
319  $pageRow,
320  $this->modTSconfig,
321  $this->‪getSearchField(),
322  $this->getLinkTypes(),
323  $this->languages
324  );
325  }
326 
330  protected function ‪loadModTSconfig(): void
331  {
332  $modTs = BackendUtility::getPagesTSconfig($this->page)['mod.']['linkvalidator.'] ?? [];
333 
334  if (!empty($this->configuration)) {
335  $typoScriptStringFactory = GeneralUtility::makeInstance(TypoScriptStringFactory::class);
336  $overrideTs = $typoScriptStringFactory->parseFromString($this->configuration, GeneralUtility::makeInstance(AstBuilder::class));
337  ArrayUtility::mergeRecursiveWithOverrule($modTs, $overrideTs->toArray()['mod.']['linkvalidator.'] ?? []);
338  }
339 
340  if (empty($modTs['mail.']['fromemail'])) {
341  $modTs['mail.']['fromemail'] = ‪MailUtility::getSystemFromAddress();
342  }
343  if (empty($modTs['mail.']['fromname'])) {
344  $modTs['mail.']['fromname'] = ‪MailUtility::getSystemFromName();
345  }
346 
347  $this->modTSconfig = $modTs;
348  }
349 
355  protected function ‪getSearchField(): array
356  {
357  $searchFields = [];
358  foreach ($this->modTSconfig['searchFields.'] as $table => $fieldList) {
359  ‪$fields = ‪GeneralUtility::trimExplode(',', $fieldList);
360  foreach (‪$fields as $field) {
361  $searchFields[$table][] = $field;
362  }
363  }
364  return $searchFields;
365  }
366 
372  protected function getLinkTypes(): array
373  {
374  $linkTypes = [];
375  $typesTmp = ‪GeneralUtility::trimExplode(',', $this->modTSconfig['linktypes'], true);
376  foreach (GeneralUtility::makeInstance(LinktypeRegistry::class)->getIdentifiers() as ‪$identifier) {
377  if (in_array(‪$identifier, $typesTmp, true)) {
378  $linkTypes[] = ‪$identifier;
379  }
380  }
381  return $linkTypes;
382  }
383 
389  protected function reportEmail(‪LinkAnalyzerResult $linkAnalyzerResult): bool
390  {
391  $lang = $this->‪getLanguageService();
392  ‪$fluidEmail = $this->‪getFluidEmail();
393 
394  // Initialize and call the event
395  ‪$validatorTaskEmailEvent = new ‪ModifyValidatorTaskEmailEvent($linkAnalyzerResult, ‪$fluidEmail, $this->modTSconfig);
396  GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(‪$validatorTaskEmailEvent);
397  ‪$fluidEmail->assign('linkAnalyzerResult', $linkAnalyzerResult);
398 
399  if (!empty($this->modTSconfig['mail.']['subject']) && ‪$fluidEmail->getSubject() === null) {
400  ‪$fluidEmail->subject($this->modTSconfig['mail.']['subject']);
401  }
402 
403  if (‪$fluidEmail->getFrom() === []) {
404  if (GeneralUtility::validEmail($this->modTSconfig['mail.']['fromemail'] ?? '')) {
405  ‪$fluidEmail->from(
406  new Address($this->modTSconfig['mail.']['fromemail'], $this->modTSconfig['mail.']['fromname'] ?? '')
407  );
408  } else {
409  throw new \Exception($lang->sL($this->languageFile . ':tasks.error.invalidFromEmail'), 1295476760);
410  }
411  }
412 
413  if ($this->email !== '') {
414  $validEmailList = [];
415 
416  if (str_contains($this->email, ',')) {
417  $emailList = ‪GeneralUtility::trimExplode(',', $this->email, true);
418  $this->email = implode(LF, $emailList);
419  $this->taskNeedsUpdate = true;
420  } else {
421  $emailList = ‪GeneralUtility::trimExplode(LF, $this->email, true);
422  }
423 
424  foreach ($emailList as ‪$email) {
425  if (GeneralUtility::validEmail(‪$email)) {
426  $validEmailList[] = ‪$email;
427  continue;
428  }
429  throw new \Exception($lang->sL($this->languageFile . ':tasks.error.invalidToEmail'), 1295476821);
430  }
431 
432  ‪$fluidEmail->addTo(...$validEmailList);
433  }
434 
435  if (‪$fluidEmail->getTo() === []) {
436  throw new \Exception($lang->sL($this->languageFile . ':tasks.error.emptyToEmail'), 1599724418);
437  }
438 
439  if (‪$fluidEmail->getReplyTo() === [] &&
440  GeneralUtility::validEmail($this->modTSconfig['mail.']['replytoemail'] ?? '')
441  ) {
442  ‪$fluidEmail->replyTo(
443  new Address($this->modTSconfig['mail.']['replytoemail'], $this->modTSconfig['mail.']['replytoname'] ?? '')
444  );
445  }
446 
447  try {
448  // TODO: DI should be used to inject the MailerInterface
449  GeneralUtility::makeInstance(MailerInterface::class)->send(‪$fluidEmail);
450  } catch (TransportExceptionInterface $e) {
451  return false;
452  }
453 
454  return true;
455  }
456 
461  public function ‪getAdditionalInformation(): string
462  {
463  $additionalInformation = [];
464  $pageLabel = ‪$this->page;
465  if ($this->page) {
466  $pageData = BackendUtility::getRecord('pages', $this->page);
467  if (!empty($pageData)) {
468  $pageTitle = BackendUtility::getRecordTitle('pages', $pageData);
469  $pageLabel = $pageTitle . ' (' . $this->page . ')';
470  }
471  }
472  $lang = $this->‪getLanguageService();
473  $depth = ‪$this->depth;
474  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.page') . ': ' . $pageLabel;
475  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.depth') . ': '
476  . $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_' . (‪$depth === 999 ? 'infi' : ‪$depth));
477  $additionalInformation[] = $lang->sL($this->languageFile . ':tasks.validate.email') . ': '
478  . $this->‪getEmail();
479 
480  return implode(', ', $additionalInformation);
481  }
482 
486  protected function ‪setCliArguments(): self
487  {
488  ‪$_SERVER['argv'] = [
489  (‪$_SERVER['argv'][0] ?? null),
490  'tx_link_scheduler_link',
491  '0',
492  '-ss',
493  '--sleepTime',
494  $this->sleepTime,
495  '--sleepAfterFinish',
496  $this->sleepAfterFinish,
497  '--countInARun',
498  $this->countInARun,
499  ];
500 
501  return $this;
502  }
503 
507  protected function ‪getFluidEmail(): ‪FluidEmail
508  {
509  $templateConfiguration = array_replace_recursive(
510  ‪$GLOBALS['TYPO3_CONF_VARS']['MAIL'],
511  ['templateRootPaths' => [20 => 'EXT:linkvalidator/Resources/Private/Templates/Email/']]
512  );
513 
514  // must be sorted after adding the default path to ensure already registered custom paths are called first
515  ksort($templateConfiguration['templateRootPaths']);
516  $templatePaths = GeneralUtility::makeInstance(TemplatePaths::class, $templateConfiguration);
517 
518  if ($this->emailTemplateName === '' || !$this->‪templateFilesExist($templatePaths->getTemplateRootPaths())) {
519  // Add default template name to task if empty or given template name does not exist
520  $this->emailTemplateName = 'ValidatorTask';
521  $this->taskNeedsUpdate = true;
522  $this->logger->notice($this->‪getLanguageService()->sL($this->languageFile . ':tasks.notice.useDefaultTemplate'));
523  }
524 
525  ‪$fluidEmail = GeneralUtility::makeInstance(FluidEmail::class, $templatePaths);
526  ‪$fluidEmail->setTemplate($this->emailTemplateName);
527 
528  return ‪$fluidEmail;
529  }
530 
534  protected function ‪templateFilesExist(array $templatePaths): bool
535  {
536  foreach ($templatePaths as $templatePath) {
537  if (file_exists($templatePath . $this->emailTemplateName . '.html')
538  && file_exists($templatePath . $this->emailTemplateName . '.txt')
539  ) {
540  return true;
541  }
542  }
543  return false;
544  }
545 }
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setDepth
‪setDepth(int $depth)
Definition: ValidatorTask.php:212
‪TYPO3\CMS\Fluid\View\TemplatePaths
Definition: TemplatePaths.php:39
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$emailOnBrokenLinkOnly
‪bool $emailOnBrokenLinkOnly
Definition: ValidatorTask.php:93
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$languages
‪string $languages
Definition: ValidatorTask.php:82
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$page
‪int $page
Definition: ValidatorTask.php:76
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getSearchField
‪array getSearchField()
Definition: ValidatorTask.php:345
‪TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository
Definition: SchedulerTaskRepository.php:36
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$validatorTaskEmailEvent
‪$validatorTaskEmailEvent
Definition: ValidatorTask.php:385
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$emailTemplateName
‪string $emailTemplateName
Definition: ValidatorTask.php:66
‪TYPO3\CMS\Core\Utility\MailUtility\getSystemFromAddress
‪static string getSystemFromAddress()
Definition: MailUtility.php:79
‪TYPO3\CMS\Linkvalidator\Event\ModifyValidatorTaskEmailEvent
Definition: ModifyValidatorTaskEmailEvent.php:27
‪TYPO3\CMS\Core\Mail\MailerInterface
Definition: MailerInterface.php:28
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmailTemplateName
‪string getEmailTemplateName()
Definition: ValidatorTask.php:223
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setCliArguments
‪setCliArguments()
Definition: ValidatorTask.php:476
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\execute
‪bool execute()
Definition: ValidatorTask.php:265
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$fluidEmail
‪$fluidEmail
Definition: ValidatorTask.php:382
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$sleepAfterFinish
‪int $sleepAfterFinish
Definition: ValidatorTask.php:50
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getLinkAnalyzerResult
‪getLinkAnalyzerResult()
Definition: ValidatorTask.php:295
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getLanguages
‪string getLanguages()
Definition: ValidatorTask.php:181
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$languageFile
‪string $languageFile
Definition: ValidatorTask.php:99
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$taskNeedsUpdate
‪bool $taskNeedsUpdate
Definition: ValidatorTask.php:111
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getAdditionalInformation
‪getAdditionalInformation()
Definition: ValidatorTask.php:451
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmail
‪setEmail(string $email)
Definition: ValidatorTask.php:128
‪TYPO3\CMS\Scheduler\Task\AbstractTask
Definition: AbstractTask.php:33
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmailOnBrokenLinkOnly
‪bool getEmailOnBrokenLinkOnly()
Definition: ValidatorTask.php:139
‪TYPO3\CMS\Core\Mail\FluidEmail
Definition: FluidEmail.php:35
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getFluidEmail
‪getFluidEmail()
Definition: ValidatorTask.php:497
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$depth
‪int $depth
Definition: ValidatorTask.php:71
‪TYPO3\CMS\Core\Utility\MailUtility
Definition: MailUtility.php:26
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$modTSconfig
‪array $modTSconfig
Definition: ValidatorTask.php:105
‪$_SERVER
‪$_SERVER['TYPO3_DEPRECATED_ENTRYPOINT']
Definition: legacy-backend.php:20
‪TYPO3\CMS\Linkvalidator\Task
Definition: ValidatorTask.php:18
‪TYPO3\CMS\Core\TypoScript\AST\AstBuilder
Definition: AstBuilder.php:45
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\loadModTSconfig
‪loadModTSconfig()
Definition: ValidatorTask.php:320
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setConfiguration
‪setConfiguration(string $configuration)
Definition: ValidatorTask.php:254
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\templateFilesExist
‪templateFilesExist(array $templatePaths)
Definition: ValidatorTask.php:524
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setLanguages
‪setLanguages(string $languages)
Definition: ValidatorTask.php:191
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$countInARun
‪int $countInARun
Definition: ValidatorTask.php:54
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getPage
‪int getPage()
Definition: ValidatorTask.php:160
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getDepth
‪int getDepth()
Definition: ValidatorTask.php:202
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmailTemplateName
‪setEmailTemplateName(string $emailTemplateName)
Definition: ValidatorTask.php:233
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setEmailOnBrokenLinkOnly
‪setEmailOnBrokenLinkOnly(bool $emailOnBrokenLinkOnly)
Definition: ValidatorTask.php:149
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\setPage
‪setPage(int $page)
Definition: ValidatorTask.php:170
‪TYPO3\CMS\Core\TypoScript\TypoScriptStringFactory
Definition: TypoScriptStringFactory.php:37
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$email
‪string $email
Definition: ValidatorTask.php:88
‪TYPO3\CMS\Core\Utility\MailUtility\getSystemFromName
‪static string null getSystemFromName()
Definition: MailUtility.php:59
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$configuration
‪string $configuration
Definition: ValidatorTask.php:60
‪TYPO3\CMS\Linkvalidator\Linktype\LinktypeRegistry
Definition: LinktypeRegistry.php:27
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getEmail
‪string getEmail()
Definition: ValidatorTask.php:118
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getLanguageService
‪array< int, getLinkTypes():array { $linkTypes=[];$typesTmp=GeneralUtility::trimExplode(',', $this->modTSconfig[ 'linktypes'], true);foreach(GeneralUtility::makeInstance(LinktypeRegistry::class) ->getIdentifiers() as $identifier) { if(in_array( $identifier, $typesTmp, true)) { $linkTypes[]=$identifier;} } return $linkTypes;} protected bool function reportEmail(LinkAnalyzerResult $linkAnalyzerResult):bool { $lang=$this-> getLanguageService()
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask
Definition: ValidatorTask.php:43
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\$sleepTime
‪int $sleepTime
Definition: ValidatorTask.php:46
‪TYPO3\CMS\Linkvalidator\Task\ValidatorTask\getConfiguration
‪string getConfiguration()
Definition: ValidatorTask.php:244