How to Create a Custom Entity and the Screens to Manage it

Note

The code inside this cookbook entry is visible in src directory, you can clone pim-dev then do a symlink and install

Creating the Entity

As Akeneo relies heavily on standard tools like Doctrine, creating the entity is quite straightforward for any developer with Doctrine experience.

  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
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
# /src/Acme/Bundle/IcecatDemoBundle/Entity/Vendor.php
<?php

namespace Acme\Bundle\IcecatDemoBundle\Entity;

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Pim\Bundle\CatalogBundle\Model\ReferableInterface;

/**
 * @UniqueEntity(fields="code", message="This code is already taken")
 */
class Vendor implements ReferableInterface
{
    protected $id;

    /**
     * @Assert\Regex(pattern="/^[a-zA-Z0-9_]+$/")
     * @Assert\Length(max=100, min=1)
     */
    protected $code;

    /**
     * @Assert\Length(max=250, min=1)
     */
    protected $label;

    protected $responsible;

    protected $created;

    protected $updated;

    public function getId()
    {
        return $this->id;
    }

    public function getCode()
    {
        return $this->code;
    }

    public function getLabel()
    {
        return $this->label;
    }

    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

    public function setLabel($label)
    {
        $this->label = $label;

        return $this;
    }

    public function getResponsible()
    {
        return $this->responsible;
    }

    public function setResponsible($responsible)
    {
        $this->responsible = $responsible;
    }

    public function setCreated($created)
    {
        $this->created = $created;

        return $this;
    }

    public function getCreated()
    {
        return $this->created;
    }

    public function setUpdated($updated)
    {
        $this->updated = $updated;

        return $this;
    }

    public function getUpdated()
    {
        return $this->updated;
    }

    public function __toString()
    {
        return $this->code;
    }

    public function getReference()
    {
        return $this->code;
    }
}
 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
50
51
52
# /src/Acme/Bundle/IcecatDemoBundle/Resources/config/doctrine/Vendor.orm.yml
Acme\Bundle\IcecatDemoBundle\Entity\Vendor:
    type: entity
    table: pim_icecatdemo_vendor
    repositoryClass: Pim\Bundle\CatalogBundle\Entity\Repository\ReferableEntityRepository
    uniqueConstraints:
        pim_icecatdemo_vendor_code:
            columns:
                - code
    fields:
        id:
            type: integer
            scale: 0
            length: null
            unique: false
            nullable: false
            precision: 0
            id: true
            generator:
                strategy: IDENTITY
        code:
            type: string
            scale: 0
            length: 100
            unique: false
            nullable: false
            precision: 0
        label:
            type: string
            scale: 0
            length: 250
            unique: false
            nullable: false
            precision: 0
        responsible:
            type: string
            scale: 0
            length: null
            unique: false
            nullable: false
            precision: 0
        created:
            type: datetime
            gedmo:
                timestampable:
                    on: create
        updated:
            type: datetime
            gedmo:
                timestampable:
                    on: update
    lifecycleCallbacks: {  }

Also add parameters for your entity in the DIC :

1
2
3
# /src/Acme/Bundle/IcecatDemoBundle/Resources/config/entities.yml
parameters:
    pim_catalog.entity.vendor.class:        Acme\Bundle\IcecatDemoBundle\Entity\Vendor

Note

We have added a code attribute in order to get a non technical unique key. We already have the id, which is the primary key, but this primary key is really dependent of Akeneo, it’s an internal id that does not carry any meaning for the user. The role of the code is to be a unique identifier that will make sense for the user and that will be used with other applications.

In the very case of our manufacturer data, they will certainly come from the ERP, with their own code that we will store in this attribute.

Creating the Entity Management Screens

The Grid

To benefit from the grid component (which comes natively with filtering and sorting), you can define the vendor grid as following :

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# /src/Acme/Bundle/IcecatDemoBundle/Resources/config/datagrid.yml
datagrid:
    vendor-grid:
        options:
            entityHint: vendor
        source:
            type: pim_orm
            entity: '%pim_catalog.entity.vendor.class%'
        properties:
            id: ~
            edit_link:
                type: custom_entity_url
                route: pim_customentity_edit{customEntityName:vendor}
                params:
                    - id
            delete_link:
                type: custom_entity_url
                route: pim_customentity_remove{customEntityName:vendor}
                params:
                    - id
        columns:
            code:
                label: Code
            label:
                label: Label
            responsible:
                label: Responsible
            created:
                label: Created
                frontend_type: datetime
            updated:
                label: Updated
                frontend_type: datetime
        actions:
            edit:
                type:      navigate
                label:     Edit
                icon:      edit
                link:      edit_link
                rowAction: true
            delete:
                type:  delete
                label: Delete
                icon:  trash
                link:  delete_link
        sorters:
            columns:
                code:
                    data_name: o.code
                label:
                    data_name: o.label
                responsible:
                    data_name: o.responsible
                created:
                    data_name: o.created
                updated:
                    data_name: o.updated
            default:
                code: '%oro_datagrid.extension.orm_sorter.class%::DIRECTION_ASC'
        filters:
            columns:
                code:
                    type:      string
                    label:     Code
                    data_name: o.code
                label:
                    type: string
                    label: Label
                    data_name: o.label
                responsible:
                    type: string
                    label: Responsible
                    data_name: o.responsible
                created:
                    type: datetime
                    label: Created
                    data_name: o.created
                updated:
                    type: datetime
                    label: Updated
                    data_name: o.updated

Creating the Form Type for this Entity

 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
# /src/Acme/Bundle/IcecatDemoBundle/Form/Type/VendorType.php
<?php

namespace Acme\Bundle\IcecatDemoBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class VendorType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('code')
            ->add('label')
            ->add('responsible');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class' => 'Acme\Bundle\IcecatDemoBundle\Entity\Vendor',
            )
        );
    }

    public function getName()
    {
        return 'pim_icecatdemo_vendor';
    }
}

Creating the CRUD

A complete CRUD can be easily obtained by defining a service for its configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# /src/Acme/Bundle/IcecatDemoBundle/Resources/config/custom_entities.yml
services:
    pim_icecat_demo.custom_entity.configuration:
        class: '%pim_custom_entity.configuration.default.class%'
        arguments:
            - vendor
            - '@pim_custom_entity.manager.orm'
            - '@pim_custom_entity.controller.strategy.crud'
            - entity_class:         Acme\Bundle\IcecatDemoBundle\Entity\Vendor
              edit_form_type:       pim_icecatdemo_vendor
              datagrid_namespace:   pim_icecatdemo
        tags:
            - { name: pim_custom_entity.configuration }

From this point a working grid screen is visible at /app_dev.php/enrich/vendor.

If some vendors are manually added to the database, the pagination will be visible as well.

Note

Have a look at the Cookbook recipe “How to add an menu entry” to add your own link in the menu to this grid.