Repositories in Shopware 6
What are the repositories in Shopware 6?
To put it very simply: repositories = database tables in Shopware 6.
Of course it is not that simple, but for the most part, it is the truth. In most cases, you can depend on it, that if you need to access the data from the table callled yadayada, you can use the yadayada repository.
So if you need to work with some data from the database, read them or write them, repositories are the way to go. You can of course use the direct access to the database and execute your own SQL code, but that should really be the last resort, because you might overlook something and break stuff. Repositories provide a comfortable abstraction layer above the database, that checks all dependencies and ensures, that the data integrity holds. Repositories should be able to allow you to achieve all, that you need with the data safely and with accordance of Shopware 6 data framework.
How to get the repositories
In order to be able to work with a repository, you need to have it available in your class. This is done using the dependency injection in the contructor of the class. A simple example, that will allow us to use the product repository and customer repository in our class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php namespace ExamplePlugin; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface; class ExampleClass { private $customerRepository; public function __construct( EntityRepositoryInterface $productRepository, EntityRepositoryInterface $customerRepository ) { $this->productRepository = $productRepository; $this->customerRepository = $customerRepository; } } |
Additionally, we need to specify the repositories, that we inject to the class, in the services.xml file, that is usually located in the custom/plugins/ExamplePlugin/src/Resources/config/ directory.
1 2 3 4 5 6 7 8 9 10 11 12 |
<?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="ExamplePlugin\ExampleClass"> <argument type="service" id="product.repository"/> <argument type="service" id="customer.repository"/> <tag name="kernel.event_subscriber"/> </service> </services> </container> |
And now we have access to those two repositories in the whole class and we can use them to retrieve or store data to the corresponding database tables.
How to use the repositories
Repositories have a unified set of methods and conventions, which is great, because once you get to know it and try it yourself on one of them, you can use it on all of them.
So let’s take a look at the most common Shopware 6 repository methods and how are they used.
Getting the data from a repository
Normally, you would use SQL query like SELECT * FROM product WHERE id=productId to search and get some data from the database. And in the end, Shopware does that as well, you just tell it differently. In both cases, you need to specify the search criteria. In Shopware, you do it using the Criteria class.
This simple example will select the same data as the fore mentioned SQL query:
1 2 3 4 |
$productData = $this->productRepository->search( (new Criteria())->addFilter(new EqualsFilter('id', $productId)), $context )->getElements(); |
What we do here, is to call method search on our repository, passing to it two arguments: criteria and context. In our example, the first argument is an instance of class Criteria, that we declare right here for this purpose, but you can also declare it in advance and save it to a variable like this:
1 2 3 4 |
$criteria = new Criteria; $criteria->addFilter(new EqualsFilter('id', $productId)); $productData = $this->productRepository->search($criteria, $context)->getElements(); |
If you just leave the criteria empty, then everything is selected. But most of the time, you want to get some specific data and for this, you use filters – just as in our example. You can of course specify more of them at once like this:
1 2 3 |
$criteria = new Criteria; $criteria->addFilter(new EqualsFilter('active', 1)); $criteria->addFilter(new EqualsAnyFilter('productNumber', $productNumberArray)) |
As you can see, here are multiple types of filters and other methods for search criteria. There is actually a pretty good reference in the official Shopware 6 documentation, so be sure to check it out: https://docs.shopware.com/en/shopware-platform-dev-en/references-internals/core/dal.
Also, very important thing to know, when working with repositories in Shopware 6, is the naming convention for the table columns. Shopware uses camel case, which means, that when you are referencing the column, that is called product_number in the database, you have to use productNumber. Simply put: first character is lower case, the underscore is removed and the next character is an upper case.
In any case, to use the criteria and filters like this, you need to have them mentioned in the file, containing your class, just above the class declaration:
1 2 3 4 5 6 7 8 |
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter; class MyClass { } |
And now briefly to the second, mysterious argument, the context. The context is mandatory and it is something, that varies from one place in the code to another. For example if you are working with repository from within the event subscriber, you would get the context simply like this:
1 2 3 4 5 6 7 |
public function onProductWritten (EntityWrittenEvent $event) { $context = $event->getContext(); //use the $context further } |
If you don’t know, where to take the context from, you can always use the default one like this:
1 |
$this->context = \Shopware\Core\Framework\Context::createDefaultContext(); |
Saving the data to the repository
For saving the data to the repository, we have to create an array with data we want to write and pass it to the repository, using one of the following methods: create, update of upsert.
If we translate these methods to SQL, it would be like this:
create | INSERT INTO table SET .. |
update | UPDATE table SET .. |
upsert | INSERT INTO table SET .. ON DUPLICATE KEY UPDATE .. |
The data array, that we pass, must consist of a non-associative arrays, each of them representing one row in the table. The best way to explain this is an example:
1 2 3 4 5 6 7 |
//store the data, we want to update, into an array $data[] = [ 'productId' => 'xxxxx', 'weight' => 1 ]; $data[] = [ 'productId' => 'aaaaa', 'weight' => 2 ]; $data[] = [ 'productId' => 'bbbbb', 'weight' => 3 ]; //pass the array to the update method of product repository $this->productRepository->update($data, $context); |
Of course we need to keep in mind, that we have to provide an identifier for each row, that we want to update, in our example a product ID.
Deleting the data from the repository
If you want to delete some items from the repository, just send the array of IDs to its delete method. Example:
1 2 3 4 5 6 7 |
//store the IDs of the rows, that we want to delete, as an array $data[] = [ 'productId' => 'xxxxx' ]; $data[] = [ 'productId' => 'aaaaa' ]; $data[] = [ 'productId' => 'bbbbb' ]; //pass the array to the delte method of product repository $this->productRepository->delete($data, $context); |
More information and links
Hopefully, this introduction to repositories in Shopware 6 was helpful to you in grasping the concept. For more information, I recommend these chapters from the official Shopware 6 documentation:
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/creating-entities-dal
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/reading-entities-dal
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/updating-entities-dal
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/deleting-entities