Introduction
Shopware 6.7 introduces significant improvements to its core architecture, particularly in how developers can extend and customize the platform. One of the most common customization requirements for merchants is the ability to add custom salutations for customer communications. This technical blog post will guide you through the complete process of registering a custom salutation in Shopware 6.7, covering both the database schema modifications and the necessary service registrations.
Understanding Salutations in Shopware 6.7
In Shopware 6.7, salutations are managed through the salutation entity within the customer module. The platform provides a robust system for handling different greeting formats, but there are scenarios where businesses require custom salutations beyond the default options like "Mr." or "Ms." This could include industry-specific greetings, company-specific titles, or multilingual requirements.
The salutation system in Shopware 6.7 is built on top of the entity system, which means it follows the standard Shopware 6 architecture patterns including entities, repositories, services, and API endpoints.
Database Schema Preparation
Before we can register a custom salutation, we need to understand how the existing salutation structure works. In Shopware 6.7, the salutation table contains the following essential columns:
CREATE TABLE `salutation` (
`id` BINARY(16) NOT NULL,
`created_at` DATETIME(3) NOT NULL,
`updated_at` DATETIME(3) DEFAULT NULL,
`display_name` VARCHAR(255) NOT NULL,
`letter_name` VARCHAR(255) NOT NULL,
`salutation_key` VARCHAR(255) NOT NULL
);
To add a custom salutation, we need to create a migration that will properly register our new entity in the system. The migration approach ensures compatibility with Shopware's database versioning system.
Creating the Migration
The first step in registering a custom salutation is creating a proper migration file. In your plugin or custom module, create a migration file:
<?php declare(strict_types=1);
namespace YourPlugin\Migration;
use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Migration\MigrationStep;
class Migration1700000000RegisterCustomSalutation extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1700000000;
}
public function update(Connection $connection): void
{
// Insert custom salutation
$connection->insert('salutation', [
'id' => Uuid::randomBytes(),
'display_name' => 'Divers',
'letter_name' => 'Dear Divers',
'salutation_key' => 'divers',
'created_at' => (new \DateTime())->format('Y-m-d H:i:s.v'),
]);
}
public function updateDestructive(Connection $connection): void
{
// No destructive operations needed for this migration
}
}
Entity Definition
In Shopware 6.7, the entity system is heavily based on Symfony's dependency injection container and Doctrine ORM. To properly register our custom salutation, we need to extend the existing salutation entity definition.
Create a new file src/Core/Content/Salutation/SalutationDefinition.php in your plugin:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\Salutation;
use Shopware\Core\Content\Customer\CustomerDefinition;
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 SalutationDefinition extends EntityDefinition
{
public function getEntityName(): string
{
return 'salutation';
}
public function getCollectionClass(): string
{
return SalutationCollection::class;
}
public function getEntityClass(): string
{
return SalutationEntity::class;
}
protected function defineFields(): FieldCollection
{
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()),
(new StringField('display_name', 'displayName'))->addFlags(new Required()),
(new StringField('letter_name', 'letterName'))->addFlags(new Required()),
(new StringField('salutation_key', 'salutationKey'))->addFlags(new Required()),
]);
}
}
Repository Implementation
The repository pattern in Shopware 6.7 provides a clean interface for data access operations. We need to create a custom repository to handle our salutation entities:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\Salutation;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
class SalutationRepository
{
private EntityRepository $repository;
public function __construct(EntityRepository $repository)
{
$this->repository = $repository;
}
public function findCustomSalutation(string $salutationKey): ?SalutationEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('salutation_key', $salutationKey));
$criteria->setLimit(1);
return $this->repository->search($criteria, Context::createDefaultContext())->first();
}
public function createCustomSalutation(array $data): string
{
$context = Context::createDefaultContext();
$this->repository->create([
[
'display_name' => $data['displayName'],
'letter_name' => $data['letterName'],
'salutation_key' => $data['salutationKey'],
]
], $context);
return $this->repository->searchIds($criteria, $context)->getIds()[0];
}
}
Service Registration
In Shopware 6.7, service registration follows Symfony's dependency injection patterns. We need to register our custom services in the plugin's service configuration:
# 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\Salutation\SalutationRepository">
<argument type="service" id="salutation.repository"/>
</service>
<service id="YourPlugin\Core\Content\Salutation\SalutationDefinition">
<tag name="shopware.entity.definition" entity="salutation"/>
</service>
<service id="YourPlugin\Core\Content\Salutation\SalesChannel\SalutationRoute">
<argument type="service" id="YourPlugin\Core\Content\Salutation\SalutationRepository"/>
<tag name="shopware.sales_channel.route"/>
</service>
</services>
</container>
API Endpoint Registration
Shopware 6.7 provides a flexible API routing system that allows us to create custom endpoints for our salutations. We need to register our endpoint in the sales channel route:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\Salutation\SalesChannel;
use OpenApi\Annotations as OA;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class SalutationRoute
{
private SalutationRepository $salutationRepository;
public function __construct(SalutationRepository $salutationRepository)
{
$this->salutationRepository = $salutationRepository;
}
/**
* @Route("/store-api/salutation/custom", name="store-api.salutation.custom", methods={"GET"})
* @OA\Get(
* path="/salutation/custom",
* summary="Get custom salutations",
* tags={"Store API"}
* )
*/
public function getCustomSalutations(Request $request, SalesChannelContext $context): Response
{
$criteria = new Criteria();
// Add custom filters here if needed
$result = $this->salutationRepository->search($criteria, $context->getSalesChannel()->getId());
return new Response(json_encode([
'data' => $result->getElements(),
'total' => $result->getTotal()
]));
}
}
Configuration and Dependency Injection
To ensure our custom salutation system integrates properly with Shopware 6.7's service container, we need to update the plugin configuration:
<?php declare(strict_types=1);
namespace YourPlugin;
use Shopware\Core\Framework\Plugin;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class YourPlugin extends Plugin
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
// Register custom services
$container->setParameter('your_plugin.salutation.config', [
'custom_salutations' => [
'divers' => [
'display_name' => 'Divers',
'letter_name' => 'Dear Divers',
'priority' => 100
]
]
]);
}
}
Integration with Customer Module
The final step involves ensuring our custom salutation integrates seamlessly with the customer module. We need to override or extend the existing customer salutation handling:
<?php declare(strict_types=1);
namespace YourPlugin\Core\Content\Customer;
use Shopware\Core\Content\Customer\CustomerDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToOneAssociationField;
use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;
class CustomerDefinitionExtension
{
public function extendCustomerDefinition(CustomerDefinition $definition): void
{
$definition->addFields([
new ManyToOneAssociationField('salutation', 'salutation_id', SalutationDefinition::class, 'id'),
]);
}
}
Testing the Implementation
To verify our custom salutation works correctly, we should create a comprehensive test:
<?php declare(strict_types=1);
namespace YourPlugin\Test\Unit\Core\Content\Salutation;
use PHPUnit\Framework\TestCase;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use YourPlugin\Core\Content\Salutation\SalutationRepository;
class SalutationRepositoryTest extends TestCase
{
public function testCreateAndFindCustomSalutation(): void
{
$repository = $this->createMock(SalutationRepository::class);
$data = [
'displayName' => 'Divers',
'letterName' => 'Dear Divers',
'salutationKey' => 'divers'
];
$id = $repository->createCustomSalutation($data);
$this->assertNotEmpty($id);
$salutation = $repository->findCustomSalutation('divers');
$this->assertNotNull($salutation);
$this->assertEquals('Divers', $salutation->getDisplayName());
}
}
Performance Considerations
When implementing custom salutations in Shopware 6.7, several performance factors need consideration:
- Caching Strategy: Implement proper caching for frequently accessed salutations
- Database Indexes: Ensure appropriate indexes on
salutation_keyanddisplay_name - Memory Usage: Be mindful of memory consumption when loading large sets of salutations
Conclusion
Registering a custom salutation in Shopware 6.7 requires understanding the platform's entity system, migration patterns, and service registration mechanisms. By following the steps outlined in this technical guide, developers can successfully extend the salutation functionality to meet specific business requirements.
The key aspects covered include database schema preparation through migrations, proper entity definition, repository implementation, service registration, API endpoint creation, and integration with existing customer modules. This approach ensures that custom salutations are properly integrated into Shopware 6.7's architecture while maintaining compatibility with the platform's core systems.
As Shopware continues to evolve, understanding these fundamental patterns will be crucial for developers looking to extend the platform's capabilities in a maintainable and scalable manner.