Answer the question
In order to leave comments, you need to log in
Separating business logic from the Symfony framework?
Hi all. Just discovering the "correct" design of software architecture, and began to write a pet project for which I chose pure architecture as the basis. Uncle Bob writes that the framework is a detail and his idea is clear, but when in practice I began to separate the business layer from the infra layer, I fell into a stupor a little. That is, for example, in the context of development on a symphony, how can entities and repositories be separated from the symphony itself? We no longer have the right to generate them. How to proceed in this case? Write your implementations? Please clarify this topic.
Answer the question
In order to leave comments, you need to log in
The generator is just a tool to help, as a result, the entities are clean, apart from annotations / attributes for mapping in the ORM, but this is just meta-information and the plot is not significant (apart from a small compromise with ArrayCollection). That is, if you choose another ORM, then these annotations will not interfere with you in any way, just extra used annotation classes.
Having the essence of the doctrine - we have code that is not related to the framework, write calmly to the business, not paying attention to how it is then mapped. That is, almost everything according to cannons
To separate the repository from the domain - just make an interface in the domain, but the implementation of this repository will be in the Infrastrucure Layer, but this is redundant ... the risk is minimal if you do it not quite according to the canon, namely the risk is the main argument for such a separation (not just do you follow the words, but do you understand the reason?)
Development is based on compromises, if you change the doctrine to another ORM - write new repositories this way and that, the probability is low and many, for example, do not make such interfaces - it will complicate the code too much ...
You will just need a repository in the ORM\Repository mapping, replace in this case.
Some companies write interfaces and greatly complicate the code, but since the risk of changes is minimal, such complication usually leads to complication and no more. Follow common sense.
My argument cannot be untwisted "well, if it's minimal, then I'll tie up in full." Nevertheless, the separation of logic must be done
in order to still maintain this purity
and not greatly complicate it, then the system can be divided into modules / features
and each module will have such layers
why it is better to do this:
- the implementation of the repositories, although infrastructural, is often corrected when changing the domain , which means that hiding too far is not an option, otherwise everything will be very smeared ... because the module is made three-layer (infra, domain and application layer)
conditionally, you no longer need to write your own query builder in the code, you delegate this to the repository interface. Each entity has its own repository interface, there is no need to write a common interface for all entities.
For example, if in your code you had:
$companyEmployees = $entityManager
->createQueryBuilder()
->where('companyId = :company')
->where('active = true')
->fetchCollection();
interface CompanyRepository {
public function getActiveEmployees(): array;
}
class DoctrineCompanyRepository implements CompanyRepository {
public function getActiveEmployees()
{
return $entityManager
->createQueryBuilder()
->where('companyId = :company')
->where('active = true')
->fetchCollection();
}
}
class EloquentCompanyRepository implements CompanyRepository {
public function getActiveEmployees()
{
return Company::where()->where()->get();
}
}
class MockCompanyRepository implements CompanyRepository {
public function getActiveEmployees()
{
return [new Employee($name, $position), new Employee($name2, $position2)];
}
}
class SqlCompanyRepository implements CompanyRepository {
public function getActiveEmployees()
{
return Db::query('select * from company_employees t where t.company_id = :id and ...')->fetchAll();
}
}
class CompanyController
{
public function fireAllAction()
{
$companyService = new CompanyService(new DoctrineCompanyRepository());
...
}
}
class CompanyServiceTest
{
public function testFireAllMethod()
{
$companyService = new CompanyService(new MockCompanyRepository());
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question