Вопрос: Отделение бизнес логики от фреймворка Symfony?

Лучший ответ:
Генератор — просто инструмент для помощи, по итогу сущности чисты, не считая аннотаций/атрибутов для маппинга в ORM,  но это просто мета-информации и завязка не существенна (не считая маленького компромисса с ArrayCollection). То есть если вы выберите др ORM, то эти аннотации вам не помешают никак, просто лишние заюзанные классы аннотаций

Имея сущности доктрины — у нас не связанный от фреймворка код, пишите спокойно бизнесуху, не обращая внимания на то, как оно потом маппится. То есть практически все по каннонам

Чтобы отделить репозиторий от домена — просто в домене делайте интерфейс, а вот реализация этого репозитория будет в Infrastrucure Layer, но это избыточно... риск минимальный, если сделаете не совсем по канону, а именно риск стоит как основной аргумент такового отделения (не просто же вы словам следуете, а причину понимаете?)
Разработка строится на компромисах, если смените доктрину на др ORM — так и так писать новые репозиторий, вероятность низкая и многие например не делают такие интерфейсы — слишком усложнит код...
Вам надо будет просто репозиторий в маппинге ORM\Repository заменить в таком случае

Некоторые компании пишут интерфейсы и сильно усложняют код, но тк риск минимальный изменений, то такое усложнение приводит как правило к усложнению и не более. Следуйте здравому смыслу.
Мой довод нельзя раскручивать "ну раз минимальный, то завяжусь по полной". Все же отделение логики надо делать

чтобы все же соблюсти эту чистоту 
и не сильно усложнить, то можно систему разбить на модули/фичи
и каждый модуль будет иметь такие слои
почему лучше это сделать:
- реализация репозиториев хоть и инфраструктурная, но правится часто при изменении домена, а значит сильно далеко прятать не вариант, иначе сильно все будет размазано... потому модуль делают трехслойным (инфра, домен и апликейшн слой)
пример


Худший ответ:
условно вам не нужно больше писать в коде свой query builder, вы делегируете это интерфейсу репозитория. У каждой сущности свой интерфейс репозитория, не нужно писать общий интерфейс для всех сущностей. 

Например, если в коде у вас было:
$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());
    }
}