Spryker-Entwickler über Shopware
In den letzten Jahren habe ich hauptsächlich mit Spryker gearbeitet. Da ich mich jetzt schwerpunktmäßig mit
Shopware beschäftige, schaue ich mir auch den Code genauer an. Als die ersten Videos Shopware für
Entwickler gesehen habe, ist mir aufgefallen, dass die Developer-Experience bei Shopware verbesserungswürdig ist,
denn ist gibt einiges and "Duplicate-Logic", die man eigentlich vermeiden kann.
Entities
Shopware nutzt nicht Doctrine oder eine eigene ORM-Library, was verständlich ist und soweit auch gut ist,
denn eine eigene Lösung, die zugeschnitten auf eigne Bedürfnisse ist, kann viel schneller und effizienter sein.
Shopware nutzt eine EntityDefinition Klasse, in der die Properties der Entities definiert werden. Eine Entity Klasse
sieht wie folgt aus.
class ExampleDefinition extends EntityDefinition
{
public const ENTITY_NAME = 'swag_example';
public function getEntityName(): string
{
return self::ENTITY_NAME;
}
protected function defineFields(): FieldCollection
{
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new Required(), new PrimaryKey()),
(new StringField('name', 'name')),
(new StringField('description', 'description')),
(new BoolField('active', 'active'))
]);
}
}
In der Methode defineFields erkennt man sofort, dass die Properties und die dazugehörigen Felder
in der Datenbank definiert werden.
Man braucht natürlich auch eine EntityClass, die wie folgt aussieht.
class ExampleEntity extends Entity
{
use EntityIdTrait;
protected ?string $name;
protected ?string $description;
protected bool $active;
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function isActive(): bool
{
return $this->active;
}
public function setActive(bool $active): void
{
$this->active = $active;
}
}
Genau hier ist das Problem, denn wir haben dieselbe Information an zwei Stellen,
denn die Entity Klasse könnte man anhand der EntityDefinition Klasse generieren.
Das ist aber leidet nicht der Fall, zumindest habe ich dafür keinen Console Command gefunden.
Die Klasse muss manuell angelegt werden die Properties müssen auch manuell definiert werden,
zumindest nach dem jetzigen Stand (13.02.2023).
Migration
Natürlich braucht man zusätzlich eine Klasse für die Datenbank-Migration und die sieht wie folgt aus.
class Migration1611664789Example extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1611664789;
}
public function update(Connection $connection): void
{
$sql = <<<SQL
CREATE TABLE IF NOT EXISTS `swag_example` (
`id` BINARY(16) NOT NULL,
`name` VARCHAR(255) COLLATE utf8mb4_unicode_ci,
`description` VARCHAR(255) COLLATE utf8mb4_unicode_ci,
`active` TINYINT(1) COLLATE utf8mb4_unicode_ci,
`created_at` DATETIME(3) NOT NULL,
`updated_at` DATETIME(3),
PRIMARY KEY (`id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
SQL;
$connection->executeStatement($sql);
}
public function updateDestructive(Connection $connection): void
{
}
}
Das macht das Problem noch schlimmer, die Klasse kann man zwar mit einem Console Command generieren lassen,
aber nicht die SQL-Query,
die muss man manuell schreiben. Jetzt haben wir die gleiche Information an drei Stellen. Das mach die Entwicklung
langsamer und fehleranfälliger. Die Migration kann man ebenfalls anhand der Information in EntityDefinition class generieren.
Ich hoffe, dass das Shopware-Team sich auch um dieses Thema kümmert und meine Wünsche bei den nächsten Updates berücksicht.