The address management allows a customer to manage more than only one address which gets changed with every order. The customer is now able to create more addresses, e.g. for home and work, and use them later on in an order without losing all existing address data. He can just change the reference to the default billing address, instead of changing it entirely.
The address service is used to manage all address entities in Shopware.
It only works with models which makes it easy to comprehend, which properties are available and can be used.
To know which properties are available, please refer to the model \Shopware\Models\Customer\Address
in the source code.
Please don't handle the persisting using Doctrine ORM yourself as you might risk data inconsistency.
Like said above, you have to pass an already complete address model and an existing customer to the address service. In case of an error, you'll get an exception.
$address = new \Shopware\Models\Customer\Address();
$address->fromArray($addressData);
$customer = $this->get('models')->find(\Shopware\Models\Customer\Customer::class, 1);
$this->get('shopware_account.address_service')->create($address, $customer);
Updating an address is almost the same as creating one. The only difference is, that you don't have to provide the customer since the address is already associated with it.
Pretending that you already fetched an address in $address
, your update call might look like this:
$address->setStreet('Alternative Street 5');
$this->get('shopware_account.address_service')->update($address);
The deletion of an address also requires an existing model. In case of errors, you'll get an exception.
Pretending that you already fetched an address in $address
, your delete call might look like this:
$this->get('shopware_account.address_service')->delete($address);
This call might throw an exception if you are trying to delete an address, which is associated with a default billing or shipping address of a customer.
The service includes two methods for setting an address as new default billing or shipping address.
Pretending that you already fetched an address in $address
, you can easily call the appropriate method:
$this->get('shopware_account.address_service')->setDefaultBillingAddress($address);
$this->get('shopware_account.address_service')->setDefaultShippingAddress($address);
The addresses are now validated by a symfony form \Shopware\Bundle\AccountBundle\Form\Account\AddressFormType
.
If you want to add your own fields to it, you can subscribe to the Shopware_Form_Builder
event and create or modify fields inside the additional
field.
The address form also supports attributes. They will automatically be mapped to the attribute model if you follow the input naming conventions. This is an example for providing attributes with an HTML input field:
<input type="text" name="address[attribute][text3]" />
If you don't want to use attributes, e.g. for temporary data transfer or non-persistent data, you can use the additional
field.
The address model now contains a new property additional
which is declared as an array, a key/value store to be exact.
This array will be filled with these form fields, you've added earlier using the event (see Example #1 below).
To correctly map the submitted data to your new fields, you have to follow the convention of using the additional array as field name like:
<input type="text" name="address[additional][neighboursName]" />
You have access to your data by using $address->getAdditional()
.
The first example will show how to add fields to the address form.
This example will add a new field named neighboursName
and it should not be empty.
<service id="pluginname.address_form_extender" class="PluginName\Subscriber\FormExtenderSubscriber">
<tag name="shopware.event_subscriber" />
</service>
// PluginFolder/Subscriber/FormExtenderSubscriber.php
public static function getSubscribedEvents()
{
return [
'Shopware_Form_Builder' => 'onFormBuild',
];
}
public function onFormBuild(\Enlight_Event_EventArgs $event)
{
/** @see \Shopware\Bundle\AccountBundle\Form\Account\AddressFormType::getBlockPrefix */
if ($event->getReference() !== 'address') {
return;
}
/** @var \Symfony\Component\Form\FormBuilderInterface $builder */
$builder = $event->getBuilder();
$builder->get('additional')
->add('neighboursName', \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
'constraints' => [
new \Symfony\Component\Validator\Constraints\NotBlank()
]
]);
}
The example will add multiple fields with different validation options. If you don't provide a list of constraints to a field, it will be optional.
<service id="pluginname.address_form_extender" class="PluginName\Subscriber\FormExtenderSubscriber">
<tag name="shopware.event_subscriber" />
</service>
// PluginFolder/Subscriber/FormExtenderSubscriber.php
public function onFormBuild(\Enlight_Event_EventArgs $event) {
if ($event->getReference() !== \Shopware\Bundle\AccountBundle\Form\Account\AddressFormType::class) {
return;
}
/** @var \Symfony\Component\Form\FormBuilderInterface $builder */
$builder = $event->getBuilder();
$builder->get('additional')
->add('neighboursName', \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
'constraints' => [
new \Symfony\Component\Validator\Constraints\NotBlank()
]
])
->add('neighboursEmail', \Symfony\Component\Form\Extension\Core\Type\EmailType::class, [
'constraints' => [
new \Symfony\Component\Validator\Constraints\NotBlank(),
new \Symfony\Component\Validator\Constraints\Email()
]
])
->add('neighboursPhone', \Symfony\Component\Form\Extension\Core\Type\IntegerType::class);
});
This example will decorate the address service in order to handle additional data.
First, we need a new class, which implements the AddressServiceInterface
.
<?php
use Shopware\Bundle\AccountBundle\Service\AddressServiceInterface;
use Shopware\Models\Customer\Address;
use Shopware\Models\Customer\Customer;
class MyAddressService implements AddressServiceInterface
{
/**
* @var AddressServiceInterface
*/
private $coreAddressService;
public function __construct(AddressServiceInterface $coreAddressService)
{
$this->coreAddressService = $coreAddressService;
}
/**
* Handles additional data
* @param Address $address
*/
private function handleAdditionalData($address)
{
// handle additional data
$additional = $address->getAdditional();
if (!empty($additional['neighboursEmail'])) {
mail($additional['neighboursEmail'], 'Address changed', 'Nice mail text');
}
}
public function create(Address $address, Customer $customer)
{
$this->coreAddressService->create($address, $customer);
$this->handleAdditionalData($address);
}
public function update(Address $address)
{
$this->coreAddressService->update($address);
$this->handleAdditionalData($address);
}
public function delete(Address $address)
{
$this->coreAddressService->delete($address);
}
public function isValid(Address $address)
{
$this->coreAddressService->isValid($address);
}
public function setDefaultBillingAddress(Address $address)
{
$this->coreAddressService->setDefaultBillingAddress($address);
}
public function setDefaultShippingAddress(Address $address)
{
$this->coreAddressService->setDefaultShippingAddress($address);
}
}
Now that we have created the class, we need to decorate the existing service with our new service.
<service id="swag_demo.subscriber.address_service_decorator"
class="SwagDoku\Services\AddressServiceDecorator"
decorates="shopware_account.address_service"
public="false"
>
<argument type="service" id="swag_demo.subscriber.address_service_decorator.inner" />
</service>
You are now set and your service takes over the work.