How to Add New Properties to a Category¶
The Akeneo PIM allows the classification of products inside a customizable category tree.
Note
To implement this task you have to be comfortable with Symfony bundle overriding and Symfony services. This cookbook can be used to override other entities such as an attribute.
Add Non Translatable Properties to your own Category¶
Extend the category entity¶
The first step is to create a class that extends PIM Category
class.
For example, we can add a description property with a text field.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # /src/Acme/Bundle/CatalogBundle/Entity/Category.php
<?php
namespace Acme\Bundle\CatalogBundle\Entity;
use Pim\Bundle\CatalogBundle\Entity\Category as BaseCategory;
class Category extends BaseCategory
{
protected $description;
public function getDescription()
{
return $this->description;
}
public function setDescription($description)
{
$this->description = $description;
return $this;
}
}
|
Configure the mapping override¶
Then, define the mapping for your own field only:
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/Category.orm.yml
Acme\Bundle\CatalogBundle\Entity\Category:
type: entity
table: pim_catalog_category
changeTrackingPolicy: DEFERRED_EXPLICIT
repositoryClass: Akeneo\Bundle\ClassificationBundle\Doctrine\ORM\Repository\CategoryRepository
uniqueConstraints:
pim_category_code_uc:
columns:
- code
gedmo:
tree:
type: nested
fields:
description:
type: string
length: 255
nullable: true
|
You also need to configure the mapping override in your application configuration (to avoid to copy/paste the whole parent class mapping):
# app/config/config.yml
akeneo_storage_utils:
mapping_overrides:
-
original: Pim\Bundle\CatalogBundle\Entity\Category
override: Acme\Bundle\CatalogBundle\Entity\Category
Define the Category Class¶
You need to update your category entity parameter used in entities.yml
file:
1 2 3 | # /src/Acme/Bundle/CatalogBundle/Resources/config/entities.yml
parameters:
pim_catalog.entity.category.class: Acme\Bundle\CatalogBundle\Entity\Category
|
Important
If you are creating a new bundle, double check that this file is inside the extension
# /src/Acme/Bundle/CatalogBundle/DependencyInjection/AcmeAppExtension.php
public function load(array $configs, ContainerBuilder $container)
{
/** ... **/
$loader->load('entities.yml');
}
Note
You don’t have to add a lot of code to the Doctrine configuration to resolve target entities. We already have a resolver which injects the new category class name.
Now, you can run the following commands to update your database:
php app/console doctrine:schema:update --dump-sql
php app/console doctrine:schema:update --force
Define the Category Form¶
Firstly, you have to create your custom type by inheriting the CategoryType class and then add your custom fields:
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 | # /src/Acme/Bundle/EnrichBundle/Form/Type/CategoryType.php
<?php
namespace Acme\Bundle\EnrichBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Pim\Bundle\EnrichBundle\Form\Type\CategoryType as BaseCategoryType;
/**
* Type for category properties
*/
class CategoryType extends BaseCategoryType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('description', 'text',
[
'required' => true
]
);
}
}
|
Then, you have to override the service definition of your form:
1 2 3 | # /src/Acme/Bundle/EnrichBundle/Resources/config/form_types.yml
parameters:
pim_enrich.form.type.category.class: Acme\Bundle\EnrichBundle\Form\Type\CategoryType
|
Then, add this new file to your dependency injection extension:
# /src/Acme/Bundle/EnrichBundle/DependencyInjection/AcmeAppExtension.php
public function load(array $configs, ContainerBuilder $container)
{
/** ... **/
$loader->load('form_types.yml');
}
Then, don’t forget to add your new field to the twig template:
# /src/Acme/Bundle/EnrichBundle/Resources/views/CategoryTree/Tab/property.html.twig
<!-- ... -->
{% set generalProperties %}
{{ form_row(form.code) }}
{{ form_row(form.description) }}
{% endset %}
<!-- ... -->
Make sure you’ve registered the template properly inside form_types.yml
:
1 2 3 4 | # /src/Acme/Bundle/EnrichBundle/Resources/config/form_types.yml
parameters:
pim_enrich.form.type.category.class: Acme\Bundle\EnrichBundle\Form\Type\CategoryType
pim_enrich.view_element.category.tab.property.template: 'AcmeEnrichBundle:CategoryTree:Tab/property.html.twig'
|
For the form validation you will have to add a new validation file:
# /src/Acme/Bundle/AppBundle/Resources/config/validation/category.yml
Acme\Bundle\AppBundle\Entity\Category:
properties:
description:
- NotBlank: ~
Add Translatable Properties to your own Category¶
Extend the category entity and its translation entity¶
The first step is to create a class that extends PIM CategoryTranslation
class.
For example, we can add an optional description property with a text field.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # /src/Acme/Bundle/CatalogBundle/Entity/CategoryTranslation.php
<?php
namespace Acme\Bundle\CatalogBundle\Entity;
use Pim\Bundle\CatalogBundle\Entity\CategoryTranslation as BaseCategoryTranslation;
class CategoryTranslation extends BaseCategoryTranslation
{
protected $description;
public function getDescription()
{
return $this->description;
}
public function setDescription($description)
{
$this->description = $description;
return $this;
}
}
|
Then we need to link this description to the Category
class.
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 | # /src/Acme/Bundle/CatalogBundle/Entity/Category.php
<?php
namespace Acme\Bundle\CatalogBundle\Entity;
use Pim\Bundle\CatalogBundle\Entity\Category as BaseCategory;
class Category extends BaseCategory
{
public function getDescription()
{
$translated = ($this->getTranslation()) ? $this->getTranslation()->getDescription() : null;
return ($translated !== '' && $translated !== null) ? $translated : '['.$this->getCode().']';
}
public function setDescription($description)
{
$this->getTranslation()->setDescription($description);
return $this;
}
public function getTranslationFQCN()
{
return CategoryTranslation::class;
}
}
|
Configure the mapping override¶
Then, define the mapping for your own field only:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # /src/Acme/Bundle/CatalogBundle/Resources/config/doctrine/CategoryTranslation.orm.yml
Acme\Bundle\CatalogBundle\Entity\CategoryTranslation:
type: entity
table: pim_catalog_category_translation
changeTrackingPolicy: DEFERRED_EXPLICIT
uniqueConstraints:
locale_foreign_key_idx:
columns:
- locale
- foreign_key
fields:
description:
type: text
nullable: true
|
As we override the Category
class, we need to redefine its mapping too, even if we have nothing to add in it:
1 2 3 4 5 6 7 8 9 10 11 12 13 | # /src/Acme/Bundle/CatalogBundle/Resources/config/doctrine/Category.orm.yml
Acme\Bundle\CatalogBundle\Entity\Category:
type: entity
table: pim_catalog_category
changeTrackingPolicy: DEFERRED_EXPLICIT
repositoryClass: Akeneo\Bundle\ClassificationBundle\Doctrine\ORM\Repository\CategoryRepository
uniqueConstraints:
pim_category_code_uc:
columns:
- code
gedmo:
tree:
type: nested
|
You also need to configure the mapping override in your application configuration (to avoid to copy/paste the whole parent class mapping):
# app/config/config.yml
akeneo_storage_utils:
mapping_overrides:
-
original: Pim\Bundle\CatalogBundle\Entity\Category
override: Acme\Bundle\CatalogBundle\Entity\Category
-
original: Pim\Bundle\CatalogBundle\Entity\CategoryTranslation
override: Acme\Bundle\CatalogBundle\Entity\CategoryTranslation
Define the Category Class¶
You need to update your category entity parameter used in entities.yml
file:
1 2 3 4 | # /src/Acme/Bundle/CatalogBundle/Resources/config/entities.yml
parameters:
pim_catalog.entity.category.class: Acme\Bundle\CatalogBundle\Entity\Category
pim_catalog.entity.category_translation.class: Acme\Bundle\CatalogBundle\Entity\CategoryTranslation
|
Important
If you are creating a new bundle, double check that this file is inside the extension
# /src/Acme/Bundle/CatalogBundle/DependencyInjection/AcmeAppExtension.php
public function load(array $configs, ContainerBuilder $container)
{
/** ... **/
$loader->load('entities.yml');
}
Note
You don’t have to add a lot of code to the Doctrine configuration to resolve target entities. We already have a resolver which injects the new category class name.
Now, you can run the following commands to update your database:
php app/console doctrine:schema:update --dump-sql
php app/console doctrine:schema:update --force
Define the Category Form¶
Firstly, you have to create your custom type by inheriting the CategoryType class and then add your custom fields:
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 | # /src/Acme/Bundle/EnrichBundle/Form/Type/CategoryType.php
<?php
namespace Acme\Bundle\EnrichBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Pim\Bundle\EnrichBundle\Form\Type\CategoryType as BaseCategoryType;
/**
* Type for category properties
*/
class CategoryType extends BaseCategoryType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add(
'description',
'pim_translatable_field',
[
'field' => 'description',
'translation_class' => $this->translationDataClass,
'entity_class' => $this->dataClass,
'property_path' => 'translations',
'widget' => 'textarea',
]
);
}
}
|
Then, you have to override the service definition of your form:
1 2 3 | # /src/Acme/Bundle/EnrichBundle/Resources/config/form_types.yml
parameters:
pim_enrich.form.type.category.class: Acme\Bundle\EnrichBundle\Form\Type\CategoryType
|
Then, add this new file to your dependency injection extension:
# /src/Acme/Bundle/EnrichBundle/DependencyInjection/AcmeAppExtension.php
public function load(array $configs, ContainerBuilder $container)
{
/** ... **/
$loader->load('form_types.yml');
}
Then, don’t forget to add your new field to the twig template:
# /src/Acme/Bundle/EnrichBundle/Resources/views/CategoryTree/Tab/property.html.twig
<!-- ... -->
{% set nodeValues %}
{{ form_row(form.label) }}
{{ form_row(form.description) }}
{% endset %}
<!-- ... -->
Make sure you’ve registered the template properly inside form_types.yml
:
1 2 3 4 | # /src/Acme/Bundle/EnrichBundle/Resources/config/form_types.yml
parameters:
pim_enrich.form.type.category.class: Acme\Bundle\EnrichBundle\Form\Type\CategoryType
pim_enrich.view_element.category.tab.property.template: 'AcmeEnrichBundle:CategoryTree:Tab/property.html.twig'
|