# TYPO3 Hooks and PSR-14 Events **Source:** TYPO3 Core API Reference - Hooks, Events, and Signals **Purpose:** Understanding TYPO3 hook system, PSR-14 events, and migration strategies ## SC_OPTIONS Hooks Status in TYPO3 13 ### ⚠️ Common Misconception **INCORRECT:** "SC_OPTIONS hooks are deprecated in TYPO3 13" **CORRECT:** SC_OPTIONS hooks are **NOT deprecated** in TYPO3 13. They remain the **official pattern** for specific use cases. ### SC_OPTIONS Hooks That Are Still Official The following SC_OPTIONS hooks remain the official TYPO3 13 pattern: #### DataHandler Hooks (Still Official) ```php // Configuration/Services.yaml Vendor\Extension\Database\MyDataHandlerHook: public: true tags: - name: event.listener identifier: 'my-extension/datahandler-hook' method: 'processDatamap_postProcessFieldArray' ``` **Still Official in ext_localconf.php:** ```php getUser(); // Your logic here } } ``` ### Common TYPO3 13 Events **Authentication Events:** - `AfterUserLoggedInEvent` - `BeforeUserLogoutEvent` - `AfterUserLoggedOutEvent` **Backend Events:** - `ModifyButtonBarEvent` - `ModifyDatabaseQueryForContentEvent` - `BeforePagePreviewUriGeneratedEvent` **DataHandler Events:** - `AfterDataInsertedEvent` - `AfterDataUpdatedEvent` - `AfterRecordDeletedEvent` **Page Events:** - `AfterPageTreeItemsPreparedEvent` - `ModifyPageLayoutContentEvent` **Complete Reference:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/EventDispatcher/Index.html ## Migration Strategy ### Step 1: Identify Hook Type ```php // Check if hook is in ext_localconf.php $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['...']['...'][] ``` ### Step 2: Check Official Documentation - **DataHandler hooks:** Still official, keep using SC_OPTIONS - **RTE transformation:** Still official, keep using SC_OPTIONS - **Other hooks:** Check if PSR-14 event exists ### Step 3: Migrate or Modernize **If PSR-14 event exists:** ```php // OLD: ext_localconf.php $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['postUserLookUp'][] = \Vendor\Extension\Hook\MyHook::class; // NEW: Configuration/Services.yaml + EventListener class Vendor\Extension\EventListener\MyEventListener: tags: - name: event.listener identifier: 'my-extension/after-login' event: TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedInEvent ``` **If no PSR-14 event exists (DataHandler, RTE):** ```php // KEEP: Still official in TYPO3 13+ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = \Vendor\Extension\Database\MyDataHandlerHook::class; // MODERNIZE: Add dependency injection // Configuration/Services.yaml Vendor\Extension\Database\MyDataHandlerHook: public: true arguments: $resourceFactory: '@TYPO3\CMS\Core\Resource\ResourceFactory' $context: '@TYPO3\CMS\Core\Context\Context' $logManager: '@TYPO3\CMS\Core\Log\LogManager' ``` ## Best Practices ### 1. Constructor Dependency Injection Even for SC_OPTIONS hooks, use constructor injection (TYPO3 13+): ```php resourceFactory->getFileObject($fileId); } } ``` ### 2. Avoid GeneralUtility::makeInstance() ```php // ❌ BAD: Using makeInstance (legacy pattern) $resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class); // ✅ GOOD: Constructor injection (TYPO3 13+ pattern) public function __construct( private readonly ResourceFactory $resourceFactory, ) {} ``` ### 3. Configure Services Explicitly ```yaml # Configuration/Services.yaml services: Vendor\Extension\Database\MyDataHandlerHook: public: true # Required for SC_OPTIONS hooks arguments: $resourceFactory: '@TYPO3\CMS\Core\Resource\ResourceFactory' $context: '@TYPO3\CMS\Core\Context\Context' $logManager: '@TYPO3\CMS\Core\Log\LogManager' ``` ## Acceptable $GLOBALS Usage Even in TYPO3 13+, certain `$GLOBALS` usage is acceptable: ### ✅ Acceptable $GLOBALS ```php // TCA access (no alternative available) $GLOBALS['TCA']['tt_content']['columns']['bodytext'] // Current request (framework-provided) $GLOBALS['TYPO3_REQUEST'] // Backend user context (framework-provided) $GLOBALS['BE_USER'] // Frontend user context (framework-provided) $GLOBALS['TSFE'] ``` ### ❌ Avoid $GLOBALS ```php // Database connection (use ConnectionPool) $GLOBALS['TYPO3_DB'] // Extension configuration (use ExtensionConfiguration) $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['my_ext'] // Object instantiation (use dependency injection) GeneralUtility::makeInstance(SomeClass::class) ``` ## Resources - [TYPO3 Hooks Documentation](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Hooks/Index.html) - [PSR-14 Events](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Events/EventDispatcher/Index.html) - [DataHandler Hooks](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Hooks/DataHandler/Index.html) - [Dependency Injection](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DependencyInjection/Index.html)