phpshopwareshopware6

Add association from ProductDefinition


I have a basic customAttributes entity with two fields: attributeName and attributeValue. The goal is to retrieve the customAttributes linked to a product whenever I retrieve the products in Shopware.

CustomAttributesDefinition.php

<?php

declare(strict_types=1);

namespace Meteor\OnboardingNielPlugin\Core\Content\CustomAttributes;

use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required;
use Shopware\Core\Framework\DataAbstractionLayer\Field\IdField;
use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToOneAssociationField;
use Shopware\Core\Framework\DataAbstractionLayer\Field\StringField;
use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('shopware.entity.definition', ['entity' => 'custom_attributes'])]
class CustomAttributesDefinition extends EntityDefinition
{
    public const ENTITY_NAME = 'custom_attributes';

    public function getEntityName(): string
    {
        return self::ENTITY_NAME;
    }

    public function getCollectionClass(): string
    {
        return CustomAttributesCollection::class;
    }

    public function getEntityClass(): string
    {
        return CustomAttributesEntity::class;
    }

    protected function defineFields(): FieldCollection
    {
        return new FieldCollection([
            (new IdField('id', 'id'))->addFlags(new Required(), new PrimaryKey()),
            new StringField('attribute_name', 'attributeName'),
            new StringField('attribute_value', 'attributeValue'),

            (new FkField('product_id', 'productId', ProductDefinition::class))->addFlags(new Required()),
            new ManyToOneAssociationField('customAttributes2', 'product_id', ProductDefinition::class, 'id', false),
        ]);
    }
}

As you can see this definition has a association to product called customAttributes2. The expected behavior is that the customAttributes-entities are retrieved when fetching products by adding an association:

    public function onProductExportProductCriteria(ProductExportProductCriteriaEvent $event): void
    {
        $event->getCriteria()->addAssociation('customAttributes2');
    }

This does not work.

The only way I can get this to work is by adding an association-field to the ProductDefinition in the core:

 (new OneToManyAssociationField('customAttributes', CustomAttributesDefinition::class, 'product_id'))->addFlags(new CascadeDelete()),

Doing

    public function onProductExportProductCriteria(ProductExportProductCriteriaEvent $event): void
    {
        $event->getCriteria()->addAssociation('customAttributes');
    }

Does retrieve the customAttributes now. But editing the core is bad practice so I need another way. Actually Shopware should have a way to extend the fields of entities in the core without actually editing the core itself? Otherwise it is impossible to set a FK or reference to a custom table/entity.


Solution

  • For this, Shopware wants you to define an Entity Extension. See: https://developer.shopware.com/docs/guides/plugins/plugins/framework/data-handling/add-complex-data-to-existing-entities.html#creating-the-extension

    Basically you define a service that does exactly the same as your core edit:

    In services.xml or similar:

    <services>
        <service id="Meteor\OnboardingNielPlugin\Extension\Content\Product\CustomExtension">
            <tag name="shopware.entity.extension"/>
        </service>
    </services>
    

    In PHP:

    <?php declare(strict_types=1);
    
    namespace Meteor\OnboardingNielPlugin\Extension\Content\Product;
    
    use Shopware\Core\Content\Product\ProductDefinition;
    use Shopware\Core\Framework\DataAbstractionLayer\EntityExtension;
    use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;
    use Shopware\Core\Framework\DataAbstractionLayer\Field\OneToManyAssociationField;
    use Meteor\OnboardingNielPlugin\Core\Content\CustomAttributes\CustomAttributesDefinition;
    
    class CustomExtension extends EntityExtension
    {
        public function extendFields(FieldCollection $collection): void
        {
            $collection->add(
                new OneToManyAssociationField('customAttributes', CustomAttributesDefinition::class, 'product_id'))
            );
        }
    
        public function getDefinitionClass(): string
        {
            return ProductDefinition::class;
        }
    }
    

    With this you can add your association to a criteria.