Aleksandr Khristenko
Подскажите, я туплю и чего-то не могу понять. Есть интерфейс, и 2 реализации интерфейса. Для одной из реализации объявлен алиас. Определяю третий сервис в виде App\C: class: App\C arguments: $a: '@correct_implementation' Все работает правильно. Убираю arguments из кода выше и добавляю следущий код в сервис: public function __construct( #[Target('correct_implementation')] private AInterface $a ) { } все перестает работать, говорит что не знает какую из реализаций интерфейса надо поставить Почему оно может не обрабатывать Target в таком случае?
Aleksandr Khristenko
Возможно таргет срабатывает для автовайринга, в доке написано именно про автовайринг . Когда же вы убираете только attributes, но оставляете объявление сервиса, то берутся настройки только из service.yml а не из обоих мест сразу с частичным оверрайдом. Но это чисто предположение
Не, там автовайринг глобально включен. Короче после изучения исходников я вообще в ступоре. С точки зрения кода #[Target('correct_implementation')] private AInterface $a просто равнозначно private AInterface $correctImplementation
Aleksandr Khristenko
И как оно вообще может работать как описано в доке вообще непонятно.
Павел
Не, там автовайринг глобально включен. Короче после изучения исходников я вообще в ступоре. С точки зрения кода #[Target('correct_implementation')] private AInterface $a просто равнозначно private AInterface $correctImplementation
Так я о чем говорю, что таргет для автовайринга (когда сервис не описан в service yml), а у вас он описан. Уберите не только arguments а весь сервис из service yml.
Aleksandr Khristenko
Так я о чем говорю, что таргет для автовайринга (когда сервис не описан в service yml), а у вас он описан. Уберите не только arguments а весь сервис из service yml.
Вы путаете autowiring и service discovery. И первое работает в зависимости от того, включен ли флаг автовайринга глобально или локально дла сервиса.
Павел
Вы путаете autowiring и service discovery. И первое работает в зависимости от того, включен ли флаг автовайринга глобально или локально дла сервиса.
Может и путаю, а может и нет. По логике все логично. Если сервис описан в yml то настройки di берутся из него (а у вас он описан и там нет описания имплементации т.е. Аргументов ), если не описан - то берутся данные из конструктора и соответственно атрибутов через рефлексию. Попробовать же не долго)
Павел
Автовайринг - это автоматическое определение завимостей, так что вроде я не путаю
Павел
@ibxth Разобрался кажется. Target не про альясы, а про variable name binding
Aleksandr Khristenko
Цитата из доки просто: Another possibility is to use the #[Target] attribute. By using this attribute on the argument you want to autowire, you can define exactly which service to inject by using its alias.
Павел
Т.е. в target указывается имя переменной, которая уже есть в DI именно имя. Например в примере стоит githubApi. Это говорит не что альяс githubApi а что в DI забинжена переменная githubApi
Павел
Павел
Павел
Вот так работает
Павел
И в доке написано жирным именно про variable name , меня это и навело на это
Павел
И что есть еще #[Autowire] отдельно
Павел
Павел
Первый скрин это bind раздел
Aleksandr Khristenko
Да хер разберешь, но я протестил
Ну вот если у меня есть interface ProviderInterface {} class ProviderA implements ProviderInterface {} class ProviderB implements ProviderInterface {} class JobService { public function __construct(ProviderInterface $prodived) {}} и в сервисах есть correct_provider: alias: App\ProviderA как мне составить Target чтобы оно подхватило?
Павел
Павел
$shoutyTransformer
Aleksandr Khristenko
Значит дока говно =\
Павел
Только я делал в разделе bind а не просто в сервисе
Павел
Павел
Опять же можно если php config название альяса/переменной вывести в константу например
The Ant
та ну хз, сегодня она константа, а завтра будешь по всему коду рыскать где эту константу поменять. Либо тесты писать на каждое применение :D
Павел
Плюс искать так проще чем по вхождению текста
Павел
Ну т.е. что то типа #[Target(DiVariables:apiMailer)]
Павел
Но в целом мутная история, но наверное все равно лучше чем через название параметров
The Ant
лучше явно биндить в конфиге через $service->set(Foo::class) ->arg('$bar', service('@bar');
The Ant
или чето другое закинуть по агрументу
Павел
Ты биндишь 1 сервис, там и переменная не нужна
The Ant
нужна, порядок может поменяться
Павел
нужна, порядок может поменяться
Так использование совсем другое, я не много про другое "не нужна"
Павел
Ты сервис конфигурируешь, а это конфигурация всего приложения
The Ant
ну я пишу что лучше избегать этого глобала
Павел
Например есть 2 сервиса которые используются 100 раз под 1 интерфейсом в каждом экшене контрорллера почти
Павел
Будешь каждый контроллер конфигать ручками?
The Ant
🤷‍♂️ кому как бегать потом переименовывать, биндить таргетно с той же переменной проблематично
Павел
зато явно
Но это не удобно. Ровно так же неудобно как потом при каком то рефакторинге эти же 100 сервисов в DI рефачить
Павел
Например тот же Target более чем явно
The Ant
Например есть 2 сервиса которые используются 100 раз под 1 интерфейсом в каждом экшене контрорллера почти
положу под интерфейс наиболее используемое ) а в отдельных случаях вручную задам
Павел
положу под интерфейс наиболее используемое ) а в отдельных случаях вручную задам
Это если есть такая возможность, а если 50 на 50 или ты еще не знаешь какой будет более частым
The Ant
тогда ручками :D
Павел
КОроче че спорить, есть возможность, юзать или нет дело каждого. Но соглашусь что механимз ненадежный
Aleksandr Khristenko
Ладно, другой вопрос, может у меня какое-то альтернативное понимание английского. Но ведь вы тоже строчку Another possibility is to use the #[Target] attribute. By using this attribute on the argument you want to autowire, you can define exactly which service to inject by using its alias. понимаете как возможность заавтовайрить нужный сервис используя его алиас?
Aleksandr Khristenko
Вопрос не в том, что они подразумевают, а как вы понимаете эту строчку.
Павел
Ну я понял как алиас симфони
Aleksandr Khristenko
Ну я понял как алиас симфони
Ну т.е. определяем alias для сервиса и его используем, типа как я в коде выше и сделал?
Павел
Чтобы у вас заработало, надо для каждой имплементации создать биндинг на переменную, и использовать имя переменной
Aleksandr Khristenko
>_<
Aleksandr Khristenko
Да мне уже пофиг как нужно сделать, чтобы оно работало. Мне инетерсно, как люди понимают эту строчку документаци. Т.к. в моем понимании сейчас - документация врет.
Павел
С другой стороны если вчитаться, там много где написано про name
Павел
You must use the interface as the type-hint and the autowiring alias (githubApi) as the variable name:
Aleksandr Khristenko
Чтобы у вас заработало, надо для каждой имплементации создать биндинг на переменную, и использовать имя переменной
А тут я вообще смысл не вижу, зачем добавлять таргет чтобы можно было писать #[Target('another_name')] Interface $name, вместо Interface $anotherName
Павел
Т.е. это скорее для тех, кто это юзает и им плюшечка
Aleksandr Khristenko
Чтобы код (а конкретно названия переменных) не подстраивать под di
Код в таком случае все равно подстраивается, просто через аттрибут.
Павел
Код в таком случае все равно подстраивается, просто через аттрибут.
Но можно выбрать любую переменную а главное ее рефачить споокойно
Павел
Эм, не понял.
ну например сделано много каналов логгера и чтобы их использовать через name binding надо везде писать $fooLogger и нельзя поменять название параметра в конструкторе
Павел
А с учетом constructor property promotion это название еще дальше и в код лезет
Павел
И т.е. теперь нейминг в любой части приложения зависит от переменной в di и ломается от любого чиха связанной с именем переменной
Aleksandr Khristenko
А с учетом constructor property promotion это название еще дальше и в код лезет
Ну т.е. public function __construct(#[Target('some_name') private I $name) {} просто сахар для private I $name; public function __construct(I $someName) { $this->name = $someName; } ?
The Ant
Эм, не понял.
ну т.е. это это штука чтоб писать переменную как есть ) т.е. описанный тобою кейс до атрибутов надо биндить в переменную обязательно, а тут нет
Павел
Особенно опасно, если кто то забыл не знал и переименовал переменную в конструкторе и прицепилась дефолтная реализация, в случае с Target - тут всё явно