Home Blog Contact

How to create Entity, EntityDefinition, EntityHydrator and EntityCollection in Shopware 6?

Jan 27th 2022

Hello. Today I'm going to talk about how to create an entity and all related classes for it. This is a very simple tutorial. In case you are looking for something more advanced, please check the documentation.

These are the classes related to entities as well as a brief explanation why they are necessary:

Type Explanation Example
Entity This is the representation of the entity itself Book
Person
Car
EntityDefinition This class definines types of database columns, setup of entity name, hydrator, collection, default values... etc BookDefinition
PersonDefinition
CarDefinition
EntityHydrator This class populates the data coming from the database (or other storages like in-memory, external services, CSV...) BookHydrator
PersonHydrator
CarHydrator
EntityCollection This class makes working with a list of entities in a elegant way like custom filters and getters instead of primitive arrays BookCollection
PersonCollection
CarCollection

Naming convention

It's important to understand what domain your entity is related to. There are few domains that your entity might be part of, however if you are creating a general entity it should be put on Content domain. These are other possible domains: Checkout, Framework and System.

So, in the root of your plugin, please create the directory src/Content, so we will put the PHP files there.


Add entity classes to services.xml

Definition and hydrator classes should be injected in your plugin: src/Resources/config/services.xml:

<service id="MatheusGontijo\HelloWorld\Content\Speaker\SpeakerDefinition">
    <tag name="shopware.entity.definition" entity="matheusgontijo_speaker" />
</service>

<service id="MatheusGontijo\HelloWorld\Content\Speaker\SpeakerHydrator" public="true">
    <argument type="service" id="service_container" />
</service>

Entity

We will have three attributes: id, name and nationality. The attributes created at and updated at are being handled by Shopware itself. Please create the SpeakerEntity.php file on Content directory:

<?php declare(strict_types=1);

namespace MatheusGontijo\HelloWorld\Content\Speaker;

use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;

class SpeakerEntity extends Entity
{
    use EntityIdTrait;

    /**
     * @var string|null
     */
    protected $name;

    /**
     * @var string|null
     */
    protected $nationality;

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(?string $name): void
    {
        $this->name = $name;
    }

    public function getNationality(): ?string
    {
        return $this->nationality;
    }

    public function setNationality(?string $nationality): void
    {
        $this->nationality = $nationality;
    }
}

EntityDefinition

Create the SpeakerDefinition.php file:

<?php declare(strict_types=1);

namespace MatheusGontijo\HelloWorld\Content\Speaker;

use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\ApiAware;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required;
use Shopware\Core\Framework\DataAbstractionLayer\Field\IdField;
use Shopware\Core\Framework\DataAbstractionLayer\Field\StringField;
use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;

class SpeakerDefinition extends EntityDefinition
{
    public const ENTITY_NAME = 'matheusgontijo_speaker';

    public function getEntityName(): string
    {
        return self::ENTITY_NAME;
    }

    public function getCollectionClass(): string
    {
        return SpeakerCollection::class;
    }

    public function getEntityClass(): string
    {
        return SpeakerEntity::class;
    }

    public function getHydratorClass(): string
    {
        return SpeakerHydrator::class;
    }

    protected function defineFields(): FieldCollection
    {
        return new FieldCollection([
            (new IdField('id', 'id'))->addFlags(new ApiAware(), new PrimaryKey(), new Required()),
            (new StringField('name', 'name'))->addFlags(new ApiAware(), new Required()),
            (new StringField('nationality', 'nationality'))->addFlags(new ApiAware(), new Required()),
        ]);
    }
}

EntityHydrator

Create the SpeakerHydrator.php file:

<?php declare(strict_types=1);

namespace MatheusGontijo\HelloWorld\Content\Speaker;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityHydrator;
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
use Shopware\Core\Framework\Uuid\Uuid;
use DateTimeImmutable;

class SpeakerHydrator extends EntityHydrator
{
    protected function assign(EntityDefinition $definition, Entity $entity, string $root, array $row, Context $context): Entity
    {
        if (isset($row[$root . '.id'])) {
            $entity->id = Uuid::fromBytesToHex($row[$root . '.id']);
        }

        if (isset($row[$root . '.name'])) {
            $entity->name = $row[$root . '.name'];
        }

        if (isset($row[$root . '.nationality'])) {
            $entity->nationality = $row[$root . '.nationality'];
        }

        if (isset($row[$root . '.createdAt'])) {
            $entity->createdAt = new DateTimeImmutable($row[$root . '.createdAt']);
        }

        if (isset($row[$root . '.updatedAt'])) {
            $entity->updatedAt = new DateTimeImmutable($row[$root . '.updatedAt']);
        }

        return $entity;
    }
}

EntityCollection

Create the SpeakerCollection.php file:

<?php declare(strict_types=1);

namespace MatheusGontijo\HelloWorld\Content\Speaker;

use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;

/**
 * @method void               add(SpeakerEntity $entity)
 * @method void               set(string $key, SpeakerEntity $entity)
 * @method SpeakerEntity[]    getIterator()
 * @method SpeakerEntity[]    getElements()
 * @method SpeakerEntity|null get(string $key)
 * @method SpeakerEntity|null first()
 * @method SpeakerEntity|null last()
 */
class SpeakerCollection extends EntityCollection
{
    public function getApiAlias(): string
    {
        return 'matheusgontijo_speaker_collection';
    }

    protected function getExpectedClass(): string
    {
        return SpeakerEntity::class;
    }
}

Conclusion

Great! We created our Speaker entity and all entity related classes! This is how the structure should look like in the end:

MatheusGontijoHelloWorld
└── src
    └── Content
      └── Speaker
          ├── SpeakerCollection.php
          ├── SpeakerDefinition.php
          ├── SpeakerEntity.php
          └── SpeakerHydrator.php

Thank you! In the next blogpost, let's create a repository to write and read data to make sure it's all working.