How to Use a Custom Entity as an Attribute Type¶
Note
The code inside this cookbook entry is visible in src directory, you can copy/paste the code in your installed PIM (or do a symlink) to use it
Note
The code inside this cookbook entry requires you to install the `akeneo/custom-entity-bundle`_ package.
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 extend and replace to the native Akeneo ProductValue :
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 | # /src/Acme/Bundle/CatalogBundle/Entity/MyProductValue.php
<?php
namespace Acme\Bundle\CatalogBundle\Entity;
use Pim\Bundle\CatalogBundle\Model\AbstractProductValue;
use JMS\Serializer\Annotation\ExclusionPolicy;
/**
* Overrides ProductValue to add the color backend type
*
* @ExclusionPolicy("all")
*/
class MyProductValue extends AbstractProductValue
{
/**
* @var Color
*/
protected $color;
/**
* Returns the color
*
* @return Color
*/
public function getColor()
{
return $this->color;
}
/**
* Sets the color
*
* @param Color $color
*
* @return MyProductValue
*/
public function setColor(Color $color)
{
$this->color = $color;
return $this;
}
}
|
You will also need to add the mapping for the entity. To do this, copy the
src/Pim/Bundle/CatalogBundle/Resources/config/model/doctrine/ProductValue.orm.yml
file of the PIM
inside the Resources/config/doctrine
folder of one of your bundles.
First, replace the name of the class by your own class, and change the name of the table:
1 2 3 4 | # /src/Acme/Bundle/CatalogBundle/Resources/config/doctrine/MyProductValue.orm.yml
Acme\Bundle\CatalogBundle\Entity\MyProductValue:
type: entity
table: acme_catalog_product_value
|
The name of the join tables for all ManyToMany associations must also be changed :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # /src/Acme/Bundle/CatalogBundle/Resources/config/doctrine/MyProductValue.orm.yml
manyToMany:
options:
targetEntity: Pim\Bundle\CatalogBundle\Entity\AttributeOption
cascade:
- refresh
joinTable:
name: acme_catalog_product_value_option
joinColumns:
value_id:
referencedColumnName: id
nullable: true
onDelete: CASCADE
inverseJoinColumns:
option_id:
referencedColumnName: id
nullable: true
onDelete: CASCADE
|
Finally, add your custom relations to the mapping :
1 2 3 4 5 6 7 8 9 10 11 | # /src/Acme/Bundle/CatalogBundle/Resources/config/doctrine/MyProductValue.orm.yml
manyToOne:
color:
targetEntity: Acme\Bundle\CatalogBundle\Entity\Color
cascade:
- persist
- refresh
joinColumns:
color_id:
referencedColumnName: id
onDelete: 'SET NULL'
|
Registering the New Product Value Class¶
Configure the parameter for the ProductValue class :
1 2 3 | # /src/Acme/Bundle/IcecatDemoBundle/Resources/config/entities.yml
parameters:
pim_catalog.entity.product_value.class: Acme\Bundle\CatalogBundle\Entity\MyProductValue
|
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¶
To create a simple select attribute based on your entity, use the following configuration:
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 | # /src/Acme/Bundle/CatalogBundle/Resources/config/attribute_types.yml
parameters:
pim_datagrid.product.attribute_type.acme_color:
column:
type: flexible_option
selector: flexible_option
filter:
type: flexible_choice
parent_type: ajax_choice
options:
field_options:
multiple: true
sorter: flexible_field
services:
acme_catalog.attributetype.color:
class: '%pim_custom_entity.attribute_type.custom_option_simple_select.class%'
arguments:
- color
- pim_ajax_entity
- '@pim_catalog.validator.constraint_guesser.chained_attribute'
- acme_catalog_color
- Acme\Bundle\CatalogBundle\Entity\Color
tags:
- { name: pim_catalog.attribute_type, alias: acme_catalog_color, 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.
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 :
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 | # /src/Acme/Bundle/CatalogBundle/Validator/ConstraintGuesser/CustomConstraintGuesser.php
<?php
namespace Acme\Bundle\CatalogBundle\Validator\ConstraintGuesser;
use Acme\Bundle\CatalogBundle\Validator\Constraints\CustomConstraint;
class CustomConstraintGuesser implements ConstraintGuesserInterface
{
/**
* {@inheritdoc}
*/
public function supportAttribute(AbstractAttribute $attribute)
{
return in_array(
$attribute->getAttributeType(),
array(
'acme_catalog_color',
)
);
}
/**
* {@inheritdoc}
*/
public function guessConstraints(AbstractAttribute $attribute)
{
return array(
new CustomConstraint
);
}
}
|
The validator for the created custom constraint will be supplied the value of the attribute.