Utility class responsible for keeping and providing arbitrary values (such as configuration defaults, class names, feature flags etc.) based on the version of TYPO3 being used, or based on arbitrary versions of packages, extensions, PHP, PHP modules, binaries etc. Usage example ------------- Use \FluidTYPO3\Flux\Utility\CompatibilityRegistry; CompatibilityRegistry::register( 'FluidTYPO3\\Flux\\Backend\\Preview', array( '6.2.0' => 'FluidTYPO3\\Flux\\Backend\\LegacyPreview', '7.1.0' => 'FluidTYPO3\\Flux\\Backend\\Preview' ) ); $classWhichApplies = CompatibilityRegistry::get( 'FluidTYPO3\\Flux\\Backend\\Preview' ); Also supports reading a specific version's applied value: $legacyClassName = CompatibilityRegistry::get( 'FluidTYPO3\\Flux\\Backend\\Preview', '7.1.0' ); And a default to be used if nothing can be resolved: $classOrDefault = CompatibilityRegistry::get( 'FluidTYPO3\\Flux\\Backend\\Preview', NULL, 'FluidTYPO3\\Flux\\Backend\\UnsupportedPreview' ); (note that NULL is passed as version which means we attempt to resolve the currently running version's best match. It is still possible to pass a specific version number here). Another example - say you created a backend module and need it to work with a custom stylesheet on multiple versions of TYPO3 which are styled differently: CompatibilityRegistry::register( 'MyExtension', '/mySpecialNameForTheStylesheet', array( '6.2.0' => 'EXT:my_extension/.../Styles.6.2.0.css', '7.2.0' => 'EXT:my_extension/.../Styles.7.2.0.css', '7.5.0' => 'EXT:my_extension/.../Styles.7.5.0.css' ) ); And to retrieve: $styleSheet = CompatibilityRegistry::get( 'MyExtension/mySpecialNameForTheStylesheet' ); And to illustrate, if...: - TYPO3 is 6.2.* obviously the '6.2.0' entry is used - TYPO3 is 7.1.0 the '6.2.0' is used because '7.2.' is too high - TYPO3 is 7.4.0 the '7.2.0' is used - TYPO3 is anything at or above 7.5.0 then '7.5.0' is used Feature Flags ------------- The Compatibility Registry can also handle feature flags for you; returning the closest matching set of or individual feature flag based on version: CompatibilityRegistry::registerFeatureFlags( 'FluidTYPO3.Flux', array( '6.2.0' => array('form', 'nestedContent', 'provider', 'preview'), '7.5.0' => array('form', 'nestedContent', 'provider', 'preview', 'formengine'), '7.6.0' => array('form', 'provider', 'preview', 'formengine') ) ); And to retrieve: if (CompatibilityRegistry::hasFeatureFlag('FluidTYPO3.Flux', 'nestedContent')) { Would only be true until TYPO3 version hits 7.6.0, then no longer triggers. } Deprecation ----------- Because usage of CompatibilityRegistry is a very clear intention of *supporting deprecation*, there is a built-in layer warning of deprecation when you *register* either values or feature flags but *do not include a currently supported TYPO3 version* (as far as Flux is aware). To disable this deprecation reporting simply pass TRUE as the last parameter for either of the register commands: CompatibilityRegistry::register('MyClass', array(...), TRUE); CompatibilityRegistry::registerFeatureFlag('MyExt', array(...), TRUE); Doing so merely prevents the check for whether or not you include a value or feature flag for a non-deprecated TYPO3. Extension versions as key ------------------------- It is possible to make a registered variable or feature flag not depend on the TYPO3 version but instead the version of any arbitrary package - like a composer dependency or version of PHP. To utilise this slightly off-standard registry behavior, *manually include the version you are checking against when you retrieve the values from the registry*. Say your extension depends on extension "comments" (fictional) but "comments" may be installed in several versions that can be supported without breaking, as long as certain features are not enabled: CompatibilityRegistry::registerFeatureFlags( 'MyExt', array( '3.1.0' => array('falRelations'), '4.0.0' => array('falRelations', 'ajax') ), TRUE Note: *always* pass true here; the versions we record aren't for TYPO3 so we don't want deprecation warnings. ); $extensionVersion = ExtensionManagementUtility::getExtensionVersion('comments'); if (CompatibilityRegistry::hasFeatureFlag('MyExt', 'ajax', $extensionVersion) { It's okay to use our fresh feature that depends on the version of "comments" extension, not TYPO3 itself. } Which naturally means that only if the "comments" extension is installed in at least version 4.0.0 will the "ajax" feature flag query be TRUE.
Example #1
0
 /**
  * Constructor - takes an array of manifest data in the
  * same structure as in the manifest JSON file, or an
  * extension key in which case the expected manifest
  * is resolved using that and naming convention of the
  * manifest file. Or takes a full path to the manifest
  * file in which case the manifest is read from there.
  *
  * Note: applies CompatibilityRegistry-resolved versioned
  * manifest configuration values immediately.
  *
  * @param mixed $seedArrayOrExtensionKeyOrManifestPath
  */
 public function __construct($seedArrayOrExtensionKeyOrManifestPath)
 {
     if (is_array($seedArrayOrExtensionKeyOrManifestPath)) {
         $this->manifest = $seedArrayOrExtensionKeyOrManifestPath;
     } else {
         $possibleExtensionKey = ExtensionNamingUtility::getExtensionKey($seedArrayOrExtensionKeyOrManifestPath);
         if (ExtensionManagementUtility::isLoaded($possibleExtensionKey)) {
             $this->manifest = $this->loadManifestFile(GeneralUtility::getFileAbsFileName(sprintf('EXT:%s/flux.json', $possibleExtensionKey)));
         } else {
             $this->manifest = $this->loadManifestFile($seedArrayOrExtensionKeyOrManifestPath);
         }
     }
     if (!empty($this->manifest['compatibility'])) {
         $scope = $this->manifest['package'] . '/ManifestOverlay';
         CompatibilityRegistry::register($scope, $this->manifest['compatibility']);
         RecursiveArrayUtility::mergeRecursiveOverrule($this->manifest, CompatibilityRegistry::get($scope));
     }
 }
Example #2
0
		flexform {
			rteDefaults = richtext:rte_transform[flag=rte_enabled|mode=ts_css]
		}
	}
');
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['getFlexFormDSClass']['flux'] = 'FluidTYPO3\\Flux\\Backend\\DynamicFlexForm';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'FluidTYPO3\\Flux\\Backend\\TceMain';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass'][] = 'FluidTYPO3\\Flux\\Backend\\TceMain';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'][] = 'FluidTYPO3\\Flux\\Backend\\TceMain';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc'][] = 'FluidTYPO3\\Flux\\Backend\\TceMain->clearCacheCommand';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources']['flux'] = 'FluidTYPO3\\Flux\\Backend\\TypoScriptTemplate->preprocessIncludeStaticTypoScriptSources';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing']['flux'] = 'FluidTYPO3\\Flux\\Backend\\TableConfigurationPostProcessor';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['flux'] = \FluidTYPO3\Flux\Utility\CompatibilityRegistry::get('FluidTYPO3\\Flux\\Backend\\Preview');
if (TRUE === class_exists('FluidTYPO3\\Flux\\Core')) {
    \FluidTYPO3\Flux\Core::registerConfigurationProvider('FluidTYPO3\\Flux\\Provider\\ContentProvider');
    // native Outlets, replaceable by short name in subsequent registerOutlet() calls by adding second argument (string, name of type)
    \FluidTYPO3\Flux\Core::registerOutlet('standard');
    // native Pipes, replaceable by short name in subsequent registerPipe() calls by adding second argument (string, name of type)
    \FluidTYPO3\Flux\Core::registerPipe('standard');
    \FluidTYPO3\Flux\Core::registerPipe('controller');
    \FluidTYPO3\Flux\Core::registerPipe('email');
    \FluidTYPO3\Flux\Core::registerPipe('flashMessage');
    \FluidTYPO3\Flux\Core::registerPipe('typeConverter');
}
/** @var $extbaseObjectContainer \TYPO3\CMS\Extbase\Object\Container\Container */
$extbaseObjectContainer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\Container\\Container');
$extbaseObjectContainer->registerImplementation('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface', 'FluidTYPO3\\Flux\\Configuration\\ConfigurationManager');
unset($extbaseObjectContainer);
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook']['flux'] = 'FluidTYPO3\\Flux\\Hooks\\WizardItemsHookSubscriber';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks']['flux'] = \FluidTYPO3\Flux\Utility\CompatibilityRegistry::get('FluidTYPO3\\Flux\\Hooks\\ContentIconHookSubscriber->addSubIcon');
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable']['flux'] = 'FluidTYPO3\\Flux\\Hooks\\RecordListGetTableHookSubscriber';
Example #3
0
 /**
  * Hook for generating dynamic FlexForm source code.
  *
  * NOTE: patches data structure resolving in a way that solves
  * a regression in the TYPO3 core when dealing with IRRE AJAX
  * requests (in which the database record is no longer fetched
  * by the controller). This patches not only data structure
  * resolving for Flux data structures but indeed any data
  * structure built using hooks or involving user functions which
  * require the entire record (but when using hooks, supports
  * only extensions which are loaded AFTER or depend on Flux).
  *
  * @param array $dataStructArray
  * @param array $conf
  * @param array $row
  * @param string $table
  * @param string $fieldName
  * @return void
  */
 public function getFlexFormDS_postProcessDS(&$dataStructArray, $conf, &$row, $table, $fieldName)
 {
     if (empty($fieldName) === TRUE) {
         // Cast NULL if an empty but not-NULL field name was passed. This has significance to the Flux internals in
         // respect to which ConfigurationProvider(s) are returned.
         $fieldName = NULL;
     }
     if (!empty($fieldName) && !isset($row[$fieldName])) {
         // Patch required (possibly temporary). Due to changes in TYPO3 in the new FormEngine we must fetch the
         // database record at this point when the record is incomplete, which happens when attempting to render
         // IRRE records. The reason is that the controller that creates the HTML does not fetch the record any
         // more - and that the AJAX request contains only the UID. So, we fetch the record here to ensure it
         // contains the necessary fields. DOES NOT WORK FOR NEW RECORDS - SEE COMMENTS BELOW.
         $row = $this->recordService->getSingle($table, '*', $row['uid']);
     }
     $defaultDataSourceCacheIdentifier = $table . '_' . $fieldName . '_' . sha1(serialize($conf));
     if (!$row) {
         // In the case that the database record cannot be fetched we are dealing with a new or otherwise deleted
         // or unidentifiable record. This happens primarily when AJAX requests are made to render IRRE records
         // without the parent record having been saved first. To accommodate this case we have to be slightly
         // creative and store a "default" data source definition which is identified based on a checksum of the
         // configuration provided. Whenever we are then unable to fetch a record, we can at least attempt to
         // locate a default data source in previously cached content. NB: we enforce a VERY high cache lifetime
         // and continually refresh it every time it is possible to render a new DS that can serve as default.
         $dataStructArray = (array) $this->cache->get($defaultDataSourceCacheIdentifier);
     } else {
         if (FALSE === is_array($dataStructArray)) {
             $dataStructArray = array();
         }
         $providers = $this->configurationService->resolveConfigurationProviders($table, $fieldName, $row);
         foreach ($providers as $provider) {
             $provider->postProcessDataStructure($row, $dataStructArray, $conf);
         }
         if (empty($dataStructArray)) {
             $dataStructArray = array('ROOT' => array('el' => array()));
         }
         $evaluationParameters = array();
         $this->cache->set($defaultDataSourceCacheIdentifier, $this->recursivelyEvaluateClosures($dataStructArray, $evaluationParameters), array(), time() + 31536000);
     }
     // Trigger TCEforms dimension patching only if required by TYPO3 version according to CompatibilityRegistry.
     if (CompatibilityRegistry::get('FluidTYPO3\\Flux\\Backend\\DynamicFlexForm::NEEDS_TCEFORMS_WRAPPER')) {
         $dataStructArray = $this->patchTceformsWrapper($dataStructArray);
     }
 }
 /**
  * @param array $versionedValues
  * @param string $version
  * @param mixed $flag
  * @param mixed $expected
  * @test
  * @dataProvider getRegisterAndRetrieveFeatureFlagTestValues
  */
 public function testRegisterAndRetieveFeatureFlag(array $versionedValues, $version, $flag, $expected)
 {
     CompatibilityRegistry::registerFeatureFlags($scope, $versionedValues, FALSE);
     $this->assertEquals($expected, CompatibilityRegistry::hasFeatureFlag($scope, $flag, $version));
 }