Skip to content

Commit

Permalink
[!!!][FEATURE] Parent/child relationships with data inheritance by pr…
Browse files Browse the repository at this point in the history
…oduct type (#247)

* [WIP] Testing concepts

* [WIP] Testing concepts

* [TASK] Switch from sub product to parent/child

* [FEATURE] Increased speed for relations display in BE

Moved from using select (where all potential records were loaded in the form) to group (where you have to search to add a relation).

* [TASK] Implement parent/child getters and setters

* [TASK] Select inherited fields in ProductType

* [TASK] Remove showRecordFieldList from TCA

The interface->showRecordFieldList property is no longer used.

* [TASK] Set inherited fields to readOnly=true

* [TASK] Insert field parent data and inheritance info

* [FEATURE] Field data is inherited when saving a record

* [CLEANUP] Code style fixes

* [CLEANUP] Code style fixes

* [CLEANUP] Code style fixes

* [TASK] Rename AttributesValuesUpdate to UpdateAttributeValuesProcessDatamap

* [TASK] Refactored Hooks directory

* [TASK] Implemented attribute inheritance

* [TASK] ParentValueFieldWizard supports inherited attributes

* [TASK] Relation inheritance also for inline relations

* [CLEANUP] CS fixes

* [CLEANUP] CS fixes

* [WIP] Testing concepts

* [WIP] Testing concepts

* [TASK] Switch from sub product to parent/child

* [FEATURE] Increased speed for relations display in BE

Moved from using select (where all potential records were loaded in the form) to group (where you have to search to add a relation).

* [TASK] Implement parent/child getters and setters

* [TASK] Select inherited fields in ProductType

* [TASK] Remove showRecordFieldList from TCA

The interface->showRecordFieldList property is no longer used.

* [TASK] Set inherited fields to readOnly=true

* [TASK] Insert field parent data and inheritance info

* [FEATURE] Field data is inherited when saving a record

* [CLEANUP] Code style fixes

* [CLEANUP] Code style fixes

* [CLEANUP] Code style fixes

* [TASK] Rename AttributesValuesUpdate to UpdateAttributeValuesProcessDatamap

* [TASK] Refactored Hooks directory

* [TASK] Implemented attribute inheritance

* [TASK] ParentValueFieldWizard supports inherited attributes

* [TASK] Relation inheritance also for inline relations

* [CLEANUP] CS fixes

* [CLEANUP] CS fixes

* [BUGFIX] Correct spelling in label

* [TASK] Move from simulated attribute fields to real ones

* [TASK] Attribute fields look like other fields.

* [TASK] Move adding of CSS into method

* [TASK] Add attribute value's type as hidden field

Only on new, non-persisted fields

* [TASK] Skip duplicate attributes
Only on new, non-persisted fields

* [TASK] Revert previous commit

* [TASK] Reduced cyclomatic complexity

* [TASK] Fixed missing attributeId on image/fal attribute values

* [WIP] Fixing attribute inheritance

* [TASK] Working file relations in inline grandchild

* [CLEANUP] Remove unused code and comments

* [CLEANUP] CS fixes

* [TASK] Bring back AttributeIdentifierControl

Accidentally deleted.

* [BUGFIX] Childrens' children were not properly deleted

* [TASK] Show inheritance info on attribute fields

* [TASK] Show inheritance info also on inline fields

* [TASK] Show inheritance info also on inherited inline fields.

* [CLEANUP] CS fixes

* [CLEANUP] CS fixes

* [TASK] Remove tests for removed class

* [TASK] Fix ConfigurationProviderFactoryTest

* [TASK] Fix AbstractProviderTest

* [CLEANUP] CS Fixes

* [WIP] update selectboxprovider

* [WIP] fix getChildren, fix null

* [CLEANUP] CS Fixes

* [CLEANUP] Reduced cyclomatic complexity

* [CLEANUP] Disable cyclomatic complexity check for method

* [CLEANUP] Ignore CS issue for both phpcs and php-cs-fixer

* [BUGFIX] map to attribute array type value

Co-authored-by: Mats Svensson <[email protected]>
  • Loading branch information
mabolek and pixelmatseriks authored Feb 11, 2021
1 parent 9e9c831 commit e541d69
Show file tree
Hide file tree
Showing 46 changed files with 2,151 additions and 787 deletions.
18 changes: 9 additions & 9 deletions Classes/Attributes/ConfigurationProvider/AbstractProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
abstract class AbstractProvider implements ProviderInterface
{
/**
* @var Attribute
* @var array Attribute row
*/
protected Attribute $attribute;
protected array $attribute;

/**
* @var array
Expand Down Expand Up @@ -110,9 +110,9 @@ abstract class AbstractProvider implements ProviderInterface
];

/**
* @param Attribute $attribute
* @param array $attribute
*/
public function __construct(Attribute $attribute)
public function __construct(array $attribute)
{
$this->attribute = $attribute;
}
Expand All @@ -136,11 +136,11 @@ public function get(): array
*/
protected function getAttributeConfiguration(): array
{
$configuration = $this->tca[$this->attribute->getType()];
$configuration['label'] = $this->attribute->getName();
$configuration = $this->tca[$this->attribute['type']];
$configuration['label'] = $this->attribute['name'];

if ($this->attribute->getDefaultValue()) {
$configuration['config']['default'] = $this->attribute->getDefaultValue();
if ($this->attribute['default_value']) {
$configuration['config']['default'] = $this->attribute['default_value'];
}

return $configuration;
Expand All @@ -153,7 +153,7 @@ protected function getAttributeConfiguration(): array
*/
protected function isRequired(): bool
{
return $this->attribute->isRequired();
return (bool)$this->attribute['required'];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,56 @@
namespace Pixelant\PxaProductManager\Attributes\ConfigurationProvider;

use Pixelant\PxaProductManager\Domain\Model\Attribute;
use Pixelant\PxaProductManager\Domain\Repository\AttributeRepository;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Class AttributeConfigurationProviderFactory.
*/
class ConfigurationProviderFactory
{
/**
* Conversion table from attribute type to configuration provider class name.
*/
protected const TYPE_TO_PROVIDER = [
Attribute::ATTRIBUTE_TYPE_INPUT => InputProvider::class,
Attribute::ATTRIBUTE_TYPE_TEXT => TextAreaProvider::class,
Attribute::ATTRIBUTE_TYPE_MULTISELECT => SelectBoxProvider::class,
Attribute::ATTRIBUTE_TYPE_DROPDOWN => SelectBoxProvider::class,
Attribute::ATTRIBUTE_TYPE_CHECKBOX => CheckboxProvider::class,
Attribute::ATTRIBUTE_TYPE_LINK => LinkProvider::class,
Attribute::ATTRIBUTE_TYPE_FILE => FalProvider::class,
Attribute::ATTRIBUTE_TYPE_IMAGE => FalProvider::class,
Attribute::ATTRIBUTE_TYPE_DATETIME => DateTimeProvider::class,
Attribute::ATTRIBUTE_TYPE_LABEL => LabelProvider::class,
];

/**
* Factory method.
*
* @param Attribute $attribute
* @return ProviderInterface
* @throws \UnexpectedValueException
*/
public static function create(Attribute $attribute): ProviderInterface
public static function create(int $attributeId, array $attribute = null): ProviderInterface
{
switch (true) {
case $attribute->isInputType():
return GeneralUtility::makeInstance(InputProvider::class, $attribute);
case $attribute->isTextArea():
return GeneralUtility::makeInstance(TextAreaProvider::class, $attribute);
case $attribute->isSelectBoxType():
return GeneralUtility::makeInstance(SelectBoxProvider::class, $attribute);
case $attribute->isCheckboxType():
return GeneralUtility::makeInstance(CheckboxProvider::class, $attribute);
case $attribute->isLinkType():
return GeneralUtility::makeInstance(LinkProvider::class, $attribute);
case $attribute->isFalType():
return GeneralUtility::makeInstance(FalProvider::class, $attribute);
case $attribute->isDateType():
return GeneralUtility::makeInstance(DateTimeProvider::class, $attribute);
case $attribute->isLabelType():
return GeneralUtility::makeInstance(LabelProvider::class, $attribute);
if ($attribute === null) {
$attribute = BackendUtility::getRecord(
AttributeRepository::TABLE_NAME,
$attributeId
);
}

$className = self::TYPE_TO_PROVIDER[$attribute['type']];

if ($className === null) {
throw new \UnexpectedValueException(
'Attribute with type "' . $attribute['type'] . '" not supported.',
1568986135545
);
}

throw new \UnexpectedValueException(
'Attribute with type "' . $attribute->getType() . '" not supported.',
1568986135545
);
return GeneralUtility::makeInstance($className, $attribute);
}
}
28 changes: 12 additions & 16 deletions Classes/Attributes/ConfigurationProvider/FalProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Pixelant\PxaProductManager\Attributes\ConfigurationProvider;

use Pixelant\PxaProductManager\Domain\Model\Attribute;
use Pixelant\PxaProductManager\Utility\AttributeTcaNamingUtility;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

/**
Expand All @@ -14,14 +13,14 @@
class FalProvider implements ProviderInterface
{
/**
* @var Attribute
* @var array
*/
protected Attribute $attribute;
protected array $attribute;

/**
* @param Attribute $attribute
* @param array $attribute
*/
public function __construct(Attribute $attribute)
public function __construct(array $attribute)
{
$this->attribute = $attribute;
}
Expand All @@ -33,7 +32,7 @@ public function __construct(Attribute $attribute)
*/
public function get(): array
{
if ($this->attribute->getType() === Attribute::ATTRIBUTE_TYPE_IMAGE) {
if ($this->attribute['type'] === Attribute::ATTRIBUTE_TYPE_IMAGE) {
$allowedFileTypes = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
$label = 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference';
} else {
Expand All @@ -46,7 +45,7 @@ public function get(): array
$allowedFileTypes
);

$configuration['label'] = $this->attribute->getName();
$configuration['label'] = $this->attribute['name'];

return $configuration;
}
Expand All @@ -64,14 +63,12 @@ protected function getFalFieldTCAConfiguration(
string $allowedFileExtensions = '',
string $disallowedFileExtensions = ''
): array {
$fieldName = AttributeTcaNamingUtility::translateToTcaFieldName($this->attribute);

return [
'exclude' => false,
'label' => '',
// @codingStandardsIgnoreStart
'config' => ExtensionManagementUtility::getFileFieldTCAConfig(
$fieldName,
'value',
[
'appearance' => [
'createNewRelationLinkTitle' => $addNewLabel,
Expand All @@ -82,22 +79,21 @@ protected function getFalFieldTCAConfiguration(
'collapseAll' => true,
],
'foreign_match_fields' => [
'fieldname' => AttributeTcaNamingUtility::FAL_DB_FIELD,
'tablenames' => 'tx_pxaproductmanager_domain_model_product',
'fieldname' => 'value',
'tablenames' => 'tx_pxaproductmanager_domain_model_attributevalue',
'table_local' => 'sys_file',
'pxa_attribute' => $this->attribute->getUid(),
],
'behaviour' => [
'allowLanguageSynchronization' => true,
],
'overrideChildTca' => [
'columns' => [
/*'columns' => [
'pxa_attribute' => [
'config' => [
'default' => $this->attribute->getUid(),
'default' => $this->attribute,
],
],
],
],*/
'types' => [
\TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [
'showitem' => '
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Pixelant\PxaProductManager\Attributes\ConfigurationProvider;

use Pixelant\PxaProductManager\Domain\Model\Option;
use Pixelant\PxaProductManager\Utility\AttributeUtility;

/**
* Selectbox TCA.
Expand All @@ -21,9 +21,10 @@ protected function overrideWithSpecificTca(array $tca): array
}

$options = [];
/** @var Option $option */
foreach ($this->attribute->getOptions() as $option) {
$options[] = [$option->getValue(), $option->getUid()];

$attributeOptions = AttributeUtility::findAttributeOptions($this->attribute['uid'], 'uid, value');
foreach ($attributeOptions as $option) {
$options[] = [$option['value'], $option['uid']];
}

if (empty($options)) {
Expand Down
125 changes: 125 additions & 0 deletions Classes/Backend/FormDataProvider/AttributeValueFormDataProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

declare(strict_types=1);

namespace Pixelant\PxaProductManager\Backend\FormDataProvider;

use Pixelant\PxaProductManager\Domain\Collection\CanCreateCollection;
use Pixelant\PxaProductManager\Domain\Repository\AttributeValueRepository;
use Pixelant\PxaProductManager\Domain\Repository\ProductRepository;
use Pixelant\PxaProductManager\FlashMessage\BackendFlashMessage;
use Pixelant\PxaProductManager\Translate\CanTranslateInBackend;
use Pixelant\PxaProductManager\Utility\DataInheritanceUtility;
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;

/**
* Form data provider hook, add TCA on a fly.
*/
class AttributeValueFormDataProvider implements FormDataProviderInterface
{
use CanTranslateInBackend;
use CanCreateCollection;

/**
* @var DataMapper
*/
protected DataMapper $dataMapper;

/**
* @var BackendFlashMessage
*/
protected BackendFlashMessage $flashMessage;

/**
* @param BackendFlashMessage $flashMessage
*/
public function __construct(BackendFlashMessage $flashMessage = null)
{
$this->flashMessage = $flashMessage ?? GeneralUtility::makeInstance(BackendFlashMessage::class);
}

/**
* @param array $result
* @return array
*/
public function addData(array $result): array
{
if ($result['tableName'] !== AttributeValueRepository::TABLE_NAME) {
return $result;
}

$this->addCss();

$result = $this->handleInheritedFields($result);

return $result;
}

/**
* Disable inherited fields.
*
* @param array $result
* @return array
*/
protected function handleInheritedFields(array $result)
{
$attributeValue = $result['databaseRow'];

$product = BackendUtility::getRecord(
ProductRepository::TABLE_NAME,
$attributeValue['product']
);

if (!$product['product_type'] || !$product['parent']) {
return $result;
}

$configuration = &$result['processedTca']['columns']['value'];

if (
in_array(
'attribute.' . $attributeValue['attribute'][0],
DataInheritanceUtility::getInheritedFieldsForProductType((int)$product['product_type']),
true
)
) {
$configuration['config']['readOnly'] = true;

if ($configuration['config']['type'] === 'inline') {
// @codingStandardsIgnoreLine
$result['processedTca']['ctrl']['container']['inline']['fieldInformation']['inheritedProductField']['renderType']
= 'inheritedProductField';
} else {
$configuration['config']['fieldInformation']['inheritedProductField']['renderType']
= 'inheritedProductField';
}
} else {
if ($configuration['config']['type'] === 'inline') {
// @codingStandardsIgnoreLine
$result['processedTca']['ctrl']['container']['inline']['fieldWizard']['productParentValue']['renderType']
= 'productParentValue';
} else {
$configuration['config']['fieldWizard']['productParentValue']['renderType']
= 'productParentValue';
}
}

return $result;
}

/**
* Add CSS to the page renderer. Ensures attributes are styles like other fields.
*/
protected function addCss(): void
{
/** @var PageRenderer $pageRenderer */
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
$pageRenderer->addCssFile(
'EXT:pxa_product_manager/Resources/Public/Css/Backend/formEngine.css'
);
}
}
Loading

0 comments on commit e541d69

Please sign in to comment.