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 customAttribute
s 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.
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.