F
F
fman22018-12-11 20:32:06
PHP
fman2, 2018-12-11 20:32:06

Interaction of several repositories. How to merge?

Hello.
I have something like this in my system:


shop/
--entity/
------Product.php
------ProductType.php
------Category.php
--repository/
------ProductRepository.php
---- --CategoryRepository.php
------ProductTypeRepository.php
.... and more....

interface CategoryRepositoryInterface
{
     public function findOne($id): CategoryInterface;
     public function findAll(): array;
     public function save(CategoryInterface $category);
     public function remove(CategoryInterface $category);
}

interface ProductRepository
{
   // .... все тоже самое, что и у CategoryRepositoryInterface
}

Product consists of two additional parts (greatly simplified, the entity with the product is quite thick):
interface Product
{
     public function addCategory(CategoryInterface $category);

     public function setProductType(ProductTypeInterface $productTypeInterface);
}

And here several problems arise.
First, in the ProductRepository, you need to collect a product from all other repositories and return a product with all dependencies (product type, category, images, licenses, etc.) via findOne(). It turns out that ProductRepository depends on other repositories (Category, ProductType, Image, File....).
When a category is deleted via $categoryRepository->remove(), the products are also deleted (the business logic for deletion is tied there). It turns out hell, the repository with categories depends on the product. And the product repository depends on the category repository and a few other repositories. And then I got dependency-hell.
In the client code, everything should be simple:
$productRepository->findOne(100); // вжух и мы получили товар со всеми зависимостями и ИД 100.

Now the main question is how to collect a product (or other entity) from different pieces?
Now I call the corresponding methods of the other parts' repositories in the findOne() method of the repository. I feel that this is wrong, but how to be? What are your practices when an entity is assembled from different pieces?
How to handle the $productRepository->save($product) method if different pieces of a product are saved differently. Right now I'm pulling individual repositories into a transaction right from the save () method and saving them. Is it correct?
What about scaling if something else comes up in the future?

Answer the question

In order to leave comments, you need to log in

4 answer(s)
A
Alexander Makarov, 2018-12-12
@fman2

It turns out that ProductRepository depends on other repositories (Category, ProductType, Image, File....).
This is how you do it. It may or may not depend. I would not tie one to the other. Let there be a similar code ... that's okay.
Hands.
Individually. Hands.
Or take ORM or, again, by hand. Do not be afraid to write code and do not be afraid of duplicating it within reasonable limits. Not everything is DRY what they think.

N
nicandr, 2018-12-12
@nicandr

Maxim Fedorov wrote you correctly, you need another layer that will interact with your repositories, in symphony, as in any other framework, all logic should be in the service. From your description, you have made a facade pattern so that everything is simple in the client code. For this, a service is suitable, which can also inherit (implement) the interface.

interface CategoryRepositoryInterface
{
     public function findOne($id);
     public function findAll(): array;
     public function save(CategoryInterface $category);
     public function remove(CategoryInterface $category);
}
class CustomNameOfClass implements CategoryRepositoryInterface // ну тут имя лучше изменить
{
      public function findOne($id){};  // тут тоже лучше иметь return type
     public function findAll(){}: array;
     public function save(CategoryInterface $category){}; // тут тоже лучше иметь return type
     public function remove(CategoryInterface $category){}; // тут тоже лучше иметь return type
}

So it will be the same as now with you, only the repositories work separately, and the service layer combines them with your logic. Repositories should not be aware of the existence of other repositories.
Since you have several repositories, create a DTO and throw all the data after they are converted into a DTO, so you will have one standard object on which you can perform further logic.

D
dmitriy, 2018-12-12
@dmitriylanets

And why not assign work with links to ORM?

V
Viktor Mamonov, 2018-12-12
@masev

I don't know how good it is architecturally. Alternatively, you can add getter methods or modifier methods to the Product entity that will pull the necessary repositories.

$product = $productRepository->findOne(100);
$product->getCategories(); // Здесь по принципу lazy load ищем в нужном репозитории
$product->removeCategories();

As a result, it is possible to communicate with the necessary repositories along the chain.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question