How to Use a Custom Entity as an Attribute Type¶
Note
The code inside this cookbook entry is visible in src directory, you can clone pim-dev then do a symlink and install
Overriding the Product Value to Link it to the Custom Entity¶
We now have a custom attribute type that will allow to select instance of our entity, but we still need to provide a way to link the product to the entity we have on the Doctrine side (via its product value).
For this, we need to provide a replacement to the native Akeneo ProductValue. Unfortunately, annotations of a parent class are not transmitted to the child class, so we cannot just extend the native ProductValue and add the missing part. We need to copy and paste the whole class, and add the following lines:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # /src/Acme/Bundle/IcecatDemoBundle/Entity/ProductValue.php
<?php
namespace Acme\Bundle\IcecatDemoBundle\Entity;
/**
* @ExclusionPolicy("all")
*/
class ProductValue extends AbstractEntityFlexibleValue implements ProductValueInterface
{
protected $vendor;
public function getVendor()
{
return $this->vendor;
}
public function setVendor(Vendor $vendor)
{
$this->vendor = $vendor;
return $this;
}
}
|
You will also need to copy and adapt the mapping for the entity:
1 2 3 4 5 6 7 8 9 10 11 12 | # /src/Acme/Bundle/IcecatDemoBundle/Resources/config/doctrine/ProductValue.orm.yml
Acme\Bundle\IcecatDemoBundle\Entity\ProductValue:
type: entity
table: pim_icecat_product_value
manyToOne:
vendor:
targetEntity: Acme\Bundle\IcecatDemoBundle\Entity\Vendor
joinColumns:
vendor_id:
referencedColumnName: id
onDelete: CASCADE
nullable: true
|
Note
We are thinking about ways to avoid the copy paste of the full product value class, but we do not have a good working solution yet.
Registering the New Product Value Class¶
Configure the parameter for the ProductValue class :
1 2 3 4 | # /src/Acme/Bundle/IcecatDemoBundle/Resources/config/entities.yml
parameters:
pim_catalog.entity.product_value.class: Acme\Bundle\IcecatDemoBundle\Entity\ProductValue
pim_catalog.entity.vendor.class: Acme\Bundle\IcecatDemoBundle\Entity\Vendor
|
After a Doctrine schema update, you should be able to create a new attribute using this new attribute type, and link your manufacturer to your product.
Creating the Attribute Type¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # /src/Acme/Bundle/IcecatDemoBundle/AttributeType/VendorType.php
<?php
namespace Acme\Bundle\IcecatDemoBundle\AttributeType;
use Pim\Bundle\FlexibleEntityBundle\Model\AbstractAttribute;
use Pim\Bundle\FlexibleEntityBundle\AttributeType\AbstractAttributeType;
use Pim\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface;
class VendorType extends AbstractAttributeType
{
protected function prepareValueFormOptions(FlexibleValueInterface $value)
{
$options = parent::prepareValueFormOptions($value);
$options['class'] = 'Acme\Bundle\IcecatDemoBundle\Entity\Vendor';
return $options;
}
protected function defineCustomAttributeProperties(AbstractAttribute $attribute)
{
return array(
array(
'name' => 'localizable',
'fieldType' => 'switch',
'options' => array(
'disabled' => (bool) $attribute->getId(),
'read_only' => (bool) $attribute->getId()
)
),
array(
'name' => 'availableLocales',
'fieldType' => 'pim_enrich_available_locales'
),
array(
'name' => 'scopable',
'fieldType' => 'pim_enrich_scopable',
'options' => array(
'disabled' => (bool) $attribute->getId(),
'read_only' => (bool) $attribute->getId()
)
)
);
}
public function getName()
{
return 'pim_icecatdemo_vendor';
}
}
|
The following configuration must be loaded by your bundle extension:
1 2 3 4 5 6 7 8 9 10 11 12 | # /src/Acme/Bundle/IcecatDemoBundle/Resources/config/attribute_types.yml
services:
pim_icecatdemo.attributetype.vendor:
class: Acme\Bundle\IcecatDemoBundle\AttributeType\VendorType
arguments:
- vendor
- entity
- '@pim_flexibleentity.validator.attribute_constraint_guesser'
tags:
- name: pim_flexibleentity.attributetype
alias: pim_icecatdemo_vendor
entity: "%pim_catalog.entity.product.class%"
|
Adding validation¶
For the given example, validation is not really needed, but it might be if your custom attribute includes values of its own.
Note
@TODO: Create CustomConstraintGuesser class to have code example
To add validation for a ProductValue, you must create an constraint guesser which will add constraints on the fly if the product has values for your attribute :
The validator for the created custom constraint will be supplied the value of the attribute.