Skip to content

Commit 6eabf20

Browse files
refactor: resolve v14-only API references at runtime for v13 compat
1 parent 843cc55 commit 6eabf20

3 files changed

Lines changed: 33 additions & 13 deletions

File tree

Classes/EventListener/ModifyRecordListRecordActionsListener.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
use Doctrine\DBAL\Exception;
1717
use TYPO3\CMS\Backend\RecordList\Event\ModifyRecordListRecordActionsEvent;
18-
use TYPO3\CMS\Backend\Template\Components\ActionGroup;
1918
use TYPO3\CMS\Core\Attribute\AsEventListener;
2019
use TYPO3\CMS\Core\Domain\RecordInterface;
2120
use TYPO3\CMS\Core\Imaging\{IconFactory, IconSize};
@@ -28,6 +27,7 @@
2827
use Xima\XimaTypo3ContentPlanner\Utility\ExtensionUtility;
2928
use Xima\XimaTypo3ContentPlanner\Utility\Security\PermissionUtility;
3029

30+
use function constant;
3131
use function count;
3232
use function is_array;
3333

@@ -60,7 +60,7 @@ public function __invoke(ModifyRecordListRecordActionsEvent $event): void
6060
return;
6161
}
6262
// TYPO3 v13/v14 compatibility: In v14 getRecord() returns RecordInterface, in v13 it returns array
63-
// @phpstan-ignore instanceof.alwaysTrue, method.notFound
63+
// @phpstan-ignore instanceof.alwaysTrue, instanceof.alwaysFalse, method.notFound
6464
$table = $event->getRecord() instanceof RecordInterface ? $event->getRecord()->getMainType() : $event->getTable();
6565

6666
if (!ExtensionUtility::isRegisteredRecordTable($table) || $event->hasAction('Status')) {
@@ -73,7 +73,7 @@ public function __invoke(ModifyRecordListRecordActionsEvent $event): void
7373
}
7474

7575
// TYPO3 v13/v14 compatibility: In v14 getRecord() returns RecordInterface, in v13 it returns array
76-
// @phpstan-ignore instanceof.alwaysTrue
76+
// @phpstan-ignore instanceof.alwaysTrue, instanceof.alwaysFalse, method.notFound, offsetAccess.nonOffsetAccessible
7777
$uid = $event->getRecord() instanceof RecordInterface ? $event->getRecord()->getUid() : $event->getRecord()['uid'];
7878

7979
// ToDo: this is necessary cause the status is not in the record, pls check tca for this
@@ -101,10 +101,16 @@ public function __invoke(ModifyRecordListRecordActionsEvent $event): void
101101
$dropDownButton->addItem($actionToAdd);
102102
}
103103

104+
// ActionGroup::primary is v14-only; resolve via constant() at runtime
105+
// so PHPStan does not need to know the v14 enum when analysing v13.
106+
$primaryGroup = VersionUtility::is14OrHigher()
107+
? constant('TYPO3\\CMS\\Backend\\Template\\Components\\ActionGroup::primary')
108+
: 'primary';
109+
104110
$event->setAction(
105111
VersionUtility::is14OrHigher() ? $dropDownButton : $dropDownButton->render(),
106112
'Status',
107-
VersionUtility::is14OrHigher() ? ActionGroup::primary : 'primary',
113+
$primaryGroup,
108114
'delete',
109115
);
110116
}

Classes/Utility/Compatibility/ComponentFactoryUtility.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ComponentFactoryUtility
2828
public static function createDropDownButton(): DropDownButton
2929
{
3030
if (VersionUtility::is14OrHigher()) {
31+
// @phpstan-ignore method.notFound
3132
return self::getComponentFactory()->createDropDownButton();
3233
}
3334

@@ -37,6 +38,7 @@ public static function createDropDownButton(): DropDownButton
3738
public static function createDropDownItem(): DropDownItem
3839
{
3940
if (VersionUtility::is14OrHigher()) {
41+
// @phpstan-ignore method.notFound
4042
return self::getComponentFactory()->createDropDownItem();
4143
}
4244

@@ -46,6 +48,7 @@ public static function createDropDownItem(): DropDownItem
4648
public static function createDropDownDivider(): DropDownDivider
4749
{
4850
if (VersionUtility::is14OrHigher()) {
51+
// @phpstan-ignore method.notFound
4952
return self::getComponentFactory()->createDropDownDivider();
5053
}
5154

@@ -55,20 +58,24 @@ public static function createDropDownDivider(): DropDownDivider
5558
public static function createDropDownHeader(): DropDownHeader
5659
{
5760
if (VersionUtility::is14OrHigher()) {
61+
// @phpstan-ignore method.notFound
5862
return self::getComponentFactory()->createDropDownHeader();
5963
}
6064

6165
return GeneralUtility::makeInstance(DropDownHeader::class);
6266
}
6367

6468
/**
65-
* @return \TYPO3\CMS\Backend\Template\Components\ComponentFactory
69+
* Returns the v14-only ComponentFactory instance. Return type is `object`
70+
* (not the FQN) so PHPStan does not have to resolve the v14 class when
71+
* analysing against TYPO3 v13.
6672
*/
6773
private static function getComponentFactory(): object
6874
{
69-
// Use dynamic class name to avoid autoload issues on TYPO3 13
75+
// Dynamic class name to avoid autoload issues on TYPO3 13
7076
$componentFactoryClass = 'TYPO3\\CMS\\Backend\\Template\\Components\\ComponentFactory';
7177

78+
// @phpstan-ignore argument.type
7279
return GeneralUtility::makeInstance($componentFactoryClass);
7380
}
7481
}

Classes/Utility/Rendering/AssetUtility.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
use Psr\Http\Message\ServerRequestInterface;
1717
use TYPO3\CMS\Core\Resource\Exception\InvalidFileException;
18-
use TYPO3\CMS\Core\SystemResource\Publishing\{SystemResourcePublisherInterface, UriGenerationOptions};
19-
use TYPO3\CMS\Core\SystemResource\SystemResourceFactory;
2018
use TYPO3\CMS\Core\Utility\{GeneralUtility, PathUtility};
2119
use Xima\XimaTypo3ContentPlanner\Utility\Compatibility\VersionUtility;
2220

@@ -75,18 +73,27 @@ public static function getJsTag(
7573
public static function getPublicResourcePath(string $resourcePath): string
7674
{
7775
if (VersionUtility::is14OrHigher()) {
78-
/** @var SystemResourceFactory $resourceFactory */
79-
$resourceFactory = GeneralUtility::makeInstance(SystemResourceFactory::class);
80-
/** @var SystemResourcePublisherInterface $resourcePublisher */
81-
$resourcePublisher = GeneralUtility::makeInstance(SystemResourcePublisherInterface::class);
76+
// FQN strings to keep PHPStan happy when analysing against TYPO3 v13,
77+
// where these classes do not exist. Runtime path is v14-only anyway.
78+
$factoryClass = 'TYPO3\\CMS\\Core\\SystemResource\\SystemResourceFactory';
79+
$publisherClass = 'TYPO3\\CMS\\Core\\SystemResource\\Publishing\\SystemResourcePublisherInterface';
80+
$optionsClass = 'TYPO3\\CMS\\Core\\SystemResource\\Publishing\\UriGenerationOptions';
81+
82+
// @phpstan-ignore argument.type
83+
$resourceFactory = GeneralUtility::makeInstance($factoryClass);
84+
// @phpstan-ignore argument.type
85+
$resourcePublisher = GeneralUtility::makeInstance($publisherClass);
86+
// @phpstan-ignore class.notFound, method.notFound
8287
$resource = $resourceFactory->createPublicResource($resourcePath);
8388
/** @var ServerRequestInterface|null $request */
8489
$request = $GLOBALS['TYPO3_REQUEST'] ?? null;
8590

91+
// @phpstan-ignore class.notFound, method.notFound
8692
return (string) $resourcePublisher->generateUri(
8793
$resource,
8894
$request,
89-
new UriGenerationOptions(absoluteUri: false),
95+
// @phpstan-ignore class.notFound
96+
new $optionsClass(absoluteUri: false),
9097
);
9198
}
9299

0 commit comments

Comments
 (0)