Shopware 6.7 introduces powerful new features that make extending the platform more accessible than ever. In this technical deep dive, we'll walk through creating a custom entity in under 10 minutes, demonstrating the streamlined approach to extending Shopware's core functionality.
Prerequisites
Before we begin, ensure you have:
- Shopware 6.7+ installed
- Basic understanding of PHP and Symfony concepts
- Access to your plugin's directory structure
Understanding Custom Entities in Shopware 6.7
Custom entities in Shopware 6.7 represent a significant improvement over previous versions. The new entity system provides better performance, more intuitive APIs, and enhanced developer experience. Unlike earlier versions where custom entities required extensive boilerplate code, Shopware 6.7 simplifies this process while maintaining full functionality.
Step-by-Step Implementation
1. Create the Entity Definition
First, we'll create our custom entity definition. In your plugin directory, navigate to src/Core/Content/YourCustomEntity/.
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\YourCustomEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
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 YourCustomEntityDefinition extends EntityDefinition
{
public function getEntityName(): string
{
return 'your_custom_entity';
}
public function getEntityClass(): string
{
return YourCustomEntity::class;
}
protected function defineFields(): FieldCollection
{
return new FieldCollection([
(new IdField('id', 'id'))->setFlags(new PrimaryKey(), new Required()),
new StringField('name', 'name'),
new StringField('description', 'description'),
]);
}
}
2. Create the Entity Class
Next, create the entity class that will represent your data structure:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\YourCustomEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;
class YourCustomEntity extends Entity
{
use EntityIdTrait;
protected ?string $name = null;
protected ?string $description = null;
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;
}
}
3. Register the Entity in Your Plugin
In your plugin's src/YourPlugin.php file, register the entity:
<?php declare(strict_types=1);
namespace YourPlugin;
use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\ActivateContext;
use Shopware\Core\Framework\Plugin\Context\DeactivateContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class YourPlugin extends Plugin
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
}
public function activate(ActivateContext $context): void
{
// Custom activation logic
}
public function deactivate(DeactivateContext $context): void
{
// Custom deactivation logic
}
public function uninstall(UninstallContext $context): void
{
// Custom uninstallation logic
}
}
4. Create Migration for Database Schema
Create a migration to add the database table:
<?php declare(strict_types=1);
namespace YourPlugin\Migration;
use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Migration\MigrationStep;
class Migration1234567890YourCustomEntity extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1234567890;
}
public function update(Connection $connection): void
{
$connection->executeStatement('
CREATE TABLE IF NOT EXISTS `your_custom_entity` (
`id` BINARY(16) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` TEXT NULL,
`created_at` DATETIME(3) NOT NULL,
`updated_at` DATETIME(3) NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
');
}
public function updateDestructive(Connection $connection): void
{
// No destructive operations needed
}
}
5. Register the Entity in Services
Add your entity to the service configuration in src/Resources/config/services.xml:
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="YourPlugin\Core\Content\YourCustomEntity\YourCustomEntityDefinition">
<tag name="shopware.entity.definition" entity="your_custom_entity"/>
</service>
</services>
</container>
6. Implement Repository Pattern
Create a repository to handle data operations:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\YourCustomEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
class YourCustomEntityRepository
{
private EntityRepository $repository;
public function __construct(EntityRepository $repository)
{
$this->repository = $repository;
}
public function findByName(string $name): ?YourCustomEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('name', $name));
$criteria->setLimit(1);
$result = $this->repository->search($criteria, Context::createDefaultContext());
return $result->first();
}
public function create(array $data): string
{
$context = Context::createDefaultContext();
$this->repository->create([$data], $context);
return $data['id'];
}
}
7. Register Repository as Service
Add to your services.xml:
<service id="YourPlugin\Core\Content\YourCustomEntity\YourCustomEntityRepository">
<argument type="service" id="your_custom_entity.repository"/>
</service>
Advanced Features and Considerations
Validation and Constraints
Shopware 6.7 supports advanced validation through the field system:
use Shopware\Core\Framework\DataAbstractionLayer\Field\Validation\Length;
use Shopware\Core\Framework\DataAbstractionLayer\Field\Validation\NotBlank;
// In your definition
new StringField('name', 'name')
->setFlags(new NotBlank(), new Length(255)),
Relationships and Associations
For complex entities, you can define relationships:
// One-to-many relationship
(new ReferenceField('category_id', 'categoryId', CategoryDefinition::class))
->setFlags(new Required()),
Performance Optimizations
Leverage Shopware 6.7's improved caching mechanisms:
public function getCacheKey(): string
{
return 'your_custom_entity_cache_key';
}
Testing Your Custom Entity
Create a simple test to verify functionality:
<?php declare(strict_types=1);
namespace YourPlugin\Test\Core\Content\YourCustomEntity;
use PHPUnit\Framework\TestCase;
use YourPlugin\Core\Content\YourCustomEntity\YourCustomEntityRepository;
class YourCustomEntityRepositoryTest extends TestCase
{
public function testCreateEntity(): void
{
$repository = $this->getContainer()->get(YourCustomEntityRepository::class);
$id = $repository->create([
'name' => 'Test Entity',
'description' => 'A test entity for demonstration'
]);
$this->assertNotEmpty($id);
}
}
Migration Considerations
When upgrading or migrating existing data, ensure proper handling:
public function update(Connection $connection): void
{
// Add new fields if needed
$connection->executeStatement('
ALTER TABLE your_custom_entity
ADD COLUMN IF NOT EXISTS `status` VARCHAR(50) DEFAULT \'active\'
');
}
Best Practices
- Use meaningful names for entities and fields that align with Shopware conventions
- Implement proper validation to ensure data integrity
- Consider performance implications of complex queries
- Use appropriate field types based on your data requirements
- Implement proper error handling in your repository methods
Conclusion
Shopware 6.7 has significantly simplified the process of creating custom entities while maintaining the platform's robustness and performance. The streamlined approach eliminates much of the boilerplate code required in previous versions, allowing developers to focus on business logic rather than infrastructure.
The key improvements include better entity definition syntax, enhanced service registration, and improved database migration handling. This new approach makes it feasible to implement complex custom entities within minutes rather than hours or days.
Remember to test thoroughly, especially when dealing with relationships and complex data structures. The Shopware 6.7 entity system provides excellent tools for building scalable, maintainable custom functionality that integrates seamlessly with the core platform.
With these fundamentals in place, you're now equipped to extend Shopware's capabilities with custom entities that can handle anything from simple configuration options to complex business logic implementations. The improved developer experience in version 6.7 makes this an exciting time for Shopware extension development.