From a1b2e2a70b1889ec4da7c3ee41bc0694487fbf76 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Mon, 16 May 2016 22:22:23 +0200 Subject: [PATCH 01/99] [TASK] Set stability beta --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index 5ea674a7d..e516eec45 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -21,7 +21,7 @@ 'priority' => 'top', 'loadOrder' => '', 'module' => '', - 'state' => 'stable', + 'state' => 'beta', 'uploadfolder' => 0, 'createDirs' => '', 'modify_tables' => '', From f876ffdcdf8e4e76eda1b62409138f6361e32bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Jen=C3=9F?= Date: Tue, 17 May 2016 12:49:25 +0200 Subject: [PATCH 02/99] [BUGFIX] Always cache TypoScript config in FluxService (#1140) Previously, #getAllTypoScript did not cache the configuration when called from the frontend. This resulted in a rather large performance overhead, since #removeDotsFromTS was called repeatedly. This commit modifies the behaviour such that the configuration is always cached. --- Classes/Service/FluxService.php | 25 +++++++++++++++---------- Tests/Unit/Service/FluxServiceTest.php | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Classes/Service/FluxService.php b/Classes/Service/FluxService.php index 2d4245cec..df3f2f4ef 100644 --- a/Classes/Service/FluxService.php +++ b/Classes/Service/FluxService.php @@ -353,17 +353,22 @@ public function getTypoScriptByPath($path) { * @return array */ public function getAllTypoScript() { - if (!$this->configurationManager instanceof BackendConfigurationManager) { - $typoScript = (array) $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); - $typoScript = GeneralUtility::removeDotsFromTS($typoScript); - return $typoScript; + $pageId = $this->getCurrentPageId(); + if (FALSE === isset(self::$typoScript[$pageId])) { + self::$typoScript[$pageId] = (array) $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); + self::$typoScript[$pageId] = GeneralUtility::removeDotsFromTS(self::$typoScript[$pageId]); + } + return (array) self::$typoScript[$pageId]; + } + + /** + * @return integer + */ + protected function getCurrentPageId() { + if ($this->configurationManager instanceof BackendConfigurationManager) { + return (integer) $this->configurationManager->getCurrentPageId(); } else { - $pageId = $this->configurationManager->getCurrentPageId(); - if (FALSE === isset(self::$typoScript[$pageId])) { - self::$typoScript[$pageId] = (array) $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); - self::$typoScript[$pageId] = GeneralUtility::removeDotsFromTS(self::$typoScript[$pageId]); - } - return (array) self::$typoScript[$pageId]; + return (integer) $GLOBALS['TSFE']->id; } } diff --git a/Tests/Unit/Service/FluxServiceTest.php b/Tests/Unit/Service/FluxServiceTest.php index 4cc19d5f1..b2fe971a3 100644 --- a/Tests/Unit/Service/FluxServiceTest.php +++ b/Tests/Unit/Service/FluxServiceTest.php @@ -339,4 +339,18 @@ public function getConvertFlexFormContentToArrayTestValues() { ); } + /** + * @test + */ + public function testGetAllTypoScriptCache() { + $fluxService = $this->createFluxServiceInstance(array('getCurrentPageId')); + + $configurationManager = $this->getMock('FluidTYPO3\Flux\Configuration\ConfigurationManager', array('getConfiguration')); + $fluxService->injectConfigurationManager($configurationManager); + $configurationManager->expects($this->once())->method('getConfiguration'); + + $this->assertNotNull($fluxService->getAllTypoScript()); + $this->assertNotNull($fluxService->getAllTypoScript()); + } + } From c51ca738a054d51f4b7fe75a38a39ee321f5d681 Mon Sep 17 00:00:00 2001 From: Franz Kugelmann Date: Tue, 3 May 2016 20:46:46 +0200 Subject: [PATCH 03/99] [BUGFIX] Remove disfunctional shortcut icon For content elements with CType='shortcut' flux tries to render an extra icon with link to edit the referenced element. The link however does not work is not necessary anymore, because TYPO3 already places an icon with context menu there, where you can jump to edit the referenced element. --- Classes/Backend/Preview.php | 21 +-------------------- Tests/Unit/Backend/PreviewTest.php | 17 ----------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/Classes/Backend/Preview.php b/Classes/Backend/Preview.php index e6ffbb0a2..5c05abb81 100755 --- a/Classes/Backend/Preview.php +++ b/Classes/Backend/Preview.php @@ -78,11 +78,7 @@ public function preProcess(PageLayoutView &$parentObject, &$drawItem, &$headerCo public function renderPreview(&$headerContent, &$itemContent, array &$row, &$drawItem) { // every provider for tt_content will be asked to get a preview $fieldName = NULL; - if ('shortcut' === $row['CType'] && FALSE === strpos($row['records'], ',')) { - $itemContent = $this->createShortcutIcon($row) . $itemContent; - } else { - $itemContent = '' . $itemContent; - } + $itemContent = '' . $itemContent; $providers = $this->configurationService->resolveConfigurationProviders('tt_content', $fieldName, $row); foreach ($providers as $provider) { /** @var ProviderInterface $provider */ @@ -103,21 +99,6 @@ public function renderPreview(&$headerContent, &$itemContent, array &$row, &$dra return NULL; } - /** - * @param array $row - * @return string - */ - protected function createShortcutIcon($row) { - $targetRecord = $this->getPageTitleAndPidFromContentUid(intval($row['records'])); - $title = LocalizationUtility::translate('reference', 'Flux', array( - $targetRecord['title'] - )); - $targetLink = '?id=' . $targetRecord['pid'] . '#c' . $row['records']; - $iconClass = 't3-icon t3-icon-actions-insert t3-icon-insert-reference t3-icon-actions t3-icon-actions-insert-reference'; - $icon = ''; - return $icon; - } - /** * @param integer $contentUid * @return array diff --git a/Tests/Unit/Backend/PreviewTest.php b/Tests/Unit/Backend/PreviewTest.php index ea128b810..bfda7d4a8 100644 --- a/Tests/Unit/Backend/PreviewTest.php +++ b/Tests/Unit/Backend/PreviewTest.php @@ -47,23 +47,6 @@ public function canExecuteRenderer() { $this->assertEmpty($result); } - /** - * @test - */ - public function canGenerateShortcutIconAndLink() { - $className = 'FluidTYPO3\Flux\Backend\Preview'; - $instance = $this->getMock($className, array('getPageTitleAndPidFromContentUid', 'attachAssets')); - $instance->expects($this->once())->method('getPageTitleAndPidFromContentUid')->with(1)->will($this->returnValue(array('pid' => 1, 'title' => 'test'))); - $headerContent = ''; - $itemContent = ''; - $drawItem = TRUE; - $row = array('uid' => 1, 'CType' => 'shortcut', 'records' => 1); - $this->setup(); - $instance->renderPreview($headerContent, $itemContent, $row, $drawItem); - $this->assertContains('href="?id=1#c1"', $itemContent); - $this->assertContains('', $itemContent); - } - /** * @test */ From 1f660dce9647aa14ba3ede52adc282c941c04352 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Thu, 2 Jun 2016 13:45:50 +0200 Subject: [PATCH 04/99] [DOC] Add references to TCA for Wizard components Close: https://github.com/FluidTYPO3/flux/issues/1060 --- Classes/Form/Wizard/Add.php | 5 ++++- Classes/Form/Wizard/ColorPicker.php | 5 ++++- Classes/Form/Wizard/Edit.php | 5 ++++- Classes/Form/Wizard/Link.php | 5 ++++- Classes/Form/Wizard/ListWizard.php | 7 ++++++- Classes/Form/Wizard/Select.php | 5 ++++- Classes/Form/Wizard/Slider.php | 5 ++++- Classes/Form/Wizard/Suggest.php | 5 ++++- Classes/ViewHelpers/Wizard/AddViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/ColorPickerViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/EditViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/LinkViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/ListViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/SelectViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/SliderViewHelper.php | 3 +++ Classes/ViewHelpers/Wizard/SuggestViewHelper.php | 3 +++ 16 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Classes/Form/Wizard/Add.php b/Classes/Form/Wizard/Add.php index 50b9530d9..e8be32ecf 100644 --- a/Classes/Form/Wizard/Add.php +++ b/Classes/Form/Wizard/Add.php @@ -11,7 +11,10 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * Add + * Add wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Add extends AbstractWizard { diff --git a/Classes/Form/Wizard/ColorPicker.php b/Classes/Form/Wizard/ColorPicker.php index c007329d6..bfb226557 100644 --- a/Classes/Form/Wizard/ColorPicker.php +++ b/Classes/Form/Wizard/ColorPicker.php @@ -11,7 +11,10 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * ColorPicker + * ColorPicker wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class ColorPicker extends AbstractWizard { diff --git a/Classes/Form/Wizard/Edit.php b/Classes/Form/Wizard/Edit.php index 587c82b3f..0b52b6478 100644 --- a/Classes/Form/Wizard/Edit.php +++ b/Classes/Form/Wizard/Edit.php @@ -11,7 +11,10 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * Edit + * Edit wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Edit extends AbstractWizard { diff --git a/Classes/Form/Wizard/Link.php b/Classes/Form/Wizard/Link.php index 0a6b7e95c..46d570d12 100644 --- a/Classes/Form/Wizard/Link.php +++ b/Classes/Form/Wizard/Link.php @@ -12,7 +12,10 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; /** - * Link + * Link wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Link extends AbstractWizard { diff --git a/Classes/Form/Wizard/ListWizard.php b/Classes/Form/Wizard/ListWizard.php index a8603377f..17548ea5f 100644 --- a/Classes/Form/Wizard/ListWizard.php +++ b/Classes/Form/Wizard/ListWizard.php @@ -11,7 +11,12 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * ListWizard + * List wizard + * + * Note: named "ListWizard" due to restriction disallowing classes named "Wizard" + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class ListWizard extends AbstractWizard { diff --git a/Classes/Form/Wizard/Select.php b/Classes/Form/Wizard/Select.php index b2a3f94d7..23a3ac390 100644 --- a/Classes/Form/Wizard/Select.php +++ b/Classes/Form/Wizard/Select.php @@ -11,7 +11,10 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * Select + * Select wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Select extends AbstractWizard { diff --git a/Classes/Form/Wizard/Slider.php b/Classes/Form/Wizard/Slider.php index 500cacb45..ffc597dee 100644 --- a/Classes/Form/Wizard/Slider.php +++ b/Classes/Form/Wizard/Slider.php @@ -11,7 +11,10 @@ use FluidTYPO3\Flux\Form\AbstractWizard; /** - * Slider + * Slider wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Slider extends AbstractWizard { diff --git a/Classes/Form/Wizard/Suggest.php b/Classes/Form/Wizard/Suggest.php index 07422268b..311d4d2ab 100644 --- a/Classes/Form/Wizard/Suggest.php +++ b/Classes/Form/Wizard/Suggest.php @@ -12,7 +12,10 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; /** - * Suggest + * Suggest wizard + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by properties. */ class Suggest extends AbstractWizard { diff --git a/Classes/ViewHelpers/Wizard/AddViewHelper.php b/Classes/ViewHelpers/Wizard/AddViewHelper.php index fc84a0603..1e070c454 100644 --- a/Classes/ViewHelpers/Wizard/AddViewHelper.php +++ b/Classes/ViewHelpers/Wizard/AddViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Add + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class AddViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/ColorPickerViewHelper.php b/Classes/ViewHelpers/Wizard/ColorPickerViewHelper.php index 64e7b2a8a..f6521d9d3 100644 --- a/Classes/ViewHelpers/Wizard/ColorPickerViewHelper.php +++ b/Classes/ViewHelpers/Wizard/ColorPickerViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Color Picker + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class ColorPickerViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/EditViewHelper.php b/Classes/ViewHelpers/Wizard/EditViewHelper.php index 0f28b257f..aef74808d 100644 --- a/Classes/ViewHelpers/Wizard/EditViewHelper.php +++ b/Classes/ViewHelpers/Wizard/EditViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Edit + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class EditViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/LinkViewHelper.php b/Classes/ViewHelpers/Wizard/LinkViewHelper.php index 845bd472b..1ae4ed6ff 100644 --- a/Classes/ViewHelpers/Wizard/LinkViewHelper.php +++ b/Classes/ViewHelpers/Wizard/LinkViewHelper.php @@ -19,6 +19,9 @@ * * * + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class LinkViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/ListViewHelper.php b/Classes/ViewHelpers/Wizard/ListViewHelper.php index c18fa2cee..eb57f8b18 100644 --- a/Classes/ViewHelpers/Wizard/ListViewHelper.php +++ b/Classes/ViewHelpers/Wizard/ListViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: List + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class ListViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/SelectViewHelper.php b/Classes/ViewHelpers/Wizard/SelectViewHelper.php index 6dc9b4989..99f81a850 100644 --- a/Classes/ViewHelpers/Wizard/SelectViewHelper.php +++ b/Classes/ViewHelpers/Wizard/SelectViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Edit + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class SelectViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/SliderViewHelper.php b/Classes/ViewHelpers/Wizard/SliderViewHelper.php index e7bfbc661..7c29e5303 100644 --- a/Classes/ViewHelpers/Wizard/SliderViewHelper.php +++ b/Classes/ViewHelpers/Wizard/SliderViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Slider + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class SliderViewHelper extends AbstractWizardViewHelper { diff --git a/Classes/ViewHelpers/Wizard/SuggestViewHelper.php b/Classes/ViewHelpers/Wizard/SuggestViewHelper.php index 5e6ae70c7..ab3475fb1 100644 --- a/Classes/ViewHelpers/Wizard/SuggestViewHelper.php +++ b/Classes/ViewHelpers/Wizard/SuggestViewHelper.php @@ -13,6 +13,9 @@ /** * Field Wizard: Suggest + * + * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html + * for details about the behaviors that are controlled by arguments. */ class SuggestViewHelper extends AbstractWizardViewHelper { From cbbcaa3496164c767e7c4f137784e29a9aa661d6 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Thu, 2 Jun 2016 13:55:51 +0200 Subject: [PATCH 05/99] [DOC] Pure whitespace fix --- Classes/ViewHelpers/Wizard/LinkViewHelper.php | 2 +- Classes/ViewHelpers/Wizard/ListViewHelper.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/ViewHelpers/Wizard/LinkViewHelper.php b/Classes/ViewHelpers/Wizard/LinkViewHelper.php index 1ae4ed6ff..73fbee053 100644 --- a/Classes/ViewHelpers/Wizard/LinkViewHelper.php +++ b/Classes/ViewHelpers/Wizard/LinkViewHelper.php @@ -19,7 +19,7 @@ * * * - * + * * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by arguments. */ diff --git a/Classes/ViewHelpers/Wizard/ListViewHelper.php b/Classes/ViewHelpers/Wizard/ListViewHelper.php index eb57f8b18..99b4aee64 100644 --- a/Classes/ViewHelpers/Wizard/ListViewHelper.php +++ b/Classes/ViewHelpers/Wizard/ListViewHelper.php @@ -13,7 +13,7 @@ /** * Field Wizard: List - * + * * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by arguments. */ From 8986c49a5da37fd5f46200f3b60b567b9c9d56b7 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sun, 5 Jun 2016 23:26:14 +0200 Subject: [PATCH 06/99] [DOC] Add link to displayCond TCA documentation Links to the official TYPO3 documentation for displayCond in all Field ViewHelpers' displayCond argument and all Field component's displayCondition property. Close: #1096 --- Classes/Form/AbstractFormField.php | 2 ++ Classes/ViewHelpers/Field/AbstractFieldViewHelper.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/Form/AbstractFormField.php b/Classes/Form/AbstractFormField.php index e55613954..da6eacd75 100644 --- a/Classes/Form/AbstractFormField.php +++ b/Classes/Form/AbstractFormField.php @@ -33,6 +33,8 @@ abstract class AbstractFormField extends AbstractFormComponent implements FieldI protected $transform; /** + * Display condition - see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Index.html#displaycond + * * @var string */ protected $displayCondition = NULL; diff --git a/Classes/ViewHelpers/Field/AbstractFieldViewHelper.php b/Classes/ViewHelpers/Field/AbstractFieldViewHelper.php index dd1b2bb2c..4c662fcb4 100755 --- a/Classes/ViewHelpers/Field/AbstractFieldViewHelper.php +++ b/Classes/ViewHelpers/Field/AbstractFieldViewHelper.php @@ -34,7 +34,7 @@ public function initializeArguments() { $this->registerArgument('transform', 'string', 'Set this to transform your value to this type - integer, array (for csv values), float, DateTime, Tx_MyExt_Domain_Model_Object or ObjectStorage with type hint. Also supported are FED Resource classes.'); $this->registerArgument('enabled', 'boolean', 'If FALSE, disables the field in the FlexForm', FALSE, TRUE); $this->registerArgument('requestUpdate', 'boolean', 'If TRUE, the form is force-saved and reloaded when field value changes', FALSE, FALSE); - $this->registerArgument('displayCond', 'string', 'Optional "Display Condition" (TCA style) for this particular field', FALSE, NULL); + $this->registerArgument('displayCond', 'string', 'Optional "Display Condition" (TCA style) for this particular field. See: https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Index.html#displaycond', FALSE, NULL); $this->registerArgument('inherit', 'boolean', 'If TRUE, the value for this particular field is inherited - if inheritance is enabled by the ConfigurationProvider', FALSE, TRUE); $this->registerArgument('inheritEmpty', 'boolean', 'If TRUE, allows empty values (specifically excluding the number zero!) to be inherited - if inheritance is enabled by the ConfigurationProvider', FALSE, TRUE); $this->registerArgument('clear', 'boolean', 'If TRUE, a "clear value" checkbox is displayed next to the field which when checked, completely destroys the current field value all the way down to the stored XML value', FALSE, FALSE); From 2a4caac26438c0fc11a5f7c9bd41bf5f542b76d3 Mon Sep 17 00:00:00 2001 From: Dennis Geldmacher Date: Fri, 24 Jun 2016 00:28:07 +0200 Subject: [PATCH 07/99] [FEATURE] Added bool/boolean to dataType transoformation (#1158) This is very handy if you like to build up an json configuration object with `{v:format.json.encode()}`. Example: ``` {v:format.json.encode(value: settings.slick)} ``` --- Classes/Transformation/FormDataTransformer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Classes/Transformation/FormDataTransformer.php b/Classes/Transformation/FormDataTransformer.php index 50ad50dcc..bedf9bd31 100644 --- a/Classes/Transformation/FormDataTransformer.php +++ b/Classes/Transformation/FormDataTransformer.php @@ -74,6 +74,8 @@ protected function transformValueToType($value, $dataType) { return floatval($value); } elseif ('array' === $dataType) { return explode(',', $value); + } elseif ('bool' === $dataType || 'boolean' === $dataType) { + return boolval($value); } else { return $this->getObjectOfType($dataType, $value); } From 6b88a120cc397925eae29c985541d72dd399b4b7 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Fri, 24 Jun 2016 13:32:48 +0200 Subject: [PATCH 08/99] [TASK] Switch to PSR-2 and shorthand array syntax This change: * Adjusts CGL to confim with PSR-2 and exempts method names required by TYPO3 * Changes all arrays to shorthand array syntax (excluding in unit tests) * Changes some string class names to `::class` references (but not all; primarily where required for line length reduction) * Corrects/adds annotations about deprecation where missing or incorrectly formatted --- Classes/Backend/AreaListItemsProcessor.php | 170 +- Classes/Backend/DynamicFlexForm.php | 326 +-- .../Backend/FormEngine/ProviderProcessor.php | 57 +- Classes/Backend/Preview.php | 252 ++- .../TableConfigurationPostProcessor.php | 417 ++-- Classes/Backend/TceMain.php | 519 +++-- Classes/Backend/TypoScriptTemplate.php | 37 +- .../BackendConfigurationManager.php | 330 +-- .../Configuration/ConfigurationManager.php | 84 +- Classes/Controller/AbstractFluxController.php | 562 ++--- Classes/Core.php | 845 +++---- Classes/FluxPackage.php | 431 ++-- Classes/Form.php | 851 +++---- Classes/Form/AbstractFormComponent.php | 967 ++++---- Classes/Form/AbstractFormContainer.php | 346 +-- Classes/Form/AbstractFormField.php | 842 +++---- Classes/Form/AbstractInlineFormField.php | 855 +++---- Classes/Form/AbstractMultiValueFormField.php | 379 ++-- Classes/Form/AbstractRelationFormField.php | 1155 +++++----- Classes/Form/AbstractWizard.php | 117 +- Classes/Form/Container/Column.php | 211 +- Classes/Form/Container/Container.php | 42 +- Classes/Form/Container/Grid.php | 40 +- Classes/Form/Container/Object.php | 46 +- Classes/Form/Container/Row.php | 40 +- Classes/Form/Container/Section.php | 82 +- Classes/Form/Container/Sheet.php | 152 +- Classes/Form/ContainerInterface.php | 78 +- Classes/Form/Field/Checkbox.php | 19 +- Classes/Form/Field/ControllerActions.php | 903 ++++---- Classes/Form/Field/Custom.php | 67 +- Classes/Form/Field/DateTime.php | 27 +- Classes/Form/Field/File.php | 364 +-- Classes/Form/Field/Flex.php | 19 +- Classes/Form/Field/Inline.php | 19 +- Classes/Form/Field/Inline/Fal.php | 321 +-- Classes/Form/Field/Input.php | 267 +-- Classes/Form/Field/MultiRelation.php | 23 +- Classes/Form/Field/None.php | 67 +- Classes/Form/Field/Passthrough.php | 19 +- Classes/Form/Field/Radio.php | 21 +- Classes/Form/Field/Relation.php | 19 +- Classes/Form/Field/Select.php | 420 ++-- Classes/Form/Field/Text.php | 306 +-- Classes/Form/Field/Tree.php | 368 +-- Classes/Form/Field/UserFunction.php | 99 +- Classes/Form/FieldContainerInterface.php | 12 +- Classes/Form/FieldInterface.php | 236 +- Classes/Form/FormInterface.php | 386 ++-- Classes/Form/InlineRelationFieldInterface.php | 288 +-- Classes/Form/MultiValueFieldInterface.php | 156 +- Classes/Form/RelationFieldInterface.php | 444 ++-- Classes/Form/Wizard/Add.php | 209 +- Classes/Form/Wizard/ColorPicker.php | 249 ++- Classes/Form/Wizard/Edit.php | 213 +- Classes/Form/Wizard/Link.php | 367 +-- Classes/Form/Wizard/ListWizard.php | 257 ++- Classes/Form/Wizard/Select.php | 252 ++- Classes/Form/Wizard/Slider.php | 133 +- Classes/Form/Wizard/Suggest.php | 568 ++--- Classes/Form/WizardInterface.php | 30 +- Classes/Helper/Resolver.php | 282 +-- Classes/Hooks/ContentIconHookSubscriber.php | 213 +- .../RecordListGetTableHookSubscriber.php | 35 +- Classes/Hooks/WizardItemsHookSubscriber.php | 568 ++--- Classes/Outlet/AbstractOutlet.php | 256 ++- Classes/Outlet/Exception.php | 36 +- Classes/Outlet/OutletInterface.php | 108 +- Classes/Outlet/Pipe/AbstractPipe.php | 108 +- Classes/Outlet/Pipe/ControllerPipe.php | 257 +-- Classes/Outlet/Pipe/EmailPipe.php | 326 +-- Classes/Outlet/Pipe/Exception.php | 3 +- Classes/Outlet/Pipe/FlashMessagePipe.php | 257 ++- Classes/Outlet/Pipe/PipeInterface.php | 66 +- Classes/Outlet/Pipe/StandardPipe.php | 3 +- Classes/Outlet/Pipe/TypeConverterPipe.php | 191 +- Classes/Outlet/StandardOutlet.php | 3 +- Classes/Package/FluxPackageFactory.php | 155 +- Classes/Package/FluxPackageInterface.php | 186 +- Classes/Package/PackageNotFoundException.php | 3 +- Classes/Provider/AbstractProvider.php | 1979 +++++++++-------- Classes/Provider/ContentProvider.php | 318 +-- Classes/Provider/Provider.php | 3 +- Classes/Provider/ProviderInterface.php | 762 +++---- Classes/Provider/ProviderResolver.php | 297 +-- Classes/Service/ContentService.php | 880 ++++---- Classes/Service/FluxService.php | 920 ++++---- Classes/Service/RecordService.php | 140 +- .../Service/WorkspacesAwareRecordService.php | 165 +- .../Transformation/FormDataTransformer.php | 246 +- Classes/UserFunction/ClearValueWizard.php | 32 +- Classes/UserFunction/ErrorReporter.php | 38 +- Classes/UserFunction/HtmlOutput.php | 23 +- Classes/UserFunction/NoFields.php | 22 +- Classes/UserFunction/NoSelection.php | 30 +- Classes/UserFunction/NoTemplate.php | 34 +- Classes/Utility/AnnotationUtility.php | 218 +- Classes/Utility/ClipBoardUtility.php | 140 +- Classes/Utility/CompatibilityRegistry.php | 304 +-- Classes/Utility/ExtensionNamingUtility.php | 153 +- Classes/Utility/MiscellaneousUtility.php | 362 +-- Classes/Utility/PathUtility.php | 64 +- Classes/Utility/RecursiveArrayUtility.php | 188 +- Classes/Utility/VersionUtility.php | 39 +- Classes/View/ExposedTemplateView.php | 332 +-- Classes/View/PageLayoutView.php | 28 +- Classes/View/PreviewView.php | 1415 ++++++------ Classes/View/TemplatePaths.php | 580 ++--- Classes/View/ViewContext.php | 425 ++-- .../ViewHelpers/AbstractFormViewHelper.php | 424 ++-- Classes/ViewHelpers/Content/GetViewHelper.php | 336 +-- .../ViewHelpers/Content/RenderViewHelper.php | 38 +- .../Field/AbstractFieldViewHelper.php | 166 +- .../Field/AbstractInlineFieldViewHelper.php | 213 +- .../AbstractMultiValueFieldViewHelper.php | 88 +- .../Field/AbstractRelationFieldViewHelper.php | 258 ++- .../ViewHelpers/Field/CheckboxViewHelper.php | 25 +- .../Field/ControllerActionsViewHelper.php | 244 +- .../ViewHelpers/Field/CustomViewHelper.php | 113 +- Classes/ViewHelpers/Field/FileViewHelper.php | 80 +- .../Field/Inline/FalViewHelper.php | 235 +- .../ViewHelpers/Field/InlineViewHelper.php | 17 +- Classes/ViewHelpers/Field/InputViewHelper.php | 74 +- .../Field/MultiRelationViewHelper.php | 21 +- Classes/ViewHelpers/Field/NoneViewHelper.php | 21 +- Classes/ViewHelpers/Field/RadioViewHelper.php | 23 +- .../ViewHelpers/Field/RelationViewHelper.php | 17 +- .../ViewHelpers/Field/SelectViewHelper.php | 92 +- Classes/ViewHelpers/Field/TextViewHelper.php | 98 +- .../Field/Tree/CategoryViewHelper.php | 91 +- Classes/ViewHelpers/Field/TreeViewHelper.php | 99 +- .../ViewHelpers/Field/UserFuncViewHelper.php | 62 +- .../ViewHelpers/Form/ContainerViewHelper.php | 76 +- .../ViewHelpers/Form/ContentViewHelper.php | 68 +- Classes/ViewHelpers/Form/DataViewHelper.php | 299 +-- Classes/ViewHelpers/Form/ObjectViewHelper.php | 101 +- .../Form/Option/GroupViewHelper.php | 26 +- .../Form/Option/IconViewHelper.php | 26 +- .../Form/Option/SortingViewHelper.php | 31 +- .../Form/Option/TranslationViewHelper.php | 35 +- Classes/ViewHelpers/Form/OptionViewHelper.php | 117 +- Classes/ViewHelpers/Form/RenderViewHelper.php | 101 +- .../ViewHelpers/Form/SectionViewHelper.php | 96 +- Classes/ViewHelpers/Form/SheetViewHelper.php | 104 +- .../ViewHelpers/Form/VariableViewHelper.php | 50 +- Classes/ViewHelpers/FormViewHelper.php | 197 +- Classes/ViewHelpers/Grid/ColumnViewHelper.php | 101 +- Classes/ViewHelpers/Grid/RowViewHelper.php | 70 +- Classes/ViewHelpers/GridViewHelper.php | 73 +- .../Pipe/AbstractPipeViewHelper.php | 97 +- .../ViewHelpers/Pipe/ControllerViewHelper.php | 92 +- Classes/ViewHelpers/Pipe/EmailViewHelper.php | 81 +- .../Pipe/FlashMessageViewHelper.php | 69 +- .../Pipe/TypeConverterViewHelper.php | 80 +- Classes/ViewHelpers/VariableViewHelper.php | 90 +- Classes/ViewHelpers/Widget/GridViewHelper.php | 81 +- .../Wizard/AbstractWizardViewHelper.php | 79 +- Classes/ViewHelpers/Wizard/AddViewHelper.php | 71 +- .../Wizard/ColorPickerViewHelper.php | 70 +- Classes/ViewHelpers/Wizard/EditViewHelper.php | 58 +- Classes/ViewHelpers/Wizard/LinkViewHelper.php | 78 +- Classes/ViewHelpers/Wizard/ListViewHelper.php | 67 +- .../ViewHelpers/Wizard/SelectViewHelper.php | 59 +- .../ViewHelpers/Wizard/SliderViewHelper.php | 56 +- .../ViewHelpers/Wizard/SuggestViewHelper.php | 120 +- Tests/Unit/AbstractExceptionTestCase.php | 54 +- Tests/Unit/AbstractTestCase.php | 405 ++-- .../Backend/AreaListItemsProcessorTest.php | 163 +- Tests/Unit/Backend/DynamicFlexFormTest.php | 90 +- Tests/Unit/Backend/PreviewTest.php | 147 +- .../TableConfigurationPostProcessorTest.php | 171 +- Tests/Unit/Backend/TceMainTest.php | 525 +++-- Tests/Unit/Backend/TypoScriptTemplateTest.php | 62 +- .../BackendConfigurationManagerTest.php | 423 ++-- .../ConfigurationManagerTest.php | 146 +- .../AbstractFluxControllerTestCase.php | 1024 +++++---- .../Unit/Controller/ContentControllerTest.php | 46 +- Tests/Unit/CoreTest.php | 496 +++-- Tests/Unit/Form/AbstractFormTest.php | 441 ++-- .../Form/Container/AbstractContainerTest.php | 138 +- Tests/Unit/Form/Container/ColumnTest.php | 18 +- Tests/Unit/Form/Container/ContainerTest.php | 42 +- Tests/Unit/Form/Container/GridTest.php | 148 +- Tests/Unit/Form/Container/ObjectTest.php | 21 +- Tests/Unit/Form/Container/RowTest.php | 65 +- Tests/Unit/Form/Container/SectionTest.php | 49 +- Tests/Unit/Form/Container/SheetTest.php | 82 +- Tests/Unit/Form/Field/AbstractFieldTest.php | 378 ++-- Tests/Unit/Form/Field/CheckboxTest.php | 24 +- .../Unit/Form/Field/ControllerActionsTest.php | 666 +++--- Tests/Unit/Form/Field/CustomTest.php | 57 +- Tests/Unit/Form/Field/DateTimeTest.php | 18 +- Tests/Unit/Form/Field/FileTest.php | 108 +- Tests/Unit/Form/Field/FlexTest.php | 18 +- Tests/Unit/Form/Field/Inline/FalTest.php | 52 +- Tests/Unit/Form/Field/InlineTest.php | 62 +- Tests/Unit/Form/Field/InputTest.php | 68 +- Tests/Unit/Form/Field/MultiRelationTest.php | 34 +- Tests/Unit/Form/Field/NoneTest.php | 18 +- Tests/Unit/Form/Field/PassthroughTest.php | 18 +- Tests/Unit/Form/Field/RelationTest.php | 28 +- Tests/Unit/Form/Field/SelectTest.php | 261 +-- Tests/Unit/Form/Field/TextTest.php | 120 +- Tests/Unit/Form/Field/TreeTest.php | 22 +- Tests/Unit/Form/Field/UserFunctionTest.php | 22 +- Tests/Unit/Form/Wizard/AbstractWizardTest.php | 132 +- Tests/Unit/Form/Wizard/AddTest.php | 26 +- Tests/Unit/Form/Wizard/ColorPickerTest.php | 26 +- Tests/Unit/Form/Wizard/EditTest.php | 26 +- Tests/Unit/Form/Wizard/LinkTest.php | 87 +- Tests/Unit/Form/Wizard/ListWizardTest.php | 28 +- Tests/Unit/Form/Wizard/SelectTest.php | 110 +- Tests/Unit/Form/Wizard/SliderTest.php | 24 +- Tests/Unit/Form/Wizard/SuggestTest.php | 50 +- Tests/Unit/FormTest.php | 792 +++---- Tests/Unit/Helper/ResolveUtilityTest.php | 215 +- .../Hooks/ContentIconHookSubscriberTest.php | 140 +- .../RecordListGetTableHookSubscriberTest.php | 50 +- .../Hooks/WizardItemsHookSubscriberTest.php | 338 +-- Tests/Unit/Outlet/AbstractOutletTestCase.php | 122 +- Tests/Unit/Outlet/ExceptionTest.php | 3 +- .../Unit/Outlet/Pipe/AbstractPipeTestCase.php | 88 +- Tests/Unit/Outlet/Pipe/ControllerPipeTest.php | 197 +- Tests/Unit/Outlet/Pipe/EmailPipeTest.php | 174 +- .../Unit/Outlet/Pipe/FlashMessagePipeTest.php | 100 +- Tests/Unit/Outlet/Pipe/StandardPipeTest.php | 36 +- .../Outlet/Pipe/TypeConverterPipeTest.php | 167 +- Tests/Unit/Outlet/StandardOutletTest.php | 3 +- Tests/Unit/Provider/AbstractProviderTest.php | 1452 ++++++------ Tests/Unit/Provider/ContentProviderTest.php | 452 ++-- Tests/Unit/Provider/ProviderResolverTest.php | 253 ++- Tests/Unit/Provider/ProviderTest.php | 246 +- Tests/Unit/Service/ContentServiceTest.php | 676 +++--- Tests/Unit/Service/FluxServiceTest.php | 686 +++--- Tests/Unit/Service/RecordServiceTest.php | 224 +- .../WorkspacesAwareRecordServiceTest.php | 50 +- .../FormDataTransformerTest.php | 100 +- .../UserFunction/AbstractUserFunctionTest.php | 132 +- .../UserFunction/ClearValueWizardTest.php | 28 +- Tests/Unit/UserFunction/ErrorReporterTest.php | 102 +- Tests/Unit/UserFunction/HtmlOutputTest.php | 39 +- Tests/Unit/UserFunction/NoFieldsTest.php | 3 +- Tests/Unit/UserFunction/NoSelectionTest.php | 33 +- Tests/Unit/UserFunction/NoTemplateTest.php | 33 +- Tests/Unit/Utility/AnnotationUtilityTest.php | 223 +- .../Utility/CompatibilityRegistryTest.php | 228 +- .../Utility/ExtensionNamingUtilityTest.php | 254 ++- .../Unit/Utility/MiscellaneousUtilityTest.php | 430 ++-- .../Utility/RecursiveArrayUtilityTest.php | 173 +- Tests/Unit/Utility/VersionUtilityTest.php | 34 +- Tests/Unit/View/ExposedTemplateViewTest.php | 395 ++-- Tests/Unit/View/PreviewViewTest.php | 555 ++--- Tests/Unit/View/TemplatePathsTest.php | 244 +- Tests/Unit/View/ViewContextTest.php | 60 +- .../AbstractFormViewHelperTestCase.php | 299 +-- .../AbstractViewHelperTestCase.php | 308 +-- .../ViewHelpers/Content/GetViewHelperTest.php | 270 +-- .../Content/RenderViewHelperTest.php | 202 +- .../Field/AbstractFieldViewHelperTestCase.php | 22 +- .../Field/CheckboxViewHelperTest.php | 3 +- .../Field/ControllerActionsViewHelperTest.php | 228 +- .../Field/CustomViewHelperTest.php | 111 +- .../ViewHelpers/Field/FileViewHelperTest.php | 3 +- .../Field/Inline/FalViewHelperTest.php | 95 +- .../Field/InlineViewHelperTest.php | 34 +- .../Field/MultiRelationViewHelperTest.php | 3 +- .../ViewHelpers/Field/NoneViewHelperTest.php | 3 +- .../Field/RelationViewHelperTest.php | 3 +- .../Field/SelectViewHelperTest.php | 3 +- .../ViewHelpers/Field/TextViewHelperTest.php | 3 +- .../Field/Tree/CategoryViewHelperTest.php | 3 +- .../ViewHelpers/Field/TreeViewHelperTest.php | 3 +- .../Form/ContainerViewHelperTest.php | 27 +- .../Form/ContentViewHelperTest.php | 83 +- .../ViewHelpers/Form/DataViewHelperTest.php | 403 ++-- .../ViewHelpers/Form/ObjectViewHelperTest.php | 3 +- .../Form/Option/GroupViewHelperTest.php | 3 +- .../Form/Option/IconViewHelperTest.php | 3 +- .../Form/Option/SortingViewHelperTest.php | 3 +- .../Form/Option/TranslationViewHelperTest.php | 3 +- .../ViewHelpers/Form/OptionViewHelperTest.php | 3 +- .../ViewHelpers/Form/RenderViewHelperTest.php | 31 +- .../Form/SectionViewHelperTest.php | 3 +- .../Form/VariableViewHelperTest.php | 53 +- .../Pipe/AbstractPipeViewHelperTest.php | 25 +- .../Pipe/ControllerViewHelperTest.php | 42 +- .../ViewHelpers/Pipe/EmailViewHelperTest.php | 38 +- .../Pipe/FlashMessageViewHelperTest.php | 44 +- .../Pipe/TypeConverterViewHelperTest.php | 40 +- .../ViewHelpers/VariableViewHelperTest.php | 42 +- .../ViewHelpers/Widget/GridViewHelperTest.php | 17 +- .../AbstractWizardViewHelperTestCase.php | 29 +- .../ViewHelpers/Wizard/AddViewHelperTest.php | 3 +- .../Wizard/ColorPickerViewHelperTest.php | 3 +- .../ViewHelpers/Wizard/EditViewHelperTest.php | 3 +- .../ViewHelpers/Wizard/LinkViewHelperTest.php | 3 +- .../ViewHelpers/Wizard/ListViewHelperTest.php | 3 +- .../Wizard/SelectViewHelperTest.php | 3 +- .../Wizard/SliderViewHelperTest.php | 3 +- .../Wizard/SuggestViewHelperTest.php | 3 +- 300 files changed, 29411 insertions(+), 26101 deletions(-) diff --git a/Classes/Backend/AreaListItemsProcessor.php b/Classes/Backend/AreaListItemsProcessor.php index 6f0187a6f..869e0cd5f 100644 --- a/Classes/Backend/AreaListItemsProcessor.php +++ b/Classes/Backend/AreaListItemsProcessor.php @@ -18,94 +18,98 @@ /** * Returns options for a "content area" selector box */ -class AreaListItemsProcessor { +class AreaListItemsProcessor +{ - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @var FluxService - */ - protected $fluxService; + /** + * @var FluxService + */ + protected $fluxService; - /** - * @var RecordService - */ - protected $recordService; + /** + * @var RecordService + */ + protected $recordService; - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - $this->fluxService = $this->objectManager->get('FluidTYPO3\Flux\Service\FluxService'); - $this->recordService = $this->objectManager->get('FluidTYPO3\Flux\Service\RecordService'); - } + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); + $this->fluxService = $this->objectManager->get('FluidTYPO3\Flux\Service\FluxService'); + $this->recordService = $this->objectManager->get('FluidTYPO3\Flux\Service\RecordService'); + } - /** - * @return array - */ - protected function readParentAndAreaNameFromUrl() { - $urlRequestedParent = ObjectAccess::getPropertyPath($_GET, 'defVals.tt_content.tx_flux_parent'); - $urlRequestedArea = ObjectAccess::getPropertyPath($_GET, 'defVals.tt_content.tx_flux_column'); - return array($urlRequestedParent, $urlRequestedArea); - } + /** + * @return array + */ + protected function readParentAndAreaNameFromUrl() + { + $urlRequestedParent = ObjectAccess::getPropertyPath($_GET, 'defVals.tt_content.tx_flux_parent'); + $urlRequestedArea = ObjectAccess::getPropertyPath($_GET, 'defVals.tt_content.tx_flux_column'); + return [$urlRequestedParent, $urlRequestedArea]; + } - /** - * ItemsProcFunc - adds items to tt_content.colPos selector (first, pipes through EXT:gridelements) - * - * @param array $params - * @return void - */ - public function itemsProcFunc(&$params) { - list ($urlRequestedParent, $urlRequestedArea) = $this->readParentAndAreaNameFromUrl(); - if ($urlRequestedParent) { - $parentUid = $urlRequestedParent; - } else { - $parentUid = $params['row']['tx_flux_parent']; - } - if ($parentUid > 0) { - $items = $this->getContentAreasDefinedInContentElement($parentUid); - } else { - $items = array(); - } - // adds an empty option in the beginning of the item list - array_unshift($items, array('', '')); - if ($urlRequestedArea) { - foreach ($items as $index => $set) { - if ($set[1] !== $urlRequestedArea) { - unset($items[$index]); - } - } - } - $params['items'] = $items; - } - - /** - * @param integer $uid - * @return array - */ - public function getContentAreasDefinedInContentElement($uid) { - $uid = (integer) $uid; - $record = $this->recordService->getSingle('tt_content', '*', $uid); - /** @var $providers ProviderInterface[] */ - $providers = $this->fluxService->resolveConfigurationProviders('tt_content', NULL, $record); - $columns = array(); - foreach ($providers as $provider) { - $grid = $provider->getGrid($record); - if (TRUE === empty($grid)) { - continue; - } - $gridConfiguration = $grid->build(); - foreach ($gridConfiguration['rows'] as $row) { - foreach ($row['columns'] as $column) { - array_push($columns, array($column['label'] . ' (' . $column['name'] . ')', $column['name'])); - } - } - } - return array_unique($columns, SORT_REGULAR); - } + /** + * ItemsProcFunc - adds items to tt_content.colPos selector (first, pipes through EXT:gridelements) + * + * @param array $params + * @return void + */ + public function itemsProcFunc(&$params) + { + list ($urlRequestedParent, $urlRequestedArea) = $this->readParentAndAreaNameFromUrl(); + if ($urlRequestedParent) { + $parentUid = $urlRequestedParent; + } else { + $parentUid = $params['row']['tx_flux_parent']; + } + if ($parentUid > 0) { + $items = $this->getContentAreasDefinedInContentElement($parentUid); + } else { + $items = []; + } + // adds an empty option in the beginning of the item list + array_unshift($items, ['', '']); + if ($urlRequestedArea) { + foreach ($items as $index => $set) { + if ($set[1] !== $urlRequestedArea) { + unset($items[$index]); + } + } + } + $params['items'] = $items; + } + /** + * @param integer $uid + * @return array + */ + public function getContentAreasDefinedInContentElement($uid) + { + $uid = (integer) $uid; + $record = $this->recordService->getSingle('tt_content', '*', $uid); + /** @var $providers ProviderInterface[] */ + $providers = $this->fluxService->resolveConfigurationProviders('tt_content', null, $record); + $columns = []; + foreach ($providers as $provider) { + $grid = $provider->getGrid($record); + if (true === empty($grid)) { + continue; + } + $gridConfiguration = $grid->build(); + foreach ($gridConfiguration['rows'] as $row) { + foreach ($row['columns'] as $column) { + array_push($columns, [$column['label'] . ' (' . $column['name'] . ')', $column['name']]); + } + } + } + return array_unique($columns, SORT_REGULAR); + } } diff --git a/Classes/Backend/DynamicFlexForm.php b/Classes/Backend/DynamicFlexForm.php index 0c89ee30a..75d3e53cf 100755 --- a/Classes/Backend/DynamicFlexForm.php +++ b/Classes/Backend/DynamicFlexForm.php @@ -11,180 +11,192 @@ use FluidTYPO3\Flux\Service\FluxService; use FluidTYPO3\Flux\Service\WorkspacesAwareRecordService; use FluidTYPO3\Flux\Utility\CompatibilityRegistry; +use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend; /** * Dynamic FlexForm insertion hook class */ -class DynamicFlexForm { +class DynamicFlexForm +{ - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @var FluxService - */ - protected $configurationService; + /** + * @var FluxService + */ + protected $configurationService; - /** - * @var WorkspacesAwareRecordService - */ - protected $recordService; + /** + * @var WorkspacesAwareRecordService + */ + protected $recordService; - /** - * @var VariableFrontend - */ - protected $cache; + /** + * @var VariableFrontend + */ + protected $cache; - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * @param FluxService $service - * @return void - */ - public function injectConfigurationService(FluxService $service) { - $this->configurationService = $service; - } + /** + * @param FluxService $service + * @return void + */ + public function injectConfigurationService(FluxService $service) + { + $this->configurationService = $service; + } - /** - * @param WorkspacesAwareRecordService $recordService - * @return void - */ - public function injectRecordService(WorkspacesAwareRecordService $recordService) { - $this->recordService = $recordService; - } + /** + * @param WorkspacesAwareRecordService $recordService + * @return void + */ + public function injectRecordService(WorkspacesAwareRecordService $recordService) + { + $this->recordService = $recordService; + } - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->injectObjectManager(GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager')); - $this->injectConfigurationService($this->objectManager->get('FluidTYPO3\Flux\Service\FluxService')); - $this->injectRecordService($this->objectManager->get('FluidTYPO3\Flux\Service\WorkspacesAwareRecordService')); - $this->cache = $this->objectManager->get('TYPO3\\CMS\\Core\\Cache\\CacheManager', $this->objectManager)->getCache('flux'); - } + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->injectObjectManager(GeneralUtility::makeInstance(ObjectManager::class)); + $this->injectConfigurationService($this->objectManager->get(FluxService::class)); + $this->injectRecordService($this->objectManager->get(WorkspacesAwareRecordService::class)); + $this->cache = $this->objectManager->get(CacheManager::class, $this->objectManager)->getCache('flux'); + } - /** - * 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); - } - } + /** + * 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 + * @codingStandardsIgnoreStart this method signature is excluded from CGL checks due to required "bad" method name + */ + public function getFlexFormDS_postProcessDS(&$dataStructArray, $conf, &$row, $table, $fieldName) + { + // @codingStandardsIgnoreEnd This comment ends CGL exemption to ensure only the signature is exempted! - /** - * Temporary method during FormEngine transition! - * - * Performs a duplication in data source, applying a wrapper - * around field configurations which require it for correct - * rendering in flex form containers. - * - * @param array $dataStructure - * @return array - */ - protected function patchTceformsWrapper(array $dataStructure, $parentIndex = NULL) { - foreach ($dataStructure as $index => $subStructure) { - if (is_array($subStructure)) { - $dataStructure[$index] = $this->patchTceformsWrapper($subStructure, $index); - } - } - if (isset($dataStructure['config']['type']) && $parentIndex !== 'TCEforms') { - $dataStructure = array('TCEforms' => $dataStructure); - } - return $dataStructure; - } + 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 = []; + } + $providers = $this->configurationService->resolveConfigurationProviders($table, $fieldName, $row); + foreach ($providers as $provider) { + $provider->postProcessDataStructure($row, $dataStructArray, $conf); + } + if (empty($dataStructArray)) { + $dataStructArray = ['ROOT' => ['el' => []]]; + } + $evaluationParameters = []; + $this->cache->set( + $defaultDataSourceCacheIdentifier, + $this->recursivelyEvaluateClosures($dataStructArray, $evaluationParameters), + [], + (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); + } + } - /** - * Method used to ensure that all Closures in the data - * structure are evaluated. The returned array is then - * serialisation-safe. Closures can occur whenever Flux - * fields of certain types are used, for example the - * "custom" field type (which generates a Closure that - * evaluates the tag content in a deferred manner). - * - * @param array $dataStructureArray - * @param array $parameters - * @return array - */ - protected function recursivelyEvaluateClosures(array $dataStructureArray, array $parameters) { - foreach ($dataStructureArray as $key => $value) { - if ($value instanceof \Closure) { - $dataStructureArray[$key] = $value($parameters); - } elseif (is_array($value)) { - $dataStructureArray[$key] = $this->recursivelyEvaluateClosures($value, $parameters); - } - } - return $dataStructureArray; - } + /** + * Temporary method during FormEngine transition! + * + * Performs a duplication in data source, applying a wrapper + * around field configurations which require it for correct + * rendering in flex form containers. + * + * @param array $dataStructure + * @return array + */ + protected function patchTceformsWrapper(array $dataStructure, $parentIndex = null) + { + foreach ($dataStructure as $index => $subStructure) { + if (is_array($subStructure)) { + $dataStructure[$index] = $this->patchTceformsWrapper($subStructure, $index); + } + } + if (isset($dataStructure['config']['type']) && $parentIndex !== 'TCEforms') { + $dataStructure = ['TCEforms' => $dataStructure]; + } + return $dataStructure; + } + /** + * Method used to ensure that all Closures in the data + * structure are evaluated. The returned array is then + * serialisation-safe. Closures can occur whenever Flux + * fields of certain types are used, for example the + * "custom" field type (which generates a Closure that + * evaluates the tag content in a deferred manner). + * + * @param array $dataStructureArray + * @param array $parameters + * @return array + */ + protected function recursivelyEvaluateClosures(array $dataStructureArray, array $parameters) + { + foreach ($dataStructureArray as $key => $value) { + if ($value instanceof \Closure) { + $dataStructureArray[$key] = $value($parameters); + } elseif (is_array($value)) { + $dataStructureArray[$key] = $this->recursivelyEvaluateClosures($value, $parameters); + } + } + return $dataStructureArray; + } } diff --git a/Classes/Backend/FormEngine/ProviderProcessor.php b/Classes/Backend/FormEngine/ProviderProcessor.php index a7985af7d..fb222bf5d 100644 --- a/Classes/Backend/FormEngine/ProviderProcessor.php +++ b/Classes/Backend/FormEngine/ProviderProcessor.php @@ -9,32 +9,39 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; -class ProviderProcessor implements FormDataProviderInterface { +class ProviderProcessor implements FormDataProviderInterface +{ - /** - * @param array $result - * @return void - */ - public function addData(array $result) { - $providers = $this->getProviderResolver()->resolveConfigurationProviders($result['tableName'], NULL, $result['databaseRow']); - foreach ($providers as $provider) { - $result = $provider->processTableConfiguration($result['databaseRow'], $result); - } - return $result; - } + /** + * @param array $result + * @return void + */ + public function addData(array $result) + { + $providers = $this->getProviderResolver()->resolveConfigurationProviders( + $result['tableName'], + null, + $result['databaseRow'] + ); + foreach ($providers as $provider) { + $result = $provider->processTableConfiguration($result['databaseRow'], $result); + } + return $result; + } - /** - * @return ProviderResolver - */ - protected function getProviderResolver() { - return $this->getObjectManager()->get(ProviderResolver::class); - } - - /** - * @return ObjectManagerInterface - */ - protected function getObjectManager() { - return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); - } + /** + * @return ProviderResolver + */ + protected function getProviderResolver() + { + return $this->getObjectManager()->get(ProviderResolver::class); + } + /** + * @return ObjectManagerInterface + */ + protected function getObjectManager() + { + return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); + } } diff --git a/Classes/Backend/Preview.php b/Classes/Backend/Preview.php index 5c05abb81..29044936c 100755 --- a/Classes/Backend/Preview.php +++ b/Classes/Backend/Preview.php @@ -23,121 +23,139 @@ /** * Fluid Template preview renderer */ -class Preview implements PageLayoutViewDrawItemHookInterface { - - /** - * @var boolean - */ - protected static $assetsIncluded = FALSE; - - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - - /** - * @var FluxService - */ - protected $configurationService; - - /** - * @var RecordService - */ - protected $recordService; - - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - $this->configurationService = $this->objectManager->get('FluidTYPO3\Flux\Service\FluxService'); - $this->recordService = $this->objectManager->get('FluidTYPO3\Flux\Service\RecordService'); - } - - /** - * - * @param PageLayoutView $parentObject - * @param boolean $drawItem - * @param string $headerContent - * @param string $itemContent - * @param array $row - * @return void - */ - public function preProcess(PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row) { - $this->renderPreview($headerContent, $itemContent, $row, $drawItem); - unset($parentObject); - } - - /** - * @param string $headerContent - * @param string $itemContent - * @param array $row - * @param boolean $drawItem - * @return NULL - */ - public function renderPreview(&$headerContent, &$itemContent, array &$row, &$drawItem) { - // every provider for tt_content will be asked to get a preview - $fieldName = NULL; - $itemContent = '' . $itemContent; - $providers = $this->configurationService->resolveConfigurationProviders('tt_content', $fieldName, $row); - foreach ($providers as $provider) { - /** @var ProviderInterface $provider */ - list ($previewHeader, $previewContent, $continueDrawing) = $provider->getPreview($row); - if (FALSE === empty($previewHeader)) { - $headerContent = $previewHeader . (FALSE === empty($headerContent) ? ': ' . $headerContent : ''); - $drawItem = FALSE; - } - if (FALSE === empty($previewContent)) { - $itemContent .= $previewContent; - $drawItem = FALSE; - } - if (FALSE === $continueDrawing) { - break; - } - } - $this->attachAssets(); - return NULL; - } - - /** - * @param integer $contentUid - * @return array - */ - protected function getPageTitleAndPidFromContentUid($contentUid) { - return reset($this->recordService->get('tt_content t, pages p', 'p.title, t.pid', "t.uid = '" . $contentUid . "' AND p.uid = t.pid")); - } - - /** - * @return void - */ - protected function attachAssets() { - if (FALSE === self::$assetsIncluded) { - $doc = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Template\\ModuleTemplate'); - $doc->backPath = $GLOBALS['BACK_PATH']; - - /** @var PageRenderer $pageRenderer */ - $pageRenderer = $doc->getPageRenderer(); - $pageRenderer->addCssFile($doc->backPath . ExtensionManagementUtility::extRelPath('flux') . 'Resources/Public/css/grid.css'); - - // /typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js - // is not the perfect solution for Flux Grids! - // an adapted version of DragDrop.js is used - Resources/Public/js/VersionSevenPointTwo/DragDrop.js - // Also fluxCollapse.js is updated. - $fullJsPath = PathUtility::getRelativePath(PATH_typo3, GeneralUtility::getFileAbsFileName('EXT:flux/Resources/Public/js/')); - - // requirejs - $pageRenderer->addRequireJsConfiguration(array( - 'paths' => array( - 'FluidTypo3/Flux/DragDrop' => $fullJsPath . 'DragDrop', - ), - )); - $pageRenderer->loadRequireJsModule('FluidTypo3/Flux/DragDrop'); - - // This is necessary for fluxCollapse.js - $pageRenderer->loadExtJS(); - $pageRenderer->addJsFile($doc->backPath . ExtensionManagementUtility::extRelPath('flux') . 'Resources/Public/js/fluxCollapse.js'); - self::$assetsIncluded = TRUE; - } - } - +class Preview implements PageLayoutViewDrawItemHookInterface +{ + + /** + * @var boolean + */ + protected static $assetsIncluded = false; + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var FluxService + */ + protected $configurationService; + + /** + * @var RecordService + */ + protected $recordService; + + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); + $this->configurationService = $this->objectManager->get('FluidTYPO3\Flux\Service\FluxService'); + $this->recordService = $this->objectManager->get('FluidTYPO3\Flux\Service\RecordService'); + } + + /** + * + * @param PageLayoutView $parentObject + * @param boolean $drawItem + * @param string $headerContent + * @param string $itemContent + * @param array $row + * @return void + */ + public function preProcess(PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row) + { + $this->renderPreview($headerContent, $itemContent, $row, $drawItem); + unset($parentObject); + } + + /** + * @param string $headerContent + * @param string $itemContent + * @param array $row + * @param boolean $drawItem + * @return NULL + */ + public function renderPreview(&$headerContent, &$itemContent, array &$row, &$drawItem) + { + // every provider for tt_content will be asked to get a preview + $fieldName = null; + $itemContent = '' . $itemContent; + $providers = $this->configurationService->resolveConfigurationProviders('tt_content', $fieldName, $row); + foreach ($providers as $provider) { + /** @var ProviderInterface $provider */ + list ($previewHeader, $previewContent, $continueDrawing) = $provider->getPreview($row); + if (false === empty($previewHeader)) { + $headerContent = $previewHeader . (false === empty($headerContent) ? ': ' . $headerContent : ''); + $drawItem = false; + } + if (false === empty($previewContent)) { + $itemContent .= $previewContent; + $drawItem = false; + } + if (false === $continueDrawing) { + break; + } + } + $this->attachAssets(); + return null; + } + + /** + * @param integer $contentUid + * @return array + */ + protected function getPageTitleAndPidFromContentUid($contentUid) + { + return reset( + $this->recordService->get( + 'tt_content t, pages p', + 'p.title, t.pid', + "t.uid = '" . $contentUid . "' AND p.uid = t.pid" + ) + ); + } + + /** + * @return void + */ + protected function attachAssets() + { + if (false === self::$assetsIncluded) { + $doc = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\Template\\ModuleTemplate'); + $doc->backPath = $GLOBALS['BACK_PATH']; + + /** @var PageRenderer $pageRenderer */ + $pageRenderer = $doc->getPageRenderer(); + $pageRenderer->addCssFile( + $doc->backPath . ExtensionManagementUtility::extRelPath('flux') . 'Resources/Public/css/grid.css' + ); + + // /typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js + // is not the perfect solution for Flux Grids! + // an adapted version of DragDrop.js is used - Resources/Public/js/VersionSevenPointTwo/DragDrop.js + // Also fluxCollapse.js is updated. + $fullJsPath = PathUtility::getRelativePath( + PATH_typo3, + GeneralUtility::getFileAbsFileName('EXT:flux/Resources/Public/js/') + ); + + // requirejs + $pageRenderer->addRequireJsConfiguration([ + 'paths' => [ + 'FluidTypo3/Flux/DragDrop' => $fullJsPath . 'DragDrop', + ], + ]); + $pageRenderer->loadRequireJsModule('FluidTypo3/Flux/DragDrop'); + + // This is necessary for fluxCollapse.js + $pageRenderer->loadExtJS(); + $pageRenderer->addJsFile( + $doc->backPath . ExtensionManagementUtility::extRelPath('flux') . 'Resources/Public/js/fluxCollapse.js' + ); + self::$assetsIncluded = true; + } + } } diff --git a/Classes/Backend/TableConfigurationPostProcessor.php b/Classes/Backend/TableConfigurationPostProcessor.php index 847317aef..d1e29108a 100644 --- a/Classes/Backend/TableConfigurationPostProcessor.php +++ b/Classes/Backend/TableConfigurationPostProcessor.php @@ -25,209 +25,232 @@ * Simply loads the Flux service and lets methods * on this Service load necessary configuration. */ -class TableConfigurationPostProcessor implements TableConfigurationPostProcessingHookInterface { +class TableConfigurationPostProcessor implements TableConfigurationPostProcessingHookInterface +{ - /** - * @var array - */ - private static $tableTemplate = array( - 'title' => NULL, - 'label' => NULL, - 'tstamp' => 'tstamp', - 'crdate' => 'crdate', - 'cruser_id' => 'cruser_id', - 'dividers2tabs' => TRUE, - 'enablecolumns' => array(), - 'iconfile' => '', - 'hideTable' => FALSE, - ); + /** + * @var array + */ + private static $tableTemplate = [ + 'title' => null, + 'label' => null, + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'dividers2tabs' => true, + 'enablecolumns' => [], + 'iconfile' => '', + 'hideTable' => false, + ]; - /** - * @return void - */ - public function processData() { - if (TYPO3_REQUESTTYPE_INSTALL !== (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) { - $this->generateTableConfigurationForProviderForms(); - } - } + /** + * @return void + */ + public function processData() + { + if (TYPO3_REQUESTTYPE_INSTALL !== (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) { + $this->generateTableConfigurationForProviderForms(); + } + } - /** - * @return void - */ - protected function generateTableConfigurationForProviderForms() { - $resolver = new Resolver(); - $forms = Core::getRegisteredFormsForTables(); - $packages = $this->getInstalledFluxPackages(); - $models = $resolver->resolveDomainFormClassInstancesFromPackages($packages); - foreach ($forms as $fullTableName => $form) { - $this->processFormForTable($fullTableName, $form); - } - foreach ($models as $modelClassName => $form) { - $fullTableName = $resolver->resolveDatabaseTableName($modelClassName); - if (NULL === $form) { - $form = $this->generateFormInstanceFromClassName($modelClassName, $fullTableName); - } - if (NULL === $form->getName()) { - $form->setName($fullTableName); - } - $this->processFormForTable($fullTableName, $form); - } - } + /** + * @return void + */ + protected function generateTableConfigurationForProviderForms() + { + $resolver = new Resolver(); + $forms = Core::getRegisteredFormsForTables(); + $packages = $this->getInstalledFluxPackages(); + $models = $resolver->resolveDomainFormClassInstancesFromPackages($packages); + foreach ($forms as $fullTableName => $form) { + $this->processFormForTable($fullTableName, $form); + } + foreach ($models as $modelClassName => $form) { + $fullTableName = $resolver->resolveDatabaseTableName($modelClassName); + if (null === $form) { + $form = $this->generateFormInstanceFromClassName($modelClassName, $fullTableName); + } + if (null === $form->getName()) { + $form->setName($fullTableName); + } + $this->processFormForTable($fullTableName, $form); + } + } - /** - * @return array - */ - protected function getInstalledFluxPackages() { - return array_keys(Core::getRegisteredPackagesForAutoForms()); - } + /** + * @return array + */ + protected function getInstalledFluxPackages() + { + return array_keys(Core::getRegisteredPackagesForAutoForms()); + } - /** - * @param string $table - * @param Form $form - */ - protected function processFormForTable($table, Form $form) { - $extensionName = $form->getExtensionName(); - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); - $tableConfiguration = self::$tableTemplate; - $fields = array(); - $labelFields = $form->getOption(Form::OPTION_TCA_LABELS); - $enableColumns = array(); - foreach ($form->getFields() as $field) { - $name = $field->getName(); - // note: extracts the TCEforms sub-array from the configuration, as required in TCA. - $fields[$name] = array_pop($field->build()); - } - if (TRUE === $form->getOption(Form::OPTION_TCA_HIDE)) { - $enableColumns['disabled'] = 'hidden'; - } - if (TRUE === $form->getOption(Form::OPTION_TCA_START)) { - $enableColumns['start'] = 'starttime'; - } - if (TRUE === $form->getOption(Form::OPTION_TCA_END)) { - $enableColumns['end'] = 'endtime'; - } - if (TRUE === $form->getOption(Form::OPTION_TCA_FEGROUP)) { - $enableColumns['fe_group'] = 'fe_group'; - } - $tableConfiguration['iconfile'] = ExtensionManagementUtility::extRelPath($extensionKey) . $form->getOption(Form::OPTION_ICON); - $tableConfiguration['enablecolumns'] = $enableColumns; - $tableConfiguration['title'] = $form->getLabel(); - $tableConfiguration['languageField'] = 'sys_language_uid'; - $showRecordsFieldList = $this->buildShowItemList($form); - $GLOBALS['TCA'][$table] = array( - 'ctrl' => $tableConfiguration, - 'interface' => array( - 'showRecordFieldList' => implode(',', array_keys($fields)) - ), - 'columns' => $fields, - 'types' => array( - 0 => array( - 'showitem' => $showRecordsFieldList - ) - ) - ); - if (TRUE === $form->getOption(Form::OPTION_TCA_DELETE)) { - $GLOBALS['TCA'][$table]['ctrl']['delete'] = 'deleted'; - } - if (NULL === $labelFields) { - reset($fields); - $GLOBALS['TCA'][$table]['ctrl']['label'] = key($fields); - } else { - $GLOBALS['TCA'][$table]['ctrl']['label'] = array_shift($labelFields); - $GLOBALS['TCA'][$table]['ctrl']['label_alt'] = implode(',', $labelFields); - } - } + /** + * @param string $table + * @param Form $form + */ + protected function processFormForTable($table, Form $form) + { + $extensionName = $form->getExtensionName(); + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); + $tableConfiguration = self::$tableTemplate; + $fields = []; + $labelFields = $form->getOption(Form::OPTION_TCA_LABELS); + $enableColumns = []; + foreach ($form->getFields() as $field) { + $name = $field->getName(); + // note: extracts the TCEforms sub-array from the configuration, as required in TCA. + $fields[$name] = array_pop($field->build()); + } + if (true === $form->getOption(Form::OPTION_TCA_HIDE)) { + $enableColumns['disabled'] = 'hidden'; + } + if (true === $form->getOption(Form::OPTION_TCA_START)) { + $enableColumns['start'] = 'starttime'; + } + if (true === $form->getOption(Form::OPTION_TCA_END)) { + $enableColumns['end'] = 'endtime'; + } + if (true === $form->getOption(Form::OPTION_TCA_FEGROUP)) { + $enableColumns['fe_group'] = 'fe_group'; + } + $tableConfiguration['iconfile'] = ExtensionManagementUtility::extRelPath($extensionKey) . + $form->getOption(Form::OPTION_ICON); + $tableConfiguration['enablecolumns'] = $enableColumns; + $tableConfiguration['title'] = $form->getLabel(); + $tableConfiguration['languageField'] = 'sys_language_uid'; + $showRecordsFieldList = $this->buildShowItemList($form); + $GLOBALS['TCA'][$table] = [ + 'ctrl' => $tableConfiguration, + 'interface' => [ + 'showRecordFieldList' => implode(',', array_keys($fields)) + ], + 'columns' => $fields, + 'types' => [ + 0 => [ + 'showitem' => $showRecordsFieldList + ] + ] + ]; + if (true === $form->getOption(Form::OPTION_TCA_DELETE)) { + $GLOBALS['TCA'][$table]['ctrl']['delete'] = 'deleted'; + } + if (null === $labelFields) { + reset($fields); + $GLOBALS['TCA'][$table]['ctrl']['label'] = key($fields); + } else { + $GLOBALS['TCA'][$table]['ctrl']['label'] = array_shift($labelFields); + $GLOBALS['TCA'][$table]['ctrl']['label_alt'] = implode(',', $labelFields); + } + } - /** - * @param string $class - * @param string $table - * @return Form - */ - public function generateFormInstanceFromClassName($class, $table) { - $labelFields = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Label', FALSE); - $iconAnnotation = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Icon'); - $extensionName = $this->getExtensionNameFromModelClassName($class); - $values = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Form\Field', FALSE); - $sheets = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Form\Sheet', FALSE); - $labels = TRUE === is_array($labelFields) ? array_keys($labelFields) : array(key($values)); - foreach ($labels as $index => $labelField) { - $labels[$index] = GeneralUtility::camelCaseToLowerCaseUnderscored($labelField); - } - $icon = TRUE === isset($iconAnnotation['config']['path']) ? $iconAnnotation['config']['path'] : 'ext_icon.png'; - $hasVisibilityToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Control\Hide'); - $hasDeleteToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Control\Delete'); - $hasStartTimeToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Control\StartTime'); - $hasEndTimeToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Control\EndTime'); - $hasFrontendGroupToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Control\FrontendUserGroup'); - $form = Form::create(); - $form->setName($table); - $form->setExtensionName($extensionName); - $form->setOption('labels', $labels); - $form->setOption('delete', $hasDeleteToggle); - $form->setOption('hide', $hasVisibilityToggle); - $form->setOption('start', $hasStartTimeToggle); - $form->setOption('end', $hasEndTimeToggle); - $form->setOption(Form::OPTION_ICON, $icon); - $form->setOption('frontendUserGroup', $hasFrontendGroupToggle); - $fields = array(); - foreach ($sheets as $propertyName => $sheetAnnotation) { - $sheetName = $sheetAnnotation['type']; - if (FALSE === isset($fields[$sheetName])) { - $fields[$sheetName] = array(); - } - array_push($fields[$sheetName], $propertyName); - } - foreach ($fields as $sheetName => $propertyNames) { - $form->remove($sheetName); - $sheet = $form->createContainer('Sheet', $sheetName); - foreach ($propertyNames as $propertyName) { - $settings = $values[$propertyName]; - $propertyName = GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName); - if (TRUE === isset($settings['type'])) { - $fieldType = implode('/', array_map('ucfirst', explode('.', $settings['type']))); - $field = $sheet->createField($fieldType, $propertyName); - foreach ($settings['config'] as $settingName => $settingValue) { - ObjectAccess::setProperty($field, $settingName, $settingValue); - } - } - } - } - return $form; - } + /** + * @param string $class + * @param string $table + * @return Form + */ + public function generateFormInstanceFromClassName($class, $table) + { + $labelFields = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Label', false); + $iconAnnotation = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Icon'); + $extensionName = $this->getExtensionNameFromModelClassName($class); + $values = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Form\Field', false); + $sheets = AnnotationUtility::getAnnotationValueFromClass($class, 'Flux\Form\Sheet', false); + $labels = true === is_array($labelFields) ? array_keys($labelFields) : [key($values)]; + foreach ($labels as $index => $labelField) { + $labels[$index] = GeneralUtility::camelCaseToLowerCaseUnderscored($labelField); + } + $icon = true === isset($iconAnnotation['config']['path']) ? $iconAnnotation['config']['path'] : 'ext_icon.png'; + $hasVisibilityToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass( + $class, + 'Flux\Control\Hide' + ); + $hasDeleteToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass( + $class, + 'Flux\Control\Delete' + ); + $hasStartTimeToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass( + $class, + 'Flux\Control\StartTime' + ); + $hasEndTimeToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass( + $class, + 'Flux\Control\EndTime' + ); + $hasFrontendGroupToggle = (boolean) AnnotationUtility::getAnnotationValueFromClass( + $class, + 'Flux\Control\FrontendUserGroup' + ); + $form = Form::create(); + $form->setName($table); + $form->setExtensionName($extensionName); + $form->setOption('labels', $labels); + $form->setOption('delete', $hasDeleteToggle); + $form->setOption('hide', $hasVisibilityToggle); + $form->setOption('start', $hasStartTimeToggle); + $form->setOption('end', $hasEndTimeToggle); + $form->setOption(Form::OPTION_ICON, $icon); + $form->setOption('frontendUserGroup', $hasFrontendGroupToggle); + $fields = []; + foreach ($sheets as $propertyName => $sheetAnnotation) { + $sheetName = $sheetAnnotation['type']; + if (false === isset($fields[$sheetName])) { + $fields[$sheetName] = []; + } + array_push($fields[$sheetName], $propertyName); + } + foreach ($fields as $sheetName => $propertyNames) { + $form->remove($sheetName); + $sheet = $form->createContainer('Sheet', $sheetName); + foreach ($propertyNames as $propertyName) { + $settings = $values[$propertyName]; + $propertyName = GeneralUtility::camelCaseToLowerCaseUnderscored($propertyName); + if (true === isset($settings['type'])) { + $fieldType = implode('/', array_map('ucfirst', explode('.', $settings['type']))); + $field = $sheet->createField($fieldType, $propertyName); + foreach ($settings['config'] as $settingName => $settingValue) { + ObjectAccess::setProperty($field, $settingName, $settingValue); + } + } + } + } + return $form; + } - /** - * @param string $class - * @return string - */ - protected function getExtensionNameFromModelClassName($class) { - if (FALSE !== strpos($class, '_')) { - $parts = explode('_Domain_Model_', $class); - $extensionName = substr($parts[0], 3); - } else { - $parts = explode('\\', $class); - $candidate = array_slice($parts, 0, -3); - if (1 === count($candidate)) { - $extensionName = reset($candidate); - } else { - $extensionName = implode('.', $candidate); - } - } - return $extensionName; - } - - /** - * @param Form $form - * @return string - */ - protected function buildShowItemList(Form $form) { - $parts = array(); - foreach ($form->getSheets(FALSE) as $sheet) { - array_push($parts, '--div--;' . $sheet->getLabel()); - foreach ($sheet->getFields() as $field) { - array_push($parts, $field->getName()); - } - } - return implode(', ', $parts); - } + /** + * @param string $class + * @return string + */ + protected function getExtensionNameFromModelClassName($class) + { + if (false !== strpos($class, '_')) { + $parts = explode('_Domain_Model_', $class); + $extensionName = substr($parts[0], 3); + } else { + $parts = explode('\\', $class); + $candidate = array_slice($parts, 0, -3); + if (1 === count($candidate)) { + $extensionName = reset($candidate); + } else { + $extensionName = implode('.', $candidate); + } + } + return $extensionName; + } + /** + * @param Form $form + * @return string + */ + protected function buildShowItemList(Form $form) + { + $parts = []; + foreach ($form->getSheets(false) as $sheet) { + array_push($parts, '--div--;' . $sheet->getLabel()); + foreach ($sheet->getFields() as $field) { + array_push($parts, $field->getName()); + } + } + return implode(', ', $parts); + } } diff --git a/Classes/Backend/TceMain.php b/Classes/Backend/TceMain.php index b2eead8ea..5bcafb8c5 100644 --- a/Classes/Backend/TceMain.php +++ b/Classes/Backend/TceMain.php @@ -14,233 +14,306 @@ use FluidTYPO3\Flux\Service\RecordService; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * TCEMain */ -class TceMain { - - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - - /** - * @var FluxService - */ - protected $configurationService; - - /** - * @var RecordService - */ - protected $recordService; - - /** - * @var ContentService - */ - protected $contentService; - - /** - * @var boolean - */ - static private $cachesCleared = FALSE; - - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } - - /** - * @param FluxService $configurationService - * @return void - */ - public function injectConfigurationService(FluxService $configurationService) { - $this->configurationService = $configurationService; - } - - /** - * @param RecordService $recordService - * @return void - */ - public function injectRecordService(RecordService $recordService) { - $this->recordService = $recordService; - } - - /** - * @param ContentService $contentService - * @return void - */ - public function injectContentService(ContentService $contentService) { - $this->contentService = $contentService; - } - - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->injectObjectManager(GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager')); - $this->injectConfigurationService($this->objectManager->get('FluidTYPO3\\Flux\\Service\FluxService')); - $this->injectRecordService($this->objectManager->get('FluidTYPO3\\Flux\\Service\\RecordService')); - $this->injectContentService($this->objectManager->get('FluidTYPO3\\Flux\\Service\\ContentService')); - } - - /** - * @param string $command The TCEmain operation status, fx. 'update' - * @param string $table The table TCEmain is currently processing - * @param string $id The records id (if any) - * @param array $relativeTo Filled if command is relative to another element - * @param DataHandler $reference Reference to the parent object (TCEmain) - * @return void - */ - public function processCmdmap_preProcess(&$command, $table, $id, &$relativeTo, &$reference) { - $record = array(); - $arguments = array('command' => $command, 'id' => $id, 'row' => &$record, 'relativeTo' => &$relativeTo); - $this->executeConfigurationProviderMethod('preProcessCommand', $table, $id, $command, $record, $arguments, $reference); - } - - /** - * @param string $command The TCEmain operation status, fx. 'update' - * @param string $table The table TCEmain is currently processing - * @param string $id The records id (if any) - * @param array $relativeTo Filled if command is relative to another element - * @param DataHandler $reference Reference to the parent object (TCEmain) - * @return void - */ - public function processCmdmap_postProcess(&$command, $table, $id, &$relativeTo, &$reference) { - $record = array(); - $arguments = array('command' => $command, 'id' => $id, 'row' => &$record, 'relativeTo' => &$relativeTo); - $this->executeConfigurationProviderMethod('postProcessCommand', $table, $id, $command, $record, $arguments, $reference); - } - - /** - * @param array $incomingFieldArray The original field names and their values before they are processed - * @param string $table The table TCEmain is currently processing - * @param string $id The records id (if any) - * @param DataHandler $reference Reference to the parent object (TCEmain) - * @return void - */ - public function processDatamap_preProcessFieldArray(array &$incomingFieldArray, $table, $id, &$reference) { - $arguments = array('row' => &$incomingFieldArray, 'id' => $id); - $incomingFieldArray = $this->executeConfigurationProviderMethod( - 'preProcessRecord', $table, $id, '', $incomingFieldArray, $arguments, $reference); - } - - /** - * @param string $status The TCEmain operation status, fx. 'update' - * @param string $table The table TCEmain is currently processing - * @param string $id The records id (if any) - * @param array $fieldArray The field names and their values to be processed - * @param DataHandler $reference Reference to the parent object (TCEmain) - * @return void - */ - public function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$reference) { - $arguments = array('status' => $status, 'id' => $id, 'row' => &$fieldArray); - $fieldArray = $this->executeConfigurationProviderMethod( - 'postProcessRecord', $table, $id, '', $fieldArray, $arguments, $reference); - } - - /** - * @param string $status The command which has been sent to processDatamap - * @param string $table The table we're dealing with - * @param mixed $id Either the record UID or a string if a new record has been created - * @param array $fieldArray The record row how it has been inserted into the database - * @param DataHandler $reference A reference to the TCEmain instance - * @return void - */ - public function processDatamap_afterDatabaseOperations($status, $table, $id, &$fieldArray, &$reference) { - if ('new' === $status && 'tt_content' === $table) { - $this->contentService->initializeRecord($id, $fieldArray, $reference); - } - $arguments = array('status' => $status, 'id' => $id, 'row' => &$fieldArray); - $fieldArray = $this->executeConfigurationProviderMethod('postProcessDatabaseOperation', - $table, $id, '', $fieldArray, $arguments, $reference); - } - - /** - * Wrapper method to execute a ConfigurationProvider - * - * @param string $methodName - * @param string $table - * @param mixed $id - * @param string $command - * @param array $record - * @param array $arguments - * @param DataHandler $reference - * @return array - */ - protected function executeConfigurationProviderMethod($methodName, $table, $id, $command, array $record, array $arguments, DataHandler $reference) { - try { - $id = $this->resolveRecordUid($id, $reference); - $record = $this->ensureRecordDataIsLoaded($table, $id, $record); - $arguments['row'] = &$record; - $arguments[] = &$reference; - $detectedProviders = $this->configurationService->resolveConfigurationProviders($table, NULL, $record); - foreach ($detectedProviders as $provider) { - if (TRUE === $provider->shouldCall($methodName, $id, $command)) { - call_user_func_array(array($provider, $methodName), array_values($arguments)); - $provider->trackMethodCall($methodName, $id, $command); - } - } - } catch (\RuntimeException $error) { - $this->configurationService->debug($error); - } - return $record; - } - - /** - * @param string $table - * @param integer $id - * @param array $record - * @return array|NULL - */ - protected function ensureRecordDataIsLoaded($table, $id, array $record) { - if (TRUE === is_integer($id) && 0 === count($record)) { - // patch: when a record is completely empty but a UID exists - $loadedRecord = $this->recordService->getSingle($table, '*', $id); - $record = TRUE === is_array($loadedRecord) ? $loadedRecord : $record; - } - return $record; - } - - /** - * @param integer $id - * @param DataHandler $reference - * @return integer - */ - protected function resolveRecordUid($id, DataHandler $reference) { - if (FALSE !== strpos($id, 'NEW')) { - if (FALSE === empty($reference->substNEWwithIDs[$id])) { - $id = intval($reference->substNEWwithIDs[$id]); - } - } else { - $id = intval($id); - } - return $id; - } - - /** - * Perform various cleanup operations upon clearing cache - * - * @param string $command - * @return void - */ - public function clearCacheCommand($command) { - if (TRUE === self::$cachesCleared) { - return; - } - $tables = array_keys($GLOBALS['TCA']); - foreach ($tables as $table) { - $providers = $this->configurationService->resolveConfigurationProviders($table, NULL); - foreach ($providers as $provider) { - /** @var $provider ProviderInterface */ - $provider->clearCacheCommand($command); - } - } - self::$cachesCleared = TRUE; - } +class TceMain +{ + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var FluxService + */ + protected $configurationService; + + /** + * @var RecordService + */ + protected $recordService; + + /** + * @var ContentService + */ + protected $contentService; + + /** + * @var boolean + */ + static private $cachesCleared = false; + + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * @param FluxService $configurationService + * @return void + */ + public function injectConfigurationService(FluxService $configurationService) + { + $this->configurationService = $configurationService; + } + + /** + * @param RecordService $recordService + * @return void + */ + public function injectRecordService(RecordService $recordService) + { + $this->recordService = $recordService; + } + + /** + * @param ContentService $contentService + * @return void + */ + public function injectContentService(ContentService $contentService) + { + $this->contentService = $contentService; + } + + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->injectObjectManager(GeneralUtility::makeInstance(ObjectManager::class)); + $this->injectConfigurationService($this->objectManager->get(FluxService::class)); + $this->injectRecordService($this->objectManager->get(RecordService::class)); + $this->injectContentService($this->objectManager->get(ContentService::class)); + } + + /** + * @codingStandardsIgnoreStart + * + * The following methods are not covered by coding style checks due to needing + * non-confirming method names. + */ + + /** + * @param string $command The TCEmain operation status, fx. 'update' + * @param string $table The table TCEmain is currently processing + * @param string $id The records id (if any) + * @param array $relativeTo Filled if command is relative to another element + * @param DataHandler $reference Reference to the parent object (TCEmain) + * @return void + */ + public function processCmdmap_preProcess(&$command, $table, $id, &$relativeTo, &$reference) + { + $record = []; + $arguments = ['command' => $command, 'id' => $id, 'row' => &$record, 'relativeTo' => &$relativeTo]; + $this->executeConfigurationProviderMethod( + 'preProcessCommand', + $table, + $id, + $command, + $record, + $arguments, + $reference + ); + } + + /** + * @param string $command The TCEmain operation status, fx. 'update' + * @param string $table The table TCEmain is currently processing + * @param string $id The records id (if any) + * @param array $relativeTo Filled if command is relative to another element + * @param DataHandler $reference Reference to the parent object (TCEmain) + * @return void + */ + public function processCmdmap_postProcess(&$command, $table, $id, &$relativeTo, &$reference) + { + $record = []; + $arguments = ['command' => $command, 'id' => $id, 'row' => &$record, 'relativeTo' => &$relativeTo]; + $this->executeConfigurationProviderMethod( + 'postProcessCommand', + $table, + $id, + $command, + $record, + $arguments, + $reference + ); + } + + /** + * @param array $incomingFieldArray The original field names and their values before they are processed + * @param string $table The table TCEmain is currently processing + * @param string $id The records id (if any) + * @param DataHandler $reference Reference to the parent object (TCEmain) + * @return void + */ + public function processDatamap_preProcessFieldArray(array &$incomingFieldArray, $table, $id, &$reference) + { + $arguments = ['row' => &$incomingFieldArray, 'id' => $id]; + $incomingFieldArray = $this->executeConfigurationProviderMethod( + 'preProcessRecord', + $table, + $id, + '', + $incomingFieldArray, + $arguments, + $reference + ); + } + + /** + * @param string $status The TCEmain operation status, fx. 'update' + * @param string $table The table TCEmain is currently processing + * @param string $id The records id (if any) + * @param array $fieldArray The field names and their values to be processed + * @param DataHandler $reference Reference to the parent object (TCEmain) + * @return void + */ + public function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$reference) + { + $arguments = ['status' => $status, 'id' => $id, 'row' => &$fieldArray]; + $fieldArray = $this->executeConfigurationProviderMethod( + 'postProcessRecord', + $table, + $id, + '', + $fieldArray, + $arguments, + $reference + ); + } + + /** + * @param string $status The command which has been sent to processDatamap + * @param string $table The table we're dealing with + * @param mixed $id Either the record UID or a string if a new record has been created + * @param array $fieldArray The record row how it has been inserted into the database + * @param DataHandler $reference A reference to the TCEmain instance + * @return void + */ + public function processDatamap_afterDatabaseOperations($status, $table, $id, &$fieldArray, &$reference) + { + if ('new' === $status && 'tt_content' === $table) { + $this->contentService->initializeRecord($id, $fieldArray, $reference); + } + $arguments = ['status' => $status, 'id' => $id, 'row' => &$fieldArray]; + $fieldArray = $this->executeConfigurationProviderMethod( + 'postProcessDatabaseOperation', + $table, + $id, + '', + $fieldArray, + $arguments, + $reference + ); + } + + /** + * Methods above are not covered by coding style checks due to needing + * non-conforming method names. + * + * @codingStandardsIgnoreEnd + */ + + /** + * Wrapper method to execute a ConfigurationProvider + * + * @param string $methodName + * @param string $table + * @param mixed $id + * @param string $command + * @param array $record + * @param array $arguments + * @param DataHandler $reference + * @return array + */ + protected function executeConfigurationProviderMethod( + $methodName, + $table, + $id, + $command, + array $record, + array $arguments, + DataHandler $reference + ) { + try { + $id = $this->resolveRecordUid($id, $reference); + $record = $this->ensureRecordDataIsLoaded($table, $id, $record); + $arguments['row'] = &$record; + $arguments[] = &$reference; + $detectedProviders = $this->configurationService->resolveConfigurationProviders($table, null, $record); + foreach ($detectedProviders as $provider) { + if (true === $provider->shouldCall($methodName, $id, $command)) { + call_user_func_array([$provider, $methodName], array_values($arguments)); + $provider->trackMethodCall($methodName, $id, $command); + } + } + } catch (\RuntimeException $error) { + $this->configurationService->debug($error); + } + return $record; + } + + /** + * @param string $table + * @param integer $id + * @param array $record + * @return array|NULL + */ + protected function ensureRecordDataIsLoaded($table, $id, array $record) + { + if (true === is_integer($id) && 0 === count($record)) { + // patch: when a record is completely empty but a UID exists + $loadedRecord = $this->recordService->getSingle($table, '*', $id); + $record = true === is_array($loadedRecord) ? $loadedRecord : $record; + } + return $record; + } + + /** + * @param integer $id + * @param DataHandler $reference + * @return integer + */ + protected function resolveRecordUid($id, DataHandler $reference) + { + if (false !== strpos($id, 'NEW')) { + if (false === empty($reference->substNEWwithIDs[$id])) { + $id = intval($reference->substNEWwithIDs[$id]); + } + } else { + $id = intval($id); + } + return $id; + } + + /** + * Perform various cleanup operations upon clearing cache + * + * @param string $command + * @return void + */ + public function clearCacheCommand($command) + { + if (true === self::$cachesCleared) { + return; + } + $tables = array_keys($GLOBALS['TCA']); + foreach ($tables as $table) { + $providers = $this->configurationService->resolveConfigurationProviders($table, null); + foreach ($providers as $provider) { + /** @var $provider ProviderInterface */ + $provider->clearCacheCommand($command); + } + } + self::$cachesCleared = true; + } } diff --git a/Classes/Backend/TypoScriptTemplate.php b/Classes/Backend/TypoScriptTemplate.php index a6e0bb8c7..af7fcffa2 100644 --- a/Classes/Backend/TypoScriptTemplate.php +++ b/Classes/Backend/TypoScriptTemplate.php @@ -15,23 +15,24 @@ /** * TypoScriptTemplate */ -class TypoScriptTemplate { - - /** - * Includes static template from extensions - * - * @param array $params - * @param TemplateService $pObj - * @return void - */ - public function preprocessIncludeStaticTypoScriptSources(array &$params, TemplateService $pObj) { - unset($pObj); - if (TRUE === isset($params['row']['root']) && TRUE === (boolean) $params['row']['root']) { - $existingTemplates = GeneralUtility::trimExplode(',', $params['row']['include_static_file']); - $globalStaticTemplates = Core::getStaticTypoScript(); - $staticTemplates = array_merge($globalStaticTemplates, $existingTemplates); - $params['row']['include_static_file'] = implode(',', array_unique($staticTemplates)); - } - } +class TypoScriptTemplate +{ + /** + * Includes static template from extensions + * + * @param array $params + * @param TemplateService $pObj + * @return void + */ + public function preprocessIncludeStaticTypoScriptSources(array &$params, TemplateService $pObj) + { + unset($pObj); + if (true === isset($params['row']['root']) && true === (boolean) $params['row']['root']) { + $existingTemplates = GeneralUtility::trimExplode(',', $params['row']['include_static_file']); + $globalStaticTemplates = Core::getStaticTypoScript(); + $staticTemplates = array_merge($globalStaticTemplates, $existingTemplates); + $params['row']['include_static_file'] = implode(',', array_unique($staticTemplates)); + } + } } diff --git a/Classes/Configuration/BackendConfigurationManager.php b/Classes/Configuration/BackendConfigurationManager.php index 9df916ea9..e22459245 100644 --- a/Classes/Configuration/BackendConfigurationManager.php +++ b/Classes/Configuration/BackendConfigurationManager.php @@ -16,163 +16,175 @@ /** * Flux ConfigurationManager implementation: Backend */ -class BackendConfigurationManager extends CoreBackendConfigurationManager implements SingletonInterface { - - /** - * @var RecordService - */ - protected $recordService; - - /** - * @param RecordService $recordService - * @return void - */ - public function injectRecordService(RecordService $recordService) { - $this->recordService = $recordService; - } - - /** - * @param integer $currentPageId - * @return void - */ - public function setCurrentPageId($currentPageId) { - $this->currentPageId = $currentPageId; - } - - /** - * Extended page UID fetch - * - * Uses a range of additional page UID resolve methods to - * find the currently active page UID from URL, active - * record, etc. - * - * @return integer - */ - public function getCurrentPageId() { - if (0 < $this->currentPageId) { - return $this->currentPageId; - } - $pageUids = $this->getPrioritizedPageUids(); - // parent::getCurrentPageId() in getPrioritizedPageUids() set possible wrong value - $this->currentPageId = 0; - while (TRUE === empty($this->currentPageId) && TRUE !== empty($pageUids)) { - $this->currentPageId = array_shift($pageUids); - }; - return $this->currentPageId; - } - - /** - * @return array - */ - protected function getPrioritizedPageUids() { - return array( - $this->getPageIdFromGet(), - $this->getPageIdFromPost(), - $this->getPageIdFromRecordIdentifiedInEditUrlArgument(), - $this->getPageIdFromContentObject(), - parent::getCurrentPageId(), - ); - } - - /** - * Reads the reserved "id" GET variable if specified - * - * @return integer - */ - protected function getPageIdFromGet() { - return (integer) GeneralUtility::_GET('id'); - } - - /** - * Reads the reserved "id" variable if it was POST'ed - * - * @return integer - */ - protected function getPageIdFromPost() { - return (integer) GeneralUtility::_POST('id'); - } - - /** - * Reads page UID from the $_GET['edit'] argument which is - * used on the "alt_doc.php" file (TCEforms rendering file) - * which is possible since we can know the PID if: - * - * - one record is being edited from "pages" table - * - one or more content records being edited, in which case - * each content record will have the same PID and using the - * first one is then sufficient. - * - * @return integer - * @throws \UnexpectedValueException - */ - protected function getPageIdFromRecordIdentifiedInEditUrlArgument() { - list ($table, $id, $command) = $this->getEditArguments(); - if ('pages' === $table && 'new' === $command) { - // if TYPO3 wants to insert a new page, URL argument is already the PID value. - return $id; - } elseif (0 <> $id && 'pages' !== $table) { - // if any identified record is being edited, load it and return the PID value. - // if the (new) record is relative to another, $id is negative UID of relative record, hence abs(). - return $this->getPageIdFromRecordUid($table, abs($id)); - } - return $id; - } - - /** - * @param string $table - * @param integer $uid - * @return integer - */ - protected function getPageIdFromRecordUid($table, $uid) { - $record = $this->recordService->getSingle($table, 'pid', $uid); - return TRUE === is_array($record) ? $this->getPageIdFromRecord($record) : 0; - } - - /** - * @return array - */ - protected function getEditArguments() { - $editArgument = $this->getEditArgumentValuePair(); - $table = key($editArgument); - $argumentPair = reset($editArgument); - $id = (integer) key($argumentPair); - $command = reset($argumentPair); - // if TYPO3 wants to insert a new tt_content element after the element - // with uid=abs($id), translate ID. - $id = (integer) (0 > $id && 'tt_content' === $table) ? $id = -$id : $id; - return array($table, $id, $command); - } - - /** - * @return mixed - */ - protected function getEditArgumentValuePair() { - $editArgument = GeneralUtility::_GET('edit'); - return TRUE === is_array($editArgument) ? $editArgument : array(array()); - } - - /** - * Reads the PID from the record belonging to the content object - * that's currently being rendered/manipulated. Is unlikely to - * return any value but is included for completeness. - * - * @return integer - */ - protected function getPageIdFromContentObject() { - $record = $this->getContentObject()->data; - return TRUE === is_array($record) ? $this->getPageIdFromRecord($record) : 0; - } - - /** - * @param array $record - * @return integer - */ - protected function getPageIdFromRecord(array $record) { - if (FALSE === isset($record['pid'])) { - return 0; - } - - return (integer) $record['pid']; - } - +class BackendConfigurationManager extends CoreBackendConfigurationManager implements SingletonInterface +{ + + /** + * @var RecordService + */ + protected $recordService; + + /** + * @param RecordService $recordService + * @return void + */ + public function injectRecordService(RecordService $recordService) + { + $this->recordService = $recordService; + } + + /** + * @param integer $currentPageId + * @return void + */ + public function setCurrentPageId($currentPageId) + { + $this->currentPageId = $currentPageId; + } + + /** + * Extended page UID fetch + * + * Uses a range of additional page UID resolve methods to + * find the currently active page UID from URL, active + * record, etc. + * + * @return integer + */ + public function getCurrentPageId() + { + if (0 < $this->currentPageId) { + return $this->currentPageId; + } + $pageUids = $this->getPrioritizedPageUids(); + // parent::getCurrentPageId() in getPrioritizedPageUids() set possible wrong value + $this->currentPageId = 0; + while (true === empty($this->currentPageId) && true !== empty($pageUids)) { + $this->currentPageId = array_shift($pageUids); + }; + return $this->currentPageId; + } + + /** + * @return array + */ + protected function getPrioritizedPageUids() + { + return [ + $this->getPageIdFromGet(), + $this->getPageIdFromPost(), + $this->getPageIdFromRecordIdentifiedInEditUrlArgument(), + $this->getPageIdFromContentObject(), + parent::getCurrentPageId(), + ]; + } + + /** + * Reads the reserved "id" GET variable if specified + * + * @return integer + */ + protected function getPageIdFromGet() + { + return (integer) GeneralUtility::_GET('id'); + } + + /** + * Reads the reserved "id" variable if it was POST'ed + * + * @return integer + */ + protected function getPageIdFromPost() + { + return (integer) GeneralUtility::_POST('id'); + } + + /** + * Reads page UID from the $_GET['edit'] argument which is + * used on the "alt_doc.php" file (TCEforms rendering file) + * which is possible since we can know the PID if: + * + * - one record is being edited from "pages" table + * - one or more content records being edited, in which case + * each content record will have the same PID and using the + * first one is then sufficient. + * + * @return integer + * @throws \UnexpectedValueException + */ + protected function getPageIdFromRecordIdentifiedInEditUrlArgument() + { + list ($table, $id, $command) = $this->getEditArguments(); + if ('pages' === $table && 'new' === $command) { + // if TYPO3 wants to insert a new page, URL argument is already the PID value. + return $id; + } elseif (0 <> $id && 'pages' !== $table) { + // if any identified record is being edited, load it and return the PID value. + // if the (new) record is relative to another, $id is negative UID of relative record, hence abs(). + return $this->getPageIdFromRecordUid($table, abs($id)); + } + return $id; + } + + /** + * @param string $table + * @param integer $uid + * @return integer + */ + protected function getPageIdFromRecordUid($table, $uid) + { + $record = $this->recordService->getSingle($table, 'pid', $uid); + return true === is_array($record) ? $this->getPageIdFromRecord($record) : 0; + } + + /** + * @return array + */ + protected function getEditArguments() + { + $editArgument = $this->getEditArgumentValuePair(); + $table = key($editArgument); + $argumentPair = reset($editArgument); + $id = (integer) key($argumentPair); + $command = reset($argumentPair); + // if TYPO3 wants to insert a new tt_content element after the element + // with uid=abs($id), translate ID. + $id = (integer) (0 > $id && 'tt_content' === $table) ? $id = -$id : $id; + return [$table, $id, $command]; + } + + /** + * @return mixed + */ + protected function getEditArgumentValuePair() + { + $editArgument = GeneralUtility::_GET('edit'); + return true === is_array($editArgument) ? $editArgument : [[]]; + } + + /** + * Reads the PID from the record belonging to the content object + * that's currently being rendered/manipulated. Is unlikely to + * return any value but is included for completeness. + * + * @return integer + */ + protected function getPageIdFromContentObject() + { + $record = $this->getContentObject()->data; + return true === is_array($record) ? $this->getPageIdFromRecord($record) : 0; + } + + /** + * @param array $record + * @return integer + */ + protected function getPageIdFromRecord(array $record) + { + if (false === isset($record['pid'])) { + return 0; + } + + return (integer) $record['pid']; + } } diff --git a/Classes/Configuration/ConfigurationManager.php b/Classes/Configuration/ConfigurationManager.php index 3641b2bf2..d7cc6f555 100644 --- a/Classes/Configuration/ConfigurationManager.php +++ b/Classes/Configuration/ConfigurationManager.php @@ -11,6 +11,7 @@ use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Extbase\Configuration\ConfigurationManager as CoreConfigurationManager; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Extbase\Configuration\FrontendConfigurationManager; /** * Flux ConfigurationManager implementation @@ -18,48 +19,51 @@ * More context-sensitive ConfigurationManager with TS resolve * methods optimised for use in the backend. */ -class ConfigurationManager extends CoreConfigurationManager implements ConfigurationManagerInterface, SingletonInterface { +class ConfigurationManager extends CoreConfigurationManager implements ConfigurationManagerInterface, SingletonInterface +{ - /** - * @var BackendConfigurationManager - */ - protected $concreteConfigurationManager; + /** + * @var BackendConfigurationManager + */ + protected $concreteConfigurationManager; - /** - * @return void - */ - protected function initializeConcreteConfigurationManager() { - if (TRUE === $this->environmentService->isEnvironmentInFrontendMode()) { - $this->concreteConfigurationManager = $this->objectManager->get('TYPO3\CMS\Extbase\Configuration\FrontendConfigurationManager'); - } else { - $this->concreteConfigurationManager = $this->objectManager->get('FluidTYPO3\Flux\Configuration\BackendConfigurationManager'); - } - } + /** + * @return void + */ + protected function initializeConcreteConfigurationManager() + { + if (true === $this->environmentService->isEnvironmentInFrontendMode()) { + $this->concreteConfigurationManager = $this->objectManager->get(FrontendConfigurationManager::class); + } else { + $this->concreteConfigurationManager = $this->objectManager->get(BackendConfigurationManager::class); + } + } - /** - * @param integer $currentPageId - * @return void - */ - public function setCurrentPageUid($currentPageId) { - if (TRUE === $this->concreteConfigurationManager instanceof BackendConfigurationManager) { - $this->concreteConfigurationManager->setCurrentPageId($currentPageId); - } - } - - /** - * Extended page UID fetch - * - * Uses a range of additional page UID resolve methods to - * find the currently active page UID from URL, active - * record, etc. - * - * @return integer - */ - public function getCurrentPageId() { - if (TRUE === $this->concreteConfigurationManager instanceof BackendConfigurationManager) { - return $this->concreteConfigurationManager->getCurrentPageId(); - } - return 0; - } + /** + * @param integer $currentPageId + * @return void + */ + public function setCurrentPageUid($currentPageId) + { + if (true === $this->concreteConfigurationManager instanceof BackendConfigurationManager) { + $this->concreteConfigurationManager->setCurrentPageId($currentPageId); + } + } + /** + * Extended page UID fetch + * + * Uses a range of additional page UID resolve methods to + * find the currently active page UID from URL, active + * record, etc. + * + * @return integer + */ + public function getCurrentPageId() + { + if (true === $this->concreteConfigurationManager instanceof BackendConfigurationManager) { + return $this->concreteConfigurationManager->getCurrentPageId(); + } + return 0; + } } diff --git a/Classes/Controller/AbstractFluxController.php b/Classes/Controller/AbstractFluxController.php index afadce78c..02ab8f4fc 100644 --- a/Classes/Controller/AbstractFluxController.php +++ b/Classes/Controller/AbstractFluxController.php @@ -31,292 +31,332 @@ * * @route off */ -abstract class AbstractFluxController extends ActionController { +abstract class AbstractFluxController extends ActionController +{ - /** - * @var string - */ - protected $defaultViewObjectName = 'FluidTYPO3\Flux\View\ExposedTemplateView'; + /** + * @var string + */ + protected $defaultViewObjectName = 'FluidTYPO3\Flux\View\ExposedTemplateView'; - /** - * @var string - */ - protected $fallbackExtensionKey = 'flux'; + /** + * @var string + */ + protected $fallbackExtensionKey = 'flux'; - /** - * @var FluxService - */ - protected $configurationService; + /** + * @var FluxService + */ + protected $configurationService; - /** - * @var \FluidTYPO3\Flux\Provider\ProviderInterface - */ - protected $provider; + /** + * @var \FluidTYPO3\Flux\Provider\ProviderInterface + */ + protected $provider; - /** - * @var string - */ - protected $fluxRecordField = 'pi_flexform'; + /** + * @var string + */ + protected $fluxRecordField = 'pi_flexform'; - /** - * @var string - */ - protected $fluxTableName = 'tt_content'; + /** + * @var string + */ + protected $fluxTableName = 'tt_content'; - /** - * @var array - */ - protected $setup = array(); + /** + * @var array + */ + protected $setup = []; - /** - * @var array - */ - protected $data = array(); + /** + * @var array + */ + protected $data = []; - /** - * @var WorkspacesAwareRecordService - */ - protected $workspacesAwareRecordService; + /** + * @var WorkspacesAwareRecordService + */ + protected $workspacesAwareRecordService; - /** - * @param FluxService $configurationService - * @return void - */ - public function injectConfigurationService(FluxService $configurationService) { - $this->configurationService = $configurationService; - } + /** + * @param FluxService $configurationService + * @return void + */ + public function injectConfigurationService(FluxService $configurationService) + { + $this->configurationService = $configurationService; + } - /** - * @param WorkspacesAwareRecordService $workspacesAwareRecordService - * @return void - */ - public function injectWorkspacesAwareRecordService(WorkspacesAwareRecordService $workspacesAwareRecordService) { - $this->workspacesAwareRecordService = $workspacesAwareRecordService; - } + /** + * @param WorkspacesAwareRecordService $workspacesAwareRecordService + * @return void + */ + public function injectWorkspacesAwareRecordService(WorkspacesAwareRecordService $workspacesAwareRecordService) + { + $this->workspacesAwareRecordService = $workspacesAwareRecordService; + } - /** - * @return void - * @throws \RuntimeException - */ - protected function initializeSettings() { - $row = $this->getRecord(); - $extensionKey = $this->provider->getExtensionKey($row); - $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); - $pluginName = $this->request->getPluginName(); - $this->settings = RecursiveArrayUtility::merge( - (array) $this->configurationManager->getConfiguration( - ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, $extensionName, $pluginName - ), - $this->settings - ); - $this->data = $this->provider->getFlexFormValues($row); - $this->setup = $this->provider->getTemplatePaths($row); - } + /** + * @return void + * @throws \RuntimeException + */ + protected function initializeSettings() + { + $row = $this->getRecord(); + $extensionKey = $this->provider->getExtensionKey($row); + $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); + $pluginName = $this->request->getPluginName(); + $this->settings = RecursiveArrayUtility::merge( + (array) $this->configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS, + $extensionName, + $pluginName + ), + $this->settings + ); + $this->data = $this->provider->getFlexFormValues($row); + $this->setup = $this->provider->getTemplatePaths($row); + } - /** - * @return void - */ - protected function initializeOverriddenSettings() { - $row = $this->getRecord(); - $extensionKey = $this->provider->getExtensionKey($row); - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); - if (TRUE === isset($this->data['settings']) && TRUE === is_array($this->data['settings'])) { - // a "settings." array is defined in the flexform configuration - extract it, use as "settings" in template - // as well as the internal $this->settings array as per expected Extbase behavior. - $this->settings = RecursiveArrayUtility::merge($this->settings, $this->data['settings']); - } - if (TRUE === isset($this->settings['useTypoScript']) && TRUE === (boolean) $this->settings['useTypoScript']) { - // an override shared by all Flux enabled controllers: setting plugin.tx_EXTKEY.settings.useTypoScript = 1 - // will read the "settings" array from that location instead - thus excluding variables from the flexform - // which are still available as $this->data but no longer available automatically in the template. - $this->settings = $this->configurationService->getSettingsForExtensionName($extensionKey); - } - } + /** + * @return void + */ + protected function initializeOverriddenSettings() + { + $row = $this->getRecord(); + $extensionKey = $this->provider->getExtensionKey($row); + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); + if (true === isset($this->data['settings']) && true === is_array($this->data['settings'])) { + // a "settings." array is defined in the flexform configuration - extract it, use as "settings" in template + // as well as the internal $this->settings array as per expected Extbase behavior. + $this->settings = RecursiveArrayUtility::merge($this->settings, $this->data['settings']); + } + if (true === isset($this->settings['useTypoScript']) && true === (boolean) $this->settings['useTypoScript']) { + // an override shared by all Flux enabled controllers: setting plugin.tx_EXTKEY.settings.useTypoScript = 1 + // will read the "settings" array from that location instead - thus excluding variables from the flexform + // which are still available as $this->data but no longer available automatically in the template. + $this->settings = $this->configurationService->getSettingsForExtensionName($extensionKey); + } + } - /** - * @throws \RuntimeException - * @return void - */ - protected function initializeProvider() { - $row = $this->getRecord(); - $table = $this->getFluxTableName(); - $field = $this->getFluxRecordField(); - $this->provider = $this->configurationService->resolvePrimaryConfigurationProvider($table, $field, $row); - if (NULL === $this->provider) { - throw new \RuntimeException( - 'Unable to resolve a ConfigurationProvider, but controller indicates it is a Flux-enabled Controller - ' . - 'this is a grave error and indicates that EXT: ' . $this->extensionName . ' itself is broken - or that EXT:' . - $this->extensionName . ' has been overridden by another implementation which is broken. The controller that ' . - 'caused this error was ' . get_class($this) . '".', - 1377458581 - ); - } - } + /** + * @throws \RuntimeException + * @return void + */ + protected function initializeProvider() + { + $row = $this->getRecord(); + $table = $this->getFluxTableName(); + $field = $this->getFluxRecordField(); + $this->provider = $this->configurationService->resolvePrimaryConfigurationProvider($table, $field, $row); + if (null === $this->provider) { + throw new \RuntimeException( + 'Unable to resolve a ConfigurationProvider, but controller indicates it is a Flux-enabled ' . + 'Controller - this is a grave error and indicates that EXT: ' . $this->extensionName . ' itself is ' . + 'broken - or that EXT:' . $this->extensionName . ' has been overridden by another implementation ' . + 'which is broken. The controller that caused this error was ' . get_class($this) . '".', + 1377458581 + ); + } + } - /** - * @return void - */ - protected function initializeViewVariables() { - $row = $this->getRecord(); - $this->view->assignMultiple($this->provider->getTemplateVariables($row)); - $this->view->assignMultiple($this->data); - $this->view->assign('settings', $this->settings); - $this->view->assign('provider', $this->provider); - $this->view->assign('record', $row); - } + /** + * @return void + */ + protected function initializeViewVariables() + { + $row = $this->getRecord(); + $this->view->assignMultiple($this->provider->getTemplateVariables($row)); + $this->view->assignMultiple($this->data); + $this->view->assign('settings', $this->settings); + $this->view->assign('provider', $this->provider); + $this->view->assign('record', $row); + } - /** - * @return void - */ - protected function initializeViewObject() { - $row = $this->getRecord(); - $viewContext = $this->provider->getViewContext($row, $this->request); - $controllerActionName = $this->provider->getControllerActionFromRecord($row); - $this->view = $this->configurationService->getPreparedExposedTemplateView($viewContext); - } + /** + * @return void + */ + protected function initializeViewObject() + { + $row = $this->getRecord(); + $viewContext = $this->provider->getViewContext($row, $this->request); + $controllerActionName = $this->provider->getControllerActionFromRecord($row); + $this->view = $this->configurationService->getPreparedExposedTemplateView($viewContext); + } - /** - * @param ViewInterface $view - * - * @return void - */ - public function initializeView(ViewInterface $view) { - $this->view = $view; - $this->initializeProvider(); - $this->initializeSettings(); - $this->initializeOverriddenSettings(); - $this->initializeViewObject(); - $this->initializeViewVariables(); - } + /** + * @param ViewInterface $view + * + * @return void + */ + public function initializeView(ViewInterface $view) + { + $this->view = $view; + $this->initializeProvider(); + $this->initializeSettings(); + $this->initializeOverriddenSettings(); + $this->initializeViewObject(); + $this->initializeViewVariables(); + } - /** - * @return string - * @route off - */ - public function renderAction() { - $row = $this->getRecord(); - $extensionKey = $this->provider->getExtensionKey($row); - $extensionSignature = ExtensionNamingUtility::getExtensionSignature($extensionKey); - $pluginSignature = strtolower('tx_' . $extensionSignature . '_' . $this->request->getPluginName()); - $controllerExtensionKey = $this->provider->getControllerExtensionKeyFromRecord($row); - $requestActionName = $this->resolveOverriddenFluxControllerActionNameFromRequestParameters($pluginSignature); - $controllerActionName = $this->provider->getControllerActionFromRecord($row); - $actualActionName = NULL !== $requestActionName ? $requestActionName : $controllerActionName; - $controllerName = $this->request->getControllerName(); - return $this->performSubRendering($controllerExtensionKey, $controllerName, $actualActionName, $pluginSignature); - } + /** + * @return string + * @route off + */ + public function renderAction() + { + $row = $this->getRecord(); + $extensionKey = $this->provider->getExtensionKey($row); + $extensionSignature = ExtensionNamingUtility::getExtensionSignature($extensionKey); + $pluginSignature = strtolower('tx_' . $extensionSignature . '_' . $this->request->getPluginName()); + $controllerExtensionKey = $this->provider->getControllerExtensionKeyFromRecord($row); + $requestActionName = $this->resolveOverriddenFluxControllerActionNameFromRequestParameters($pluginSignature); + $controllerActionName = $this->provider->getControllerActionFromRecord($row); + $actualActionName = null !== $requestActionName ? $requestActionName : $controllerActionName; + $controllerName = $this->request->getControllerName(); + return $this->performSubRendering( + $controllerExtensionKey, + $controllerName, + $actualActionName, + $pluginSignature + ); + } - /** - * @param string $pluginSignature - * @return string|NULL - */ - protected function resolveOverriddenFluxControllerActionNameFromRequestParameters($pluginSignature) { - $requestParameters = (array) GeneralUtility::_GET($pluginSignature); - $overriddenControllerActionName = TRUE === isset($requestParameters['action']) ? $requestParameters['action'] : NULL; - return $overriddenControllerActionName; - } + /** + * @param string $pluginSignature + * @return string|NULL + */ + protected function resolveOverriddenFluxControllerActionNameFromRequestParameters($pluginSignature) + { + $requestParameters = (array) GeneralUtility::_GET($pluginSignature); + $overriddenControllerActionName = isset($requestParameters['action']) ? $requestParameters['action'] : null; + return $overriddenControllerActionName; + } - /** - * @param string $extensionName - * @param string $controllerName - * @param string $actionName - * @param string $pluginSignature - * @return string - */ - protected function performSubRendering($extensionName, $controllerName, $actionName, $pluginSignature) { - $shouldRelay = $this->hasSubControllerActionOnForeignController($extensionName, $controllerName, $actionName); - if (TRUE === $shouldRelay) { - $foreignControllerClass = $this->configurationService - ->getResolver()->resolveFluxControllerClassNameByExtensionKeyAndAction( - $extensionName, $actionName, $controllerName - ); - return $this->callSubControllerAction($extensionName, $foreignControllerClass, $actionName, $pluginSignature); - } - return $this->view->render(); - } + /** + * @param string $extensionName + * @param string $controllerName + * @param string $actionName + * @param string $pluginSignature + * @return string + */ + protected function performSubRendering($extensionName, $controllerName, $actionName, $pluginSignature) + { + $shouldRelay = $this->hasSubControllerActionOnForeignController($extensionName, $controllerName, $actionName); + if (true === $shouldRelay) { + $foreignControllerClass = $this->configurationService + ->getResolver()->resolveFluxControllerClassNameByExtensionKeyAndAction( + $extensionName, + $actionName, + $controllerName + ); + return $this->callSubControllerAction( + $extensionName, + $foreignControllerClass, + $actionName, + $pluginSignature + ); + } + return $this->view->render(); + } - /** - * @param string $extensionName - * @param string $controllerName - * @param string $actionName - * @return boolean - */ - protected function hasSubControllerActionOnForeignController($extensionName, $controllerName, $actionName) { - $potentialControllerClassName = $this->configurationService - ->getResolver()->resolveFluxControllerClassNameByExtensionKeyAndAction($extensionName, $actionName, $controllerName); - $isForeign = $extensionName !== $this->extensionName; - $isValidController = class_exists($potentialControllerClassName); - return (TRUE === $isForeign && TRUE === $isValidController); - } + /** + * @param string $extensionName + * @param string $controllerName + * @param string $actionName + * @return boolean + */ + protected function hasSubControllerActionOnForeignController($extensionName, $controllerName, $actionName) + { + $potentialControllerClassName = $this->configurationService + ->getResolver()->resolveFluxControllerClassNameByExtensionKeyAndAction( + $extensionName, + $actionName, + $controllerName + ); + $isForeign = $extensionName !== $this->extensionName; + $isValidController = class_exists($potentialControllerClassName); + return (true === $isForeign && true === $isValidController); + } - /** - * @param string $extensionName - * @param string $controllerClassName - * @param string $controllerActionName - * @param string $pluginSignature - * @return string - */ - protected function callSubControllerAction($extensionName, $controllerClassName, $controllerActionName, $pluginSignature) { - /** @var Response $response */ - $post = GeneralUtility::_POST($pluginSignature); - $row = $this->getRecord(); - $response = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Response'); - $arguments = (array) (TRUE === is_array($post) ? $post : GeneralUtility::_GET($pluginSignature)); - $potentialControllerInstance = $this->objectManager->get($controllerClassName); - $viewContext = $this->provider->getViewContext($row, $this->request); - $viewContext->setPackageName($this->provider->getControllerPackageNameFromRecord($row)); - /** @var \TYPO3\CMS\Extbase\Mvc\Web\Request $subRequest */ - $subRequest = $viewContext->getRequest(); - $subRequest->setArguments($arguments); - $subRequest->setControllerExtensionName($viewContext->getExtensionName()); - $subRequest->setControllerVendorName($viewContext->getVendorName()); - $subRequest->setControllerActionName($this->provider->getControllerActionFromRecord($row)); - $potentialControllerInstance->processRequest($subRequest, $response); - return $response->getContent(); - } + /** + * @param string $extensionName + * @param string $controllerClassName + * @param string $controllerActionName + * @param string $pluginSignature + * @return string + */ + protected function callSubControllerAction( + $extensionName, + $controllerClassName, + $controllerActionName, + $pluginSignature + ) { + /** @var Response $response */ + $post = GeneralUtility::_POST($pluginSignature); + $row = $this->getRecord(); + $response = $this->objectManager->get(Response::class); + $arguments = (array) (true === is_array($post) ? $post : GeneralUtility::_GET($pluginSignature)); + $potentialControllerInstance = $this->objectManager->get($controllerClassName); + $viewContext = $this->provider->getViewContext($row, $this->request); + $viewContext->setPackageName($this->provider->getControllerPackageNameFromRecord($row)); + /** @var \TYPO3\CMS\Extbase\Mvc\Web\Request $subRequest */ + $subRequest = $viewContext->getRequest(); + $subRequest->setArguments($arguments); + $subRequest->setControllerExtensionName($viewContext->getExtensionName()); + $subRequest->setControllerVendorName($viewContext->getVendorName()); + $subRequest->setControllerActionName($this->provider->getControllerActionFromRecord($row)); + $potentialControllerInstance->processRequest($subRequest, $response); + return $response->getContent(); + } - /** - * Get the data stored in a record's Flux-enabled field, - * i.e. the variables of the Flux template as configured in this - * particular record. - * - * @return array - */ - protected function getData() { - return $this->data; - } + /** + * Get the data stored in a record's Flux-enabled field, + * i.e. the variables of the Flux template as configured in this + * particular record. + * + * @return array + */ + protected function getData() + { + return $this->data; + } - /** - * Get the array of TS configuration associated with the - * Flux template of the record (or overall record type) - * currently being rendered. - * - * @return array - */ - protected function getSetup() { - return $this->setup; - } + /** + * Get the array of TS configuration associated with the + * Flux template of the record (or overall record type) + * currently being rendered. + * + * @return array + */ + protected function getSetup() + { + return $this->setup; + } - /** - * @return string - */ - protected function getFluxRecordField() { - return $this->fluxRecordField; - } + /** + * @return string + */ + protected function getFluxRecordField() + { + return $this->fluxRecordField; + } - /** - * @return string - */ - protected function getFluxTableName() { - return $this->fluxTableName; - } - - /** - * @return array - */ - public function getRecord() { - $row = $this->configurationManager->getContentObject()->data; - return (array) $row; - } + /** + * @return string + */ + protected function getFluxTableName() + { + return $this->fluxTableName; + } + /** + * @return array + */ + public function getRecord() + { + $row = $this->configurationManager->getContentObject()->data; + return (array) $row; + } } diff --git a/Classes/Core.php b/Classes/Core.php index 9dd804b6e..fc8eaf153 100755 --- a/Classes/Core.php +++ b/Classes/Core.php @@ -10,8 +10,10 @@ use FluidTYPO3\Flux\Form; use FluidTYPO3\Flux\Provider\ContentProvider; +use FluidTYPO3\Flux\Provider\Provider; use FluidTYPO3\Flux\Provider\ProviderInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** @@ -19,400 +21,451 @@ * * Quick-access API methods to easily integrate with Flux */ -class Core { - - const CONTROLLER_ALL = '_all'; - - /** - * Contains all ConfigurationProviders registered with Flux - * @var array - */ - private static $providers = array(); - - /** - * @var array - */ - protected static $pipes = array(); - - /** - * @var array - */ - protected static $outlets = array(); - - /** - * Contains all Forms for tables registered with Flux - * @var array - */ - private static $forms = array( - 'models' => array(), - 'tables' => array(), - 'packages' => array() - ); - - /** - * Contains ConfigurationProviders which have been unregistered - * @var array - */ - private static $unregisteredProviders = array(); - - /** - * Contains all extensions registered with Flux - * @var array - */ - private static $extensions = array( - self::CONTROLLER_ALL => array() - ); - - /** - * Contains all programatically added TypoScript configuration files for auto-inclusion - * @var array - */ - private static $staticTypoScript = array(); - - /** - * @return array - */ - public static function getStaticTypoScript() { - return self::$staticTypoScript; - } - - /** - * @param mixed $locationOrLocations - * @return void - */ - public static function addStaticTypoScript($locationOrLocations) { - if (TRUE === is_array($locationOrLocations) || TRUE === $locationOrLocations instanceof \Traversable) { - foreach ($locationOrLocations as $location) { - self::addStaticTypoScript($location); - } - } else { - if (FALSE === in_array($locationOrLocations, self::$staticTypoScript)) { - array_push(self::$staticTypoScript, $locationOrLocations); - } - } - } - - /** - * @param string $table - * @param Form $form - * @return void - */ - public static function registerFormForTable($table, Form $form) { - if (NULL === $form->getName()) { - $form->setName($table); - } - if (NULL === $form->getExtensionName() && TRUE === isset($GLOBALS['_EXTKEY'])) { - $form->setExtensionName(GeneralUtility::underscoredToUpperCamelCase($GLOBALS['_EXTKEY'])); - } - self::$forms['tables'][$table] = $form; - } - - /** - * Registers automatic Form instance building and use as TCA for a model object class/table. - * - * @param string $className - * @return void - */ - public static function registerAutoFormForModelObjectClassName($className) { - self::registerFormForModelObjectClassName($className); - } - - /** - * Registers a Form instance to use when TCA for a model object class/table is requested. - * - * @param string $className - * @param Form $form - * @return void - */ - public static function registerFormForModelObjectClassName($className, Form $form = NULL) { - if (NULL !== $form && TRUE === isset($GLOBALS['_EXTKEY']) && NULL === $form->getExtensionName()) { - $form->setExtensionName(GeneralUtility::underscoredToUpperCamelCase($GLOBALS['_EXTKEY'])); - } - self::$forms['models'][$className] = $form; - } - - /** - * @param string $className - * @return void - */ - public static function unregisterFormForModelObjectClassName($className) { - if (TRUE === isset(self::$forms['models'][$className])) { - unset(self::$forms['models'][$className]); - } - } - - /** - * Registers a package key (Vendor.ExtensionName) which is expected to - * contain Domain/Form/{$modelName}Form classes. - * - * @param string $packageName - * @return void - */ - public static function registerFluxDomainFormPackage($packageName) { - self::$forms['packages'][$packageName] = TRUE; - } - - /** - * @param string $packageName - * @return void - */ - public static function unregisterFluxDomainFormPackage($packageName) { - if (TRUE === isset(self::$forms['packages'][$packageName])) { - unset(self::$forms['packages'][$packageName]); - } - } - - /** - * @param string $extensionKey - * @param string $providesControllerName - * @return void - */ - public static function registerProviderExtensionKey($extensionKey, $providesControllerName = self::CONTROLLER_ALL) { - if (FALSE === isset(self::$extensions[$providesControllerName])) { - self::$extensions[$providesControllerName] = array(); - } - - if (FALSE === in_array($extensionKey, self::$extensions[$providesControllerName])) { - array_push(self::$extensions[$providesControllerName], $extensionKey); - } - } - - /** - * @param string $forControllerName - * @return array - */ - public static function getRegisteredProviderExtensionKeys($forControllerName) { - if (TRUE === isset(self::$extensions[$forControllerName])) { - return array_unique(array_merge(self::$extensions[self::CONTROLLER_ALL], self::$extensions[$forControllerName])); - } - return self::$extensions[self::CONTROLLER_ALL]; - } - - /** - * Registers a class implementing one of the Flux ConfigurationProvider - * interfaces. - * - * @param string|object $classNameOrInstance - * @return void - * @throws \RuntimeException - */ - public static function registerConfigurationProvider($classNameOrInstance) { - if (FALSE === in_array($classNameOrInstance, self::$unregisteredProviders) && FALSE === in_array($classNameOrInstance, self::$providers)) { - array_push(self::$providers, $classNameOrInstance); - } - } - - /** - * Registers a Fluid template for use as a Dynamic Flex Form template in the - * style of Flux's Fluid Content Element and Fluid Page configurations. See - * documentation web site for more detailed information about how to - * configure such a FlexForm template. - * - * Note: you can point to your Model Object templates and place the - * configuration in these templates - and get automatically transformed - * values from your FlexForms, i.e. a Domain Object instance from a "group" - * type select box or an ObjectStorage from a list of records. Usual output - * is completely ignored, only the "Configuration" section is considered. - * - * @param mixed $extensionKey The extension key which registered this FlexForm - * @param mixed $pluginSignature The plugin signature this FlexForm belongs to - * @param mixed $templateFilename Location of the Fluid template containing field definitions - * @param mixed $variables Optional array of variables to pass to Fluid template - * @param mixed|NULL Optional section name containing the configuration - * @param mixed|NULL Optional paths array / Closure to return paths - * @param string $fieldName Optional fieldname if not from pi_flexform - * @return void - */ - public static function registerFluidFlexFormPlugin($extensionKey, $pluginSignature, $templateFilename, $variables=array(), $section=NULL, $paths=NULL, $fieldName='pi_flexform') { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - /** @var $provider ProviderInterface */ - $provider = $objectManager->get('FluidTYPO3\Flux\Provider\Provider'); - $provider->setTableName('tt_content'); - $provider->setFieldName($fieldName); - $provider->setExtensionKey($extensionKey); - $provider->setListType($pluginSignature); - $provider->setTemplatePathAndFilename($templateFilename); - $provider->setTemplateVariables($variables); - $provider->setTemplatePaths($paths); - $provider->setConfigurationSectionName($section); - self::registerConfigurationProvider($provider); - } - - /** - * Same as registerFluidFlexFormPlugin, but uses a content object type for - * resolution - use this if you registered your Extbase plugin as a content - * object in your localconf. - * - * @param mixed $extensionKey The extension key which registered this FlexForm - * @param mixed $contentObjectType The cType of the object you registered - * @param mixed $templateFilename Location of the Fluid template containing field definitions - * @param mixed $variables Optional array of variables to pass to Fluid template - * @param mixed|NULL Optional section name containing the configuration - * @param mixed|NULL Optional paths array / Closure to return paths - * @param string $fieldName Optional fieldname if not from pi_flexform - * @return void - */ - public static function registerFluidFlexFormContentObject($extensionKey, $contentObjectType, $templateFilename, $variables = array(), $section = NULL, $paths = NULL, $fieldName = 'pi_flexform') { - /** @var $objectManager ObjectManagerInterface */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - /** @var $provider ContentProvider */ - $provider = $objectManager->get('FluidTYPO3\Flux\Provider\ContentProvider'); - $provider->setTableName('tt_content'); - $provider->setFieldName($fieldName); - $provider->setExtensionKey($extensionKey); - $provider->setTemplatePathAndFilename($templateFilename); - $provider->setTemplateVariables($variables); - $provider->setTemplatePaths($paths); - $provider->setConfigurationSectionName($section); - $provider->setContentObjectType($contentObjectType); - self::registerConfigurationProvider($provider); - } - - /** - * Same as registerFluidFlexFormPlugin, but enables registering FlexForms - * for any TCA field (type "flex") or field whose TCA you have overridden - * to display as a FlexForm. - * - * @param mixed $table The SQL table this FlexForm is bound to - * @param mixed $fieldName The SQL field this FlexForm is bound to - * @param mixed $templateFilename Location of the Fluid template containing field definitions - * @param mixed $variables Optional array of variables to pass to Fluid template - * @param mixed|NULL Optional section name containing the configuration - * @param mixed|NULL Optional paths array / Closure to return paths - * @return void - */ - public static function registerFluidFlexFormTable($table, $fieldName, $templateFilename, $variables = array(), $section = NULL, $paths = NULL) { - /** @var $objectManager ObjectManagerInterface */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - /** @var $provider ProviderInterface */ - $provider = $objectManager->get('FluidTYPO3\Flux\Provider\Provider'); - $provider->setTableName($table); - $provider->setFieldName($fieldName); - $provider->setTemplatePathAndFilename($templateFilename); - $provider->setTemplateVariables($variables); - $provider->setTemplatePaths($paths); - $provider->setConfigurationSectionName($section); - self::registerConfigurationProvider($provider); - } - - /** - * @param string $providerClassName - * @return void - */ - public static function unregisterConfigurationProvider($providerClassName) { - if (TRUE === in_array($providerClassName, self::$providers)) { - $index = array_search($providerClassName, self::$providers); - unset(self::$providers[$index]); - } elseif (FALSE === in_array($providerClassName, self::$unregisteredProviders)) { - array_push(self::$unregisteredProviders, $providerClassName); - } - } - - /** - * @param string $typeOrClassName - * @param string $insteadOfNativeType - * @return void - */ - public static function registerPipe($typeOrClassName, $insteadOfNativeType = NULL) { - $key = NULL === $insteadOfNativeType ? $typeOrClassName : $insteadOfNativeType; - self::$pipes[$key] = $typeOrClassName; - } - - /** - * @param string $typeOrClassName - */ - public static function unregisterPipe($typeOrClassName) { - if (TRUE === in_array($typeOrClassName, self::$pipes)) { - $index = array_search($typeOrClassName, self::$pipes); - unset(self::$pipes[$index]); - } - } - - /** - * @param string $typeOrClassName - * @param string $insteadOfNativeType - * @return void - */ - public static function registerOutlet($typeOrClassName, $insteadOfNativeType = NULL) { - $key = NULL === $insteadOfNativeType ? $typeOrClassName : $insteadOfNativeType; - self::$outlets[$key] = $typeOrClassName; - } - - /** - * @param string $typeOrClassName - */ - public static function unregisterOutlet($typeOrClassName) { - if (TRUE === in_array($typeOrClassName, self::$outlets)) { - $index = array_search($typeOrClassName, self::$outlets); - unset(self::$outlets[$index]); - } - } - - /** - * Gets the defined FlexForms configuration providers based on parameters - * @return array - */ - public static function getRegisteredFlexFormProviders() { - reset(self::$providers); - return self::$providers; - } - - /** - * @return Form[] - */ - public static function getRegisteredFormsForTables() { - return self::$forms['tables']; - } - - /** - * @param string $table - * @return Form|NULL - */ - public static function getRegisteredFormForTable($table) { - if (TRUE === isset(self::$forms['tables'][$table])) { - return self::$forms['tables'][$table]; - } - return NULL; - } - - /** - * @return Form[] - */ - public static function getRegisteredFormsForModelObjectClasses() { - return self::$forms['models']; - } - - /** - * @return Form[] - */ - public static function getRegisteredPackagesForAutoForms() { - return self::$forms['packages']; - } - - /** - * @param string $class - * @return Form|NULL - */ - public static function getRegisteredFormForModelObjectClass($class) { - if (TRUE === isset(self::$forms['models'][$class])) { - return self::$forms['models'][$class]; - } - return NULL; - } - - /** - * @return array - */ - public static function getPipes() { - return array_values(self::$pipes); - } - - /** - * @return array - */ - public static function getOutlets() { - return array_values(self::$outlets); - } - +class Core +{ + + const CONTROLLER_ALL = '_all'; + + /** + * Contains all ConfigurationProviders registered with Flux + * @var array + */ + private static $providers = []; + + /** + * @var array + */ + protected static $pipes = []; + + /** + * @var array + */ + protected static $outlets = []; + + /** + * Contains all Forms for tables registered with Flux + * @var array + */ + private static $forms = [ + 'models' => [], + 'tables' => [], + 'packages' => [] + ]; + + /** + * Contains ConfigurationProviders which have been unregistered + * @var array + */ + private static $unregisteredProviders = []; + + /** + * Contains all extensions registered with Flux + * @var array + */ + private static $extensions = [ + self::CONTROLLER_ALL => [] + ]; + + /** + * Contains all programatically added TypoScript configuration files for auto-inclusion + * @var array + */ + private static $staticTypoScript = []; + + /** + * @return array + */ + public static function getStaticTypoScript() + { + return self::$staticTypoScript; + } + + /** + * @param mixed $locationOrLocations + * @return void + */ + public static function addStaticTypoScript($locationOrLocations) + { + if (true === is_array($locationOrLocations) || true === $locationOrLocations instanceof \Traversable) { + foreach ($locationOrLocations as $location) { + self::addStaticTypoScript($location); + } + } else { + if (false === in_array($locationOrLocations, self::$staticTypoScript)) { + array_push(self::$staticTypoScript, $locationOrLocations); + } + } + } + + /** + * @param string $table + * @param Form $form + * @return void + */ + public static function registerFormForTable($table, Form $form) + { + if (null === $form->getName()) { + $form->setName($table); + } + if (null === $form->getExtensionName() && true === isset($GLOBALS['_EXTKEY'])) { + $form->setExtensionName(GeneralUtility::underscoredToUpperCamelCase($GLOBALS['_EXTKEY'])); + } + self::$forms['tables'][$table] = $form; + } + + /** + * Registers automatic Form instance building and use as TCA for a model object class/table. + * + * @param string $className + * @return void + */ + public static function registerAutoFormForModelObjectClassName($className) + { + self::registerFormForModelObjectClassName($className); + } + + /** + * Registers a Form instance to use when TCA for a model object class/table is requested. + * + * @param string $className + * @param Form $form + * @return void + */ + public static function registerFormForModelObjectClassName($className, Form $form = null) + { + if (null !== $form && true === isset($GLOBALS['_EXTKEY']) && null === $form->getExtensionName()) { + $form->setExtensionName(GeneralUtility::underscoredToUpperCamelCase($GLOBALS['_EXTKEY'])); + } + self::$forms['models'][$className] = $form; + } + + /** + * @param string $className + * @return void + */ + public static function unregisterFormForModelObjectClassName($className) + { + if (true === isset(self::$forms['models'][$className])) { + unset(self::$forms['models'][$className]); + } + } + + /** + * Registers a package key (Vendor.ExtensionName) which is expected to + * contain Domain/Form/{$modelName}Form classes. + * + * @param string $packageName + * @return void + */ + public static function registerFluxDomainFormPackage($packageName) + { + self::$forms['packages'][$packageName] = true; + } + + /** + * @param string $packageName + * @return void + */ + public static function unregisterFluxDomainFormPackage($packageName) + { + if (true === isset(self::$forms['packages'][$packageName])) { + unset(self::$forms['packages'][$packageName]); + } + } + + /** + * @param string $extensionKey + * @param string $providesControllerName + * @return void + */ + public static function registerProviderExtensionKey($extensionKey, $providesControllerName = self::CONTROLLER_ALL) + { + if (false === isset(self::$extensions[$providesControllerName])) { + self::$extensions[$providesControllerName] = []; + } + + if (false === in_array($extensionKey, self::$extensions[$providesControllerName])) { + array_push(self::$extensions[$providesControllerName], $extensionKey); + } + } + + /** + * @param string $forControllerName + * @return array + */ + public static function getRegisteredProviderExtensionKeys($forControllerName) + { + if (true === isset(self::$extensions[$forControllerName])) { + return array_unique( + array_merge(self::$extensions[self::CONTROLLER_ALL], self::$extensions[$forControllerName]) + ); + } + return self::$extensions[self::CONTROLLER_ALL]; + } + + /** + * Registers a class implementing one of the Flux ConfigurationProvider + * interfaces. + * + * @param string|object $classNameOrInstance + * @return void + * @throws \RuntimeException + */ + public static function registerConfigurationProvider($classNameOrInstance) + { + $alreadyRegistered = in_array($classNameOrInstance, self::$providers); + $alreadyUnregistered = in_array($classNameOrInstance, self::$unregisteredProviders); + if (!$alreadyUnregistered && !$alreadyRegistered) { + array_push(self::$providers, $classNameOrInstance); + } + } + + /** + * Registers a Fluid template for use as a Dynamic Flex Form template in the + * style of Flux's Fluid Content Element and Fluid Page configurations. See + * documentation web site for more detailed information about how to + * configure such a FlexForm template. + * + * Note: you can point to your Model Object templates and place the + * configuration in these templates - and get automatically transformed + * values from your FlexForms, i.e. a Domain Object instance from a "group" + * type select box or an ObjectStorage from a list of records. Usual output + * is completely ignored, only the "Configuration" section is considered. + * + * @param mixed $extensionKey The extension key which registered this FlexForm + * @param mixed $pluginSignature The plugin signature this FlexForm belongs to + * @param mixed $templateFilename Location of the Fluid template containing field definitions + * @param mixed $variables Optional array of variables to pass to Fluid template + * @param mixed|NULL Optional section name containing the configuration + * @param mixed|NULL Optional paths array / Closure to return paths + * @param string $fieldName Optional fieldname if not from pi_flexform + * @return void + */ + public static function registerFluidFlexFormPlugin( + $extensionKey, + $pluginSignature, + $templateFilename, + $variables = [], + $section = null, + $paths = null, + $fieldName = 'pi_flexform' + ) { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + /** @var $provider ProviderInterface */ + $provider = $objectManager->get(Provider::class); + $provider->setTableName('tt_content'); + $provider->setFieldName($fieldName); + $provider->setExtensionKey($extensionKey); + $provider->setListType($pluginSignature); + $provider->setTemplatePathAndFilename($templateFilename); + $provider->setTemplateVariables($variables); + $provider->setTemplatePaths($paths); + $provider->setConfigurationSectionName($section); + self::registerConfigurationProvider($provider); + } + + /** + * Same as registerFluidFlexFormPlugin, but uses a content object type for + * resolution - use this if you registered your Extbase plugin as a content + * object in your localconf. + * + * @param mixed $extensionKey The extension key which registered this FlexForm + * @param mixed $contentObjectType The cType of the object you registered + * @param mixed $templateFilename Location of the Fluid template containing field definitions + * @param mixed $variables Optional array of variables to pass to Fluid template + * @param mixed|NULL Optional section name containing the configuration + * @param mixed|NULL Optional paths array / Closure to return paths + * @param string $fieldName Optional fieldname if not from pi_flexform + * @return void + */ + public static function registerFluidFlexFormContentObject( + $extensionKey, + $contentObjectType, + $templateFilename, + $variables = [], + $section = null, + $paths = null, + $fieldName = 'pi_flexform' + ) { + /** @var $objectManager ObjectManagerInterface */ + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + /** @var $provider ContentProvider */ + $provider = $objectManager->get(ContentProvider::class); + $provider->setTableName('tt_content'); + $provider->setFieldName($fieldName); + $provider->setExtensionKey($extensionKey); + $provider->setTemplatePathAndFilename($templateFilename); + $provider->setTemplateVariables($variables); + $provider->setTemplatePaths($paths); + $provider->setConfigurationSectionName($section); + $provider->setContentObjectType($contentObjectType); + self::registerConfigurationProvider($provider); + } + + /** + * Same as registerFluidFlexFormPlugin, but enables registering FlexForms + * for any TCA field (type "flex") or field whose TCA you have overridden + * to display as a FlexForm. + * + * @param mixed $table The SQL table this FlexForm is bound to + * @param mixed $fieldName The SQL field this FlexForm is bound to + * @param mixed $templateFilename Location of the Fluid template containing field definitions + * @param mixed $variables Optional array of variables to pass to Fluid template + * @param mixed|NULL Optional section name containing the configuration + * @param mixed|NULL Optional paths array / Closure to return paths + * @return void + */ + public static function registerFluidFlexFormTable( + $table, + $fieldName, + $templateFilename, + $variables = [], + $section = null, + $paths = null + ) { + /** @var $objectManager ObjectManagerInterface */ + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + /** @var $provider ProviderInterface */ + $provider = $objectManager->get(Provider::class); + $provider->setTableName($table); + $provider->setFieldName($fieldName); + $provider->setTemplatePathAndFilename($templateFilename); + $provider->setTemplateVariables($variables); + $provider->setTemplatePaths($paths); + $provider->setConfigurationSectionName($section); + self::registerConfigurationProvider($provider); + } + + /** + * @param string $providerClassName + * @return void + */ + public static function unregisterConfigurationProvider($providerClassName) + { + if (true === in_array($providerClassName, self::$providers)) { + $index = array_search($providerClassName, self::$providers); + unset(self::$providers[$index]); + } elseif (false === in_array($providerClassName, self::$unregisteredProviders)) { + array_push(self::$unregisteredProviders, $providerClassName); + } + } + + /** + * @param string $typeOrClassName + * @param string $insteadOfNativeType + * @return void + */ + public static function registerPipe($typeOrClassName, $insteadOfNativeType = null) + { + $key = null === $insteadOfNativeType ? $typeOrClassName : $insteadOfNativeType; + self::$pipes[$key] = $typeOrClassName; + } + + /** + * @param string $typeOrClassName + */ + public static function unregisterPipe($typeOrClassName) + { + if (true === in_array($typeOrClassName, self::$pipes)) { + $index = array_search($typeOrClassName, self::$pipes); + unset(self::$pipes[$index]); + } + } + + /** + * @param string $typeOrClassName + * @param string $insteadOfNativeType + * @return void + */ + public static function registerOutlet($typeOrClassName, $insteadOfNativeType = null) + { + $key = null === $insteadOfNativeType ? $typeOrClassName : $insteadOfNativeType; + self::$outlets[$key] = $typeOrClassName; + } + + /** + * @param string $typeOrClassName + */ + public static function unregisterOutlet($typeOrClassName) + { + if (true === in_array($typeOrClassName, self::$outlets)) { + $index = array_search($typeOrClassName, self::$outlets); + unset(self::$outlets[$index]); + } + } + + /** + * Gets the defined FlexForms configuration providers based on parameters + * @return array + */ + public static function getRegisteredFlexFormProviders() + { + reset(self::$providers); + return self::$providers; + } + + /** + * @return Form[] + */ + public static function getRegisteredFormsForTables() + { + return self::$forms['tables']; + } + + /** + * @param string $table + * @return Form|NULL + */ + public static function getRegisteredFormForTable($table) + { + if (true === isset(self::$forms['tables'][$table])) { + return self::$forms['tables'][$table]; + } + return null; + } + + /** + * @return Form[] + */ + public static function getRegisteredFormsForModelObjectClasses() + { + return self::$forms['models']; + } + + /** + * @return Form[] + */ + public static function getRegisteredPackagesForAutoForms() + { + return self::$forms['packages']; + } + + /** + * @param string $class + * @return Form|NULL + */ + public static function getRegisteredFormForModelObjectClass($class) + { + if (true === isset(self::$forms['models'][$class])) { + return self::$forms['models'][$class]; + } + return null; + } + + /** + * @return array + */ + public static function getPipes() + { + return array_values(self::$pipes); + } + + /** + * @return array + */ + public static function getOutlets() + { + return array_values(self::$outlets); + } } diff --git a/Classes/FluxPackage.php b/Classes/FluxPackage.php index 0670a9c41..fc0005c00 100644 --- a/Classes/FluxPackage.php +++ b/Classes/FluxPackage.php @@ -25,212 +25,227 @@ /** * Class FluxPackage */ -class FluxPackage implements FluxPackageInterface { - - const IMPLEMENTATION_VIEW = 'view'; - const IMPLEMENTATION_VIEWCONTEXT = 'viewContext'; - const IMPLEMENTATION_RENDERINGCONTEXT = 'renderingContext'; - const IMPLEMENTATION_FORM = 'form'; - const IMPLEMENTATION_TEMPLATEPATHS = 'templatePaths'; - const IMPLEMENTATION_TEMPLATEVARIABLEPROVIDER = 'templateVariableProvider'; - const IMPLEMENTATION_VIEWHELPERRESOLVER = 'viewHelperResolver'; - const IMPLEMENTATION_VIEWHELPERINVOKER = 'viewHelperInvoker'; - - const FEATURE_PREVIEW = 'preview'; - const FEATURE_TRANSFORMATION = 'transformation'; - const FEATURE_DATAHANDLING = 'dataHandling'; - - /** - * @var array - */ - protected $manifest = array(); - - /** - * @var array - */ - protected $defaultImplementations = array( - self::IMPLEMENTATION_VIEW => ExposedTemplateView::class, - self::IMPLEMENTATION_VIEWCONTEXT => ViewContext::class, - self::IMPLEMENTATION_RENDERINGCONTEXT => RenderingContext::class, - self::IMPLEMENTATION_FORM => Form::class, - self::IMPLEMENTATION_TEMPLATEPATHS => TemplatePaths::class, - self::IMPLEMENTATION_TEMPLATEVARIABLEPROVIDER => TemplateVariableContainer::class, - self::IMPLEMENTATION_VIEWHELPERRESOLVER => NULL, // @TODO: fill when standalone fluid arrives - self::IMPLEMENTATION_VIEWHELPERINVOKER => NULL // @TODO: fill when standalone fluid arrives - ); - - /** - * @param mixed $seedArrayOrExtensionKeyOrManifestPath - * @return FluxPackageInterface - */ - public static function create($seedArrayOrExtensionKeyOrManifestPath) { - return new static($seedArrayOrExtensionKeyOrManifestPath); - } - - /** - * 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)); - } - } - - /** - * Load flux.json manifest file by path or reference. - * - * @param string $filePathAndFilename - * @return array - */ - protected function loadManifestFile($filePathAndFilename) { - if (strpos($filePathAndFilename, '/') !== 0) { - $absoluteManifestPath = GeneralUtility::getFileAbsFileName($filePathAndFilename); - } else { - $absoluteManifestPath = $filePathAndFilename; - } - if (!file_exists($absoluteManifestPath)) { - throw new PackageNotFoundException( - sprintf('Flux manifest file not found! I looked for %s - make sure the manifest exists.', $absoluteManifestPath) - ); - } - return json_decode(file_get_contents($absoluteManifestPath), JSON_OBJECT_AS_ARRAY); - } - - /** - * Must always return the vendor name (as used in class - * namespaces) corresponding to this package. - * - * @return string - */ - public function getVendorName() { - return ExtensionNamingUtility::getVendorName($this->manifest['package']); - } - - /** - * Must always return the ExtensionName format of the - * extension key, excluding the vendor name. - * - * @return string - */ - public function getExtensionName() { - return ExtensionNamingUtility::getExtensionName($this->manifest['package']); - } - - /** - * Must always return the $vendor\$extensioName format - * of the vendor and extension name, using values from - * the two preceeding methods. - * - * @return string - */ - public function getNamespacePrefix() { - return $this->getVendorName() . '\\' . $this->getExtensionName() . '\\'; - } - - /** - * Returns an instance of Flux's TemplatePaths class - * with template paths of this package preloaded. - * - * @return TemplatePaths - */ - public function getViewPaths() { - return new TemplatePaths(!empty($this->manifest['view']) ? $this->manifest['view'] : $this->getExtensionName()); - } - - /** - * Asserts whether or not this FluxPackage contains an - * integration designed for the controller name, e.g. - * "Content", "Page" etc. - * - * @param string $controllerName - * @return boolean - */ - public function isProviderFor($controllerName) { - return !empty($this->manifest['providers']) && in_array($controllerName, $this->manifest['providers']); - } - - /** - * Asserts whether or not the feature is enabled for - * this FluxPackage. - * - * @param string $featureName - * @return boolean - */ - public function isFeatureEnabled($featureName) { - return !empty($this->manifest['features']) && in_array($featureName, $this->manifest['features']); - } - - /** - * Get FQN of the class that's designated as an - * implementation, meaning it is replaceable by Flux - * Packages via this method. - * - * @param string $implementationName - * @return string - */ - public function getImplementation($implementationName) { - if (!empty($this->manifest['implementations']) && array_key_exists($implementationName, $this->manifest['implementations'])) { - return $this->manifest['implementations'][$implementationName]; - } - return $this->defaultImplementations[$implementationName]; - } - - /** - * Modify properties of this FluxPackage (in this class - * instance only) by passing an array using the same - * structure as the constructor and as in the manifest. - * - * Is used internally when applying compatibility values: - * the "overlay" type subset of version dependent values - * is detected based on current version and passed to - * this function which then assimilates the values. - * - * @param array $alternativeManifestDeclaration - * @return void - */ - public function modify(array $alternativeManifestDeclaration) { - RecursiveArrayUtility::mergeRecursiveOverrule($this->manifest, $alternativeManifestDeclaration); - } - - /** - * Upcasts (promotes) the instance to another class name - * by creating a new instance of the provided class and - * passing $this->manifest as seed. If NULL is passed as - * desired class name the expected final class name is - * determined based on naming convention. - * - * @param string $desiredClassName - * @return FluxPackageInterface - */ - public function upcast($desiredClassName = NULL) { - if (!$desiredClassName) { - $desiredClassName = $this->getNamespacePrefix() . 'FluxPackage'; - } - return new $desiredClassName($this->manifest); - } - +class FluxPackage implements FluxPackageInterface +{ + + const IMPLEMENTATION_VIEW = 'view'; + const IMPLEMENTATION_VIEWCONTEXT = 'viewContext'; + const IMPLEMENTATION_RENDERINGCONTEXT = 'renderingContext'; + const IMPLEMENTATION_FORM = 'form'; + const IMPLEMENTATION_TEMPLATEPATHS = 'templatePaths'; + const IMPLEMENTATION_TEMPLATEVARIABLEPROVIDER = 'templateVariableProvider'; + const IMPLEMENTATION_VIEWHELPERRESOLVER = 'viewHelperResolver'; + const IMPLEMENTATION_VIEWHELPERINVOKER = 'viewHelperInvoker'; + + const FEATURE_PREVIEW = 'preview'; + const FEATURE_TRANSFORMATION = 'transformation'; + const FEATURE_DATAHANDLING = 'dataHandling'; + + /** + * @var array + */ + protected $manifest = []; + + /** + * @var array + */ + protected $defaultImplementations = [ + self::IMPLEMENTATION_VIEW => ExposedTemplateView::class, + self::IMPLEMENTATION_VIEWCONTEXT => ViewContext::class, + self::IMPLEMENTATION_RENDERINGCONTEXT => RenderingContext::class, + self::IMPLEMENTATION_FORM => Form::class, + self::IMPLEMENTATION_TEMPLATEPATHS => TemplatePaths::class, + self::IMPLEMENTATION_TEMPLATEVARIABLEPROVIDER => TemplateVariableContainer::class, + self::IMPLEMENTATION_VIEWHELPERRESOLVER => null, // @TODO: fill when standalone fluid arrives + self::IMPLEMENTATION_VIEWHELPERINVOKER => null // @TODO: fill when standalone fluid arrives + ]; + + /** + * @param mixed $seedArrayOrExtensionKeyOrManifestPath + * @return FluxPackageInterface + */ + public static function create($seedArrayOrExtensionKeyOrManifestPath) + { + return new static($seedArrayOrExtensionKeyOrManifestPath); + } + + /** + * 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)); + } + } + + /** + * Load flux.json manifest file by path or reference. + * + * @param string $filePathAndFilename + * @return array + */ + protected function loadManifestFile($filePathAndFilename) + { + if (strpos($filePathAndFilename, '/') !== 0) { + $absoluteManifestPath = GeneralUtility::getFileAbsFileName($filePathAndFilename); + } else { + $absoluteManifestPath = $filePathAndFilename; + } + if (!file_exists($absoluteManifestPath)) { + throw new PackageNotFoundException( + sprintf( + 'Flux manifest file not found! I looked for %s - make sure the manifest exists.', + $absoluteManifestPath + ) + ); + } + return json_decode(file_get_contents($absoluteManifestPath), JSON_OBJECT_AS_ARRAY); + } + + /** + * Must always return the vendor name (as used in class + * namespaces) corresponding to this package. + * + * @return string + */ + public function getVendorName() + { + return ExtensionNamingUtility::getVendorName($this->manifest['package']); + } + + /** + * Must always return the ExtensionName format of the + * extension key, excluding the vendor name. + * + * @return string + */ + public function getExtensionName() + { + return ExtensionNamingUtility::getExtensionName($this->manifest['package']); + } + + /** + * Must always return the $vendor\$extensioName format + * of the vendor and extension name, using values from + * the two preceeding methods. + * + * @return string + */ + public function getNamespacePrefix() + { + return $this->getVendorName() . '\\' . $this->getExtensionName() . '\\'; + } + + /** + * Returns an instance of Flux's TemplatePaths class + * with template paths of this package preloaded. + * + * @return TemplatePaths + */ + public function getViewPaths() + { + return new TemplatePaths(!empty($this->manifest['view']) ? $this->manifest['view'] : $this->getExtensionName()); + } + + /** + * Asserts whether or not this FluxPackage contains an + * integration designed for the controller name, e.g. + * "Content", "Page" etc. + * + * @param string $controllerName + * @return boolean + */ + public function isProviderFor($controllerName) + { + return !empty($this->manifest['providers']) && in_array($controllerName, $this->manifest['providers']); + } + + /** + * Asserts whether or not the feature is enabled for + * this FluxPackage. + * + * @param string $featureName + * @return boolean + */ + public function isFeatureEnabled($featureName) + { + return !empty($this->manifest['features']) && in_array($featureName, $this->manifest['features']); + } + + /** + * Get FQN of the class that's designated as an + * implementation, meaning it is replaceable by Flux + * Packages via this method. + * + * @param string $name + * @return string + */ + public function getImplementation($name) + { + if (!empty($this->manifest['implementations']) && array_key_exists($name, $this->manifest['implementations'])) { + return $this->manifest['implementations'][$name]; + } + return $this->defaultImplementations[$name]; + } + + /** + * Modify properties of this FluxPackage (in this class + * instance only) by passing an array using the same + * structure as the constructor and as in the manifest. + * + * Is used internally when applying compatibility values: + * the "overlay" type subset of version dependent values + * is detected based on current version and passed to + * this function which then assimilates the values. + * + * @param array $alternativeManifestDeclaration + * @return void + */ + public function modify(array $alternativeManifestDeclaration) + { + RecursiveArrayUtility::mergeRecursiveOverrule($this->manifest, $alternativeManifestDeclaration); + } + + /** + * Upcasts (promotes) the instance to another class name + * by creating a new instance of the provided class and + * passing $this->manifest as seed. If NULL is passed as + * desired class name the expected final class name is + * determined based on naming convention. + * + * @param string $desiredClassName + * @return FluxPackageInterface + */ + public function upcast($desiredClassName = null) + { + if (!$desiredClassName) { + $desiredClassName = $this->getNamespacePrefix() . 'FluxPackage'; + } + return new $desiredClassName($this->manifest); + } } diff --git a/Classes/Form.php b/Classes/Form.php index d2907839b..28bdd9c8a 100644 --- a/Classes/Form.php +++ b/Classes/Form.php @@ -8,423 +8,456 @@ * LICENSE.md file that was distributed with this source code. */ +use FluidTYPO3\Flux\Form\Container\Sheet; use FluidTYPO3\Flux\Outlet\OutletInterface; +use FluidTYPO3\Flux\Outlet\StandardOutlet; use FluidTYPO3\Flux\Package\FluxPackageFactory; use FluidTYPO3\Flux\Utility\ExtensionNamingUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Reflection\ObjectAccess; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; /** * Form */ -class Form extends Form\AbstractFormContainer implements Form\FieldContainerInterface { - - const OPTION_SORTING = 'sorting'; - const OPTION_TRANSLATION = 'translation'; - const OPTION_GROUP = 'group'; - const OPTION_ICON = 'icon'; - const OPTION_TCA_LABELS = 'labels'; - const OPTION_TCA_HIDE = 'hide'; - const OPTION_TCA_START = 'start'; - const OPTION_TCA_END = 'end'; - const OPTION_TCA_DELETE = 'delete'; - const OPTION_TCA_FEGROUP = 'frontendUserGroup'; - const OPTION_TEMPLATEFILE = 'templateFile'; - const OPTION_RECORD = 'record'; - const OPTION_RECORD_FIELD = 'recordField'; - const OPTION_RECORD_TABLE = 'recordTable'; - const OPTION_DEFAULT_VALUES = 'defaultValues'; - const TRANSLATION_DISABLED = 'disabled'; - const TRANSLATION_SEPARATE = 'separate'; - const TRANSLATION_INHERIT = 'inherit'; - const POSITION_TOP = 'top'; - const POSITION_BOTTOM = 'bottom'; - const POSITION_BOTH = 'both'; - const POSITION_NONE = 'none'; - const CONTROL_INFO = 'info'; - const CONTROL_NEW = 'new'; - const CONTROL_DRAGDROP = 'dragdrop'; - const CONTROL_SORT = 'sort'; - const CONTROL_HIDE = 'hide'; - const CONTROL_DELETE = 'delete'; - const CONTROL_LOCALISE = 'localize'; - const DEFAULT_LANGUAGEFILE = '/Resources/Private/Language/locallang.xlf'; - - /** - * Machine-readable, lowerCamelCase ID of this form. DOM compatible. - * - * @var string - */ - protected $id; - - /** - * Should be set to contain the extension name in UpperCamelCase of - * the extension implementing this form object. - * - * @var string - */ - protected $extensionName; - - /** - * If TRUE, removes sheet wrappers if there is only a single sheet. - * - * @var boolean - */ - protected $compact = FALSE; - - /** - * @var string - */ - protected $description; - - /** - * @var array - */ - protected $options = array(); - - /** - * @var OutletInterface - */ - protected $outlet; - - /** - * @return void - */ - public function initializeObject() { - /** @var Form\Container\Sheet $defaultSheet */ - $defaultSheet = $this->getObjectManager()->get('FluidTYPO3\Flux\Form\Container\Sheet'); - $defaultSheet->setName('options'); - $defaultSheet->setLabel('LLL:EXT:flux' . $this->localLanguageFileRelativePath . ':tt_content.tx_flux_options'); - $this->add($defaultSheet); - $this->outlet = $this->getObjectManager()->get('FluidTYPO3\Flux\Outlet\StandardOutlet'); - } - - /** - * @param array $settings - * @return FormInterface - */ - public static function create(array $settings = array()) { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - if (isset($settings['extensionName'])) { - $className = FluxPackageFactory::getPackageWithFallback($settings['extensionName']) - ->getImplementation(FluxPackage::IMPLEMENTATION_FORM); - } else { - $className = get_called_class(); - } - /** @var FormInterface $object */ - $object = $objectManager->get($className); - return $object->modify($settings); - } - - /** - * @param Form\FormInterface $child - * @return Form\FormInterface - */ - public function add(Form\FormInterface $child) { - if (FALSE === $child instanceof Form\Container\Sheet) { - /** @var Form\Container\Sheet $last */ - $last = $this->last(); - $last->add($child); - } else { - $children = $this->children; - foreach ($children as $existingChild) { - if ($child->getName() === $existingChild->getName()) { - return $this; - } - } - $this->children->attach($child); - $child->setParent($this); - } - return $this; - } - - /** - * @return array - */ - public function build() { - $translateOption = $this->getOption(self::OPTION_TRANSLATION); - $translateOption = TRUE === empty($translateOption) ? self::TRANSLATION_DISABLED : $translateOption; - $disableLocalisation = self::TRANSLATION_DISABLED === $translateOption ? 1 : 0; - $inheritLocalisation = self::TRANSLATION_INHERIT === $translateOption ? 1 : 0; - $dataStructArray = array( - 'meta' => array( - 'langDisable' => $disableLocalisation, - 'langChildren' => $inheritLocalisation - ), - ); - $copy = clone $this; - foreach ($this->getSheets(TRUE) as $sheet) { - if (FALSE === $sheet->hasChildren()) { - $copy->remove($sheet->getName()); - } - } - $sheets = $copy->getSheets(); - $compactExtensionToggleOn = 0 < $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['compact']; - $compactConfigurationToggleOn = 0 < $copy->getCompact(); - if (($compactExtensionToggleOn || $compactConfigurationToggleOn) && 1 === count($sheets)) { - $dataStructArray = $copy->last()->build(); - $dataStructArray['meta'] = array('langDisable' => $disableLocalisation); - unset($dataStructArray['ROOT']['TCEforms']); - } elseif (0 < count($sheets)) { - $dataStructArray['sheets'] = $copy->buildChildren($this->children); - } else { - $dataStructArray['ROOT'] = array( - 'type' => 'array', - 'el' => array() - ); - } - return $dataStructArray; - } - - /** - * @param boolean $includeEmpty - * @return Form\Container\Sheet[] - */ - public function getSheets($includeEmpty = FALSE) { - $sheets = array(); - foreach ($this->children as $sheet) { - if (FALSE === $sheet->hasChildren() && FALSE === $includeEmpty) { - continue; - } - $name = $sheet->getName(); - $sheets[$name] = $sheet; - } - return $sheets; - } - - /** - * @return Form\FieldInterface[] - */ - public function getFields() { - $fields = array(); - foreach ($this->getSheets() as $sheet) { - $fieldsInSheet = $sheet->getFields(); - $fields = array_merge($fields, $fieldsInSheet); - } - return $fields; - } - - /** - * @param boolean $compact - * @return Form\FormInterface - */ - public function setCompact($compact) { - $this->compact = $compact; - return $this; - } - - /** - * @return boolean - */ - public function getCompact() { - return $this->compact; - } - - /** - * @param string $extensionName - * @return Form\FormInterface - */ - public function setExtensionName($extensionName) { - $this->extensionName = $extensionName; - return $this; - } - - /** - * @return string - */ - public function getExtensionName() { - return $this->extensionName; - } - - /** - * @param string $group - * @return Form\FormInterface - */ - public function setGroup($group) { - GeneralUtility::logDeprecatedFunction(); - $this->setOption(self::OPTION_GROUP, $group); - return $this; - } - - /** - * @return string - */ - public function getGroup() { - GeneralUtility::logDeprecatedFunction(); - return $this->getOption(self::OPTION_GROUP); - } - - /** - * @param string $icon - * @return Form\FormInterface - * @deprecated - */ - public function setIcon($icon) { - GeneralUtility::logDeprecatedFunction(); - $this->setOption(self::OPTION_ICON, $icon); - return $this; - } - - /** - * @return string - * @deprecated - */ - public function getIcon() { - GeneralUtility::logDeprecatedFunction(); - $icon = $this->getOption(self::OPTION_ICON); - if (0 === strpos($icon, 'EXT:')) { - $icon = GeneralUtility::getFileAbsFileName($icon); - } - return $icon; - } - - /** - * @param string $id - * @return Form\FormInterface - */ - public function setId($id) { - $allowed = 'a-z0-9_'; - $pattern = '/[^' . $allowed . ']+/i'; - if (preg_match($pattern, $id)) { - $this->getConfigurationService()->message('Flux FlexForm with id "' . $id . '" uses invalid characters in the ID; valid characters - are: "' . $allowed . '" and the pattern used for matching is "' . $pattern . '". This bad ID name will prevent - you from utilising some features, fx automatic LLL reference building, but is not fatal', GeneralUtility::SYSLOG_SEVERITY_NOTICE); - } - $this->id = $id; - if (TRUE === empty($this->name)) { - $this->name = $id; - } - return $this; - } - - /** - * @return string - */ - public function getId() { - return $this->id; - } - - /** - * @param string $description - * @return Form\FormInterface - */ - public function setDescription($description) { - $this->description = $description; - return $this; - } - - /** - * @return string - */ - public function getDescription() { - $description = $this->description; - $translated = NULL; - $extensionKey = ExtensionNamingUtility::getExtensionKey($this->extensionName); - if (TRUE === empty($description)) { - $relativeFilePath = $this->getLocalLanguageFileRelativePath(); - $relativeFilePath = ltrim($relativeFilePath, '/'); - $filePrefix = 'LLL:EXT:' . $extensionKey . '/' . $relativeFilePath; - $description = $filePrefix . ':' . trim('flux.' . $this->id . '.description'); - } - return $description; - } - - /** - * @param array $options - * @return Form\FormInterface - */ - public function setOptions(array $options) { - $this->options = $options; - return $this; - } - - /** - * @return array - */ - public function getOptions() { - return $this->options; - } - - /** - * @param string $name - * @param mixed $value - * @return Form\FormInterface - */ - public function setOption($name, $value) { - $this->options[$name] = $value; - return $this; - } - - /** - * @param string $name - * @return mixed - */ - public function getOption($name) { - return ObjectAccess::getPropertyPath($this->options, $name); - } - - /** - * @param string $name - * @return boolean - */ - public function hasOption($name) { - return TRUE === isset($this->options[$name]); - } - - /** - * @return boolean - */ - public function hasChildren() { - foreach ($this->children as $child) { - if (TRUE === $child->hasChildren()) { - return TRUE; - } - } - return FALSE; - } - - /** - * @param OutletInterface $outlet - * @return Form\FormInterface - */ - public function setOutlet(OutletInterface $outlet) { - $this->outlet = $outlet; - return $this; - } - - /** - * @return OutletInterface - */ - public function getOutlet() { - return $this->outlet; - } - - /** - * @param array $structure - * @return ContainerInterface - */ - public function modify(array $structure) { - if (TRUE === isset($structure['options']) && TRUE === is_array($structure['options'])) { - foreach ($structure['options'] as $name => $value) { - $this->setOption($name, $value); - } - unset($structure['options']); - } - if (TRUE === isset($structure['sheets'])) { - foreach ((array) $structure['sheets'] as $index => $sheetData) { - $sheetName = TRUE === isset($sheetData['name']) ? $sheetData['name'] : $index; - // check if field already exists - if it does, modify it. If it does not, create it. - if (TRUE === $this->has($sheetName)) { - $sheet = $this->get($sheetName); - } else { - $sheet = $this->createContainer('Sheet', $sheetName); - } - $sheet->modify($sheetData); - } - } - return parent::modify($structure); - } - +class Form extends Form\AbstractFormContainer implements Form\FieldContainerInterface +{ + + const OPTION_SORTING = 'sorting'; + const OPTION_TRANSLATION = 'translation'; + const OPTION_GROUP = 'group'; + const OPTION_ICON = 'icon'; + const OPTION_TCA_LABELS = 'labels'; + const OPTION_TCA_HIDE = 'hide'; + const OPTION_TCA_START = 'start'; + const OPTION_TCA_END = 'end'; + const OPTION_TCA_DELETE = 'delete'; + const OPTION_TCA_FEGROUP = 'frontendUserGroup'; + const OPTION_TEMPLATEFILE = 'templateFile'; + const OPTION_RECORD = 'record'; + const OPTION_RECORD_FIELD = 'recordField'; + const OPTION_RECORD_TABLE = 'recordTable'; + const OPTION_DEFAULT_VALUES = 'defaultValues'; + const TRANSLATION_DISABLED = 'disabled'; + const TRANSLATION_SEPARATE = 'separate'; + const TRANSLATION_INHERIT = 'inherit'; + const POSITION_TOP = 'top'; + const POSITION_BOTTOM = 'bottom'; + const POSITION_BOTH = 'both'; + const POSITION_NONE = 'none'; + const CONTROL_INFO = 'info'; + const CONTROL_NEW = 'new'; + const CONTROL_DRAGDROP = 'dragdrop'; + const CONTROL_SORT = 'sort'; + const CONTROL_HIDE = 'hide'; + const CONTROL_DELETE = 'delete'; + const CONTROL_LOCALISE = 'localize'; + const DEFAULT_LANGUAGEFILE = '/Resources/Private/Language/locallang.xlf'; + + /** + * Machine-readable, lowerCamelCase ID of this form. DOM compatible. + * + * @var string + */ + protected $id; + + /** + * Should be set to contain the extension name in UpperCamelCase of + * the extension implementing this form object. + * + * @var string + */ + protected $extensionName; + + /** + * If TRUE, removes sheet wrappers if there is only a single sheet. + * + * @var boolean + */ + protected $compact = false; + + /** + * @var string + */ + protected $description; + + /** + * @var array + */ + protected $options = []; + + /** + * @var OutletInterface + */ + protected $outlet; + + /** + * @return void + */ + public function initializeObject() + { + /** @var Form\Container\Sheet $defaultSheet */ + $defaultSheet = $this->getObjectManager()->get(Sheet::class); + $defaultSheet->setName('options'); + $defaultSheet->setLabel('LLL:EXT:flux' . $this->localLanguageFileRelativePath . ':tt_content.tx_flux_options'); + $this->add($defaultSheet); + $this->outlet = $this->getObjectManager()->get(StandardOutlet::class); + } + + /** + * @param array $settings + * @return FormInterface + */ + public static function create(array $settings = []) + { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + if (isset($settings['extensionName'])) { + $className = FluxPackageFactory::getPackageWithFallback($settings['extensionName']) + ->getImplementation(FluxPackage::IMPLEMENTATION_FORM); + } else { + $className = get_called_class(); + } + /** @var FormInterface $object */ + $object = $objectManager->get($className); + return $object->modify($settings); + } + + /** + * @param Form\FormInterface $child + * @return Form\FormInterface + */ + public function add(Form\FormInterface $child) + { + if (false === $child instanceof Form\Container\Sheet) { + /** @var Form\Container\Sheet $last */ + $last = $this->last(); + $last->add($child); + } else { + $children = $this->children; + foreach ($children as $existingChild) { + if ($child->getName() === $existingChild->getName()) { + return $this; + } + } + $this->children->attach($child); + $child->setParent($this); + } + return $this; + } + + /** + * @return array + */ + public function build() + { + $translateOption = $this->getOption(self::OPTION_TRANSLATION); + $translateOption = true === empty($translateOption) ? self::TRANSLATION_DISABLED : $translateOption; + $disableLocalisation = self::TRANSLATION_DISABLED === $translateOption ? 1 : 0; + $inheritLocalisation = self::TRANSLATION_INHERIT === $translateOption ? 1 : 0; + $dataStructArray = [ + 'meta' => [ + 'langDisable' => $disableLocalisation, + 'langChildren' => $inheritLocalisation + ], + ]; + $copy = clone $this; + foreach ($this->getSheets(true) as $sheet) { + if (false === $sheet->hasChildren()) { + $copy->remove($sheet->getName()); + } + } + $sheets = $copy->getSheets(); + $compactExtensionToggleOn = 0 < $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['compact']; + $compactConfigurationToggleOn = 0 < $copy->getCompact(); + if (($compactExtensionToggleOn || $compactConfigurationToggleOn) && 1 === count($sheets)) { + $dataStructArray = $copy->last()->build(); + $dataStructArray['meta'] = ['langDisable' => $disableLocalisation]; + unset($dataStructArray['ROOT']['TCEforms']); + } elseif (0 < count($sheets)) { + $dataStructArray['sheets'] = $copy->buildChildren($this->children); + } else { + $dataStructArray['ROOT'] = [ + 'type' => 'array', + 'el' => [] + ]; + } + return $dataStructArray; + } + + /** + * @param boolean $includeEmpty + * @return Form\Container\Sheet[] + */ + public function getSheets($includeEmpty = false) + { + $sheets = []; + foreach ($this->children as $sheet) { + if (false === $sheet->hasChildren() && false === $includeEmpty) { + continue; + } + $name = $sheet->getName(); + $sheets[$name] = $sheet; + } + return $sheets; + } + + /** + * @return Form\FieldInterface[] + */ + public function getFields() + { + $fields = []; + foreach ($this->getSheets() as $sheet) { + $fieldsInSheet = $sheet->getFields(); + $fields = array_merge($fields, $fieldsInSheet); + } + return $fields; + } + + /** + * @param boolean $compact + * @return Form\FormInterface + */ + public function setCompact($compact) + { + $this->compact = $compact; + return $this; + } + + /** + * @return boolean + */ + public function getCompact() + { + return $this->compact; + } + + /** + * @param string $extensionName + * @return Form\FormInterface + */ + public function setExtensionName($extensionName) + { + $this->extensionName = $extensionName; + return $this; + } + + /** + * @return string + */ + public function getExtensionName() + { + return $this->extensionName; + } + + /** + * @param string $group + * @return Form\FormInterface + */ + public function setGroup($group) + { + GeneralUtility::logDeprecatedFunction(); + $this->setOption(self::OPTION_GROUP, $group); + return $this; + } + + /** + * @return string + */ + public function getGroup() + { + GeneralUtility::logDeprecatedFunction(); + return $this->getOption(self::OPTION_GROUP); + } + + /** + * @param string $icon + * @return Form\FormInterface + * @deprecated + */ + public function setIcon($icon) + { + GeneralUtility::logDeprecatedFunction(); + $this->setOption(self::OPTION_ICON, $icon); + return $this; + } + + /** + * @return string + * @deprecated + */ + public function getIcon() + { + GeneralUtility::logDeprecatedFunction(); + $icon = $this->getOption(self::OPTION_ICON); + if (0 === strpos($icon, 'EXT:')) { + $icon = GeneralUtility::getFileAbsFileName($icon); + } + return $icon; + } + + /** + * @param string $id + * @return Form\FormInterface + */ + public function setId($id) + { + $allowed = 'a-z0-9_'; + $pattern = '/[^' . $allowed . ']+/i'; + if (preg_match($pattern, $id)) { + $this->getConfigurationService()->message( + 'Flux FlexForm with id "' . $id . '" uses invalid characters in the ID; valid characters are: "' . + $allowed . '" and the pattern used for matching is "' . $pattern . '". This bad ID name will prevent ' . + 'you from utilising some features, fx automatic LLL reference building, but is not fatal', + GeneralUtility::SYSLOG_SEVERITY_NOTICE + ); + } + $this->id = $id; + if (true === empty($this->name)) { + $this->name = $id; + } + return $this; + } + + /** + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * @param string $description + * @return Form\FormInterface + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * @return string + */ + public function getDescription() + { + $description = $this->description; + $translated = null; + $extensionKey = ExtensionNamingUtility::getExtensionKey($this->extensionName); + if (true === empty($description)) { + $relativeFilePath = $this->getLocalLanguageFileRelativePath(); + $relativeFilePath = ltrim($relativeFilePath, '/'); + $filePrefix = 'LLL:EXT:' . $extensionKey . '/' . $relativeFilePath; + $description = $filePrefix . ':' . trim('flux.' . $this->id . '.description'); + } + return $description; + } + + /** + * @param array $options + * @return Form\FormInterface + */ + public function setOptions(array $options) + { + $this->options = $options; + return $this; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * @param string $name + * @param mixed $value + * @return Form\FormInterface + */ + public function setOption($name, $value) + { + $this->options[$name] = $value; + return $this; + } + + /** + * @param string $name + * @return mixed + */ + public function getOption($name) + { + return ObjectAccess::getPropertyPath($this->options, $name); + } + + /** + * @param string $name + * @return boolean + */ + public function hasOption($name) + { + return true === isset($this->options[$name]); + } + + /** + * @return boolean + */ + public function hasChildren() + { + foreach ($this->children as $child) { + if (true === $child->hasChildren()) { + return true; + } + } + return false; + } + + /** + * @param OutletInterface $outlet + * @return Form\FormInterface + */ + public function setOutlet(OutletInterface $outlet) + { + $this->outlet = $outlet; + return $this; + } + + /** + * @return OutletInterface + */ + public function getOutlet() + { + return $this->outlet; + } + + /** + * @param array $structure + * @return ContainerInterface + */ + public function modify(array $structure) + { + if (true === isset($structure['options']) && true === is_array($structure['options'])) { + foreach ($structure['options'] as $name => $value) { + $this->setOption($name, $value); + } + unset($structure['options']); + } + if (true === isset($structure['sheets'])) { + foreach ((array) $structure['sheets'] as $index => $sheetData) { + $sheetName = true === isset($sheetData['name']) ? $sheetData['name'] : $index; + // check if field already exists - if it does, modify it. If it does not, create it. + if (true === $this->has($sheetName)) { + $sheet = $this->get($sheetName); + } else { + $sheet = $this->createContainer('Sheet', $sheetName); + } + $sheet->modify($sheetData); + } + } + return parent::modify($structure); + } } diff --git a/Classes/Form/AbstractFormComponent.php b/Classes/Form/AbstractFormComponent.php index 5da59c383..174f7f8ca 100644 --- a/Classes/Form/AbstractFormComponent.php +++ b/Classes/Form/AbstractFormComponent.php @@ -27,468 +27,507 @@ /** * AbstractFormComponent */ -abstract class AbstractFormComponent implements FormInterface { - - /** - * @var string - */ - protected $name; - - /** - * @var boolean - */ - protected $enabled = TRUE; - - /** - * @var string - */ - protected $label = NULL; - - /** - * If TRUE, disables LLL label usage and always returns the - * raw value of $label. - * - * @var boolean - */ - protected $disableLocalLanguageLabels = FALSE; - - /** - * Relative (from extension $extensionName) path to locallang - * file containing labels for the LLL values built by this class. - * - * @var string - */ - protected $localLanguageFileRelativePath = Form::DEFAULT_LANGUAGEFILE; - - /** - * @var string - */ - protected $extensionName = 'FluidTYPO3.Flux'; - - /** - * @var ContainerInterface - */ - protected $parent; - - /** - * @var array - */ - protected $variables = array(); - - /** - * @var boolean - */ - protected $inherit = FALSE; - - /** - * @var boolean - */ - protected $inheritEmpty = FALSE; - - /** - * @param array $settings - * @return FormInterface - */ - public static function create(array $settings = array()) { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - $className = get_called_class(); - /** @var FormInterface $object */ - $object = $objectManager->get($className); - return $object->modify($settings); - } - - /** - * @param string $type - * @param string $prefix - * @return string - */ - protected function createComponentClassName($type, $prefix) { - $className = str_replace('/', '\\', $type); - $className = TRUE === class_exists($prefix . '\\' . $className) ? $prefix . '\\' . $className : $className; - return $className; - } - - /** - * @param string $type - * @param string $name - * @param string $label - * @return FieldInterface - */ - public function createField($type, $name, $label = NULL) { - return $this->createComponent('FluidTYPO3\Flux\Form\Field', $type, $name, $label); - } - - /** - * @param string $type - * @param string $name - * @param string $label - * @return ContainerInterface - */ - public function createContainer($type, $name, $label = NULL) { - return $this->createComponent('FluidTYPO3\Flux\Form\Container', $type, $name, $label); - } - - /** - * @param string $type - * @param string $name - * @param string $label - * @return WizardInterface - */ - public function createWizard($type, $name, $label = NULL) { - return $this->createComponent('FluidTYPO3\Flux\Form\Wizard', $type, $name, $label); - } - - /** - * @param string $namespace - * @param string $type - * @param string $name - * @param string|NULL $label - * @return FormInterface - */ - public function createComponent($namespace, $type, $name, $label = NULL) { - /** @var FormInterface $component */ - $className = $this->createComponentClassName($type, $namespace); - $component = $this->getObjectManager()->get($className); - if (NULL === $component->getName()) { - $component->setName($name); - } - $component->setLabel($label); - $component->setLocalLanguageFileRelativePath($this->getLocalLanguageFileRelativePath()); - $component->setDisableLocalLanguageLabels($this->getDisableLocalLanguageLabels()); - $component->setExtensionName($this->getExtensionName()); - return $component; - } - - /** - * @param string $name - * @return FormInterface - */ - public function setName($name) { - $this->name = $name; - return $this; - } - - /** - * @return string - */ - public function getName() { - return $this->name; - } - - /** - * @return boolean - */ - public function getEnabled() { - return (boolean) $this->enabled; - } - - /** - * @param boolean $enabled - * @return Form\FormInterface - */ - public function setEnabled($enabled) { - $this->enabled = (boolean) $enabled; - return $this; - } - - /** - * @param string $extensionName - * @return FormInterface - */ - public function setExtensionName($extensionName) { - $this->extensionName = $extensionName; - return $this; - } - - /** - * @return string - */ - public function getExtensionName() { - return $this->extensionName; - } - - /** - * @param string $label - * @return FormInterface - */ - public function setLabel($label) { - $this->label = $label; - return $this; - } - - /** - * @return string - */ - public function getPath() { - $prefix = ''; - if (TRUE === $this instanceof Sheet) { - $prefix = 'sheets'; - } elseif (TRUE === $this instanceof Section) { - $prefix = 'sections'; - } elseif (TRUE === $this instanceof Grid) { - $prefix = 'grids'; - } elseif (TRUE === $this instanceof Column) { - $prefix = 'columns'; - } elseif (TRUE === $this instanceof Object) { - $prefix = 'objects'; - } elseif (TRUE === $this instanceof Container) { - $prefix = 'containers'; - } elseif (TRUE === $this instanceof FieldInterface) { - if (TRUE === $this->isChildOfType('Object')) { - $prefix = 'objects.' . $this->getParent()->getName(); - } else { - $prefix = 'fields'; - } - } - return trim($prefix . '.' . $this->getName(), '.'); - } - - /** - * @return string - */ - public function getLabel() { - return $this->resolveLocalLanguageValueOfLabel($this->label); - } - - /** - * @param string $label - * @param string $path - * @return NULL|string - */ - protected function resolveLocalLanguageValueOfLabel($label, $path = NULL) { - if ($this->getDisableLocalLanguageLabels()) { - return $label; - } - - $name = $this->getName(); - $extensionName = $this->extensionName; - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); - if (empty($label) && !ExtensionManagementUtility::isLoaded($extensionKey)) { - return $name; - } elseif (strpos($label, 'LLL:EXT:') === 0) { - return $label; - } - - $relativeFilePath = $this->getLocalLanguageFileRelativePath(); - $relativeFilePath = ltrim($relativeFilePath, '/'); - $filePrefix = 'LLL:EXT:' . $extensionKey . '/' . $relativeFilePath; - if (strpos($label, 'LLL:') === 0) { - // Shorthand LLL:name.of.index reference, expand - list (, $labelIdentifier) = explode(':', $label, 2); - return $filePrefix . ':' . $labelIdentifier; - } elseif (!empty($label)) { - return $label; - } - if ($this instanceof Form) { - return $filePrefix . ':flux.' . $this->getName(); - } - $root = $this->getRoot(); - $id = $root->getName(); - if (empty($path)) { - $path = $this->getPath(); - } - return $filePrefix . ':' . trim('flux.' . $id . '.' . $path, '.'); - } - - /** - * @param string $localLanguageFileRelativePath - * @return FormInterface - */ - public function setLocalLanguageFileRelativePath($localLanguageFileRelativePath) { - $this->localLanguageFileRelativePath = $localLanguageFileRelativePath; - return $this; - } - - /** - * @return string - */ - public function getLocalLanguageFileRelativePath() { - return $this->localLanguageFileRelativePath; - } - - - /** - * @param boolean $disableLocalLanguageLabels - * @return FormInterface - */ - public function setDisableLocalLanguageLabels($disableLocalLanguageLabels) { - $this->disableLocalLanguageLabels = (boolean) $disableLocalLanguageLabels; - return $this; - } - - /** - * @return boolean - */ - public function getDisableLocalLanguageLabels() { - return (boolean) $this->disableLocalLanguageLabels; - } - - /** - * @param ContainerInterface $parent - * @return FormInterface - */ - public function setParent($parent) { - $this->parent = $parent; - return $this; - } - - /** - * @return ContainerInterface - */ - public function getParent() { - return $this->parent; - } - - /** - * @param array $variables - * @return FormInterface - */ - public function setVariables($variables) { - $this->variables = (array) $variables; - return $this; - } - - /** - * @return array - */ - public function getVariables() { - return $this->variables; - } - - /** - * @param string $name - * @param mixed $value - * @return FormInterface - */ - public function setVariable($name, $value) { - $this->variables = RecursiveArrayUtility::mergeRecursiveOverrule($this->variables, RecursiveArrayUtility::convertPathToArray($name, $value)); - return $this; - } - - /** - * @param string $name - * @return mixed - */ - public function getVariable($name) { - return ObjectAccess::getPropertyPath($this->variables, $name); - } - - /** - * @return ContainerInterface - */ - public function getRoot() { - $parent = $this->getParent(); - if (NULL === $parent || $this === $parent) { - return $this; - } - return $parent->getRoot(); - } - - /** - * @param string $type - * @return boolean - */ - public function isChildOfType($type) { - $parent = $this->getParent(); - if ($parent === NULL) { - return FALSE; - } - return ('FluidTYPO3\Flux\Form\Container\\' . $type === get_class($parent) || TRUE === is_a($parent, $type)); - } - - /** - * @param boolean $inherit - * @return FormInterface - */ - public function setInherit($inherit) { - $this->inherit = (boolean) $inherit; - return $this; - } - - /** - * @return integer - */ - public function getInherit() { - return (boolean) $this->inherit; - } - - /** - * @param boolean $inheritEmpty - * @return FormInterface - */ - public function setInheritEmpty($inheritEmpty) { - $this->inheritEmpty = (boolean) $inheritEmpty; - return $this; - } - - /** - * @return boolean - */ - public function getInheritEmpty() { - return (boolean) $this->inheritEmpty; - } - - /** - * Modifies the current Form Component by changing any properties - * that were passed in $structure. If a component supports special - * indices in $structure (for example a "fields" property) then - * that component may specify its own `modify()` method and manually - * process each of the specially supported keywords. - * - * For example, the AbstractFormContainer supports passing "fields" - * and each field is then attempted fetched from children. If not - * found, it is created (and the structure passed to the `create()` - * function which uses the same structure syntax). If it already - * exists, the `modify()` method is called on that object to trigger - * the recursive modification of all child components. - * - * @param array $structure - * @return FormInterface - */ - public function modify(array $structure) { - if (TRUE === isset($structure['options']) && TRUE === is_array($structure['options'])) { - foreach ($structure['options'] as $name => $value) { - $this->setVariable($name, $value); - } - unset($structure['options']); - } - foreach ($structure as $propertyName => $propertyValue) { - $setterMethodName = ObjectAccess::buildSetterMethodName($propertyName); - if (TRUE === method_exists($this, $setterMethodName)) { - ObjectAccess::setProperty($this, $propertyName, $propertyValue); - } - } - return $this; - } - - /** - * @return ObjectManagerInterface - */ - protected function getObjectManager() { - return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); - } - - /** - * @return FluxService - */ - protected function getConfigurationService() { - return $this->getObjectManager()->get('FluidTYPO3\\Flux\\Service\\FluxService'); - } - - /** - * @param \SplObjectStorage|array $children - * @return array - */ - protected function buildChildren($children) { - $structure = array(); - foreach ($children as $child) { - if (TRUE === (boolean) $child->getEnabled()) { - $name = $child->getName(); - $structure[$name] = $child->build(); - } - } - return $structure; - } - +abstract class AbstractFormComponent implements FormInterface +{ + + /** + * @var string + */ + protected $name; + + /** + * @var boolean + */ + protected $enabled = true; + + /** + * @var string + */ + protected $label = null; + + /** + * If TRUE, disables LLL label usage and always returns the + * raw value of $label. + * + * @var boolean + */ + protected $disableLocalLanguageLabels = false; + + /** + * Relative (from extension $extensionName) path to locallang + * file containing labels for the LLL values built by this class. + * + * @var string + */ + protected $localLanguageFileRelativePath = Form::DEFAULT_LANGUAGEFILE; + + /** + * @var string + */ + protected $extensionName = 'FluidTYPO3.Flux'; + + /** + * @var ContainerInterface + */ + protected $parent; + + /** + * @var array + */ + protected $variables = []; + + /** + * @var boolean + */ + protected $inherit = false; + + /** + * @var boolean + */ + protected $inheritEmpty = false; + + /** + * @param array $settings + * @return FormInterface + */ + public static function create(array $settings = []) + { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); + $className = get_called_class(); + /** @var FormInterface $object */ + $object = $objectManager->get($className); + return $object->modify($settings); + } + + /** + * @param string $type + * @param string $prefix + * @return string + */ + protected function createComponentClassName($type, $prefix) + { + $className = str_replace('/', '\\', $type); + $className = true === class_exists($prefix . '\\' . $className) ? $prefix . '\\' . $className : $className; + return $className; + } + + /** + * @param string $type + * @param string $name + * @param string $label + * @return FieldInterface + */ + public function createField($type, $name, $label = null) + { + return $this->createComponent('FluidTYPO3\Flux\Form\Field', $type, $name, $label); + } + + /** + * @param string $type + * @param string $name + * @param string $label + * @return ContainerInterface + */ + public function createContainer($type, $name, $label = null) + { + return $this->createComponent('FluidTYPO3\Flux\Form\Container', $type, $name, $label); + } + + /** + * @param string $type + * @param string $name + * @param string $label + * @return WizardInterface + */ + public function createWizard($type, $name, $label = null) + { + return $this->createComponent('FluidTYPO3\Flux\Form\Wizard', $type, $name, $label); + } + + /** + * @param string $namespace + * @param string $type + * @param string $name + * @param string|NULL $label + * @return FormInterface + */ + public function createComponent($namespace, $type, $name, $label = null) + { + /** @var FormInterface $component */ + $className = $this->createComponentClassName($type, $namespace); + $component = $this->getObjectManager()->get($className); + if (null === $component->getName()) { + $component->setName($name); + } + $component->setLabel($label); + $component->setLocalLanguageFileRelativePath($this->getLocalLanguageFileRelativePath()); + $component->setDisableLocalLanguageLabels($this->getDisableLocalLanguageLabels()); + $component->setExtensionName($this->getExtensionName()); + return $component; + } + + /** + * @param string $name + * @return FormInterface + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return boolean + */ + public function getEnabled() + { + return (boolean) $this->enabled; + } + + /** + * @param boolean $enabled + * @return Form\FormInterface + */ + public function setEnabled($enabled) + { + $this->enabled = (boolean) $enabled; + return $this; + } + + /** + * @param string $extensionName + * @return FormInterface + */ + public function setExtensionName($extensionName) + { + $this->extensionName = $extensionName; + return $this; + } + + /** + * @return string + */ + public function getExtensionName() + { + return $this->extensionName; + } + + /** + * @param string $label + * @return FormInterface + */ + public function setLabel($label) + { + $this->label = $label; + return $this; + } + + /** + * @return string + */ + public function getPath() + { + $prefix = ''; + if (true === $this instanceof Sheet) { + $prefix = 'sheets'; + } elseif (true === $this instanceof Section) { + $prefix = 'sections'; + } elseif (true === $this instanceof Grid) { + $prefix = 'grids'; + } elseif (true === $this instanceof Column) { + $prefix = 'columns'; + } elseif (true === $this instanceof Object) { + $prefix = 'objects'; + } elseif (true === $this instanceof Container) { + $prefix = 'containers'; + } elseif (true === $this instanceof FieldInterface) { + if (true === $this->isChildOfType('Object')) { + $prefix = 'objects.' . $this->getParent()->getName(); + } else { + $prefix = 'fields'; + } + } + return trim($prefix . '.' . $this->getName(), '.'); + } + + /** + * @return string + */ + public function getLabel() + { + return $this->resolveLocalLanguageValueOfLabel($this->label); + } + + /** + * @param string $label + * @param string $path + * @return NULL|string + */ + protected function resolveLocalLanguageValueOfLabel($label, $path = null) + { + if ($this->getDisableLocalLanguageLabels()) { + return $label; + } + + $name = $this->getName(); + $extensionName = $this->extensionName; + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); + if (empty($label) && !ExtensionManagementUtility::isLoaded($extensionKey)) { + return $name; + } elseif (strpos($label, 'LLL:EXT:') === 0) { + return $label; + } + + $relativeFilePath = $this->getLocalLanguageFileRelativePath(); + $relativeFilePath = ltrim($relativeFilePath, '/'); + $filePrefix = 'LLL:EXT:' . $extensionKey . '/' . $relativeFilePath; + if (strpos($label, 'LLL:') === 0) { + // Shorthand LLL:name.of.index reference, expand + list (, $labelIdentifier) = explode(':', $label, 2); + return $filePrefix . ':' . $labelIdentifier; + } elseif (!empty($label)) { + return $label; + } + if ($this instanceof Form) { + return $filePrefix . ':flux.' . $this->getName(); + } + $root = $this->getRoot(); + $id = $root->getName(); + if (empty($path)) { + $path = $this->getPath(); + } + return $filePrefix . ':' . trim('flux.' . $id . '.' . $path, '.'); + } + + /** + * @param string $localLanguageFileRelativePath + * @return FormInterface + */ + public function setLocalLanguageFileRelativePath($localLanguageFileRelativePath) + { + $this->localLanguageFileRelativePath = $localLanguageFileRelativePath; + return $this; + } + + /** + * @return string + */ + public function getLocalLanguageFileRelativePath() + { + return $this->localLanguageFileRelativePath; + } + + + /** + * @param boolean $disableLocalLanguageLabels + * @return FormInterface + */ + public function setDisableLocalLanguageLabels($disableLocalLanguageLabels) + { + $this->disableLocalLanguageLabels = (boolean) $disableLocalLanguageLabels; + return $this; + } + + /** + * @return boolean + */ + public function getDisableLocalLanguageLabels() + { + return (boolean) $this->disableLocalLanguageLabels; + } + + /** + * @param ContainerInterface $parent + * @return FormInterface + */ + public function setParent($parent) + { + $this->parent = $parent; + return $this; + } + + /** + * @return ContainerInterface + */ + public function getParent() + { + return $this->parent; + } + + /** + * @param array $variables + * @return FormInterface + */ + public function setVariables($variables) + { + $this->variables = (array) $variables; + return $this; + } + + /** + * @return array + */ + public function getVariables() + { + return $this->variables; + } + + /** + * @param string $name + * @param mixed $value + * @return FormInterface + */ + public function setVariable($name, $value) + { + $this->variables = RecursiveArrayUtility::mergeRecursiveOverrule( + $this->variables, + RecursiveArrayUtility::convertPathToArray($name, $value) + ); + return $this; + } + + /** + * @param string $name + * @return mixed + */ + public function getVariable($name) + { + return ObjectAccess::getPropertyPath($this->variables, $name); + } + + /** + * @return ContainerInterface + */ + public function getRoot() + { + $parent = $this->getParent(); + if (null === $parent || $this === $parent) { + return $this; + } + return $parent->getRoot(); + } + + /** + * @param string $type + * @return boolean + */ + public function isChildOfType($type) + { + $parent = $this->getParent(); + if ($parent === null) { + return false; + } + return ('FluidTYPO3\Flux\Form\Container\\' . $type === get_class($parent) || true === is_a($parent, $type)); + } + + /** + * @param boolean $inherit + * @return FormInterface + */ + public function setInherit($inherit) + { + $this->inherit = (boolean) $inherit; + return $this; + } + + /** + * @return integer + */ + public function getInherit() + { + return (boolean) $this->inherit; + } + + /** + * @param boolean $inheritEmpty + * @return FormInterface + */ + public function setInheritEmpty($inheritEmpty) + { + $this->inheritEmpty = (boolean) $inheritEmpty; + return $this; + } + + /** + * @return boolean + */ + public function getInheritEmpty() + { + return (boolean) $this->inheritEmpty; + } + + /** + * Modifies the current Form Component by changing any properties + * that were passed in $structure. If a component supports special + * indices in $structure (for example a "fields" property) then + * that component may specify its own `modify()` method and manually + * process each of the specially supported keywords. + * + * For example, the AbstractFormContainer supports passing "fields" + * and each field is then attempted fetched from children. If not + * found, it is created (and the structure passed to the `create()` + * function which uses the same structure syntax). If it already + * exists, the `modify()` method is called on that object to trigger + * the recursive modification of all child components. + * + * @param array $structure + * @return FormInterface + */ + public function modify(array $structure) + { + if (true === isset($structure['options']) && true === is_array($structure['options'])) { + foreach ($structure['options'] as $name => $value) { + $this->setVariable($name, $value); + } + unset($structure['options']); + } + foreach ($structure as $propertyName => $propertyValue) { + $setterMethodName = ObjectAccess::buildSetterMethodName($propertyName); + if (true === method_exists($this, $setterMethodName)) { + ObjectAccess::setProperty($this, $propertyName, $propertyValue); + } + } + return $this; + } + + /** + * @return ObjectManagerInterface + */ + protected function getObjectManager() + { + return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager'); + } + + /** + * @return FluxService + */ + protected function getConfigurationService() + { + return $this->getObjectManager()->get('FluidTYPO3\\Flux\\Service\\FluxService'); + } + + /** + * @param \SplObjectStorage|array $children + * @return array + */ + protected function buildChildren($children) + { + $structure = []; + foreach ($children as $child) { + if (true === (boolean) $child->getEnabled()) { + $name = $child->getName(); + $structure[$name] = $child->build(); + } + } + return $structure; + } } diff --git a/Classes/Form/AbstractFormContainer.php b/Classes/Form/AbstractFormContainer.php index 1ab61e48b..6d1522237 100644 --- a/Classes/Form/AbstractFormContainer.php +++ b/Classes/Form/AbstractFormContainer.php @@ -11,170 +11,184 @@ /** * AbstractFormContainer */ -abstract class AbstractFormContainer extends AbstractFormComponent implements ContainerInterface { - - /** - * @var \SplObjectStorage - */ - protected $children; - - /** - * @var string - */ - protected $transform; - - /** - * @var boolean - */ - protected $inherit = TRUE; - - /** - * @var boolean - */ - protected $inheritEmpty = FALSE; - - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->children = new \SplObjectStorage(); - } - - /** - * @param string $namespace - * @param string $type - * @param string $name - * @param null $label - * @return FormInterface - */ - public function createComponent($namespace, $type, $name, $label = NULL) { - $component = parent::createComponent($namespace, $type, $name, $label); - $this->add($component); - return $component; - } - - /** - * @param FormInterface $child - * @return FormInterface - */ - public function add(FormInterface $child) { - if (FALSE === $this->children->contains($child)) { - $this->children->attach($child); - $child->setParent($this); - } - return $this; - } - - /** - * @param array|\Traversable $children - * @return FormInterface - */ - public function addAll($children) { - foreach ($children as $child) { - $this->add($child); - } - return $this; - } - - /** - * @param FieldInterface|string $childName - * @return FormInterface|FALSE - */ - public function remove($childName) { - foreach ($this->children as $child) { - /** @var FieldInterface $child */ - $isMatchingInstance = (TRUE === $childName instanceof FormInterface && $childName->getName() === $child->getName()); - $isMatchingName = ($childName === $child->getName()); - if (TRUE === $isMatchingName || TRUE === $isMatchingInstance) { - $this->children->detach($child); - $this->children->rewind(); - $child->setParent(NULL); - return $child; - } - } - return FALSE; - } - - /** - * @param mixed $childOrChildName - * @return boolean - */ - public function has($childOrChildName) { - $name = (TRUE === $childOrChildName instanceof FormInterface) ? $childOrChildName->getName() : $childOrChildName; - return (FALSE !== $this->get($name)); - } - - /** - * @param string $childName - * @param boolean $recursive - * @param string $requiredClass - * @return FormInterface|FALSE - */ - public function get($childName, $recursive = FALSE, $requiredClass = NULL) { - foreach ($this->children as $existingChild) { - if ($childName === $existingChild->getName() && ($requiredClass === NULL || TRUE === $existingChild instanceof $requiredClass)) { - return $existingChild; - } - if (TRUE === $recursive && TRUE === $existingChild instanceof ContainerInterface) { - $candidate = $existingChild->get($childName, $recursive); - if (FALSE !== $candidate) { - return $candidate; - } - } - } - return FALSE; - } - - /** - * @return FormInterface|FALSE - */ - public function last() { - $result = array_pop(iterator_to_array($this->children)); - return $result; - } - - /** - * @return boolean - */ - public function hasChildren() { - return 0 < $this->children->count(); - } - - /** - * @param string $transform - * @return ContainerInterface - */ - public function setTransform($transform) { - $this->transform = $transform; - return $this; - } - - /** - * @return string - */ - public function getTransform() { - return $this->transform; - } - - /** - * @param array $structure - * @return ContainerInterface - */ - public function modify(array $structure) { - if (TRUE === isset($structure['fields'])) { - foreach ((array) $structure['fields'] as $index => $fieldData) { - $fieldName = TRUE === isset($fieldData['name']) ? $fieldData['name'] : $index; - // check if field already exists - if it does, modify it. If it does not, create it. - if (TRUE === $this->has($fieldName)) { - $field = $this->get($fieldName); - } else { - $fieldType = TRUE === isset($fieldData['type']) ? $fieldData['type'] : 'None'; - $field = $this->createField($fieldType, $fieldName); - } - $field->modify($fieldData); - } - } - return parent::modify($structure); - } - +abstract class AbstractFormContainer extends AbstractFormComponent implements ContainerInterface +{ + + /** + * @var \SplObjectStorage + */ + protected $children; + + /** + * @var string + */ + protected $transform; + + /** + * @var boolean + */ + protected $inherit = true; + + /** + * @var boolean + */ + protected $inheritEmpty = false; + + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->children = new \SplObjectStorage(); + } + + /** + * @param string $namespace + * @param string $type + * @param string $name + * @param null $label + * @return FormInterface + */ + public function createComponent($namespace, $type, $name, $label = null) + { + $component = parent::createComponent($namespace, $type, $name, $label); + $this->add($component); + return $component; + } + + /** + * @param FormInterface $child + * @return FormInterface + */ + public function add(FormInterface $child) + { + if (false === $this->children->contains($child)) { + $this->children->attach($child); + $child->setParent($this); + } + return $this; + } + + /** + * @param array|\Traversable $children + * @return FormInterface + */ + public function addAll($children) + { + foreach ($children as $child) { + $this->add($child); + } + return $this; + } + + /** + * @param FieldInterface|string $childName + * @return FormInterface|FALSE + */ + public function remove($childName) + { + foreach ($this->children as $child) { + /** @var FieldInterface $child */ + $isMatchingInstance = ($childName instanceof FormInterface && $childName->getName() === $child->getName()); + $isMatchingName = ($childName === $child->getName()); + if (true === $isMatchingName || true === $isMatchingInstance) { + $this->children->detach($child); + $this->children->rewind(); + $child->setParent(null); + return $child; + } + } + return false; + } + + /** + * @param mixed $childOrChildName + * @return boolean + */ + public function has($childOrChildName) + { + $name = ($childOrChildName instanceof FormInterface) ? $childOrChildName->getName() : $childOrChildName; + return (false !== $this->get($name)); + } + + /** + * @param string $childName + * @param boolean $recursive + * @param string $requiredClass + * @return FormInterface|FALSE + */ + public function get($childName, $recursive = false, $requiredClass = null) + { + foreach ($this->children as $existingChild) { + if ($childName === $existingChild->getName() + && (!$requiredClass || $existingChild instanceof $requiredClass) + ) { + return $existingChild; + } + if (true === $recursive && true === $existingChild instanceof ContainerInterface) { + $candidate = $existingChild->get($childName, $recursive); + if (false !== $candidate) { + return $candidate; + } + } + } + return false; + } + + /** + * @return FormInterface|FALSE + */ + public function last() + { + $result = array_pop(iterator_to_array($this->children)); + return $result; + } + + /** + * @return boolean + */ + public function hasChildren() + { + return 0 < $this->children->count(); + } + + /** + * @param string $transform + * @return ContainerInterface + */ + public function setTransform($transform) + { + $this->transform = $transform; + return $this; + } + + /** + * @return string + */ + public function getTransform() + { + return $this->transform; + } + + /** + * @param array $structure + * @return ContainerInterface + */ + public function modify(array $structure) + { + if (true === isset($structure['fields'])) { + foreach ((array) $structure['fields'] as $index => $fieldData) { + $fieldName = true === isset($fieldData['name']) ? $fieldData['name'] : $index; + // check if field already exists - if it does, modify it. If it does not, create it. + if (true === $this->has($fieldName)) { + $field = $this->get($fieldName); + } else { + $fieldType = true === isset($fieldData['type']) ? $fieldData['type'] : 'None'; + $field = $this->createField($fieldType, $fieldName); + } + $field->modify($fieldData); + } + } + return parent::modify($structure); + } } diff --git a/Classes/Form/AbstractFormField.php b/Classes/Form/AbstractFormField.php index da6eacd75..03694190a 100644 --- a/Classes/Form/AbstractFormField.php +++ b/Classes/Form/AbstractFormField.php @@ -15,407 +15,443 @@ /** * AbstractFormField */ -abstract class AbstractFormField extends AbstractFormComponent implements FieldInterface { - - /** - * @var boolean - */ - protected $required = FALSE; - - /** - * @var mixed - */ - protected $default; - - /** - * @var string - */ - protected $transform; - - /** - * Display condition - see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Index.html#displaycond - * - * @var string - */ - protected $displayCondition = NULL; - - /** - * @var boolean - */ - protected $requestUpdate = FALSE; - - /** - * @var boolean - */ - protected $inherit = TRUE; - - /** - * @var boolean - */ - protected $inheritEmpty = FALSE; - - /** - * @var boolean - */ - protected $clearable = FALSE; - - /** - * @var boolean - */ - protected $exclude = TRUE; - - /** - * @var boolean - */ - protected $enable = TRUE; - - /** - * @var string - */ - protected $validate; - - /** - * @var \SplObjectStorage - */ - protected $wizards; - - /** - * CONSTRUCTOR - */ - public function __construct() { - $this->wizards = new \SplObjectStorage(); - } - - /** - * @param array $settings - * @return FieldInterface - * @throws \RuntimeException - */ - public static function create(array $settings = array()) { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - if ('Section' === $settings['type']) { - return Section::create($settings); - } else { - $prefix = 'FluidTYPO3\Flux\Form\Field\\'; - $type = $settings['type']; - $className = str_replace('/', '\\', $type); - $className = TRUE === class_exists($prefix . $className) ? $prefix . $className : $className; - } - if (FALSE === class_exists($className)) { - $className = $settings['type']; - } - if (FALSE === class_exists($className)) { - throw new \RuntimeException('Invalid class- or type-name used in type of field "' . $settings['name'] . '"; "' . $className . '" is invalid', 1375373527); - } - /** @var FormInterface $object */ - $object = $objectManager->get($className); - foreach ($settings as $settingName => $settingValue) { - $setterMethodName = 'set' . ucfirst($settingName); - if (TRUE === method_exists($object, $setterMethodName)) { - call_user_func_array(array($object, $setterMethodName), array($settingValue)); - } - } - return $object; - } - - /** - * @param string $type - * @param string $name - * @param string $label - * @return WizardInterface - */ - public function createWizard($type, $name, $label = NULL) { - $wizard = parent::createWizard($type, $name, $label); - $this->add($wizard); - return $wizard; - } - - /** - * @param WizardInterface $wizard - * @return FieldInterface - */ - public function add(WizardInterface $wizard) { - if (FALSE === $this->wizards->contains($wizard)) { - $this->wizards->attach($wizard); - $wizard->setParent($this); - } - return $this; - } - - /** - * @param string $wizardName - * @return WizardInterface|FALSE - */ - public function get($wizardName) { - foreach ($this->wizards as $wizard) { - if ($wizardName === $wizard->getName()) { - return $wizard; - } - } - return FALSE; - } - - /** - * @param mixed $childOrChildName - * @return boolean - */ - public function has($childOrChildName) { - $name = (TRUE === $childOrChildName instanceof FormInterface) ? $childOrChildName->getName() : $childOrChildName; - return (FALSE !== $this->get($name)); - } - - /** - * @param string $wizardName - * @return WizardInterface|FALSE - */ - public function remove($wizardName) { - foreach ($this->wizards as $wizard) { - if ($wizardName === $wizard->getName()) { - $this->wizards->detach($wizard); - $this->wizards->rewind(); - $wizard->setParent(NULL); - return $wizard; - } - } - return FALSE; - } - - /** - * Creates a TCEforms configuration array based on the - * configuration stored in this ViewHelper. Calls the - * expected-to-be-overridden stub method getConfiguration() - * to return the TCE field configuration - see that method - * for information about how to implement that method. - * - * @return array - */ - public function build() { - if (FALSE === $this->getEnable()) { - return array(); - } - $configuration = $this->buildConfiguration(); - $fieldStructureArray = array( - 'label' => $this->getLabel(), - 'exclude' => intval($this->getExclude()), - 'config' => $configuration, - 'displayCond' => $this->getDisplayCondition() - ); - if (TRUE === isset($configuration['defaultExtras'])) { - $fieldStructureArray['defaultExtras'] = $configuration['defaultExtras']; - unset($fieldStructureArray['config']['defaultExtras']); - } - $wizards = $this->buildChildren($this->wizards); - if (TRUE === $this->getClearable()) { - array_push($wizards, array( - 'type' => 'userFunc', - 'userFunc' => 'FluidTYPO3\Flux\UserFunction\ClearValueWizard->renderField', - 'params' => array( - 'itemName' => $this->getName(), - ), - )); - } - $fieldStructureArray['config']['wizards'] = $wizards; - if (TRUE === $this->getRequestUpdate()) { - $fieldStructureArray['onChange'] = 'reload'; - } - return $fieldStructureArray; - } - - /** - * @param string $type - * @return array - */ - protected function prepareConfiguration($type) { - $fieldConfiguration = array( - 'type' => $type, - 'transform' => $this->getTransform(), - 'default' => $this->getDefault(), - ); - return $fieldConfiguration; - } - - /** - * @param boolean $required - * @return FieldInterface - */ - public function setRequired($required) { - $this->required = (boolean) $required; - return $this; - } - - /** - * @return boolean - */ - public function getRequired() { - return (boolean) $this->required; - } - - /** - * @param mixed $default - * @return FieldInterface - */ - public function setDefault($default) { - $this->default = $default; - return $this; - } - - /** - * @return mixed - */ - public function getDefault() { - return $this->default; - } - - /** - * @param string $transform - * @return FieldInterface - */ - public function setTransform($transform) { - $this->transform = $transform; - return $this; - } - - /** - * @return string - */ - public function getTransform() { - return $this->transform; - } - - /** - * @param string $displayCondition - * @return FieldInterface - */ - public function setDisplayCondition($displayCondition) { - $this->displayCondition = $displayCondition; - return $this; - } - - /** - * @return string - */ - public function getDisplayCondition() { - return $this->displayCondition; - } - - /** - * @param boolean $requestUpdate - * @return FieldInterface - */ - public function setRequestUpdate($requestUpdate) { - $this->requestUpdate = (boolean) $requestUpdate; - return $this; - } - - /** - * @return boolean - */ - public function getRequestUpdate() { - return (boolean) $this->requestUpdate; - } - - /** - * @param boolean $exclude - * @return FieldInterface - */ - public function setExclude($exclude) { - $this->exclude = (boolean) $exclude; - return $this; - } - - /** - * @return boolean - */ - public function getExclude() { - return (boolean) $this->exclude; - } - - /** - * @param boolean $enable - * @return FieldInterface - */ - public function setEnable($enable) { - $this->enable = (boolean) $enable; - return $this; - } - - /** - * @return boolean - */ - public function getEnable() { - return (boolean) $this->enable; - } - - /** - * @param string $validate - * @return FieldInterface - */ - public function setValidate($validate) { - $this->validate = $validate; - return $this; - } - - /** - * @return string - */ - public function getValidate() { - if (FALSE === (boolean) $this->getRequired()) { - $validate = $this->validate; - } else { - if (TRUE === empty($this->validate)) { - $validate = 'required'; - } else { - $validators = GeneralUtility::trimExplode(',', $this->validate); - array_push($validators, 'required'); - $validate = implode(',', $validators); - } - } - return $validate; - } - - /** - * @param boolean $clearable - * @return FieldInterface - */ - public function setClearable($clearable) { - $this->clearable = (boolean) $clearable; - return $this; - } - - /** - * @return boolean - */ - public function getClearable() { - return (boolean) $this->clearable; - } - - /** - * @return boolean - */ - public function hasChildren() { - return 0 < $this->wizards->count(); - } - - /** - * @param array $structure - * @return ContainerInterface - */ - public function modify(array $structure) { - if (TRUE === isset($structure['wizards'])) { - foreach ((array) $structure['wizards'] as $index => $wizardData) { - $wizardName = TRUE === isset($wizardData['name']) ? $wizardData['name'] : $index; - // check if field already exists - if it does, modify it. If it does not, create it. - if (TRUE === $this->has($wizardName)) { - $field = $this->get($wizardName); - } else { - $wizardType = TRUE === isset($wizardData['type']) ? $wizardData['type'] : 'None'; - $field = $this->createWizard($wizardType, $wizardName); - } - $field->modify($wizardData); - } - } - return parent::modify($structure); - } - +abstract class AbstractFormField extends AbstractFormComponent implements FieldInterface +{ + + /** + * @var boolean + */ + protected $required = false; + + /** + * @var mixed + */ + protected $default; + + /** + * @var string + */ + protected $transform; + + /** + * Display condition - see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Index.html#displaycond + * + * @var string + */ + protected $displayCondition = null; + + /** + * @var boolean + */ + protected $requestUpdate = false; + + /** + * @var boolean + */ + protected $inherit = true; + + /** + * @var boolean + */ + protected $inheritEmpty = false; + + /** + * @var boolean + */ + protected $clearable = false; + + /** + * @var boolean + */ + protected $exclude = true; + + /** + * @var boolean + */ + protected $enable = true; + + /** + * @var string + */ + protected $validate; + + /** + * @var \SplObjectStorage + */ + protected $wizards; + + /** + * CONSTRUCTOR + */ + public function __construct() + { + $this->wizards = new \SplObjectStorage(); + } + + /** + * @param array $settings + * @return FieldInterface + * @throws \RuntimeException + */ + public static function create(array $settings = []) + { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); + if ('Section' === $settings['type']) { + return Section::create($settings); + } else { + $prefix = 'FluidTYPO3\Flux\Form\Field\\'; + $type = $settings['type']; + $className = str_replace('/', '\\', $type); + $className = true === class_exists($prefix . $className) ? $prefix . $className : $className; + } + if (false === class_exists($className)) { + $className = $settings['type']; + } + if (false === class_exists($className)) { + throw new \RuntimeException( + sprintf( + 'Invalid class- or type-name used in type of field "%s"; "%s" is invalid', + $settings['name'], + $className + ), + 1375373527 + ); + } + /** @var FormInterface $object */ + $object = $objectManager->get($className); + foreach ($settings as $settingName => $settingValue) { + $setterMethodName = 'set' . ucfirst($settingName); + if (true === method_exists($object, $setterMethodName)) { + call_user_func_array([$object, $setterMethodName], [$settingValue]); + } + } + return $object; + } + + /** + * @param string $type + * @param string $name + * @param string $label + * @return WizardInterface + */ + public function createWizard($type, $name, $label = null) + { + $wizard = parent::createWizard($type, $name, $label); + $this->add($wizard); + return $wizard; + } + + /** + * @param WizardInterface $wizard + * @return FieldInterface + */ + public function add(WizardInterface $wizard) + { + if (false === $this->wizards->contains($wizard)) { + $this->wizards->attach($wizard); + $wizard->setParent($this); + } + return $this; + } + + /** + * @param string $wizardName + * @return WizardInterface|FALSE + */ + public function get($wizardName) + { + foreach ($this->wizards as $wizard) { + if ($wizardName === $wizard->getName()) { + return $wizard; + } + } + return false; + } + + /** + * @param mixed $childOrChildName + * @return boolean + */ + public function has($childOrChildName) + { + $name = ($childOrChildName instanceof FormInterface) ? $childOrChildName->getName() : $childOrChildName; + return (false !== $this->get($name)); + } + + /** + * @param string $wizardName + * @return WizardInterface|FALSE + */ + public function remove($wizardName) + { + foreach ($this->wizards as $wizard) { + if ($wizardName === $wizard->getName()) { + $this->wizards->detach($wizard); + $this->wizards->rewind(); + $wizard->setParent(null); + return $wizard; + } + } + return false; + } + + /** + * Creates a TCEforms configuration array based on the + * configuration stored in this ViewHelper. Calls the + * expected-to-be-overridden stub method getConfiguration() + * to return the TCE field configuration - see that method + * for information about how to implement that method. + * + * @return array + */ + public function build() + { + if (false === $this->getEnable()) { + return []; + } + $configuration = $this->buildConfiguration(); + $fieldStructureArray = [ + 'label' => $this->getLabel(), + 'exclude' => intval($this->getExclude()), + 'config' => $configuration, + 'displayCond' => $this->getDisplayCondition() + ]; + if (true === isset($configuration['defaultExtras'])) { + $fieldStructureArray['defaultExtras'] = $configuration['defaultExtras']; + unset($fieldStructureArray['config']['defaultExtras']); + } + $wizards = $this->buildChildren($this->wizards); + if (true === $this->getClearable()) { + array_push($wizards, [ + 'type' => 'userFunc', + 'userFunc' => 'FluidTYPO3\Flux\UserFunction\ClearValueWizard->renderField', + 'params' => [ + 'itemName' => $this->getName(), + ], + ]); + } + $fieldStructureArray['config']['wizards'] = $wizards; + if (true === $this->getRequestUpdate()) { + $fieldStructureArray['onChange'] = 'reload'; + } + return $fieldStructureArray; + } + + /** + * @param string $type + * @return array + */ + protected function prepareConfiguration($type) + { + $fieldConfiguration = [ + 'type' => $type, + 'transform' => $this->getTransform(), + 'default' => $this->getDefault(), + ]; + return $fieldConfiguration; + } + + /** + * @param boolean $required + * @return FieldInterface + */ + public function setRequired($required) + { + $this->required = (boolean) $required; + return $this; + } + + /** + * @return boolean + */ + public function getRequired() + { + return (boolean) $this->required; + } + + /** + * @param mixed $default + * @return FieldInterface + */ + public function setDefault($default) + { + $this->default = $default; + return $this; + } + + /** + * @return mixed + */ + public function getDefault() + { + return $this->default; + } + + /** + * @param string $transform + * @return FieldInterface + */ + public function setTransform($transform) + { + $this->transform = $transform; + return $this; + } + + /** + * @return string + */ + public function getTransform() + { + return $this->transform; + } + + /** + * @param string $displayCondition + * @return FieldInterface + */ + public function setDisplayCondition($displayCondition) + { + $this->displayCondition = $displayCondition; + return $this; + } + + /** + * @return string + */ + public function getDisplayCondition() + { + return $this->displayCondition; + } + + /** + * @param boolean $requestUpdate + * @return FieldInterface + */ + public function setRequestUpdate($requestUpdate) + { + $this->requestUpdate = (boolean) $requestUpdate; + return $this; + } + + /** + * @return boolean + */ + public function getRequestUpdate() + { + return (boolean) $this->requestUpdate; + } + + /** + * @param boolean $exclude + * @return FieldInterface + */ + public function setExclude($exclude) + { + $this->exclude = (boolean) $exclude; + return $this; + } + + /** + * @return boolean + */ + public function getExclude() + { + return (boolean) $this->exclude; + } + + /** + * @param boolean $enable + * @return FieldInterface + */ + public function setEnable($enable) + { + $this->enable = (boolean) $enable; + return $this; + } + + /** + * @return boolean + */ + public function getEnable() + { + return (boolean) $this->enable; + } + + /** + * @param string $validate + * @return FieldInterface + */ + public function setValidate($validate) + { + $this->validate = $validate; + return $this; + } + + /** + * @return string + */ + public function getValidate() + { + if (false === (boolean) $this->getRequired()) { + $validate = $this->validate; + } else { + if (true === empty($this->validate)) { + $validate = 'required'; + } else { + $validators = GeneralUtility::trimExplode(',', $this->validate); + array_push($validators, 'required'); + $validate = implode(',', $validators); + } + } + return $validate; + } + + /** + * @param boolean $clearable + * @return FieldInterface + */ + public function setClearable($clearable) + { + $this->clearable = (boolean) $clearable; + return $this; + } + + /** + * @return boolean + */ + public function getClearable() + { + return (boolean) $this->clearable; + } + + /** + * @return boolean + */ + public function hasChildren() + { + return 0 < $this->wizards->count(); + } + + /** + * @param array $structure + * @return ContainerInterface + */ + public function modify(array $structure) + { + if (true === isset($structure['wizards'])) { + foreach ((array) $structure['wizards'] as $index => $wizardData) { + $wizardName = true === isset($wizardData['name']) ? $wizardData['name'] : $index; + // check if field already exists - if it does, modify it. If it does not, create it. + if (true === $this->has($wizardName)) { + $field = $this->get($wizardName); + } else { + $wizardType = true === isset($wizardData['type']) ? $wizardData['type'] : 'None'; + $field = $this->createWizard($wizardType, $wizardName); + } + $field->modify($wizardData); + } + } + return parent::modify($structure); + } } diff --git a/Classes/Form/AbstractInlineFormField.php b/Classes/Form/AbstractInlineFormField.php index 20c96d7d0..14f379720 100644 --- a/Classes/Form/AbstractInlineFormField.php +++ b/Classes/Form/AbstractInlineFormField.php @@ -14,415 +14,448 @@ /** * AbstractInlineFormField */ -abstract class AbstractInlineFormField extends AbstractRelationFormField implements InlineRelationFieldInterface { - - /** - * If true, all child records are shown as collapsed. - * - * @var boolean - */ - protected $collapseAll = FALSE; - - /** - * Show only one expanded record at any time. If a new record is expanded, - * all others are collapsed. - * - * @var boolean - */ - protected $expandSingle = FALSE; - - /** - * Add the foreign table's title to the 'Add new' link (ie. 'Add new (sometable)') - * - * @var boolean - */ - protected $newRecordLinkAddTitle = FALSE; - - /** - * Record link position - can be either \FluidTYPO3\Flux\Form::POSITION_TOP, - * \FluidTYPO3\Flux\Form::POSITION_BOTTOM, \FluidTYPO3\Flux\Form::POSITION_BOTH or - * \FluidTYPO3\Flux\Form::POSITION_NONE. - * - * @var string - */ - protected $newRecordLinkPosition = Form::POSITION_TOP; - - /** - * For use on bidirectional relations using an intermediary table. - * In combinations, it's possible to edit attributes and the related child record. - * - * @var boolean - */ - protected $useCombination = FALSE; - - /** - * Allow manual sorting of child objects. - * - * @var boolean - */ - protected $useSortable = FALSE; - - /** - * Show unlocalized records which are in the original language, but not yet localized. - * - * @var boolean - */ - protected $showPossibleLocalizationRecords = FALSE; - - /** - * Show records which were once localized but do not exist in the original - * language anymore. - * - * @var boolean - */ - protected $showRemovedLocalizationRecords = FALSE; - - /** - * Defines whether to show the 'localize all records' link to fetch untranslated - * records from the original language. - * - * @var boolean - */ - protected $showAllLocalizationLink = FALSE; - - /** - * Defines whether to show a 'synchronize' link to update to a 1:1 translation with - * the original language. - * - * @var boolean - */ - protected $showSynchronizationLink = FALSE; - - /** - * Associative array with the keys 'info', 'new', 'dragdrop', 'sort', 'hide', delete' - * and 'localize'. Set either one to TRUE or FALSE to show or hide it. - * - * @var array - */ - protected $enabledControls = array( - Form::CONTROL_INFO => FALSE, - Form::CONTROL_NEW => TRUE, - Form::CONTROL_DRAGDROP => TRUE, - Form::CONTROL_SORT => TRUE, - Form::CONTROL_HIDE => TRUE, - Form::CONTROL_DELETE => FALSE, - Form::CONTROL_LOCALISE => FALSE, - ); - - /** - * Array of field=>value pairs which are always used in conditions as well as inserted into new - * records created through this form component. - * - * @var array - */ - protected $foreignMatchFields = array(); - - /** - * @var array - */ - protected $headerThumbnail = NULL; - - /** - * @var string - */ - protected $levelLinksPosition = NULL; - - /** - * @var string - */ - protected $foreignSelectorFieldTcaOverride; - - /** - * @var array - */ - protected $foreignTypes = NULL; - - /** - * @param string $type - * @return array - */ - public function prepareConfiguration($type) { - $configuration = parent::prepareConfiguration($type); - $configuration['foreign_match_fields'] = $this->getForeignMatchFields(); - $configuration['foreign_selector_fieldTcaOverride'] = $this->getForeignSelectorFieldTcaOverride(); - $configuration['foreign_types'] = $this->getForeignTypes(); - $configuration['appearance'] = array( - 'collapseAll' => $this->getCollapseAll(), - 'expandSingle' => $this->getExpandSingle(), - 'newRecordLinkAddTitle' => $this->getNewRecordLinkAddTitle(), - 'newRecordLinkPosition' => $this->getNewRecordLinkPosition(), - 'useCombination' => $this->getUseCombination(), - 'useSortable' => $this->getUseSortable(), - 'showPossibleLocalizationRecords' => $this->getShowPossibleLocalizationRecords(), - 'showRemovedLocalizationRecords' => $this->getShowRemovedLocalizationRecords(), - 'showAllLocalizationLink' => $this->getShowAllLocalizationLink(), - 'showSynchronizationLink' => $this->getShowSynchronizationLink(), - 'enabledControls' => $this->getEnabledControls(), - 'headerThumbnail' => $this->getHeaderThumbnail(), - 'levelLinksPosition' => $this->getLevelLinksPosition(), - ); - $configuration['behaviour'] = array( - 'localizationMode' => $this->getLocalizationMode(), - 'localizeChildrenAtParentLocalization' => $this->getLocalizeChildrenAtParentLocalization(), - 'disableMovingChildrenWithParent' => $this->getDisableMovingChildrenWithParent(), - ); - return $configuration; - } - - /** - * @param boolean $collapseAll - * @return AbstractInlineFormField - */ - public function setCollapseAll($collapseAll) { - $this->collapseAll = $collapseAll; - return $this; - } - - /** - * @return boolean - */ - public function getCollapseAll() { - return $this->collapseAll; - } - - /** - * @param array $enabledControls - * @return AbstractInlineFormField - */ - public function setEnabledControls(array $enabledControls) { - $this->enabledControls = $enabledControls; - return $this; - } - - /** - * @return array - */ - public function getEnabledControls() { - return $this->enabledControls; - } - - /** - * @param boolean $expandSingle - * @return AbstractInlineFormField - */ - public function setExpandSingle($expandSingle) { - $this->expandSingle = $expandSingle; - return $this; - } - - /** - * @return boolean - */ - public function getExpandSingle() { - return $this->expandSingle; - } - - /** - * @param boolean $newRecordLinkAddTitle - * @return AbstractInlineFormField - */ - public function setNewRecordLinkAddTitle($newRecordLinkAddTitle) { - $this->newRecordLinkAddTitle = $newRecordLinkAddTitle; - return $this; - } - - /** - * @return boolean - */ - public function getNewRecordLinkAddTitle() { - return $this->newRecordLinkAddTitle; - } - - /** - * @param string $newRecordLinkPosition - * @return AbstractInlineFormField - */ - public function setNewRecordLinkPosition($newRecordLinkPosition) { - $this->newRecordLinkPosition = $newRecordLinkPosition; - return $this; - } - - /** - * @return string - */ - public function getNewRecordLinkPosition() { - return $this->newRecordLinkPosition; - } - - /** - * @param boolean $showAllLocalizationLink - * @return AbstractInlineFormField - */ - public function setShowAllLocalizationLink($showAllLocalizationLink) { - $this->showAllLocalizationLink = $showAllLocalizationLink; - return $this; - } - - /** - * @return boolean - */ - public function getShowAllLocalizationLink() { - return $this->showAllLocalizationLink; - } - - /** - * @param boolean $showPossibleLocalizationRecords - * @return AbstractInlineFormField - */ - public function setShowPossibleLocalizationRecords($showPossibleLocalizationRecords) { - $this->showPossibleLocalizationRecords = $showPossibleLocalizationRecords; - return $this; - } - - /** - * @return boolean - */ - public function getShowPossibleLocalizationRecords() { - return $this->showPossibleLocalizationRecords; - } - - /** - * @param boolean $showRemovedLocalizationRecords - * @return AbstractInlineFormField - */ - public function setShowRemovedLocalizationRecords($showRemovedLocalizationRecords) { - $this->showRemovedLocalizationRecords = $showRemovedLocalizationRecords; - return $this; - } - - /** - * @return boolean - */ - public function getShowRemovedLocalizationRecords() { - return $this->showRemovedLocalizationRecords; - } - - /** - * @param boolean $showSynchronizationLink - * @return AbstractInlineFormField - */ - public function setShowSynchronizationLink($showSynchronizationLink) { - $this->showSynchronizationLink = $showSynchronizationLink; - return $this; - } - - /** - * @return boolean - */ - public function getShowSynchronizationLink() { - return $this->showSynchronizationLink; - } - - /** - * @param boolean $useCombination - * @return AbstractInlineFormField - */ - public function setUseCombination($useCombination) { - $this->useCombination = $useCombination; - return $this; - } - - /** - * @return boolean - */ - public function getUseCombination() { - return $this->useCombination; - } - - /** - * @param boolean $useSortable - * @return AbstractInlineFormField - */ - public function setUseSortable($useSortable) { - $this->useSortable = $useSortable; - return $this; - } - - /** - * @return boolean - */ - public function getUseSortable() { - return $this->useSortable; - } - - /** - * @param array $foreignMatchFields - * @return Inline - */ - public function setForeignMatchFields(array $foreignMatchFields) { - $this->foreignMatchFields = $foreignMatchFields; - return $this; - } - - /** - * @return array - */ - public function getForeignMatchFields() { - return $this->foreignMatchFields; - } - - /** - * @param array $headerThumbnail - * @return AbstractInlineFormField - */ - public function setHeaderThumbnail(array $headerThumbnail) { - $this->headerThumbnail = $headerThumbnail; - return $this; - } - - /** - * @return array - */ - public function getHeaderThumbnail() { - return $this->headerThumbnail; - } - - /** - * @param string $levelLinksPosition - * @return AbstractInlineFormField - */ - public function setLevelLinksPosition($levelLinksPosition) { - $this->levelLinksPosition = $levelLinksPosition; - return $this; - } - - /** - * @return array - */ - public function getLevelLinksPosition() { - return $this->levelLinksPosition; - } - - /** - * @param string $foreignSelectorFieldTcaOverride - * @return RelationFieldInterface - */ - public function setForeignSelectorFieldTcaOverride($foreignSelectorFieldTcaOverride) { - $this->foreignSelectorFieldTcaOverride = $foreignSelectorFieldTcaOverride; - return $this; - } - - /** - * @return string - */ - public function getForeignSelectorFieldTcaOverride() { - return $this->foreignSelectorFieldTcaOverride; - } - - /** - * @param array $foreignTypes - * @return RelationFieldInterface - */ - public function setForeignTypes($foreignTypes) { - $this->foreignTypes = TRUE === is_array($foreignTypes) ? $foreignTypes : NULL; - return $this; - } - - /** - * @return array - */ - public function getForeignTypes() { - return $this->foreignTypes; - } - +abstract class AbstractInlineFormField extends AbstractRelationFormField implements InlineRelationFieldInterface +{ + + /** + * If true, all child records are shown as collapsed. + * + * @var boolean + */ + protected $collapseAll = false; + + /** + * Show only one expanded record at any time. If a new record is expanded, + * all others are collapsed. + * + * @var boolean + */ + protected $expandSingle = false; + + /** + * Add the foreign table's title to the 'Add new' link (ie. 'Add new (sometable)') + * + * @var boolean + */ + protected $newRecordLinkAddTitle = false; + + /** + * Record link position - can be either \FluidTYPO3\Flux\Form::POSITION_TOP, + * \FluidTYPO3\Flux\Form::POSITION_BOTTOM, \FluidTYPO3\Flux\Form::POSITION_BOTH or + * \FluidTYPO3\Flux\Form::POSITION_NONE. + * + * @var string + */ + protected $newRecordLinkPosition = Form::POSITION_TOP; + + /** + * For use on bidirectional relations using an intermediary table. + * In combinations, it's possible to edit attributes and the related child record. + * + * @var boolean + */ + protected $useCombination = false; + + /** + * Allow manual sorting of child objects. + * + * @var boolean + */ + protected $useSortable = false; + + /** + * Show unlocalized records which are in the original language, but not yet localized. + * + * @var boolean + */ + protected $showPossibleLocalizationRecords = false; + + /** + * Show records which were once localized but do not exist in the original + * language anymore. + * + * @var boolean + */ + protected $showRemovedLocalizationRecords = false; + + /** + * Defines whether to show the 'localize all records' link to fetch untranslated + * records from the original language. + * + * @var boolean + */ + protected $showAllLocalizationLink = false; + + /** + * Defines whether to show a 'synchronize' link to update to a 1:1 translation with + * the original language. + * + * @var boolean + */ + protected $showSynchronizationLink = false; + + /** + * Associative array with the keys 'info', 'new', 'dragdrop', 'sort', 'hide', delete' + * and 'localize'. Set either one to TRUE or FALSE to show or hide it. + * + * @var array + */ + protected $enabledControls = [ + Form::CONTROL_INFO => false, + Form::CONTROL_NEW => true, + Form::CONTROL_DRAGDROP => true, + Form::CONTROL_SORT => true, + Form::CONTROL_HIDE => true, + Form::CONTROL_DELETE => false, + Form::CONTROL_LOCALISE => false, + ]; + + /** + * Array of field=>value pairs which are always used in conditions as well as inserted into new + * records created through this form component. + * + * @var array + */ + protected $foreignMatchFields = []; + + /** + * @var array + */ + protected $headerThumbnail = null; + + /** + * @var string + */ + protected $levelLinksPosition = null; + + /** + * @var string + */ + protected $foreignSelectorFieldTcaOverride; + + /** + * @var array + */ + protected $foreignTypes = null; + + /** + * @param string $type + * @return array + */ + public function prepareConfiguration($type) + { + $configuration = parent::prepareConfiguration($type); + $configuration['foreign_match_fields'] = $this->getForeignMatchFields(); + $configuration['foreign_selector_fieldTcaOverride'] = $this->getForeignSelectorFieldTcaOverride(); + $configuration['foreign_types'] = $this->getForeignTypes(); + $configuration['appearance'] = [ + 'collapseAll' => $this->getCollapseAll(), + 'expandSingle' => $this->getExpandSingle(), + 'newRecordLinkAddTitle' => $this->getNewRecordLinkAddTitle(), + 'newRecordLinkPosition' => $this->getNewRecordLinkPosition(), + 'useCombination' => $this->getUseCombination(), + 'useSortable' => $this->getUseSortable(), + 'showPossibleLocalizationRecords' => $this->getShowPossibleLocalizationRecords(), + 'showRemovedLocalizationRecords' => $this->getShowRemovedLocalizationRecords(), + 'showAllLocalizationLink' => $this->getShowAllLocalizationLink(), + 'showSynchronizationLink' => $this->getShowSynchronizationLink(), + 'enabledControls' => $this->getEnabledControls(), + 'headerThumbnail' => $this->getHeaderThumbnail(), + 'levelLinksPosition' => $this->getLevelLinksPosition(), + ]; + $configuration['behaviour'] = [ + 'localizationMode' => $this->getLocalizationMode(), + 'localizeChildrenAtParentLocalization' => $this->getLocalizeChildrenAtParentLocalization(), + 'disableMovingChildrenWithParent' => $this->getDisableMovingChildrenWithParent(), + ]; + return $configuration; + } + + /** + * @param boolean $collapseAll + * @return AbstractInlineFormField + */ + public function setCollapseAll($collapseAll) + { + $this->collapseAll = $collapseAll; + return $this; + } + + /** + * @return boolean + */ + public function getCollapseAll() + { + return $this->collapseAll; + } + + /** + * @param array $enabledControls + * @return AbstractInlineFormField + */ + public function setEnabledControls(array $enabledControls) + { + $this->enabledControls = $enabledControls; + return $this; + } + + /** + * @return array + */ + public function getEnabledControls() + { + return $this->enabledControls; + } + + /** + * @param boolean $expandSingle + * @return AbstractInlineFormField + */ + public function setExpandSingle($expandSingle) + { + $this->expandSingle = $expandSingle; + return $this; + } + + /** + * @return boolean + */ + public function getExpandSingle() + { + return $this->expandSingle; + } + + /** + * @param boolean $newRecordLinkAddTitle + * @return AbstractInlineFormField + */ + public function setNewRecordLinkAddTitle($newRecordLinkAddTitle) + { + $this->newRecordLinkAddTitle = $newRecordLinkAddTitle; + return $this; + } + + /** + * @return boolean + */ + public function getNewRecordLinkAddTitle() + { + return $this->newRecordLinkAddTitle; + } + + /** + * @param string $newRecordLinkPosition + * @return AbstractInlineFormField + */ + public function setNewRecordLinkPosition($newRecordLinkPosition) + { + $this->newRecordLinkPosition = $newRecordLinkPosition; + return $this; + } + + /** + * @return string + */ + public function getNewRecordLinkPosition() + { + return $this->newRecordLinkPosition; + } + + /** + * @param boolean $showAllLocalizationLink + * @return AbstractInlineFormField + */ + public function setShowAllLocalizationLink($showAllLocalizationLink) + { + $this->showAllLocalizationLink = $showAllLocalizationLink; + return $this; + } + + /** + * @return boolean + */ + public function getShowAllLocalizationLink() + { + return $this->showAllLocalizationLink; + } + + /** + * @param boolean $showPossibleLocalizationRecords + * @return AbstractInlineFormField + */ + public function setShowPossibleLocalizationRecords($showPossibleLocalizationRecords) + { + $this->showPossibleLocalizationRecords = $showPossibleLocalizationRecords; + return $this; + } + + /** + * @return boolean + */ + public function getShowPossibleLocalizationRecords() + { + return $this->showPossibleLocalizationRecords; + } + + /** + * @param boolean $showRemovedLocalizationRecords + * @return AbstractInlineFormField + */ + public function setShowRemovedLocalizationRecords($showRemovedLocalizationRecords) + { + $this->showRemovedLocalizationRecords = $showRemovedLocalizationRecords; + return $this; + } + + /** + * @return boolean + */ + public function getShowRemovedLocalizationRecords() + { + return $this->showRemovedLocalizationRecords; + } + + /** + * @param boolean $showSynchronizationLink + * @return AbstractInlineFormField + */ + public function setShowSynchronizationLink($showSynchronizationLink) + { + $this->showSynchronizationLink = $showSynchronizationLink; + return $this; + } + + /** + * @return boolean + */ + public function getShowSynchronizationLink() + { + return $this->showSynchronizationLink; + } + + /** + * @param boolean $useCombination + * @return AbstractInlineFormField + */ + public function setUseCombination($useCombination) + { + $this->useCombination = $useCombination; + return $this; + } + + /** + * @return boolean + */ + public function getUseCombination() + { + return $this->useCombination; + } + + /** + * @param boolean $useSortable + * @return AbstractInlineFormField + */ + public function setUseSortable($useSortable) + { + $this->useSortable = $useSortable; + return $this; + } + + /** + * @return boolean + */ + public function getUseSortable() + { + return $this->useSortable; + } + + /** + * @param array $foreignMatchFields + * @return Inline + */ + public function setForeignMatchFields(array $foreignMatchFields) + { + $this->foreignMatchFields = $foreignMatchFields; + return $this; + } + + /** + * @return array + */ + public function getForeignMatchFields() + { + return $this->foreignMatchFields; + } + + /** + * @param array $headerThumbnail + * @return AbstractInlineFormField + */ + public function setHeaderThumbnail(array $headerThumbnail) + { + $this->headerThumbnail = $headerThumbnail; + return $this; + } + + /** + * @return array + */ + public function getHeaderThumbnail() + { + return $this->headerThumbnail; + } + + /** + * @param string $levelLinksPosition + * @return AbstractInlineFormField + */ + public function setLevelLinksPosition($levelLinksPosition) + { + $this->levelLinksPosition = $levelLinksPosition; + return $this; + } + + /** + * @return array + */ + public function getLevelLinksPosition() + { + return $this->levelLinksPosition; + } + + /** + * @param string $foreignSelectorFieldTcaOverride + * @return RelationFieldInterface + */ + public function setForeignSelectorFieldTcaOverride($foreignSelectorFieldTcaOverride) + { + $this->foreignSelectorFieldTcaOverride = $foreignSelectorFieldTcaOverride; + return $this; + } + + /** + * @return string + */ + public function getForeignSelectorFieldTcaOverride() + { + return $this->foreignSelectorFieldTcaOverride; + } + + /** + * @param array $foreignTypes + * @return RelationFieldInterface + */ + public function setForeignTypes($foreignTypes) + { + $this->foreignTypes = true === is_array($foreignTypes) ? $foreignTypes : null; + return $this; + } + + /** + * @return array + */ + public function getForeignTypes() + { + return $this->foreignTypes; + } } diff --git a/Classes/Form/AbstractMultiValueFormField.php b/Classes/Form/AbstractMultiValueFormField.php index cdbc79496..4504c1b22 100644 --- a/Classes/Form/AbstractMultiValueFormField.php +++ b/Classes/Form/AbstractMultiValueFormField.php @@ -11,185 +11,202 @@ /** * AbstractMultiValueFormField */ -abstract class AbstractMultiValueFormField extends AbstractFormField implements MultiValueFieldInterface { - - /** - * @var integer - */ - protected $size = 1; - - /** - * @var boolean - */ - protected $multiple = FALSE; - - /** - * @var integer - */ - protected $minItems = 0; - - /** - * @var integer - */ - protected $maxItems; - - /** - * @var string - */ - protected $itemListStyle; - - /** - * @var string - */ - protected $selectedListStyle; - - /** - * @var string - */ - protected $renderMode = 'default'; - - /** - * @param string $type - * @return array - */ - public function prepareConfiguration($type) { - $configuration = parent::prepareConfiguration($type); - $configuration['size'] = $this->getSize(); - $configuration['maxitems'] = $this->getMaxItems(); - $configuration['minitems'] = $this->getMinItems(); - $configuration['multiple'] = $this->getMultiple(); - $configuration['renderMode'] = $this->getRenderMode(); - $configuration['itemListStyle'] = $this->getItemListStyle(); - $configuration['selectedListStyle'] = $this->getSelectedListStyle(); - $configuration['renderType'] = $this->getRenderType(); - return $configuration; - } - - /** - * @param integer $size - * @return MultiValueFieldInterface - */ - public function setSize($size) { - $this->size = $size; - return $this; - } - - /** - * @return int - */ - public function getSize() { - return $this->size; - } - - /** - * @param boolean $multiple - * @return MultiValueFieldInterface - */ - public function setMultiple($multiple) { - $this->multiple = $multiple; - return $this; - } - - /** - * @return boolean - */ - public function getMultiple() { - return $this->multiple; - } - - /** - * @param integer $maxItems - * @return MultiValueFieldInterface - */ - public function setMaxItems($maxItems) { - $this->maxItems = $maxItems; - return $this; - } - - /** - * @return integer - */ - public function getMaxItems() { - return $this->maxItems; - } - - /** - * @param integer $minItems - * @return MultiValueFieldInterface - */ - public function setMinItems($minItems) { - $this->minItems = $minItems; - return $this; - } - - /** - * @return integer - */ - public function getMinItems() { - return $this->minItems; - } - - /** - * @param string $itemListStyle - * @return MultiValueFieldInterface - */ - public function setItemListStyle($itemListStyle) { - $this->itemListStyle = $itemListStyle; - return $this; - } - - /** - * @return string - */ - public function getItemListStyle() { - return $this->itemListStyle; - } - - /** - * @param string $selectedListStyle - * @return MultiValueFieldInterface - */ - public function setSelectedListStyle($selectedListStyle) { - $this->selectedListStyle = $selectedListStyle; - return $this; - } - - /** - * @return string - */ - public function getSelectedListStyle() { - return $this->selectedListStyle; - } - - /** - * @param string $renderMode - * @return MultiValueFieldInterface - */ - public function setRenderMode($renderMode) { - $this->renderMode = $renderMode; - return $this; - } - - /** - * @return string - */ - public function getRenderMode() { - return $this->renderMode; - } - - /** - * @return string - */ - public function getRenderType() { - return $this->renderType; - } - - /** - * @param string $renderType - * @return void - */ - public function setRenderType($renderType) { - $this->renderType = $renderType; - } - +abstract class AbstractMultiValueFormField extends AbstractFormField implements MultiValueFieldInterface +{ + + /** + * @var integer + */ + protected $size = 1; + + /** + * @var boolean + */ + protected $multiple = false; + + /** + * @var integer + */ + protected $minItems = 0; + + /** + * @var integer + */ + protected $maxItems; + + /** + * @var string + */ + protected $itemListStyle; + + /** + * @var string + */ + protected $selectedListStyle; + + /** + * @var string + */ + protected $renderMode = 'default'; + + /** + * @param string $type + * @return array + */ + public function prepareConfiguration($type) + { + $configuration = parent::prepareConfiguration($type); + $configuration['size'] = $this->getSize(); + $configuration['maxitems'] = $this->getMaxItems(); + $configuration['minitems'] = $this->getMinItems(); + $configuration['multiple'] = $this->getMultiple(); + $configuration['renderMode'] = $this->getRenderMode(); + $configuration['itemListStyle'] = $this->getItemListStyle(); + $configuration['selectedListStyle'] = $this->getSelectedListStyle(); + $configuration['renderType'] = $this->getRenderType(); + return $configuration; + } + + /** + * @param integer $size + * @return MultiValueFieldInterface + */ + public function setSize($size) + { + $this->size = $size; + return $this; + } + + /** + * @return int + */ + public function getSize() + { + return $this->size; + } + + /** + * @param boolean $multiple + * @return MultiValueFieldInterface + */ + public function setMultiple($multiple) + { + $this->multiple = $multiple; + return $this; + } + + /** + * @return boolean + */ + public function getMultiple() + { + return $this->multiple; + } + + /** + * @param integer $maxItems + * @return MultiValueFieldInterface + */ + public function setMaxItems($maxItems) + { + $this->maxItems = $maxItems; + return $this; + } + + /** + * @return integer + */ + public function getMaxItems() + { + return $this->maxItems; + } + + /** + * @param integer $minItems + * @return MultiValueFieldInterface + */ + public function setMinItems($minItems) + { + $this->minItems = $minItems; + return $this; + } + + /** + * @return integer + */ + public function getMinItems() + { + return $this->minItems; + } + + /** + * @param string $itemListStyle + * @return MultiValueFieldInterface + */ + public function setItemListStyle($itemListStyle) + { + $this->itemListStyle = $itemListStyle; + return $this; + } + + /** + * @return string + */ + public function getItemListStyle() + { + return $this->itemListStyle; + } + + /** + * @param string $selectedListStyle + * @return MultiValueFieldInterface + */ + public function setSelectedListStyle($selectedListStyle) + { + $this->selectedListStyle = $selectedListStyle; + return $this; + } + + /** + * @return string + */ + public function getSelectedListStyle() + { + return $this->selectedListStyle; + } + + /** + * @param string $renderMode + * @return MultiValueFieldInterface + */ + public function setRenderMode($renderMode) + { + $this->renderMode = $renderMode; + return $this; + } + + /** + * @return string + */ + public function getRenderMode() + { + return $this->renderMode; + } + + /** + * @return string + */ + public function getRenderType() + { + return $this->renderType; + } + + /** + * @param string $renderType + * @return void + */ + public function setRenderType($renderType) + { + $this->renderType = $renderType; + } } diff --git a/Classes/Form/AbstractRelationFormField.php b/Classes/Form/AbstractRelationFormField.php index a05481625..ca51beb94 100644 --- a/Classes/Form/AbstractRelationFormField.php +++ b/Classes/Form/AbstractRelationFormField.php @@ -11,557 +11,606 @@ /** * AbstractRelationFormField */ -abstract class AbstractRelationFormField extends AbstractMultiValueFormField implements RelationFieldInterface { - - /** - * @var string - */ - protected $table; - - /** - * @var string - */ - protected $condition; - - /** - * Optional filter - as an array($userFunctionReferenceString, $parameters) - * - to further condition which records are allowed to be selected in this field. - * - * @var array - */ - protected $filter = array(); - - /** - * The foreign_field is the field of the child record pointing to the - * parent record. This defines where to store the uid of the parent record. - * - * @var string - */ - protected $foreignField; - - /** - * The field of the child record pointing to the parent record. This defines - * where to store the table name of the parent record. On setting this - * configuration key together with foreign_field, the child record knows what - * its parent record is – so the child record could also be used on other - * parent tables. - * - * @var string - */ - protected $foreignTableField; - - /** - * @var string|NULL - */ - protected $manyToMany = NULL; - - /** - * When using many-to-many mode you can specify an array of field=>value pairs - * which must also match in the relation table when the relation is resolved. - * - * @var array - */ - protected $matchFields = array(); - - /** - * If set, it overrides the label set in TCA[foreign_table]['ctrl']['label'] - * for the foreign table view. - * - * @var string - */ - protected $foreignLabel; - - /** - * A selector is used to show all possible child records that could be used - * to create a relation with the parent record. It will be rendered as a - * multi-select-box. On clicking on an item inside the selector a new relation - * is created. The foreign_selector points to a field of the foreign_table that - * is responsible for providing a selector-box – this field on the foreign_table - * usually has the type "select" and also has a "foreign_table" defined. - * - * @var string - */ - protected $foreignSelector; - - /** - * Defines a field on the child record (or on the intermediate table) that - * stores the manual sorting information. - * - * @var string - */ - protected $foreignSortby; - - /** - * If a fieldname for foreign_sortby is defined, then this is ignored. Otherwise - * this is used as the "ORDER BY" statement to sort the records in the table - * when listed. - * - * @var string - */ - protected $foreignDefaultSortby; - - /** - * Field which must be uniue for all children of a parent record. - * - * @var string - */ - protected $foreignUnique; - - /** - * In case of bidirectional symmetric relations, this defines the field name on - * the foreign table which contains the UID of this side of the relation. - * - * @var string - */ - protected $symmetricField; - - /** - * If set, this overrides the default label of the selected symmetric table. - * - * @var string - */ - protected $symmetricLabel; - - /** - * This works like foreign_sortby, but defines the field on foreign_table where - * the "other" sort order is stored (this order is then used only in the reverse - * symmetric relation). - * - * @var string - */ - protected $symmetricSortby; - - /** - * Set whether children can be localizable ('select') or just inherit from - * default language ('keep'). Default is empty, meaning no particular behavior. - * - * @var string - */ - protected $localizationMode; - - /** - * Defines whether children should be localized when the localization of the - * parent gets created. - * - * @var boolean - */ - protected $localizeChildrenAtParentLocalization = FALSE; - - /** - * Disables that child records get moved along with their parent records. - * - * @var boolean - */ - protected $disableMovingChildrenWithParent = FALSE; - - /** - * @var boolean - */ - protected $showThumbnails = FALSE; - - /** - * If not-FALSE, adds one empty option/value pair to the generated selector - * box and tries to use this property's value (cast to string) as label. - * - * @var boolean|string - */ - protected $emptyOption = FALSE; - - /** - * @param string $type - * @return array - */ - public function prepareConfiguration($type) { - $configuration = parent::prepareConfiguration($type); - $configuration['foreign_table'] = $this->getTable(); - $configuration['foreign_field'] = $this->getForeignField(); - $configuration['foreign_table_where'] = $this->getCondition(); - $configuration['foreign_table_field'] = $this->getForeignTableField(); - $configuration['foreign_unique'] = $this->getForeignUnique(); - $configuration['foreign_label'] = $this->getForeignLabel(); - $configuration['foreign_selector'] = $this->getForeignSelector(); - $configuration['foreign_sortby'] = $this->getForeignSortby(); - $configuration['foreign_default_sortby'] = $this->getForeignDefaultSortby(); - $configuration['symmetricSortBy'] = $this->getSymmetricSortby(); - $configuration['symmetricLabel'] = $this->getSymmetricLabel(); - $configuration['symmetricField'] = $this->getSymmetricField(); - $configuration['localizationMode'] = $this->getLocalizationMode(); - $configuration['localizeChildrenAtParentLocalization'] = intval($this->getLocalizeChildrenAtParentLocalization()); - $configuration['disableMovingChildrenWithParent'] = intval($this->getDisableMovingChildrenWithParent()); - $configuration['showThumbs'] = intval($this->getShowThumbnails()); - $configuration['MM'] = $this->getManyToMany(); - $configuration['MM_match_fields'] = $this->getMatchFields(); - $configuration['MM_opposite_field'] = $this->getOppositeField(); - $configuration['filter'] = $this->getFilter(); - return $configuration; - } - - /** - * @param string $condition - * @return \FluidTYPO3\Flux\Form\RelationFieldInterface - */ - public function setCondition($condition) { - $this->condition = $condition; - return $this; - } - - /** - * @return string - */ - public function getCondition() { - return $this->condition; - } - - /** - * @param array $filter - * @return RelationFieldInterface - */ - public function setFilter(array $filter) { - $this->filter = $filter; - return $this; - } - - /** - * @return array - */ - public function getFilter() { - return $this->filter; - } - - /** - * @param string $foreignField - * @return RelationFieldInterface - */ - public function setForeignField($foreignField) { - $this->foreignField = $foreignField; - return $this; - } - - /** - * @return string - */ - public function getForeignField() { - return $this->foreignField; - } - - /** - * @param NULL|string $manyToMany - * @return RelationFieldInterface - */ - public function setManyToMany($manyToMany) { - $this->manyToMany = $manyToMany; - return $this; - } - - /** - * @return NULL|string - */ - public function getManyToMany() { - return $this->manyToMany; - } - - /** - * @return array - */ - public function getMatchFields() { - return $this->matchFields; - } - - /** - * @param array $matchFields - * @return RelationFieldInterface - */ - public function setMatchFields(array $matchFields) { - $this->matchFields = $matchFields; - return $this; - } - - /** - * @return string - */ - public function getOppositeField() { - return $this->oppositeField; - } - - /** - * @param string $oppositeField - * @return RelationFieldInterface - */ - public function setOppositeField($oppositeField) { - $this->oppositeField = $oppositeField; - return $this; - } - - /** - * @param string $table - * @return RelationFieldInterface - */ - public function setTable($table) { - $this->table = $table; - return $this; - } - - /** - * @return string - */ - public function getTable() { - return $this->table; - } - - /** - * @param boolean $disableMovingChildrenWithParent - * @return RelationFieldInterface - */ - public function setDisableMovingChildrenWithParent($disableMovingChildrenWithParent) { - $this->disableMovingChildrenWithParent = $disableMovingChildrenWithParent; - return $this; - } - - /** - * @return boolean - */ - public function getDisableMovingChildrenWithParent() { - return $this->disableMovingChildrenWithParent; - } - - /** - * @param string $foreignDefaultSortby - * @return RelationFieldInterface - */ - public function setForeignDefaultSortby($foreignDefaultSortby) { - $this->foreignDefaultSortby = $foreignDefaultSortby; - return $this; - } - - /** - * @return string - */ - public function getForeignDefaultSortby() { - return $this->foreignDefaultSortby; - } - - /** - * @param string $foreignLabel - * @return RelationFieldInterface - */ - public function setForeignLabel($foreignLabel) { - $this->foreignLabel = $foreignLabel; - return $this; - } - - /** - * @return string - */ - public function getForeignLabel() { - return $this->foreignLabel; - } - - /** - * @param string $foreignSelector - * @return RelationFieldInterface - */ - public function setForeignSelector($foreignSelector) { - $this->foreignSelector = $foreignSelector; - return $this; - } - - /** - * @return string - */ - public function getForeignSelector() { - return $this->foreignSelector; - } - - /** - * @param string $foreignSortby - * @return RelationFieldInterface - */ - public function setForeignSortby($foreignSortby) { - $this->foreignSortby = $foreignSortby; - return $this; - } - - /** - * @return string - */ - public function getForeignSortby() { - return $this->foreignSortby; - } - - /** - * @param string $foreignTableField - * @return RelationFieldInterface - */ - public function setForeignTableField($foreignTableField) { - $this->foreignTableField = $foreignTableField; - return $this; - } - - /** - * @return string - */ - public function getForeignTableField() { - return $this->foreignTableField; - } - - /** - * @param string $foreignUnique - * @return RelationFieldInterface - */ - public function setForeignUnique($foreignUnique) { - $this->foreignUnique = $foreignUnique; - return $this; - } - - /** - * @return string - */ - public function getForeignUnique() { - return $this->foreignUnique; - } - - /** - * @param string $itemListStyle - * @return RelationFieldInterface - */ - public function setItemListStyle($itemListStyle) { - $this->itemListStyle = $itemListStyle; - return $this; - } - - /** - * @return string - */ - public function getItemListStyle() { - return $this->itemListStyle; - } - - /** - * @param string $localizationMode - * @return RelationFieldInterface - */ - public function setLocalizationMode($localizationMode) { - $this->localizationMode = $localizationMode; - return $this; - } - - /** - * @return string - */ - public function getLocalizationMode() { - return $this->localizationMode; - } - - /** - * @param boolean $localizeChildrenAtParentLocalization - * @return RelationFieldInterface - */ - public function setLocalizeChildrenAtParentLocalization($localizeChildrenAtParentLocalization) { - $this->localizeChildrenAtParentLocalization = $localizeChildrenAtParentLocalization; - return $this; - } - - /** - * @return boolean - */ - public function getLocalizeChildrenAtParentLocalization() { - return $this->localizeChildrenAtParentLocalization; - } - - /** - * @param string $selectedListStyle - * @return RelationFieldInterface - */ - public function setSelectedListStyle($selectedListStyle) { - $this->selectedListStyle = $selectedListStyle; - return $this; - } - - /** - * @return string - */ - public function getSelectedListStyle() { - return $this->selectedListStyle; - } - - /** - * @param string $symmetricField - * @return RelationFieldInterface - */ - public function setSymmetricField($symmetricField) { - $this->symmetricField = $symmetricField; - return $this; - } - - /** - * @return string - */ - public function getSymmetricField() { - return $this->symmetricField; - } - - /** - * @param string $symmetricLabel - * @return RelationFieldInterface - */ - public function setSymmetricLabel($symmetricLabel) { - $this->symmetricLabel = $symmetricLabel; - return $this; - } - - /** - * @return string - */ - public function getSymmetricLabel() { - return $this->symmetricLabel; - } - - /** - * @param string $symmetricSortby - * @return RelationFieldInterface - */ - public function setSymmetricSortby($symmetricSortby) { - $this->symmetricSortby = $symmetricSortby; - return $this; - } - - /** - * @return string - */ - public function getSymmetricSortby() { - return $this->symmetricSortby; - } - - /** - * @param boolean $showThumbnails - * @return RelationFieldInterface - */ - public function setShowThumbnails($showThumbnails) { - $this->showThumbnails = $showThumbnails; - return $this; - } - - /** - * @return boolean - */ - public function getShowThumbnails() { - return $this->showThumbnails; - } - - /** - * @param boolean|string $emptyOption - * @return Select - */ - public function setEmptyOption($emptyOption) { - $this->emptyOption = $emptyOption; - return $this; - } - - /** - * @return boolean|string - */ - public function getEmptyOption() { - return $this->emptyOption; - } - +abstract class AbstractRelationFormField extends AbstractMultiValueFormField implements RelationFieldInterface +{ + + /** + * @var string + */ + protected $table; + + /** + * @var string + */ + protected $condition; + + /** + * Optional filter - as an [$userFunctionReferenceString, $parameters) + * - to further condition which records are allowed to be selected in this field. + * + * @var array + */ + protected $filter = []; + + /** + * The foreign_field is the field of the child record pointing to the + * parent record. This defines where to store the uid of the parent record. + * + * @var string + */ + protected $foreignField; + + /** + * The field of the child record pointing to the parent record. This defines + * where to store the table name of the parent record. On setting this + * configuration key together with foreign_field, the child record knows what + * its parent record is – so the child record could also be used on other + * parent tables. + * + * @var string + */ + protected $foreignTableField; + + /** + * @var string|NULL + */ + protected $manyToMany = null; + + /** + * When using many-to-many mode you can specify an array of field=>value pairs + * which must also match in the relation table when the relation is resolved. + * + * @var array + */ + protected $matchFields = []; + + /** + * If set, it overrides the label set in TCA[foreign_table]['ctrl']['label'] + * for the foreign table view. + * + * @var string + */ + protected $foreignLabel; + + /** + * A selector is used to show all possible child records that could be used + * to create a relation with the parent record. It will be rendered as a + * multi-select-box. On clicking on an item inside the selector a new relation + * is created. The foreign_selector points to a field of the foreign_table that + * is responsible for providing a selector-box – this field on the foreign_table + * usually has the type "select" and also has a "foreign_table" defined. + * + * @var string + */ + protected $foreignSelector; + + /** + * Defines a field on the child record (or on the intermediate table) that + * stores the manual sorting information. + * + * @var string + */ + protected $foreignSortby; + + /** + * If a fieldname for foreign_sortby is defined, then this is ignored. Otherwise + * this is used as the "ORDER BY" statement to sort the records in the table + * when listed. + * + * @var string + */ + protected $foreignDefaultSortby; + + /** + * Field which must be uniue for all children of a parent record. + * + * @var string + */ + protected $foreignUnique; + + /** + * In case of bidirectional symmetric relations, this defines the field name on + * the foreign table which contains the UID of this side of the relation. + * + * @var string + */ + protected $symmetricField; + + /** + * If set, this overrides the default label of the selected symmetric table. + * + * @var string + */ + protected $symmetricLabel; + + /** + * This works like foreign_sortby, but defines the field on foreign_table where + * the "other" sort order is stored (this order is then used only in the reverse + * symmetric relation). + * + * @var string + */ + protected $symmetricSortby; + + /** + * Set whether children can be localizable ('select') or just inherit from + * default language ('keep'). Default is empty, meaning no particular behavior. + * + * @var string + */ + protected $localizationMode; + + /** + * Defines whether children should be localized when the localization of the + * parent gets created. + * + * @var boolean + */ + protected $localizeChildrenAtParentLocalization = false; + + /** + * Disables that child records get moved along with their parent records. + * + * @var boolean + */ + protected $disableMovingChildrenWithParent = false; + + /** + * @var boolean + */ + protected $showThumbnails = false; + + /** + * If not-FALSE, adds one empty option/value pair to the generated selector + * box and tries to use this property's value (cast to string) as label. + * + * @var boolean|string + */ + protected $emptyOption = false; + + /** + * @param string $type + * @return array + */ + public function prepareConfiguration($type) + { + $configuration = parent::prepareConfiguration($type); + $configuration['foreign_table'] = $this->getTable(); + $configuration['foreign_field'] = $this->getForeignField(); + $configuration['foreign_table_where'] = $this->getCondition(); + $configuration['foreign_table_field'] = $this->getForeignTableField(); + $configuration['foreign_unique'] = $this->getForeignUnique(); + $configuration['foreign_label'] = $this->getForeignLabel(); + $configuration['foreign_selector'] = $this->getForeignSelector(); + $configuration['foreign_sortby'] = $this->getForeignSortby(); + $configuration['foreign_default_sortby'] = $this->getForeignDefaultSortby(); + $configuration['symmetricSortBy'] = $this->getSymmetricSortby(); + $configuration['symmetricLabel'] = $this->getSymmetricLabel(); + $configuration['symmetricField'] = $this->getSymmetricField(); + $configuration['localizationMode'] = $this->getLocalizationMode(); + $configuration['localizeChildrenAtParentLocalization'] = + (integer) $this->getLocalizeChildrenAtParentLocalization(); + $configuration['disableMovingChildrenWithParent'] = + (integer) $this->getDisableMovingChildrenWithParent(); + $configuration['showThumbs'] = intval($this->getShowThumbnails()); + $configuration['MM'] = $this->getManyToMany(); + $configuration['MM_match_fields'] = $this->getMatchFields(); + $configuration['MM_opposite_field'] = $this->getOppositeField(); + $configuration['filter'] = $this->getFilter(); + return $configuration; + } + + /** + * @param string $condition + * @return \FluidTYPO3\Flux\Form\RelationFieldInterface + */ + public function setCondition($condition) + { + $this->condition = $condition; + return $this; + } + + /** + * @return string + */ + public function getCondition() + { + return $this->condition; + } + + /** + * @param array $filter + * @return RelationFieldInterface + */ + public function setFilter(array $filter) + { + $this->filter = $filter; + return $this; + } + + /** + * @return array + */ + public function getFilter() + { + return $this->filter; + } + + /** + * @param string $foreignField + * @return RelationFieldInterface + */ + public function setForeignField($foreignField) + { + $this->foreignField = $foreignField; + return $this; + } + + /** + * @return string + */ + public function getForeignField() + { + return $this->foreignField; + } + + /** + * @param NULL|string $manyToMany + * @return RelationFieldInterface + */ + public function setManyToMany($manyToMany) + { + $this->manyToMany = $manyToMany; + return $this; + } + + /** + * @return NULL|string + */ + public function getManyToMany() + { + return $this->manyToMany; + } + + /** + * @return array + */ + public function getMatchFields() + { + return $this->matchFields; + } + + /** + * @param array $matchFields + * @return RelationFieldInterface + */ + public function setMatchFields(array $matchFields) + { + $this->matchFields = $matchFields; + return $this; + } + + /** + * @return string + */ + public function getOppositeField() + { + return $this->oppositeField; + } + + /** + * @param string $oppositeField + * @return RelationFieldInterface + */ + public function setOppositeField($oppositeField) + { + $this->oppositeField = $oppositeField; + return $this; + } + + /** + * @param string $table + * @return RelationFieldInterface + */ + public function setTable($table) + { + $this->table = $table; + return $this; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } + + /** + * @param boolean $disableMovingChildrenWithParent + * @return RelationFieldInterface + */ + public function setDisableMovingChildrenWithParent($disableMovingChildrenWithParent) + { + $this->disableMovingChildrenWithParent = $disableMovingChildrenWithParent; + return $this; + } + + /** + * @return boolean + */ + public function getDisableMovingChildrenWithParent() + { + return $this->disableMovingChildrenWithParent; + } + + /** + * @param string $foreignDefaultSortby + * @return RelationFieldInterface + */ + public function setForeignDefaultSortby($foreignDefaultSortby) + { + $this->foreignDefaultSortby = $foreignDefaultSortby; + return $this; + } + + /** + * @return string + */ + public function getForeignDefaultSortby() + { + return $this->foreignDefaultSortby; + } + + /** + * @param string $foreignLabel + * @return RelationFieldInterface + */ + public function setForeignLabel($foreignLabel) + { + $this->foreignLabel = $foreignLabel; + return $this; + } + + /** + * @return string + */ + public function getForeignLabel() + { + return $this->foreignLabel; + } + + /** + * @param string $foreignSelector + * @return RelationFieldInterface + */ + public function setForeignSelector($foreignSelector) + { + $this->foreignSelector = $foreignSelector; + return $this; + } + + /** + * @return string + */ + public function getForeignSelector() + { + return $this->foreignSelector; + } + + /** + * @param string $foreignSortby + * @return RelationFieldInterface + */ + public function setForeignSortby($foreignSortby) + { + $this->foreignSortby = $foreignSortby; + return $this; + } + + /** + * @return string + */ + public function getForeignSortby() + { + return $this->foreignSortby; + } + + /** + * @param string $foreignTableField + * @return RelationFieldInterface + */ + public function setForeignTableField($foreignTableField) + { + $this->foreignTableField = $foreignTableField; + return $this; + } + + /** + * @return string + */ + public function getForeignTableField() + { + return $this->foreignTableField; + } + + /** + * @param string $foreignUnique + * @return RelationFieldInterface + */ + public function setForeignUnique($foreignUnique) + { + $this->foreignUnique = $foreignUnique; + return $this; + } + + /** + * @return string + */ + public function getForeignUnique() + { + return $this->foreignUnique; + } + + /** + * @param string $itemListStyle + * @return RelationFieldInterface + */ + public function setItemListStyle($itemListStyle) + { + $this->itemListStyle = $itemListStyle; + return $this; + } + + /** + * @return string + */ + public function getItemListStyle() + { + return $this->itemListStyle; + } + + /** + * @param string $localizationMode + * @return RelationFieldInterface + */ + public function setLocalizationMode($localizationMode) + { + $this->localizationMode = $localizationMode; + return $this; + } + + /** + * @return string + */ + public function getLocalizationMode() + { + return $this->localizationMode; + } + + /** + * @param boolean $localizeChildrenAtParentLocalization + * @return RelationFieldInterface + */ + public function setLocalizeChildrenAtParentLocalization($localizeChildrenAtParentLocalization) + { + $this->localizeChildrenAtParentLocalization = $localizeChildrenAtParentLocalization; + return $this; + } + + /** + * @return boolean + */ + public function getLocalizeChildrenAtParentLocalization() + { + return $this->localizeChildrenAtParentLocalization; + } + + /** + * @param string $selectedListStyle + * @return RelationFieldInterface + */ + public function setSelectedListStyle($selectedListStyle) + { + $this->selectedListStyle = $selectedListStyle; + return $this; + } + + /** + * @return string + */ + public function getSelectedListStyle() + { + return $this->selectedListStyle; + } + + /** + * @param string $symmetricField + * @return RelationFieldInterface + */ + public function setSymmetricField($symmetricField) + { + $this->symmetricField = $symmetricField; + return $this; + } + + /** + * @return string + */ + public function getSymmetricField() + { + return $this->symmetricField; + } + + /** + * @param string $symmetricLabel + * @return RelationFieldInterface + */ + public function setSymmetricLabel($symmetricLabel) + { + $this->symmetricLabel = $symmetricLabel; + return $this; + } + + /** + * @return string + */ + public function getSymmetricLabel() + { + return $this->symmetricLabel; + } + + /** + * @param string $symmetricSortby + * @return RelationFieldInterface + */ + public function setSymmetricSortby($symmetricSortby) + { + $this->symmetricSortby = $symmetricSortby; + return $this; + } + + /** + * @return string + */ + public function getSymmetricSortby() + { + return $this->symmetricSortby; + } + + /** + * @param boolean $showThumbnails + * @return RelationFieldInterface + */ + public function setShowThumbnails($showThumbnails) + { + $this->showThumbnails = $showThumbnails; + return $this; + } + + /** + * @return boolean + */ + public function getShowThumbnails() + { + return $this->showThumbnails; + } + + /** + * @param boolean|string $emptyOption + * @return Select + */ + public function setEmptyOption($emptyOption) + { + $this->emptyOption = $emptyOption; + return $this; + } + + /** + * @return boolean|string + */ + public function getEmptyOption() + { + return $this->emptyOption; + } } diff --git a/Classes/Form/AbstractWizard.php b/Classes/Form/AbstractWizard.php index 4a4ff62a7..caf3991a1 100644 --- a/Classes/Form/AbstractWizard.php +++ b/Classes/Form/AbstractWizard.php @@ -13,69 +13,74 @@ /** * AbstractWizard */ -abstract class AbstractWizard extends AbstractFormComponent implements WizardInterface { +abstract class AbstractWizard extends AbstractFormComponent implements WizardInterface +{ - /** - * @var boolean - */ - protected $hideParent = FALSE; + /** + * @var boolean + */ + protected $hideParent = false; - /** - * @var string - */ - protected $name; + /** + * @var string + */ + protected $name; - /** - * @var string - */ - protected $type; + /** + * @var string + */ + protected $type; - /** - * @var string - */ - protected $icon; + /** + * @var string + */ + protected $icon; - /** - * @var array - */ - protected $module; + /** + * @var array + */ + protected $module; - /** - * @return array - */ - public function build() { - $structure = array( - 'type' => $this->type, - 'title' => $this->getLabel(), - 'icon' => $this->icon, - 'hideParent' => intval($this->getHideParent()), - 'module' => $this->module - ); - $configuration = $this->buildConfiguration(); - $structure = array_merge($structure, $configuration); - return $structure; - } + /** + * @return array + */ + public function build() + { + $structure = [ + 'type' => $this->type, + 'title' => $this->getLabel(), + 'icon' => $this->icon, + 'hideParent' => intval($this->getHideParent()), + 'module' => $this->module + ]; + $configuration = $this->buildConfiguration(); + $structure = array_merge($structure, $configuration); + return $structure; + } - /** - * @param boolean $hideParent - * @return Add - */ - public function setHideParent($hideParent) { - $this->hideParent = $hideParent; - return $this; - } + /** + * @param boolean $hideParent + * @return Add + */ + public function setHideParent($hideParent) + { + $this->hideParent = $hideParent; + return $this; + } - /** - * @return boolean - */ - public function getHideParent() { - return $this->hideParent; - } + /** + * @return boolean + */ + public function getHideParent() + { + return $this->hideParent; + } - /** - * @return boolean - */ - public function hasChildren() { - return FALSE; - } + /** + * @return boolean + */ + public function hasChildren() + { + return false; + } } diff --git a/Classes/Form/Container/Column.php b/Classes/Form/Container/Column.php index 8fac9c16a..d523f41a5 100644 --- a/Classes/Form/Container/Column.php +++ b/Classes/Form/Container/Column.php @@ -14,105 +14,114 @@ /** * Column */ -class Column extends AbstractFormContainer implements ContainerInterface { - - /** - * @var integer - */ - protected $columnPosition = 0; - - /** - * @var integer - */ - protected $colspan = 1; - - /** - * @var integer - */ - protected $rowspan = 1; - - /** - * @var string - */ - protected $style = NULL; - - /** - * @return array - */ - public function build() { - $structure = array( - 'name' => $this->getName(), - 'label' => $this->getLabel(), - 'colspan' => $this->getColspan(), - 'rowspan' => $this->getRowspan(), - 'style' => $this->getStyle(), - 'colPos' => $this->getColumnPosition() - ); - return $structure; - } - - /** - * @param integer $colspan - * @return Column - */ - public function setColspan($colspan) { - $this->colspan = $colspan; - return $this; - } - - /** - * @return integer - */ - public function getColspan() { - return $this->colspan; - } - - /** - * @param integer $columnPosition - * @return Column - */ - public function setColumnPosition($columnPosition) { - $this->columnPosition = (integer) $columnPosition; - return $this; - } - - /** - * @return integer - */ - public function getColumnPosition() { - return $this->columnPosition; - } - - /** - * @param integer $rowspan - * @return Column - */ - public function setRowspan($rowspan) { - $this->rowspan = $rowspan; - return $this; - } - - /** - * @return integer - */ - public function getRowspan() { - return $this->rowspan; - } - - /** - * @param string $style - * @return Column - */ - public function setStyle($style) { - $this->style = $style; - return $this; - } - - /** - * @return string - */ - public function getStyle() { - return $this->style; - } - +class Column extends AbstractFormContainer implements ContainerInterface +{ + + /** + * @var integer + */ + protected $columnPosition = 0; + + /** + * @var integer + */ + protected $colspan = 1; + + /** + * @var integer + */ + protected $rowspan = 1; + + /** + * @var string + */ + protected $style = null; + + /** + * @return array + */ + public function build() + { + $structure = [ + 'name' => $this->getName(), + 'label' => $this->getLabel(), + 'colspan' => $this->getColspan(), + 'rowspan' => $this->getRowspan(), + 'style' => $this->getStyle(), + 'colPos' => $this->getColumnPosition() + ]; + return $structure; + } + + /** + * @param integer $colspan + * @return Column + */ + public function setColspan($colspan) + { + $this->colspan = $colspan; + return $this; + } + + /** + * @return integer + */ + public function getColspan() + { + return $this->colspan; + } + + /** + * @param integer $columnPosition + * @return Column + */ + public function setColumnPosition($columnPosition) + { + $this->columnPosition = (integer) $columnPosition; + return $this; + } + + /** + * @return integer + */ + public function getColumnPosition() + { + return $this->columnPosition; + } + + /** + * @param integer $rowspan + * @return Column + */ + public function setRowspan($rowspan) + { + $this->rowspan = $rowspan; + return $this; + } + + /** + * @return integer + */ + public function getRowspan() + { + return $this->rowspan; + } + + /** + * @param string $style + * @return Column + */ + public function setStyle($style) + { + $this->style = $style; + return $this; + } + + /** + * @return string + */ + public function getStyle() + { + return $this->style; + } } diff --git a/Classes/Form/Container/Container.php b/Classes/Form/Container/Container.php index e4f6c32b2..9ee07d7c4 100644 --- a/Classes/Form/Container/Container.php +++ b/Classes/Form/Container/Container.php @@ -16,26 +16,28 @@ /** * Container */ -class Container extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface { +class Container extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface +{ - /** - * @return array - */ - public function build() { - $structureArray = array( - 'type' => 'array', - 'section' => '1', - 'title' => $this->getLabel(), - 'el' => $this->buildChildren($this->children) - ); - return $structureArray; - } - - /** - * @return FieldInterface[] - */ - public function getFields() { - return (array) iterator_to_array($this->children); - } + /** + * @return array + */ + public function build() + { + $structureArray = [ + 'type' => 'array', + 'section' => '1', + 'title' => $this->getLabel(), + 'el' => $this->buildChildren($this->children) + ]; + return $structureArray; + } + /** + * @return FieldInterface[] + */ + public function getFields() + { + return (array) iterator_to_array($this->children); + } } diff --git a/Classes/Form/Container/Grid.php b/Classes/Form/Container/Grid.php index c97ec125f..6b159f894 100644 --- a/Classes/Form/Container/Grid.php +++ b/Classes/Form/Container/Grid.php @@ -14,25 +14,27 @@ /** * Grid */ -class Grid extends AbstractFormContainer implements ContainerInterface { +class Grid extends AbstractFormContainer implements ContainerInterface +{ - /** - * @return array - */ - public function build() { - $structure = array( - 'name' => $this->getName(), - 'label' => $this->getLabel(), - 'rows' => $this->buildChildren($this->children) - ); - return $structure; - } - - /** - * @return Row[] - */ - public function getRows() { - return (array) iterator_to_array($this->children); - } + /** + * @return array + */ + public function build() + { + $structure = [ + 'name' => $this->getName(), + 'label' => $this->getLabel(), + 'rows' => $this->buildChildren($this->children) + ]; + return $structure; + } + /** + * @return Row[] + */ + public function getRows() + { + return (array) iterator_to_array($this->children); + } } diff --git a/Classes/Form/Container/Object.php b/Classes/Form/Container/Object.php index 6b4287d31..3e2bc9160 100644 --- a/Classes/Form/Container/Object.php +++ b/Classes/Form/Container/Object.php @@ -16,28 +16,30 @@ /** * Object */ -class Object extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface { +class Object extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface +{ - /** - * @return array - */ - public function build() { - $label = $this->getLabel(); - $structureArray = array( - 'title' => $label, - 'type' => 'array', - 'el' => $this->buildChildren($this->children) - ); - // patch: TYPO3 core legacy required for section objects. - $structureArray['tx_templavoila'] = array('title' => $structureArray['title']); - return $structureArray; - } - - /** - * @return FieldInterface[] - */ - public function getFields() { - return (array) iterator_to_array($this->children); - } + /** + * @return array + */ + public function build() + { + $label = $this->getLabel(); + $structureArray = [ + 'title' => $label, + 'type' => 'array', + 'el' => $this->buildChildren($this->children) + ]; + // patch: TYPO3 core legacy required for section objects. + $structureArray['tx_templavoila'] = ['title' => $structureArray['title']]; + return $structureArray; + } + /** + * @return FieldInterface[] + */ + public function getFields() + { + return (array) iterator_to_array($this->children); + } } diff --git a/Classes/Form/Container/Row.php b/Classes/Form/Container/Row.php index b7ca246d1..446fb0374 100644 --- a/Classes/Form/Container/Row.php +++ b/Classes/Form/Container/Row.php @@ -14,25 +14,27 @@ /** * Row */ -class Row extends AbstractFormContainer implements ContainerInterface { +class Row extends AbstractFormContainer implements ContainerInterface +{ - /** - * @return array - */ - public function build() { - $structure = array( - 'name' => $this->getName(), - 'label' => $this->getLabel(), - 'columns' => $this->buildChildren($this->children) - ); - return $structure; - } - - /** - * @return Column[] - */ - public function getColumns() { - return (array) iterator_to_array($this->children); - } + /** + * @return array + */ + public function build() + { + $structure = [ + 'name' => $this->getName(), + 'label' => $this->getLabel(), + 'columns' => $this->buildChildren($this->children) + ]; + return $structure; + } + /** + * @return Column[] + */ + public function getColumns() + { + return (array) iterator_to_array($this->children); + } } diff --git a/Classes/Form/Container/Section.php b/Classes/Form/Container/Section.php index ddcacf85e..395389072 100644 --- a/Classes/Form/Container/Section.php +++ b/Classes/Form/Container/Section.php @@ -17,46 +17,48 @@ /** * Section */ -class Section extends AbstractFormContainer implements ContainerInterface { +class Section extends AbstractFormContainer implements ContainerInterface +{ - /** - * @param array $settings - * @return \FluidTYPO3\Flux\Form\Container\Section - */ - public static function create(array $settings = array()) { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - /** @var Section */ - $section = $objectManager->get('FluidTYPO3\Flux\Form\Container\Section'); - foreach ($settings as $settingName => $settingValue) { - $setterMethodName = ObjectAccess::buildSetterMethodName($settingName); - if (TRUE === method_exists($section, $setterMethodName)) { - ObjectAccess::setProperty($section, $settingName, $settingValue); - } - } - if (TRUE === isset($settings['objects'])) { - foreach ($settings['objects'] as $fieldName => $objectSettings) { - if (FALSE === isset($objectSettings['name'])) { - $objectSettings['name'] = $fieldName; - } - $object = Object::create($objectSettings); - $section->add($object); - } - } - return $section; - } - - /** - * @return array - */ - public function build() { - $structureArray = array( - 'type' => 'array', - 'title' => $this->getLabel(), - 'section' => '1', - 'el' => $this->buildChildren($this->children) - ); - return $structureArray; - } + /** + * @param array $settings + * @return \FluidTYPO3\Flux\Form\Container\Section + */ + public static function create(array $settings = []) + { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); + /** @var Section */ + $section = $objectManager->get('FluidTYPO3\Flux\Form\Container\Section'); + foreach ($settings as $settingName => $settingValue) { + $setterMethodName = ObjectAccess::buildSetterMethodName($settingName); + if (true === method_exists($section, $setterMethodName)) { + ObjectAccess::setProperty($section, $settingName, $settingValue); + } + } + if (true === isset($settings['objects'])) { + foreach ($settings['objects'] as $fieldName => $objectSettings) { + if (false === isset($objectSettings['name'])) { + $objectSettings['name'] = $fieldName; + } + $object = Object::create($objectSettings); + $section->add($object); + } + } + return $section; + } + /** + * @return array + */ + public function build() + { + $structureArray = [ + 'type' => 'array', + 'title' => $this->getLabel(), + 'section' => '1', + 'el' => $this->buildChildren($this->children) + ]; + return $structureArray; + } } diff --git a/Classes/Form/Container/Sheet.php b/Classes/Form/Container/Sheet.php index 191109103..ae24b01e0 100644 --- a/Classes/Form/Container/Sheet.php +++ b/Classes/Form/Container/Sheet.php @@ -16,85 +16,91 @@ /** * Sheet */ -class Sheet extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface { +class Sheet extends AbstractFormContainer implements ContainerInterface, FieldContainerInterface +{ - /** - * @var string - */ - protected $description; + /** + * @var string + */ + protected $description; - /** - * @var string - */ - protected $shortDescription; + /** + * @var string + */ + protected $shortDescription; - /** - * @param string $shortDescription - * @return self - */ - public function setShortDescription($shortDescription) { - $this->shortDescription = $shortDescription; - return $this; - } + /** + * @param string $shortDescription + * @return self + */ + public function setShortDescription($shortDescription) + { + $this->shortDescription = $shortDescription; + return $this; + } - /** - * @return string - */ - public function getShortDescription() { - return $this->resolveLocalLanguageValueOfLabel($this->shortDescription, $this->getPath() . '.shortDescription'); - } + /** + * @return string + */ + public function getShortDescription() + { + return $this->resolveLocalLanguageValueOfLabel($this->shortDescription, $this->getPath() . '.shortDescription'); + } - /** - * @param string $description - * @return self - */ - public function setDescription($description) { - $this->description = $description; - return $this; - } + /** + * @param string $description + * @return self + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } - /** - * @return string - */ - public function getDescription() { - return $this->resolveLocalLanguageValueOfLabel($this->description, $this->getPath() . '.description'); - } + /** + * @return string + */ + public function getDescription() + { + return $this->resolveLocalLanguageValueOfLabel($this->description, $this->getPath() . '.description'); + } - /** - * @return array - */ - public function build() { - $sheetStructArray = array( - 'ROOT' => array( - 'sheetTitle' => $this->getLabel(), - 'sheetDescription' => $this->getDescription(), - 'sheetShortDescr' => $this->getShortDescription(), - 'type' => 'array', - 'el' => $this->buildChildren($this->getFields()) - ) - ); - return $sheetStructArray; - } - - /** - * @return \FluidTYPO3\Flux\Form\FieldInterface[] - */ - public function getFields() { - $fields = array(); - foreach ($this->children as $child) { - if (TRUE === $child->getEnabled()) { - $isSectionOrContainer = (TRUE === $child instanceof Section || TRUE === $child instanceof Container); - $isFieldEmulatorAndHasChildren = ($isSectionOrContainer && TRUE === $child->hasChildren()); - $isActualField = (TRUE === $child instanceof FieldInterface); - $isNotInsideObject = (FALSE === $child->isChildOfType('Object')); - $isNotInsideContainer = (FALSE === $child->isChildOfType('Container')); - if (TRUE === $isFieldEmulatorAndHasChildren || (TRUE === $isActualField && TRUE === $isNotInsideObject && TRUE === $isNotInsideContainer)) { - $name = $child->getName(); - $fields[$name] = $child; - } - } - } - return $fields; - } + /** + * @return array + */ + public function build() + { + $sheetStructArray = [ + 'ROOT' => [ + 'sheetTitle' => $this->getLabel(), + 'sheetDescription' => $this->getDescription(), + 'sheetShortDescr' => $this->getShortDescription(), + 'type' => 'array', + 'el' => $this->buildChildren($this->getFields()) + ] + ]; + return $sheetStructArray; + } + /** + * @return \FluidTYPO3\Flux\Form\FieldInterface[] + */ + public function getFields() + { + $fields = []; + foreach ($this->children as $child) { + if (true === $child->getEnabled()) { + $isSectionOrContainer = (true === $child instanceof Section || true === $child instanceof Container); + $isFieldEmulatorAndHasChildren = ($isSectionOrContainer && true === $child->hasChildren()); + $isActualField = (true === $child instanceof FieldInterface); + $isNotInsideObject = (false === $child->isChildOfType('Object')); + $isNotInsideContainer = (false === $child->isChildOfType('Container')); + if ($isFieldEmulatorAndHasChildren || ($isActualField && $isNotInsideObject && $isNotInsideContainer)) { + $name = $child->getName(); + $fields[$name] = $child; + } + } + } + return $fields; + } } diff --git a/Classes/Form/ContainerInterface.php b/Classes/Form/ContainerInterface.php index bf8aa232c..f9ac30dea 100644 --- a/Classes/Form/ContainerInterface.php +++ b/Classes/Form/ContainerInterface.php @@ -11,43 +11,43 @@ /** * ContainerInterface */ -interface ContainerInterface extends FormInterface { - - /** - * @param string $childName - * @param boolean $recursive - * @param string $requiredClass - * @return FormInterface|FALSE - */ - public function get($childName, $recursive = FALSE, $requiredClass = NULL); - - /** - * @param FormInterface $child - * @return FormInterface - */ - public function add(FormInterface $child); - - /** - * @param mixed $childOrChildName - * @return boolean - */ - public function has($childOrChildName); - - /** - * @param string $childName - * @return FormInterface|FALSE - */ - public function remove($childName); - - /** - * @param string $transform - * @return ContainerInterface - */ - public function setTransform($transform); - - /** - * @return string - */ - public function getTransform(); - +interface ContainerInterface extends FormInterface +{ + + /** + * @param string $childName + * @param boolean $recursive + * @param string $requiredClass + * @return FormInterface|FALSE + */ + public function get($childName, $recursive = false, $requiredClass = null); + + /** + * @param FormInterface $child + * @return FormInterface + */ + public function add(FormInterface $child); + + /** + * @param mixed $childOrChildName + * @return boolean + */ + public function has($childOrChildName); + + /** + * @param string $childName + * @return FormInterface|FALSE + */ + public function remove($childName); + + /** + * @param string $transform + * @return ContainerInterface + */ + public function setTransform($transform); + + /** + * @return string + */ + public function getTransform(); } diff --git a/Classes/Form/Field/Checkbox.php b/Classes/Form/Field/Checkbox.php index adcf185ad..9320f99ea 100644 --- a/Classes/Form/Field/Checkbox.php +++ b/Classes/Form/Field/Checkbox.php @@ -13,14 +13,15 @@ /** * Checkbox */ -class Checkbox extends AbstractFormField { - - /** - * @return array - */ - public function buildConfiguration() { - $fieldConfiguration = $this->prepareConfiguration('check'); - return $fieldConfiguration; - } +class Checkbox extends AbstractFormField +{ + /** + * @return array + */ + public function buildConfiguration() + { + $fieldConfiguration = $this->prepareConfiguration('check'); + return $fieldConfiguration; + } } diff --git a/Classes/Form/Field/ControllerActions.php b/Classes/Form/Field/ControllerActions.php index a237feb40..18fcfe4a9 100644 --- a/Classes/Form/Field/ControllerActions.php +++ b/Classes/Form/Field/ControllerActions.php @@ -16,437 +16,474 @@ /** * ControllerActions */ -class ControllerActions extends Select { - - /** - * Name of the Extbase extension that contains the Controller - * to parse, ex. MyExtension. In vendor based extensions use - * dot, ex. Vendor.MyExtension. - * - * @var string - */ - protected $controllerExtensionName; - - /** - * Name of the Extbase plugin that contains Controller - * definitions to parse, ex. MyPluginName. - * - * @var string - */ - protected $pluginName; - - /** - * Optional extra limiting of actions displayed - if used, - * field only displays actions for this controller name - ex - * Article(Controller) or FrontendUser(Controller) - the - * Controller part is implied. - * - * @var string - */ - protected $controllerName; - - /** - * Array of "ControllerName" => "csv,of,actions" which are - * allowed. If used, does not require the use of an - * ExtensionName and PluginName (will use the one specified - * in your current plugin automatically). - * - * @var array - */ - protected $actions = array(); - - /** - * Array of "ControllerName" => "csv,of,actions" which must - * be excluded. - * - * @var array - */ - protected $excludeActions = array(); - - /** - * A short string denoting that the method takes arguments, - * ex * (which should then be explained in the documentation - * for your extension about how to setup your plugins. - * - * @var string - */ - protected $prefixOnRequiredArguments = '*'; - - /** - * Separator for non-LLL action labels which have no manual - * label set. - * - * @var string - */ - protected $separator = '->'; - - /** - * Array of also allowed actions which will be allowed when - * a particular Controller+action is selected - but will not - * be displayed as selectable options. - * - * Example: defining an array such as this one: - * - * array( - * 'News' => array( - * 'list' => 'update,delete - * ), - * 'Category' => array( - * 'new' => 'create', - * 'list' => 'filter,search' - * ) - * ); - * - * Indicates that whenever the selector field is set to use - * the "News->list" SwitchableControllerAction, Extbase will - * in addition also allow the "News->update" and "News->delete" - * sub-actions, but will not display them. And when the value - * is "Category->new", Extbase will also allow "Category->create", - * and finally when value is "Category->list" the additional - * actions "Category->filter" and "Category->search" are allowed - * but not displayed as select options. - * - * This behavior can be compared to small "sub-plugins"; regular - * Extbase plugins will have a default action and additional - * allowed "Controller->action" combinations - whereas this - * method uses the selected value as a sort of "default" action - * and uses these sub actions much the same way an Extbase plugin - * would use the not-default actions configured in a plugin. - * - * Use of this feature is necessary if one or more of your - * SwitchableControllerAction selection values must allow more - * than one action to be used (which would be the case in for - * example a new/create, edit/update pair of actions). - * - * @var array - */ - protected $subActions = array(); - - /** - * Overridden getter: the name of a SwitchableControllerActions - * field is enforced - the TYPO3 core depends on this name. - * - * @return string - */ - public function getName() { - return 'switchableControllerActions'; - } - - /** - * Overridden setter: ignores any attempt to set another name - * for this field. - * - * @param string $name - * @return FormInterface - */ - public function setName($name) { - // intentional intermediate; avoids "unused argument" - $name = 'switchableControllerActions'; - $this->name = $name; - return $this; - } - - /** - * @param array $actions - * @return ControllerActions - */ - public function setActions($actions) { - $this->actions = $actions; - return $this; - } - - /** - * @return array - */ - public function getActions() { - return $this->actions; - } - - /** - * @param string $controllerName - * @return ControllerActions - */ - public function setControllerName($controllerName) { - $this->controllerName = $controllerName; - return $this; - } - - /** - * @return string - */ - public function getControllerName() { - return $this->controllerName; - } - /** - * @param array $excludeActions - * @return ControllerActions - */ - public function setExcludeActions($excludeActions) { - $this->excludeActions = (array) $excludeActions; - return $this; - } - - /** - * @return array - */ - public function getExcludeActions() { - return (array) $this->excludeActions; - } - - /** - * @param string $extensionName - * @return ControllerActions - */ - public function setControllerExtensionName($extensionName) { - $this->controllerExtensionName = $extensionName; - return $this; - } - - /** - * @return string - */ - public function getControllerExtensionName() { - return $this->controllerExtensionName; - } - - /** - * @param string $pluginName - * @return ControllerActions - */ - public function setPluginName($pluginName) { - $this->pluginName = $pluginName; - return $this; - } - - /** - * @return string - */ - public function getPluginName() { - return $this->pluginName; - } - - /** - * @param string $separator - * @return ControllerActions - */ - public function setSeparator($separator) { - $this->separator = $separator; - return $this; - } - - /** - * @return string - */ - public function getSeparator() { - return $this->separator; - } - - /** - * @param string $prefixOnRequiredArguments - * @return ControllerActions - */ - public function setPrefixOnRequiredArguments($prefixOnRequiredArguments) { - $this->prefixOnRequiredArguments = $prefixOnRequiredArguments; - return $this; - } - - /** - * @return string - */ - public function getPrefixOnRequiredArguments() { - return $this->prefixOnRequiredArguments; - } - - /** - * @param array $subActions - * @return ControllerActions - */ - public function setSubActions($subActions) { - $this->subActions = $subActions; - return $this; - } - - /** - * @return array - */ - public function getSubActions() { - return $this->subActions; - } - - /** - * @return array - */ - public function getItems() { - $basicItems = parent::getItems(); - if (0 < count($basicItems)) { - return $basicItems; - } else { - $actions = $this->getActions(); - if (0 === count($actions)) { - $actions = $this->getActionsForExtensionNameAndPluginName($this->controllerExtensionName, $this->pluginName); - } - return $this->buildItemsForActions($actions); - } - } - - /** - * Reads a list of allowed actions for $extensionName's plugin $pluginName - * - * @return array - */ - protected function getActionsForExtensionNameAndPluginName() { - $extensionName = $this->getControllerExtensionName(); - $extensionName = ExtensionNamingUtility::getExtensionName($extensionName); - $pluginName = $this->getPluginName(); - $actions = (array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers']; - foreach ($actions as $controllerName => $definitions) { - $actions[$controllerName] = $definitions['actions']; - } - return $actions; - } - - /** - * @param string $controllerName - * @return string|NULL - */ - protected function buildExpectedAndExistingControllerClassName($controllerName) { - $extensionName = $this->getControllerExtensionName(); - list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionName); - if (NULL !== $vendorName) { - $controllerClassName = $vendorName . '\\' . $extensionName . '\\Controller\\' . $controllerName . 'Controller'; - } else { - $controllerClassName = $extensionName . '\\Controller\\' . $controllerName . 'Controller'; - if (FALSE === class_exists($controllerClassName)) { - $controllerClassName = 'Tx_' . $extensionName . '_Controller_' . $controllerName . 'Controller'; - } - } - if (FALSE === class_exists($controllerClassName)) { - $controllerClassName = NULL; - } - return $controllerClassName; - } - - /** - * @param string $controllerName - * @param string $actionName - * @return string|NULL - */ - protected function getLabelForControllerAction($controllerName, $actionName) { - $localLanguageFileRelativePath = $this->getLocalLanguageFileRelativePath(); - $extensionName = $this->getControllerExtensionName(); - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); - $pluginName = $this->getPluginName(); - $separator = $this->getSeparator(); - $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); - $disableLocalLanguageLabels = $this->getDisableLocalLanguageLabels(); - $labelPath = strtolower($pluginName . '.' . $controllerName . '.' . $actionName); - $hasLocalLanguageFile = file_exists(ExtensionManagementUtility::extPath($extensionKey, $localLanguageFileRelativePath)); - $label = $actionName . $separator . $controllerName; - if (FALSE === $disableLocalLanguageLabels && TRUE === $hasLocalLanguageFile) { - $label = 'LLL:EXT:' . $extensionKey . $localLanguageFileRelativePath . ':' . $labelPath; - } elseif (TRUE === method_exists($controllerClassName, $actionName . 'Action') && TRUE === $disableLocalLanguageLabels) { - $methodReflection = $this->reflectAction($controllerName, $actionName); - $line = array_shift(explode("\n", trim($methodReflection->getDocComment(), "/*\n"))); - $line = trim(trim($line), '* '); - if (substr($line, 0, 1) !== '@') { - $label = $line; - } - } - return $label; - } - - /** - * @param string $controllerName - * @param string $actionName - * @return \ReflectionMethod - */ - protected function reflectAction($controllerName, $actionName) { - $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); - /** @var \ReflectionMethod $methodReflection */ - $controllerClassReflection = new \ReflectionClass($controllerClassName); - $methodReflection = $controllerClassReflection->getMethod($actionName . 'Action'); - return $methodReflection; - } - - - /** - * @param string $controllerName - * @param string $actionName - * @param string $label - * @return string - */ - protected function prefixLabel($controllerName, $actionName, $label) { - $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); - if (NULL === $controllerClassName || FALSE === method_exists($controllerClassName, $actionName . 'Action')) { - return $label; - } - $methodReflection = $this->reflectAction($controllerName, $actionName); - $hasRequiredArguments = (boolean) ($methodReflection->getNumberOfRequiredParameters() > 0); - $prefixOnRequiredArguments = $this->getPrefixOnRequiredArguments(); - $prefix = FALSE === empty($prefixOnRequiredArguments) && TRUE === $hasRequiredArguments ? $prefixOnRequiredArguments : NULL; - if (NULL !== $prefix) { - $label = $prefix . ' ' . $label; - } - return $label; - } - - /** - * @param mixed $actionList - * @return array - */ - protected function convertActionListToArray($actionList) { - if (FALSE === is_array($actionList)) { - return GeneralUtility::trimExplode(',', $actionList, TRUE); - } - return $actionList; - } - - /** - * Renders the TCA-style items array based on the Extbase FlexForm-style - * definitions of selectable actions (specified manually or read based on - * ViewHelper arguments) - * - * @param array $actions - * @return array - */ - protected function buildItemsForActions(array $actions) { - $separator = $this->getSeparator(); - $subActions = $this->getSubActions(); - $exclusions = $this->getExcludeActions(); - foreach ($exclusions as $controllerName => $controllerActionList) { - $exclusions[$controllerName] = $this->convertActionListToArray($controllerActionList); - } - $items = array(); - $limitByControllerName = $this->getControllerName(); - foreach ($actions as $controllerName => $controllerActionList) { - $controllerActions = $this->convertActionListToArray($controllerActionList); - $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); - if (NULL === $controllerClassName) { - continue; - } - foreach ($controllerActions as $actionName) { - if (TRUE === is_array($exclusions[$controllerName]) && TRUE === in_array($actionName, $exclusions[$controllerName])) { - continue; - } elseif ($limitByControllerName && $controllerName !== $limitByControllerName) { - continue; - } - $label = $this->getLabelForControllerAction($controllerName, $actionName); - $label = $this->prefixLabel($controllerName, $actionName, $label); - $actionKey = array($controllerName . $separator . $actionName); - if (isset($subActions[$controllerName][$actionName])) { - $subActionsArray = $this->convertActionListToArray($subActions[$controllerName][$actionName]); - foreach ($subActionsArray as $allowedActionName) { - $actionKey[] = $controllerName . $separator . $allowedActionName; - } - } - $values = array( - $label, - implode(';', $actionKey), - ); - array_push($items, $values); - } - } - return $items; - } - +class ControllerActions extends Select +{ + + /** + * Name of the Extbase extension that contains the Controller + * to parse, ex. MyExtension. In vendor based extensions use + * dot, ex. Vendor.MyExtension. + * + * @var string + */ + protected $controllerExtensionName; + + /** + * Name of the Extbase plugin that contains Controller + * definitions to parse, ex. MyPluginName. + * + * @var string + */ + protected $pluginName; + + /** + * Optional extra limiting of actions displayed - if used, + * field only displays actions for this controller name - ex + * Article(Controller) or FrontendUser(Controller) - the + * Controller part is implied. + * + * @var string + */ + protected $controllerName; + + /** + * Array of "ControllerName" => "csv,of,actions" which are + * allowed. If used, does not require the use of an + * ExtensionName and PluginName (will use the one specified + * in your current plugin automatically). + * + * @var array + */ + protected $actions = []; + + /** + * Array of "ControllerName" => "csv,of,actions" which must + * be excluded. + * + * @var array + */ + protected $excludeActions = []; + + /** + * A short string denoting that the method takes arguments, + * ex * (which should then be explained in the documentation + * for your extension about how to setup your plugins. + * + * @var string + */ + protected $prefixOnRequiredArguments = '*'; + + /** + * Separator for non-LLL action labels which have no manual + * label set. + * + * @var string + */ + protected $separator = '->'; + + /** + * Array of also allowed actions which will be allowed when + * a particular Controller+action is selected - but will not + * be displayed as selectable options. + * + * Example: defining an array such as this one: + * + * [ + * 'News' => [ + * 'list' => 'update,delete + * ), + * 'Category' => [ + * 'new' => 'create', + * 'list' => 'filter,search' + * ) + * ); + * + * Indicates that whenever the selector field is set to use + * the "News->list" SwitchableControllerAction, Extbase will + * in addition also allow the "News->update" and "News->delete" + * sub-actions, but will not display them. And when the value + * is "Category->new", Extbase will also allow "Category->create", + * and finally when value is "Category->list" the additional + * actions "Category->filter" and "Category->search" are allowed + * but not displayed as select options. + * + * This behavior can be compared to small "sub-plugins"; regular + * Extbase plugins will have a default action and additional + * allowed "Controller->action" combinations - whereas this + * method uses the selected value as a sort of "default" action + * and uses these sub actions much the same way an Extbase plugin + * would use the not-default actions configured in a plugin. + * + * Use of this feature is necessary if one or more of your + * SwitchableControllerAction selection values must allow more + * than one action to be used (which would be the case in for + * example a new/create, edit/update pair of actions). + * + * @var array + */ + protected $subActions = []; + + /** + * Overridden getter: the name of a SwitchableControllerActions + * field is enforced - the TYPO3 core depends on this name. + * + * @return string + */ + public function getName() + { + return 'switchableControllerActions'; + } + + /** + * Overridden setter: ignores any attempt to set another name + * for this field. + * + * @param string $name + * @return FormInterface + */ + public function setName($name) + { + // intentional intermediate; avoids "unused argument" + $name = 'switchableControllerActions'; + $this->name = $name; + return $this; + } + + /** + * @param array $actions + * @return ControllerActions + */ + public function setActions($actions) + { + $this->actions = $actions; + return $this; + } + + /** + * @return array + */ + public function getActions() + { + return $this->actions; + } + + /** + * @param string $controllerName + * @return ControllerActions + */ + public function setControllerName($controllerName) + { + $this->controllerName = $controllerName; + return $this; + } + + /** + * @return string + */ + public function getControllerName() + { + return $this->controllerName; + } + /** + * @param array $excludeActions + * @return ControllerActions + */ + public function setExcludeActions($excludeActions) + { + $this->excludeActions = (array) $excludeActions; + return $this; + } + + /** + * @return array + */ + public function getExcludeActions() + { + return (array) $this->excludeActions; + } + + /** + * @param string $extensionName + * @return ControllerActions + */ + public function setControllerExtensionName($extensionName) + { + $this->controllerExtensionName = $extensionName; + return $this; + } + + /** + * @return string + */ + public function getControllerExtensionName() + { + return $this->controllerExtensionName; + } + + /** + * @param string $pluginName + * @return ControllerActions + */ + public function setPluginName($pluginName) + { + $this->pluginName = $pluginName; + return $this; + } + + /** + * @return string + */ + public function getPluginName() + { + return $this->pluginName; + } + + /** + * @param string $separator + * @return ControllerActions + */ + public function setSeparator($separator) + { + $this->separator = $separator; + return $this; + } + + /** + * @return string + */ + public function getSeparator() + { + return $this->separator; + } + + /** + * @param string $prefixOnRequiredArguments + * @return ControllerActions + */ + public function setPrefixOnRequiredArguments($prefixOnRequiredArguments) + { + $this->prefixOnRequiredArguments = $prefixOnRequiredArguments; + return $this; + } + + /** + * @return string + */ + public function getPrefixOnRequiredArguments() + { + return $this->prefixOnRequiredArguments; + } + + /** + * @param array $subActions + * @return ControllerActions + */ + public function setSubActions($subActions) + { + $this->subActions = $subActions; + return $this; + } + + /** + * @return array + */ + public function getSubActions() + { + return $this->subActions; + } + + /** + * @return array + */ + public function getItems() + { + $basicItems = parent::getItems(); + if (0 < count($basicItems)) { + return $basicItems; + } else { + $actions = $this->getActions(); + if (0 === count($actions)) { + $actions = $this->getActionsForExtensionNameAndPluginName( + $this->controllerExtensionName, + $this->pluginName + ); + } + return $this->buildItemsForActions($actions); + } + } + + /** + * Reads a list of allowed actions for $extensionName's plugin $pluginName + * + * @return array + */ + protected function getActionsForExtensionNameAndPluginName() + { + $extensionName = $this->getControllerExtensionName(); + $extensionName = ExtensionNamingUtility::getExtensionName($extensionName); + $pluginName = $this->getPluginName(); + $actions = (array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'] + [$extensionName]['plugins'][$pluginName]['controllers']; + foreach ($actions as $controllerName => $definitions) { + $actions[$controllerName] = $definitions['actions']; + } + return $actions; + } + + /** + * @param string $controllerName + * @return string|NULL + */ + protected function buildExpectedAndExistingControllerClassName($controllerName) + { + $extensionName = $this->getControllerExtensionName(); + list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionName); + if (null !== $vendorName) { + $controllerClassName = sprintf( + '%s\\%s\\Controller\\%sController', + $vendorName, + $extensionName, + $controllerName + ); + } else { + $controllerClassName = $extensionName . '\\Controller\\' . $controllerName . 'Controller'; + if (false === class_exists($controllerClassName)) { + $controllerClassName = 'Tx_' . $extensionName . '_Controller_' . $controllerName . 'Controller'; + } + } + if (false === class_exists($controllerClassName)) { + $controllerClassName = null; + } + return $controllerClassName; + } + + /** + * @param string $controllerName + * @param string $actionName + * @return string|NULL + */ + protected function getLabelForControllerAction($controllerName, $actionName) + { + $localLanguageFileRelativePath = $this->getLocalLanguageFileRelativePath(); + $extensionName = $this->getControllerExtensionName(); + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionName); + $pluginName = $this->getPluginName(); + $separator = $this->getSeparator(); + $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); + $disableLocalLanguageLabels = $this->getDisableLocalLanguageLabels(); + $labelPath = strtolower($pluginName . '.' . $controllerName . '.' . $actionName); + $hasLocalLanguageFile = file_exists( + ExtensionManagementUtility::extPath($extensionKey, $localLanguageFileRelativePath) + ); + $label = $actionName . $separator . $controllerName; + if (false === $disableLocalLanguageLabels && true === $hasLocalLanguageFile) { + $label = 'LLL:EXT:' . $extensionKey . $localLanguageFileRelativePath . ':' . $labelPath; + } elseif (method_exists($controllerClassName, $actionName . 'Action') && true === $disableLocalLanguageLabels) { + $methodReflection = $this->reflectAction($controllerName, $actionName); + $line = array_shift(explode("\n", trim($methodReflection->getDocComment(), "/*\n"))); + $line = trim(trim($line), '* '); + if (substr($line, 0, 1) !== '@') { + $label = $line; + } + } + return $label; + } + + /** + * @param string $controllerName + * @param string $actionName + * @return \ReflectionMethod + */ + protected function reflectAction($controllerName, $actionName) + { + $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); + /** @var \ReflectionMethod $methodReflection */ + $controllerClassReflection = new \ReflectionClass($controllerClassName); + $methodReflection = $controllerClassReflection->getMethod($actionName . 'Action'); + return $methodReflection; + } + + + /** + * @param string $controllerName + * @param string $actionName + * @param string $label + * @return string + */ + protected function prefixLabel($controllerName, $actionName, $label) + { + $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); + if (null === $controllerClassName || false === method_exists($controllerClassName, $actionName . 'Action')) { + return $label; + } + $methodReflection = $this->reflectAction($controllerName, $actionName); + $hasRequiredArguments = (boolean) ($methodReflection->getNumberOfRequiredParameters() > 0); + $prefixOnRequiredArguments = $this->getPrefixOnRequiredArguments(); + $prefix = !empty($prefixOnRequiredArguments) && $hasRequiredArguments ? $prefixOnRequiredArguments : null; + if (null !== $prefix) { + $label = $prefix . ' ' . $label; + } + return $label; + } + + /** + * @param mixed $actionList + * @return array + */ + protected function convertActionListToArray($actionList) + { + if (false === is_array($actionList)) { + return GeneralUtility::trimExplode(',', $actionList, true); + } + return $actionList; + } + + /** + * Renders the TCA-style items array based on the Extbase FlexForm-style + * definitions of selectable actions (specified manually or read based on + * ViewHelper arguments) + * + * @param array $actions + * @return array + */ + protected function buildItemsForActions(array $actions) + { + $separator = $this->getSeparator(); + $subActions = $this->getSubActions(); + $exclusions = $this->getExcludeActions(); + foreach ($exclusions as $controllerName => $controllerActionList) { + $exclusions[$controllerName] = $this->convertActionListToArray($controllerActionList); + } + $items = []; + $limitByControllerName = $this->getControllerName(); + foreach ($actions as $controllerName => $controllerActionList) { + $controllerActions = $this->convertActionListToArray($controllerActionList); + $controllerClassName = $this->buildExpectedAndExistingControllerClassName($controllerName); + if (null === $controllerClassName) { + continue; + } + foreach ($controllerActions as $actionName) { + if (is_array($exclusions[$controllerName]) && in_array($actionName, $exclusions[$controllerName])) { + continue; + } elseif ($limitByControllerName && $controllerName !== $limitByControllerName) { + continue; + } + $label = $this->getLabelForControllerAction($controllerName, $actionName); + $label = $this->prefixLabel($controllerName, $actionName, $label); + $actionKey = [$controllerName . $separator . $actionName]; + if (isset($subActions[$controllerName][$actionName])) { + $subActionsArray = $this->convertActionListToArray($subActions[$controllerName][$actionName]); + foreach ($subActionsArray as $allowedActionName) { + $actionKey[] = $controllerName . $separator . $allowedActionName; + } + } + $values = [ + $label, + implode(';', $actionKey), + ]; + array_push($items, $values); + } + } + return $items; + } } diff --git a/Classes/Form/Field/Custom.php b/Classes/Form/Field/Custom.php index 96c123dc5..b90a0d55c 100644 --- a/Classes/Form/Field/Custom.php +++ b/Classes/Form/Field/Custom.php @@ -11,40 +11,43 @@ /** * Custom */ -class Custom extends UserFunction { +class Custom extends UserFunction +{ - /** - * @var \Closure - */ - protected $closure; + /** + * @var \Closure + */ + protected $closure; - /** - * @return array - */ - public function buildConfiguration() { - $fieldConfiguration = $this->prepareConfiguration('user'); - $fieldConfiguration['userFunc'] = 'FluidTYPO3\Flux\UserFunction\HtmlOutput->renderField'; - $fieldConfiguration['parameters'] = array( - 'closure' => $this->getClosure(), - 'arguments' => $this->getArguments(), - ); - return $fieldConfiguration; - } + /** + * @return array + */ + public function buildConfiguration() + { + $fieldConfiguration = $this->prepareConfiguration('user'); + $fieldConfiguration['userFunc'] = 'FluidTYPO3\Flux\UserFunction\HtmlOutput->renderField'; + $fieldConfiguration['parameters'] = [ + 'closure' => $this->getClosure(), + 'arguments' => $this->getArguments(), + ]; + return $fieldConfiguration; + } - /** - * @param \Closure $closure - * @return Custom - */ - public function setClosure(\Closure $closure) { - $this->closure = $closure; - return $this; - } - - /** - * @return \Closure|NULL - */ - public function getClosure() { - return $this->closure; - } + /** + * @param \Closure $closure + * @return Custom + */ + public function setClosure(\Closure $closure) + { + $this->closure = $closure; + return $this; + } + /** + * @return \Closure|NULL + */ + public function getClosure() + { + return $this->closure; + } } diff --git a/Classes/Form/Field/DateTime.php b/Classes/Form/Field/DateTime.php index be2b04102..6cc47cd6b 100644 --- a/Classes/Form/Field/DateTime.php +++ b/Classes/Form/Field/DateTime.php @@ -13,19 +13,20 @@ /** * DateTime */ -class DateTime extends Input implements FieldInterface { +class DateTime extends Input implements FieldInterface +{ - /** - * @var string - */ - protected $validate = 'date'; - - /** - * @param array $settings - * @return FieldInterface - */ - public static function create(array $settings = array()) { - return parent::create($settings); - } + /** + * @var string + */ + protected $validate = 'date'; + /** + * @param array $settings + * @return FieldInterface + */ + public static function create(array $settings = []) + { + return parent::create($settings); + } } diff --git a/Classes/Form/Field/File.php b/Classes/Form/Field/File.php index 22d6d629d..57e67aaa2 100644 --- a/Classes/Form/Field/File.php +++ b/Classes/Form/Field/File.php @@ -14,179 +14,193 @@ /** * File */ -class File extends AbstractMultiValueFormField { - - /** - * @var string - */ - protected $disallowed = ''; - - /** - * @var string - */ - protected $allowed = ''; - - /** - * @var integer - */ - protected $maxSize; - - /** - * @var string - */ - protected $uploadFolder; - - /** - * @var boolean - */ - protected $showThumbnails = FALSE; - - /** - * @var boolean - */ - protected $useFalRelation = FALSE; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('group'); - $configuration['disallowed'] = $this->getDisallowed(); - $configuration['allowed'] = $this->getAllowed(); - $configuration['max_size'] = $this->getMaxSize(); - $configuration['uploadfolder'] = $this->getUploadFolder(); - $configuration['show_thumbs'] = $this->getShowThumbnails(); - $configuration['internal_type'] = 'file'; - - if ($this->getUseFalRelation() === TRUE) { - $configuration['internal_type'] = 'db'; - $configuration['allowed'] = 'sys_file'; - $configuration['appearance'] = array( - 'elementBrowserAllowed' => $this->getAllowed() ? $this->getAllowed() : '*', - 'elementBrowserType' => 'file' - ); - } - return $configuration; - } - - /** - * Overrides parent method to ensure properly formatted - * default values for files - * - * @param mixed $default - * @return \FluidTYPO3\Flux\Form\FieldInterface - */ - public function setDefault($default) { - if (NULL !== $default) { - $files = array(); - $filePaths = GeneralUtility::trimExplode(',', $default); - foreach ($filePaths as $path) { - if (FALSE === strpos($path, '|')) { - $files[] = $path . '|' . rawurlencode($path); - } else { - $files[] = $path; - } - } - $default = implode(',', $files); - } - $this->default = $default; - return $this; - } - - /** - * @param string $allowed - * @return File - */ - public function setAllowed($allowed) { - $this->allowed = $allowed; - return $this; - } - - /** - * @return string - */ - public function getAllowed() { - return $this->allowed; - } - - /** - * @param string $disallowed - * @return File - */ - public function setDisallowed($disallowed) { - $this->disallowed = $disallowed; - return $this; - } - - /** - * @return string - */ - public function getDisallowed() { - return $this->disallowed; - } - - /** - * @param integer $maxSize - * @return File - */ - public function setMaxSize($maxSize) { - $this->maxSize = $maxSize; - return $this; - } - - /** - * @return integer - */ - public function getMaxSize() { - return $this->maxSize; - } - - /** - * @param string $uploadFolder - * @return File - */ - public function setUploadFolder($uploadFolder) { - $this->uploadFolder = $uploadFolder; - return $this; - } - - /** - * @return string - */ - public function getUploadFolder() { - return $this->uploadFolder; - } - - /** - * @param boolean $showThumbnails - * @return File - */ - public function setShowThumbnails($showThumbnails) { - $this->showThumbnails = (boolean) $showThumbnails; - return $this; - } - - /** - * @return boolean - */ - public function getShowThumbnails() { - return (boolean) $this->showThumbnails; - } - - /** - * @param boolean $useFalRelation - * @return File - */ - public function setUseFalRelation($useFalRelation) { - $this->useFalRelation = $useFalRelation; - return $this; - } - - /** - * @return boolean - */ - public function getUseFalRelation() { - return $this->useFalRelation; - } - +class File extends AbstractMultiValueFormField +{ + + /** + * @var string + */ + protected $disallowed = ''; + + /** + * @var string + */ + protected $allowed = ''; + + /** + * @var integer + */ + protected $maxSize; + + /** + * @var string + */ + protected $uploadFolder; + + /** + * @var boolean + */ + protected $showThumbnails = false; + + /** + * @var boolean + */ + protected $useFalRelation = false; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('group'); + $configuration['disallowed'] = $this->getDisallowed(); + $configuration['allowed'] = $this->getAllowed(); + $configuration['max_size'] = $this->getMaxSize(); + $configuration['uploadfolder'] = $this->getUploadFolder(); + $configuration['show_thumbs'] = $this->getShowThumbnails(); + $configuration['internal_type'] = 'file'; + + if ($this->getUseFalRelation() === true) { + $configuration['internal_type'] = 'db'; + $configuration['allowed'] = 'sys_file'; + $configuration['appearance'] = [ + 'elementBrowserAllowed' => $this->getAllowed() ? $this->getAllowed() : '*', + 'elementBrowserType' => 'file' + ]; + } + return $configuration; + } + + /** + * Overrides parent method to ensure properly formatted + * default values for files + * + * @param mixed $default + * @return \FluidTYPO3\Flux\Form\FieldInterface + */ + public function setDefault($default) + { + if (null !== $default) { + $files = []; + $filePaths = GeneralUtility::trimExplode(',', $default); + foreach ($filePaths as $path) { + if (false === strpos($path, '|')) { + $files[] = $path . '|' . rawurlencode($path); + } else { + $files[] = $path; + } + } + $default = implode(',', $files); + } + $this->default = $default; + return $this; + } + + /** + * @param string $allowed + * @return File + */ + public function setAllowed($allowed) + { + $this->allowed = $allowed; + return $this; + } + + /** + * @return string + */ + public function getAllowed() + { + return $this->allowed; + } + + /** + * @param string $disallowed + * @return File + */ + public function setDisallowed($disallowed) + { + $this->disallowed = $disallowed; + return $this; + } + + /** + * @return string + */ + public function getDisallowed() + { + return $this->disallowed; + } + + /** + * @param integer $maxSize + * @return File + */ + public function setMaxSize($maxSize) + { + $this->maxSize = $maxSize; + return $this; + } + + /** + * @return integer + */ + public function getMaxSize() + { + return $this->maxSize; + } + + /** + * @param string $uploadFolder + * @return File + */ + public function setUploadFolder($uploadFolder) + { + $this->uploadFolder = $uploadFolder; + return $this; + } + + /** + * @return string + */ + public function getUploadFolder() + { + return $this->uploadFolder; + } + + /** + * @param boolean $showThumbnails + * @return File + */ + public function setShowThumbnails($showThumbnails) + { + $this->showThumbnails = (boolean) $showThumbnails; + return $this; + } + + /** + * @return boolean + */ + public function getShowThumbnails() + { + return (boolean) $this->showThumbnails; + } + + /** + * @param boolean $useFalRelation + * @return File + */ + public function setUseFalRelation($useFalRelation) + { + $this->useFalRelation = $useFalRelation; + return $this; + } + + /** + * @return boolean + */ + public function getUseFalRelation() + { + return $this->useFalRelation; + } } diff --git a/Classes/Form/Field/Flex.php b/Classes/Form/Field/Flex.php index 86e500550..70cc492c8 100644 --- a/Classes/Form/Field/Flex.php +++ b/Classes/Form/Field/Flex.php @@ -14,14 +14,15 @@ /** * Flex */ -class Flex extends AbstractFormField implements FieldInterface { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('flex'); - return $configuration; - } +class Flex extends AbstractFormField implements FieldInterface +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('flex'); + return $configuration; + } } diff --git a/Classes/Form/Field/Inline.php b/Classes/Form/Field/Inline.php index a2f11d2ad..be641032a 100644 --- a/Classes/Form/Field/Inline.php +++ b/Classes/Form/Field/Inline.php @@ -13,14 +13,15 @@ /** * Inline */ -class Inline extends AbstractInlineFormField { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('inline'); - return $configuration; - } +class Inline extends AbstractInlineFormField +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('inline'); + return $configuration; + } } diff --git a/Classes/Form/Field/Inline/Fal.php b/Classes/Form/Field/Inline/Fal.php index 50b58d115..0aa66ab51 100644 --- a/Classes/Form/Field/Inline/Fal.php +++ b/Classes/Form/Field/Inline/Fal.php @@ -14,163 +14,166 @@ /** * Fal */ -class Fal extends AbstractInlineFormField { - - const DEFAULT_TABLE = 'sys_file_reference'; - const DEFAULT_FOREIGN_FIELD = 'uid_foreign'; - const DEFAULT_FOREIGN_TABLE_FIELD = 'tablenames'; - const DEFAULT_FOREIGN_LABEL = 'uid_local'; - const DEFAULT_FOREIGN_SELECTOR = 'uid_local'; - const DEFAULT_FOREIGN_SORTBY = 'sorting_foreign'; - const DEFAULT_USE_SORTABLE = TRUE; - const DEFAULT_LEVEL_LINKS_POSITION = 'both'; - const DEFAULT_LOCALIZATION_MODE = 'select'; - const DEFAULT_LOCALIZE_CHILDREN_AT_PARENT_LOCALIZATION = TRUE; - const DEFAULT_NEW_RECORD_LINK_ADD_TITLE = TRUE; - const DEFAULT_CREATE_NEW_RELATION_LINK_TITLE = 'LLL:EXT:lang/locallang_core.xlf:cm.createNewRelation'; - - /** - * @var string - */ - protected $table = self::DEFAULT_TABLE; - - /** - * The foreign_field is the field of the child record pointing to the - * parent record. This defines where to store the uid of the parent record. - * - * @var string - */ - protected $foreignField = self::DEFAULT_FOREIGN_FIELD; - - /** - * The field of the child record pointing to the parent record. This defines - * where to store the table name of the parent record. On setting this - * configuration key together with foreign_field, the child record knows what - * its parent record is – so the child record could also be used on other - * parent tables. - * - * @var string - */ - protected $foreignTableField = self::DEFAULT_FOREIGN_TABLE_FIELD; - - /** - * If set, it overrides the label set in TCA[foreign_table]['ctrl']['label'] - * for the foreign table view. - * - * @var string - */ - protected $foreignLabel = self::DEFAULT_FOREIGN_LABEL; - - /** - * A selector is used to show all possible child records that could be used - * to create a relation with the parent record. It will be rendered as a - * multi-select-box. On clicking on an item inside the selector a new relation - * is created. The foreign_selector points to a field of the foreign_table that - * is responsible for providing a selector-box – this field on the foreign_table - * usually has the type "select" and also has a "foreign_table" defined. - * - * @var string - */ - protected $foreignSelector = self::DEFAULT_FOREIGN_SELECTOR; - - /** - * Defines a field on the child record (or on the intermediate table) that - * stores the manual sorting information. - * - * @var string - */ - protected $foreignSortby = self::DEFAULT_FOREIGN_SORTBY; - - /** - * Allow manual sorting of child objects. - * - * @var boolean - */ - protected $useSortable = self::DEFAULT_USE_SORTABLE; - - /** - * Associative array with the keys 'info', 'new', 'dragdrop', 'sort', 'hide', delete' - * and 'localize'. Set either one to TRUE or FALSE to show or hide it. - * - * @var array - */ - protected $enabledControls = array( - Form::CONTROL_INFO => FALSE, - Form::CONTROL_NEW => FALSE, - Form::CONTROL_DRAGDROP => TRUE, - Form::CONTROL_SORT => TRUE, - Form::CONTROL_HIDE => TRUE, - Form::CONTROL_DELETE => TRUE, - Form::CONTROL_LOCALISE => TRUE, - ); - - /** - * @var array - */ - protected $headerThumbnail = array( - 'field' => 'uid_local', - 'width' => '64', - 'height' => '64', - ); - - /** - * @var string - */ - protected $levelLinksPosition = self::DEFAULT_LEVEL_LINKS_POSITION; - - /** - * Set whether children can be localizable ('select') or just inherit from - * default language ('keep'). Default is empty, meaning no particular behavior. - * - * @var string - */ - protected $localizationMode = self::DEFAULT_LOCALIZATION_MODE; - - /** - * Defines whether children should be localized when the localization of the - * parent gets created. - * - * @var boolean - */ - protected $localizeChildrenAtParentLocalization = self::DEFAULT_LOCALIZE_CHILDREN_AT_PARENT_LOCALIZATION; - - /** - * Add the foreign table's title to the 'Add new' link (ie. 'Add new (sometable)') - * - * @var boolean - */ - protected $newRecordLinkAddTitle = self::DEFAULT_NEW_RECORD_LINK_ADD_TITLE; - - /** - * Label of 'create new relation' button - * - * @var string - */ - protected $createNewRelationLinkTitle = self::DEFAULT_CREATE_NEW_RELATION_LINK_TITLE; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('inline'); - $configuration['appearance']['createNewRelationLinkTitle'] = $this->getCreateNewRelationLinkTitle(); - return $configuration; - } - - /** - * @return string - */ - public function getCreateNewRelationLinkTitle() { - return $this->createNewRelationLinkTitle; - } - - /** - * @param string $createNewRelationLinkTitle - * @return Fal - */ - public function setCreateNewRelationLinkTitle($createNewRelationLinkTitle) { - $this->createNewRelationLinkTitle = $createNewRelationLinkTitle; - return $this; - } - +class Fal extends AbstractInlineFormField +{ + + const DEFAULT_TABLE = 'sys_file_reference'; + const DEFAULT_FOREIGN_FIELD = 'uid_foreign'; + const DEFAULT_FOREIGN_TABLE_FIELD = 'tablenames'; + const DEFAULT_FOREIGN_LABEL = 'uid_local'; + const DEFAULT_FOREIGN_SELECTOR = 'uid_local'; + const DEFAULT_FOREIGN_SORTBY = 'sorting_foreign'; + const DEFAULT_USE_SORTABLE = true; + const DEFAULT_LEVEL_LINKS_POSITION = 'both'; + const DEFAULT_LOCALIZATION_MODE = 'select'; + const DEFAULT_LOCALIZE_CHILDREN_AT_PARENT_LOCALIZATION = true; + const DEFAULT_NEW_RECORD_LINK_ADD_TITLE = true; + const DEFAULT_CREATE_NEW_RELATION_LINK_TITLE = 'LLL:EXT:lang/locallang_core.xlf:cm.createNewRelation'; + + /** + * @var string + */ + protected $table = self::DEFAULT_TABLE; + + /** + * The foreign_field is the field of the child record pointing to the + * parent record. This defines where to store the uid of the parent record. + * + * @var string + */ + protected $foreignField = self::DEFAULT_FOREIGN_FIELD; + + /** + * The field of the child record pointing to the parent record. This defines + * where to store the table name of the parent record. On setting this + * configuration key together with foreign_field, the child record knows what + * its parent record is – so the child record could also be used on other + * parent tables. + * + * @var string + */ + protected $foreignTableField = self::DEFAULT_FOREIGN_TABLE_FIELD; + + /** + * If set, it overrides the label set in TCA[foreign_table]['ctrl']['label'] + * for the foreign table view. + * + * @var string + */ + protected $foreignLabel = self::DEFAULT_FOREIGN_LABEL; + + /** + * A selector is used to show all possible child records that could be used + * to create a relation with the parent record. It will be rendered as a + * multi-select-box. On clicking on an item inside the selector a new relation + * is created. The foreign_selector points to a field of the foreign_table that + * is responsible for providing a selector-box – this field on the foreign_table + * usually has the type "select" and also has a "foreign_table" defined. + * + * @var string + */ + protected $foreignSelector = self::DEFAULT_FOREIGN_SELECTOR; + + /** + * Defines a field on the child record (or on the intermediate table) that + * stores the manual sorting information. + * + * @var string + */ + protected $foreignSortby = self::DEFAULT_FOREIGN_SORTBY; + + /** + * Allow manual sorting of child objects. + * + * @var boolean + */ + protected $useSortable = self::DEFAULT_USE_SORTABLE; + + /** + * Associative array with the keys 'info', 'new', 'dragdrop', 'sort', 'hide', delete' + * and 'localize'. Set either one to TRUE or FALSE to show or hide it. + * + * @var array + */ + protected $enabledControls = [ + Form::CONTROL_INFO => false, + Form::CONTROL_NEW => false, + Form::CONTROL_DRAGDROP => true, + Form::CONTROL_SORT => true, + Form::CONTROL_HIDE => true, + Form::CONTROL_DELETE => true, + Form::CONTROL_LOCALISE => true, + ]; + + /** + * @var array + */ + protected $headerThumbnail = [ + 'field' => 'uid_local', + 'width' => '64', + 'height' => '64', + ]; + + /** + * @var string + */ + protected $levelLinksPosition = self::DEFAULT_LEVEL_LINKS_POSITION; + + /** + * Set whether children can be localizable ('select') or just inherit from + * default language ('keep'). Default is empty, meaning no particular behavior. + * + * @var string + */ + protected $localizationMode = self::DEFAULT_LOCALIZATION_MODE; + + /** + * Defines whether children should be localized when the localization of the + * parent gets created. + * + * @var boolean + */ + protected $localizeChildrenAtParentLocalization = self::DEFAULT_LOCALIZE_CHILDREN_AT_PARENT_LOCALIZATION; + + /** + * Add the foreign table's title to the 'Add new' link (ie. 'Add new (sometable)') + * + * @var boolean + */ + protected $newRecordLinkAddTitle = self::DEFAULT_NEW_RECORD_LINK_ADD_TITLE; + + /** + * Label of 'create new relation' button + * + * @var string + */ + protected $createNewRelationLinkTitle = self::DEFAULT_CREATE_NEW_RELATION_LINK_TITLE; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('inline'); + $configuration['appearance']['createNewRelationLinkTitle'] = $this->getCreateNewRelationLinkTitle(); + return $configuration; + } + + /** + * @return string + */ + public function getCreateNewRelationLinkTitle() + { + return $this->createNewRelationLinkTitle; + } + + /** + * @param string $createNewRelationLinkTitle + * @return Fal + */ + public function setCreateNewRelationLinkTitle($createNewRelationLinkTitle) + { + $this->createNewRelationLinkTitle = $createNewRelationLinkTitle; + return $this; + } } diff --git a/Classes/Form/Field/Input.php b/Classes/Form/Field/Input.php index c5540c727..01335e65e 100644 --- a/Classes/Form/Field/Input.php +++ b/Classes/Form/Field/Input.php @@ -15,132 +15,143 @@ /** * Input */ -class Input extends AbstractFormField implements FieldInterface { - - /** - * @var integer - */ - protected $size = 32; - - /** - * @var integer - */ - protected $maxCharacters; - - /** - * @var integer - */ - protected $minimum; - - /** - * @var integer - */ - protected $maximum; - - /** - * @var string - */ - protected $placeholder; - - /** - * @return array - */ - public function buildConfiguration() { - $minimum = $this->getMinimum(); - $maximum = $this->getMaximum(); - $validate = $this->getValidate(); - $configuration = $this->prepareConfiguration('input'); - $configuration['placeholder'] = $this->getPlaceholder(); - $configuration['size'] = $this->getSize(); - $configuration['max'] = $this->getMaxCharacters(); - $configuration['eval'] = $validate; - if (NULL !== $minimum && NULL !== $maximum && in_array('int', GeneralUtility::trimExplode(',', $validate))) { - $configuration['range'] = array( - 'lower' => $minimum, - 'upper' => $maximum - ); - } - return $configuration; - } - - /** - * @param integer $maxCharacters - * @return Input - */ - public function setMaxCharacters($maxCharacters) { - $this->maxCharacters = $maxCharacters; - return $this; - } - - /** - * @return integer - */ - public function getMaxCharacters() { - return $this->maxCharacters; - } - - /** - * @param integer $maximum - * @return Input - */ - public function setMaximum($maximum) { - $this->maximum = $maximum; - return $this; - } - - /** - * @return integer - */ - public function getMaximum() { - return $this->maximum; - } - - /** - * @param integer $minimum - * @return Input - */ - public function setMinimum($minimum) { - $this->minimum = $minimum; - return $this; - } - - /** - * @return integer - */ - public function getMinimum() { - return $this->minimum; - } - - /** - * @param string $placeholder - * @return Input - */ - public function setPlaceholder($placeholder) { - $this->placeholder = $placeholder; - return $this; - } - - /** - * @return string - */ - public function getPlaceholder() { - return $this->placeholder; - } - - /** - * @param integer $size - * @return Input - */ - public function setSize($size) { - $this->size = $size; - return $this; - } - - /** - * @return integer - */ - public function getSize() { - return $this->size; - } - +class Input extends AbstractFormField implements FieldInterface +{ + + /** + * @var integer + */ + protected $size = 32; + + /** + * @var integer + */ + protected $maxCharacters; + + /** + * @var integer + */ + protected $minimum; + + /** + * @var integer + */ + protected $maximum; + + /** + * @var string + */ + protected $placeholder; + + /** + * @return array + */ + public function buildConfiguration() + { + $minimum = $this->getMinimum(); + $maximum = $this->getMaximum(); + $validate = $this->getValidate(); + $configuration = $this->prepareConfiguration('input'); + $configuration['placeholder'] = $this->getPlaceholder(); + $configuration['size'] = $this->getSize(); + $configuration['max'] = $this->getMaxCharacters(); + $configuration['eval'] = $validate; + if (null !== $minimum && null !== $maximum && in_array('int', GeneralUtility::trimExplode(',', $validate))) { + $configuration['range'] = [ + 'lower' => $minimum, + 'upper' => $maximum + ]; + } + return $configuration; + } + + /** + * @param integer $maxCharacters + * @return Input + */ + public function setMaxCharacters($maxCharacters) + { + $this->maxCharacters = $maxCharacters; + return $this; + } + + /** + * @return integer + */ + public function getMaxCharacters() + { + return $this->maxCharacters; + } + + /** + * @param integer $maximum + * @return Input + */ + public function setMaximum($maximum) + { + $this->maximum = $maximum; + return $this; + } + + /** + * @return integer + */ + public function getMaximum() + { + return $this->maximum; + } + + /** + * @param integer $minimum + * @return Input + */ + public function setMinimum($minimum) + { + $this->minimum = $minimum; + return $this; + } + + /** + * @return integer + */ + public function getMinimum() + { + return $this->minimum; + } + + /** + * @param string $placeholder + * @return Input + */ + public function setPlaceholder($placeholder) + { + $this->placeholder = $placeholder; + return $this; + } + + /** + * @return string + */ + public function getPlaceholder() + { + return $this->placeholder; + } + + /** + * @param integer $size + * @return Input + */ + public function setSize($size) + { + $this->size = $size; + return $this; + } + + /** + * @return integer + */ + public function getSize() + { + return $this->size; + } } diff --git a/Classes/Form/Field/MultiRelation.php b/Classes/Form/Field/MultiRelation.php index 84ba8e877..176d486e4 100644 --- a/Classes/Form/Field/MultiRelation.php +++ b/Classes/Form/Field/MultiRelation.php @@ -13,16 +13,17 @@ /** * MultiRelation */ -class MultiRelation extends AbstractRelationFormField { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('group'); - $configuration['internal_type'] = 'db'; - $configuration['allowed'] = $this->getTable(); - return $configuration; - } +class MultiRelation extends AbstractRelationFormField +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('group'); + $configuration['internal_type'] = 'db'; + $configuration['allowed'] = $this->getTable(); + return $configuration; + } } diff --git a/Classes/Form/Field/None.php b/Classes/Form/Field/None.php index 22065d89f..832f6f412 100644 --- a/Classes/Form/Field/None.php +++ b/Classes/Form/Field/None.php @@ -14,36 +14,39 @@ /** * None */ -class None extends AbstractFormField implements FieldInterface { - - /** - * @var integer - */ - protected $size = 12; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('none'); - $configuration['size'] = $this->getSize(); - return $configuration; - } - - /** - * @param integer $size - * @return None - */ - public function setSize($size) { - $this->size = $size; - return $this; - } - - /** - * @return integer - */ - public function getSize() { - return $this->size; - } - +class None extends AbstractFormField implements FieldInterface +{ + + /** + * @var integer + */ + protected $size = 12; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('none'); + $configuration['size'] = $this->getSize(); + return $configuration; + } + + /** + * @param integer $size + * @return None + */ + public function setSize($size) + { + $this->size = $size; + return $this; + } + + /** + * @return integer + */ + public function getSize() + { + return $this->size; + } } diff --git a/Classes/Form/Field/Passthrough.php b/Classes/Form/Field/Passthrough.php index 893f0cf19..11e1409b1 100644 --- a/Classes/Form/Field/Passthrough.php +++ b/Classes/Form/Field/Passthrough.php @@ -14,14 +14,15 @@ /** * Passthrough */ -class Passthrough extends AbstractFormField implements FieldInterface { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('passthrough'); - return $configuration; - } +class Passthrough extends AbstractFormField implements FieldInterface +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('passthrough'); + return $configuration; + } } diff --git a/Classes/Form/Field/Radio.php b/Classes/Form/Field/Radio.php index f3504e47d..02b0b18d1 100644 --- a/Classes/Form/Field/Radio.php +++ b/Classes/Form/Field/Radio.php @@ -17,15 +17,16 @@ * @package Flux * @subpackage Form\Field */ -class Radio extends Select { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = parent::prepareConfiguration('radio'); - $configuration['items'] = $this->getItems(); - return $configuration; - } +class Radio extends Select +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = parent::prepareConfiguration('radio'); + $configuration['items'] = $this->getItems(); + return $configuration; + } } diff --git a/Classes/Form/Field/Relation.php b/Classes/Form/Field/Relation.php index 72f46e194..0fbe42893 100644 --- a/Classes/Form/Field/Relation.php +++ b/Classes/Form/Field/Relation.php @@ -13,14 +13,15 @@ /** * Relation */ -class Relation extends AbstractRelationFormField { - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('select'); - return $configuration; - } +class Relation extends AbstractRelationFormField +{ + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('select'); + return $configuration; + } } diff --git a/Classes/Form/Field/Select.php b/Classes/Form/Field/Select.php index 56f143962..7a8a0ec55 100755 --- a/Classes/Form/Field/Select.php +++ b/Classes/Form/Field/Select.php @@ -16,206 +16,222 @@ /** * Select */ -class Select extends AbstractMultiValueFormField { - - /** - * Mixed - string (CSV), Traversable or array of items. Format of key/value - * pairs is also optional. For single-dim arrays, key becomes option value - * and each member value becomes label. For multidim/Traversable each member - * is inspected; if it is a raw value it is used for both value and label, - * if it is a scalar value the first item is used as value and the second - * as label. - * - * @var mixed - */ - protected $items = NULL; - - /** - * If not-FALSE, adds one empty option/value pair to the generated selector - * box and tries to use this property's value (cast to string) as label. - * - * @var boolean|string - */ - protected $emptyOption = FALSE; - - /** - * If set to TRUE, Flux will attempt to translate the LLL labels of items - * provided as CSV values, e.g. items "foo,bar" would try to resolve LLL - * values for "LLL:EXT:myext/Resources/Private/Languages/locallang.xlf:foo" - * and "LLL:EXT:myext/Resources/Private/Languages/locallang.xlf:bar" to be - * used as value labels. - * - * @var boolean - */ - protected $translateCsvItems = FALSE; - - /** - * Special rendering type of this component - supports all values normally - * supported by TCA of the "select" field type. - * - * @var string - * @see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Select/Index.html#rendertype - */ - protected $renderType = 'selectSingle'; - - /** - * Displays option icons as table beneath the select. - * - * @var boolean - * @see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Select/Index.html#showicontable - */ - protected $showIconTable = FALSE; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = parent::prepareConfiguration('select'); - $configuration['items'] = $this->getItems(); - $configuration['showIconTable'] = $this->getShowIconTable(); - return $configuration; - } - - /** - * @param array $items - * @return Select - */ - public function setItems($items) { - $this->items = $items; - return $this; - } - - /** - * @return boolean - */ - public function getTranslateCsvItems() { - return $this->translateCsvItems; - } - - /** - * @param boolean $translateCsvItems - * @return Select - */ - public function setTranslateCsvItems($translateCsvItems) { - $this->translateCsvItems = $translateCsvItems; - return $this; - } - - /** - * @return array - */ - public function getItems() { - $items = array(); - if (TRUE === $this->items instanceof QueryInterface) { - $items = $this->addOptionsFromResults($this->items); - } elseif (TRUE === is_string($this->items)) { - $itemNames = GeneralUtility::trimExplode(',', $this->items); - if (!$this->getTranslateCsvItems()) { - foreach ($itemNames as $itemName) { - array_push($items, array($itemName, $itemName)); - } - } else { - foreach ($itemNames as $itemName) { - $resolvedLabel = $this->resolveLocalLanguageValueOfLabel('', $this->getPath() . '.option.' . $itemName); - array_push($items, array($resolvedLabel, $itemName)); - } - } - } elseif (TRUE === is_array($this->items) || TRUE === $this->items instanceof \Traversable) { - foreach ($this->items as $itemIndex => $itemValue) { - if (TRUE === is_array($itemValue) || TRUE === $itemValue instanceof \ArrayObject) { - array_push($items, $itemValue); - } else { - array_push($items, array($itemValue, $itemIndex)); - } - } - } - $emptyOption = $this->getEmptyOption(); - if (FALSE !== $emptyOption) { - array_unshift($items, array($emptyOption, '')); - } - return $items; - } - - /** - * @param boolean|string $emptyOption - * @return Select - */ - public function setEmptyOption($emptyOption) { - $this->emptyOption = $emptyOption; - return $this; - } - - /** - * @return boolean|string - */ - public function getEmptyOption() { - return $this->emptyOption; - } - - /** - * @return string - */ - public function getRenderType() { - return $this->renderType; - } - - /** - * @param string $renderType - * @return void - */ - public function setRenderType($renderType) { - $this->renderType = $renderType; - } - - /** - * @param QueryInterface $query - * @return array - */ - protected function addOptionsFromResults(QueryInterface $query) { - $items = array(); - $results = $query->execute(); - $type = $query->getType(); - $table = strtolower(str_replace('\\', '_', $type)); - $propertyName = $this->getLabelPropertyName($table, $type); - foreach ($results as $result) { - $uid = $result->getUid(); - array_push($items, array(ObjectAccess::getProperty($result, $propertyName), $uid)); - } - return $items; - } - - /** - * @param string $table - * @param string $type - * @return string - */ - protected function getLabelPropertyName($table, $type) { - $typoScript = $this->getConfigurationService()->getAllTypoScript(); - if (TRUE === isset($typoScript['config']['tx_extbase']['persistence']['classes'][$type])) { - $mapping = $typoScript['config']['tx_extbase']['persistence']['classes'][$type]; - if (TRUE === isset($mapping['mapping']['tableName'])) { - $table = $mapping['mapping']['tableName']; - } - } - $labelField = $GLOBALS['TCA'][$table]['ctrl']['label']; - $propertyName = GeneralUtility::underscoredToLowerCamelCase($labelField); - return $propertyName; - } - - /** - * @return boolean - */ - public function getShowIconTable() { - return $this->showIconTable; - } - - /** - * @param boolean $showIconTable - * @return Select - */ - public function setShowIconTable($showIconTable) { - $this->showIconTable = $showIconTable; - return $this; - } - +class Select extends AbstractMultiValueFormField +{ + + /** + * Mixed - string (CSV), Traversable or array of items. Format of key/value + * pairs is also optional. For single-dim arrays, key becomes option value + * and each member value becomes label. For multidim/Traversable each member + * is inspected; if it is a raw value it is used for both value and label, + * if it is a scalar value the first item is used as value and the second + * as label. + * + * @var mixed + */ + protected $items = null; + + /** + * If not-FALSE, adds one empty option/value pair to the generated selector + * box and tries to use this property's value (cast to string) as label. + * + * @var boolean|string + */ + protected $emptyOption = false; + + /** + * If set to TRUE, Flux will attempt to translate the LLL labels of items + * provided as CSV values, e.g. items "foo,bar" would try to resolve LLL + * values for "LLL:EXT:myext/Resources/Private/Languages/locallang.xlf:foo" + * and "LLL:EXT:myext/Resources/Private/Languages/locallang.xlf:bar" to be + * used as value labels. + * + * @var boolean + */ + protected $translateCsvItems = false; + + /** + * Special rendering type of this component - supports all values normally + * supported by TCA of the "select" field type. + * + * @var string + * @see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Select/Index.html#rendertype + */ + protected $renderType = 'selectSingle'; + + /** + * Displays option icons as table beneath the select. + * + * @var boolean + * @see https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Select/Index.html#showicontable + */ + protected $showIconTable = false; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = parent::prepareConfiguration('select'); + $configuration['items'] = $this->getItems(); + $configuration['showIconTable'] = $this->getShowIconTable(); + return $configuration; + } + + /** + * @param array $items + * @return Select + */ + public function setItems($items) + { + $this->items = $items; + return $this; + } + + /** + * @return boolean + */ + public function getTranslateCsvItems() + { + return $this->translateCsvItems; + } + + /** + * @param boolean $translateCsvItems + * @return Select + */ + public function setTranslateCsvItems($translateCsvItems) + { + $this->translateCsvItems = $translateCsvItems; + return $this; + } + + /** + * @return array + */ + public function getItems() + { + $items = []; + if (true === $this->items instanceof QueryInterface) { + $items = $this->addOptionsFromResults($this->items); + } elseif (true === is_string($this->items)) { + $itemNames = GeneralUtility::trimExplode(',', $this->items); + if (!$this->getTranslateCsvItems()) { + foreach ($itemNames as $itemName) { + array_push($items, [$itemName, $itemName]); + } + } else { + foreach ($itemNames as $itemName) { + $resolvedLabel = $this->resolveLocalLanguageValueOfLabel( + '', + $this->getPath() . '.option.' . $itemName + ); + array_push($items, [$resolvedLabel, $itemName]); + } + } + } elseif (true === is_array($this->items) || true === $this->items instanceof \Traversable) { + foreach ($this->items as $itemIndex => $itemValue) { + if (true === is_array($itemValue) || true === $itemValue instanceof \ArrayObject) { + array_push($items, $itemValue); + } else { + array_push($items, [$itemValue, $itemIndex]); + } + } + } + $emptyOption = $this->getEmptyOption(); + if (false !== $emptyOption) { + array_unshift($items, [$emptyOption, '']); + } + return $items; + } + + /** + * @param boolean|string $emptyOption + * @return Select + */ + public function setEmptyOption($emptyOption) + { + $this->emptyOption = $emptyOption; + return $this; + } + + /** + * @return boolean|string + */ + public function getEmptyOption() + { + return $this->emptyOption; + } + + /** + * @return string + */ + public function getRenderType() + { + return $this->renderType; + } + + /** + * @param string $renderType + * @return void + */ + public function setRenderType($renderType) + { + $this->renderType = $renderType; + } + + /** + * @param QueryInterface $query + * @return array + */ + protected function addOptionsFromResults(QueryInterface $query) + { + $items = []; + $results = $query->execute(); + $type = $query->getType(); + $table = strtolower(str_replace('\\', '_', $type)); + $propertyName = $this->getLabelPropertyName($table, $type); + foreach ($results as $result) { + $uid = $result->getUid(); + array_push($items, [ObjectAccess::getProperty($result, $propertyName), $uid]); + } + return $items; + } + + /** + * @param string $table + * @param string $type + * @return string + */ + protected function getLabelPropertyName($table, $type) + { + $typoScript = $this->getConfigurationService()->getAllTypoScript(); + if (true === isset($typoScript['config']['tx_extbase']['persistence']['classes'][$type])) { + $mapping = $typoScript['config']['tx_extbase']['persistence']['classes'][$type]; + if (true === isset($mapping['mapping']['tableName'])) { + $table = $mapping['mapping']['tableName']; + } + } + $labelField = $GLOBALS['TCA'][$table]['ctrl']['label']; + $propertyName = GeneralUtility::underscoredToLowerCamelCase($labelField); + return $propertyName; + } + + /** + * @return boolean + */ + public function getShowIconTable() + { + return $this->showIconTable; + } + + /** + * @param boolean $showIconTable + * @return Select + */ + public function setShowIconTable($showIconTable) + { + $this->showIconTable = $showIconTable; + return $this; + } } diff --git a/Classes/Form/Field/Text.php b/Classes/Form/Field/Text.php index c4b903465..e7d1b4e5b 100644 --- a/Classes/Form/Field/Text.php +++ b/Classes/Form/Field/Text.php @@ -13,150 +13,164 @@ /** * Text */ -class Text extends Input implements FieldInterface { - - /** - * @var integer - */ - protected $columns = 85; - - /** - * @var integer - */ - protected $rows = 10; - - /** - * @var string - */ - protected $defaultExtras; - - /** - * @var boolean - */ - protected $enableRichText = FALSE; - - /** - * @var string - */ - protected $renderType = ''; - - /** - * @var string - */ - protected $format; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('text'); - $configuration['rows'] = $this->getRows(); - $configuration['cols'] = $this->getColumns(); - $configuration['eval'] = $this->getValidate(); - $defaultExtras = $this->getDefaultExtras(); - if (TRUE === $this->getEnableRichText() && TRUE === empty($defaultExtras)) { - $typoScript = $this->getConfigurationService()->getAllTypoScript(); - $configuration['defaultExtras'] = $typoScript['plugin']['tx_flux']['settings']['flexform']['rteDefaults']; - } else { - $configuration['defaultExtras'] = $defaultExtras; - } - $renderType = $this->getRenderType(); - if (FALSE === empty($renderType)) { - $configuration['renderType'] = $renderType; - $configuration['format'] = $this->getFormat(); - } - return $configuration; - } - - /** - * @param integer $columns - * @return Text - */ - public function setColumns($columns) { - $this->columns = $columns; - return $this; - } - - /** - * @return integer - */ - public function getColumns() { - return $this->columns; - } - - /** - * @param string $defaultExtras - * @return Text - */ - public function setDefaultExtras($defaultExtras) { - $this->defaultExtras = $defaultExtras; - return $this; - } - - /** - * @return string - */ - public function getDefaultExtras() { - return $this->defaultExtras; - } - - /** - * @param boolean $enableRichText - * @return Text - */ - public function setEnableRichText($enableRichText) { - $this->enableRichText = (boolean) $enableRichText; - return $this; - } - - /** - * @return boolean - */ - public function getEnableRichText() { - return (boolean) $this->enableRichText; - } - - /** - * @param integer $rows - * @return Text - */ - public function setRows($rows) { - $this->rows = $rows; - return $this; - } - - /** - * @return integer - */ - public function getRows() { - return $this->rows; - } - - /** - * @return string - */ - public function getRenderType() { - return $this->renderType; - } - - /** - * @param string $renderType - */ - public function setRenderType($renderType) { - $this->renderType = $renderType; - } - - /** - * @return string - */ - public function getFormat() { - return $this->format; - } - - /** - * @param string $format - */ - public function setFormat($format) { - $this->format = $format; - } +class Text extends Input implements FieldInterface +{ + + /** + * @var integer + */ + protected $columns = 85; + + /** + * @var integer + */ + protected $rows = 10; + + /** + * @var string + */ + protected $defaultExtras; + + /** + * @var boolean + */ + protected $enableRichText = false; + + /** + * @var string + */ + protected $renderType = ''; + + /** + * @var string + */ + protected $format; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('text'); + $configuration['rows'] = $this->getRows(); + $configuration['cols'] = $this->getColumns(); + $configuration['eval'] = $this->getValidate(); + $defaultExtras = $this->getDefaultExtras(); + if (true === $this->getEnableRichText() && true === empty($defaultExtras)) { + $typoScript = $this->getConfigurationService()->getAllTypoScript(); + $configuration['defaultExtras'] = $typoScript['plugin']['tx_flux']['settings']['flexform']['rteDefaults']; + } else { + $configuration['defaultExtras'] = $defaultExtras; + } + $renderType = $this->getRenderType(); + if (false === empty($renderType)) { + $configuration['renderType'] = $renderType; + $configuration['format'] = $this->getFormat(); + } + return $configuration; + } + + /** + * @param integer $columns + * @return Text + */ + public function setColumns($columns) + { + $this->columns = $columns; + return $this; + } + + /** + * @return integer + */ + public function getColumns() + { + return $this->columns; + } + + /** + * @param string $defaultExtras + * @return Text + */ + public function setDefaultExtras($defaultExtras) + { + $this->defaultExtras = $defaultExtras; + return $this; + } + + /** + * @return string + */ + public function getDefaultExtras() + { + return $this->defaultExtras; + } + + /** + * @param boolean $enableRichText + * @return Text + */ + public function setEnableRichText($enableRichText) + { + $this->enableRichText = (boolean) $enableRichText; + return $this; + } + + /** + * @return boolean + */ + public function getEnableRichText() + { + return (boolean) $this->enableRichText; + } + + /** + * @param integer $rows + * @return Text + */ + public function setRows($rows) + { + $this->rows = $rows; + return $this; + } + + /** + * @return integer + */ + public function getRows() + { + return $this->rows; + } + + /** + * @return string + */ + public function getRenderType() + { + return $this->renderType; + } + + /** + * @param string $renderType + */ + public function setRenderType($renderType) + { + $this->renderType = $renderType; + } + + /** + * @return string + */ + public function getFormat() + { + return $this->format; + } + + /** + * @param string $format + */ + public function setFormat($format) + { + $this->format = $format; + } } diff --git a/Classes/Form/Field/Tree.php b/Classes/Form/Field/Tree.php index 55d74e171..9acb0862a 100644 --- a/Classes/Form/Field/Tree.php +++ b/Classes/Form/Field/Tree.php @@ -13,181 +13,195 @@ /** * Tree */ -class Tree extends AbstractRelationFormField { - - const DEFAULT_ALLOW_RECURSIVE_MODE = FALSE; - const DEFAULT_EXPAND_ALL = FALSE; - const DEFAULT_NON_SELECTABLE_LEVELS = '0'; - const DEFAULT_MAX_LEVELS = 2; - const DEFAULT_SHOW_HEADER = FALSE; - const DEFAULT_WIDTH = 280; - - /** - * @var string - */ - protected $parentField; - - /** - * @var boolean - */ - protected $allowRecursiveMode = self::DEFAULT_ALLOW_RECURSIVE_MODE; - - /** - * @var boolean - */ - protected $expandAll = self::DEFAULT_EXPAND_ALL; - - /** - * @var string - */ - protected $nonSelectableLevels = self::DEFAULT_NON_SELECTABLE_LEVELS; - - /** - * @var integer - */ - protected $maxLevels = self::DEFAULT_MAX_LEVELS; - - /** - * @var boolean - */ - protected $showHeader = self::DEFAULT_SHOW_HEADER; - - /** - * @var integer - */ - protected $width = self::DEFAULT_WIDTH; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('select'); - $configuration['renderMode'] = 'tree'; - $configuration['treeConfig'] = array( - 'parentField' => $this->getParentField(), - 'appearance' => array ( - 'allowRecursiveMode' => $this->getAllowRecursiveMode(), - 'expandAll' => $this->getExpandAll(), - 'nonSelectableLevels' => $this->getNonSelectableLevels(), - 'maxLevels' => $this->getMaxLevels(), - 'showHeader' => $this->getShowHeader(), - 'width' => $this->getWidth(), - ), - ); - return $configuration; - } - - /** - * @param string $parentField - * @return Tree - */ - public function setParentField($parentField) { - $this->parentField = $parentField; - return $this; - } - - /** - * @return string - */ - public function getParentField() { - return $this->parentField; - } - - /** - * @param boolean $allowRecursiveMode - * @return Tree - */ - public function setAllowRecursiveMode($allowRecursiveMode) { - $this->allowRecursiveMode = $allowRecursiveMode; - return $this; - } - - /** - * @return boolean - */ - public function getAllowRecursiveMode() { - return $this->allowRecursiveMode; - } - - /** - * @param boolean $expandAll - * @return Tree - */ - public function setExpandAll($expandAll) { - $this->expandAll = $expandAll; - return $this; - } - - /** - * @return boolean - */ - public function getExpandAll() { - return $this->expandAll; - } - - /** - * @param string $nonSelectableLevels - * @return Tree - */ - public function setNonSelectableLevels($nonSelectableLevels) { - $this->nonSelectableLevels = $nonSelectableLevels; - return $this; - } - - /** - * @return string - */ - public function getNonSelectableLevels() { - return $this->nonSelectableLevels; - } - - /** - * @param integer $maxLevels - * @return Tree - */ - public function setMaxLevels($maxLevels) { - $this->maxLevels = $maxLevels; - return $this; - } - - /** - * @return integer - */ - public function getMaxLevels() { - return $this->maxLevels; - } - - /** - * @param boolean $showHeader - * @return Tree - */ - public function setShowHeader($showHeader) { - $this->showHeader = $showHeader; - return $this; - } - - /** - * @return boolean - */ - public function getShowHeader() { - return $this->showHeader; - } - - /** - * @param integer $width - * @return Tree - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } - - +class Tree extends AbstractRelationFormField +{ + + const DEFAULT_ALLOW_RECURSIVE_MODE = false; + const DEFAULT_EXPAND_ALL = false; + const DEFAULT_NON_SELECTABLE_LEVELS = '0'; + const DEFAULT_MAX_LEVELS = 2; + const DEFAULT_SHOW_HEADER = false; + const DEFAULT_WIDTH = 280; + + /** + * @var string + */ + protected $parentField; + + /** + * @var boolean + */ + protected $allowRecursiveMode = self::DEFAULT_ALLOW_RECURSIVE_MODE; + + /** + * @var boolean + */ + protected $expandAll = self::DEFAULT_EXPAND_ALL; + + /** + * @var string + */ + protected $nonSelectableLevels = self::DEFAULT_NON_SELECTABLE_LEVELS; + + /** + * @var integer + */ + protected $maxLevels = self::DEFAULT_MAX_LEVELS; + + /** + * @var boolean + */ + protected $showHeader = self::DEFAULT_SHOW_HEADER; + + /** + * @var integer + */ + protected $width = self::DEFAULT_WIDTH; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('select'); + $configuration['renderMode'] = 'tree'; + $configuration['treeConfig'] = [ + 'parentField' => $this->getParentField(), + 'appearance' => [ + 'allowRecursiveMode' => $this->getAllowRecursiveMode(), + 'expandAll' => $this->getExpandAll(), + 'nonSelectableLevels' => $this->getNonSelectableLevels(), + 'maxLevels' => $this->getMaxLevels(), + 'showHeader' => $this->getShowHeader(), + 'width' => $this->getWidth(), + ], + ]; + return $configuration; + } + + /** + * @param string $parentField + * @return Tree + */ + public function setParentField($parentField) + { + $this->parentField = $parentField; + return $this; + } + + /** + * @return string + */ + public function getParentField() + { + return $this->parentField; + } + + /** + * @param boolean $allowRecursiveMode + * @return Tree + */ + public function setAllowRecursiveMode($allowRecursiveMode) + { + $this->allowRecursiveMode = $allowRecursiveMode; + return $this; + } + + /** + * @return boolean + */ + public function getAllowRecursiveMode() + { + return $this->allowRecursiveMode; + } + + /** + * @param boolean $expandAll + * @return Tree + */ + public function setExpandAll($expandAll) + { + $this->expandAll = $expandAll; + return $this; + } + + /** + * @return boolean + */ + public function getExpandAll() + { + return $this->expandAll; + } + + /** + * @param string $nonSelectableLevels + * @return Tree + */ + public function setNonSelectableLevels($nonSelectableLevels) + { + $this->nonSelectableLevels = $nonSelectableLevels; + return $this; + } + + /** + * @return string + */ + public function getNonSelectableLevels() + { + return $this->nonSelectableLevels; + } + + /** + * @param integer $maxLevels + * @return Tree + */ + public function setMaxLevels($maxLevels) + { + $this->maxLevels = $maxLevels; + return $this; + } + + /** + * @return integer + */ + public function getMaxLevels() + { + return $this->maxLevels; + } + + /** + * @param boolean $showHeader + * @return Tree + */ + public function setShowHeader($showHeader) + { + $this->showHeader = $showHeader; + return $this; + } + + /** + * @return boolean + */ + public function getShowHeader() + { + return $this->showHeader; + } + + /** + * @param integer $width + * @return Tree + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } } diff --git a/Classes/Form/Field/UserFunction.php b/Classes/Form/Field/UserFunction.php index 936269204..c6b02175c 100644 --- a/Classes/Form/Field/UserFunction.php +++ b/Classes/Form/Field/UserFunction.php @@ -14,58 +14,63 @@ /** * UserFunction */ -class UserFunction extends AbstractFormField implements FieldInterface { +class UserFunction extends AbstractFormField implements FieldInterface +{ - /** - * @var array - */ - protected $arguments = array(); + /** + * @var array + */ + protected $arguments = []; - /** - * @var string - */ - protected $function; + /** + * @var string + */ + protected $function; - /** - * @return array - */ - public function buildConfiguration() { - $configuration = $this->prepareConfiguration('user'); - $configuration['userFunc'] = $this->getFunction(); - $configuration['arguments'] = $this->getArguments(); - return $configuration; - } + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = $this->prepareConfiguration('user'); + $configuration['userFunc'] = $this->getFunction(); + $configuration['arguments'] = $this->getArguments(); + return $configuration; + } - /** - * @param string $function - * @return UserFunction - */ - public function setFunction($function) { - $this->function = $function; - return $this; - } + /** + * @param string $function + * @return UserFunction + */ + public function setFunction($function) + { + $this->function = $function; + return $this; + } - /** - * @return string - */ - public function getFunction() { - return $this->function; - } + /** + * @return string + */ + public function getFunction() + { + return $this->function; + } - /** - * @param array $arguments - * @return UserFunction - */ - public function setArguments($arguments) { - $this->arguments = $arguments; - return $this; - } - - /** - * @return array - */ - public function getArguments() { - return $this->arguments; - } + /** + * @param array $arguments + * @return UserFunction + */ + public function setArguments($arguments) + { + $this->arguments = $arguments; + return $this; + } + /** + * @return array + */ + public function getArguments() + { + return $this->arguments; + } } diff --git a/Classes/Form/FieldContainerInterface.php b/Classes/Form/FieldContainerInterface.php index 0194f446e..48faa1e0a 100644 --- a/Classes/Form/FieldContainerInterface.php +++ b/Classes/Form/FieldContainerInterface.php @@ -11,11 +11,11 @@ /** * FieldContainerInterface */ -interface FieldContainerInterface extends ContainerInterface { - - /** - * @return FieldInterface[] - */ - public function getFields(); +interface FieldContainerInterface extends ContainerInterface +{ + /** + * @return FieldInterface[] + */ + public function getFields(); } diff --git a/Classes/Form/FieldInterface.php b/Classes/Form/FieldInterface.php index e9bb1600c..e76bc8767 100644 --- a/Classes/Form/FieldInterface.php +++ b/Classes/Form/FieldInterface.php @@ -11,122 +11,122 @@ /** * FieldInterface */ -interface FieldInterface extends FormInterface { - - /** - * @return array - */ - public function buildConfiguration(); - - /** - * @param boolean $clearable - * @return FieldInterface - */ - public function setClearable($clearable); - - /** - * @return boolean - */ - public function getClearable(); - - /** - * @param boolean $required - * @return FieldInterface - */ - public function setRequired($required); - - /** - * @return boolean - */ - public function getRequired(); - - /** - * @param mixed $default - * @return FieldInterface - */ - public function setDefault($default); - - /** - * @return mixed - */ - public function getDefault(); - - /** - * @param string $transform - * @return FieldInterface - */ - public function setTransform($transform); - - /** - * @return string - */ - public function getTransform(); - - /** - * @param string $displayCondition - * @return FieldInterface - */ - public function setDisplayCondition($displayCondition); - - /** - * @return string - */ - public function getDisplayCondition(); - - /** - * @param boolean $requestUpdate - * @return FieldInterface - */ - public function setRequestUpdate($requestUpdate); - - /** - * @return boolean - */ - public function getRequestUpdate(); - - /** - * @param boolean $exclude - * @return FieldInterface - */ - public function setExclude($exclude); - - /** - * @return boolean - */ - public function getExclude(); - - /** - * @param boolean $enable - * @return FieldInterface - */ - public function setEnable($enable); - - /** - * @return boolean - */ - public function getEnable(); - - /** - * @param string $validate - * @return FieldInterface - */ - public function setValidate($validate); - - /** - * @return string - */ - public function getValidate(); - - /** - * @param WizardInterface $wizard - * @return FormInterface - */ - public function add(WizardInterface $wizard); - - /** - * @param string $wizardName - * @return WizardInterface|FALSE - */ - public function remove($wizardName); - +interface FieldInterface extends FormInterface +{ + + /** + * @return array + */ + public function buildConfiguration(); + + /** + * @param boolean $clearable + * @return FieldInterface + */ + public function setClearable($clearable); + + /** + * @return boolean + */ + public function getClearable(); + + /** + * @param boolean $required + * @return FieldInterface + */ + public function setRequired($required); + + /** + * @return boolean + */ + public function getRequired(); + + /** + * @param mixed $default + * @return FieldInterface + */ + public function setDefault($default); + + /** + * @return mixed + */ + public function getDefault(); + + /** + * @param string $transform + * @return FieldInterface + */ + public function setTransform($transform); + + /** + * @return string + */ + public function getTransform(); + + /** + * @param string $displayCondition + * @return FieldInterface + */ + public function setDisplayCondition($displayCondition); + + /** + * @return string + */ + public function getDisplayCondition(); + + /** + * @param boolean $requestUpdate + * @return FieldInterface + */ + public function setRequestUpdate($requestUpdate); + + /** + * @return boolean + */ + public function getRequestUpdate(); + + /** + * @param boolean $exclude + * @return FieldInterface + */ + public function setExclude($exclude); + + /** + * @return boolean + */ + public function getExclude(); + + /** + * @param boolean $enable + * @return FieldInterface + */ + public function setEnable($enable); + + /** + * @return boolean + */ + public function getEnable(); + + /** + * @param string $validate + * @return FieldInterface + */ + public function setValidate($validate); + + /** + * @return string + */ + public function getValidate(); + + /** + * @param WizardInterface $wizard + * @return FormInterface + */ + public function add(WizardInterface $wizard); + + /** + * @param string $wizardName + * @return WizardInterface|FALSE + */ + public function remove($wizardName); } diff --git a/Classes/Form/FormInterface.php b/Classes/Form/FormInterface.php index 90e5a1b3f..860c9bb8d 100644 --- a/Classes/Form/FormInterface.php +++ b/Classes/Form/FormInterface.php @@ -11,197 +11,197 @@ /** * FormInterface */ -interface FormInterface { - - /** - * @return array - */ - public function build(); - - /** - * @param string $name - */ - public function setName($name); - - /** - * @return string - */ - public function getName(); - - /** - * @return boolean - */ - public function getEnabled(); - - /** - * @param boolean $enabled - * @return FormInterface - */ - public function setEnabled($enabled); - - /** - * @param string $label - */ - public function setLabel($label); - - /** - * @return string - */ - public function getLabel(); - - /** - * @param string $localLanguageFileRelativePath - * @return FormInterface - */ - public function setLocalLanguageFileRelativePath($localLanguageFileRelativePath); - - /** - * @return string - */ - public function getLocalLanguageFileRelativePath(); - - - /** - * @param boolean $disableLocalLanguageLabels - * @return FormInterface - */ - public function setDisableLocalLanguageLabels($disableLocalLanguageLabels); - - /** - * @return boolean - */ - public function getDisableLocalLanguageLabels(); - - /** - * @param ContainerInterface $parent - * @return FormInterface - */ - public function setParent($parent); - - /** - * @return ContainerInterface - */ - public function getParent(); - - /** - * @param array $variables - * @return FormInterface - */ - public function setVariables($variables); - - /** - * @return array - */ - public function getVariables(); - - /** - * @param string $name - * @param mixed $value - * @return FormInterface - */ - public function setVariable($name, $value); - - /** - * @param string $name - * @return mixed - */ - public function getVariable($name); - - /** - * @return ContainerInterface - */ - public function getRoot(); - - /** - * @return string - */ - public function getPath(); - - /** - * @param string $extensionName - * @return FormInterface - */ - public function setExtensionName($extensionName); - - /** - * @return mixed - */ - public function getExtensionName(); - - /** - * @param string $type - * @return boolean - */ - public function isChildOfType($type); - - /** - * @return boolean - */ - public function hasChildren(); - - /** - * @param string $type - * @param string $name - * @param string $label - * @return FieldInterface - */ - public function createField($type, $name, $label = NULL); - - /** - * @param string $type - * @param string $name - * @param string $label - * @return ContainerInterface - */ - public function createContainer($type, $name, $label = NULL); - - /** - * @param string $type - * @param string $name - * @param string $label - * @return WizardInterface - */ - public function createWizard($type, $name, $label = NULL); - - /** - * @param integer $inherit - * @return FormInterface - */ - public function setInherit($inherit); - - /** - * @return integer - */ - public function getInherit(); - - /** - * @param boolean $inheritEmpty - * @return FormInterface - */ - public function setInheritEmpty($inheritEmpty); - - /** - * @return boolean - */ - public function getInheritEmpty(); - - /** - * Modifies the current Form Component by changing any properties - * that were passed in $structure. If a component supports special - * indices in $structure (for example a "fields" property) then - * that component may specify its own `modify()` method and manually - * process each of the specially supported keywords. - * - * For example, the AbstractFormContainer supports passing "fields" - * and each field is then attempted fetched from children. If not - * found, it is created (and the structure passed to the `create()` - * function which uses the same structure syntax). If it already - * exists, the `modify()` method is called on that object to trigger - * the recursive modification of all child components. - * - * @param array $structure - * @return FormInterface - */ - public function modify(array $structure); - +interface FormInterface +{ + + /** + * @return array + */ + public function build(); + + /** + * @param string $name + */ + public function setName($name); + + /** + * @return string + */ + public function getName(); + + /** + * @return boolean + */ + public function getEnabled(); + + /** + * @param boolean $enabled + * @return FormInterface + */ + public function setEnabled($enabled); + + /** + * @param string $label + */ + public function setLabel($label); + + /** + * @return string + */ + public function getLabel(); + + /** + * @param string $localLanguageFileRelativePath + * @return FormInterface + */ + public function setLocalLanguageFileRelativePath($localLanguageFileRelativePath); + + /** + * @return string + */ + public function getLocalLanguageFileRelativePath(); + + + /** + * @param boolean $disableLocalLanguageLabels + * @return FormInterface + */ + public function setDisableLocalLanguageLabels($disableLocalLanguageLabels); + + /** + * @return boolean + */ + public function getDisableLocalLanguageLabels(); + + /** + * @param ContainerInterface $parent + * @return FormInterface + */ + public function setParent($parent); + + /** + * @return ContainerInterface + */ + public function getParent(); + + /** + * @param array $variables + * @return FormInterface + */ + public function setVariables($variables); + + /** + * @return array + */ + public function getVariables(); + + /** + * @param string $name + * @param mixed $value + * @return FormInterface + */ + public function setVariable($name, $value); + + /** + * @param string $name + * @return mixed + */ + public function getVariable($name); + + /** + * @return ContainerInterface + */ + public function getRoot(); + + /** + * @return string + */ + public function getPath(); + + /** + * @param string $extensionName + * @return FormInterface + */ + public function setExtensionName($extensionName); + + /** + * @return mixed + */ + public function getExtensionName(); + + /** + * @param string $type + * @return boolean + */ + public function isChildOfType($type); + + /** + * @return boolean + */ + public function hasChildren(); + + /** + * @param string $type + * @param string $name + * @param string $label + * @return FieldInterface + */ + public function createField($type, $name, $label = null); + + /** + * @param string $type + * @param string $name + * @param string $label + * @return ContainerInterface + */ + public function createContainer($type, $name, $label = null); + + /** + * @param string $type + * @param string $name + * @param string $label + * @return WizardInterface + */ + public function createWizard($type, $name, $label = null); + + /** + * @param integer $inherit + * @return FormInterface + */ + public function setInherit($inherit); + + /** + * @return integer + */ + public function getInherit(); + + /** + * @param boolean $inheritEmpty + * @return FormInterface + */ + public function setInheritEmpty($inheritEmpty); + + /** + * @return boolean + */ + public function getInheritEmpty(); + + /** + * Modifies the current Form Component by changing any properties + * that were passed in $structure. If a component supports special + * indices in $structure (for example a "fields" property) then + * that component may specify its own `modify()` method and manually + * process each of the specially supported keywords. + * + * For example, the AbstractFormContainer supports passing "fields" + * and each field is then attempted fetched from children. If not + * found, it is created (and the structure passed to the `create()` + * function which uses the same structure syntax). If it already + * exists, the `modify()` method is called on that object to trigger + * the recursive modification of all child components. + * + * @param array $structure + * @return FormInterface + */ + public function modify(array $structure); } diff --git a/Classes/Form/InlineRelationFieldInterface.php b/Classes/Form/InlineRelationFieldInterface.php index 27880846e..39c7fb471 100644 --- a/Classes/Form/InlineRelationFieldInterface.php +++ b/Classes/Form/InlineRelationFieldInterface.php @@ -11,148 +11,148 @@ /** * InlineRelationFieldInterface */ -interface InlineRelationFieldInterface extends RelationFieldInterface { - - /** - * @param mixed $foreignTypes - * @return InlineRelationFieldInterface - */ - public function setForeignTypes($foreignTypes); - - /** - * @return array - */ - public function getForeignTypes(); - - /** - * @param boolean $collapseAll - * @return InlineRelationFieldInterface - */ - public function setCollapseAll($collapseAll); - - /** - * @return boolean - */ - public function getCollapseAll(); - - /** - * @param array $enabledControls - * @return InlineRelationFieldInterface - */ - public function setEnabledControls(array $enabledControls); - - /** - * @return array - */ - public function getEnabledControls(); - - /** - * @param boolean $expandSingle - * @return InlineRelationFieldInterface - */ - public function setExpandSingle($expandSingle); - - /** - * @return boolean - */ - public function getExpandSingle(); - - /** - * @param boolean $newRecordLinkAddTitle - * @return InlineRelationFieldInterface - */ - public function setNewRecordLinkAddTitle($newRecordLinkAddTitle); - - /** - * @return boolean - */ - public function getNewRecordLinkAddTitle(); - - /** - * @param string $newRecordLinkPosition - * @return InlineRelationFieldInterface - */ - public function setNewRecordLinkPosition($newRecordLinkPosition); - - /** - * @return string - */ - public function getNewRecordLinkPosition(); - - /** - * @param boolean $showAllLocalizationLink - * @return InlineRelationFieldInterface - */ - public function setShowAllLocalizationLink($showAllLocalizationLink); - - /** - * @return boolean - */ - public function getShowAllLocalizationLink(); - - /** - * @param boolean $showPossibleLocalizationRecords - * @return InlineRelationFieldInterface - */ - public function setShowPossibleLocalizationRecords($showPossibleLocalizationRecords); - - /** - * @return boolean - */ - public function getShowPossibleLocalizationRecords(); - - /** - * @param boolean $showRemovedLocalizationRecords - * @return InlineRelationFieldInterface - */ - public function setShowRemovedLocalizationRecords($showRemovedLocalizationRecords); - - /** - * @return boolean - */ - public function getShowRemovedLocalizationRecords(); - - /** - * @param boolean $showSynchronizationLink - * @return InlineRelationFieldInterface - */ - public function setShowSynchronizationLink($showSynchronizationLink); - - /** - * @return boolean - */ - public function getShowSynchronizationLink(); - - /** - * @param boolean $useCombination - * @return InlineRelationFieldInterface - */ - public function setUseCombination($useCombination); - - /** - * @return boolean - */ - public function getUseCombination(); - - /** - * @param boolean $useSortable - * @return InlineRelationFieldInterface - */ - public function setUseSortable($useSortable); - /** - * @return boolean - */ - public function getUseSortable(); - - /** - * @param array $foreignMatchFields - * @return InlineRelationFieldInterface - */ - public function setForeignMatchFields(array $foreignMatchFields); - - /** - * @return array - */ - public function getForeignMatchFields(); - +interface InlineRelationFieldInterface extends RelationFieldInterface +{ + + /** + * @param mixed $foreignTypes + * @return InlineRelationFieldInterface + */ + public function setForeignTypes($foreignTypes); + + /** + * @return array + */ + public function getForeignTypes(); + + /** + * @param boolean $collapseAll + * @return InlineRelationFieldInterface + */ + public function setCollapseAll($collapseAll); + + /** + * @return boolean + */ + public function getCollapseAll(); + + /** + * @param array $enabledControls + * @return InlineRelationFieldInterface + */ + public function setEnabledControls(array $enabledControls); + + /** + * @return array + */ + public function getEnabledControls(); + + /** + * @param boolean $expandSingle + * @return InlineRelationFieldInterface + */ + public function setExpandSingle($expandSingle); + + /** + * @return boolean + */ + public function getExpandSingle(); + + /** + * @param boolean $newRecordLinkAddTitle + * @return InlineRelationFieldInterface + */ + public function setNewRecordLinkAddTitle($newRecordLinkAddTitle); + + /** + * @return boolean + */ + public function getNewRecordLinkAddTitle(); + + /** + * @param string $newRecordLinkPosition + * @return InlineRelationFieldInterface + */ + public function setNewRecordLinkPosition($newRecordLinkPosition); + + /** + * @return string + */ + public function getNewRecordLinkPosition(); + + /** + * @param boolean $showAllLocalizationLink + * @return InlineRelationFieldInterface + */ + public function setShowAllLocalizationLink($showAllLocalizationLink); + + /** + * @return boolean + */ + public function getShowAllLocalizationLink(); + + /** + * @param boolean $showPossibleLocalizationRecords + * @return InlineRelationFieldInterface + */ + public function setShowPossibleLocalizationRecords($showPossibleLocalizationRecords); + + /** + * @return boolean + */ + public function getShowPossibleLocalizationRecords(); + + /** + * @param boolean $showRemovedLocalizationRecords + * @return InlineRelationFieldInterface + */ + public function setShowRemovedLocalizationRecords($showRemovedLocalizationRecords); + + /** + * @return boolean + */ + public function getShowRemovedLocalizationRecords(); + + /** + * @param boolean $showSynchronizationLink + * @return InlineRelationFieldInterface + */ + public function setShowSynchronizationLink($showSynchronizationLink); + + /** + * @return boolean + */ + public function getShowSynchronizationLink(); + + /** + * @param boolean $useCombination + * @return InlineRelationFieldInterface + */ + public function setUseCombination($useCombination); + + /** + * @return boolean + */ + public function getUseCombination(); + + /** + * @param boolean $useSortable + * @return InlineRelationFieldInterface + */ + public function setUseSortable($useSortable); + /** + * @return boolean + */ + public function getUseSortable(); + + /** + * @param array $foreignMatchFields + * @return InlineRelationFieldInterface + */ + public function setForeignMatchFields(array $foreignMatchFields); + + /** + * @return array + */ + public function getForeignMatchFields(); } diff --git a/Classes/Form/MultiValueFieldInterface.php b/Classes/Form/MultiValueFieldInterface.php index 3ff31543e..e6613f54c 100644 --- a/Classes/Form/MultiValueFieldInterface.php +++ b/Classes/Form/MultiValueFieldInterface.php @@ -11,82 +11,82 @@ /** * MultiValueFieldInterface */ -interface MultiValueFieldInterface extends FieldInterface { - - /** - * @param integer $size - * @return MultiValueFieldInterface - */ - public function setSize($size); - - /** - * @return integer - */ - public function getSize(); - - /** - * @param boolean $multiple - */ - public function setMultiple($multiple); - - /** - * @return boolean - */ - public function getMultiple(); - - /** - * @param integer $maxItems - * @return MultiValueFieldInterface - */ - public function setMaxItems($maxItems); - - /** - * @return integer - */ - public function getMaxItems(); - - /** - * @param integer $minItems - * @return MultiValueFieldInterface - */ - public function setMinItems($minItems); - - /** - * @return integer - */ - public function getMinItems(); - - /** - * @param string $itemListStyle - * @return MultiValueFieldInterface - */ - public function setItemListStyle($itemListStyle); - - /** - * @return string - */ - public function getItemListStyle(); - - /** - * @param string $selectedListStyle - * @return MultiValueFieldInterface - */ - public function setSelectedListStyle($selectedListStyle); - - /** - * @return string - */ - public function getSelectedListStyle(); - - /** - * @param string $renderMode - * @return MultiValueFieldInterface - */ - public function setRenderMode($renderMode); - - /** - * @return string - */ - public function getRenderMode(); - +interface MultiValueFieldInterface extends FieldInterface +{ + + /** + * @param integer $size + * @return MultiValueFieldInterface + */ + public function setSize($size); + + /** + * @return integer + */ + public function getSize(); + + /** + * @param boolean $multiple + */ + public function setMultiple($multiple); + + /** + * @return boolean + */ + public function getMultiple(); + + /** + * @param integer $maxItems + * @return MultiValueFieldInterface + */ + public function setMaxItems($maxItems); + + /** + * @return integer + */ + public function getMaxItems(); + + /** + * @param integer $minItems + * @return MultiValueFieldInterface + */ + public function setMinItems($minItems); + + /** + * @return integer + */ + public function getMinItems(); + + /** + * @param string $itemListStyle + * @return MultiValueFieldInterface + */ + public function setItemListStyle($itemListStyle); + + /** + * @return string + */ + public function getItemListStyle(); + + /** + * @param string $selectedListStyle + * @return MultiValueFieldInterface + */ + public function setSelectedListStyle($selectedListStyle); + + /** + * @return string + */ + public function getSelectedListStyle(); + + /** + * @param string $renderMode + * @return MultiValueFieldInterface + */ + public function setRenderMode($renderMode); + + /** + * @return string + */ + public function getRenderMode(); } diff --git a/Classes/Form/RelationFieldInterface.php b/Classes/Form/RelationFieldInterface.php index 27081bcad..fbf7d3770 100644 --- a/Classes/Form/RelationFieldInterface.php +++ b/Classes/Form/RelationFieldInterface.php @@ -11,226 +11,226 @@ /** * RelationFieldInterface */ -interface RelationFieldInterface extends MultiValueFieldInterface { - - /** - * @param string $condition - * @return RelationFieldInterface - */ - public function setCondition($condition); - - /** - * @return string - */ - public function getCondition(); - - /** - * @param string $foreignField - * @return RelationFieldInterface - */ - public function setForeignField($foreignField); - - /** - * @return string - */ - public function getForeignField(); - - /** - * @param NULL|string $manyToMany - * @return RelationFieldInterface - */ - public function setManyToMany($manyToMany); - - /** - * @return NULL|string - */ - public function getManyToMany(); - - /** - * @return array - */ - public function getMatchFields(); - - /** - * @param array $matchFields - * @return RelationFieldInterface - */ - public function setMatchFields(array $matchFields); - - /** - * @param string $table - * @return RelationFieldInterface - */ - public function setTable($table); - - /** - * @return string - */ - public function getTable(); - - /** - * @param boolean $disableMovingChildrenWithParent - * @return RelationFieldInterface - */ - public function setDisableMovingChildrenWithParent($disableMovingChildrenWithParent); - - /** - * @return boolean - */ - public function getDisableMovingChildrenWithParent(); - - /** - * @param string $foreignDefaultSortby - * @return RelationFieldInterface - */ - public function setForeignDefaultSortby($foreignDefaultSortby); - - /** - * @return string - */ - public function getForeignDefaultSortby(); - - /** - * @param string $foreignLabel - * @return RelationFieldInterface - */ - public function setForeignLabel($foreignLabel); - - /** - * @return string - */ - public function getForeignLabel(); - - /** - * @param string $foreignSelector - * @return RelationFieldInterface - */ - public function setForeignSelector($foreignSelector); - - /** - * @return string - */ - public function getForeignSelector(); - - /** - * @param string $foreignSortby - * @return RelationFieldInterface - */ - public function setForeignSortby($foreignSortby); - - /** - * @return string - */ - public function getForeignSortby(); - - /** - * @param string $foreignTableField - * @return RelationFieldInterface - */ - public function setForeignTableField($foreignTableField); - - /** - * @return string - */ - public function getForeignTableField(); - - /** - * @param string $foreignUnique - * @return RelationFieldInterface - */ - public function setForeignUnique($foreignUnique); - - /** - * @return string - */ - public function getForeignUnique(); - - /** - * @param string $localizationMode - * @return RelationFieldInterface - */ - public function setLocalizationMode($localizationMode); - - /** - * @return string - */ - public function getLocalizationMode(); - - /** - * @param boolean $localizeChildrenAtParentLocalization - * @return RelationFieldInterface - */ - public function setLocalizeChildrenAtParentLocalization($localizeChildrenAtParentLocalization); - - /** - * @return boolean - */ - public function getLocalizeChildrenAtParentLocalization(); - - /** - * @param string $symmetricField - * @return RelationFieldInterface - */ - public function setSymmetricField($symmetricField); - - /** - * @return string - */ - public function getSymmetricField(); - - /** - * @param string $symmetricLabel - * @return RelationFieldInterface - */ - public function setSymmetricLabel($symmetricLabel); - - /** - * @return string - */ - public function getSymmetricLabel(); - - /** - * @param string $symmetricSortby - * @return RelationFieldInterface - */ - public function setSymmetricSortby($symmetricSortby); - - /** - * @return string - */ - public function getSymmetricSortby(); - - /** - * @param boolean $showThumbnails - * @return RelationFieldInterface - */ - public function setShowThumbnails($showThumbnails); - - /** - * @return boolean - */ - public function getShowThumbnails(); - - /** - * @param boolean|string $emptyOption - * @return Select - */ - public function setEmptyOption($emptyOption); - - /** - * @return boolean|string - */ - public function getEmptyOption(); - - /** - * @return string - */ - public function getOppositeField(); - - /** - * @param string $oppositeField - * @return RelationFieldInterface - */ - public function setOppositeField($oppositeField); - +interface RelationFieldInterface extends MultiValueFieldInterface +{ + + /** + * @param string $condition + * @return RelationFieldInterface + */ + public function setCondition($condition); + + /** + * @return string + */ + public function getCondition(); + + /** + * @param string $foreignField + * @return RelationFieldInterface + */ + public function setForeignField($foreignField); + + /** + * @return string + */ + public function getForeignField(); + + /** + * @param NULL|string $manyToMany + * @return RelationFieldInterface + */ + public function setManyToMany($manyToMany); + + /** + * @return NULL|string + */ + public function getManyToMany(); + + /** + * @return array + */ + public function getMatchFields(); + + /** + * @param array $matchFields + * @return RelationFieldInterface + */ + public function setMatchFields(array $matchFields); + + /** + * @param string $table + * @return RelationFieldInterface + */ + public function setTable($table); + + /** + * @return string + */ + public function getTable(); + + /** + * @param boolean $disableMovingChildrenWithParent + * @return RelationFieldInterface + */ + public function setDisableMovingChildrenWithParent($disableMovingChildrenWithParent); + + /** + * @return boolean + */ + public function getDisableMovingChildrenWithParent(); + + /** + * @param string $foreignDefaultSortby + * @return RelationFieldInterface + */ + public function setForeignDefaultSortby($foreignDefaultSortby); + + /** + * @return string + */ + public function getForeignDefaultSortby(); + + /** + * @param string $foreignLabel + * @return RelationFieldInterface + */ + public function setForeignLabel($foreignLabel); + + /** + * @return string + */ + public function getForeignLabel(); + + /** + * @param string $foreignSelector + * @return RelationFieldInterface + */ + public function setForeignSelector($foreignSelector); + + /** + * @return string + */ + public function getForeignSelector(); + + /** + * @param string $foreignSortby + * @return RelationFieldInterface + */ + public function setForeignSortby($foreignSortby); + + /** + * @return string + */ + public function getForeignSortby(); + + /** + * @param string $foreignTableField + * @return RelationFieldInterface + */ + public function setForeignTableField($foreignTableField); + + /** + * @return string + */ + public function getForeignTableField(); + + /** + * @param string $foreignUnique + * @return RelationFieldInterface + */ + public function setForeignUnique($foreignUnique); + + /** + * @return string + */ + public function getForeignUnique(); + + /** + * @param string $localizationMode + * @return RelationFieldInterface + */ + public function setLocalizationMode($localizationMode); + + /** + * @return string + */ + public function getLocalizationMode(); + + /** + * @param boolean $localizeChildrenAtParentLocalization + * @return RelationFieldInterface + */ + public function setLocalizeChildrenAtParentLocalization($localizeChildrenAtParentLocalization); + + /** + * @return boolean + */ + public function getLocalizeChildrenAtParentLocalization(); + + /** + * @param string $symmetricField + * @return RelationFieldInterface + */ + public function setSymmetricField($symmetricField); + + /** + * @return string + */ + public function getSymmetricField(); + + /** + * @param string $symmetricLabel + * @return RelationFieldInterface + */ + public function setSymmetricLabel($symmetricLabel); + + /** + * @return string + */ + public function getSymmetricLabel(); + + /** + * @param string $symmetricSortby + * @return RelationFieldInterface + */ + public function setSymmetricSortby($symmetricSortby); + + /** + * @return string + */ + public function getSymmetricSortby(); + + /** + * @param boolean $showThumbnails + * @return RelationFieldInterface + */ + public function setShowThumbnails($showThumbnails); + + /** + * @return boolean + */ + public function getShowThumbnails(); + + /** + * @param boolean|string $emptyOption + * @return Select + */ + public function setEmptyOption($emptyOption); + + /** + * @return boolean|string + */ + public function getEmptyOption(); + + /** + * @return string + */ + public function getOppositeField(); + + /** + * @param string $oppositeField + * @return RelationFieldInterface + */ + public function setOppositeField($oppositeField); } diff --git a/Classes/Form/Wizard/Add.php b/Classes/Form/Wizard/Add.php index e8be32ecf..a00dfcde0 100644 --- a/Classes/Form/Wizard/Add.php +++ b/Classes/Form/Wizard/Add.php @@ -16,105 +16,112 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Add extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'add'; - - /** - * @var string - */ - protected $type = 'script'; - - /** - * @var string - */ - protected $icon = 'add.gif'; - - /** - * @var array - */ - protected $module = array( - 'name' => 'wizard_add' - ); - - /** - * @var string - */ - protected $table; - - /** - * @var integer - */ - protected $storagePageUid; - - /** - * @var boolean - */ - protected $setValue = TRUE; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = array( - 'params' => array( - 'table' => $this->getTable(), - 'pid' => $this->getStoragePageUid(), - 'setValue' => intval($this->getSetValue()) - ) - ); - return $configuration; - } - - /** - * @param boolean $setValue - * @return Add - */ - public function setSetValue($setValue) { - $this->setValue = $setValue; - return $this; - } - - /** - * @return boolean - */ - public function getSetValue() { - return $this->setValue; - } - - /** - * @param integer $storagePageUid - * @return Add - */ - public function setStoragePageUid($storagePageUid) { - $this->storagePageUid = $storagePageUid; - return $this; - } - - /** - * @return integer - */ - public function getStoragePageUid() { - return $this->storagePageUid; - } - - /** - * @param string $table - * @return Add - */ - public function setTable($table) { - $this->table = $table; - return $this; - } - - /** - * @return string - */ - public function getTable() { - return $this->table; - } - +class Add extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'add'; + + /** + * @var string + */ + protected $type = 'script'; + + /** + * @var string + */ + protected $icon = 'add.gif'; + + /** + * @var array + */ + protected $module = [ + 'name' => 'wizard_add' + ]; + + /** + * @var string + */ + protected $table; + + /** + * @var integer + */ + protected $storagePageUid; + + /** + * @var boolean + */ + protected $setValue = true; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = [ + 'params' => [ + 'table' => $this->getTable(), + 'pid' => $this->getStoragePageUid(), + 'setValue' => intval($this->getSetValue()) + ] + ]; + return $configuration; + } + + /** + * @param boolean $setValue + * @return Add + */ + public function setSetValue($setValue) + { + $this->setValue = $setValue; + return $this; + } + + /** + * @return boolean + */ + public function getSetValue() + { + return $this->setValue; + } + + /** + * @param integer $storagePageUid + * @return Add + */ + public function setStoragePageUid($storagePageUid) + { + $this->storagePageUid = $storagePageUid; + return $this; + } + + /** + * @return integer + */ + public function getStoragePageUid() + { + return $this->storagePageUid; + } + + /** + * @param string $table + * @return Add + */ + public function setTable($table) + { + $this->table = $table; + return $this; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } } diff --git a/Classes/Form/Wizard/ColorPicker.php b/Classes/Form/Wizard/ColorPicker.php index bfb226557..e3217ec1e 100644 --- a/Classes/Form/Wizard/ColorPicker.php +++ b/Classes/Form/Wizard/ColorPicker.php @@ -16,122 +16,135 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class ColorPicker extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'color'; - - /** - * @var string - */ - protected $type = 'script'; - - /** - * @var string - */ - protected $icon = 'EXT:flux/Resources/Public/Icons/ColorWheel.png'; - - /** - * @var array - */ - protected $module = array( - 'name' => 'wizard_colorpicker', - ); - - /** - * @var string - */ - protected $dimensions = '20x20'; - - /** - * @var integer - */ - protected $width = 450; - - /** - * @var integer - */ - protected $height = 720; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = array( - 'type' => 'colorbox', - 'title' => $this->getLabel(), - 'hideParent' => intval($this->getHideParent()), - 'dim' => $this->getDimensions(), - 'exampleImg' => $this->getIcon(), - 'JSopenParams' => 'height=' . $this->getHeight() . ',width=' . $this->getWidth() . ',status=0,menubar=0,scrollbars=1' - ); - return $configuration; - } - - /** - * @param string $dimensions - * @return ColorPicker - */ - public function setDimensions($dimensions) { - $this->dimensions = $dimensions; - return $this; - } - - /** - * @return string - */ - public function getDimensions() { - return $this->dimensions; - } - - /** - * @param integer $height - * @return ColorPicker - */ - public function setHeight($height) { - $this->height = $height; - return $this; - } - - /** - * @return integer - */ - public function getHeight() { - return $this->height; - } - - /** - * @param string $icon - * @return ColorPicker - */ - public function setIcon($icon) { - $this->icon = $icon; - return $this; - } - - /** - * @return string - */ - public function getIcon() { - return $this->icon; - } - - /** - * @param integer $width - * @return ColorPicker - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } - +class ColorPicker extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'color'; + + /** + * @var string + */ + protected $type = 'script'; + + /** + * @var string + */ + protected $icon = 'EXT:flux/Resources/Public/Icons/ColorWheel.png'; + + /** + * @var array + */ + protected $module = [ + 'name' => 'wizard_colorpicker', + ]; + + /** + * @var string + */ + protected $dimensions = '20x20'; + + /** + * @var integer + */ + protected $width = 450; + + /** + * @var integer + */ + protected $height = 720; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = [ + 'type' => 'colorbox', + 'title' => $this->getLabel(), + 'hideParent' => intval($this->getHideParent()), + 'dim' => $this->getDimensions(), + 'exampleImg' => $this->getIcon(), + 'JSopenParams' => sprintf( + 'height=%d,width=%d,status=0,menubar=0,scrollbars=1', + $this->getHeight(), + $this->getWidth() + ) + ]; + return $configuration; + } + + /** + * @param string $dimensions + * @return ColorPicker + */ + public function setDimensions($dimensions) + { + $this->dimensions = $dimensions; + return $this; + } + + /** + * @return string + */ + public function getDimensions() + { + return $this->dimensions; + } + + /** + * @param integer $height + * @return ColorPicker + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } + + /** + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * @param string $icon + * @return ColorPicker + */ + public function setIcon($icon) + { + $this->icon = $icon; + return $this; + } + + /** + * @return string + */ + public function getIcon() + { + return $this->icon; + } + + /** + * @param integer $width + * @return ColorPicker + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } } diff --git a/Classes/Form/Wizard/Edit.php b/Classes/Form/Wizard/Edit.php index 0b52b6478..ac74a3a1a 100644 --- a/Classes/Form/Wizard/Edit.php +++ b/Classes/Form/Wizard/Edit.php @@ -16,105 +16,116 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Edit extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'edit'; - - /** - * @var string - */ - protected $type = 'script'; - - /** - * @var string - */ - protected $icon = 'edit2.gif'; - - /** - * @var array - */ - protected $module = array( - 'name' => 'wizard_edit' - ); - - /** - * @var boolean - */ - protected $openOnlyIfSelected = TRUE; - - /** - * @var integer - */ - protected $width = 450; - - /** - * @var integer - */ - protected $height = 720; - - /** - * @return array - */ - public function buildConfiguration() { - $configuration = array( - 'type' => 'popup', - 'title' => $this->getLabel(), - 'icon' => $this->icon, - 'popup_onlyOpenIfSelected' => intval($this->getOpenOnlyIfSelected()), - 'JSopenParams' => 'height=' . $this->getHeight() . ',width=' . $this->getWidth() . ',status=0,menubar=0,scrollbars=1' - ); - return $configuration; - } - - /** - * @param boolean $openOnlyIfSelected - * @return Edit - */ - public function setOpenOnlyIfSelected($openOnlyIfSelected) { - $this->openOnlyIfSelected = $openOnlyIfSelected; - return $this; - } - - /** - * @return boolean - */ - public function getOpenOnlyIfSelected() { - return $this->openOnlyIfSelected; - } - - /** - * @param integer $height - * @return Edit - */ - public function setHeight($height) { - $this->height = $height; - return $this; - } - - /** - * @return integer - */ - public function getHeight() { - return $this->height; - } - - /** - * @param integer $width - * @return Edit - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } - +class Edit extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'edit'; + + /** + * @var string + */ + protected $type = 'script'; + + /** + * @var string + */ + protected $icon = 'edit2.gif'; + + /** + * @var array + */ + protected $module = [ + 'name' => 'wizard_edit' + ]; + + /** + * @var boolean + */ + protected $openOnlyIfSelected = true; + + /** + * @var integer + */ + protected $width = 450; + + /** + * @var integer + */ + protected $height = 720; + + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = [ + 'type' => 'popup', + 'title' => $this->getLabel(), + 'icon' => $this->icon, + 'popup_onlyOpenIfSelected' => intval($this->getOpenOnlyIfSelected()), + 'JSopenParams' => sprintf( + 'height=%d,width=%d,status=0,menubar=0,scrollbars=1', + $this->getHeight(), + $this->getWidth() + ) + ]; + return $configuration; + } + + /** + * @param boolean $openOnlyIfSelected + * @return Edit + */ + public function setOpenOnlyIfSelected($openOnlyIfSelected) + { + $this->openOnlyIfSelected = $openOnlyIfSelected; + return $this; + } + + /** + * @return boolean + */ + public function getOpenOnlyIfSelected() + { + return $this->openOnlyIfSelected; + } + + /** + * @param integer $height + * @return Edit + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } + + /** + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * @param integer $width + * @return Edit + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } } diff --git a/Classes/Form/Wizard/Link.php b/Classes/Form/Wizard/Link.php index 46d570d12..b90148221 100644 --- a/Classes/Form/Wizard/Link.php +++ b/Classes/Form/Wizard/Link.php @@ -17,179 +17,196 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Link extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'link'; - - /** - * @var string - */ - protected $type = 'popup'; - - /** - * @var string - */ - protected $icon = 'link_popup.gif'; - - /** - * @var string - */ - protected $activeTab = 'file'; - - /** - * @var integer - */ - protected $height = 500; - - /** - * @var integer - */ - protected $width = 400; - - /** - * @var mixed - */ - protected $blindLinkOptions = ''; - - /** - * @var mixed - */ - protected $blindLinkFields = ''; - - /** - * @var mixed - */ - protected $allowedExtensions; - - /** - * @return array - */ - public function buildConfiguration() { - $structure = array( - 'JSopenParams' => 'height=' . $this->getHeight() . ',width=' . $this->getWidth() . ',status=0,menubar=0,scrollbars=1', - 'params' => array( - 'blindLinkOptions' => implode(',', $this->getBlindLinkOptions()), - 'blindLinkFields' => implode(',', $this->getBlindLinkFields()), - 'allowedExtensions' => implode(',', $this->getAllowedExtensions()) - ), - 'module' => array( - 'name' => 'wizard_element_browser', - 'urlParameters' => array( - 'mode' => 'wizard', - 'act' => $this->getActiveTab() - ) - ) - ); - - return $structure; - } - - /** - * @param string $activeTab - * @return Link - */ - public function setActiveTab($activeTab) { - $this->activeTab = $activeTab; - return $this; - } - - /** - * @return string - */ - public function getActiveTab() { - return $this->activeTab; - } - - /** - * @param integer $height - * @return Link - */ - public function setHeight($height) { - $this->height = $height; - return $this; - } - - /** - * @return integer - */ - public function getHeight() { - return $this->height; - } - - /** - * @param integer $width - * @return Link - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } - - /** - * @param mixed $blindLinkOptions - * @return Link - */ - public function setBlindLinkOptions($blindLinkOptions) { - $this->blindLinkOptions = $blindLinkOptions; - return $this; - } - - /** - * @return mixed - */ - public function getBlindLinkOptions() { - if (FALSE === is_array($this->blindLinkOptions) && FALSE === $this->blindLinkOptions instanceof \Traversable) { - return GeneralUtility::trimExplode(',', $this->blindLinkOptions); - } - return $this->blindLinkOptions; - } - - /** - * @param mixed $blindLinkFields - * @return Link - */ - public function setBlindLinkFields($blindLinkFields) { - $this->blindLinkFields = $blindLinkFields; - return $this; - } - - /** - * @return mixed - */ - public function getBlindLinkFields() { - if (FALSE === is_array($this->blindLinkFields) && FALSE === $this->blindLinkFields instanceof \Traversable) { - return GeneralUtility::trimExplode(',', $this->blindLinkFields); - } - return $this->blindLinkFields; - } - - /** - * @param mixed $allowedExtensions - * @return Link - */ - public function setAllowedExtensions($allowedExtensions) { - $this->allowedExtensions = $allowedExtensions; - return $this; - } - - /** - * @return mixed - */ - public function getAllowedExtensions() { - if (FALSE === is_array($this->allowedExtensions) && FALSE === $this->allowedExtensions instanceof \Traversable) { - return GeneralUtility::trimExplode(',', $this->allowedExtensions); - } - return $this->allowedExtensions; - } - +class Link extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'link'; + + /** + * @var string + */ + protected $type = 'popup'; + + /** + * @var string + */ + protected $icon = 'link_popup.gif'; + + /** + * @var string + */ + protected $activeTab = 'file'; + + /** + * @var integer + */ + protected $height = 500; + + /** + * @var integer + */ + protected $width = 400; + + /** + * @var mixed + */ + protected $blindLinkOptions = ''; + + /** + * @var mixed + */ + protected $blindLinkFields = ''; + + /** + * @var mixed + */ + protected $allowedExtensions; + + /** + * @return array + */ + public function buildConfiguration() + { + $structure = [ + 'JSopenParams' => sprintf( + 'height=%d,width=%d,status=0,menubar=0,scrollbars=1', + $this->getHeight(), + $this->getWidth() + ), + 'params' => [ + 'blindLinkOptions' => implode(',', $this->getBlindLinkOptions()), + 'blindLinkFields' => implode(',', $this->getBlindLinkFields()), + 'allowedExtensions' => implode(',', $this->getAllowedExtensions()) + ], + 'module' => [ + 'name' => 'wizard_element_browser', + 'urlParameters' => [ + 'mode' => 'wizard', + 'act' => $this->getActiveTab() + ] + ] + ]; + + return $structure; + } + + /** + * @param string $activeTab + * @return Link + */ + public function setActiveTab($activeTab) + { + $this->activeTab = $activeTab; + return $this; + } + + /** + * @return string + */ + public function getActiveTab() + { + return $this->activeTab; + } + + /** + * @param integer $height + * @return Link + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } + + /** + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * @param integer $width + * @return Link + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * @param mixed $blindLinkOptions + * @return Link + */ + public function setBlindLinkOptions($blindLinkOptions) + { + $this->blindLinkOptions = $blindLinkOptions; + return $this; + } + + /** + * @return mixed + */ + public function getBlindLinkOptions() + { + if (!is_array($this->blindLinkOptions) && !$this->blindLinkOptions instanceof \Traversable) { + return GeneralUtility::trimExplode(',', $this->blindLinkOptions); + } + return $this->blindLinkOptions; + } + + /** + * @param mixed $blindLinkFields + * @return Link + */ + public function setBlindLinkFields($blindLinkFields) + { + $this->blindLinkFields = $blindLinkFields; + return $this; + } + + /** + * @return mixed + */ + public function getBlindLinkFields() + { + if (!is_array($this->blindLinkFields) && !$this->blindLinkFields instanceof \Traversable) { + return GeneralUtility::trimExplode(',', $this->blindLinkFields); + } + return $this->blindLinkFields; + } + + /** + * @param mixed $allowedExtensions + * @return Link + */ + public function setAllowedExtensions($allowedExtensions) + { + $this->allowedExtensions = $allowedExtensions; + return $this; + } + + /** + * @return mixed + */ + public function getAllowedExtensions() + { + if (!is_array($this->allowedExtensions) && !$this->allowedExtensions instanceof \Traversable) { + return GeneralUtility::trimExplode(',', $this->allowedExtensions); + } + return $this->allowedExtensions; + } } diff --git a/Classes/Form/Wizard/ListWizard.php b/Classes/Form/Wizard/ListWizard.php index 17548ea5f..10935b83b 100644 --- a/Classes/Form/Wizard/ListWizard.php +++ b/Classes/Form/Wizard/ListWizard.php @@ -18,126 +18,139 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class ListWizard extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'list'; - - /** - * @var string - */ - protected $type = 'popup'; - - /** - * @var string - */ - protected $icon = 'list.gif'; - - /** - * @var array - */ - protected $module = array( - 'name' => 'wizard_list' - ); - - /** - * @var string - */ - protected $table; - - /** - * @var integer - */ - protected $height = 500; - - /** - * @var integer - */ - protected $width = 400; - - /** - * @var integer - */ - protected $storagePageUid; - - /** - * @return array - */ - public function buildConfiguration() { - $structure = array( - 'JSopenParams' => 'height=' . $this->getHeight() . ',width=' . $this->getWidth() . ',status=0,menubar=0,scrollbars=1', - 'params' => array( - 'table' => $this->getTable(), - 'pid' => $this->getStoragePageUid(), - ) - ); - return $structure; - } - - /** - * @param integer $height - * @return ListWizard - */ - public function setHeight($height) { - $this->height = $height; - return $this; - } - - /** - * @return integer - */ - public function getHeight() { - return $this->height; - } - - /** - * @param integer $width - * @return ListWizard - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } - - /** - * @param integer $storagePageUid - * @return ListWizard - */ - public function setStoragePageUid($storagePageUid) { - $this->storagePageUid = $storagePageUid; - return $this; - } - - /** - * @return integer - */ - public function getStoragePageUid() { - return $this->storagePageUid; - } - - /** - * @param string $table - * @return ListWizard - */ - public function setTable($table) { - $this->table = $table; - return $this; - } - - /** - * @return string - */ - public function getTable() { - return $this->table; - } - +class ListWizard extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'list'; + + /** + * @var string + */ + protected $type = 'popup'; + + /** + * @var string + */ + protected $icon = 'list.gif'; + + /** + * @var array + */ + protected $module = [ + 'name' => 'wizard_list' + ]; + + /** + * @var string + */ + protected $table; + + /** + * @var integer + */ + protected $height = 500; + + /** + * @var integer + */ + protected $width = 400; + + /** + * @var integer + */ + protected $storagePageUid; + + /** + * @return array + */ + public function buildConfiguration() + { + $structure = [ + 'JSopenParams' => sprintf( + 'height=%d,width=%d,status=0,menubar=0,scrollbars=1', + $this->getHeight(), + $this->getWidth() + ), + 'params' => [ + 'table' => $this->getTable(), + 'pid' => $this->getStoragePageUid(), + ] + ]; + return $structure; + } + + /** + * @param integer $height + * @return ListWizard + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } + + /** + * @return integer + */ + public function getHeight() + { + return $this->height; + } + + /** + * @param integer $width + * @return ListWizard + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * @param integer $storagePageUid + * @return ListWizard + */ + public function setStoragePageUid($storagePageUid) + { + $this->storagePageUid = $storagePageUid; + return $this; + } + + /** + * @return integer + */ + public function getStoragePageUid() + { + return $this->storagePageUid; + } + + /** + * @param string $table + * @return ListWizard + */ + public function setTable($table) + { + $this->table = $table; + return $this; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } } diff --git a/Classes/Form/Wizard/Select.php b/Classes/Form/Wizard/Select.php index 23a3ac390..8f6ae64a4 100644 --- a/Classes/Form/Wizard/Select.php +++ b/Classes/Form/Wizard/Select.php @@ -16,126 +16,134 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Select extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'select'; - - /** - * @var string - */ - protected $type = 'select'; - - /** - * @var string - */ - protected $icon = 'list.gif'; - - /** - * @var string - */ - protected $mode = 'substitution'; - - /** - * Comma-separated, comma-and-semicolon-separated or array - * list of possible values - * - * @var mixed - */ - protected $items; - - /** - * Build the configuration array - * - * @return array - */ - public function buildConfiguration() { - return array( - 'mode' => $this->getMode(), - 'items' => $this->getFormattedItems() - ); - } - - /** - * Builds an array of selector options based on a type of string - * - * @param string $itemsString - * @return array - */ - protected function buildItems($itemsString) { - $itemsString = trim($itemsString, ','); - if (strpos($itemsString, ',') && strpos($itemsString, ';')) { - $return = array(); - $items = explode(',', $itemsString); - foreach ($items as $itemPair) { - $item = explode(';', $itemPair); - $return[$item[0]] = $item[1]; - } - return $return; - } else if (strpos($itemsString, ',')) { - $items = explode(',', $itemsString); - return array_combine($items, $items); - } else { - return array($itemsString => $itemsString); - } - } - - /** - * @return string - */ - public function getName() { - if (NULL !== $this->getParent()) { - return $this->getParent()->getName() . '_' . $this->name; - } - return $this->name; - } - - /** - * @return string - */ - public function getFormattedItems() { - $items = $this->getItems(); - if (TRUE === $items instanceof \Traversable) { - $items = iterator_to_array($items); - } - if (TRUE === is_array($items)) { - return $items; - } - return $this->buildItems($items); - } - - /** - * @param mixed $items - * @return Select - */ - public function setItems($items) { - $this->items = $items; - return $this; - } - - /** - * @return mixed - */ - public function getItems() { - return $this->items; - } - - /** - * @param string $mode - * @return Select - */ - public function setMode($mode) { - $this->mode = $mode; - return $this; - } - - /** - * @return string - */ - public function getMode() { - return $this->mode; - } - +class Select extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'select'; + + /** + * @var string + */ + protected $type = 'select'; + + /** + * @var string + */ + protected $icon = 'list.gif'; + + /** + * @var string + */ + protected $mode = 'substitution'; + + /** + * Comma-separated, comma-and-semicolon-separated or array + * list of possible values + * + * @var mixed + */ + protected $items; + + /** + * Build the configuration array + * + * @return array + */ + public function buildConfiguration() + { + return [ + 'mode' => $this->getMode(), + 'items' => $this->getFormattedItems() + ]; + } + + /** + * Builds an array of selector options based on a type of string + * + * @param string $itemsString + * @return array + */ + protected function buildItems($itemsString) + { + $itemsString = trim($itemsString, ','); + if (strpos($itemsString, ',') && strpos($itemsString, ';')) { + $return = []; + $items = explode(',', $itemsString); + foreach ($items as $itemPair) { + $item = explode(';', $itemPair); + $return[$item[0]] = $item[1]; + } + return $return; + } elseif (strpos($itemsString, ',')) { + $items = explode(',', $itemsString); + return array_combine($items, $items); + } else { + return [$itemsString => $itemsString]; + } + } + + /** + * @return string + */ + public function getName() + { + if (null !== $this->getParent()) { + return $this->getParent()->getName() . '_' . $this->name; + } + return $this->name; + } + + /** + * @return string + */ + public function getFormattedItems() + { + $items = $this->getItems(); + if (true === $items instanceof \Traversable) { + $items = iterator_to_array($items); + } + if (true === is_array($items)) { + return $items; + } + return $this->buildItems($items); + } + + /** + * @param mixed $items + * @return Select + */ + public function setItems($items) + { + $this->items = $items; + return $this; + } + + /** + * @return mixed + */ + public function getItems() + { + return $this->items; + } + + /** + * @param string $mode + * @return Select + */ + public function setMode($mode) + { + $this->mode = $mode; + return $this; + } + + /** + * @return string + */ + public function getMode() + { + return $this->mode; + } } diff --git a/Classes/Form/Wizard/Slider.php b/Classes/Form/Wizard/Slider.php index ffc597dee..01482d4a6 100644 --- a/Classes/Form/Wizard/Slider.php +++ b/Classes/Form/Wizard/Slider.php @@ -16,79 +16,84 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Slider extends AbstractWizard { +class Slider extends AbstractWizard +{ - /** - * @var string - */ - protected $name = 'slider'; + /** + * @var string + */ + protected $name = 'slider'; - /** - * @var string - */ - protected $type = 'slider'; + /** + * @var string + */ + protected $type = 'slider'; - /** - * @var string - */ - protected $icon = NULL; + /** + * @var string + */ + protected $icon = null; - /** - * @var array - */ - protected $module = NULL; + /** + * @var array + */ + protected $module = null; - /** - * @var integer - */ - protected $width = 400; + /** + * @var integer + */ + protected $width = 400; - /** - * @var integer - */ - protected $step; + /** + * @var integer + */ + protected $step; - /** - * @return array - */ - public function buildConfiguration() { - $configuration = array( - 'width' => $this->getWidth(), - 'step' => $this->getStep(), - ); - return $configuration; - } + /** + * @return array + */ + public function buildConfiguration() + { + $configuration = [ + 'width' => $this->getWidth(), + 'step' => $this->getStep(), + ]; + return $configuration; + } - /** - * @param integer $step - * @return Slider - */ - public function setStep($step) { - $this->step = $step; - return $this; - } + /** + * @param integer $step + * @return Slider + */ + public function setStep($step) + { + $this->step = $step; + return $this; + } - /** - * @return integer - */ - public function getStep() { - return $this->step; - } + /** + * @return integer + */ + public function getStep() + { + return $this->step; + } - /** - * @param integer $width - * @return Slider - */ - public function setWidth($width) { - $this->width = $width; - return $this; - } - - /** - * @return integer - */ - public function getWidth() { - return $this->width; - } + /** + * @param integer $width + * @return Slider + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + /** + * @return integer + */ + public function getWidth() + { + return $this->width; + } } diff --git a/Classes/Form/Wizard/Suggest.php b/Classes/Form/Wizard/Suggest.php index 311d4d2ab..accb2328f 100644 --- a/Classes/Form/Wizard/Suggest.php +++ b/Classes/Form/Wizard/Suggest.php @@ -17,277 +17,299 @@ * See https://docs.typo3.org/typo3cms/TCAReference/AdditionalFeatures/CoreWizardScripts/Index.html * for details about the behaviors that are controlled by properties. */ -class Suggest extends AbstractWizard { - - /** - * @var string - */ - protected $name = 'suggest'; - - /** - * @var string - */ - protected $type = 'suggest'; - - /** - * @var string - */ - protected $icon = NULL; - - /** - * @var array - */ - protected $module = NULL; - - /** - * @var string - */ - protected $table = 'pages'; - - /** - * @var array - */ - protected $storagePageUids = array(); - - /** - * @var integer - */ - protected $storagePageRecursiveDepth = 99; - - /** - * @var integer - */ - protected $minimumCharacters = 1; - - /** - * Maximum path segment length - crops titles over this length - * @var integer - */ - protected $maxPathTitleLength = 15; - - /** - * A match requires a full word that matches the search value - * @var boolean - */ - protected $searchWholePhrase = FALSE; - - /** - * Search condition - for example, if table is pages "doktype = 1" to only allow standard pages - * @var string - */ - protected $searchCondition = ''; - - /** - * Use this CSS class for all list items - * @var string - */ - protected $cssClass = ''; - - /** - * Class reference, target class should be derived from "t3lib_tceforms_suggest_defaultreceiver" - * @var string - */ - protected $receiverClass = ''; - - /** - * Reference to function which processes all records displayed in results - * @var string - */ - protected $renderFunction = ''; - - /** - * @return array - */ - public function buildConfiguration() { - $table = $this->getTable(); - $configuration = array( - 'type' => 'suggest', - $table => array( - 'table' => $table, - 'pidList' => implode(',', $this->getStoragePageUids()), - 'pidDepth' => $this->getStoragePageRecursiveDepth(), - 'minimumCharacters' => $this->getMinimumCharacters(), - 'maxPathTitleLength' => $this->getMaxPathTitleLength(), - 'searchWholePhrase' => intval($this->getSearchWholePhrase()), - 'searchCondition' => $this->getSearchCondition(), - 'cssClass' => $this->getCssClass(), - 'receiverClass' => $this->getReceiverClass(), - 'renderFunc' => $this->getRenderFunction(), - ), - ); - return $configuration; - } - - /** - * @return string - */ - public function getName() { - $name = $this->name; - return $name; - } - - /** - * @param string $cssClass - * @return Suggest - */ - public function setCssClass($cssClass) { - $this->cssClass = $cssClass; - return $this; - } - - /** - * @return string - */ - public function getCssClass() { - return $this->cssClass; - } - - /** - * @param integer $maxPathTitleLength - * @return Suggest - */ - public function setMaxPathTitleLength($maxPathTitleLength) { - $this->maxPathTitleLength = $maxPathTitleLength; - return $this; - } - - /** - * @return integer - */ - public function getMaxPathTitleLength() { - return $this->maxPathTitleLength; - } - - /** - * @param integer $minimumCharacters - * @return Suggest - */ - public function setMinimumCharacters($minimumCharacters) { - $this->minimumCharacters = $minimumCharacters; - return $this; - } - - /** - * @return integer - */ - public function getMinimumCharacters() { - return $this->minimumCharacters; - } - - /** - * @param string $receiverClass - * @return Suggest - */ - public function setReceiverClass($receiverClass) { - $this->receiverClass = $receiverClass; - return $this; - } - - /** - * @return string - */ - public function getReceiverClass() { - return $this->receiverClass; - } - - /** - * @param string $renderFunction - * @return Suggest - */ - public function setRenderFunction($renderFunction) { - $this->renderFunction = $renderFunction; - return $this; - } - - /** - * @return string - */ - public function getRenderFunction() { - return $this->renderFunction; - } - - /** - * @param string $searchCondition - * @return Suggest - */ - public function setSearchCondition($searchCondition) { - $this->searchCondition = $searchCondition; - return $this; - } - - /** - * @return string - */ - public function getSearchCondition() { - return $this->searchCondition; - } - - /** - * @param boolean $searchWholePhrase - * @return Suggest - */ - public function setSearchWholePhrase($searchWholePhrase) { - $this->searchWholePhrase = $searchWholePhrase; - return $this; - } - - /** - * @return boolean - */ - public function getSearchWholePhrase() { - return $this->searchWholePhrase; - } - - /** - * @return Suggest - * @param integer $storagePageRecursiveDepth - */ - public function setStoragePageRecursiveDepth($storagePageRecursiveDepth) { - $this->storagePageRecursiveDepth = $storagePageRecursiveDepth; - return $this; - } - - /** - * @return integer - */ - public function getStoragePageRecursiveDepth() { - return $this->storagePageRecursiveDepth; - } - - /** - * @param array $storagePageUids - * @return Suggest - */ - public function setStoragePageUids($storagePageUids) { - if (FALSE === is_array($storagePageUids)) { - $this->storagePageUids = GeneralUtility::trimExplode(',', $storagePageUids); - } else { - $this->storagePageUids = $storagePageUids; - } - return $this; - } - - /** - * @return array - */ - public function getStoragePageUids() { - return $this->storagePageUids; - } - - /** - * @param string $table - * @return Suggest - */ - public function setTable($table) { - $this->table = $table; - return $this; - } - - /** - * @return string - */ - public function getTable() { - return $this->table; - } - +class Suggest extends AbstractWizard +{ + + /** + * @var string + */ + protected $name = 'suggest'; + + /** + * @var string + */ + protected $type = 'suggest'; + + /** + * @var string + */ + protected $icon = null; + + /** + * @var array + */ + protected $module = null; + + /** + * @var string + */ + protected $table = 'pages'; + + /** + * @var array + */ + protected $storagePageUids = []; + + /** + * @var integer + */ + protected $storagePageRecursiveDepth = 99; + + /** + * @var integer + */ + protected $minimumCharacters = 1; + + /** + * Maximum path segment length - crops titles over this length + * @var integer + */ + protected $maxPathTitleLength = 15; + + /** + * A match requires a full word that matches the search value + * @var boolean + */ + protected $searchWholePhrase = false; + + /** + * Search condition - for example, if table is pages "doktype = 1" to only allow standard pages + * @var string + */ + protected $searchCondition = ''; + + /** + * Use this CSS class for all list items + * @var string + */ + protected $cssClass = ''; + + /** + * Class reference, target class should be derived from "t3lib_tceforms_suggest_defaultreceiver" + * @var string + */ + protected $receiverClass = ''; + + /** + * Reference to function which processes all records displayed in results + * @var string + */ + protected $renderFunction = ''; + + /** + * @return array + */ + public function buildConfiguration() + { + $table = $this->getTable(); + $configuration = [ + 'type' => 'suggest', + $table => [ + 'table' => $table, + 'pidList' => implode(',', $this->getStoragePageUids()), + 'pidDepth' => $this->getStoragePageRecursiveDepth(), + 'minimumCharacters' => $this->getMinimumCharacters(), + 'maxPathTitleLength' => $this->getMaxPathTitleLength(), + 'searchWholePhrase' => intval($this->getSearchWholePhrase()), + 'searchCondition' => $this->getSearchCondition(), + 'cssClass' => $this->getCssClass(), + 'receiverClass' => $this->getReceiverClass(), + 'renderFunc' => $this->getRenderFunction(), + ], + ]; + return $configuration; + } + + /** + * @return string + */ + public function getName() + { + $name = $this->name; + return $name; + } + + /** + * @param string $cssClass + * @return Suggest + */ + public function setCssClass($cssClass) + { + $this->cssClass = $cssClass; + return $this; + } + + /** + * @return string + */ + public function getCssClass() + { + return $this->cssClass; + } + + /** + * @param integer $maxPathTitleLength + * @return Suggest + */ + public function setMaxPathTitleLength($maxPathTitleLength) + { + $this->maxPathTitleLength = $maxPathTitleLength; + return $this; + } + + /** + * @return integer + */ + public function getMaxPathTitleLength() + { + return $this->maxPathTitleLength; + } + + /** + * @param integer $minimumCharacters + * @return Suggest + */ + public function setMinimumCharacters($minimumCharacters) + { + $this->minimumCharacters = $minimumCharacters; + return $this; + } + + /** + * @return integer + */ + public function getMinimumCharacters() + { + return $this->minimumCharacters; + } + + /** + * @param string $receiverClass + * @return Suggest + */ + public function setReceiverClass($receiverClass) + { + $this->receiverClass = $receiverClass; + return $this; + } + + /** + * @return string + */ + public function getReceiverClass() + { + return $this->receiverClass; + } + + /** + * @param string $renderFunction + * @return Suggest + */ + public function setRenderFunction($renderFunction) + { + $this->renderFunction = $renderFunction; + return $this; + } + + /** + * @return string + */ + public function getRenderFunction() + { + return $this->renderFunction; + } + + /** + * @param string $searchCondition + * @return Suggest + */ + public function setSearchCondition($searchCondition) + { + $this->searchCondition = $searchCondition; + return $this; + } + + /** + * @return string + */ + public function getSearchCondition() + { + return $this->searchCondition; + } + + /** + * @param boolean $searchWholePhrase + * @return Suggest + */ + public function setSearchWholePhrase($searchWholePhrase) + { + $this->searchWholePhrase = $searchWholePhrase; + return $this; + } + + /** + * @return boolean + */ + public function getSearchWholePhrase() + { + return $this->searchWholePhrase; + } + + /** + * @return Suggest + * @param integer $storagePageRecursiveDepth + */ + public function setStoragePageRecursiveDepth($storagePageRecursiveDepth) + { + $this->storagePageRecursiveDepth = $storagePageRecursiveDepth; + return $this; + } + + /** + * @return integer + */ + public function getStoragePageRecursiveDepth() + { + return $this->storagePageRecursiveDepth; + } + + /** + * @param array $storagePageUids + * @return Suggest + */ + public function setStoragePageUids($storagePageUids) + { + if (false === is_array($storagePageUids)) { + $this->storagePageUids = GeneralUtility::trimExplode(',', $storagePageUids); + } else { + $this->storagePageUids = $storagePageUids; + } + return $this; + } + + /** + * @return array + */ + public function getStoragePageUids() + { + return $this->storagePageUids; + } + + /** + * @param string $table + * @return Suggest + */ + public function setTable($table) + { + $this->table = $table; + return $this; + } + + /** + * @return string + */ + public function getTable() + { + return $this->table; + } } diff --git a/Classes/Form/WizardInterface.php b/Classes/Form/WizardInterface.php index 9683525a9..a35011e3b 100644 --- a/Classes/Form/WizardInterface.php +++ b/Classes/Form/WizardInterface.php @@ -11,22 +11,22 @@ /** * WizardInterface */ -interface WizardInterface extends FormInterface { +interface WizardInterface extends FormInterface +{ - /** - * @return array - */ - public function buildConfiguration(); + /** + * @return array + */ + public function buildConfiguration(); - /** - * @param boolean $hideParent - * @return WizardInterface - */ - public function setHideParent($hideParent); - - /** - * @return boolean - */ - public function getHideParent(); + /** + * @param boolean $hideParent + * @return WizardInterface + */ + public function setHideParent($hideParent); + /** + * @return boolean + */ + public function getHideParent(); } diff --git a/Classes/Helper/Resolver.php b/Classes/Helper/Resolver.php index bc2e58267..02aca8c0b 100644 --- a/Classes/Helper/Resolver.php +++ b/Classes/Helper/Resolver.php @@ -17,145 +17,155 @@ /** * Class Resolver */ -class Resolver { +class Resolver +{ - /** - * @param string $extensionKey - * @param string $action - * @param string $controllerObjectShortName - * @param boolean $failHardClass - * @param boolean $failHardAction - * @throws \RuntimeException - * @return string|NULL - */ - public function resolveFluxControllerClassNameByExtensionKeyAndAction( - $extensionKey, - $action, - $controllerObjectShortName, - $failHardClass = FALSE, - $failHardAction = FALSE - ) { - $potentialControllerClassName = $this->buildControllerClassNameFromExtensionKeyAndControllerType( - $extensionKey, - $controllerObjectShortName - ); - if (FALSE === class_exists($potentialControllerClassName)) { - if (TRUE === $failHardClass) { - throw new \RuntimeException( - 'Class ' . $potentialControllerClassName . ' does not exist. It was build from: ' . - var_export($extensionKey, TRUE) . ' but the resulting class name was not found.', - 1364498093 - ); - } - return NULL; - } - if (FALSE === method_exists($potentialControllerClassName, $action . 'Action')) { - if (TRUE === $failHardAction) { - throw new \RuntimeException( - 'Class ' . $potentialControllerClassName . ' does not contain a method named ' . $action . 'Action', - 1364498223 - ); - } - return NULL; - } - return $potentialControllerClassName; - } + /** + * @param string $extensionKey + * @param string $action + * @param string $controllerObjectShortName + * @param boolean $failHardClass + * @param boolean $failHardAction + * @throws \RuntimeException + * @return string|NULL + */ + public function resolveFluxControllerClassNameByExtensionKeyAndAction( + $extensionKey, + $action, + $controllerObjectShortName, + $failHardClass = false, + $failHardAction = false + ) { + $potentialControllerClassName = $this->buildControllerClassNameFromExtensionKeyAndControllerType( + $extensionKey, + $controllerObjectShortName + ); + if (false === class_exists($potentialControllerClassName)) { + if (true === $failHardClass) { + throw new \RuntimeException( + 'Class ' . $potentialControllerClassName . ' does not exist. It was build from: ' . + var_export($extensionKey, true) . ' but the resulting class name was not found.', + 1364498093 + ); + } + return null; + } + if (false === method_exists($potentialControllerClassName, $action . 'Action')) { + if (true === $failHardAction) { + throw new \RuntimeException( + 'Class ' . $potentialControllerClassName . ' does not contain a method named ' . $action . 'Action', + 1364498223 + ); + } + return null; + } + return $potentialControllerClassName; + } - /** - * Resolves a list (array) of class names (not instances) of - * all classes in files in the specified sub-namespace of the - * specified package name. Does not attempt to load the class. - * Does not work recursively. - * - * @param string $packageName - * @param string $subNamespace - * @param string|NULL $requiredSuffix If specified, class name must use this suffix - * @return array - */ - public function resolveClassNamesInPackageSubNamespace($packageName, $subNamespace, $requiredSuffix = NULL) { - $classNames = array(); - $extensionKey = ExtensionNamingUtility::getExtensionKey($packageName); - $prefix = str_replace('.', '\\', $packageName); - $suffix = TRUE === empty($subNamespace) ? '' : str_replace('/', '\\', $subNamespace) . '\\'; - $folder = ExtensionManagementUtility::extPath($extensionKey, 'Classes/' . $subNamespace); - $files = GeneralUtility::getFilesInDir($folder, 'php'); - if (TRUE === is_array($files)) { - foreach ($files as $file) { - $filename = pathinfo($file, PATHINFO_FILENAME); - // include if no required suffix is given or string ends with suffix - if (NULL === $requiredSuffix || 1 === preg_match('/' . $requiredSuffix . '$/', $filename)) { - $classNames[] = $prefix . '\\' . $suffix . $filename; - } - } - } - return $classNames; - } + /** + * Resolves a list (array) of class names (not instances) of + * all classes in files in the specified sub-namespace of the + * specified package name. Does not attempt to load the class. + * Does not work recursively. + * + * @param string $packageName + * @param string $subNamespace + * @param string|NULL $requiredSuffix If specified, class name must use this suffix + * @return array + */ + public function resolveClassNamesInPackageSubNamespace($packageName, $subNamespace, $requiredSuffix = null) + { + $classNames = []; + $extensionKey = ExtensionNamingUtility::getExtensionKey($packageName); + $prefix = str_replace('.', '\\', $packageName); + $suffix = true === empty($subNamespace) ? '' : str_replace('/', '\\', $subNamespace) . '\\'; + $folder = ExtensionManagementUtility::extPath($extensionKey, 'Classes/' . $subNamespace); + $files = GeneralUtility::getFilesInDir($folder, 'php'); + if (true === is_array($files)) { + foreach ($files as $file) { + $filename = pathinfo($file, PATHINFO_FILENAME); + // include if no required suffix is given or string ends with suffix + if (null === $requiredSuffix || 1 === preg_match('/' . $requiredSuffix . '$/', $filename)) { + $classNames[] = $prefix . '\\' . $suffix . $filename; + } + } + } + return $classNames; + } - /** - * Resolves a list (array) of instances of Form implementations - * from the provided package names, or all package names if empty. - * - * @param array $packageNames - * @return Form[] - */ - public function resolveDomainFormClassInstancesFromPackages(array $packageNames = NULL) { - $packageNames = NULL === $packageNames ? Core::getRegisteredPackagesForAutoForms() : $packageNames; - $models = (array) Core::getRegisteredFormsForModelObjectClasses(); - foreach ($packageNames as $packageName) { - $classNames = $this->resolveClassNamesInPackageSubNamespace($packageName, 'Domain/Form', 'Form'); - foreach ($classNames as $formClassName) { - // convert form class name to model class name by convention - $modelClassName = str_replace('\\Domain\\Form\\', '\\Domain\\Model\\', $formClassName); - $modelClassName = substr($modelClassName, 0, -4); - $fullTableName = $this->resolveDatabaseTableName($modelClassName); - $models[$modelClassName] = $formClassName::create(); - $models[$modelClassName]->setName($fullTableName); - $models[$modelClassName]->setExtensionName($packageName); - } - } - return $models; - } + /** + * Resolves a list (array) of instances of Form implementations + * from the provided package names, or all package names if empty. + * + * @param array $packageNames + * @return Form[] + */ + public function resolveDomainFormClassInstancesFromPackages(array $packageNames = null) + { + $packageNames = null === $packageNames ? Core::getRegisteredPackagesForAutoForms() : $packageNames; + $models = (array) Core::getRegisteredFormsForModelObjectClasses(); + foreach ($packageNames as $packageName) { + $classNames = $this->resolveClassNamesInPackageSubNamespace($packageName, 'Domain/Form', 'Form'); + foreach ($classNames as $formClassName) { + // convert form class name to model class name by convention + $modelClassName = str_replace('\\Domain\\Form\\', '\\Domain\\Model\\', $formClassName); + $modelClassName = substr($modelClassName, 0, -4); + $fullTableName = $this->resolveDatabaseTableName($modelClassName); + $models[$modelClassName] = $formClassName::create(); + $models[$modelClassName]->setName($fullTableName); + $models[$modelClassName]->setExtensionName($packageName); + } + } + return $models; + } - /** - * Resolve the table name for the given class name - * - * @param string $className - * @return string The table name - */ - public function resolveDatabaseTableName($className) { - $className = ltrim($className, '\\'); - if (strpos($className, '\\') !== FALSE) { - $classNameParts = explode('\\', $className, 6); - // Skip vendor and product name for core classes - if (strpos($className, 'TYPO3\\CMS\\') === 0) { - $classPartsToSkip = 2; - } else { - $classPartsToSkip = 1; - } - $tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip))); - } else { - $tableName = strtolower($className); - } - return $tableName; - } - - /** - * @param string $extensionKey - * @param string $controllerName - * @return boolean|string - */ - private static function buildControllerClassNameFromExtensionKeyAndControllerType($extensionKey, $controllerName) { - if (TRUE === ExtensionNamingUtility::hasVendorName($extensionKey)) { - list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionKey); - $potentialClassName = $vendorName . '\\' . $extensionName . '\\Controller\\' . $controllerName . 'Controller'; - } else { - $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); - $potentialClassName = $extensionName . '\\Controller\\' . $controllerName . 'Controller'; - if (FALSE === class_exists($potentialClassName)) { - $potentialClassName = 'Tx_' . $extensionName . '_Controller_' . $controllerName . 'Controller'; - } - } - return $potentialClassName; - } + /** + * Resolve the table name for the given class name + * + * @param string $className + * @return string The table name + */ + public function resolveDatabaseTableName($className) + { + $className = ltrim($className, '\\'); + if (strpos($className, '\\') !== false) { + $classNameParts = explode('\\', $className, 6); + // Skip vendor and product name for core classes + if (strpos($className, 'TYPO3\\CMS\\') === 0) { + $classPartsToSkip = 2; + } else { + $classPartsToSkip = 1; + } + $tableName = 'tx_' . strtolower(implode('_', array_slice($classNameParts, $classPartsToSkip))); + } else { + $tableName = strtolower($className); + } + return $tableName; + } + /** + * @param string $extensionKey + * @param string $controllerName + * @return boolean|string + */ + private static function buildControllerClassNameFromExtensionKeyAndControllerType($extensionKey, $controllerName) + { + if (true === ExtensionNamingUtility::hasVendorName($extensionKey)) { + list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionKey); + $potentialClassName = sprintf( + '%s\\%s\\Controller\\%sController', + $vendorName, + $extensionName, + $controllerName + ); + } else { + $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); + $potentialClassName = $extensionName . '\\Controller\\' . $controllerName . 'Controller'; + // @TODO remove legacy + if (false === class_exists($potentialClassName)) { + $potentialClassName = 'Tx_' . $extensionName . '_Controller_' . $controllerName . 'Controller'; + } + } + return $potentialClassName; + } } diff --git a/Classes/Hooks/ContentIconHookSubscriber.php b/Classes/Hooks/ContentIconHookSubscriber.php index 6b8b91d0e..43e9cd85a 100644 --- a/Classes/Hooks/ContentIconHookSubscriber.php +++ b/Classes/Hooks/ContentIconHookSubscriber.php @@ -13,125 +13,136 @@ use FluidTYPO3\Flux\Utility\MiscellaneousUtility; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\PageLayoutView; +use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList; /** * Class ContentIconHookSubscriber */ -class ContentIconHookSubscriber { +class ContentIconHookSubscriber +{ - /** - * @var array - */ - protected $templates = array( - 'iconWrapper' => '%s
' - ); + /** + * @var array + */ + protected $templates = [ + 'iconWrapper' => '
%s +
' + ]; - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @var FluxService - */ - protected $fluxService; + /** + * @var FluxService + */ + protected $fluxService; - /** - * @var VariableFrontend - */ - protected $cache; + /** + * @var VariableFrontend + */ + protected $cache; - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * @param FluxService $fluxService - * @return void - */ - public function injectFluxService(FluxService $fluxService) { - $this->fluxService = $fluxService; - } + /** + * @param FluxService $fluxService + * @return void + */ + public function injectFluxService(FluxService $fluxService) + { + $this->fluxService = $fluxService; + } - /** - * Construct - */ - public function __construct() { - $this->injectObjectManager(GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager')); - $this->injectFluxService($this->objectManager->get('FluidTYPO3\\Flux\\Service\\FluxService')); - $this->cache = $this->objectManager->get('TYPO3\\CMS\\Core\\Cache\\CacheManager', $this->objectManager)->getCache('flux'); - } + /** + * Construct + */ + public function __construct() + { + $this->injectObjectManager(GeneralUtility::makeInstance(ObjectManager::class)); + $this->injectFluxService($this->objectManager->get(FluxService::class)); + $this->cache = $this->objectManager->get(CacheManager::class, $this->objectManager)->getCache('flux'); + } - /** - * @param array $parameters - * @param PageLayoutView|DatabaseRecordList $caller - * @return string - */ - public function addSubIcon(array $parameters, $caller = NULL) { - $this->attachAssets(); - list ($table, $uid, $record) = $parameters; - $icon = NULL; - if (NULL !== $caller) { - $record = NULL === $record && 0 < $uid ? BackendUtility::getRecord($table, $uid) : $record; - $cacheIdentity = $table . $uid . sha1(serialize($record)); - // filter 1: icon must not already be cached and both record and caller must be provided. - if (TRUE === $this->cache->has($cacheIdentity)) { - $icon = $this->cache->get($cacheIdentity); - } elseif (NULL !== $record) { - $field = $this->detectFirstFlexTypeFieldInTableFromPossibilities($table, array_keys($record)); - // filter 2: table must have one field defined as "flex" and record must include it. - if (NULL !== $field && TRUE === isset($record[$field])) { - // we check the cache here because at this point, the cache key is decidedly - // unique and we have not yet consulted the (potentially costly) Provider. - $provider = $this->fluxService->resolvePrimaryConfigurationProvider($table, $field, $record); - // filter 3: a Provider must be resolved for the record. - if (NULL !== $provider) { - $form = $provider->getForm((array) $record); - if (NULL !== $form) { - $icon = MiscellaneousUtility::getIconForTemplate($form); - if (NULL !== $icon) { - $label = trim($form->getLabel()); - $icon = '' . $label . 'attachAssets(); + list ($table, $uid, $record) = $parameters; + $icon = null; + if (null !== $caller) { + $record = null === $record && 0 < $uid ? BackendUtility::getRecord($table, $uid) : $record; + $cacheIdentity = $table . $uid . sha1(serialize($record)); + // filter 1: icon must not already be cached and both record and caller must be provided. + if (true === $this->cache->has($cacheIdentity)) { + $icon = $this->cache->get($cacheIdentity); + } elseif (null !== $record) { + $field = $this->detectFirstFlexTypeFieldInTableFromPossibilities($table, array_keys($record)); + // filter 2: table must have one field defined as "flex" and record must include it. + if (null !== $field && true === isset($record[$field])) { + // we check the cache here because at this point, the cache key is decidedly + // unique and we have not yet consulted the (potentially costly) Provider. + $provider = $this->fluxService->resolvePrimaryConfigurationProvider($table, $field, $record); + // filter 3: a Provider must be resolved for the record. + if (null !== $provider) { + $form = $provider->getForm((array) $record); + if (null !== $form) { + $icon = MiscellaneousUtility::getIconForTemplate($form); + if (null !== $icon) { + $label = trim($form->getLabel()); + $icon = '' . $label . ''; - $icon = sprintf($this->templates['iconWrapper'], $icon); - } - } - } - } - $this->cache->set($cacheIdentity, $icon); - } - } - return $icon; - } + $icon = sprintf($this->templates['iconWrapper'], $icon); + } + } + } + } + $this->cache->set($cacheIdentity, $icon); + } + } + return $icon; + } - /** - * @param string $table - * @param array $fields - * @return string - */ - protected function detectFirstFlexTypeFieldInTableFromPossibilities($table, $fields) { - foreach ($fields as $fieldName) { - if ('flex' === $GLOBALS['TCA'][$table]['columns'][$fieldName]['config']['type']) { - return $fieldName; - } - } - return NULL; - } - - /** - * @return void - */ - protected function attachAssets() { - $GLOBALS['TBE_STYLES']['stylesheet'] = $doc->backPath . ExtensionManagementUtility::extRelPath('flux') . 'Resources/Public/css/icon.css'; - } + /** + * @param string $table + * @param array $fields + * @return string + */ + protected function detectFirstFlexTypeFieldInTableFromPossibilities($table, $fields) + { + foreach ($fields as $fieldName) { + if ('flex' === $GLOBALS['TCA'][$table]['columns'][$fieldName]['config']['type']) { + return $fieldName; + } + } + return null; + } + /** + * @return void + */ + protected function attachAssets() + { + $GLOBALS['TBE_STYLES']['stylesheet'] = $doc->backPath . + ExtensionManagementUtility::extRelPath('flux') . + 'Resources/Public/css/icon.css'; + } } diff --git a/Classes/Hooks/RecordListGetTableHookSubscriber.php b/Classes/Hooks/RecordListGetTableHookSubscriber.php index 36b4c7148..466cc3648 100644 --- a/Classes/Hooks/RecordListGetTableHookSubscriber.php +++ b/Classes/Hooks/RecordListGetTableHookSubscriber.php @@ -16,22 +16,23 @@ * This class removes all elements with colPos=18181 from db list view to avoid trouble with sorting * containers into child elements. */ -class RecordListGetTableHookSubscriber implements RecordListGetTableHookInterface { - - /** - * modifies the DB list query: no elements with colPos=18181 are shown, these are child elements - * - * @param string $table The current database table - * @param integer $pageId The record's page ID - * @param string $additionalWhereClause An additional WHERE clause - * @param string $selectedFieldsList Comma separated list of selected fields - * @param DatabaseRecordList $parentObject Parent localRecordList object - * @return void - */ - public function getDBlistQuery($table, $pageId, &$additionalWhereClause, &$selectedFieldsList, &$parentObject) { - if ('tt_content' === $table) { - $additionalWhereClause .= ' AND colPos <> ' . ContentService::COLPOS_FLUXCONTENT; - } - } +class RecordListGetTableHookSubscriber implements RecordListGetTableHookInterface +{ + /** + * modifies the DB list query: no elements with colPos=18181 are shown, these are child elements + * + * @param string $table The current database table + * @param integer $pageId The record's page ID + * @param string $additionalWhereClause An additional WHERE clause + * @param string $selectedFieldsList Comma separated list of selected fields + * @param DatabaseRecordList $parentObject Parent localRecordList object + * @return void + */ + public function getDBlistQuery($table, $pageId, &$additionalWhereClause, &$selectedFieldsList, &$parentObject) + { + if ('tt_content' === $table) { + $additionalWhereClause .= ' AND colPos <> ' . ContentService::COLPOS_FLUXCONTENT; + } + } } diff --git a/Classes/Hooks/WizardItemsHookSubscriber.php b/Classes/Hooks/WizardItemsHookSubscriber.php index 8cf573bbc..3dc07233d 100644 --- a/Classes/Hooks/WizardItemsHookSubscriber.php +++ b/Classes/Hooks/WizardItemsHookSubscriber.php @@ -14,289 +14,335 @@ use TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController; use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * WizardItemsHookSubscriber */ -class WizardItemsHookSubscriber implements NewContentElementWizardHookInterface { +class WizardItemsHookSubscriber implements NewContentElementWizardHookInterface +{ - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @var FluxService - */ - protected $configurationService; + /** + * @var FluxService + */ + protected $configurationService; - /** - * @var WorkspacesAwareRecordService - */ - protected $recordService; + /** + * @var WorkspacesAwareRecordService + */ + protected $recordService; - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * @param FluxService $configurationService - * @return void - */ - public function injectConfigurationService(FluxService $configurationService) { - $this->configurationService = $configurationService; - } + /** + * @param FluxService $configurationService + * @return void + */ + public function injectConfigurationService(FluxService $configurationService) + { + $this->configurationService = $configurationService; + } - /** - * @param WorkspacesAwareRecordService $recordService - * @return void - */ - public function injectRecordService(WorkspacesAwareRecordService $recordService) { - $this->recordService = $recordService; - } + /** + * @param WorkspacesAwareRecordService $recordService + * @return void + */ + public function injectRecordService(WorkspacesAwareRecordService $recordService) + { + $this->recordService = $recordService; + } - /** - * Constructor - */ - public function __construct() { - /** @var ObjectManagerInterface $objectManager */ - $objectManager = GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager'); - $this->injectObjectManager($objectManager); - /** @var FluxService $configurationService */ - $configurationService = $this->objectManager->get('FluidTYPO3\Flux\Service\FluxService'); - $this->injectConfigurationService($configurationService); - /** @var WorkspacesAwareRecordService $recordService */ - $recordService = $this->objectManager->get('FluidTYPO3\Flux\Service\WorkspacesAwareRecordService'); - $this->injectRecordService($recordService); - } + /** + * Constructor + */ + public function __construct() + { + /** @var ObjectManagerInterface $objectManager */ + $objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $this->injectObjectManager($objectManager); + /** @var FluxService $configurationService */ + $configurationService = $this->objectManager->get(FluxService::class); + $this->injectConfigurationService($configurationService); + /** @var WorkspacesAwareRecordService $recordService */ + $recordService = $this->objectManager->get(WorkspacesAwareRecordService::class); + $this->injectRecordService($recordService); + } - /** - * @param array $items - * @param \TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController - * @return void - */ - public function manipulateWizardItems(&$items, &$parentObject) { - $items = $this->filterPermittedFluidContentTypesByInsertionPosition($items, $parentObject); - } + /** + * @param array $items + * @param \TYPO3\CMS\Backend\Controller\ContentElement\NewContentElementController + * @return void + */ + public function manipulateWizardItems(&$items, &$parentObject) + { + $items = $this->filterPermittedFluidContentTypesByInsertionPosition($items, $parentObject); + } - /** - * @param array $items - * @param NewContentElementController $parentObject - * @return array - */ - protected function filterPermittedFluidContentTypesByInsertionPosition(array $items, $parentObject) { - list ($whitelist, $blacklist) = $this->getWhiteAndBlackListsFromPageAndContentColumn( - $parentObject->id, - $parentObject->colPos, - $parentObject->uid_pid - ); - $items = $this->applyWhitelist($items, $whitelist); - $items = $this->applyBlacklist($items, $blacklist); - $items = $this->applyDefaultValues($items, $this->getDefaultValues()); - $items = $this->trimItems($items); - return $items; - } + /** + * @param array $items + * @param NewContentElementController $parentObject + * @return array + */ + protected function filterPermittedFluidContentTypesByInsertionPosition(array $items, $parentObject) + { + list ($whitelist, $blacklist) = $this->getWhiteAndBlackListsFromPageAndContentColumn( + $parentObject->id, + $parentObject->colPos, + $parentObject->uid_pid + ); + $items = $this->applyWhitelist($items, $whitelist); + $items = $this->applyBlacklist($items, $blacklist); + $items = $this->applyDefaultValues($items, $this->getDefaultValues()); + $items = $this->trimItems($items); + return $items; + } - /** - * @return array - */ - protected function getDefaultValues() { - $values = GeneralUtility::_GET('defVals'); - return (array) $values['tt_content']; - } + /** + * @return array + */ + protected function getDefaultValues() + { + $values = GeneralUtility::_GET('defVals'); + return (array) $values['tt_content']; + } - /** - * @param integer $pageUid - * @param integer $columnPosition - * @param integer $relativeUid - * @return array - */ - protected function getWhiteAndBlackListsFromPageAndContentColumn($pageUid, $columnPosition, $relativeUid) { - $whitelist = array(); - $blacklist = array(); - // if a Provider is registered for the "pages" table, try to get a Grid from it. If the Grid - // returned contains a Column which matches the desired colPos value, attempt to read a list - // of allowed/denied content element types from it. - $pageRecord = (array) $this->recordService->getSingle('pages', '*', $pageUid); - $pageProviders = $this->configurationService->resolveConfigurationProviders('pages', NULL, $pageRecord); - $this->appendToWhiteAndBlacklistFromProviders($pageProviders, $pageRecord, $whitelist, $blacklist, $columnPosition); - // Detect what was clicked in order to create the new content element; decide restrictions - // based on this. Returned parent UID and area name is either non-zero and string, or zero - // and NULL when record is NOT inserted as child. - list ($parentRecordUid, $fluxAreaName) = $this->getAreaNameAndParentFromRelativeRecordOrDefaults($relativeUid); - // if these variables now indicate that we are inserting content elements into a Flux-enabled content - // area inside another content element, attempt to read allowed/denied content types from the - // Grid returned by the Provider that applies to the parent element's type and configuration - // (admitted, that's quite a mouthful - but it's not that different from reading the values from - // a page template like above; it's the same principle). - if (0 < $parentRecordUid && FALSE === empty($fluxAreaName)) { - $parentRecord = (array) $this->recordService->getSingle('tt_content', '*', $parentRecordUid); - $contentProviders = $this->configurationService->resolveConfigurationProviders('tt_content', NULL, $parentRecord); - $this->appendToWhiteAndBlacklistFromProviders($contentProviders, $parentRecord, $whitelist, $blacklist, NULL, $fluxAreaName); - } - // White/blacklist filtering. If whitelist contains elements, filter the list - // of possible types by whitelist first. Then apply the blacklist, removing - // any element types recorded herein. - $whitelist = array_unique($whitelist); - $blacklist = array_unique($blacklist); - return array($whitelist, $blacklist); - } + /** + * @param integer $pageUid + * @param integer $columnPosition + * @param integer $relativeUid + * @return array + */ + protected function getWhiteAndBlackListsFromPageAndContentColumn($pageUid, $columnPosition, $relativeUid) + { + $whitelist = []; + $blacklist = []; + // if a Provider is registered for the "pages" table, try to get a Grid from it. If the Grid + // returned contains a Column which matches the desired colPos value, attempt to read a list + // of allowed/denied content element types from it. + $pageRecord = (array) $this->recordService->getSingle('pages', '*', $pageUid); + $pageProviders = $this->configurationService->resolveConfigurationProviders('pages', null, $pageRecord); + $this->appendToWhiteAndBlacklistFromProviders( + $pageProviders, + $pageRecord, + $whitelist, + $blacklist, + $columnPosition + ); + // Detect what was clicked in order to create the new content element; decide restrictions + // based on this. Returned parent UID and area name is either non-zero and string, or zero + // and NULL when record is NOT inserted as child. + list ($parentRecordUid, $fluxAreaName) = $this->getAreaNameAndParentFromRelativeRecordOrDefaults($relativeUid); + // if these variables now indicate that we are inserting content elements into a Flux-enabled content + // area inside another content element, attempt to read allowed/denied content types from the + // Grid returned by the Provider that applies to the parent element's type and configuration + // (admitted, that's quite a mouthful - but it's not that different from reading the values from + // a page template like above; it's the same principle). + if (0 < $parentRecordUid && false === empty($fluxAreaName)) { + $parentRecord = (array) $this->recordService->getSingle('tt_content', '*', $parentRecordUid); + $contentProviders = $this->configurationService->resolveConfigurationProviders( + 'tt_content', + null, + $parentRecord + ); + $this->appendToWhiteAndBlacklistFromProviders( + $contentProviders, + $parentRecord, + $whitelist, + $blacklist, + null, + $fluxAreaName + ); + } + // White/blacklist filtering. If whitelist contains elements, filter the list + // of possible types by whitelist first. Then apply the blacklist, removing + // any element types recorded herein. + $whitelist = array_unique($whitelist); + $blacklist = array_unique($blacklist); + return [$whitelist, $blacklist]; + } - /** - * @param integer $relativeUid - * @return array - */ - protected function getAreaNameAndParentFromRelativeRecordOrDefaults($relativeUid) { - $fluxAreaName = NULL; - $parentRecordUid = 0; - $defaultValues = $this->getDefaultValues(); - if (0 > $relativeUid) { - // pasting after another element means we should try to resolve the Flux content relation - // from that element instead of GET parameters (clicked: "create new" icon after other element) - $parentRecord = $this->recordService->getSingle('tt_content', '*', abs($relativeUid)); - $fluxAreaName = (string) $parentRecord['tx_flux_column']; - $parentRecordUid = (integer) $parentRecord['tx_flux_parent']; - } elseif (TRUE === isset($defaultValues['tx_flux_column'])) { - // attempt to read the target Flux content area from GET parameters (clicked: "create new" icon - // in top of nested Flux content area - $fluxAreaName = (string) $defaultValues['tx_flux_column']; - $parentRecordUid = (integer) $defaultValues['tx_flux_parent']; - } - return array($parentRecordUid, $fluxAreaName); - } + /** + * @param integer $relativeUid + * @return array + */ + protected function getAreaNameAndParentFromRelativeRecordOrDefaults($relativeUid) + { + $fluxAreaName = null; + $parentRecordUid = 0; + $defaultValues = $this->getDefaultValues(); + if (0 > $relativeUid) { + // pasting after another element means we should try to resolve the Flux content relation + // from that element instead of GET parameters (clicked: "create new" icon after other element) + $parentRecord = $this->recordService->getSingle('tt_content', '*', abs($relativeUid)); + $fluxAreaName = (string) $parentRecord['tx_flux_column']; + $parentRecordUid = (integer) $parentRecord['tx_flux_parent']; + } elseif (true === isset($defaultValues['tx_flux_column'])) { + // attempt to read the target Flux content area from GET parameters (clicked: "create new" icon + // in top of nested Flux content area + $fluxAreaName = (string) $defaultValues['tx_flux_column']; + $parentRecordUid = (integer) $defaultValues['tx_flux_parent']; + } + return [$parentRecordUid, $fluxAreaName]; + } - /** - * @param array $providers - * @param array $record - * @param array $whitelist - * @param array $blacklist - * @param integer $columnPosition - * @param string $fluxAreaName - */ - protected function appendToWhiteAndBlacklistFromProviders( - array $providers, - array $record, - array &$whitelist, - array &$blacklist, - $columnPosition, - $fluxAreaName = NULL - ) { - foreach ($providers as $provider) { - $grid = $provider->getGrid($record); - if (NULL === $grid) { - continue; - } - foreach ($grid->getRows() as $row) { - foreach ($row->getColumns() as $column) { - if (FALSE === empty($fluxAreaName)) { - if ($column->getName() === $fluxAreaName) { - list ($whitelist, $blacklist) = $this->appendToWhiteAndBlacklistFromComponent($column, $whitelist, $blacklist); - } - } elseif ($column->getColumnPosition() === $columnPosition) { - list ($whitelist, $blacklist) = $this->appendToWhiteAndBlacklistFromComponent($column, $whitelist, $blacklist); - } - } - } - } + /** + * @param array $providers + * @param array $record + * @param array $whitelist + * @param array $blacklist + * @param integer $columnPosition + * @param string $fluxAreaName + */ + protected function appendToWhiteAndBlacklistFromProviders( + array $providers, + array $record, + array &$whitelist, + array &$blacklist, + $columnPosition, + $fluxAreaName = null + ) { + foreach ($providers as $provider) { + $grid = $provider->getGrid($record); + if (null === $grid) { + continue; + } + foreach ($grid->getRows() as $row) { + foreach ($row->getColumns() as $column) { + if (false === empty($fluxAreaName)) { + if ($column->getName() === $fluxAreaName) { + list ($whitelist, $blacklist) = $this->appendToWhiteAndBlacklistFromComponent( + $column, + $whitelist, + $blacklist + ); + } + } elseif ($column->getColumnPosition() === $columnPosition) { + list ($whitelist, $blacklist) = $this->appendToWhiteAndBlacklistFromComponent( + $column, + $whitelist, + $blacklist + ); + } + } + } + } - } + } - /** - * @param array $items - * @param array $defaultValues - * @return array - */ - protected function applyDefaultValues(array $items, array $defaultValues) { - foreach ($items as $name => $item) { - if (FALSE === empty($defaultValues['tx_flux_column'])) { - $items[$name]['tt_content_defValues']['tx_flux_column'] = $defaultValues['tx_flux_column']; - $items[$name]['params'] .= '&defVals[tt_content][tx_flux_column]=' . rawurlencode($defaultValues['tx_flux_column']); - } - if (FALSE === empty($defaultValues['tx_flux_parent'])) { - $items[$name]['tt_content_defValues']['tx_flux_parent'] = $defaultValues['tx_flux_parent']; - $items[$name]['params'] .= '&defVals[tt_content][tx_flux_parent]=' . rawurlencode($defaultValues['tx_flux_parent']); - $items[$name]['params'] .= '&overrideVals[tt_content][tx_flux_parent]=' . rawurlencode($defaultValues['tx_flux_parent']); - } - } - return $items; - } + /** + * @param array $items + * @param array $defaultValues + * @return array + */ + protected function applyDefaultValues(array $items, array $defaultValues) + { + foreach ($items as $name => $item) { + if (false === empty($defaultValues['tx_flux_column'])) { + $items[$name]['tt_content_defValues']['tx_flux_column'] = $defaultValues['tx_flux_column']; + $items[$name]['params'] .= '&defVals[tt_content][tx_flux_column]=' . + rawurlencode($defaultValues['tx_flux_column']); + } + if (false === empty($defaultValues['tx_flux_parent'])) { + $items[$name]['tt_content_defValues']['tx_flux_parent'] = $defaultValues['tx_flux_parent']; + $items[$name]['params'] .= '&defVals[tt_content][tx_flux_parent]=' . + rawurlencode($defaultValues['tx_flux_parent']); + $items[$name]['params'] .= '&overrideVals[tt_content][tx_flux_parent]=' . + rawurlencode($defaultValues['tx_flux_parent']); + } + } + return $items; + } - /** - * @param array $items - * @return array - */ - protected function trimItems(array $items) { - $preserveHeaders = array(); - foreach ($items as $name => $item) { - if (FALSE !== strpos($name, '_')) { - array_push($preserveHeaders, reset(explode('_', $name))); - } - } - foreach ($items as $name => $item) { - if (FALSE === strpos($name, '_') && FALSE === in_array($name, $preserveHeaders)) { - unset($items[$name]); - } - } - return $items; - } + /** + * @param array $items + * @return array + */ + protected function trimItems(array $items) + { + $preserveHeaders = []; + foreach ($items as $name => $item) { + if (false !== strpos($name, '_')) { + array_push($preserveHeaders, reset(explode('_', $name))); + } + } + foreach ($items as $name => $item) { + if (false === strpos($name, '_') && false === in_array($name, $preserveHeaders)) { + unset($items[$name]); + } + } + return $items; + } - /** - * @param array $items - * @param array $blacklist - * @return array - */ - protected function applyBlacklist(array $items, array $blacklist) { - $blacklist = array_unique($blacklist); - if (0 < count($blacklist)) { - foreach ($blacklist as $contentElementType) { - foreach ($items as $name => $item) { - if ($item['tt_content_defValues']['CType'] === $contentElementType) { - unset($items[$name]); - } - } - } - } - return $items; - } + /** + * @param array $items + * @param array $blacklist + * @return array + */ + protected function applyBlacklist(array $items, array $blacklist) + { + $blacklist = array_unique($blacklist); + if (0 < count($blacklist)) { + foreach ($blacklist as $contentElementType) { + foreach ($items as $name => $item) { + if ($item['tt_content_defValues']['CType'] === $contentElementType) { + unset($items[$name]); + } + } + } + } + return $items; + } - /** - * @param array $items - * @param array $whitelist - * @return array - */ - protected function applyWhitelist(array $items, array $whitelist) { - $whitelist = array_unique($whitelist); - if (0 < count($whitelist)) { - foreach ($items as $name => $item) { - if (FALSE !== strpos($name, '_') && FALSE === in_array($item['tt_content_defValues']['CType'], $whitelist)) { - unset($items[$name]); - } - } - } - return $items; - } - - /** - * @param FormInterface $component - * @param array $whitelist - * @param array $blacklist - * @return array - */ - protected function appendToWhiteAndBlacklistFromComponent(FormInterface $component, array $whitelist, array $blacklist) { - $allowed = $component->getVariable('allowedContentTypes'); - if (NULL !== $allowed) { - $whitelist = array_merge($whitelist, GeneralUtility::trimExplode(',', $allowed)); - } - $denied = $component->getVariable('deniedContentTypes'); - if (NULL !== $denied) { - $blacklist = array_merge($blacklist, GeneralUtility::trimExplode(',', $denied)); - } - return array($whitelist, $blacklist); - } + /** + * @param array $items + * @param array $whitelist + * @return array + */ + protected function applyWhitelist(array $items, array $whitelist) + { + $whitelist = array_unique($whitelist); + if (0 < count($whitelist)) { + foreach ($items as $name => $item) { + if (false !== strpos($name, '_') && !in_array($item['tt_content_defValues']['CType'], $whitelist)) { + unset($items[$name]); + } + } + } + return $items; + } + /** + * @param FormInterface $component + * @param array $whitelist + * @param array $blacklist + * @return array + */ + protected function appendToWhiteAndBlacklistFromComponent( + FormInterface $component, + array $whitelist, + array $blacklist + ) { + $allowed = $component->getVariable('allowedContentTypes'); + if (null !== $allowed) { + $whitelist = array_merge($whitelist, GeneralUtility::trimExplode(',', $allowed)); + } + $denied = $component->getVariable('deniedContentTypes'); + if (null !== $denied) { + $blacklist = array_merge($blacklist, GeneralUtility::trimExplode(',', $denied)); + } + return [$whitelist, $blacklist]; + } } diff --git a/Classes/Outlet/AbstractOutlet.php b/Classes/Outlet/AbstractOutlet.php index 4d17938f8..0f29cc143 100644 --- a/Classes/Outlet/AbstractOutlet.php +++ b/Classes/Outlet/AbstractOutlet.php @@ -17,127 +17,137 @@ * Defines one data outlet for a Fluid form. Each outlet * is updated with the information when the form is saved. */ -abstract class AbstractOutlet implements OutletInterface { - - /** - * @var boolean - */ - protected $enabled = TRUE; - - /** - * @var mixed - */ - protected $data; - - /** - * @var PipeInterface[] - */ - protected $pipesIn = array(); - - /** - * @var PipeInterface[] - */ - protected $pipesOut = array(); - - /** - * @param boolean $enabled - * @return OutletInterface - */ - public function setEnabled($enabled) { - $this->enabled = $enabled; - return $this; - } - - /** - * @return boolean - */ - public function getEnabled() { - return $this->enabled; - } - - /** - * @param PipeInterface[] $pipes - * @return OutletInterface - * @return void - */ - public function setPipesIn(array $pipes) { - $this->pipesIn = array(); - foreach ($pipes as $pipe) { - $this->addPipeIn($pipe); - } - return $this; - } - - /** - * @return PipeInterface[] - */ - public function getPipesIn() { - return $this->pipesIn; - } - - /** - * @param PipeInterface[] $pipes - * @return OutletInterface - * @return void - */ - public function setPipesOut(array $pipes) { - $this->pipesOut = array(); - foreach ($pipes as $pipe) { - $this->addPipeOut($pipe); - } - return $this; - } - - /** - * @return PipeInterface[] - */ - public function getPipesOut() { - return $this->pipesOut; - } - - /** - * @param PipeInterface $pipe - * @return OutletInterface - */ - public function addPipeIn(PipeInterface $pipe) { - if (FALSE === in_array($pipe, $this->pipesIn)) { - array_push($this->pipesIn, $pipe); - } - return $this; - } - - /** - * @param PipeInterface $pipe - * @return OutletInterface - */ - public function addPipeOut(PipeInterface $pipe) { - if (FALSE === in_array($pipe, $this->pipesOut)) { - array_push($this->pipesOut, $pipe); - } - return $this; - } - - /** - * @param mixed $data - * @return OutletInterface - */ - public function fill($data) { - foreach ($this->pipesIn as $pipe) { - $data = $pipe->conduct($data); - } - $this->data = $data; - return $this; - } - - /** - * @return mixed - */ - public function produce() { - $data = $this->data; - foreach ($this->pipesOut as $pipe) { - $pipe->conduct($data); - } - return $data; - } - +abstract class AbstractOutlet implements OutletInterface +{ + + /** + * @var boolean + */ + protected $enabled = true; + + /** + * @var mixed + */ + protected $data; + + /** + * @var PipeInterface[] + */ + protected $pipesIn = []; + + /** + * @var PipeInterface[] + */ + protected $pipesOut = []; + + /** + * @param boolean $enabled + * @return OutletInterface + */ + public function setEnabled($enabled) + { + $this->enabled = $enabled; + return $this; + } + + /** + * @return boolean + */ + public function getEnabled() + { + return $this->enabled; + } + + /** + * @param PipeInterface[] $pipes + * @return OutletInterface + * @return void + */ + public function setPipesIn(array $pipes) + { + $this->pipesIn = []; + foreach ($pipes as $pipe) { + $this->addPipeIn($pipe); + } + return $this; + } + + /** + * @return PipeInterface[] + */ + public function getPipesIn() + { + return $this->pipesIn; + } + + /** + * @param PipeInterface[] $pipes + * @return OutletInterface + * @return void + */ + public function setPipesOut(array $pipes) + { + $this->pipesOut = []; + foreach ($pipes as $pipe) { + $this->addPipeOut($pipe); + } + return $this; + } + + /** + * @return PipeInterface[] + */ + public function getPipesOut() + { + return $this->pipesOut; + } + + /** + * @param PipeInterface $pipe + * @return OutletInterface + */ + public function addPipeIn(PipeInterface $pipe) + { + if (false === in_array($pipe, $this->pipesIn)) { + array_push($this->pipesIn, $pipe); + } + return $this; + } + + /** + * @param PipeInterface $pipe + * @return OutletInterface + */ + public function addPipeOut(PipeInterface $pipe) + { + if (false === in_array($pipe, $this->pipesOut)) { + array_push($this->pipesOut, $pipe); + } + return $this; + } + + /** + * @param mixed $data + * @return OutletInterface + */ + public function fill($data) + { + foreach ($this->pipesIn as $pipe) { + $data = $pipe->conduct($data); + } + $this->data = $data; + return $this; + } + + /** + * @return mixed + */ + public function produce() + { + $data = $this->data; + foreach ($this->pipesOut as $pipe) { + $pipe->conduct($data); + } + return $data; + } } diff --git a/Classes/Outlet/Exception.php b/Classes/Outlet/Exception.php index e54d5e6ae..1c60814e0 100644 --- a/Classes/Outlet/Exception.php +++ b/Classes/Outlet/Exception.php @@ -13,26 +13,26 @@ * * Thrown by Outlets on errors. */ -class Exception extends \Exception { +class Exception extends \Exception +{ - /** - * @var string - */ - protected $message; + /** + * @var string + */ + protected $message; - /** - * @var integer - */ - protected $code; + /** + * @var integer + */ + protected $code; - /** - * @var string - */ - protected $file; - - /** - * @var integer - */ - protected $line; + /** + * @var string + */ + protected $file; + /** + * @var integer + */ + protected $line; } diff --git a/Classes/Outlet/OutletInterface.php b/Classes/Outlet/OutletInterface.php index e1e15e4f1..125921c1c 100644 --- a/Classes/Outlet/OutletInterface.php +++ b/Classes/Outlet/OutletInterface.php @@ -16,68 +16,68 @@ * * Implemented by all Outlet types. */ -interface OutletInterface { +interface OutletInterface +{ - /** - * @param boolean $enabled - * @return void - * @abstract - */ - public function setEnabled($enabled); + /** + * @param boolean $enabled + * @return void + * @abstract + */ + public function setEnabled($enabled); - /** - * @return boolean - * @abstract - */ - public function getEnabled(); + /** + * @return boolean + * @abstract + */ + public function getEnabled(); - /** - * @param array $data - * @return mixed - * @abstract - */ - public function fill($data); + /** + * @param array $data + * @return mixed + * @abstract + */ + public function fill($data); - /** - * @return mixed - * @abstract - */ - public function produce(); + /** + * @return mixed + * @abstract + */ + public function produce(); - /** - * @param PipeInterface[] $pipes - * @return OutletInterface - * @return void - */ - public function setPipesIn(array $pipes); + /** + * @param PipeInterface[] $pipes + * @return OutletInterface + * @return void + */ + public function setPipesIn(array $pipes); - /** - * @return PipeInterface[] - */ - public function getPipesIn(); + /** + * @return PipeInterface[] + */ + public function getPipesIn(); - /** - * @param PipeInterface[] $pipes - * @return OutletInterface - * @return void - */ - public function setPipesOut(array $pipes); + /** + * @param PipeInterface[] $pipes + * @return OutletInterface + * @return void + */ + public function setPipesOut(array $pipes); - /** - * @return PipeInterface[] - */ - public function getPipesOut(); + /** + * @return PipeInterface[] + */ + public function getPipesOut(); - /** - * @param PipeInterface $pipe - * @return OutletInterface - */ - public function addPipeIn(PipeInterface $pipe); - - /** - * @param PipeInterface $pipe - * @return OutletInterface - */ - public function addPipeOut(PipeInterface $pipe); + /** + * @param PipeInterface $pipe + * @return OutletInterface + */ + public function addPipeIn(PipeInterface $pipe); + /** + * @param PipeInterface $pipe + * @return OutletInterface + */ + public function addPipeOut(PipeInterface $pipe); } diff --git a/Classes/Outlet/Pipe/AbstractPipe.php b/Classes/Outlet/Pipe/AbstractPipe.php index 82ed8151c..1ec5e7ba5 100644 --- a/Classes/Outlet/Pipe/AbstractPipe.php +++ b/Classes/Outlet/Pipe/AbstractPipe.php @@ -20,60 +20,66 @@ * * Base class for all Pipes */ -abstract class AbstractPipe implements PipeInterface { +abstract class AbstractPipe implements PipeInterface +{ - /** - * @param array $settings - * @return void - */ - public function loadSettings(array $settings) { - foreach ($settings as $name => $value) { - if (TRUE === property_exists($this, $name)) { - ObjectAccess::setProperty($this, $name, $value); - } - } - } + /** + * @param array $settings + * @return void + */ + public function loadSettings(array $settings) + { + foreach ($settings as $name => $value) { + if (true === property_exists($this, $name)) { + ObjectAccess::setProperty($this, $name, $value); + } + } + } - /** - * @param mixed $data - * @return mixed - */ - public function conduct($data) { - return $data; - } + /** + * @param mixed $data + * @return mixed + */ + public function conduct($data) + { + return $data; + } - /** - * @return string - */ - public function getType() { - return substr(lcfirst(array_pop(explode('\\', get_class($this)))), 0, -4); - } + /** + * @return string + */ + public function getType() + { + return substr(lcfirst(array_pop(explode('\\', get_class($this)))), 0, -4); + } - /** - * @return string - */ - public function getLabel() { - $type = $this->getType(); - $translated = LocalizationUtility::translate('pipes.' . $type . '.label', 'flux'); - return (NULL === $translated ? $type : $translated); - } + /** + * @return string + */ + public function getLabel() + { + $type = $this->getType(); + $translated = LocalizationUtility::translate('pipes.' . $type . '.label', 'flux'); + return (null === $translated ? $type : $translated); + } - /** - * @return FieldInterface[] - */ - public function getFormFields() { - $class = get_class($this); - /** @var Input $labelField */ - $labelField = Input::create(array('type' => 'Input')); - $labelField->setName('label'); - $labelField->setDefault($this->getLabel()); - /** @var Select $classField */ - $classField = Select::create(array('type' => 'Select')); - $classField->setName('class'); - $classField->setItems(array($class => $class)); - return array( - 'label' => $labelField, - 'class' => $classField - ); - } + /** + * @return FieldInterface[] + */ + public function getFormFields() + { + $class = get_class($this); + /** @var Input $labelField */ + $labelField = Input::create(['type' => 'Input']); + $labelField->setName('label'); + $labelField->setDefault($this->getLabel()); + /** @var Select $classField */ + $classField = Select::create(['type' => 'Select']); + $classField->setName('class'); + $classField->setItems([$class => $class]); + return [ + 'label' => $labelField, + 'class' => $classField + ]; + } } diff --git a/Classes/Outlet/Pipe/ControllerPipe.php b/Classes/Outlet/Pipe/ControllerPipe.php index 21bd44ed7..3f0ce1c11 100644 --- a/Classes/Outlet/Pipe/ControllerPipe.php +++ b/Classes/Outlet/Pipe/ControllerPipe.php @@ -22,128 +22,137 @@ * * Passes data through a controller action */ -class ControllerPipe extends AbstractPipe implements PipeInterface { - - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - - /** - * @var string - */ - protected $controller; - - /** - * @var string - */ - protected $action; - - /** - * @var string - */ - protected $extensionName; - - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } - - /** - * @return FieldInterface[] - */ - public function getFormFields() { - $fields = parent::getFormFields(); - $extensionNames = array_keys((array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions']); - $extensionNames = array_combine($extensionNames, $extensionNames); - $fields['action'] = Input::create(array('type' => 'Input')); - $fields['action']->setName('action'); - $fields['action']->setValidate('trim,required'); - $fields['controller'] = Input::create(array('type' => 'Input')); - $fields['controller']->setName('controller'); - $fields['controller']->setValidate('trim,required'); - /** @var Select $selectField */ - $selectField = Select::create(array('type' => 'Select')); - $selectField->setName('extensionName'); - $selectField->setItems($extensionNames); - $fields['extensionName'] = $selectField; - return $fields; - } - - /** - * @param string $controller - * @return ControllerPipe - */ - public function setController($controller) { - $this->controller = $controller; - return $this; - } - - /** - * @return string - */ - public function getController() { - return $this->controller; - } - - /** - * @param string $action - * @return ControllerPipe - */ - public function setAction($action) { - $this->action = $action; - return $this; - } - - /** - * @return string - */ - public function getAction() { - return $this->action; - } - - /** - * @param string $extensionName - * @return ControllerPipe - */ - public function setExtensionName($extensionName) { - $this->extensionName = $extensionName; - return $this; - } - - /** - * @return string - */ - public function getExtensionName() { - return $this->extensionName; - } - - /** - * @param array $data - * @return mixed - */ - public function conduct($data) { - $extensionName = $this->getExtensionName(); - /** @var $request Request */ - $request = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Request'); - $request->setControllerName($this->getController()); - $request->setControllerActionName($this->getAction()); - list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionName); - $request->setControllerExtensionName($extensionName); - if (NULL !== $vendorName) { - $request->setControllerVendorName($vendorName); - } - - $request->setArguments($data); - /** @var $response Response */ - $response = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Response'); - /** @var $dispatcher Dispatcher */ - $dispatcher = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Dispatcher'); - $dispatcher->dispatch($request, $response); - return $response->getContent(); - } - +class ControllerPipe extends AbstractPipe implements PipeInterface +{ + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var string + */ + protected $controller; + + /** + * @var string + */ + protected $action; + + /** + * @var string + */ + protected $extensionName; + + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * @return FieldInterface[] + */ + public function getFormFields() + { + $fields = parent::getFormFields(); + $extensionNames = array_keys((array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions']); + $extensionNames = array_combine($extensionNames, $extensionNames); + $fields['action'] = Input::create(['type' => 'Input']); + $fields['action']->setName('action'); + $fields['action']->setValidate('trim,required'); + $fields['controller'] = Input::create(['type' => 'Input']); + $fields['controller']->setName('controller'); + $fields['controller']->setValidate('trim,required'); + /** @var Select $selectField */ + $selectField = Select::create(['type' => 'Select']); + $selectField->setName('extensionName'); + $selectField->setItems($extensionNames); + $fields['extensionName'] = $selectField; + return $fields; + } + + /** + * @param string $controller + * @return ControllerPipe + */ + public function setController($controller) + { + $this->controller = $controller; + return $this; + } + + /** + * @return string + */ + public function getController() + { + return $this->controller; + } + + /** + * @param string $action + * @return ControllerPipe + */ + public function setAction($action) + { + $this->action = $action; + return $this; + } + + /** + * @return string + */ + public function getAction() + { + return $this->action; + } + + /** + * @param string $extensionName + * @return ControllerPipe + */ + public function setExtensionName($extensionName) + { + $this->extensionName = $extensionName; + return $this; + } + + /** + * @return string + */ + public function getExtensionName() + { + return $this->extensionName; + } + + /** + * @param array $data + * @return mixed + */ + public function conduct($data) + { + $extensionName = $this->getExtensionName(); + /** @var $request Request */ + $request = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Request'); + $request->setControllerName($this->getController()); + $request->setControllerActionName($this->getAction()); + list($vendorName, $extensionName) = ExtensionNamingUtility::getVendorNameAndExtensionName($extensionName); + $request->setControllerExtensionName($extensionName); + if (null !== $vendorName) { + $request->setControllerVendorName($vendorName); + } + + $request->setArguments($data); + /** @var $response Response */ + $response = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Response'); + /** @var $dispatcher Dispatcher */ + $dispatcher = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Dispatcher'); + $dispatcher->dispatch($request, $response); + return $response->getContent(); + } } diff --git a/Classes/Outlet/Pipe/EmailPipe.php b/Classes/Outlet/Pipe/EmailPipe.php index 464045be6..a1259fabd 100644 --- a/Classes/Outlet/Pipe/EmailPipe.php +++ b/Classes/Outlet/Pipe/EmailPipe.php @@ -21,161 +21,173 @@ * Pipe if you want to - just as an example - create a proper * email body text containing a nice representaton of the data. */ -class EmailPipe extends AbstractPipe implements PipeInterface { - - /** - * @var string - */ - protected $subject; - - /** - * @var mixed - */ - protected $recipient; - - /** - * @var mixed - */ - protected $sender; - - /** - * @var string|NULL - */ - protected $body = NULL; - - /** - * @return FieldInterface[] - */ - public function getFormFields() { - $fields = parent::getFormFields(); - $fields['subject'] = Input::create(array('type' => 'Input')) - ->setName('subject'); - $fields['body'] = Text::create(array('type' => 'Text')) - ->setName('body'); - $fields['receipent'] = Input::create(array('type' => 'Input')) - ->setName('recipient'); - $fields['sender'] = Input::create(array('type' => 'Input')) - ->setName('sender'); - return $fields; - } - - /** - * @param string $recipient - * @return EmailPipe - */ - public function setRecipient($recipient) { - $this->recipient = $recipient; - return $this; - } - - /** - * @return string - */ - public function getRecipient() { - return $this->recipient; - } - - /** - * @param string $sender - * @return EmailPipe - */ - public function setSender($sender) { - $this->sender = $sender; - return $this; - } - - /** - * @return string - */ - public function getSender() { - return $this->sender; - } - - /** - * @param string $subject - * @return EmailPipe - */ - public function setSubject($subject) { - $this->subject = $subject; - return $this; - } - - /** - * @return string - */ - public function getSubject() { - return $this->subject; - } - - /** - * @param string|NULL $body - * @return EmailPipe - */ - public function setBody($body) { - $this->body = $body; - return $this; - } - - /** - * @return string|NULL - */ - public function getBody() { - return $this->body; - } - - /** - * @param mixed $data - * @return mixed - * @throws Exception - */ - public function conduct($data) { - try { - $message = $this->prepareEmail($data); - $this->sendEmail($message); - } catch (\Swift_RfcComplianceException $error) { - throw new Exception($error->getMessage(), $error->getCode()); - } - return $data; - } - - /** - * @param string $data - * @return MailMessage - */ - protected function prepareEmail($data) { - $body = $this->getBody(); - $sender = $this->getSender(); - $recipient = $this->getRecipient(); - if (TRUE === is_array($recipient)) { - list ($recipientAddress, $recipientName) = $recipient; - } else { - $recipientAddress = $recipient; - $recipientName = NULL; - } - if (TRUE === is_array($sender)) { - list ($senderAddress, $senderName) = $sender; - } else { - $senderAddress = $sender; - $senderName = NULL; - } - $subject = $this->getSubject(); - if (TRUE === is_string($data)) { - $body = $data; - } - $message = new MailMessage(); - $message->setSubject($subject); - $message->setFrom($senderAddress, $senderName); - $message->setTo($recipientAddress, $recipientName); - $message->setBody($body); - return $message; - } - - /** - * @param MailMessage $message - * @return void - */ - protected function sendEmail(MailMessage $message) { - $message->send(); - } - +class EmailPipe extends AbstractPipe implements PipeInterface +{ + + /** + * @var string + */ + protected $subject; + + /** + * @var mixed + */ + protected $recipient; + + /** + * @var mixed + */ + protected $sender; + + /** + * @var string|NULL + */ + protected $body = null; + + /** + * @return FieldInterface[] + */ + public function getFormFields() + { + $fields = parent::getFormFields(); + $fields['subject'] = Input::create(['type' => 'Input']) + ->setName('subject'); + $fields['body'] = Text::create(['type' => 'Text']) + ->setName('body'); + $fields['receipent'] = Input::create(['type' => 'Input']) + ->setName('recipient'); + $fields['sender'] = Input::create(['type' => 'Input']) + ->setName('sender'); + return $fields; + } + + /** + * @param string $recipient + * @return EmailPipe + */ + public function setRecipient($recipient) + { + $this->recipient = $recipient; + return $this; + } + + /** + * @return string + */ + public function getRecipient() + { + return $this->recipient; + } + + /** + * @param string $sender + * @return EmailPipe + */ + public function setSender($sender) + { + $this->sender = $sender; + return $this; + } + + /** + * @return string + */ + public function getSender() + { + return $this->sender; + } + + /** + * @param string $subject + * @return EmailPipe + */ + public function setSubject($subject) + { + $this->subject = $subject; + return $this; + } + + /** + * @return string + */ + public function getSubject() + { + return $this->subject; + } + + /** + * @param string|NULL $body + * @return EmailPipe + */ + public function setBody($body) + { + $this->body = $body; + return $this; + } + + /** + * @return string|NULL + */ + public function getBody() + { + return $this->body; + } + + /** + * @param mixed $data + * @return mixed + * @throws Exception + */ + public function conduct($data) + { + try { + $message = $this->prepareEmail($data); + $this->sendEmail($message); + } catch (\Swift_RfcComplianceException $error) { + throw new Exception($error->getMessage(), $error->getCode()); + } + return $data; + } + + /** + * @param string $data + * @return MailMessage + */ + protected function prepareEmail($data) + { + $body = $this->getBody(); + $sender = $this->getSender(); + $recipient = $this->getRecipient(); + if (true === is_array($recipient)) { + list ($recipientAddress, $recipientName) = $recipient; + } else { + $recipientAddress = $recipient; + $recipientName = null; + } + if (true === is_array($sender)) { + list ($senderAddress, $senderName) = $sender; + } else { + $senderAddress = $sender; + $senderName = null; + } + $subject = $this->getSubject(); + if (true === is_string($data)) { + $body = $data; + } + $message = new MailMessage(); + $message->setSubject($subject); + $message->setFrom($senderAddress, $senderName); + $message->setTo($recipientAddress, $recipientName); + $message->setBody($body); + return $message; + } + + /** + * @param MailMessage $message + * @return void + */ + protected function sendEmail(MailMessage $message) + { + $message->send(); + } } diff --git a/Classes/Outlet/Pipe/Exception.php b/Classes/Outlet/Pipe/Exception.php index af829757c..50b05e525 100644 --- a/Classes/Outlet/Pipe/Exception.php +++ b/Classes/Outlet/Pipe/Exception.php @@ -13,6 +13,7 @@ * * Thrown by Outlet Pipes on errors. */ -class Exception extends \Exception { +class Exception extends \Exception +{ } diff --git a/Classes/Outlet/Pipe/FlashMessagePipe.php b/Classes/Outlet/Pipe/FlashMessagePipe.php index 1c2ca72c5..38a0f921e 100644 --- a/Classes/Outlet/Pipe/FlashMessagePipe.php +++ b/Classes/Outlet/Pipe/FlashMessagePipe.php @@ -20,125 +20,140 @@ * * Sends a custom FlashMessage */ -class FlashMessagePipe extends AbstractPipe implements PipeInterface { - - const FLASHMESSAGE_QUEUE = 'extbase.flashmessages.flux'; - - /** - * @var integer - */ - protected $severity = FlashMessage::OK; - - /** - * @var boolean - */ - protected $storeInSession = TRUE; - - /** - * @var string - */ - protected $title; - - /** - * @var string - */ - protected $message; - - /** - * @param array $data - * @return mixed - */ - public function conduct($data) { - $queue = new FlashMessageQueue(self::FLASHMESSAGE_QUEUE); - $flashMessage = new FlashMessage($this->getMessage(), $this->getTitle(), $this->getSeverity(), $this->getStoreInSession()); - $queue->enqueue($flashMessage); - return $data; - } - - /** - * @return FieldInterface[] - */ - public function getFormFields() { - $severities = array( - FlashMessage::OK => 'OK', - FlashMessage::ERROR => 'ERROR', - FlashMessage::NOTICE => 'NOTICE', - FlashMessage::WARNING => 'WARNING' - ); - $fields = parent::getFormFields(); - $fields['message'] = Text::create(array('type' => 'Text'))->setName('message'); - $fields['title'] = Input::create(array('type' => 'Input'))->setName('title'); - /** @var Select $severity */ - $severity = Select::create(array('type' => 'Select')); - $severity->setName('severity'); - $severity->setItems($severities); - $severity->setDefault(FlashMessage::OK); - $fields['severity'] = $severity; - return $fields; - } - - /** - * @param integer $severity - * @return FlashMessagePipe - */ - public function setSeverity($severity) { - $this->severity = $severity; - return $this; - } - - /** - * @return integer - */ - public function getSeverity() { - return $this->severity; - } - - /** - * @param boolean $storeInSession - * @return FlashMessagePipe - */ - public function setStoreInSession($storeInSession) { - $this->storeInSession = $storeInSession; - return $this; - } - - /** - * @return boolean - */ - public function getStoreInSession() { - return $this->storeInSession; - } - - /** - * @param string $title - * @return FlashMessagePipe - */ - public function setTitle($title) { - $this->title = $title; - return $this; - } - - /** - * @return string - */ - public function getTitle() { - return $this->title; - } - - /** - * @param string $message - * @return FlashMessagePipe - */ - public function setMessage($message) { - $this->message = $message; - return $this; - } - - /** - * @return string - */ - public function getMessage() { - return $this->message; - } - +class FlashMessagePipe extends AbstractPipe implements PipeInterface +{ + + const FLASHMESSAGE_QUEUE = 'extbase.flashmessages.flux'; + + /** + * @var integer + */ + protected $severity = FlashMessage::OK; + + /** + * @var boolean + */ + protected $storeInSession = true; + + /** + * @var string + */ + protected $title; + + /** + * @var string + */ + protected $message; + + /** + * @param array $data + * @return mixed + */ + public function conduct($data) + { + $queue = new FlashMessageQueue(self::FLASHMESSAGE_QUEUE); + $flashMessage = new FlashMessage( + $this->getMessage(), + $this->getTitle(), + $this->getSeverity(), + $this->getStoreInSession() + ); + $queue->enqueue($flashMessage); + return $data; + } + + /** + * @return FieldInterface[] + */ + public function getFormFields() + { + $severities = [ + FlashMessage::OK => 'OK', + FlashMessage::ERROR => 'ERROR', + FlashMessage::NOTICE => 'NOTICE', + FlashMessage::WARNING => 'WARNING' + ]; + $fields = parent::getFormFields(); + $fields['message'] = Text::create(['type' => 'Text'])->setName('message'); + $fields['title'] = Input::create(['type' => 'Input'])->setName('title'); + /** @var Select $severity */ + $severity = Select::create(['type' => 'Select']); + $severity->setName('severity'); + $severity->setItems($severities); + $severity->setDefault(FlashMessage::OK); + $fields['severity'] = $severity; + return $fields; + } + + /** + * @param integer $severity + * @return FlashMessagePipe + */ + public function setSeverity($severity) + { + $this->severity = $severity; + return $this; + } + + /** + * @return integer + */ + public function getSeverity() + { + return $this->severity; + } + + /** + * @param boolean $storeInSession + * @return FlashMessagePipe + */ + public function setStoreInSession($storeInSession) + { + $this->storeInSession = $storeInSession; + return $this; + } + + /** + * @return boolean + */ + public function getStoreInSession() + { + return $this->storeInSession; + } + + /** + * @param string $title + * @return FlashMessagePipe + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $message + * @return FlashMessagePipe + */ + public function setMessage($message) + { + $this->message = $message; + return $this; + } + + /** + * @return string + */ + public function getMessage() + { + return $this->message; + } } diff --git a/Classes/Outlet/Pipe/PipeInterface.php b/Classes/Outlet/Pipe/PipeInterface.php index f5fd0d0e9..56713aecc 100644 --- a/Classes/Outlet/Pipe/PipeInterface.php +++ b/Classes/Outlet/Pipe/PipeInterface.php @@ -16,37 +16,37 @@ * * Interface for Pipes which process data for Outlets. */ -interface PipeInterface { - - /** - * @param array $settings - * @return void - */ - public function loadSettings(array $settings); - - /** - * Accept $data and do whatever the Pipe should do before - * returning the same or a modified version of $data for - * chaining with other potential Pipes. - * - * @param mixed $data - * @return mixed - */ - public function conduct($data); - - /** - * Get a human-readable name of this Pipe. - * - * @return string - */ - public function getLabel(); - - /** - * Return the FormComponent "Field" instances which represent - * options this Pipe supports. - * - * @return FieldInterface[] - */ - public function getFormFields(); - +interface PipeInterface +{ + + /** + * @param array $settings + * @return void + */ + public function loadSettings(array $settings); + + /** + * Accept $data and do whatever the Pipe should do before + * returning the same or a modified version of $data for + * chaining with other potential Pipes. + * + * @param mixed $data + * @return mixed + */ + public function conduct($data); + + /** + * Get a human-readable name of this Pipe. + * + * @return string + */ + public function getLabel(); + + /** + * Return the FormComponent "Field" instances which represent + * options this Pipe supports. + * + * @return FieldInterface[] + */ + public function getFormFields(); } diff --git a/Classes/Outlet/Pipe/StandardPipe.php b/Classes/Outlet/Pipe/StandardPipe.php index 1bd4905c0..3fa511c1c 100644 --- a/Classes/Outlet/Pipe/StandardPipe.php +++ b/Classes/Outlet/Pipe/StandardPipe.php @@ -14,6 +14,7 @@ * Accepts POST array form data and uses a Flux Form * to perform pre-saving steps (validation, transformation etc). */ -class StandardPipe extends AbstractPipe implements PipeInterface { +class StandardPipe extends AbstractPipe implements PipeInterface +{ } diff --git a/Classes/Outlet/Pipe/TypeConverterPipe.php b/Classes/Outlet/Pipe/TypeConverterPipe.php index 1ae45f4a1..7d0307cc2 100644 --- a/Classes/Outlet/Pipe/TypeConverterPipe.php +++ b/Classes/Outlet/Pipe/TypeConverterPipe.php @@ -21,99 +21,122 @@ * Accepts POST array form data and uses a Flux Form * to perform pre-saving steps (validation, transformation etc). */ -class TypeConverterPipe extends AbstractPipe implements PipeInterface { +class TypeConverterPipe extends AbstractPipe implements PipeInterface +{ - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @var TypeConverterInterface - */ - protected $typeConverter; + /** + * @var TypeConverterInterface + */ + protected $typeConverter; - /** - * @var string - */ - protected $targetType; + /** + * @var string + */ + protected $targetType; - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * @return FieldInterface[] - */ - public function getFormFields() { - $fields = parent::getFormFields(); - $converters = array_values((array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters']); - $converters = array_combine($converters, $converters); - /** @var Select $typeConverter */ - $typeConverter = Select::create(array('type' => 'Select')); - $typeConverter->setName('typeConverter'); - $typeConverter->setItems($converters); - $fields['typeConverter'] = $typeConverter; - $fields['targetType'] = Input::create(array('type' => 'Input'))->setName('targetType'); - return $fields; - } + /** + * @return FieldInterface[] + */ + public function getFormFields() + { + $fields = parent::getFormFields(); + $converters = array_values((array) $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['typeConverters']); + $converters = array_combine($converters, $converters); + /** @var Select $typeConverter */ + $typeConverter = Select::create(['type' => 'Select']); + $typeConverter->setName('typeConverter'); + $typeConverter->setItems($converters); + $fields['typeConverter'] = $typeConverter; + $fields['targetType'] = Input::create(['type' => 'Input'])->setName('targetType'); + return $fields; + } - /** - * @param TypeConverterInterface|string $typeConverter - * @return TypeConverterPipe - */ - public function setTypeConverter($typeConverter) { - if (TRUE === is_string($typeConverter)) { - $typeConverter = $this->objectManager->get($typeConverter); - } - $this->typeConverter = $typeConverter; - return $this; - } + /** + * @param TypeConverterInterface|string $typeConverter + * @return TypeConverterPipe + */ + public function setTypeConverter($typeConverter) + { + if (true === is_string($typeConverter)) { + $typeConverter = $this->objectManager->get($typeConverter); + } + $this->typeConverter = $typeConverter; + return $this; + } - /** - * @return TypeConverterInterface - */ - public function getTypeConverter() { - return $this->typeConverter; - } + /** + * @return TypeConverterInterface + */ + public function getTypeConverter() + { + return $this->typeConverter; + } - /** - * @param string $targetType - * @return TypeConverterPipe - */ - public function setTargetType($targetType) { - $this->targetType = $targetType; - return $this; - } + /** + * @param string $targetType + * @return TypeConverterPipe + */ + public function setTargetType($targetType) + { + $this->targetType = $targetType; + return $this; + } - /** - * @return string - */ - public function getTargetType() { - return $this->targetType; - } - - /** - * @param mixed $data - * @return mixed - * @throws Exception - */ - public function conduct($data) { - $targetType = $this->getTargetType(); - $typeConverter = $this->getTypeConverter(); - if (FALSE === $typeConverter->canConvertFrom($data, $targetType)) { - throw new Exception('TypeConverter ' . get_class($typeConverter) . ' cannot convert ' . gettype($data) . ' to ' . $targetType, 1386292424); - } - $output = $this->typeConverter->convertFrom($data, $targetType); - if (TRUE === $output instanceof Error) { - throw new Exception('Conversion of ' . gettype($data) . ' to ' . $targetType . ' was unsuccessful, Error was: ' . $output->getMessage(), $output->getCode()); - } - return $output; - } + /** + * @return string + */ + public function getTargetType() + { + return $this->targetType; + } + /** + * @param mixed $data + * @return mixed + * @throws Exception + */ + public function conduct($data) + { + $targetType = $this->getTargetType(); + $typeConverter = $this->getTypeConverter(); + if (false === $typeConverter->canConvertFrom($data, $targetType)) { + throw new Exception( + sprintf( + 'TypeConverter %s cannot convert %s to %s', + get_class($typeConverter), + gettype($data), + $targetType + ), + 1386292424 + ); + } + $output = $this->typeConverter->convertFrom($data, $targetType); + if (true === $output instanceof Error) { + throw new Exception( + sprintf( + 'Conversion of %s to %s was unsuccessful, Error was: %s', + gettype($data), + $targetType, + $output->getMessage() + ), + $output->getCode() + ); + } + return $output; + } } diff --git a/Classes/Outlet/StandardOutlet.php b/Classes/Outlet/StandardOutlet.php index 9b1f85f7a..2cf059c1e 100644 --- a/Classes/Outlet/StandardOutlet.php +++ b/Classes/Outlet/StandardOutlet.php @@ -14,6 +14,7 @@ * Performs a 100% standard Outlet processing; Pipes leading * data in and other Pipes leading data out. */ -class StandardOutlet extends AbstractOutlet implements OutletInterface { +class StandardOutlet extends AbstractOutlet implements OutletInterface +{ } diff --git a/Classes/Package/FluxPackageFactory.php b/Classes/Package/FluxPackageFactory.php index 6431c5c4f..c4fff598f 100644 --- a/Classes/Package/FluxPackageFactory.php +++ b/Classes/Package/FluxPackageFactory.php @@ -20,85 +20,88 @@ * Creates instances of FluxPackage based on provided * extension name. Stores created instances in memory. */ -abstract class FluxPackageFactory { +abstract class FluxPackageFactory +{ - /** - * @var FluxPackageInterface[] - */ - protected static $packages = array(); + /** + * @var FluxPackageInterface[] + */ + protected static $packages = []; - /** - * @var array|NULL - */ - protected static $overrides = NULL; + /** + * @var array|NULL + */ + protected static $overrides = null; - /** - * Returns the FluxPackage instance associated with - * and possibly existing in $qualifiedExtensionName. - * - * @param string $qualifiedExtensionName - * @return FluxPackageInterface - */ - public static function getPackage($qualifiedExtensionName) { - if (empty($qualifiedExtensionName)) { - throw new PackageNotFoundException('Package name cannot be empty'); - } - $extensionKey = ExtensionNamingUtility::getExtensionKey($qualifiedExtensionName); - if (!ExtensionManagementUtility::isLoaded($extensionKey)) { - throw new PackageNotFoundException( - sprintf( - 'Package name %s (extension key %s) is not loaded', - $qualifiedExtensionName, - $extensionKey - ) - ); - } - if (!array_key_exists($extensionKey, static::$packages)) { - $manifestPath = ExtensionManagementUtility::extPath($extensionKey, 'flux.json'); - static::$packages[$extensionKey] = FluxPackage::create($manifestPath)->upcast(); - } - return static::$packages[$extensionKey]; - } + /** + * Returns the FluxPackage instance associated with + * and possibly existing in $qualifiedExtensionName. + * + * @param string $qualifiedExtensionName + * @return FluxPackageInterface + */ + public static function getPackage($qualifiedExtensionName) + { + if (empty($qualifiedExtensionName)) { + throw new PackageNotFoundException('Package name cannot be empty'); + } + $extensionKey = ExtensionNamingUtility::getExtensionKey($qualifiedExtensionName); + if (!ExtensionManagementUtility::isLoaded($extensionKey)) { + throw new PackageNotFoundException( + sprintf( + 'Package name %s (extension key %s) is not loaded', + $qualifiedExtensionName, + $extensionKey + ) + ); + } + if (!array_key_exists($extensionKey, static::$packages)) { + $manifestPath = ExtensionManagementUtility::extPath($extensionKey, 'flux.json'); + static::$packages[$extensionKey] = FluxPackage::create($manifestPath)->upcast(); + } + return static::$packages[$extensionKey]; + } - /** - * Returns the FluxPackage instance associated with - * and possibly existing in $qualifiedExtensionName, - * but falls back to returning the Flux root package - * if the requested package does not exist. - * - * @param string $qualifiedExtensionName - * @return FluxPackageInterface - */ - public static function getPackageWithFallback($qualifiedExtensionName) { - try { - return static::getPackage($qualifiedExtensionName); - } catch (PackageNotFoundException $error) { - return static::getPackage('FluidTYPO3.Flux'); - } - } - - /** - * @param string $qualifiedExtensionName - * @return array - */ - protected function getTypoScriptOverrides($qualifiedExtensionName) { - if (static::$overrides === NULL) { - $collected = array(); - $typoScript = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager') - ->get('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface') - ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); - foreach ((array) ObjectAccess::getPropertyPath($typoScript, 'plugin') as $prefix => $pluginSettings) { - if (!empty($pluginSettings['package'])) { - $collected[substr($prefix, 3)] = $pluginSettings['package']; - } - } - static::$overrides = $collected; - } - $packageSignature = ExtensionNamingUtility::getExtensionSignature($qualifiedExtensionName); - if (!empty(static::$overrides[$packageSignature])) { - return static::$overrides[$packageSignature]; - } - return array(); - } + /** + * Returns the FluxPackage instance associated with + * and possibly existing in $qualifiedExtensionName, + * but falls back to returning the Flux root package + * if the requested package does not exist. + * + * @param string $qualifiedExtensionName + * @return FluxPackageInterface + */ + public static function getPackageWithFallback($qualifiedExtensionName) + { + try { + return static::getPackage($qualifiedExtensionName); + } catch (PackageNotFoundException $error) { + return static::getPackage('FluidTYPO3.Flux'); + } + } + /** + * @param string $qualifiedExtensionName + * @return array + */ + protected function getTypoScriptOverrides($qualifiedExtensionName) + { + if (static::$overrides === null) { + $collected = []; + $typoScript = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager') + ->get('TYPO3\\CMS\\Extbase\\Object\\ObjectManagerInterface') + ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); + foreach ((array) ObjectAccess::getPropertyPath($typoScript, 'plugin') as $prefix => $pluginSettings) { + if (!empty($pluginSettings['package'])) { + $collected[substr($prefix, 3)] = $pluginSettings['package']; + } + } + static::$overrides = $collected; + } + $packageSignature = ExtensionNamingUtility::getExtensionSignature($qualifiedExtensionName); + if (!empty(static::$overrides[$packageSignature])) { + return static::$overrides[$packageSignature]; + } + return []; + } } diff --git a/Classes/Package/FluxPackageInterface.php b/Classes/Package/FluxPackageInterface.php index fb7043f6c..794804fdb 100644 --- a/Classes/Package/FluxPackageInterface.php +++ b/Classes/Package/FluxPackageInterface.php @@ -17,107 +17,107 @@ * methods for a package class (manifest API) that's unique * per extension. */ -interface FluxPackageInterface { +interface FluxPackageInterface +{ - /** - * 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. - * - * @param mixed $seedArrayOrExtensionKeyOrManifestPath - */ - public function __construct($seedArrayOrExtensionKeyOrManifestPath); + /** + * 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. + * + * @param mixed $seedArrayOrExtensionKeyOrManifestPath + */ + public function __construct($seedArrayOrExtensionKeyOrManifestPath); - /** - * Must always return the vendor name (as used in class - * namespaces) corresponding to this package. - * - * @return string - */ - public function getVendorName(); + /** + * Must always return the vendor name (as used in class + * namespaces) corresponding to this package. + * + * @return string + */ + public function getVendorName(); - /** - * Must always return the ExtensionName format of the - * extension key, excluding the vendor name. - * - * @return string - */ - public function getExtensionName(); + /** + * Must always return the ExtensionName format of the + * extension key, excluding the vendor name. + * + * @return string + */ + public function getExtensionName(); - /** - * Must always return the $vendor\$extensioName format - * of the vendor and extension name, using values from - * the two preceeding methods. - * - * @return string - */ - public function getNamespacePrefix(); + /** + * Must always return the $vendor\$extensioName format + * of the vendor and extension name, using values from + * the two preceeding methods. + * + * @return string + */ + public function getNamespacePrefix(); - /** - * Returns an instance of Flux's TemplatePaths class - * with template paths of this package preloaded. - * - * @return TemplatePaths - */ - public function getViewPaths(); + /** + * Returns an instance of Flux's TemplatePaths class + * with template paths of this package preloaded. + * + * @return TemplatePaths + */ + public function getViewPaths(); - /** - * Asserts whether or not this FluxPackage contains an - * integration designed for the controller name, e.g. - * "Content", "Page" etc. - * - * @param string $controllerName - * @return boolean - */ - public function isProviderFor($controllerName); + /** + * Asserts whether or not this FluxPackage contains an + * integration designed for the controller name, e.g. + * "Content", "Page" etc. + * + * @param string $controllerName + * @return boolean + */ + public function isProviderFor($controllerName); - /** - * Asserts whether or not the feature is enabled for - * this FluxPackage. - * - * @param string $featureName - * @return boolean - */ - public function isFeatureEnabled($featureName); + /** + * Asserts whether or not the feature is enabled for + * this FluxPackage. + * + * @param string $featureName + * @return boolean + */ + public function isFeatureEnabled($featureName); - /** - * Get FQN of the class that's designated as an - * implementation, meaning it is replaceable by Flux - * Packages via this method. - * - * @param string $implementationName - * @return string - */ - public function getImplementation($implementationName); + /** + * Get FQN of the class that's designated as an + * implementation, meaning it is replaceable by Flux + * Packages via this method. + * + * @param string $implementationName + * @return string + */ + public function getImplementation($implementationName); - /** - * Modify properties of this FluxPackage (in this class - * instance only) by passing an array using the same - * structure as the constructor and as in the manifest. - * - * Is used internally when applying compatibility values: - * the "overlay" type subset of version dependent values - * is detected based on current version and passed to - * this function which then assimilates the values. - * - * @param array $alternativeManifestDeclaration - * @return void - */ - public function modify(array $alternativeManifestDeclaration); - - /** - * Upcasts (promotes) the instance to another class name - * by creating a new instance of the provided class and - * passing $this->manifest as seed. If NULL is passed as - * desired class name the expected final class name is - * determined based on naming convention. - * - * @param string|NULL $desiredClassName - * @return FluxPackageInterface - */ - public function upcast($desiredClassName = NULL); + /** + * Modify properties of this FluxPackage (in this class + * instance only) by passing an array using the same + * structure as the constructor and as in the manifest. + * + * Is used internally when applying compatibility values: + * the "overlay" type subset of version dependent values + * is detected based on current version and passed to + * this function which then assimilates the values. + * + * @param array $alternativeManifestDeclaration + * @return void + */ + public function modify(array $alternativeManifestDeclaration); + /** + * Upcasts (promotes) the instance to another class name + * by creating a new instance of the provided class and + * passing $this->manifest as seed. If NULL is passed as + * desired class name the expected final class name is + * determined based on naming convention. + * + * @param string|NULL $desiredClassName + * @return FluxPackageInterface + */ + public function upcast($desiredClassName = null); } diff --git a/Classes/Package/PackageNotFoundException.php b/Classes/Package/PackageNotFoundException.php index a660cc424..b7414a8fd 100644 --- a/Classes/Package/PackageNotFoundException.php +++ b/Classes/Package/PackageNotFoundException.php @@ -11,6 +11,7 @@ /** * Class PackageNotFoundException */ -class PackageNotFoundException extends \RuntimeException { +class PackageNotFoundException extends \RuntimeException +{ } diff --git a/Classes/Provider/AbstractProvider.php b/Classes/Provider/AbstractProvider.php index a0df510eb..8f3a854eb 100644 --- a/Classes/Provider/AbstractProvider.php +++ b/Classes/Provider/AbstractProvider.php @@ -26,956 +26,1031 @@ /** * AbstractProvider */ -class AbstractProvider implements ProviderInterface { - - const FORM_CLASS_PATTERN = '%s\\Form\\%s\\%sForm'; - - const CONTENT_OBJECT_TYPE_LIST = 'list'; - - /** - * @var array - */ - private static $cache = array(); - - /** - * @var array - */ - private static $trackedMethodCalls = array(); - - /** - * @var string - */ - protected $name = NULL; - - /** - * Fill with the table column name which should trigger this Provider. - * - * @var string - */ - protected $fieldName = NULL; - - /** - * Fill with the name of the DB table which should trigger this Provider. - * - * @var string - */ - protected $tableName = NULL; - - /** - * Fill with the "list_type" value that should trigger this Provider. - * - * @var string - */ - protected $listType = NULL; - - /** - * Fill with the "CType" value that should trigger this Provider. - * - * @var string - */ - protected $contentObjectType = NULL; - - /** - * @var string - */ - protected $parentFieldName = NULL; - - /** - * @var array|NULL - */ - protected $row = NULL; - - /** - * @var array - */ - protected $dataStructArray; - - /** - * @var string|NULL - */ - protected $templatePathAndFilename = NULL; - - /** - * @var array - */ - protected $templateVariables = array(); - - /** - * @var array|NULL - */ - protected $templatePaths = NULL; - - /** - * @var string|NULL - */ - protected $configurationSectionName = 'Configuration'; - - /** - * @var string|NULL - */ - protected $extensionKey = NULL; - - /** - * @var integer - */ - protected $priority = 50; - - /** - * @var Form - */ - protected $form = NULL; - - /** - * @var Grid - */ - protected $grid = NULL; - - /** - * @var ViewContext - */ - protected $viewContext; - - /** - * @var FluxService - */ - protected $configurationService; - - /** - * @var WorkspacesAwareRecordService - */ - protected $recordService; - - /** - * @param FluxService $configurationService - * @return void - */ - public function injectConfigurationService(FluxService $configurationService) { - $this->configurationService = $configurationService; - } - - /** - * @param WorkspacesAwareRecordService $recordService - * @return void - */ - public function injectRecordService(WorkspacesAwareRecordService $recordService) { - $this->recordService = $recordService; - } - - /** - * @param array $settings - * @return void - */ - public function loadSettings(array $settings) { - if (TRUE === isset($settings['name'])) { - $this->setName($settings['name']); - } - if (TRUE === isset($settings['form'])) { - $form = Form::create($settings['form']); - if (TRUE === isset($settings['extensionKey'])) { - $extensionKey = $settings['extensionKey']; - $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); - $form->setExtensionName($extensionName); - } - $settings['form'] = $form; - } - if (TRUE === isset($settings['grid'])) { - $settings['grid'] = Grid::create($settings['grid']); - } - foreach ($settings as $name => $value) { - $this->$name = $value; - } - $fieldName = $this->getFieldName(array()); - if (TRUE === isset($settings['listType'])) { - $listType = $settings['listType']; - $GLOBALS['TCA'][$this->tableName]['types']['list']['subtypes_addlist'][$listType] = $fieldName; - } - $GLOBALS['TCA'][$this->tableName]['columns'][$fieldName]['config']['type'] = 'flex'; - } - - /** - * @param array $row - * @param string $table - * @param string $field - * @param string $extensionKey - * @return boolean - */ - public function trigger(array $row, $table, $field, $extensionKey = NULL) { - $providerFieldName = $this->getFieldName($row); - $providerTableName = $this->tableName; - $providerExtensionKey = $this->extensionKey; - $contentObjectType = $this->contentObjectType; - $listType = $this->listType; - $rowContainsPlugin = (FALSE === empty($row['CType']) && self::CONTENT_OBJECT_TYPE_LIST === $row['CType']); - $rowIsEmpty = (0 === count($row)); - $matchesContentType = ((TRUE === empty($contentObjectType) && TRUE === empty($row['CType'])) || (FALSE === empty($row['CType']) && $row['CType'] === $contentObjectType)); - $matchesPluginType = ((FALSE === empty($row['list_type']) && $row['list_type'] === $listType)); - $matchesTableName = ($providerTableName === $table || NULL === $table); - $matchesFieldName = ($providerFieldName === $field || NULL === $field); - $matchesExtensionKey = ($providerExtensionKey === $extensionKey || NULL === $extensionKey); - $isFullMatch = $matchesExtensionKey && $matchesTableName && $matchesFieldName && ($matchesContentType || ($rowContainsPlugin && $matchesPluginType)); - $isFallbackMatch = ($matchesTableName && $matchesFieldName && $rowIsEmpty); - return ($isFullMatch || $isFallbackMatch); - } - - /** - * If not-NULL is returned, the value is used as - * object class name when creating a Form implementation - * instance which can be returned as form instead of - * reading from template or overriding the getForm() method. - * - * @param array $row - * @return string - */ - protected function resolveFormClassName(array $row) { - $packageName = $this->getControllerPackageNameFromRecord($row); - $packageKey = str_replace('.', '\\', $packageName); - $controllerName = $this->getControllerNameFromRecord($row); - $action = $this->getControllerActionFromRecord($row); - $expectedClassName = sprintf(self::FORM_CLASS_PATTERN, $packageKey, $controllerName, ucfirst($action)); - return TRUE === class_exists($expectedClassName) ? $expectedClassName : NULL; - } - - /** - * @param array $row - * @return array - */ - protected function getViewVariables(array $row) { - $extensionKey = $this->getExtensionKey($row); - $fieldName = $this->getFieldName($row); - $variables = array( - 'record' => $row, - 'settings' => $this->configurationService->getSettingsForExtensionName($extensionKey) - ); - - // Special case: when saving a new record variable $row[$fieldName] is already an array - // and must not be processed by the configuration service. This has limited support from - // Flux (essentially: no Form instance which means no inheritance, transformation or - // form options can be dependended upon at this stage). - $lang = $this->getCurrentLanguageName(); - $value = $this->getCurrentValuePointerName(); - if (FALSE === is_array($row[$fieldName])) { - $recordVariables = $this->configurationService->convertFlexFormContentToArray($row[$fieldName], NULL, $lang, $value); - $variables = RecursiveArrayUtility::mergeRecursiveOverrule($variables, $recordVariables); - } - - $variables = RecursiveArrayUtility::mergeRecursiveOverrule($this->templateVariables, $variables); - - return $variables; - } - - /** - * @param array $row - * @return ViewContext - */ - public function getViewContext(array $row, RequestInterface $request = NULL) { - if (FALSE === $this->viewContext instanceof ViewContext) { - // Note: we do *not* store a local property because we do *not* want this function - // to re-use the ViewContext unless explicitly set from the outside or initialised - // by a sub-class. - $context = new ViewContext( - $this->getTemplatePathAndFilename($row), - $this->getControllerPackageNameFromRecord($row), - $this->getControllerNameFromRecord($row), - $request - ); - $context->setSectionName($this->getConfigurationSectionName($row)); - $context->setTemplatePaths(new TemplatePaths($this->getTemplatePaths($row))); - $context->setVariables($this->getViewVariables($row)); - return $context; - } - return $this->viewContext; - } - - /** - * @param ViewContext $viewContext - * @return void - */ - public function setViewContext(ViewContext $viewContext) { - $this->viewContext = $viewContext; - } - - /** - * @param array $row - * @return Form|NULL - */ - public function getForm(array $row) { - if (NULL !== $this->form) { - return $this->form; - } - $formName = 'form'; - $cacheKey = $this->getCacheKeyForStoredVariable($row, $formName); - if (FALSE === array_key_exists($cacheKey, self::$cache)) { - $formClassName = $this->resolveFormClassName($row); - if (NULL !== $formClassName) { - $form = call_user_func_array(array($formClassName, 'create'), array($row)); - } else { - $viewContext = $this->getViewContext($row); - if (NULL !== $viewContext->getTemplatePathAndFilename()) { - $view = $this->configurationService->getPreparedExposedTemplateView($viewContext); - $form = $view->getForm($viewContext->getSectionName(), $formName); - } - } - if (NULL !== $form) { - $form->setOption(Form::OPTION_RECORD, $row); - $form->setOption(Form::OPTION_RECORD_TABLE, $this->getTableName($row)); - $form->setOption(Form::OPTION_RECORD_FIELD, $this->getFieldName($row)); - } - self::$cache[$cacheKey] = $form; - } - return self::$cache[$cacheKey]; - } - - /** - * @param array $row - * @return Grid - */ - public function getGrid(array $row) { - if (NULL !== $this->grid) { - return $this->grid; - } - $gridName = 'grid'; - $cacheKey = $this->getCacheKeyForStoredVariable($row, $gridName); - if (FALSE === array_key_exists($cacheKey, self::$cache)) { - $viewContext = $this->getViewContext($row); - $grid = $this->configurationService->getGridFromTemplateFile($viewContext, $gridName); - self::$cache[$cacheKey] = $grid; - } - return self::$cache[$cacheKey]; - } - - /** - * @param string $listType - */ - public function setListType($listType) { - $this->listType = $listType; - } - - /** - * @return string - */ - public function getListType() { - return $this->listType; - } - - /** - * @param string $contentObjectType - */ - public function setContentObjectType($contentObjectType) { - $this->contentObjectType = $contentObjectType; - } - - /** - * @return string - */ - public function getContentObjectType() { - return $this->contentObjectType; - } - - /** - * @param array $row The record row which triggered processing - * @return string|NULL - */ - public function getFieldName(array $row) { - return $this->fieldName; - } - - /** - * @param array $row - * @return string - */ - public function getParentFieldName(array $row) { - unset($row); - return $this->parentFieldName; - } - - /** - * @param array $row The record row which triggered processing - * @return string|NULL - */ - public function getTableName(array $row) { - unset($row); - return $this->tableName; - } - - /** - * @param array $row - * @return string|NULL - */ - public function getTemplatePathAndFilename(array $row) { - unset($row); - if (0 === strpos($this->templatePathAndFilename, 'EXT:') || 0 !== strpos($this->templatePathAndFilename, '/')) { - $path = GeneralUtility::getFileAbsFileName($this->templatePathAndFilename); - if (TRUE === empty($path)) { - return NULL; - } - return $path; - } - return $this->templatePathAndFilename; - } - - /** - * Converts the contents of the provided row's Flux-enabled field, - * at the same time running through the inheritance tree generated - * by getInheritanceTree() in order to apply inherited values. - * - * @param array $row - * @return array - */ - public function getFlexFormValues(array $row) { - $fieldName = $this->getFieldName($row); - $form = $this->getForm($row); - $languageName = $this->getCurrentLanguageName(); - $valuePointer = $this->getCurrentValuePointerName(); - return $this->configurationService->convertFlexFormContentToArray($row[$fieldName], $form, $languageName, $valuePointer); - } - - /** - * Gets the current language name as string, in a format that is - * compatible with language pointers in a flexform. Usually this - * implies values like "en", "de" etc. - * - * Return NULL when language is site default language. - * - * @return string|NULL - */ - protected function getCurrentLanguageName() { - $language = $GLOBALS['TSFE']->lang; - if (TRUE === empty($language) || 'default' === $language) { - $language = NULL; - } - return $language; - } - - /** - * Gets the pointer name to use whne retrieving values from a - * flexform source. Return NULL when pointer is default. - * - * @return string|NULL - */ - protected function getCurrentValuePointerName() { - return $this->getCurrentLanguageName(); - } - - /** - * Returns the page record with localisation applied, if any - * exists in database. Maintains uid and pid of the original - * page if localisation is applied. - * - * @return array - */ - protected function getPageValues() { - $record = $GLOBALS['TSFE']->page; - if ($GLOBALS['TSFE']->sys_language_uid != 0) { - $localisation = $this->recordService->get( - 'pages_language_overlay', - '*', - 'pid = "' . $record['uid'] . - '" AND sys_language_uid = "' . $GLOBALS['TSFE']->sys_language_uid . '"' . - ' AND hidden = false' . - ' AND deleted = false' . - ' AND (starttime = 0 OR starttime <= UNIX_TIMESTAMP())' . - ' AND (endtime = 0 OR endtime > UNIX_TIMESTAMP())' - ); - } - if (FALSE === empty($localisation)) { - $mergedRecord = RecursiveArrayUtility::merge($record, reset($localisation)); - if (isset($record['uid']) && isset($record['pid'])) { - $mergedRecord['uid'] = $record['uid']; - $mergedRecord['pid'] = $record['pid']; - } - return $mergedRecord; - } - return $record; - } - - /** - * @param array $row - * @return array|NULL - */ - public function getTemplateVariables(array $row) { - $variables = (array) $this->templateVariables; - $variables['record'] = $row; - $variables['page'] = $this->getPageValues(); - $variables['user'] = $GLOBALS['TSFE']->fe_user->user; - if (TRUE === file_exists($this->getTemplatePathAndFilename($row))) { - $variables['grid'] = $this->getGrid($row); - $variables['form'] = $this->getForm($row); - } - return $variables; - } - - /** - * @param array $row - * @return array - */ - public function getTemplatePaths(array $row) { - $paths = $this->templatePaths; - if (FALSE === is_array($paths)) { - $extensionKey = $this->getExtensionKey($row); - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); - if (FALSE === empty($extensionKey)) { - $paths = $this->configurationService->getViewConfigurationForExtensionName($extensionKey); - } - } - if (TRUE === is_array($paths)) { - $paths = PathUtility::translatePath($paths); - } - return $paths; - } - - /** - * @param array $row - * @return string|NULL - */ - public function getConfigurationSectionName(array $row) { - unset($row); - return $this->configurationSectionName; - } - - /** - * @param array $row - * @return string|NULL - */ - public function getExtensionKey(array $row) { - unset($row); - return $this->extensionKey; - } - - /** - * @param array $row - * @return integer - */ - public function getPriority(array $row) { - unset($row); - return $this->priority; - } - - /** - * @return string - */ - public function getName() { - return $this->name; - } - - /** - * Pre-process record data for the table that this ConfigurationProvider - * is attached to. - * - * @param array $row The record data, by reference. Changing fields' values changes the record's values before display - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently displaying the record - * @return void - */ - public function preProcessRecord(array &$row, $id, DataHandler $reference) { - $fieldName = $this->getFieldName($row); - $tableName = $this->getTableName($row); - if (TRUE === is_array($row[$fieldName]) && TRUE === isset($row[$fieldName]['data']['options']['lDEF']) && TRUE === is_array($row[$fieldName]['data']['options']['lDEF'])) { - foreach ($row[$fieldName]['data']['options']['lDEF'] as $key => $value) { - if (0 === strpos($key, $tableName)) { - $realKey = array_pop(explode('.', $key)); - if (TRUE === isset($row[$realKey])) { - $row[$realKey] = $value['vDEF']; - } - } - } - } - } - - /** - * Post-process record data for the table that this ConfigurationProvider - * is attached to. - * - * @param string $operation TYPO3 operation identifier, i.e. "update", "new" etc. - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param array $row the record data, by reference. Changing fields' values changes the record's values just before saving - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently saving the record - * @param array $removals Allows overridden methods to pass an additional array of field names to remove from the stored Flux value - * @return void - */ - public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = array()) { - if ('update' === $operation) { - $record = $reference->datamap[$this->tableName][$id]; - $stored = $this->recordService->getSingle($this->tableName, '*', $record['uid']); - $fieldName = $this->getFieldName((array) $record); - $dontProcess = ( - NULL === $fieldName - || FALSE === isset($row[$fieldName]) - || FALSE === isset($record[$fieldName]['data']) - || FALSE === is_array($record[$fieldName]['data']) - ); - if (TRUE === $dontProcess) { - return; - } - $data = $record[$fieldName]['data']; - foreach ($data as $sheetName => $sheetFields) { - foreach ($sheetFields['lDEF'] as $sheetFieldName => $fieldDefinition) { - if ('_clear' === substr($sheetFieldName, -6)) { - array_push($removals, $sheetFieldName); - } else { - $clearFieldName = $sheetFieldName . '_clear'; - $clearFieldValue = (boolean) (TRUE === isset($data[$sheetName]['lDEF'][$clearFieldName]['vDEF']) ? $data[$sheetName]['lDEF'][$clearFieldName]['vDEF'] : 0); - $shouldClearField = (0 < $data[$sheetName]['lDEF'][$clearFieldName]['vDEF']); - if (TRUE === $shouldClearField || TRUE === $clearFieldValue) { - array_push($removals, $sheetFieldName); - } - } - } - } - $stored[$fieldName] = MiscellaneousUtility::cleanFlexFormXml($row[$fieldName], $removals); - $row[$fieldName] = $stored[$fieldName]; - $reference->datamap[$this->tableName][$id][$fieldName] = $row[$fieldName]; - $this->recordService->update($this->tableName, $stored); - } - } - - /** - * Post-process database operation for the table that this ConfigurationProvider - * is attached to. - * - * @param string $status TYPO3 operation identifier, i.e. "new" etc. - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param array $row The record's data, by reference. Changing fields' values changes the record's values just before saving after operation - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently performing the database operation - * @return void - */ - public function postProcessDatabaseOperation($status, $id, &$row, DataHandler $reference) { - // We dispatch the Outlet associated with the Form, triggering each defined - // Pipe inside the Outlet to "conduct" the data. - $record = $this->loadRecordFromDatabase($id); - if (NULL !== $record) { - $form = $this->getForm($record); - if (TRUE === $form instanceof Form\FormInterface) { - $form->getOutlet()->fill(array( - 'command' => $status, - 'uid' => $id, - 'record' => $row, - 'table' => $this->getTableName($record), - 'provider' => $this, - 'dataHandler' => $reference - )); - } - } - } - - /** - * Pre-process a command executed on a record form the table this ConfigurationProvider - * is attached to. - * - * @param string $command - * @param integer $id - * @param array $row - * @param integer $relativeTo - * @param DataHandler $reference - * @return void - */ - public function preProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) { - unset($command, $id, $row, $relativeTo, $reference); - } - - /** - * Post-process a command executed on a record form the table this ConfigurationProvider - * is attached to. - * - * @param string $command - * @param integer $id - * @param array $row - * @param integer $relativeTo - * @param DataHandler $reference - * @return void - */ - public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) { - unset($command, $id, $row, $relativeTo, $reference); - } - - /** - * Post-process the TCEforms DataStructure for a record associated - * with this ConfigurationProvider - * - * @param array $row - * @param mixed $dataStructure - * @param array $conf - * @return void - */ - public function postProcessDataStructure(array &$row, &$dataStructure, array $conf) { - $form = $this->getForm($row); - if (NULL !== $form) { - $dataStructure = $form->build(); - } - } - - /** - * Processes the table configuration (TCA) for the table associated - * with this Provider, as determined by the trigger() method. Gets - * passed an instance of the record being edited/created along with - * the current configuration array - and must return a complete copy - * of the configuration array manipulated to the Provider's needs. - * - * @param array $row The record being edited/created - * @return array The large FormEngine configuration array - see FormEngine documentation! - */ - public function processTableConfiguration(array $row, array $configuration) { - return $configuration; - } - - /** - * Perform various cleanup operations upon clearing cache - * - * @param array $command - * @return void - */ - public function clearCacheCommand($command = array()) { - } - - /** - * @return PreviewView - */ - protected function getPreviewView() { - $preview = 'FluidTYPO3\\Flux\\View\\PreviewView'; - return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager')->get($preview); - } - - /** - * Get preview chunks - header and content - as - * array(string $headerContent, string $previewContent, boolean $continueRendering) - * - * Default implementation renders the Preview section from the template - * file that the actual Provider returns for $row, using paths also - * determined by $row. Example: fluidcontent's Provider returns files - * and paths based on selected "Fluid Content type" and inherits and - * uses this method to render a Preview from the template file in the - * specific path. This default implementation expects the TYPO3 core - * to render the default header, so it returns NULL as $headerContent. - * - * @param array $row The record data to be analysed for variables to use in a rendered preview - * @return array - */ - public function getPreview(array $row) { - $previewContent = $this->getPreviewView()->getPreview($this, $row); - return array(NULL, $previewContent, empty($previewContent)); - } - - /** - * @param array $row - * @param string $variable - * @return string - */ - protected function getCacheKeyForStoredVariable(array $row, $variable) { - $table = $this->getTableName($row); - $field = $this->getFieldName($row); - $uid = (TRUE === isset($row['uid']) ? $row['uid'] : uniqid()); - return $table . $this->getListType() . $this->getContentObjectType() . md5(serialize($row[$field])) . $uid . $variable . get_class($this); - } - - /** - * Stub: override this to return a controller action name associated with $row. - * Default strategy: return base name of Provider class minus the "Provider" suffix. - * - * @param array $row - * @return string - */ - public function getControllerNameFromRecord(array $row) { - $class = get_class($this); - $separator = FALSE !== strpos($class, '\\') ? '\\' : '_'; - $base = array_pop(explode($separator, $class)); - return substr($base, 0, -8); - } - - /** - * Stub: Get the extension key of the controller associated with $row - * - * @param array $row - * @return string - */ - public function getControllerExtensionKeyFromRecord(array $row) { - return $this->extensionKey; - } - - /** - * Stub: Get the package name of the controller associated with $row - * - * @param array $row - * @return string - */ - public function getControllerPackageNameFromRecord(array $row) { - $extensionKey = $this->getControllerExtensionKeyFromRecord($row); - $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); - $vendor = ExtensionNamingUtility::getVendorName($extensionKey); - return NULL !== $vendor ? $vendor . '.' . $extensionName : $extensionName; - } - - /** - * Stub: Get the name of the controller action associated with $row - * - * @param array $row - * @return string - */ - public function getControllerActionFromRecord(array $row) { - return 'default'; - } - - /** - * Stub: Get a compacted controller name + action name string - * - * @param array $row - * @return string - */ - public function getControllerActionReferenceFromRecord(array $row) { - return $this->getControllerNameFromRecord($row) . '->' . $this->getControllerActionFromRecord($row); - } - - /** - * @param string $tableName - * @return void - */ - public function setTableName($tableName) { - $this->tableName = $tableName; - } - - /** - * @param string $fieldName - * @return void - */ - public function setFieldName($fieldName) { - $this->fieldName = $fieldName; - } - - /** - * @param string $extensionKey - * @return void - */ - public function setExtensionKey($extensionKey) { - $this->extensionKey = $extensionKey; - } - - /** - * @param array|NULL $templateVariables - * @return void - */ - public function setTemplateVariables($templateVariables) { - $this->templateVariables = $templateVariables; - } - - /** - * @param string $templatePathAndFilename - * @return void - */ - public function setTemplatePathAndFilename($templatePathAndFilename) { - $this->templatePathAndFilename = $templatePathAndFilename; - } - - /** - * @param array|NULL $templatePaths - * @return void - */ - public function setTemplatePaths($templatePaths) { - $this->templatePaths = $templatePaths; - } - - /** - * @param string|NULL $configurationSectionName - * @return void - */ - public function setConfigurationSectionName($configurationSectionName) { - $this->configurationSectionName = $configurationSectionName; - } - - /** - * @param string $name - */ - public function setName($name) { - $this->name = $name; - } - - /** - * @param Form $form - */ - public function setForm(Form $form) { - $this->form = $form; - } - - /** - * @param Grid $grid - */ - public function setGrid(Grid $grid) { - $this->grid = $grid; - } - - /** - * @param integer $uid - * @return array|NULL - */ - protected function loadRecordFromDatabase($uid) { - $uid = intval($uid); - $tableName = $this->tableName; - return $this->recordService->getSingle($tableName, '*', $uid); - } - - /** - * Use by TceMain to track method calls to providers for a certain $id. - * Every provider should only be called once per method / $id / command. - * When TceMain has called the provider it will call this method afterwards. - * - * @param string $methodName - * @param mixed $id - * @param string command - * @return void - */ - public function trackMethodCall($methodName, $id, $command = '') { - self::trackMethodCallWithClassName(get_called_class(), $methodName, $id, $command); - } - - /** - * Use by TceMain to track method calls to providers for a certain $id. - * Every provider should only be called once per method / $id. - * Before calling a provider, TceMain will call this method. - * If the provider hasn't been called for that method / $id before, it is. - * - * - * @param string $methodName - * @param mixed $id - * @param string $command - * @return boolean - */ - public function shouldCall($methodName, $id, $command = '') { - return self::shouldCallWithClassName(get_class($this), $methodName, $id, $command); - } - - /** - * Internal method. See trackMethodCall. - * This is used by flux own provider to make sure on inheritance they are still only executed once. - * - * @param string $className - * @param string $methodName - * @param mixed $id - * @param string $command - * @return void - */ - protected function trackMethodCallWithClassName($className, $methodName, $id, $command = '') { - $cacheKey = $className . $methodName . $id . $command; - self::$trackedMethodCalls[$cacheKey] = TRUE; - } - - /** - * Internal method. See shouldCall. - * This is used by flux own provider to make sure on inheritance they are still only executed once. - * - * @param string $className - * @param string $methodName - * @param mixed $id - * @param string $command - * @return boolean - */ - protected function shouldCallWithClassName($className, $methodName, $id, $command = '') { - $cacheKey = $className . $methodName . $id . $command; - return empty(self::$trackedMethodCalls[$cacheKey]); - } - - /** - * @return void - */ - public function reset() { - self::$cache = array(); - self::$trackedMethodCalls = array(); - } - +class AbstractProvider implements ProviderInterface +{ + + const FORM_CLASS_PATTERN = '%s\\Form\\%s\\%sForm'; + + const CONTENT_OBJECT_TYPE_LIST = 'list'; + + /** + * @var array + */ + private static $cache = []; + + /** + * @var array + */ + private static $trackedMethodCalls = []; + + /** + * @var string + */ + protected $name = null; + + /** + * Fill with the table column name which should trigger this Provider. + * + * @var string + */ + protected $fieldName = null; + + /** + * Fill with the name of the DB table which should trigger this Provider. + * + * @var string + */ + protected $tableName = null; + + /** + * Fill with the "list_type" value that should trigger this Provider. + * + * @var string + */ + protected $listType = null; + + /** + * Fill with the "CType" value that should trigger this Provider. + * + * @var string + */ + protected $contentObjectType = null; + + /** + * @var string + */ + protected $parentFieldName = null; + + /** + * @var array|NULL + */ + protected $row = null; + + /** + * @var array + */ + protected $dataStructArray; + + /** + * @var string|NULL + */ + protected $templatePathAndFilename = null; + + /** + * @var array + */ + protected $templateVariables = []; + + /** + * @var array|NULL + */ + protected $templatePaths = null; + + /** + * @var string|NULL + */ + protected $configurationSectionName = 'Configuration'; + + /** + * @var string|NULL + */ + protected $extensionKey = null; + + /** + * @var integer + */ + protected $priority = 50; + + /** + * @var Form + */ + protected $form = null; + + /** + * @var Grid + */ + protected $grid = null; + + /** + * @var ViewContext + */ + protected $viewContext; + + /** + * @var FluxService + */ + protected $configurationService; + + /** + * @var WorkspacesAwareRecordService + */ + protected $recordService; + + /** + * @param FluxService $configurationService + * @return void + */ + public function injectConfigurationService(FluxService $configurationService) + { + $this->configurationService = $configurationService; + } + + /** + * @param WorkspacesAwareRecordService $recordService + * @return void + */ + public function injectRecordService(WorkspacesAwareRecordService $recordService) + { + $this->recordService = $recordService; + } + + /** + * @param array $settings + * @return void + */ + public function loadSettings(array $settings) + { + if (true === isset($settings['name'])) { + $this->setName($settings['name']); + } + if (true === isset($settings['form'])) { + $form = Form::create($settings['form']); + if (true === isset($settings['extensionKey'])) { + $extensionKey = $settings['extensionKey']; + $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); + $form->setExtensionName($extensionName); + } + $settings['form'] = $form; + } + if (true === isset($settings['grid'])) { + $settings['grid'] = Grid::create($settings['grid']); + } + foreach ($settings as $name => $value) { + $this->$name = $value; + } + $fieldName = $this->getFieldName([]); + if (true === isset($settings['listType'])) { + $listType = $settings['listType']; + $GLOBALS['TCA'][$this->tableName]['types']['list']['subtypes_addlist'][$listType] = $fieldName; + } + $GLOBALS['TCA'][$this->tableName]['columns'][$fieldName]['config']['type'] = 'flex'; + } + + /** + * @param array $row + * @param string $table + * @param string $field + * @param string $extensionKey + * @return boolean + */ + public function trigger(array $row, $table, $field, $extensionKey = null) + { + $providerFieldName = $this->getFieldName($row); + $providerTableName = $this->tableName; + $providerExtensionKey = $this->extensionKey; + $contentObjectType = $this->contentObjectType; + $listType = $this->listType; + $rowContainsPlugin = (!empty($row['CType']) && self::CONTENT_OBJECT_TYPE_LIST === $row['CType']); + $rowIsEmpty = (0 === count($row)); + $matchesContentType = ((empty($contentObjectType) && empty($row['CType'])) + || (!empty($row['CType']) && $row['CType'] === $contentObjectType)); + $matchesPluginType = ((!empty($row['list_type']) && $row['list_type'] === $listType)); + $matchesTableName = ($providerTableName === $table || !$table); + $matchesFieldName = ($providerFieldName === $field || !$field); + $matchesExtensionKey = ($providerExtensionKey === $extensionKey || !$extensionKey); + $isFullMatch = $matchesExtensionKey && $matchesTableName && $matchesFieldName + && ($matchesContentType || ($rowContainsPlugin && $matchesPluginType)); + $isFallbackMatch = ($matchesTableName && $matchesFieldName && $rowIsEmpty); + return ($isFullMatch || $isFallbackMatch); + } + + /** + * If not-NULL is returned, the value is used as + * object class name when creating a Form implementation + * instance which can be returned as form instead of + * reading from template or overriding the getForm() method. + * + * @param array $row + * @return string + */ + protected function resolveFormClassName(array $row) + { + $packageName = $this->getControllerPackageNameFromRecord($row); + $packageKey = str_replace('.', '\\', $packageName); + $controllerName = $this->getControllerNameFromRecord($row); + $action = $this->getControllerActionFromRecord($row); + $expectedClassName = sprintf(self::FORM_CLASS_PATTERN, $packageKey, $controllerName, ucfirst($action)); + return true === class_exists($expectedClassName) ? $expectedClassName : null; + } + + /** + * @param array $row + * @return array + */ + protected function getViewVariables(array $row) + { + $extensionKey = $this->getExtensionKey($row); + $fieldName = $this->getFieldName($row); + $variables = [ + 'record' => $row, + 'settings' => $this->configurationService->getSettingsForExtensionName($extensionKey) + ]; + + // Special case: when saving a new record variable $row[$fieldName] is already an array + // and must not be processed by the configuration service. This has limited support from + // Flux (essentially: no Form instance which means no inheritance, transformation or + // form options can be dependended upon at this stage). + $lang = $this->getCurrentLanguageName(); + $value = $this->getCurrentValuePointerName(); + if (false === is_array($row[$fieldName])) { + $recordVariables = $this->configurationService->convertFlexFormContentToArray( + $row[$fieldName], + null, + $lang, + $value + ); + $variables = RecursiveArrayUtility::mergeRecursiveOverrule($variables, $recordVariables); + } + + $variables = RecursiveArrayUtility::mergeRecursiveOverrule($this->templateVariables, $variables); + + return $variables; + } + + /** + * @param array $row + * @return ViewContext + */ + public function getViewContext(array $row, RequestInterface $request = null) + { + if (false === $this->viewContext instanceof ViewContext) { + // Note: we do *not* store a local property because we do *not* want this function + // to re-use the ViewContext unless explicitly set from the outside or initialised + // by a sub-class. + $context = new ViewContext( + $this->getTemplatePathAndFilename($row), + $this->getControllerPackageNameFromRecord($row), + $this->getControllerNameFromRecord($row), + $request + ); + $context->setSectionName($this->getConfigurationSectionName($row)); + $context->setTemplatePaths(new TemplatePaths($this->getTemplatePaths($row))); + $context->setVariables($this->getViewVariables($row)); + return $context; + } + return $this->viewContext; + } + + /** + * @param ViewContext $viewContext + * @return void + */ + public function setViewContext(ViewContext $viewContext) + { + $this->viewContext = $viewContext; + } + + /** + * @param array $row + * @return Form|NULL + */ + public function getForm(array $row) + { + if (null !== $this->form) { + return $this->form; + } + $formName = 'form'; + $cacheKey = $this->getCacheKeyForStoredVariable($row, $formName); + if (false === array_key_exists($cacheKey, self::$cache)) { + $formClassName = $this->resolveFormClassName($row); + if (null !== $formClassName) { + $form = call_user_func_array([$formClassName, 'create'], [$row]); + } else { + $viewContext = $this->getViewContext($row); + if (null !== $viewContext->getTemplatePathAndFilename()) { + $view = $this->configurationService->getPreparedExposedTemplateView($viewContext); + $form = $view->getForm($viewContext->getSectionName(), $formName); + } + } + if (null !== $form) { + $form->setOption(Form::OPTION_RECORD, $row); + $form->setOption(Form::OPTION_RECORD_TABLE, $this->getTableName($row)); + $form->setOption(Form::OPTION_RECORD_FIELD, $this->getFieldName($row)); + } + self::$cache[$cacheKey] = $form; + } + return self::$cache[$cacheKey]; + } + + /** + * @param array $row + * @return Grid + */ + public function getGrid(array $row) + { + if (null !== $this->grid) { + return $this->grid; + } + $gridName = 'grid'; + $cacheKey = $this->getCacheKeyForStoredVariable($row, $gridName); + if (false === array_key_exists($cacheKey, self::$cache)) { + $viewContext = $this->getViewContext($row); + $grid = $this->configurationService->getGridFromTemplateFile($viewContext, $gridName); + self::$cache[$cacheKey] = $grid; + } + return self::$cache[$cacheKey]; + } + + /** + * @param string $listType + */ + public function setListType($listType) + { + $this->listType = $listType; + } + + /** + * @return string + */ + public function getListType() + { + return $this->listType; + } + + /** + * @param string $contentObjectType + */ + public function setContentObjectType($contentObjectType) + { + $this->contentObjectType = $contentObjectType; + } + + /** + * @return string + */ + public function getContentObjectType() + { + return $this->contentObjectType; + } + + /** + * @param array $row The record row which triggered processing + * @return string|NULL + */ + public function getFieldName(array $row) + { + return $this->fieldName; + } + + /** + * @param array $row + * @return string + */ + public function getParentFieldName(array $row) + { + unset($row); + return $this->parentFieldName; + } + + /** + * @param array $row The record row which triggered processing + * @return string|NULL + */ + public function getTableName(array $row) + { + unset($row); + return $this->tableName; + } + + /** + * @param array $row + * @return string|NULL + */ + public function getTemplatePathAndFilename(array $row) + { + unset($row); + if (0 === strpos($this->templatePathAndFilename, 'EXT:') || 0 !== strpos($this->templatePathAndFilename, '/')) { + $path = GeneralUtility::getFileAbsFileName($this->templatePathAndFilename); + if (true === empty($path)) { + return null; + } + return $path; + } + return $this->templatePathAndFilename; + } + + /** + * Converts the contents of the provided row's Flux-enabled field, + * at the same time running through the inheritance tree generated + * by getInheritanceTree() in order to apply inherited values. + * + * @param array $row + * @return array + */ + public function getFlexFormValues(array $row) + { + $fieldName = $this->getFieldName($row); + $form = $this->getForm($row); + $languageName = $this->getCurrentLanguageName(); + $valuePointer = $this->getCurrentValuePointerName(); + return $this->configurationService->convertFlexFormContentToArray( + $row[$fieldName], + $form, + $languageName, + $valuePointer + ); + } + + /** + * Gets the current language name as string, in a format that is + * compatible with language pointers in a flexform. Usually this + * implies values like "en", "de" etc. + * + * Return NULL when language is site default language. + * + * @return string|NULL + */ + protected function getCurrentLanguageName() + { + $language = $GLOBALS['TSFE']->lang; + if (true === empty($language) || 'default' === $language) { + $language = null; + } + return $language; + } + + /** + * Gets the pointer name to use whne retrieving values from a + * flexform source. Return NULL when pointer is default. + * + * @return string|NULL + */ + protected function getCurrentValuePointerName() + { + return $this->getCurrentLanguageName(); + } + + /** + * Returns the page record with localisation applied, if any + * exists in database. Maintains uid and pid of the original + * page if localisation is applied. + * + * @return array + */ + protected function getPageValues() + { + $record = $GLOBALS['TSFE']->page; + if ($GLOBALS['TSFE']->sys_language_uid != 0) { + $localisation = $this->recordService->get( + 'pages_language_overlay', + '*', + 'pid = "' . $record['uid'] . + '" AND sys_language_uid = "' . $GLOBALS['TSFE']->sys_language_uid . '"' . + ' AND hidden = false' . + ' AND deleted = false' . + ' AND (starttime = 0 OR starttime <= UNIX_TIMESTAMP())' . + ' AND (endtime = 0 OR endtime > UNIX_TIMESTAMP())' + ); + } + if (false === empty($localisation)) { + $mergedRecord = RecursiveArrayUtility::merge($record, reset($localisation)); + if (isset($record['uid']) && isset($record['pid'])) { + $mergedRecord['uid'] = $record['uid']; + $mergedRecord['pid'] = $record['pid']; + } + return $mergedRecord; + } + return $record; + } + + /** + * @param array $row + * @return array|NULL + */ + public function getTemplateVariables(array $row) + { + $variables = (array) $this->templateVariables; + $variables['record'] = $row; + $variables['page'] = $this->getPageValues(); + $variables['user'] = $GLOBALS['TSFE']->fe_user->user; + if (true === file_exists($this->getTemplatePathAndFilename($row))) { + $variables['grid'] = $this->getGrid($row); + $variables['form'] = $this->getForm($row); + } + return $variables; + } + + /** + * @param array $row + * @return array + */ + public function getTemplatePaths(array $row) + { + $paths = $this->templatePaths; + if (false === is_array($paths)) { + $extensionKey = $this->getExtensionKey($row); + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); + if (false === empty($extensionKey)) { + $paths = $this->configurationService->getViewConfigurationForExtensionName($extensionKey); + } + } + if (true === is_array($paths)) { + $paths = PathUtility::translatePath($paths); + } + return $paths; + } + + /** + * @param array $row + * @return string|NULL + */ + public function getConfigurationSectionName(array $row) + { + unset($row); + return $this->configurationSectionName; + } + + /** + * @param array $row + * @return string|NULL + */ + public function getExtensionKey(array $row) + { + unset($row); + return $this->extensionKey; + } + + /** + * @param array $row + * @return integer + */ + public function getPriority(array $row) + { + unset($row); + return $this->priority; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Pre-process record data for the table that this ConfigurationProvider + * is attached to. + * + * @param array $row The record by reference. Changing fields' values changes the record's values before display + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param DataHandler $reference A reference to the DataHandler object that is currently displaying the record + * @return void + */ + public function preProcessRecord(array &$row, $id, DataHandler $reference) + { + $fieldName = $this->getFieldName($row); + $tableName = $this->getTableName($row); + if (is_array($row[$fieldName]) && isset($row[$fieldName]['data']['options']['lDEF']) + && is_array($row[$fieldName]['data']['options']['lDEF'])) { + foreach ($row[$fieldName]['data']['options']['lDEF'] as $key => $value) { + if (0 === strpos($key, $tableName)) { + $realKey = array_pop(explode('.', $key)); + if (isset($row[$realKey])) { + $row[$realKey] = $value['vDEF']; + } + } + } + } + } + + /** + * Post-process record data for the table that this ConfigurationProvider + * is attached to. + * + * @param string $operation TYPO3 operation identifier, i.e. "update", "new" etc. + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param array $row the record by reference. Changing fields' values changes the record's values just before saving + * @param DataHandler $reference A reference to the DataHandler object that is currently saving the record + * @param array $removals Allows overridden methods to pass an array of fields to remove from the stored Flux value + * @return void + */ + public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = []) + { + if ('update' === $operation) { + $record = $reference->datamap[$this->tableName][$id]; + $stored = $this->recordService->getSingle($this->tableName, '*', $record['uid']); + $fieldName = $this->getFieldName((array) $record); + $dontProcess = ( + null === $fieldName + || false === isset($row[$fieldName]) + || false === isset($record[$fieldName]['data']) + || false === is_array($record[$fieldName]['data']) + ); + if (true === $dontProcess) { + return; + } + $data = $record[$fieldName]['data']; + foreach ($data as $sheetName => $sheetFields) { + foreach ($sheetFields['lDEF'] as $sheetFieldName => $fieldDefinition) { + if ('_clear' === substr($sheetFieldName, -6)) { + array_push($removals, $sheetFieldName); + } else { + $clearFieldName = $sheetFieldName . '_clear'; + if (isset($data[$sheetName]['lDEF'][$clearFieldName]['vDEF'])) { + if ((boolean) $data[$sheetName]['lDEF'][$clearFieldName]['vDEF']) { + array_push($removals, $sheetFieldName); + } + } + } + } + } + $stored[$fieldName] = MiscellaneousUtility::cleanFlexFormXml($row[$fieldName], $removals); + $row[$fieldName] = $stored[$fieldName]; + $reference->datamap[$this->tableName][$id][$fieldName] = $row[$fieldName]; + $this->recordService->update($this->tableName, $stored); + } + } + + /** + * Post-process database operation for the table that this ConfigurationProvider + * is attached to. + * + * @param string $status TYPO3 operation identifier, i.e. "new" etc. + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param array $row The record by reference. Changing fields' values changes the record's values just + * before saving after operation + * @param DataHandler $reference A reference to the DataHandler object that is currently performing the operation + * @return void + */ + public function postProcessDatabaseOperation($status, $id, &$row, DataHandler $reference) + { + // We dispatch the Outlet associated with the Form, triggering each defined + // Pipe inside the Outlet to "conduct" the data. + $record = $this->loadRecordFromDatabase($id); + if (null !== $record) { + $form = $this->getForm($record); + if (true === $form instanceof Form\FormInterface) { + $form->getOutlet()->fill([ + 'command' => $status, + 'uid' => $id, + 'record' => $row, + 'table' => $this->getTableName($record), + 'provider' => $this, + 'dataHandler' => $reference + ]); + } + } + } + + /** + * Pre-process a command executed on a record form the table this ConfigurationProvider + * is attached to. + * + * @param string $command + * @param integer $id + * @param array $row + * @param integer $relativeTo + * @param DataHandler $reference + * @return void + */ + public function preProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) + { + unset($command, $id, $row, $relativeTo, $reference); + } + + /** + * Post-process a command executed on a record form the table this ConfigurationProvider + * is attached to. + * + * @param string $command + * @param integer $id + * @param array $row + * @param integer $relativeTo + * @param DataHandler $reference + * @return void + */ + public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) + { + unset($command, $id, $row, $relativeTo, $reference); + } + + /** + * Post-process the TCEforms DataStructure for a record associated + * with this ConfigurationProvider + * + * @param array $row + * @param mixed $dataStructure + * @param array $conf + * @return void + */ + public function postProcessDataStructure(array &$row, &$dataStructure, array $conf) + { + $form = $this->getForm($row); + if (null !== $form) { + $dataStructure = $form->build(); + } + } + + /** + * Processes the table configuration (TCA) for the table associated + * with this Provider, as determined by the trigger() method. Gets + * passed an instance of the record being edited/created along with + * the current configuration array - and must return a complete copy + * of the configuration array manipulated to the Provider's needs. + * + * @param array $row The record being edited/created + * @return array The large FormEngine configuration array - see FormEngine documentation! + */ + public function processTableConfiguration(array $row, array $configuration) + { + return $configuration; + } + + /** + * Perform various cleanup operations upon clearing cache + * + * @param array $command + * @return void + */ + public function clearCacheCommand($command = []) + { + } + + /** + * @return PreviewView + */ + protected function getPreviewView() + { + $preview = 'FluidTYPO3\\Flux\\View\\PreviewView'; + return GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager')->get($preview); + } + + /** + * Get preview chunks - header and content - as + * [string $headerContent, string $previewContent, boolean $continueRendering) + * + * Default implementation renders the Preview section from the template + * file that the actual Provider returns for $row, using paths also + * determined by $row. Example: fluidcontent's Provider returns files + * and paths based on selected "Fluid Content type" and inherits and + * uses this method to render a Preview from the template file in the + * specific path. This default implementation expects the TYPO3 core + * to render the default header, so it returns NULL as $headerContent. + * + * @param array $row The record data to be analysed for variables to use in a rendered preview + * @return array + */ + public function getPreview(array $row) + { + $previewContent = $this->getPreviewView()->getPreview($this, $row); + return [null, $previewContent, empty($previewContent)]; + } + + /** + * @param array $row + * @param string $variable + * @return string + */ + protected function getCacheKeyForStoredVariable(array $row, $variable) + { + $table = $this->getTableName($row); + $field = $this->getFieldName($row); + $uid = (true === isset($row['uid']) ? $row['uid'] : uniqid()); + return $table . $this->getListType() . $this->getContentObjectType() . + md5(serialize($row[$field])) . $uid . $variable . get_class($this); + } + + /** + * Stub: override this to return a controller action name associated with $row. + * Default strategy: return base name of Provider class minus the "Provider" suffix. + * + * @param array $row + * @return string + */ + public function getControllerNameFromRecord(array $row) + { + $class = get_class($this); + $separator = false !== strpos($class, '\\') ? '\\' : '_'; + $base = array_pop(explode($separator, $class)); + return substr($base, 0, -8); + } + + /** + * Stub: Get the extension key of the controller associated with $row + * + * @param array $row + * @return string + */ + public function getControllerExtensionKeyFromRecord(array $row) + { + return $this->extensionKey; + } + + /** + * Stub: Get the package name of the controller associated with $row + * + * @param array $row + * @return string + */ + public function getControllerPackageNameFromRecord(array $row) + { + $extensionKey = $this->getControllerExtensionKeyFromRecord($row); + $extensionName = ExtensionNamingUtility::getExtensionName($extensionKey); + $vendor = ExtensionNamingUtility::getVendorName($extensionKey); + return null !== $vendor ? $vendor . '.' . $extensionName : $extensionName; + } + + /** + * Stub: Get the name of the controller action associated with $row + * + * @param array $row + * @return string + */ + public function getControllerActionFromRecord(array $row) + { + return 'default'; + } + + /** + * Stub: Get a compacted controller name + action name string + * + * @param array $row + * @return string + */ + public function getControllerActionReferenceFromRecord(array $row) + { + return $this->getControllerNameFromRecord($row) . '->' . $this->getControllerActionFromRecord($row); + } + + /** + * @param string $tableName + * @return void + */ + public function setTableName($tableName) + { + $this->tableName = $tableName; + } + + /** + * @param string $fieldName + * @return void + */ + public function setFieldName($fieldName) + { + $this->fieldName = $fieldName; + } + + /** + * @param string $extensionKey + * @return void + */ + public function setExtensionKey($extensionKey) + { + $this->extensionKey = $extensionKey; + } + + /** + * @param array|NULL $templateVariables + * @return void + */ + public function setTemplateVariables($templateVariables) + { + $this->templateVariables = $templateVariables; + } + + /** + * @param string $templatePathAndFilename + * @return void + */ + public function setTemplatePathAndFilename($templatePathAndFilename) + { + $this->templatePathAndFilename = $templatePathAndFilename; + } + + /** + * @param array|NULL $templatePaths + * @return void + */ + public function setTemplatePaths($templatePaths) + { + $this->templatePaths = $templatePaths; + } + + /** + * @param string|NULL $configurationSectionName + * @return void + */ + public function setConfigurationSectionName($configurationSectionName) + { + $this->configurationSectionName = $configurationSectionName; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @param Form $form + */ + public function setForm(Form $form) + { + $this->form = $form; + } + + /** + * @param Grid $grid + */ + public function setGrid(Grid $grid) + { + $this->grid = $grid; + } + + /** + * @param integer $uid + * @return array|NULL + */ + protected function loadRecordFromDatabase($uid) + { + $uid = intval($uid); + $tableName = $this->tableName; + return $this->recordService->getSingle($tableName, '*', $uid); + } + + /** + * Use by TceMain to track method calls to providers for a certain $id. + * Every provider should only be called once per method / $id / command. + * When TceMain has called the provider it will call this method afterwards. + * + * @param string $methodName + * @param mixed $id + * @param string command + * @return void + */ + public function trackMethodCall($methodName, $id, $command = '') + { + self::trackMethodCallWithClassName(get_called_class(), $methodName, $id, $command); + } + + /** + * Use by TceMain to track method calls to providers for a certain $id. + * Every provider should only be called once per method / $id. + * Before calling a provider, TceMain will call this method. + * If the provider hasn't been called for that method / $id before, it is. + * + * + * @param string $methodName + * @param mixed $id + * @param string $command + * @return boolean + */ + public function shouldCall($methodName, $id, $command = '') + { + return self::shouldCallWithClassName(get_class($this), $methodName, $id, $command); + } + + /** + * Internal method. See trackMethodCall. + * This is used by flux own provider to make sure on inheritance they are still only executed once. + * + * @param string $className + * @param string $methodName + * @param mixed $id + * @param string $command + * @return void + */ + protected function trackMethodCallWithClassName($className, $methodName, $id, $command = '') + { + $cacheKey = $className . $methodName . $id . $command; + self::$trackedMethodCalls[$cacheKey] = true; + } + + /** + * Internal method. See shouldCall. + * This is used by flux own provider to make sure on inheritance they are still only executed once. + * + * @param string $className + * @param string $methodName + * @param mixed $id + * @param string $command + * @return boolean + */ + protected function shouldCallWithClassName($className, $methodName, $id, $command = '') + { + $cacheKey = $className . $methodName . $id . $command; + return empty(self::$trackedMethodCalls[$cacheKey]); + } + + /** + * @return void + */ + public function reset() + { + self::$cache = []; + self::$trackedMethodCalls = []; + } } diff --git a/Classes/Provider/ContentProvider.php b/Classes/Provider/ContentProvider.php index 65ad93ddb..0eb0cce67 100644 --- a/Classes/Provider/ContentProvider.php +++ b/Classes/Provider/ContentProvider.php @@ -20,159 +20,167 @@ * processing records. This processing ensures that relationships * between content elements get stored correctly. */ -class ContentProvider extends AbstractProvider implements ProviderInterface { - - /** - * @var string - */ - protected $extensionKey = 'flux'; - - /** - * @var integer - */ - protected $priority = 50; - - /** - * @var string - */ - protected $tableName = 'tt_content'; - - /** - * @var string - */ - protected $fieldName = 'pi_flexform'; - - /** - * @var ContentService - */ - protected $contentService; - - /** - * @param ContentService $contentService - * @return void - */ - public function injectContentService(ContentService $contentService) { - $this->contentService = $contentService; - } - - /** - * @param array $row - * @param string $table - * @param string $field - * @param string $extensionKey - * @return bool - */ - public function trigger(array $row, $table, $field, $extensionKey = NULL) { - if ('tt_content' === $table && NULL === $field) { - // This Provider will bypass checking for matched plugin- - // and/or content type in the case where $field is NULL. - // This case is triggered *once* per record from our - // TCEMain class; subsequent calls all have a $field and - // will pass through to the basic trigger() method. - // Note for implementers: if you subclass this ContentProvider - // in your own extension (which is perfectly valid to do!) - // please consider if you must override the trigger() method - // to ensure that your particular Provider only reacts when - // users save records that your Provider actually supports. - return TRUE; - } - return parent::trigger($row, $table, $field, $extensionKey); - } - - /** - * Note: This Provider will -always- trigger on tt_content list_type records (plugin) - * but has the lowest possible (0) priority, ensuring that any - * Provider which wants to take over, can do so. - * - * @param array $row - * @return integer - */ - public function getPriority(array $row) { - if (FALSE === empty($row['list_type'])) { - return 0; - } - return $this->priority; - } - - /** - * @param string $operation - * @param integer $id - * @param array $row - * @param DataHandler $reference - * @param array $removals Allows overridden methods to pass an additional array of field names to remove from the stored Flux value - * @return void - */ - public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = array()) { - if (TRUE === self::shouldCallWithClassName(__CLASS__, __FUNCTION__, $id, $operation)) { - parent::postProcessRecord($operation, $id, $row, $reference, $removals); - $parameters = GeneralUtility::_GET(); - $this->contentService->affectRecordByRequestParameters($id, $row, $parameters, $reference); - self::trackMethodCallWithClassName(__CLASS__, __FUNCTION__, $id, $operation); - } - } - - /** - * Post-process a command executed on a record form the table this ConfigurationProvider - * is attached to. - * - * @param string $command - * @param integer $id - * @param array $row - * @param integer $relativeTo - * @param DataHandler $reference - * @return void - */ - public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) { - if (TRUE === self::shouldCallWithClassName(__CLASS__, __FUNCTION__, $id, $command)) { - parent::postProcessCommand($command, $id, $row, $relativeTo, $reference); - $pasteCommands = array('copy', 'move'); - if (TRUE === in_array($command, $pasteCommands)) { - $callback = $this->getCallbackCommand(); - if (TRUE === isset($callback['paste'])) { - $pasteCommand = $callback['paste']; - $parameters = explode('|', $pasteCommand); - $this->contentService->pasteAfter($command, $row, $parameters, $reference); - } else { - $moveData = (array) $this->getMoveData(); - $this->contentService->moveRecord($row, $relativeTo, $moveData, $reference); - } - } - if ('localize' === $command) { - $this->contentService->fixPositionInLocalization($id, $relativeTo, $row, $reference); - } - self::trackMethodCallWithClassName(__CLASS__, __FUNCTION__, $id, $command); - } - } - - /** - * @return array|NULL - */ - protected function getMoveData() { - $return = NULL; - $rawPostData = $this->getRawPostData(); - if (FALSE === empty($rawPostData)) { - $request = (array) json_decode($rawPostData, TRUE); - $hasRequestData = TRUE === isset($request['method']) && TRUE === isset($request['data']); - $isMoveMethod = 'moveContentElement' === $request['method']; - $return = (TRUE === $hasRequestData && TRUE === $isMoveMethod) ? $request['data'] : NULL; - } - return $return; - } - - /** - * @return array - */ - protected function getCallbackCommand() { - $command = GeneralUtility::_GET('CB'); - return (array) $command; - } - - /** - * @return string - * @codeCoverageIgnore - */ - protected function getRawPostData() { - return file_get_contents('php://input'); - } - +class ContentProvider extends AbstractProvider implements ProviderInterface +{ + + /** + * @var string + */ + protected $extensionKey = 'flux'; + + /** + * @var integer + */ + protected $priority = 50; + + /** + * @var string + */ + protected $tableName = 'tt_content'; + + /** + * @var string + */ + protected $fieldName = 'pi_flexform'; + + /** + * @var ContentService + */ + protected $contentService; + + /** + * @param ContentService $contentService + * @return void + */ + public function injectContentService(ContentService $contentService) + { + $this->contentService = $contentService; + } + + /** + * @param array $row + * @param string $table + * @param string $field + * @param string $extensionKey + * @return bool + */ + public function trigger(array $row, $table, $field, $extensionKey = null) + { + if ('tt_content' === $table && null === $field) { + // This Provider will bypass checking for matched plugin- + // and/or content type in the case where $field is NULL. + // This case is triggered *once* per record from our + // TCEMain class; subsequent calls all have a $field and + // will pass through to the basic trigger() method. + // Note for implementers: if you subclass this ContentProvider + // in your own extension (which is perfectly valid to do!) + // please consider if you must override the trigger() method + // to ensure that your particular Provider only reacts when + // users save records that your Provider actually supports. + return true; + } + return parent::trigger($row, $table, $field, $extensionKey); + } + + /** + * Note: This Provider will -always- trigger on tt_content list_type records (plugin) + * but has the lowest possible (0) priority, ensuring that any + * Provider which wants to take over, can do so. + * + * @param array $row + * @return integer + */ + public function getPriority(array $row) + { + if (false === empty($row['list_type'])) { + return 0; + } + return $this->priority; + } + + /** + * @param string $operation + * @param integer $id + * @param array $row + * @param DataHandler $reference + * @param array $removals Allows methods to pass an array of field names to remove from the stored Flux value + * @return void + */ + public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = []) + { + if (true === self::shouldCallWithClassName(__CLASS__, __FUNCTION__, $id, $operation)) { + parent::postProcessRecord($operation, $id, $row, $reference, $removals); + $parameters = GeneralUtility::_GET(); + $this->contentService->affectRecordByRequestParameters($id, $row, $parameters, $reference); + self::trackMethodCallWithClassName(__CLASS__, __FUNCTION__, $id, $operation); + } + } + + /** + * Post-process a command executed on a record form the table this ConfigurationProvider + * is attached to. + * + * @param string $command + * @param integer $id + * @param array $row + * @param integer $relativeTo + * @param DataHandler $reference + * @return void + */ + public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference) + { + if (true === self::shouldCallWithClassName(__CLASS__, __FUNCTION__, $id, $command)) { + parent::postProcessCommand($command, $id, $row, $relativeTo, $reference); + $pasteCommands = ['copy', 'move']; + if (true === in_array($command, $pasteCommands)) { + $callback = $this->getCallbackCommand(); + if (true === isset($callback['paste'])) { + $pasteCommand = $callback['paste']; + $parameters = explode('|', $pasteCommand); + $this->contentService->pasteAfter($command, $row, $parameters, $reference); + } else { + $moveData = (array) $this->getMoveData(); + $this->contentService->moveRecord($row, $relativeTo, $moveData, $reference); + } + } + if ('localize' === $command) { + $this->contentService->fixPositionInLocalization($id, $relativeTo, $row, $reference); + } + self::trackMethodCallWithClassName(__CLASS__, __FUNCTION__, $id, $command); + } + } + + /** + * @return array|NULL + */ + protected function getMoveData() + { + $return = null; + $rawPostData = $this->getRawPostData(); + if (false === empty($rawPostData)) { + $request = (array) json_decode($rawPostData, true); + $hasRequestData = true === isset($request['method']) && true === isset($request['data']); + $isMoveMethod = 'moveContentElement' === $request['method']; + $return = (true === $hasRequestData && true === $isMoveMethod) ? $request['data'] : null; + } + return $return; + } + + /** + * @return array + */ + protected function getCallbackCommand() + { + $command = GeneralUtility::_GET('CB'); + return (array) $command; + } + + /** + * @return string + * @codeCoverageIgnore + */ + protected function getRawPostData() + { + return file_get_contents('php://input'); + } } diff --git a/Classes/Provider/Provider.php b/Classes/Provider/Provider.php index cf17dad13..b4cf04010 100644 --- a/Classes/Provider/Provider.php +++ b/Classes/Provider/Provider.php @@ -11,6 +11,7 @@ /** * Base implementation of Provider concept. */ -class Provider extends AbstractProvider implements ProviderInterface { +class Provider extends AbstractProvider implements ProviderInterface +{ } diff --git a/Classes/Provider/ProviderInterface.php b/Classes/Provider/ProviderInterface.php index 4e407e244..92398b242 100644 --- a/Classes/Provider/ProviderInterface.php +++ b/Classes/Provider/ProviderInterface.php @@ -17,384 +17,386 @@ /** * ProviderInterface */ -interface ProviderInterface { - - /** - * Use by TceMain to track method calls to providers for a certain $id. - * Every provider should only be called once per method / $id / command. - * Before calling a provider, TceMain will call this method. - * If the provider hasn't been called for that method / $id / command - * before, it is. - * - * - * @param string $methodName - * @param mixed $id - * @param string $command - * @return boolean - */ - public function shouldCall($methodName, $id, $command = ''); - - /** - * Use by TceMain to track method calls to providers for a certain $id. - * Every provider should only be called once per method / $id. - * When TceMain has called the provider it will call this method afterwards. - * - * @param string $methodName - * @param mixed $id - * @return void - */ - public function trackMethodCall($methodName, $id); - - /** - * @param array $settings - * @return void - */ - public function loadSettings(array $settings); - - /** - * Must return TRUE if this ConfigurationProvider instance wants - * to be the one used for proccesing $row - * - * @param array $row - * @param string $table - * @param string $field - * @param string $extensionKey - * @return boolean - */ - public function trigger(array $row, $table, $field, $extensionKey = NULL); - - /** - * Returns an instance of \FluidTYPO3\Flux\View\ViewContext as required by this record, - * with the provided RequestInterface instance as context. - * - * @param array $row - * @param RequestInterface|NULL $request - * @return ViewContext - */ - public function getViewContext(array $row, RequestInterface $request = NULL); - - /** - * Returns an instance of \FluidTYPO3\Flux\Form as required by this record. - * - * @param array $row - * @return Form|NULL - */ - public function getForm(array $row); - - /** - * Returns a \FluidTYPO3\Flux\Form\Container\Grid as required by this record. - * - * @param array $row - * @return Grid - */ - public function getGrid(array $row); - - /** - * Return the extension key this processor belongs to - * - * @param array $row The record which triggered the processing - * @return string - */ - public function getExtensionKey(array $row); - - /** - * Get the absolute path to the template file containing the FlexForm - * field and sheets configuration. EXT:myext... syntax allowed - * - * @param array $row The record which triggered the processing - * @return string|NULL - */ - public function getTemplatePathAndFilename(array $row); - - /** - * Get an array of variables that should be used when rendering the - * FlexForm configuration - * - * @param array $row The record which triggered the processing - * @return array|NULL - */ - public function getTemplateVariables(array $row); - - /** - * Get paths for rendering the template, usual format i.e. partialRootPath, - * layoutRootPath, templateRootPath members must be in the returned array - * - * @param array $row - * @return array - */ - public function getTemplatePaths(array $row); - - /** - * Get the section name containing the FlexForm configuration. Return NULL - * if no sections are used. If you use sections in your template, you MUST - * use a section to contain the FlexForm configuration - * - * @param array $row The record which triggered the processing - * @return string|NULL - */ - public function getConfigurationSectionName(array $row); - - /** - * @param string $listType - */ - public function setListType($listType); - - /** - * @return string - */ - public function getListType(); - - /** - * @param string $contentObjectType - */ - public function setContentObjectType($contentObjectType); - - /** - * @return string - */ - public function getContentObjectType(); - - /** - * Get the field name which will trigger processing - * - * @param array $row The record which triggered the processing - * @return string|NULL - */ - public function getFieldName(array $row); - - /** - * Get the list_type value that will trigger processing - * - * @param array $row The record which triggered the processing - * @return string|NULL - */ - public function getTableName(array $row); - - /** - * @param string $tableName - * @return void - */ - public function setTableName($tableName); - - /** - * @param string $fieldName - * @return void - */ - public function setFieldName($fieldName); - - /** - * @return string - */ - public function getName(); - - /** - * @param string $name - */ - public function setName($name); - - /** - * @param string $extensionKey - * @return void - */ - public function setExtensionKey($extensionKey); - - /** - * @param array|NULL $templateVariables - * @return void - */ - public function setTemplateVariables($templateVariables); - - /** - * @param string $templatePathAndFilename - * @return void - */ - public function setTemplatePathAndFilename($templatePathAndFilename); - - /** - * @param array|NULL $templatePaths - * @return void - */ - public function setTemplatePaths($templatePaths); - - /** - * @param string|NULL $configurationSectionName - * @return void - */ - public function setConfigurationSectionName($configurationSectionName); - - /** - * Post-process the TCEforms DataStructure for a record associated - * with this ConfigurationProvider - * - * @param array $row - * @param mixed $dataStructure Array or string; should only be processed if argument is an array - * @param array $conf - * @return void - */ - public function postProcessDataStructure(array &$row, &$dataStructure, array $conf); - - /** - * Pre-process record data for the table that this ConfigurationProvider - * is attached to. - * - * @abstract - * @param array $row The record data, by reference. Changing fields' values changes the record's values before display - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently displaying the record - * @return void - */ - public function preProcessRecord(array &$row, $id, DataHandler $reference); - - /** - * @abstract - * @param array $row The record data. Changing fields' values changes the record's values before display - * @return integer - */ - public function getPriority(array $row); - - /** - * Returns array($header, $content) preview chunks - * - * @abstract - * @param array $row The record data to be analysed for variables to use in a rendered preview - * @return array - */ - public function getPreview(array $row); - - /** - * Post-process record data for the table that this ConfigurationProvider - * is attached to. - * - * @abstract - * @param string $operation TYPO3 operation identifier, i.e. "update", "new" etc. - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param array $row the record data, by reference. Changing fields' values changes the record's values just before saving - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently saving the record - * @param array $removals Allows overridden methods to pass an additional array of field names to remove from the stored Flux value - * @return void - */ - public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = array()); - - /** - * Post-process database operation for the table that this ConfigurationProvider - * is attached to. - * - * @abstract - * @param string $status TYPO3 operation identifier, i.e. "new" etc. - * @param integer $id The ID of the current record (which is sometimes now included in $row - * @param array $row The record's data, by reference. Changing fields' values changes the record's values just before saving after operation - * @param DataHandler $reference A reference to the \TYPO3\CMS\Core\DataHandling\DataHandler object that is currently performing the database operation - * @return void - */ - public function postProcessDatabaseOperation($status, $id, &$row, DataHandler $reference); - - /** - * Pre-process a command executed on a record form the table this ConfigurationProvider - * is attached to. - * - * @abstract - * @param string $command - * @param integer $id - * @param array $row - * @param integer $relativeTo - * @param DataHandler $reference - * @return void - */ - public function preProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference); - - /** - * Post-process a command executed on a record form the table this ConfigurationProvider - * is attached to. - * - * @abstract - * @param string $command - * @param integer $id - * @param array $row - * @param integer $relativeTo - * @param DataHandler $reference - * @return void - */ - public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference); - - /** - * Processes the table configuration (TCA) for the table associated - * with this Provider, as determined by the trigger() method. Gets - * passed an instance of the record being edited/created along with - * the current configuration array - and must return a complete copy - * of the configuration array manipulated to the Provider's needs. - * - * @param array $row The record being edited/created - * @return array The large FormEngine configuration array - see FormEngine documentation! - */ - public function processTableConfiguration(array $row, array $configuration); - - /** - * Perform operations upon clearing cache(s) - * - * @param array $command - * @return void - */ - public function clearCacheCommand($command = array()); - - /** - * Converts the contents of the provided row's Flux-enabled field, - * at the same time running through the inheritance tree generated - * by getInheritanceTree() in order to apply inherited values. - * - * @param array $row - * @return array - */ - public function getFlexFormValues(array $row); - - /** - * Implement to return a controller action name associated with $row. - * Default strategy: return base name of Provider class minus the "Provider" suffix. - * - * @param array $row - * @return string - */ - public function getControllerNameFromRecord(array $row); - - /** - * @param array $row - * @return string - */ - public function getControllerExtensionKeyFromRecord(array $row); - - /** - * Implement this and return a fully qualified VendorName.PackageName - * value based on $row. - * - * @param array $row - * @return string - */ - public function getControllerPackageNameFromRecord(array $row); - - /** - * @param array $row - * @return string - */ - public function getControllerActionFromRecord(array $row); - - /** - * @param array $row - * @return string - */ - public function getControllerActionReferenceFromRecord(array $row); - - /** - * @param Form $form - */ - public function setForm(Form $form); - - /** - * @param Grid $grid - */ - public function setGrid(Grid $grid); - - /** - * @return void - */ - public function reset(); - +interface ProviderInterface +{ + + /** + * Use by TceMain to track method calls to providers for a certain $id. + * Every provider should only be called once per method / $id / command. + * Before calling a provider, TceMain will call this method. + * If the provider hasn't been called for that method / $id / command + * before, it is. + * + * + * @param string $methodName + * @param mixed $id + * @param string $command + * @return boolean + */ + public function shouldCall($methodName, $id, $command = ''); + + /** + * Use by TceMain to track method calls to providers for a certain $id. + * Every provider should only be called once per method / $id. + * When TceMain has called the provider it will call this method afterwards. + * + * @param string $methodName + * @param mixed $id + * @param string $command + * @return void + */ + public function trackMethodCall($methodName, $id, $command = ''); + + /** + * @param array $settings + * @return void + */ + public function loadSettings(array $settings); + + /** + * Must return TRUE if this ConfigurationProvider instance wants + * to be the one used for proccesing $row + * + * @param array $row + * @param string $table + * @param string $field + * @param string $extensionKey + * @return boolean + */ + public function trigger(array $row, $table, $field, $extensionKey = null); + + /** + * Returns an instance of \FluidTYPO3\Flux\View\ViewContext as required by this record, + * with the provided RequestInterface instance as context. + * + * @param array $row + * @param RequestInterface|NULL $request + * @return ViewContext + */ + public function getViewContext(array $row, RequestInterface $request = null); + + /** + * Returns an instance of \FluidTYPO3\Flux\Form as required by this record. + * + * @param array $row + * @return Form|NULL + */ + public function getForm(array $row); + + /** + * Returns a \FluidTYPO3\Flux\Form\Container\Grid as required by this record. + * + * @param array $row + * @return Grid + */ + public function getGrid(array $row); + + /** + * Return the extension key this processor belongs to + * + * @param array $row The record which triggered the processing + * @return string + */ + public function getExtensionKey(array $row); + + /** + * Get the absolute path to the template file containing the FlexForm + * field and sheets configuration. EXT:myext... syntax allowed + * + * @param array $row The record which triggered the processing + * @return string|NULL + */ + public function getTemplatePathAndFilename(array $row); + + /** + * Get an array of variables that should be used when rendering the + * FlexForm configuration + * + * @param array $row The record which triggered the processing + * @return array|NULL + */ + public function getTemplateVariables(array $row); + + /** + * Get paths for rendering the template, usual format i.e. partialRootPath, + * layoutRootPath, templateRootPath members must be in the returned array + * + * @param array $row + * @return array + */ + public function getTemplatePaths(array $row); + + /** + * Get the section name containing the FlexForm configuration. Return NULL + * if no sections are used. If you use sections in your template, you MUST + * use a section to contain the FlexForm configuration + * + * @param array $row The record which triggered the processing + * @return string|NULL + */ + public function getConfigurationSectionName(array $row); + + /** + * @param string $listType + */ + public function setListType($listType); + + /** + * @return string + */ + public function getListType(); + + /** + * @param string $contentObjectType + */ + public function setContentObjectType($contentObjectType); + + /** + * @return string + */ + public function getContentObjectType(); + + /** + * Get the field name which will trigger processing + * + * @param array $row The record which triggered the processing + * @return string|NULL + */ + public function getFieldName(array $row); + + /** + * Get the list_type value that will trigger processing + * + * @param array $row The record which triggered the processing + * @return string|NULL + */ + public function getTableName(array $row); + + /** + * @param string $tableName + * @return void + */ + public function setTableName($tableName); + + /** + * @param string $fieldName + * @return void + */ + public function setFieldName($fieldName); + + /** + * @return string + */ + public function getName(); + + /** + * @param string $name + */ + public function setName($name); + + /** + * @param string $extensionKey + * @return void + */ + public function setExtensionKey($extensionKey); + + /** + * @param array|NULL $templateVariables + * @return void + */ + public function setTemplateVariables($templateVariables); + + /** + * @param string $templatePathAndFilename + * @return void + */ + public function setTemplatePathAndFilename($templatePathAndFilename); + + /** + * @param array|NULL $templatePaths + * @return void + */ + public function setTemplatePaths($templatePaths); + + /** + * @param string|NULL $configurationSectionName + * @return void + */ + public function setConfigurationSectionName($configurationSectionName); + + /** + * Post-process the TCEforms DataStructure for a record associated + * with this ConfigurationProvider + * + * @param array $row + * @param mixed $dataStructure Array or string; should only be processed if argument is an array + * @param array $conf + * @return void + */ + public function postProcessDataStructure(array &$row, &$dataStructure, array $conf); + + /** + * Pre-process record data for the table that this ConfigurationProvider + * is attached to. + * + * @abstract + * @param array $row The record by reference. Changing fields' values changes the record's values before display + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param DataHandler $reference A reference to the DataHandler object that is currently displaying the record + * @return void + */ + public function preProcessRecord(array &$row, $id, DataHandler $reference); + + /** + * @abstract + * @param array $row The record data. Changing fields' values changes the record's values before display + * @return integer + */ + public function getPriority(array $row); + + /** + * Returns [$header, $content) preview chunks + * + * @abstract + * @param array $row The record data to be analysed for variables to use in a rendered preview + * @return array + */ + public function getPreview(array $row); + + /** + * Post-process record data for the table that this ConfigurationProvider + * is attached to. + * + * @abstract + * @param string $operation TYPO3 operation identifier, i.e. "update", "new" etc. + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param array $row the record by reference. Changing fields' values changes the record's values before saving + * @param DataHandler $reference A reference to the DataHandler object that is currently saving the record + * @param array $removals Allows methods to pass an array of field names to remove from the stored Flux value + * @return void + */ + public function postProcessRecord($operation, $id, array &$row, DataHandler $reference, array $removals = []); + + /** + * Post-process database operation for the table that this ConfigurationProvider + * is attached to. + * + * @abstract + * @param string $status TYPO3 operation identifier, i.e. "new" etc. + * @param integer $id The ID of the current record (which is sometimes now included in $row + * @param array $row The record by reference. Changing fields' values changes the record's values + * just before saving after operation + * @param DataHandler $reference A reference to the DataHandler object that is currently performing the operation + * @return void + */ + public function postProcessDatabaseOperation($status, $id, &$row, DataHandler $reference); + + /** + * Pre-process a command executed on a record form the table this ConfigurationProvider + * is attached to. + * + * @abstract + * @param string $command + * @param integer $id + * @param array $row + * @param integer $relativeTo + * @param DataHandler $reference + * @return void + */ + public function preProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference); + + /** + * Post-process a command executed on a record form the table this ConfigurationProvider + * is attached to. + * + * @abstract + * @param string $command + * @param integer $id + * @param array $row + * @param integer $relativeTo + * @param DataHandler $reference + * @return void + */ + public function postProcessCommand($command, $id, array &$row, &$relativeTo, DataHandler $reference); + + /** + * Processes the table configuration (TCA) for the table associated + * with this Provider, as determined by the trigger() method. Gets + * passed an instance of the record being edited/created along with + * the current configuration array - and must return a complete copy + * of the configuration array manipulated to the Provider's needs. + * + * @param array $row The record being edited/created + * @return array The large FormEngine configuration array - see FormEngine documentation! + */ + public function processTableConfiguration(array $row, array $configuration); + + /** + * Perform operations upon clearing cache(s) + * + * @param array $command + * @return void + */ + public function clearCacheCommand($command = []); + + /** + * Converts the contents of the provided row's Flux-enabled field, + * at the same time running through the inheritance tree generated + * by getInheritanceTree() in order to apply inherited values. + * + * @param array $row + * @return array + */ + public function getFlexFormValues(array $row); + + /** + * Implement to return a controller action name associated with $row. + * Default strategy: return base name of Provider class minus the "Provider" suffix. + * + * @param array $row + * @return string + */ + public function getControllerNameFromRecord(array $row); + + /** + * @param array $row + * @return string + */ + public function getControllerExtensionKeyFromRecord(array $row); + + /** + * Implement this and return a fully qualified VendorName.PackageName + * value based on $row. + * + * @param array $row + * @return string + */ + public function getControllerPackageNameFromRecord(array $row); + + /** + * @param array $row + * @return string + */ + public function getControllerActionFromRecord(array $row); + + /** + * @param array $row + * @return string + */ + public function getControllerActionReferenceFromRecord(array $row); + + /** + * @param Form $form + */ + public function setForm(Form $form); + + /** + * @param Grid $grid + */ + public function setGrid(Grid $grid); + + /** + * @return void + */ + public function reset(); } diff --git a/Classes/Provider/ProviderResolver.php b/Classes/Provider/ProviderResolver.php index cd3822bc0..ef551aed6 100644 --- a/Classes/Provider/ProviderResolver.php +++ b/Classes/Provider/ProviderResolver.php @@ -18,158 +18,169 @@ * * Returns one or more Provider instances based on parameters. */ -class ProviderResolver implements SingletonInterface { +class ProviderResolver implements SingletonInterface +{ - /** - * @var array - */ - protected $providers = NULL; + /** + * @var array + */ + protected $providers = null; - /** - * @var FluxService - */ - protected $configurationService; + /** + * @var FluxService + */ + protected $configurationService; - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @param FluxService $configurationService - * @return void - */ - public function injectConfigurationService(FluxService $configurationService) { - $this->configurationService = $configurationService; - } + /** + * @param FluxService $configurationService + * @return void + */ + public function injectConfigurationService(FluxService $configurationService) + { + $this->configurationService = $configurationService; + } - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * ResolveUtility the top-priority ConfigurationPrivider which can provide - * a working FlexForm configuration baed on the given parameters. - * - * @param string $table - * @param string $fieldName - * @param array $row - * @param string $extensionKey - * @return ProviderInterface|NULL - */ - public function resolvePrimaryConfigurationProvider($table, $fieldName, array $row = NULL, $extensionKey = NULL) { - if (is_array($row) === FALSE) { - $row = array(); - } - $providers = $this->resolveConfigurationProviders($table, $fieldName, $row, $extensionKey); - $priority = 0; - $providerWithTopPriority = NULL; - foreach ($providers as $provider) { - if ($provider->getPriority($row) >= $priority) { - $providerWithTopPriority = &$provider; - } - } - return $providerWithTopPriority; - } + /** + * ResolveUtility the top-priority ConfigurationPrivider which can provide + * a working FlexForm configuration baed on the given parameters. + * + * @param string $table + * @param string $fieldName + * @param array $row + * @param string $extensionKey + * @return ProviderInterface|NULL + */ + public function resolvePrimaryConfigurationProvider($table, $fieldName, array $row = null, $extensionKey = null) + { + if (is_array($row) === false) { + $row = []; + } + $providers = $this->resolveConfigurationProviders($table, $fieldName, $row, $extensionKey); + $priority = 0; + $providerWithTopPriority = null; + foreach ($providers as $provider) { + if ($provider->getPriority($row) >= $priority) { + $providerWithTopPriority = &$provider; + } + } + return $providerWithTopPriority; + } - /** - * Resolves a ConfigurationProvider which can provide a working FlexForm - * configuration based on the given parameters. - * - * @param string $table - * @param string $fieldName - * @param array $row - * @param string $extensionKey - * @throws \RuntimeException - * @return ProviderInterface[] - */ - public function resolveConfigurationProviders($table, $fieldName, array $row = NULL, $extensionKey = NULL) { - $row = FALSE === is_array($row) ? array() : $row; - $providers = $this->getAllRegisteredProviderInstances(); - $prioritizedProviders = array(); - foreach ($providers as $provider) { - if (TRUE === $provider->trigger($row, $table, $fieldName, $extensionKey)) { - $priority = $provider->getPriority($row); - if (FALSE === is_array($prioritizedProviders[$priority])) { - $prioritizedProviders[$priority] = array(); - } - $prioritizedProviders[$priority][] = $provider; - } - } - ksort($prioritizedProviders); - $providersToReturn = array(); - foreach ($prioritizedProviders as $providerSet) { - foreach ($providerSet as $provider) { - array_push($providersToReturn, $provider); - } - } - return $providersToReturn; - } + /** + * Resolves a ConfigurationProvider which can provide a working FlexForm + * configuration based on the given parameters. + * + * @param string $table + * @param string $fieldName + * @param array $row + * @param string $extensionKey + * @throws \RuntimeException + * @return ProviderInterface[] + */ + public function resolveConfigurationProviders($table, $fieldName, array $row = null, $extensionKey = null) + { + $row = false === is_array($row) ? [] : $row; + $providers = $this->getAllRegisteredProviderInstances(); + $prioritizedProviders = []; + foreach ($providers as $provider) { + if (true === $provider->trigger($row, $table, $fieldName, $extensionKey)) { + $priority = $provider->getPriority($row); + if (false === is_array($prioritizedProviders[$priority])) { + $prioritizedProviders[$priority] = []; + } + $prioritizedProviders[$priority][] = $provider; + } + } + ksort($prioritizedProviders); + $providersToReturn = []; + foreach ($prioritizedProviders as $providerSet) { + foreach ($providerSet as $provider) { + array_push($providersToReturn, $provider); + } + } + return $providersToReturn; + } - /** - * @return ProviderInterface[] - */ - public function loadTypoScriptConfigurationProviderInstances() { - $providerConfigurations = (array) $this->configurationService->getTypoScriptByPath('plugin.tx_flux.providers'); - $providers = array(); - foreach ($providerConfigurations as $name => $providerSettings) { - $className = 'FluidTYPO3\Flux\Provider\Provider'; - if (TRUE === isset($providerSettings['className']) && TRUE === class_exists($providerSettings['className'])) { - $className = $providerSettings['className']; - } - /** @var ProviderInterface $provider */ - $provider = $this->objectManager->get($className); - $provider->setName($name); - $provider->loadSettings($providerSettings); - $providers[$name] = $provider; - } - return $providers; - } + /** + * @return ProviderInterface[] + */ + public function loadTypoScriptConfigurationProviderInstances() + { + $providerConfigurations = (array) $this->configurationService->getTypoScriptByPath('plugin.tx_flux.providers'); + $providers = []; + foreach ($providerConfigurations as $name => $providerSettings) { + $className = 'FluidTYPO3\Flux\Provider\Provider'; + if (isset($providerSettings['className']) && class_exists($providerSettings['className'])) { + $className = $providerSettings['className']; + } + /** @var ProviderInterface $provider */ + $provider = $this->objectManager->get($className); + $provider->setName($name); + $provider->loadSettings($providerSettings); + $providers[$name] = $provider; + } + return $providers; + } - /** - * @return ProviderInterface[] - */ - protected function getAllRegisteredProviderInstances() { - if (NULL === $this->providers) { - $providers = $this->loadCoreRegisteredProviders(); - $typoScriptConfigurationProviders = $this->loadTypoScriptConfigurationProviderInstances(); - $providers = array_merge($providers, $typoScriptConfigurationProviders); - $this->providers = $this->validateAndInstantiateProviders($providers); - } - return $this->providers; - } + /** + * @return ProviderInterface[] + */ + protected function getAllRegisteredProviderInstances() + { + if (null === $this->providers) { + $providers = $this->loadCoreRegisteredProviders(); + $typoScriptConfigurationProviders = $this->loadTypoScriptConfigurationProviderInstances(); + $providers = array_merge($providers, $typoScriptConfigurationProviders); + $this->providers = $this->validateAndInstantiateProviders($providers); + } + return $this->providers; + } - /** - * @param array $providers - * @return ProviderInterface[] - * @throws \RuntimeException - */ - protected function validateAndInstantiateProviders(array $providers) { - $instances = array(); - foreach ($providers as $classNameOrInstance) { - if (FALSE === in_array('FluidTYPO3\Flux\Provider\ProviderInterface', class_implements($classNameOrInstance))) { - $className = is_object($classNameOrInstance) ? get_class($classNameOrInstance) : $classNameOrInstance; - throw new \RuntimeException($className . ' must implement ProviderInterfaces from Flux/Provider', 1327173536); - } - if (TRUE === is_object($classNameOrInstance)) { - $provider = $classNameOrInstance; - } else { - $provider = $this->objectManager->get($classNameOrInstance); - } - $instances[] = $provider; - } - return $instances; - } - - /** - * @return array - */ - protected function loadCoreRegisteredProviders() { - return Core::getRegisteredFlexFormProviders(); - } + /** + * @param array $providers + * @return ProviderInterface[] + * @throws \RuntimeException + */ + protected function validateAndInstantiateProviders(array $providers) + { + $instances = []; + foreach ($providers as $classNameOrInstance) { + if (!in_array('FluidTYPO3\Flux\Provider\ProviderInterface', class_implements($classNameOrInstance))) { + $className = is_object($classNameOrInstance) ? get_class($classNameOrInstance) : $classNameOrInstance; + throw new \RuntimeException( + $className . ' must implement ProviderInterfaces from Flux/Provider', + 1327173536 + ); + } + if (true === is_object($classNameOrInstance)) { + $provider = $classNameOrInstance; + } else { + $provider = $this->objectManager->get($classNameOrInstance); + } + $instances[] = $provider; + } + return $instances; + } + /** + * @return array + */ + protected function loadCoreRegisteredProviders() + { + return Core::getRegisteredFlexFormProviders(); + } } diff --git a/Classes/Service/ContentService.php b/Classes/Service/ContentService.php index 4e78164c7..1950a1477 100644 --- a/Classes/Service/ContentService.php +++ b/Classes/Service/ContentService.php @@ -19,431 +19,503 @@ * * Main API Service for interacting with Flux-based FlexForms */ -class ContentService implements SingletonInterface { +class ContentService implements SingletonInterface +{ - const COLPOS_FLUXCONTENT = 18181; + const COLPOS_FLUXCONTENT = 18181; - /** - * @var RecordService - */ - protected $recordService; + /** + * @var RecordService + */ + protected $recordService; - /** - * @var WorkspacesAwareRecordService - */ - protected $workspacesAwareRecordService; + /** + * @var WorkspacesAwareRecordService + */ + protected $workspacesAwareRecordService; - /** - * @param RecordService $recordService - * @return void - */ - public function injectRecordService(RecordService $recordService) { - $this->recordService = $recordService; - } + /** + * @param RecordService $recordService + * @return void + */ + public function injectRecordService(RecordService $recordService) + { + $this->recordService = $recordService; + } - /** - * @param WorkspacesAwareRecordService $workspacesAwareRecordService - * @return void - */ - public function injectWorkspacesAwareRecordService(WorkspacesAwareRecordService $workspacesAwareRecordService) { - $this->workspacesAwareRecordService = $workspacesAwareRecordService; - } + /** + * @param WorkspacesAwareRecordService $workspacesAwareRecordService + * @return void + */ + public function injectWorkspacesAwareRecordService(WorkspacesAwareRecordService $workspacesAwareRecordService) + { + $this->workspacesAwareRecordService = $workspacesAwareRecordService; + } - /** - * @param mixed $id - * @param array $row - * @param array $parameters - * @param DataHandler $tceMain - * @return void - */ - public function affectRecordByRequestParameters($id, array &$row, $parameters, DataHandler $tceMain) { - unset($id, $tceMain); - if (FALSE === empty($parameters['overrideVals']['tt_content']['tx_flux_parent'])) { - $row['tx_flux_parent'] = (integer) $parameters['overrideVals']['tt_content']['tx_flux_parent']; - if (0 < $row['tx_flux_parent']) { - $row['colPos'] = self::COLPOS_FLUXCONTENT; - } - } - } + /** + * @param mixed $id + * @param array $row + * @param array $parameters + * @param DataHandler $tceMain + * @return void + */ + public function affectRecordByRequestParameters($id, array &$row, $parameters, DataHandler $tceMain) + { + unset($id, $tceMain); + if (false === empty($parameters['overrideVals']['tt_content']['tx_flux_parent'])) { + $row['tx_flux_parent'] = (integer) $parameters['overrideVals']['tt_content']['tx_flux_parent']; + if (0 < $row['tx_flux_parent']) { + $row['colPos'] = self::COLPOS_FLUXCONTENT; + } + } + } - /** - * Paste one record after another record. - * - * @param string $command The command which caused pasting - "copy" is targeted in order to determine "reference" pasting. - * @param array $row The record to be pasted, by reference. Changes original $row - * @param array $parameters List of parameters defining the paste operation target - * @param DataHandler $tceMain - * @return void - */ - public function pasteAfter($command, array &$row, $parameters, DataHandler $tceMain) { - $id = $row['uid']; - $tablename = 'tt_content'; - $subCommand = NULL; - $possibleArea = NULL; - $parentUid = NULL; - $relativeRecord = NULL; - $possibleColPos = NULL; - $nestedArguments = explode('-', $parameters[1]); - $numberOfNestedArguments = count($nestedArguments); - if (5 < $numberOfNestedArguments) { - // Parameters were passed in a hyphen-glued string, created by Flux and passed into command. - list ($pid, $subCommand, $relativeUid, $parentUid, $possibleArea, $possibleColPos) = $nestedArguments; - $parentUid = (integer) $parentUid; - // Parent into same grid results in endless loop - if ('move' === $command && (integer) $id === $parentUid && (integer) $pid === (integer) $row['pid']) { - return; - } - $relativeUid = 0 - (integer) $relativeUid; - if (FALSE === empty($possibleArea)) { - // Flux content area detected, override colPos to virtual Flux column number. - // The $possibleColPos variable may or may not already be set but must be - // overridden regardless. - $possibleColPos = self::COLPOS_FLUXCONTENT; - } - } elseif (5 === $numberOfNestedArguments) { - // Parameters are directly from TYPO3 and it almost certainly is a paste to page column. - list (, $possibleColPos, , $relativeUid) = $nestedArguments; - // $relativeUid parameter is not passed by every context. If not set and $pid is negative, - // we must assume that the positive value of $pid is our relative target UID. - $relativeUid = (integer) (0 >= (integer) $pid) ? $pid : $relativeUid; - } elseif (2 === count($parameters) && is_numeric($parameters[1])) { - // The most basic form of pasting: using the clickmenu to "paste after" sends only - // two parameters and the second parameter is always numeric-only. - list ($tablename, $relativeUid) = $parameters; - } + /** + * Paste one record after another record. + * + * @param string $command Command when pasting - "copy" is targeted in order to determine "reference" pasting. + * @param array $row The record to be pasted, by reference. Changes original $row + * @param array $parameters List of parameters defining the paste operation target + * @param DataHandler $tceMain + * @return void + */ + public function pasteAfter($command, array &$row, $parameters, DataHandler $tceMain) + { + $id = $row['uid']; + $tablename = 'tt_content'; + $subCommand = null; + $possibleArea = null; + $parentUid = null; + $relativeRecord = null; + $possibleColPos = null; + $nestedArguments = explode('-', $parameters[1]); + $numberOfNestedArguments = count($nestedArguments); + if (5 < $numberOfNestedArguments) { + // Parameters were passed in a hyphen-glued string, created by Flux and passed into command. + list ($pid, $subCommand, $relativeUid, $parentUid, $possibleArea, $possibleColPos) = $nestedArguments; + $parentUid = (integer) $parentUid; + // Parent into same grid results in endless loop + if ('move' === $command && (integer) $id === $parentUid && (integer) $pid === (integer) $row['pid']) { + return; + } + $relativeUid = 0 - (integer) $relativeUid; + if (false === empty($possibleArea)) { + // Flux content area detected, override colPos to virtual Flux column number. + // The $possibleColPos variable may or may not already be set but must be + // overridden regardless. + $possibleColPos = self::COLPOS_FLUXCONTENT; + } + } elseif (5 === $numberOfNestedArguments) { + // Parameters are directly from TYPO3 and it almost certainly is a paste to page column. + list (, $possibleColPos, , $relativeUid) = $nestedArguments; + // $relativeUid parameter is not passed by every context. If not set and $pid is negative, + // we must assume that the positive value of $pid is our relative target UID. + $relativeUid = (integer) (0 >= (integer) $pid) ? $pid : $relativeUid; + } elseif (2 === count($parameters) && is_numeric($parameters[1])) { + // The most basic form of pasting: using the clickmenu to "paste after" sends only + // two parameters and the second parameter is always numeric-only. + list ($tablename, $relativeUid) = $parameters; + } - // Creating the copy mapping array. Initial processing of all records being pasted, - // either simply assigning them (copy action) or adjusting the copies to become - // "insert records" elements which then render the original record (paste reference). - $mappingArray = $this->createMappingArray($command, $subCommand, $id, $row, $tceMain); + // Creating the copy mapping array. Initial processing of all records being pasted, + // either simply assigning them (copy action) or adjusting the copies to become + // "insert records" elements which then render the original record (paste reference). + $mappingArray = $this->createMappingArray($command, $subCommand, $id, $row, $tceMain); - // If copying is performed relative to another element we must assume the values of - // that element and use them as target relation values regardless of earlier parameters. - if (0 > $relativeUid) { - $relativeRecord = $this->loadRecordFromDatabase(abs($relativeUid)); - $possibleColPos = (integer) $relativeRecord['colPos']; - $possibleArea = $relativeRecord['tx_flux_column']; - $parentUid = (integer) $relativeRecord['tx_flux_parent']; - } - $this->applyMappingArray($mappingArray, $pid, $possibleColPos, $possibleArea, $parentUid, $tablename, $relativeUid, - $relativeRecord, $tceMain); - } + // If copying is performed relative to another element we must assume the values of + // that element and use them as target relation values regardless of earlier parameters. + if (0 > $relativeUid) { + $relativeRecord = $this->loadRecordFromDatabase(abs($relativeUid)); + $possibleColPos = (integer) $relativeRecord['colPos']; + $possibleArea = $relativeRecord['tx_flux_column']; + $parentUid = (integer) $relativeRecord['tx_flux_parent']; + } + $this->applyMappingArray( + $mappingArray, + $pid, + $possibleColPos, + $possibleArea, + $parentUid, + $tablename, + $relativeUid, + $relativeRecord, + $tceMain + ); + } - /** - * @param array $mappingArray - * @param integer $pid - * @param integer $colPos - * @param string $area - * @param integer $parentUid - * @param string $table - * @param integer $relativeUid - * @param array|NULL $relativeRecord - * @param DataHandler $tceMain - * @return void - */ - protected function applyMappingArray($mappingArray, $pid, $colPos, $area, $parentUid, $table, $relativeUid, $relativeRecord, DataHandler $tceMain) { - foreach ($mappingArray as $record) { - if (0 < $pid) { - $record['pid'] = $pid; - } - if ((FALSE === empty($colPos) || 0 === $colPos || '0' === $colPos)) { - $record['colPos'] = $colPos; - } - $record['tx_flux_column'] = (string) (self::COLPOS_FLUXCONTENT === (integer) $colPos ? $area : ''); - $record['tx_flux_parent'] = (integer) (self::COLPOS_FLUXCONTENT === (integer) $colPos ? $parentUid : 0); - if (0 > $relativeUid) { - $record['sorting'] = $tceMain->resorting($table, $relativeRecord['pid'], 'sorting', abs($relativeUid)); - } - $this->updateRecordInDatabase($record); - $tceMain->registerDBList[$table][$record['uid']]; - } - } + /** + * @param array $mappingArray + * @param integer $pid + * @param integer $colPos + * @param string $area + * @param integer $parentUid + * @param string $table + * @param integer $relativeUid + * @param array|NULL $relativeRecord + * @param DataHandler $tceMain + * @return void + */ + protected function applyMappingArray( + $mappingArray, + $pid, + $colPos, + $area, + $parentUid, + $table, + $relativeUid, + $relativeRecord, + DataHandler $tceMain + ) { + foreach ($mappingArray as $record) { + if (0 < $pid) { + $record['pid'] = $pid; + } + if ((false === empty($colPos) || 0 === $colPos || '0' === $colPos)) { + $record['colPos'] = $colPos; + } + $record['tx_flux_column'] = (string) (self::COLPOS_FLUXCONTENT === (integer) $colPos ? $area : ''); + $record['tx_flux_parent'] = (integer) (self::COLPOS_FLUXCONTENT === (integer) $colPos ? $parentUid : 0); + if (0 > $relativeUid) { + $record['sorting'] = $tceMain->resorting($table, $relativeRecord['pid'], 'sorting', abs($relativeUid)); + } + $this->updateRecordInDatabase($record); + $tceMain->registerDBList[$table][$record['uid']]; + } + } - /** - * @param string $command - * @param string $subCommand - * @param integer $id - * @param array $row - * @param DataHandler $tceMain - * @return array - */ - protected function createMappingArray($command, $subCommand, $id, array $row, DataHandler $tceMain) { - $mappingArray = array(); - if ('copy' !== $command) { - $mappingArray[$id] = $row; - } else { - // Only override values from content elements in cmdmap to prevent that child elements "inherits" - // tx_flux_parent and tx_flux_column which would position them outside their tx_flux_parent. - foreach ($tceMain->cmdmap['tt_content'] as $copyFromUid => $cmdMapValues) { - $copyToUid = $tceMain->copyMappingArray['tt_content'][$copyFromUid]; - $record = $this->loadRecordFromDatabase($copyToUid); - if ('reference' === $subCommand) { - $record['CType'] = 'shortcut'; - $record['records'] = $id; - } + /** + * @param string $command + * @param string $subCommand + * @param integer $id + * @param array $row + * @param DataHandler $tceMain + * @return array + */ + protected function createMappingArray($command, $subCommand, $id, array $row, DataHandler $tceMain) + { + $mappingArray = []; + if ('copy' !== $command) { + $mappingArray[$id] = $row; + } else { + // Only override values from content elements in cmdmap to prevent that child elements "inherits" + // tx_flux_parent and tx_flux_column which would position them outside their tx_flux_parent. + foreach ($tceMain->cmdmap['tt_content'] as $copyFromUid => $cmdMapValues) { + $copyToUid = $tceMain->copyMappingArray['tt_content'][$copyFromUid]; + $record = $this->loadRecordFromDatabase($copyToUid); + if ('reference' === $subCommand) { + $record['CType'] = 'shortcut'; + $record['records'] = $id; + } - $mappingArray[$copyFromUid] = $record; - } - } - return $mappingArray; - } + $mappingArray[$copyFromUid] = $record; + } + } + return $mappingArray; + } - /** - * Move the content element depending on various request/row parameters. - * - * @param array $row The row which may, may not, trigger moving. - * @param string $relativeTo If not-zero moves record to after this UID (negative) or top of this colPos (positive) - * @param array $parameters List of parameters defining the move operation target - * @param DataHandler $tceMain - * @return void - */ - public function moveRecord(array &$row, &$relativeTo, $parameters, DataHandler $tceMain) { - // Note: this condition is here in order to NOT perform any actions if - // the $relativeTo variable was passed by EXT:gridelements in which case - // it is invalid (not a negative/positive integer but a string). - if (FALSE === strpos($relativeTo, 'x')) { - if (0 - MiscellaneousUtility::UNIQUE_INTEGER_OVERHEAD > $relativeTo) { - // Fake relative to value - we can get the target from a session variable - list ($parent, $column) = $this->getTargetAreaStoredInSession($relativeTo); - $row['tx_flux_parent'] = $parent; - $row['tx_flux_column'] = $column; - $row['sorting'] = $tceMain->getSortNumber('tt_content', 0, $row['pid']); - } elseif (0 <= (integer) $relativeTo && FALSE === empty($parameters[1])) { - list($prefix, $column, $prefix2, , , $relativePosition, $relativeUid, $area) = GeneralUtility::trimExplode('-', $parameters[1]); - $relativeUid = (integer) $relativeUid; - if ('colpos' === $prefix && 'page' === $prefix2) { - $row['colPos'] = $column; - $row['tx_flux_parent'] = $relativeUid; - $row['tx_flux_column'] = $area; - } - } elseif (0 > (integer) $relativeTo) { - // inserting a new element after another element. Check column position of that element. - $relativeToRecord = $this->loadRecordFromDatabase(abs($relativeTo)); - $row['tx_flux_parent'] = $relativeToRecord['tx_flux_parent']; - $row['tx_flux_column'] = $relativeToRecord['tx_flux_column']; - $row['colPos'] = $relativeToRecord['colPos']; - $row['sorting'] = $tceMain->resorting('tt_content', $relativeToRecord['pid'], 'sorting', abs($relativeTo)); - } elseif (0 < (integer) $relativeTo) { - // moving to first position in colPos, means that $relativeTo is the pid of the containing page - $row['sorting'] = $tceMain->getSortNumber('tt_content', 0, $relativeTo); - $row['tx_flux_parent'] = NULL; - $row['tx_flux_column'] = NULL; - } else { - $row['tx_flux_parent'] = NULL; - $row['tx_flux_column'] = NULL; - } - } else { - // $relativeTo variable was passed by EXT:gridelements - $row['tx_flux_parent'] = NULL; - $row['tx_flux_column'] = NULL; - } - if (0 < $row['tx_flux_parent']) { - $row['colPos'] = self::COLPOS_FLUXCONTENT; - } - $this->updateRecordInDatabase($row); - $this->updateMovePlaceholder($row); - } + /** + * Move the content element depending on various request/row parameters. + * + * @param array $row The row which may, may not, trigger moving. + * @param string $relativeTo If not-zero moves record to after this UID (negative) or top of this colPos (positive) + * @param array $parameters List of parameters defining the move operation target + * @param DataHandler $tceMain + * @return void + */ + public function moveRecord(array &$row, &$relativeTo, $parameters, DataHandler $tceMain) + { + // Note: this condition is here in order to NOT perform any actions if + // the $relativeTo variable was passed by EXT:gridelements in which case + // it is invalid (not a negative/positive integer but a string). + if (false === strpos($relativeTo, 'x')) { + if (0 - MiscellaneousUtility::UNIQUE_INTEGER_OVERHEAD > $relativeTo) { + // Fake relative to value - we can get the target from a session variable + list ($parent, $column) = $this->getTargetAreaStoredInSession($relativeTo); + $row['tx_flux_parent'] = $parent; + $row['tx_flux_column'] = $column; + $row['sorting'] = $tceMain->getSortNumber('tt_content', 0, $row['pid']); + } elseif (0 <= (integer) $relativeTo && false === empty($parameters[1])) { + list($prefix, $column, $prefix2, , , $relativePosition, $relativeUid, $area) = + GeneralUtility::trimExplode('-', $parameters[1]); + $relativeUid = (integer) $relativeUid; + if ('colpos' === $prefix && 'page' === $prefix2) { + $row['colPos'] = $column; + $row['tx_flux_parent'] = $relativeUid; + $row['tx_flux_column'] = $area; + } + } elseif (0 > (integer) $relativeTo) { + // inserting a new element after another element. Check column position of that element. + $relativeToRecord = $this->loadRecordFromDatabase(abs($relativeTo)); + $row['tx_flux_parent'] = $relativeToRecord['tx_flux_parent']; + $row['tx_flux_column'] = $relativeToRecord['tx_flux_column']; + $row['colPos'] = $relativeToRecord['colPos']; + $row['sorting'] = $tceMain->resorting( + 'tt_content', + $relativeToRecord['pid'], + 'sorting', + abs($relativeTo) + ); + } elseif (0 < (integer) $relativeTo) { + // moving to first position in colPos, means that $relativeTo is the pid of the containing page + $row['sorting'] = $tceMain->getSortNumber('tt_content', 0, $relativeTo); + $row['tx_flux_parent'] = null; + $row['tx_flux_column'] = null; + } else { + $row['tx_flux_parent'] = null; + $row['tx_flux_column'] = null; + } + } else { + // $relativeTo variable was passed by EXT:gridelements + $row['tx_flux_parent'] = null; + $row['tx_flux_column'] = null; + } + if (0 < $row['tx_flux_parent']) { + $row['colPos'] = self::COLPOS_FLUXCONTENT; + } + $this->updateRecordInDatabase($row); + $this->updateMovePlaceholder($row); + } - /** - * @param array $row - * @return void - */ - protected function updateMovePlaceholder(array $row) { - $movePlaceholder = $this->getMovePlaceholder($row['uid']); - if (FALSE !== $movePlaceholder) { - $movePlaceholder['tx_flux_parent'] = $row['tx_flux_parent']; - $movePlaceholder['tx_flux_column'] = $row['tx_flux_column']; - $movePlaceholder['colPos'] = $row['colPos']; - $this->updateRecordInDatabase($movePlaceholder); - } - } + /** + * @param array $row + * @return void + */ + protected function updateMovePlaceholder(array $row) + { + $movePlaceholder = $this->getMovePlaceholder($row['uid']); + if (false !== $movePlaceholder) { + $movePlaceholder['tx_flux_parent'] = $row['tx_flux_parent']; + $movePlaceholder['tx_flux_column'] = $row['tx_flux_column']; + $movePlaceholder['colPos'] = $row['colPos']; + $this->updateRecordInDatabase($movePlaceholder); + } + } - /** - * @param integer $recordUid - * @return array - */ - protected function getMovePlaceholder($recordUid) { - return BackendUtility::getMovePlaceholder('tt_content', $recordUid); - } + /** + * @param integer $recordUid + * @return array + */ + protected function getMovePlaceholder($recordUid) + { + return BackendUtility::getMovePlaceholder('tt_content', $recordUid); + } - /** - * @param String $id - * @param array $row - * @param DataHandler $tceMain - * @return void - */ - public function initializeRecord($id, array &$row, DataHandler $tceMain) { - $origUidFieldName = $GLOBALS['TCA']['tt_content']['ctrl']['origUid']; - $languageFieldName = $GLOBALS['TCA']['tt_content']['ctrl']['languageField']; - $newUid = (integer) $tceMain->substNEWwithIDs[$id]; - $oldUid = (integer) $row[$origUidFieldName]; - $newLanguageUid = (integer) $row[$languageFieldName]; - $this->initializeRecordByNewAndOldAndLanguageUids($row, $newUid, $oldUid, $newLanguageUid, $languageFieldName, $tceMain); - } + /** + * @param String $id + * @param array $row + * @param DataHandler $tceMain + * @return void + */ + public function initializeRecord($id, array &$row, DataHandler $tceMain) + { + $origUidFieldName = $GLOBALS['TCA']['tt_content']['ctrl']['origUid']; + $languageFieldName = $GLOBALS['TCA']['tt_content']['ctrl']['languageField']; + $newUid = (integer) $tceMain->substNEWwithIDs[$id]; + $oldUid = (integer) $row[$origUidFieldName]; + $newLanguageUid = (integer) $row[$languageFieldName]; + $this->initializeRecordByNewAndOldAndLanguageUids( + $row, + $newUid, + $oldUid, + $newLanguageUid, + $languageFieldName, + $tceMain + ); + } - /** - * @param array $row - * @param integer $newUid - * @param integer $oldUid - * @param integer $newLanguageUid - * @param string $languageFieldName - * @param DataHandler $tceMain - */ - protected function initializeRecordByNewAndOldAndLanguageUids($row, $newUid, $oldUid, $newLanguageUid, $languageFieldName, DataHandler $tceMain) { - if (0 < $newUid && 0 < $oldUid && 0 < $newLanguageUid) { - $oldRecord = $this->loadRecordFromDatabase($oldUid); - if ($oldRecord[$languageFieldName] !== $newLanguageUid && $oldRecord['pid'] === $row['pid']) { - // look for the translated version of the parent record indicated - // in this new, translated record. Below, we adjust the parent UID - // so it has the UID of the translated parent if one exists. - $translatedParents = (array) $this->workspacesAwareRecordService->get('tt_content', 'uid,sys_language_uid', "t3_origuid = '" . $oldRecord['tx_flux_parent'] . "'" . BackendUtility::deleteClause('tt_content')); - foreach ($translatedParents as $translatedParent) { - if ($translatedParent['sys_language_uid'] == $newLanguageUid) { - // set $translatedParent to the right language ($newLanguageUid): - break; - } - unset($translatedParent); - } - $sortbyFieldName = TRUE === isset($GLOBALS['TCA']['tt_content']['ctrl']['sortby']) ? - $GLOBALS['TCA']['tt_content']['ctrl']['sortby'] : 'sorting'; - $overrideValues = array( - $sortbyFieldName => $tceMain->resorting('tt_content', $row['pid'], $sortbyFieldName, $oldUid), - 'tx_flux_parent' => NULL !== $translatedParent ? $translatedParent['uid'] : $oldRecord['tx_flux_parent'] - ); - $this->updateRecordInDatabase($overrideValues, $newUid); - } - } - } + /** + * @param array $row + * @param integer $newUid + * @param integer $oldUid + * @param integer $newLanguageUid + * @param string $languageFieldName + * @param DataHandler $tceMain + */ + protected function initializeRecordByNewAndOldAndLanguageUids( + $row, + $newUid, + $oldUid, + $newLanguageUid, + $languageFieldName, + DataHandler $tceMain + ) { + if (0 < $newUid && 0 < $oldUid && 0 < $newLanguageUid) { + $oldRecord = $this->loadRecordFromDatabase($oldUid); + if ($oldRecord[$languageFieldName] !== $newLanguageUid && $oldRecord['pid'] === $row['pid']) { + // look for the translated version of the parent record indicated + // in this new, translated record. Below, we adjust the parent UID + // so it has the UID of the translated parent if one exists. + $translatedParents = (array) $this->workspacesAwareRecordService->get( + 'tt_content', + 'uid,sys_language_uid', + "t3_origuid = '" . $oldRecord['tx_flux_parent'] . "'" . BackendUtility::deleteClause('tt_content') + ); + foreach ($translatedParents as $translatedParent) { + if ($translatedParent['sys_language_uid'] == $newLanguageUid) { + // set $translatedParent to the right language ($newLanguageUid): + break; + } + unset($translatedParent); + } + $sortbyFieldName = true === isset($GLOBALS['TCA']['tt_content']['ctrl']['sortby']) ? + $GLOBALS['TCA']['tt_content']['ctrl']['sortby'] : 'sorting'; + $overrideValues = [ + $sortbyFieldName => $tceMain->resorting('tt_content', $row['pid'], $sortbyFieldName, $oldUid), + 'tx_flux_parent' => $translatedParent ? $translatedParent['uid'] : $oldRecord['tx_flux_parent'] + ]; + $this->updateRecordInDatabase($overrideValues, $newUid); + } + } + } - /** - * @param integer $uid - * @param integer $languageUid - * @return array|NULL - */ - protected function loadRecordFromDatabase($uid, $languageUid = 0) { - $uid = (integer) $uid; - $languageUid = (integer) $languageUid; - if (0 === $languageUid) { - $record = BackendUtility::getRecord('tt_content', $uid); - } else { - $record = BackendUtility::getRecordLocalization('tt_content', $uid, $languageUid); - } - $record = $this->workspacesAwareRecordService->getSingle('tt_content', '*', $record['uid']); - return $record; - } + /** + * @param integer $uid + * @param integer $languageUid + * @return array|NULL + */ + protected function loadRecordFromDatabase($uid, $languageUid = 0) + { + $uid = (integer) $uid; + $languageUid = (integer) $languageUid; + if (0 === $languageUid) { + $record = BackendUtility::getRecord('tt_content', $uid); + } else { + $record = BackendUtility::getRecordLocalization('tt_content', $uid, $languageUid); + } + $record = $this->workspacesAwareRecordService->getSingle('tt_content', '*', $record['uid']); + return $record; + } - /** - * @param integer $parentUid - * @return array|NULL - */ - protected function loadRecordsFromDatabase($parentUid) { - $parentUid = (integer) $parentUid; - return $this->workspacesAwareRecordService->get('tt_content', '*', "tx_flux_parent = '" . $parentUid . "'"); - } + /** + * @param integer $parentUid + * @return array|NULL + */ + protected function loadRecordsFromDatabase($parentUid) + { + $parentUid = (integer) $parentUid; + return $this->workspacesAwareRecordService->get('tt_content', '*', "tx_flux_parent = '" . $parentUid . "'"); + } - /** - * @param array $row - * @param integer $uid - * @return void - */ - protected function updateRecordInDatabase(array $row, $uid = NULL) { - if (NULL === $uid) { - $uid = $row['uid']; - } - $uid = (integer) $uid; - if (FALSE === empty($uid)) { - $row['uid'] = $uid; - $this->workspacesAwareRecordService->update('tt_content', $row); - // reload our record for the next bits to have access to all fields - $row = $this->recordService->getSingle('tt_content', '*', $uid); - } - $versionedRecordUid = (integer) (TRUE === isset($row['t3ver_oid']) && 0 < (integer) $row['t3ver_oid'] ? $row['t3ver_oid'] : 0); - if (0 < $versionedRecordUid) { - // temporary record; duplicate key values of original record into temporary one. - // Note: will continue to call this method until all temporary records in chain have been processed. - $placeholder = $this->recordService->getSingle('tt_content', '*', $row['t3ver_oid']); - $placeholder['tx_flux_parent'] = (integer) $row['tx_flux_parent']; - $placeholder['tx_flux_column'] = $row['tx_flux_column']; - $this->updateRecordInDatabase($placeholder, $row['t3ver_oid']); - } - } + /** + * @param array $row + * @param integer $uid + * @return void + */ + protected function updateRecordInDatabase(array $row, $uid = null) + { + if (null === $uid) { + $uid = $row['uid']; + } + $uid = (integer) $uid; + if (false === empty($uid)) { + $row['uid'] = $uid; + $this->workspacesAwareRecordService->update('tt_content', $row); + // reload our record for the next bits to have access to all fields + $row = $this->recordService->getSingle('tt_content', '*', $uid); + } + $versionedRecordUid = (integer) (isset($row['t3ver_oid']) && !empty($row['t3ver_oid']) ? $row['t3ver_oid'] : 0); + if (0 < $versionedRecordUid) { + // temporary record; duplicate key values of original record into temporary one. + // Note: will continue to call this method until all temporary records in chain have been processed. + $placeholder = $this->recordService->getSingle('tt_content', '*', $row['t3ver_oid']); + $placeholder['tx_flux_parent'] = (integer) $row['tx_flux_parent']; + $placeholder['tx_flux_column'] = $row['tx_flux_column']; + $this->updateRecordInDatabase($placeholder, $row['t3ver_oid']); + } + } - /** - * @codeCoverageIgnore - * @param integer $relativeTo - * @return array - */ - protected function getTargetAreaStoredInSession($relativeTo) { - '' !== session_id() ? : session_start(); - return $_SESSION['target' . $relativeTo]; - } + /** + * @codeCoverageIgnore + * @param integer $relativeTo + * @return array + */ + protected function getTargetAreaStoredInSession($relativeTo) + { + '' !== session_id() ? : session_start(); + return $_SESSION['target' . $relativeTo]; + } - /** - * @param integer $uid uid of record in default language - * @param integer $languageUid sys_language_uid of language for the localized record - * @param array $defaultLanguageRecord record in default language (from table tt_content) - * @param DataHandler $reference - */ - public function fixPositionInLocalization($uid, $languageUid, &$defaultLanguageRecord, DataHandler $reference) { - $previousLocalizedRecordUid = $this->getPreviousLocalizedRecordUid($uid, $languageUid, $reference); - $localizedRecord = BackendUtility::getRecordLocalization('tt_content', $uid, $languageUid); - if (NULL === $previousLocalizedRecordUid) { - // moving to first position in tx_flux_column - $localizedRecord[0][$sortingRow] = $reference->getSortNumber('tt_content', 0, $defaultLanguageRecord['pid']); - } else { - $sortingRow = $GLOBALS['TCA']['tt_content']['ctrl']['sortby']; - $localizedRecord[0][$sortingRow] = $reference->resorting( - 'tt_content', - $defaultLanguageRecord['pid'], - $sortingRow, - $previousLocalizedRecordUid - ); - } - $this->updateRecordInDatabase($localizedRecord[0]); - } - - /** - * Returning uid of previous localized record, if any, for tables with a "sortby" column - * Used when new localized records are created so that localized records are sorted in the same order as the default language records - * - * This is a port from DataHandler::getPreviousLocalizedRecordUid that respects tx_flux_parent and tx_flux_column! - * - * @param integer $uid Uid of default language record - * @param integer $language Language of localization - * @param TYPO3\CMS\Core\DataHandling\DataHandler $datahandler - * @return integer uid of record after which the localized record should be inserted - */ - protected function getPreviousLocalizedRecordUid($uid, $language, DataHandler $reference) { - $table = 'tt_content'; - $previousLocalizedRecordUid = $uid; - $sortRow = $GLOBALS['TCA'][$table]['ctrl']['sortby']; - $select = $sortRow . ',pid,uid,colPos,tx_flux_parent,tx_flux_column'; - // Get the sort value of the default language record - $row = BackendUtility::getRecord($table, $uid, $select); - if (is_array($row)) { - // Find the previous record in default language on the same page - $where = sprintf('pid=%d AND sys_language_uid=0 AND %s < %d', (integer) $row['pid'], $sortRow, (integer) $row[$sortRow]); - // Respect the colPos for content elements - if ($table === 'tt_content') { - $where .= sprintf( - ' AND colPos=%d AND tx_flux_column=\'%s\' AND tx_flux_parent=%d', - (integer) $row['colPos'], - $row['tx_flux_column'], - (integer) $row['tx_flux_parent'] - ); - } - $where .= $reference->deleteClause($table); - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select, $table, $where, '', $sortRow . ' DESC', '1'); - // If there is an element, find its localized record in specified localization language - if ($previousRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { - $previousLocalizedRecord = BackendUtility::getRecordLocalization($table, $previousRow['uid'], $language); - if (is_array($previousLocalizedRecord[0])) { - $previousLocalizedRecordUid = $previousLocalizedRecord[0]['uid']; - } - } - $GLOBALS['TYPO3_DB']->sql_free_result($res); - } - return $previousLocalizedRecordUid; - } + /** + * @param integer $uid uid of record in default language + * @param integer $languageUid sys_language_uid of language for the localized record + * @param array $defaultLanguageRecord record in default language (from table tt_content) + * @param DataHandler $reference + */ + public function fixPositionInLocalization($uid, $languageUid, &$defaultLanguageRecord, DataHandler $reference) + { + $previousLocalizedRecordUid = $this->getPreviousLocalizedRecordUid($uid, $languageUid, $reference); + $localizedRecord = BackendUtility::getRecordLocalization('tt_content', $uid, $languageUid); + if (null === $previousLocalizedRecordUid) { + // moving to first position in tx_flux_column + $localizedRecord[0][$sortingRow] = $reference->getSortNumber( + 'tt_content', + 0, + $defaultLanguageRecord['pid'] + ); + } else { + $sortingRow = $GLOBALS['TCA']['tt_content']['ctrl']['sortby']; + $localizedRecord[0][$sortingRow] = $reference->resorting( + 'tt_content', + $defaultLanguageRecord['pid'], + $sortingRow, + $previousLocalizedRecordUid + ); + } + $this->updateRecordInDatabase($localizedRecord[0]); + } + /** + * Returning uid of previous localized record, if any, for tables with a "sortby" column + * Used when new localized records are created so that localized records are sorted in the same order + * as the default language records + * + * This is a port from DataHandler::getPreviousLocalizedRecordUid that respects tx_flux_parent and tx_flux_column! + * + * @param integer $uid Uid of default language record + * @param integer $language Language of localization + * @param TYPO3\CMS\Core\DataHandling\DataHandler $datahandler + * @return integer uid of record after which the localized record should be inserted + */ + protected function getPreviousLocalizedRecordUid($uid, $language, DataHandler $reference) + { + $table = 'tt_content'; + $previousLocalizedRecordUid = $uid; + $sortRow = $GLOBALS['TCA'][$table]['ctrl']['sortby']; + $select = $sortRow . ',pid,uid,colPos,tx_flux_parent,tx_flux_column'; + // Get the sort value of the default language record + $row = BackendUtility::getRecord($table, $uid, $select); + if (is_array($row)) { + // Find the previous record in default language on the same page + $where = sprintf( + 'pid=%d AND sys_language_uid=0 AND %s < %d', + (integer) $row['pid'], + $sortRow, + (integer) $row[$sortRow] + ); + // Respect the colPos for content elements + if ($table === 'tt_content') { + $where .= sprintf( + ' AND colPos=%d AND tx_flux_column=\'%s\' AND tx_flux_parent=%d', + (integer) $row['colPos'], + $row['tx_flux_column'], + (integer) $row['tx_flux_parent'] + ); + } + $where .= $reference->deleteClause($table); + $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select, $table, $where, '', $sortRow . ' DESC', '1'); + // If there is an element, find its localized record in specified localization language + if ($previousRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { + $previousLocalizedRecord = BackendUtility::getRecordLocalization( + $table, + $previousRow['uid'], + $language + ); + if (is_array($previousLocalizedRecord[0])) { + $previousLocalizedRecordUid = $previousLocalizedRecord[0]['uid']; + } + } + $GLOBALS['TYPO3_DB']->sql_free_result($res); + } + return $previousLocalizedRecordUid; + } } diff --git a/Classes/Service/FluxService.php b/Classes/Service/FluxService.php index df3f2f4ef..944490255 100644 --- a/Classes/Service/FluxService.php +++ b/Classes/Service/FluxService.php @@ -44,447 +44,481 @@ * * Main API Service for interacting with Flux-based FlexForms */ -class FluxService implements SingletonInterface { - - /** - * @var array - */ - protected static $cache = array(); - - /** - * @var array - */ - protected static $typoScript = array(); - - /** - * @var array - */ - protected static $friendlySeverities = array( - GeneralUtility::SYSLOG_SEVERITY_INFO, - GeneralUtility::SYSLOG_SEVERITY_NOTICE, - ); - - /** - * @var array - */ - protected $sentDebugMessages = array(); - - /** - * @var string - */ - protected $raw; - - /** - * @var array - */ - protected $contentObjectData; - - /** - * @var ConfigurationManagerInterface - */ - protected $configurationManager; - - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - - /** - * @var ReflectionService - */ - protected $reflectionService; - - /** - * @var ProviderResolver - */ - protected $providerResolver; - - /** - * @param ConfigurationManagerInterface $configurationManager - * @return void - */ - public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager) { - $this->configurationManager = $configurationManager; - } - - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } - - /** - * @param ReflectionService $reflectionService - * @return void - */ - public function injectReflectionService(ReflectionService $reflectionService) { - $this->reflectionService = $reflectionService; - } - - /** - * @param ProviderResolver $providerResolver - * @return void - */ - public function injectProviderResolver(ProviderResolver $providerResolver) { - $this->providerResolver = $providerResolver; - } - - /** - * @param array $objects - * @param string $sortBy - * @param string $sortDirection - * @return array - */ - public function sortObjectsByProperty(array $objects, $sortBy, $sortDirection = 'ASC') { - $sorted = array(); - $sort = array(); - foreach ($objects as $index => $object) { - $sortValue = ObjectAccess::getPropertyPath($object, $sortBy); - $sort[$index] = $sortValue; - } - if ('ASC' === strtoupper($sortDirection)) { - asort($sort); - } else { - arsort($sort); - } - $hasStringIndex = FALSE; - foreach ($sort as $index => $value) { - $sorted[$index] = $objects[$index]; - if (TRUE === is_string($index)) { - $hasStringIndex = TRUE; - } - } - if (FALSE === $hasStringIndex) { - // reset out-of-sequence indices if provided indices contain no strings - $sorted = array_values($sorted); - } - return $sorted; - } - - /** - * @param ViewContext $viewContext - * @return ExposedTemplateView - */ - public function getPreparedExposedTemplateView(ViewContext $viewContext) { - $vendorName = $viewContext->getVendorName(); - $extensionKey = $viewContext->getExtensionKey(); - $qualifiedExtensionName = $viewContext->getExtensionName(); - $controllerName = $viewContext->getControllerName(); - $variables = $viewContext->getVariables(); - if (NULL === $qualifiedExtensionName || FALSE === ExtensionManagementUtility::isLoaded($extensionKey)) { - // Note here: a default value of the argument would not be adequate; outside callers could still pass NULL. - $qualifiedExtensionName = 'Flux'; - } - $extensionName = ExtensionNamingUtility::getExtensionName($qualifiedExtensionName); - /** @var $context ControllerContext */ - $context = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext'); - $request = $viewContext->getRequest(); - /** @var $response Response */ - $response = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Response'); - /** @var $uriBuilder UriBuilder */ - $uriBuilder = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder'); - $uriBuilder->setRequest($request); - $context->setUriBuilder($uriBuilder); - $context->setRequest($request); - $context->setResponse($response); - /** @var $renderingContext RenderingContext */ - $renderingContext = $this->objectManager->get( - FluxPackageFactory::getPackageWithFallback($qualifiedExtensionName) - ->getImplementation(FluxPackage::IMPLEMENTATION_RENDERINGCONTEXT) - ); - $renderingContext->setControllerContext($context); - /** @var $exposedView ExposedTemplateView */ - $exposedView = $this->objectManager->get( - FluxPackageFactory::getPackageWithFallback($qualifiedExtensionName) - ->getImplementation(FluxPackage::IMPLEMENTATION_VIEW) - ); - $exposedView->setRenderingContext($renderingContext); - $exposedView->setControllerContext($context); - $exposedView->assignMultiple($variables); - $exposedView->setTemplatePaths($viewContext->getTemplatePaths()); - $exposedView->setTemplatePathAndFilename($viewContext->getTemplatePathAndFilename()); - return $exposedView; - } - - /** - * @param ViewContext $viewContext - * @param string $formName - * @return Form|NULL - */ - public function getFormFromTemplateFile(ViewContext $viewContext, $formName = 'form') { - $templatePathAndFilename = $viewContext->getTemplatePathAndFilename(); - if (FALSE === file_exists($templatePathAndFilename)) { - return NULL; - } - $section = $viewContext->getSectionName(); - $variables = $viewContext->getVariables(); - $extensionName = $viewContext->getExtensionName(); - $variableCheck = json_encode($variables); - $cacheKey = md5($templatePathAndFilename . $formName . $extensionName . $section . $variableCheck); - if (FALSE === isset(self::$cache[$cacheKey])) { - try { - $exposedView = $this->getPreparedExposedTemplateView($viewContext); - self::$cache[$cacheKey] = $exposedView->getForm($section, $formName); - } catch (\RuntimeException $error) { - $this->debug($error); - /** @var Form $form */ - self::$cache[$cacheKey] = $this->objectManager->get( - FluxPackageFactory::getPackageWithFallback($extensionName) - ->getImplementation(FluxPackage::IMPLEMENTATION_FORM) - ); - self::$cache[$cacheKey]->createField('UserFunction', 'error') - ->setFunction('FluidTYPO3\Flux\UserFunction\ErrorReporter->renderField') - ->setArguments(array($error) - ); - } - } - return self::$cache[$cacheKey]; - } - - /** - * Reads a Grid constructed using flux:grid, returning an array of - * defined rows and columns along with any content areas. - * - * Note about specific implementations: - * - * * EXT:fluidpages uses the Grid to render a BackendLayout on TYPO3 6.0 and above - * * EXT:flux uses the Grid to render content areas inside content elements - * registered with Flux - * - * But your custom extension is of course allowed to use the Grid for any - * purpose. You can even read the Grid from - for example - the currently - * selected page template to know exactly how the BackendLayout looks. - * - * @param ViewContext $viewContext - * @param string $gridName - * @return Grid|NULL - */ - public function getGridFromTemplateFile(ViewContext $viewContext, $gridName = 'grid') { - $templatePathAndFilename = $viewContext->getTemplatePathAndFilename(); - $section = $viewContext->getSectionName(); - $grid = NULL; - if (TRUE === file_exists($templatePathAndFilename)) { - $exposedView = $this->getPreparedExposedTemplateView($viewContext); - $exposedView->setTemplatePathAndFilename($templatePathAndFilename); - $grid = $exposedView->getGrid($section, $gridName); - } - if (NULL === $grid) { - $grid = Grid::create(array('name' => $gridName)); - } - return $grid; - } - - /** - * Gets an array with the default view configuration for the provided - * extension key. Maybe overwritten by a sub-service class adding - * additional subfolders used by default. - * (e.g. EXT:fluidpages can provide "Resources/Private/Templates/Page" - * as default templateRootPath) - * - * @param string $extensionKey - * @return array - */ - protected function getDefaultViewConfigurationForExtensionKey($extensionKey) { - $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); - return array( - TemplatePaths::CONFIG_TEMPLATEROOTPATHS => array(0 => 'EXT:' . $extensionKey . '/Resources/Private/Templates/'), - TemplatePaths::CONFIG_PARTIALROOTPATHS => array(0 => 'EXT:' . $extensionKey . '/Resources/Private/Partials/'), - TemplatePaths::CONFIG_LAYOUTROOTPATHS => array(0 => 'EXT:' . $extensionKey . '/Resources/Private/Layouts/'), - ); - } - - /** - * Returns the plugin.tx_extsignature.view array, - * or a default set of paths if that array is not - * defined in TypoScript. - * - * @param string $extensionName - * @return array|NULL - */ - public function getViewConfigurationForExtensionName($extensionName) { - $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); - $defaults = (array) $this->getDefaultViewConfigurationForExtensionKey($extensionName); - $configuration = (array) $this->getTypoScriptByPath('plugin.tx_' . $signature . '.view'); - return RecursiveArrayUtility::mergeRecursiveOverrule($defaults, $configuration); - } - - /** - * Returns the module.tx_extsignature.view array. - * Accepts any input extension name type. - * - * @param string $extensionName - * @return array|NULL - */ - public function getBackendViewConfigurationForExtensionName($extensionName) { - $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); - return $this->getTypoScriptByPath('module.tx_' . $signature . '.view'); - } - - /** - * Returns the plugin.tx_extsignature.settings array. - * Accepts any input extension name type. - * - * @param string $extensionName - * @return array - */ - public function getSettingsForExtensionName($extensionName) { - $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); - return (array) $this->getTypoScriptByPath('plugin.tx_' . $signature . '.settings'); - } - - /** - * Gets the value/array from global TypoScript by - * dotted path expression. - * - * @param string $path - * @return array - */ - public function getTypoScriptByPath($path) { - $typoScript = $this->getAllTypoScript(); - return (array) ObjectAccess::getPropertyPath($typoScript, $path); - } - - /** - * Returns the complete, global TypoScript array - * defined in TYPO3. - * - * @return array - */ - public function getAllTypoScript() { - $pageId = $this->getCurrentPageId(); - if (FALSE === isset(self::$typoScript[$pageId])) { - self::$typoScript[$pageId] = (array) $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); - self::$typoScript[$pageId] = GeneralUtility::removeDotsFromTS(self::$typoScript[$pageId]); - } - return (array) self::$typoScript[$pageId]; - } - - /** - * @return integer - */ - protected function getCurrentPageId() { - if ($this->configurationManager instanceof BackendConfigurationManager) { - return (integer) $this->configurationManager->getCurrentPageId(); - } else { - return (integer) $GLOBALS['TSFE']->id; - } - } - - /** - * ResolveUtility the top-priority ConfigurationPrivider which can provide - * a working FlexForm configuration baed on the given parameters. - * - * @param string $table - * @param string $fieldName - * @param array $row - * @param string $extensionKey - * @return ProviderInterface|NULL - */ - public function resolvePrimaryConfigurationProvider($table, $fieldName, array $row = NULL, $extensionKey = NULL) { - return $this->providerResolver->resolvePrimaryConfigurationProvider($table, $fieldName, $row, $extensionKey); - } - - /** - * Resolves a ConfigurationProvider which can provide a working FlexForm - * configuration based on the given parameters. - * - * @param string $table - * @param string $fieldName - * @param array $row - * @param string $extensionKey - * @return ProviderInterface[] - */ - public function resolveConfigurationProviders($table, $fieldName, array $row = NULL, $extensionKey = NULL) { - return $this->providerResolver->resolveConfigurationProviders($table, $fieldName, $row, $extensionKey); - } - - /** - * @return Resolver - */ - public function getResolver() { - return new Resolver(); - } - - /** - * Parses the flexForm content and converts it to an array - * The resulting array will be multi-dimensional, as a value "bla.blubb" - * results in two levels, and a value "bla.blubb.bla" results in three levels. - * - * Note: multi-language flexForms are not supported yet - * - * @param string $flexFormContent flexForm xml string - * @param Form $form An instance of \FluidTYPO3\Flux\Form. If transformation instructions are contained in this configuration they are applied after conversion to array - * @param string $languagePointer language pointer used in the flexForm - * @param string $valuePointer value pointer used in the flexForm - * @return array the processed array - */ - public function convertFlexFormContentToArray($flexFormContent, Form $form = NULL, $languagePointer = 'lDEF', $valuePointer = 'vDEF') { - if (TRUE === empty($flexFormContent)) { - return array(); - } - $formTranslationDisabled = (NULL !== $form && FALSE === (boolean) $form->getOption(Form::OPTION_TRANSLATION)); - if (TRUE === empty($languagePointer) || TRUE === $formTranslationDisabled) { - $languagePointer = 'lDEF'; - } - if (TRUE === empty($valuePointer) || TRUE === $formTranslationDisabled) { - $valuePointer = 'vDEF'; - } - $settings = $this->objectManager->get('TYPO3\CMS\Extbase\Service\FlexFormService') - ->convertFlexFormContentToArray($flexFormContent, $languagePointer, $valuePointer); - if (NULL !== $form) { - /** @var FormDataTransformer $transformer */ - $transformer = $this->objectManager->get('FluidTYPO3\Flux\Transformation\FormDataTransformer'); - $settings = $transformer->transformAccordingToConfiguration($settings, $form); - } - return $settings; - } - - /** - * @param mixed $instance - * @param boolean $plainText - * @param integer $depth - * @return void - */ - public function debug($instance, $plainText = TRUE, $depth = 2) { - $text = DebuggerUtility::var_dump($instance, NULL, $depth, $plainText, FALSE, TRUE); - GeneralUtility::devLog('Flux variable dump: ' . gettype($instance), 'flux', GeneralUtility::SYSLOG_SEVERITY_INFO, $text); - } - - /** - * @param string $message - * @param integer $severity - * @param string $title - * @return void - */ - public function message($message, $severity = GeneralUtility::SYSLOG_SEVERITY_INFO, $title = 'Flux Debug') { - $hash = $message . $severity; - $disabledDebugMode = (boolean) (1 < $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['debugMode']); - $alreadySent = TRUE === isset($this->sentDebugMessages[$hash]); - $shouldExcludedFriendlySeverities = 2 == $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['debugMode']; - $isExcludedSeverity = (TRUE === $shouldExcludedFriendlySeverities && TRUE === in_array($severity, self::$friendlySeverities)); - if (FALSE === $disabledDebugMode && FALSE === $alreadySent && FALSE === $isExcludedSeverity) { - $this->logMessage($message, $severity); - $this->sentDebugMessages[$hash] = TRUE; - } - } - - /** - * @return void - */ - public function flushCache() { - self::$cache = array(); - } - - /** - * @param string $message - * @param integer $severity - * @return void - * @codeCoverageIgnore - */ - protected function logMessage($message, $severity) { - GeneralUtility::sysLog($message, 'flux', $severity); - } - +class FluxService implements SingletonInterface +{ + + /** + * @var array + */ + protected static $cache = []; + + /** + * @var array + */ + protected static $typoScript = []; + + /** + * @var array + */ + protected static $friendlySeverities = [ + GeneralUtility::SYSLOG_SEVERITY_INFO, + GeneralUtility::SYSLOG_SEVERITY_NOTICE, + ]; + + /** + * @var array + */ + protected $sentDebugMessages = []; + + /** + * @var string + */ + protected $raw; + + /** + * @var array + */ + protected $contentObjectData; + + /** + * @var ConfigurationManagerInterface + */ + protected $configurationManager; + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var ReflectionService + */ + protected $reflectionService; + + /** + * @var ProviderResolver + */ + protected $providerResolver; + + /** + * @param ConfigurationManagerInterface $configurationManager + * @return void + */ + public function injectConfigurationManager(ConfigurationManagerInterface $configurationManager) + { + $this->configurationManager = $configurationManager; + } + + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * @param ReflectionService $reflectionService + * @return void + */ + public function injectReflectionService(ReflectionService $reflectionService) + { + $this->reflectionService = $reflectionService; + } + + /** + * @param ProviderResolver $providerResolver + * @return void + */ + public function injectProviderResolver(ProviderResolver $providerResolver) + { + $this->providerResolver = $providerResolver; + } + + /** + * @param array $objects + * @param string $sortBy + * @param string $sortDirection + * @return array + */ + public function sortObjectsByProperty(array $objects, $sortBy, $sortDirection = 'ASC') + { + $sorted = []; + $sort = []; + foreach ($objects as $index => $object) { + $sortValue = ObjectAccess::getPropertyPath($object, $sortBy); + $sort[$index] = $sortValue; + } + if ('ASC' === strtoupper($sortDirection)) { + asort($sort); + } else { + arsort($sort); + } + $hasStringIndex = false; + foreach ($sort as $index => $value) { + $sorted[$index] = $objects[$index]; + if (true === is_string($index)) { + $hasStringIndex = true; + } + } + if (false === $hasStringIndex) { + // reset out-of-sequence indices if provided indices contain no strings + $sorted = array_values($sorted); + } + return $sorted; + } + + /** + * @param ViewContext $viewContext + * @return ExposedTemplateView + */ + public function getPreparedExposedTemplateView(ViewContext $viewContext) + { + $vendorName = $viewContext->getVendorName(); + $extensionKey = $viewContext->getExtensionKey(); + $qualifiedExtensionName = $viewContext->getExtensionName(); + $controllerName = $viewContext->getControllerName(); + $variables = $viewContext->getVariables(); + if (null === $qualifiedExtensionName || false === ExtensionManagementUtility::isLoaded($extensionKey)) { + // Note here: a default value of the argument would not be adequate; outside callers could still pass NULL. + $qualifiedExtensionName = 'Flux'; + } + $extensionName = ExtensionNamingUtility::getExtensionName($qualifiedExtensionName); + /** @var $context ControllerContext */ + $context = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext'); + $request = $viewContext->getRequest(); + /** @var $response Response */ + $response = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Response'); + /** @var $uriBuilder UriBuilder */ + $uriBuilder = $this->objectManager->get('TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder'); + $uriBuilder->setRequest($request); + $context->setUriBuilder($uriBuilder); + $context->setRequest($request); + $context->setResponse($response); + /** @var $renderingContext RenderingContext */ + $renderingContext = $this->objectManager->get( + FluxPackageFactory::getPackageWithFallback($qualifiedExtensionName) + ->getImplementation(FluxPackage::IMPLEMENTATION_RENDERINGCONTEXT) + ); + $renderingContext->setControllerContext($context); + /** @var $exposedView ExposedTemplateView */ + $exposedView = $this->objectManager->get( + FluxPackageFactory::getPackageWithFallback($qualifiedExtensionName) + ->getImplementation(FluxPackage::IMPLEMENTATION_VIEW) + ); + $exposedView->setRenderingContext($renderingContext); + $exposedView->setControllerContext($context); + $exposedView->assignMultiple($variables); + $exposedView->setTemplatePaths($viewContext->getTemplatePaths()); + $exposedView->setTemplatePathAndFilename($viewContext->getTemplatePathAndFilename()); + return $exposedView; + } + + /** + * @param ViewContext $viewContext + * @param string $formName + * @return Form|NULL + */ + public function getFormFromTemplateFile(ViewContext $viewContext, $formName = 'form') + { + $templatePathAndFilename = $viewContext->getTemplatePathAndFilename(); + if (false === file_exists($templatePathAndFilename)) { + return null; + } + $section = $viewContext->getSectionName(); + $variables = $viewContext->getVariables(); + $extensionName = $viewContext->getExtensionName(); + $variableCheck = json_encode($variables); + $cacheKey = md5($templatePathAndFilename . $formName . $extensionName . $section . $variableCheck); + if (false === isset(self::$cache[$cacheKey])) { + try { + $exposedView = $this->getPreparedExposedTemplateView($viewContext); + self::$cache[$cacheKey] = $exposedView->getForm($section, $formName); + } catch (\RuntimeException $error) { + $this->debug($error); + /** @var Form $form */ + self::$cache[$cacheKey] = $this->objectManager->get( + FluxPackageFactory::getPackageWithFallback($extensionName) + ->getImplementation(FluxPackage::IMPLEMENTATION_FORM) + ); + self::$cache[$cacheKey]->createField('UserFunction', 'error') + ->setFunction('FluidTYPO3\Flux\UserFunction\ErrorReporter->renderField') + ->setArguments([$error]); + } + } + return self::$cache[$cacheKey]; + } + + /** + * Reads a Grid constructed using flux:grid, returning an array of + * defined rows and columns along with any content areas. + * + * Note about specific implementations: + * + * * EXT:fluidpages uses the Grid to render a BackendLayout on TYPO3 6.0 and above + * * EXT:flux uses the Grid to render content areas inside content elements + * registered with Flux + * + * But your custom extension is of course allowed to use the Grid for any + * purpose. You can even read the Grid from - for example - the currently + * selected page template to know exactly how the BackendLayout looks. + * + * @param ViewContext $viewContext + * @param string $gridName + * @return Grid|NULL + */ + public function getGridFromTemplateFile(ViewContext $viewContext, $gridName = 'grid') + { + $templatePathAndFilename = $viewContext->getTemplatePathAndFilename(); + $section = $viewContext->getSectionName(); + $grid = null; + if (true === file_exists($templatePathAndFilename)) { + $exposedView = $this->getPreparedExposedTemplateView($viewContext); + $exposedView->setTemplatePathAndFilename($templatePathAndFilename); + $grid = $exposedView->getGrid($section, $gridName); + } + if (null === $grid) { + $grid = Grid::create(['name' => $gridName]); + } + return $grid; + } + + /** + * Gets an array with the default view configuration for the provided + * extension key. Maybe overwritten by a sub-service class adding + * additional subfolders used by default. + * (e.g. EXT:fluidpages can provide "Resources/Private/Templates/Page" + * as default templateRootPath) + * + * @param string $extensionKey + * @return array + */ + protected function getDefaultViewConfigurationForExtensionKey($extensionKey) + { + $extensionKey = ExtensionNamingUtility::getExtensionKey($extensionKey); + return [ + TemplatePaths::CONFIG_TEMPLATEROOTPATHS => [0 => 'EXT:' . $extensionKey . '/Resources/Private/Templates/'], + TemplatePaths::CONFIG_PARTIALROOTPATHS => [0 => 'EXT:' . $extensionKey . '/Resources/Private/Partials/'], + TemplatePaths::CONFIG_LAYOUTROOTPATHS => [0 => 'EXT:' . $extensionKey . '/Resources/Private/Layouts/'], + ]; + } + + /** + * Returns the plugin.tx_extsignature.view array, + * or a default set of paths if that array is not + * defined in TypoScript. + * + * @param string $extensionName + * @return array|NULL + */ + public function getViewConfigurationForExtensionName($extensionName) + { + $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); + $defaults = (array) $this->getDefaultViewConfigurationForExtensionKey($extensionName); + $configuration = (array) $this->getTypoScriptByPath('plugin.tx_' . $signature . '.view'); + return RecursiveArrayUtility::mergeRecursiveOverrule($defaults, $configuration); + } + + /** + * Returns the module.tx_extsignature.view array. + * Accepts any input extension name type. + * + * @param string $extensionName + * @return array|NULL + */ + public function getBackendViewConfigurationForExtensionName($extensionName) + { + $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); + return $this->getTypoScriptByPath('module.tx_' . $signature . '.view'); + } + + /** + * Returns the plugin.tx_extsignature.settings array. + * Accepts any input extension name type. + * + * @param string $extensionName + * @return array + */ + public function getSettingsForExtensionName($extensionName) + { + $signature = ExtensionNamingUtility::getExtensionSignature($extensionName); + return (array) $this->getTypoScriptByPath('plugin.tx_' . $signature . '.settings'); + } + + /** + * Gets the value/array from global TypoScript by + * dotted path expression. + * + * @param string $path + * @return array + */ + public function getTypoScriptByPath($path) + { + $typoScript = $this->getAllTypoScript(); + return (array) ObjectAccess::getPropertyPath($typoScript, $path); + } + + /** + * Returns the complete, global TypoScript array + * defined in TYPO3. + * + * @return array + */ + public function getAllTypoScript() + { + $pageId = $this->getCurrentPageId(); + if (false === isset(self::$typoScript[$pageId])) { + self::$typoScript[$pageId] = (array) $this->configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT + ); + self::$typoScript[$pageId] = GeneralUtility::removeDotsFromTS(self::$typoScript[$pageId]); + } + return (array) self::$typoScript[$pageId]; + } + + /** + * @return integer + */ + protected function getCurrentPageId() + { + if ($this->configurationManager instanceof BackendConfigurationManager) { + return (integer) $this->configurationManager->getCurrentPageId(); + } else { + return (integer) $GLOBALS['TSFE']->id; + } + } + + /** + * ResolveUtility the top-priority ConfigurationPrivider which can provide + * a working FlexForm configuration baed on the given parameters. + * + * @param string $table + * @param string $fieldName + * @param array $row + * @param string $extensionKey + * @return ProviderInterface|NULL + */ + public function resolvePrimaryConfigurationProvider($table, $fieldName, array $row = null, $extensionKey = null) + { + return $this->providerResolver->resolvePrimaryConfigurationProvider($table, $fieldName, $row, $extensionKey); + } + + /** + * Resolves a ConfigurationProvider which can provide a working FlexForm + * configuration based on the given parameters. + * + * @param string $table + * @param string $fieldName + * @param array $row + * @param string $extensionKey + * @return ProviderInterface[] + */ + public function resolveConfigurationProviders($table, $fieldName, array $row = null, $extensionKey = null) + { + return $this->providerResolver->resolveConfigurationProviders($table, $fieldName, $row, $extensionKey); + } + + /** + * @return Resolver + */ + public function getResolver() + { + return new Resolver(); + } + + /** + * Parses the flexForm content and converts it to an array + * The resulting array will be multi-dimensional, as a value "bla.blubb" + * results in two levels, and a value "bla.blubb.bla" results in three levels. + * + * Note: multi-language flexForms are not supported yet + * + * @param string $flexFormContent flexForm xml string + * @param Form $form An instance of \FluidTYPO3\Flux\Form. If transformation instructions are contained in this + * configuration they are applied after conversion to array + * @param string $languagePointer language pointer used in the flexForm + * @param string $valuePointer value pointer used in the flexForm + * @return array the processed array + */ + public function convertFlexFormContentToArray( + $flexFormContent, + Form $form = null, + $languagePointer = 'lDEF', + $valuePointer = 'vDEF' + ) { + if (true === empty($flexFormContent)) { + return []; + } + $formTranslationDisabled = (null !== $form && false === (boolean) $form->getOption(Form::OPTION_TRANSLATION)); + if (true === empty($languagePointer) || true === $formTranslationDisabled) { + $languagePointer = 'lDEF'; + } + if (true === empty($valuePointer) || true === $formTranslationDisabled) { + $valuePointer = 'vDEF'; + } + $settings = $this->objectManager->get('TYPO3\CMS\Extbase\Service\FlexFormService') + ->convertFlexFormContentToArray($flexFormContent, $languagePointer, $valuePointer); + if (null !== $form) { + /** @var FormDataTransformer $transformer */ + $transformer = $this->objectManager->get('FluidTYPO3\Flux\Transformation\FormDataTransformer'); + $settings = $transformer->transformAccordingToConfiguration($settings, $form); + } + return $settings; + } + + /** + * @param mixed $instance + * @param boolean $plainText + * @param integer $depth + * @return void + */ + public function debug($instance, $plainText = true, $depth = 2) + { + $text = DebuggerUtility::var_dump($instance, null, $depth, $plainText, false, true); + GeneralUtility::devLog( + 'Flux variable dump: ' . gettype($instance), + 'flux', + GeneralUtility::SYSLOG_SEVERITY_INFO, + $text + ); + } + + /** + * @param string $message + * @param integer $severity + * @param string $title + * @return void + */ + public function message($message, $severity = GeneralUtility::SYSLOG_SEVERITY_INFO, $title = 'Flux Debug') + { + $hash = $message . $severity; + $disabledDebugMode = (boolean) (1 < $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['debugMode']); + $alreadySent = isset($this->sentDebugMessages[$hash]); + $shouldExcludedFriendlySeverities = 2 == $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['flux']['setup']['debugMode']; + $isExcludedSeverity = ($shouldExcludedFriendlySeverities && in_array($severity, self::$friendlySeverities)); + if (!$disabledDebugMode && !$alreadySent && !$isExcludedSeverity) { + $this->logMessage($message, $severity); + $this->sentDebugMessages[$hash] = true; + } + } + + /** + * @return void + */ + public function flushCache() + { + self::$cache = []; + } + + /** + * @param string $message + * @param integer $severity + * @return void + * @codeCoverageIgnore + */ + protected function logMessage($message, $severity) + { + GeneralUtility::sysLog($message, 'flux', $severity); + } } diff --git a/Classes/Service/RecordService.php b/Classes/Service/RecordService.php index d527371c4..d9de40ce6 100644 --- a/Classes/Service/RecordService.php +++ b/Classes/Service/RecordService.php @@ -15,77 +15,83 @@ * Service to wrap around record operations normally going through * the $TYPO3_DB global variable. */ -class RecordService implements SingletonInterface { +class RecordService implements SingletonInterface +{ - /** - * @param string $table - * @param string $fields - * @param string $clause - * @param string $groupBy - * @param string $orderBy - * @param string $limit - * @return array|NULL - */ - public function get($table, $fields, $clause = '1=1', $groupBy = '', $orderBy = '', $limit = '') { - $connection = $this->getDatabaseConnection(); - return $connection->exec_SELECTgetRows($fields, $table, $clause, $groupBy, $orderBy, $limit); - } + /** + * @param string $table + * @param string $fields + * @param string $clause + * @param string $groupBy + * @param string $orderBy + * @param string $limit + * @return array|NULL + */ + public function get($table, $fields, $clause = '1=1', $groupBy = '', $orderBy = '', $limit = '') + { + $connection = $this->getDatabaseConnection(); + return $connection->exec_SELECTgetRows($fields, $table, $clause, $groupBy, $orderBy, $limit); + } - /** - * @param string $table - * @param string $fields - * @param string $uid - * @return array|NULL - */ - public function getSingle($table, $fields, $uid) { - $connection = $this->getDatabaseConnection(); - $record = $connection->exec_SELECTgetSingleRow($fields, $table, "uid = '" . intval($uid) . "'"); - return FALSE !== $record ? $record : NULL; - } + /** + * @param string $table + * @param string $fields + * @param string $uid + * @return array|NULL + */ + public function getSingle($table, $fields, $uid) + { + $connection = $this->getDatabaseConnection(); + $record = $connection->exec_SELECTgetSingleRow($fields, $table, "uid = '" . intval($uid) . "'"); + return false !== $record ? $record : null; + } - /** - * @param string $table - * @param array $record - * @return boolean - */ - public function update($table, array $record) { - $connection = $this->getDatabaseConnection(); - return $connection->exec_UPDATEquery($table, "uid = '" . intval($record['uid']) . "'", $record); - } + /** + * @param string $table + * @param array $record + * @return boolean + */ + public function update($table, array $record) + { + $connection = $this->getDatabaseConnection(); + return $connection->exec_UPDATEquery($table, "uid = '" . intval($record['uid']) . "'", $record); + } - /** - * @param string $table - * @param mixed $recordOrUid - * @return boolean - */ - public function delete($table, $recordOrUid) { - $connection = $this->getDatabaseConnection(); - $clauseUid = TRUE === is_array($recordOrUid) ? $recordOrUid['uid'] : $recordOrUid; - $clause = "uid = '" . intval($clauseUid) . "'"; - return $connection->exec_DELETEquery($table, $clause); - } + /** + * @param string $table + * @param mixed $recordOrUid + * @return boolean + */ + public function delete($table, $recordOrUid) + { + $connection = $this->getDatabaseConnection(); + $clauseUid = true === is_array($recordOrUid) ? $recordOrUid['uid'] : $recordOrUid; + $clause = "uid = '" . intval($clauseUid) . "'"; + return $connection->exec_DELETEquery($table, $clause); + } - /** - * @param string $table - * @param string $fields - * @param string $condition - * @param array $values - * @return array - */ - public function preparedGet($table, $fields, $condition, $values = array()) { - $connection = $this->getDatabaseConnection(); - $query = $connection->prepare_SELECTquery($fields, $table, $condition); - $query->execute($values); - $result = $query->fetchAll(); - $query->free(); - return $result; - } - - /** - * @return DatabaseConnection - */ - protected function getDatabaseConnection() { - return $GLOBALS['TYPO3_DB']; - } + /** + * @param string $table + * @param string $fields + * @param string $condition + * @param array $values + * @return array + */ + public function preparedGet($table, $fields, $condition, $values = []) + { + $connection = $this->getDatabaseConnection(); + $query = $connection->prepare_SELECTquery($fields, $table, $condition); + $query->execute($values); + $result = $query->fetchAll(); + $query->free(); + return $result; + } + /** + * @return DatabaseConnection + */ + protected function getDatabaseConnection() + { + return $GLOBALS['TYPO3_DB']; + } } diff --git a/Classes/Service/WorkspacesAwareRecordService.php b/Classes/Service/WorkspacesAwareRecordService.php index 5ea6fbc42..a11fbbc29 100644 --- a/Classes/Service/WorkspacesAwareRecordService.php +++ b/Classes/Service/WorkspacesAwareRecordService.php @@ -15,90 +15,97 @@ * Service to wrap around record operations normally going through * the $TYPO3_DB global variable. */ -class WorkspacesAwareRecordService extends RecordService implements SingletonInterface { +class WorkspacesAwareRecordService extends RecordService implements SingletonInterface +{ - /** - * @param string $table - * @param string $fields - * @param string $clause - * @param string $groupBy - * @param string $orderBy - * @param string $limit - * @return array|NULL - */ - public function get($table, $fields, $clause = '1=1', $groupBy = '', $orderBy = '', $limit = '') { - $records = parent::get($table, $fields, $clause, $groupBy, $orderBy, $limit); - return NULL === $records ? NULL : $this->overlayRecords($table, $records); - } + /** + * @param string $table + * @param string $fields + * @param string $clause + * @param string $groupBy + * @param string $orderBy + * @param string $limit + * @return array|NULL + */ + public function get($table, $fields, $clause = '1=1', $groupBy = '', $orderBy = '', $limit = '') + { + $records = parent::get($table, $fields, $clause, $groupBy, $orderBy, $limit); + return null === $records ? null : $this->overlayRecords($table, $records); + } - /** - * @param string $table - * @param string $fields - * @param string $uid - * @return array|NULL - */ - public function getSingle($table, $fields, $uid) { - $record = parent::getSingle($table, $fields, $uid); - return NULL === $record ? NULL : $this->overlayRecord($table, $record); - } + /** + * @param string $table + * @param string $fields + * @param string $uid + * @return array|NULL + */ + public function getSingle($table, $fields, $uid) + { + $record = parent::getSingle($table, $fields, $uid); + return null === $record ? null : $this->overlayRecord($table, $record); + } - /** - * @param string $table - * @param string $fields - * @param string $condition - * @param array $values - * @return array - */ - public function preparedGet($table, $fields, $condition, $values = array()) { - $records = parent::preparedGet($table, $fields, $condition, $values); - return $this->overlayRecords($table, $records); - } + /** + * @param string $table + * @param string $fields + * @param string $condition + * @param array $values + * @return array + */ + public function preparedGet($table, $fields, $condition, $values = []) + { + $records = parent::preparedGet($table, $fields, $condition, $values); + return $this->overlayRecords($table, $records); + } - /** - * @param string $table - * @param array $records - * @return array - */ - protected function overlayRecords($table, array $records) { - if (FALSE === $this->hasWorkspacesSupport($table)) { - return $records; - } - foreach ($records as $index => $record) { - $records[$index] = $this->overlayRecord($table, $record); - } - return $records; - } + /** + * @param string $table + * @param array $records + * @return array + */ + protected function overlayRecords($table, array $records) + { + if (false === $this->hasWorkspacesSupport($table)) { + return $records; + } + foreach ($records as $index => $record) { + $records[$index] = $this->overlayRecord($table, $record); + } + return $records; + } - /** - * @param string $table - * @param array $record - * @return array - */ - protected function overlayRecord($table, array $record) { - $enabled = $this->hasWorkspacesSupport($table); - return (TRUE === $enabled) ? $this->getWorkspaceVersionOfRecordOrRecordItself($table, $record) : $record; - } + /** + * @param string $table + * @param array $record + * @return array + */ + protected function overlayRecord($table, array $record) + { + $enabled = $this->hasWorkspacesSupport($table); + return (true === $enabled) ? $this->getWorkspaceVersionOfRecordOrRecordItself($table, $record) : $record; + } - /** - * @param string $table - * @param array $record - * @return array|boolean - */ - protected function getWorkspaceVersionOfRecordOrRecordItself($table, $record) { - $copy = FALSE; - if (NULL !== $GLOBALS['BE_USER']) { - $copy = $record; - BackendUtility::workspaceOL($table, $copy); - } - return $copy === FALSE ? $record : $copy; - } - - /** - * @param string $table - * @return boolean - */ - protected function hasWorkspacesSupport($table) { - return (NULL !== $GLOBALS['BE_USER'] && BackendUtility::isTableWorkspaceEnabled($table)); - } + /** + * @param string $table + * @param array $record + * @return array|boolean + */ + protected function getWorkspaceVersionOfRecordOrRecordItself($table, $record) + { + $copy = false; + if (null !== $GLOBALS['BE_USER']) { + $copy = $record; + BackendUtility::workspaceOL($table, $copy); + } + return $copy === false ? $record : $copy; + } + /** + * @param string $table + * @return boolean + */ + protected function hasWorkspacesSupport($table) + { + return (null !== $GLOBALS['BE_USER'] && BackendUtility::isTableWorkspaceEnabled($table)); + } } diff --git a/Classes/Transformation/FormDataTransformer.php b/Classes/Transformation/FormDataTransformer.php index bedf9bd31..c0df74d21 100644 --- a/Classes/Transformation/FormDataTransformer.php +++ b/Classes/Transformation/FormDataTransformer.php @@ -18,129 +18,141 @@ /** * Transforms data according to settings defined in the Form instance. */ -class FormDataTransformer { +class FormDataTransformer +{ - /** - * @var ObjectManagerInterface - */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + protected $objectManager; - /** - * @param ObjectManagerInterface $objectManager - * @return void - */ - public function injectObjectManager(ObjectManagerInterface $objectManager) { - $this->objectManager = $objectManager; - } + /** + * @param ObjectManagerInterface $objectManager + * @return void + */ + public function injectObjectManager(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } - /** - * Transforms members on $values recursively according to the provided - * Flux configuration extracted from a Flux template. Uses "transform" - * attributes on fields to determine how to transform values. - * - * @param array $values - * @param Form $form - * @param string $prefix - * @return array - */ - public function transformAccordingToConfiguration($values, Form $form, $prefix = '') { - foreach ((array) $values as $index => $value) { - if (TRUE === is_array($value)) { - $value = $this->transformAccordingToConfiguration($value, $form, $prefix . $index . '.'); - } else { - /** @var FieldInterface|ContainerInterface $object */ - $object = $form->get($prefix . $index, TRUE); - if (FALSE !== $object) { - $transformType = $object->getTransform(); - $value = $this->transformValueToType($value, $transformType); - } - } - $values[$index] = $value; - } - return $values; - } + /** + * Transforms members on $values recursively according to the provided + * Flux configuration extracted from a Flux template. Uses "transform" + * attributes on fields to determine how to transform values. + * + * @param array $values + * @param Form $form + * @param string $prefix + * @return array + */ + public function transformAccordingToConfiguration($values, Form $form, $prefix = '') + { + foreach ((array) $values as $index => $value) { + if (true === is_array($value)) { + $value = $this->transformAccordingToConfiguration($value, $form, $prefix . $index . '.'); + } else { + /** @var FieldInterface|ContainerInterface $object */ + $object = $form->get($prefix . $index, true); + if (false !== $object) { + $transformType = $object->getTransform(); + $value = $this->transformValueToType($value, $transformType); + } + } + $values[$index] = $value; + } + return $values; + } - /** - * Transforms a single value to $dataType - * - * @param string $value - * @param string $dataType - * @return mixed - */ - protected function transformValueToType($value, $dataType) { - if ('int' === $dataType || 'integer' === $dataType) { - return intval($value); - } elseif ('float' === $dataType) { - return floatval($value); - } elseif ('array' === $dataType) { - return explode(',', $value); - } elseif ('bool' === $dataType || 'boolean' === $dataType) { - return boolval($value); - } else { - return $this->getObjectOfType($dataType, $value); - } - } + /** + * Transforms a single value to $dataType + * + * @param string $value + * @param string $dataType + * @return mixed + */ + protected function transformValueToType($value, $dataType) + { + if ('int' === $dataType || 'integer' === $dataType) { + return intval($value); + } elseif ('float' === $dataType) { + return floatval($value); + } elseif ('array' === $dataType) { + return explode(',', $value); + } elseif ('bool' === $dataType || 'boolean' === $dataType) { + return boolval($value); + } else { + return $this->getObjectOfType($dataType, $value); + } + } - /** - * Gets a DomainObject or QueryResult of $dataType - * - * @param string $dataType - * @param string $uids - * @return mixed - */ - protected function getObjectOfType($dataType, $uids) { - $identifiers = TRUE === is_array($uids) ? $uids : GeneralUtility::trimExplode(',', trim($uids, ','), TRUE); - $identifiers = array_map('intval', $identifiers); - $isModel = $this->isDomainModelClassName($dataType); - list ($container, $object) = FALSE !== strpos($dataType, '<') ? explode('<', trim($dataType, '>')) : array(NULL, $dataType); - $repositoryClassName = $this->resolveRepositoryClassName($object); - // Fast decisions - if (TRUE === $isModel && NULL === $container) { - if (TRUE === class_exists($repositoryClassName)) { - $repository = $this->objectManager->get($repositoryClassName); - return reset($this->loadObjectsFromRepository($repository, $identifiers)); - } - } elseif (TRUE === class_exists($dataType)) { - // using constructor value to support objects like DateTime - return $this->objectManager->get($dataType, $uids); - } - // slower decisions with support for type-hinted collection objects - if ($container && $object) { - if (TRUE === $isModel && TRUE === class_exists($repositoryClassName) && 0 < count($identifiers)) { - /** @var $repository RepositoryInterface */ - $repository = $this->objectManager->get($repositoryClassName); - return $this->loadObjectsFromRepository($repository, $identifiers); - } else { - $container = $this->objectManager->get($container); - return $container; - } - } - return $uids; - } + /** + * Gets a DomainObject or QueryResult of $dataType + * + * @param string $dataType + * @param string $uids + * @return mixed + */ + protected function getObjectOfType($dataType, $uids) + { + $identifiers = true === is_array($uids) ? $uids : GeneralUtility::trimExplode(',', trim($uids, ','), true); + $identifiers = array_map('intval', $identifiers); + $isModel = $this->isDomainModelClassName($dataType); + if (false !== strpos($dataType, '<')) { + list ($container, $object) = explode('<', trim($dataType, '>')); + } else { + $container = null; + $object = $dataType; + } + $repositoryClassName = $this->resolveRepositoryClassName($object); + // Fast decisions + if (true === $isModel && null === $container) { + if (true === class_exists($repositoryClassName)) { + $repository = $this->objectManager->get($repositoryClassName); + return reset($this->loadObjectsFromRepository($repository, $identifiers)); + } + } elseif (true === class_exists($dataType)) { + // using constructor value to support objects like DateTime + return $this->objectManager->get($dataType, $uids); + } + // slower decisions with support for type-hinted collection objects + if ($container && $object) { + if (true === $isModel && true === class_exists($repositoryClassName) && 0 < count($identifiers)) { + /** @var $repository RepositoryInterface */ + $repository = $this->objectManager->get($repositoryClassName); + return $this->loadObjectsFromRepository($repository, $identifiers); + } else { + $container = $this->objectManager->get($container); + return $container; + } + } + return $uids; + } - /** - * @param string $object - * @return string - */ - protected function resolveRepositoryClassName($object) { - return str_replace('\\Domain\\Model\\', '\\Domain\\Repository\\', $object) . 'Repository'; - } + /** + * @param string $object + * @return string + */ + protected function resolveRepositoryClassName($object) + { + return str_replace('\\Domain\\Model\\', '\\Domain\\Repository\\', $object) . 'Repository'; + } - /** - * @param string $dataType - * @return boolean - */ - protected function isDomainModelClassName($dataType) { - return (FALSE !== strpos($dataType, '\\Domain\\Model\\')); - } - - /** - * @param RepositoryInterface $repository - * @param array $identifiers - * @return mixed - */ - protected function loadObjectsFromRepository(RepositoryInterface $repository, array $identifiers) { - return array_map(array($repository, 'findByUid'), $identifiers); - } + /** + * @param string $dataType + * @return boolean + */ + protected function isDomainModelClassName($dataType) + { + return (false !== strpos($dataType, '\\Domain\\Model\\')); + } + /** + * @param RepositoryInterface $repository + * @param array $identifiers + * @return mixed + */ + protected function loadObjectsFromRepository(RepositoryInterface $repository, array $identifiers) + { + return array_map([$repository, 'findByUid'], $identifiers); + } } diff --git a/Classes/UserFunction/ClearValueWizard.php b/Classes/UserFunction/ClearValueWizard.php index 7de0547a5..a1b1acf47 100644 --- a/Classes/UserFunction/ClearValueWizard.php +++ b/Classes/UserFunction/ClearValueWizard.php @@ -13,20 +13,22 @@ /** * Renders a checkbox which, when checked, clears a flexform field value. */ -class ClearValueWizard { +class ClearValueWizard +{ - /** - * @param array $parameters - * @param object $pObj Not used - * @return string - */ - public function renderField(&$parameters, &$pObj) { - unset($pObj); - $nameSegments = explode('][', $parameters['itemName']); - $nameSegments[6] .= '_clear'; - $fieldName = implode('][', $nameSegments); - $html = '