Replacing associated data

Overview

This short guide will give you an example on how to replace associated ToMany data using our Data Abstraction Layer.

Prerequisites

Having read our guide about writing data is mandatory to understand the next few steps here. Other than that, the default prerequisites apply here as well: A running Shopware 6 instance and full access to the files.
The examples mentioned here are built upon the plugin base guide. If you don't know how to create a plugin or how to use the code examples here in the first place, the plugin base guide is a good way to start.

Replacing data

So let's start with the main issue going on here. Let's imagine you've created a product using our previously mentioned guide about writing data and you've assigned a category to it. Unfortunately you made a mistake, since this was the wrong category to be assigned and you want another category to be assigned instead.

A wrong example

The following example will show you how not to do it. It's assuming that you've previously assigned the category Old category with the ID oldId to the product.
1
public function replaceData(Context $context): void
2
{
3
$this->productRepository->update([
4
[
5
'id' => 'myProductId',
6
'categories' => [
7
[
8
'id' => 'newCategoryId'
9
]
10
]
11
]
12
], $context);
13
}
Copied!
You're assigning an array of category arrays to the product with the ID myProductId. This array of category arrays does not contain the old category ID, only the new one. Thus, the old category association should be removed and instead the new category should be assigned, right?
Well, this is not how it works. Using a write operation will not delete data, but only add up more data. The result of the example above will be a product with two categories assigned instead.

The right example

The right way to do it is to delete the category association first, only to then re-assign a new category. Let's take a look at the deletion part first, since this is where most people struggle.
The product categories are a ManyToMany association and thus come with a mapping table, and a custom entity. You can find the entity definition for the association here.
In order to delete it, we once again need its repository. The name for the entity can be found in the definition, to be precise inside of the getEntityName method.
So let's inject this repository into our class called ReplacingData:
1
// SwagBasicExample/src/Resources/config/services.xml
2
<?xml version="1.0" ?>
3
<container xmlns="http://symfony.com/schema/dic/services"
4
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6
7
<services>
8
<service id="Swag\BasicExample\Service\ReplacingData" >
9
<argument type="service" id="product.repository"/>
10
<argument type="service" id="product_category.repository"/>
11
</service>
12
</services>
13
</container>
Copied!
Afterwards, you can just use the delete method on the repository, just like you did before in the writing data guide.
1
public function replaceData(Context $context): void
2
{
3
$this->productCategoryRepository->delete([
4
[
5
'productId' => 'myProductId',
6
'categoryId' => 'oldId'
7
]
8
], $context);
9
}
Copied!
Now the association to the old category was removed and you can now use the code above to add the new category instead.
1
public function replaceData(Context $context): void
2
{
3
$productId = 'myProductId';
4
5
$this->productCategoryRepository->delete([
6
[
7
'productId' => $productId,
8
'categoryId' => 'oldCategoryId'
9
]
10
], $context);
11
12
$this->productRepository->update([
13
[
14
'id' => $productId,
15
'categories' => [
16
[
17
'id' => 'newCategoryId'
18
]
19
]
20
]
21
], $context);
22
}
Copied!
And that's it, you've successfully deleted one association and then replaced it by another. This works for both ManyToMany, as well as OneToMany associations.

ToOne associations

Replacing OneToOne or ManyToOne associations works just like expected via an update call, e.g. for the tax of a product:
1
public function replaceData(Context $context): void
2
{
3
$this->productRepository->update([
4
[
5
'id' => 'myProductId',
6
'taxId' => 'newTaxId'
7
]
8
], $context);
9
}
Copied!
This works as expected.

More interesting topics