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 as attribute.

Add Properties to your own Category

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/AppBundle/Entity/Category.php
<?php

namespace Acme\Bundle\AppBundle\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
# /src/Acme/Bundle/AppBundle/Resources/config/doctrine/Category.orm.yml
Acme\Bundle\AppBundle\Entity\Category:
    type: entity
    table: pim_catalog_category
    repositoryClass: Akeneo\Bundle\ClassificationBundle\Doctrine\ORM\Repository\CategoryRepository
    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\AppBundle\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/AppBundle/Resources/config/entities.yml
parameters:
    pim_catalog.entity.category.class:      Acme\Bundle\CatalogBundle\Entity\Category

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.

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)
    {

        $builder->add('description', 'text',
            [
                'required' => true
            ]
        );
        parent::buildForm($builder, $options);
    }
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# /src/Acme/Bundle/EnrichBundle/Resources/views/CategoryTree/_tab-panes.html.twig
<div class="tab-pane active" id="properties">
    {% set generalProperties %}
        {{ form_row(form.code) }}
        {{ form_row(form.description) }}
    {% endset %}

    {% set nodeValues %}
        {{ form_row(form.label) }}
    {% endset %}

    {{ elements.accordion({ 'pane.accordion.general_properties': generalProperties, 'pane.accordion.node_values': nodeValues }) }}

</div>

{% if form.vars.value.id %}
    <div class="tab-pane" id="history">
        {% import 'PimDataGridBundle::macros.html.twig' as dataGrid %}
        {{ dataGrid.renderHistoryGrid(form.vars.value) }}
    </div>
{% endif %}

For the form validation you will have to add a new validation file:

1
2
3
4
5
# /src/Acme/Bundle/CatalogBundle/Resources/config/validation/category.yml
Acme\Bundle\CatalogBundle\Entity\Category:
    properties:
        description:
            - NotBlank: ~