Квест → Как хакнуть форму
Прошли: 77
Я хочу поговорить о пространствах имен для сервисов в Symfony, специфичное для Symfony3.

Это захватывающие времена, Symfony 4 уже на подходе — выходит 30-го ноября — так что этот пост может стать неактуальным в ближайшее время! Тем не менее концепт всё тот же, так что давайте взглянем на него!
В последнее время, общаясь со своей командой в SlowCode, мы определили общий способ создания сервисов.
Любой сервис, который обеспечивает логику приложения, будет находиться в папке App\Service. Таким образом, все аккуратно, и все разработчики в команде знают, где их найти.
Следующий слой — это доменное имя. Это опять же, чтобы обеспечить порядок. Возможно, вы так не думаете, но когда вы в конечном итоге работаете с 8-ю доменными именами, в каждом из которых по 2-3 сервиса, то всё может стать запутано, если оно не аккуратно :)
Например, если у нас есть сервис, который имеет отношение к остаткам (Stock) под названием StockAvailability, то её название вместе с пространством имен будет AppBundle\Service\Stock\StockAvailability.
Идентификатор сервиса должен быть разделён точкой ('.') по названию папок и подчёркиванием ('_'), если в названии — папки или сервиса — больше, чем одно слово.
Так, в предыдущем примере, мы задали бы все это дело вот так:
services:
app.service.stock.stock_availability:
class: AppBundle\Service\Stock\StockAvailability
arguments:
- '@doctrine.orm.entity_manager'
...
В последнее время в Symfony 3.3, был принят новый способ определения сервиса.
Теперь лучше задать идентификатор сервиса через FQCN (полное название класса с пространством имён). Итак, вместо того, как задавали мы его раньше, мы можем это сделать так:
services:
AppBundle\Service\Stock\StockAvailability:
public: true
arguments:
- '@doctrine.orm.entity_manager'
...
Задав его таким способом, вы по-прежнему можете достать сервис из сервис-контейнера (с новым идентификатором, конечно, – с полным имением класса):
use AppBundle\Service\Stock\StockAvailability
public function fooAction(Request $request)
{
// до Symfony 3.3 вы получали бы её так
// $stockService = $this->get('app.service.stock.stock_availability');
// В Symfony 3.3 вы можете получить сервис так
// (Это возможно, только если вы объявлили свой сервис как публичный)
$stockService = $this->get(StockAvailability::class);
}
Как следует из официальной страницы Symfony, хорошей практикой является объявление ваших сервисов закрытыми (приватными), а не публичными, а затем внедрять (инджектить) любые сервисы, которые могут понадобиться внутри контроллера, а не получать их из сервис-контейнера (аналогично инъекции зависимостей внутри сервисов), например:
use AppBundle\Service\Stock\StockAvailability
public function fooAction(Request $request, StockAvailability $stockService)
{
// now we have it injected into our variable $stockService
// so we don't need to get it from the container
}
Итак, я думаю, что идентификатор с полным именем класса, вместо изобретенной номенклатуры — это хорошо. По крайней мере, больше не будет путаницы среди различных разработчиков из команды.
О приватных/публичных сервисах. Я понимаю, куда Symfony "клонит", и я думаю, что ограничение использовать ‘инъекции’ вместо ‘получения’ делает код более надежным, и, вероятно, более читаемым, в конце концов. Однако, я все же думаю, есть и плюсы у подхода, использовавшегося до 3.3 версии. Получение сервисов из контейнера является очень полезным, и обеспечивает гибкость и скорость.
Я думаю, что, поскольку по-прежнему можно объявить сервис публичным, это я и буду делать... что вы будете делать?
Подробнее здесь:
Symfony service container
Symfony 3.3 best practices
Symfony class for service id