Symfony Dependency Injection XML to YAML - symfony

How i can define service look like this in YAML pattern?
XML:
<service id="my_service" class="MyClass">
<!-- XML FORMAT NO NEED TO DEFINE THIS ARGUMENT IN OTHER SERVICE -->
<argument type="service">
<service class="OtherFacotryServiceClass" factory-service="other_facoty_service" factory-method="get">
<argument>other_service_param</argument>
</service>
</argument>
</service>
This will output in PHP: (in a container dump)
protected function getMYServiceService()
{
return $this->services['my_service'] = new \MyClass($this->get('other_facoty_service')->get('other_service_param'));
}
EDITED: Full (long) yaml definition.
services:
an_other_service:
public: false
class: OtherFacotryServiceClass
factory_service: other_facoty_service
factory_method: get
arguments: [other_service_param]
my_service:
class: MyClass
arguments: [#an_other_service]
How i can define similar XML like:
services:
# THIS'S WRONG FORMAT!!
my_service:
class: MyClass
arguments:
-
class: OtherFacotryServiceClass
factory_service: other_facoty_service
factory_method: get
arguments: [other_service_param]

In your services.yml
services:
my_service_factory:
class: OtherFactoryServiceClass
my_service:
class: MyClass
factory_service: my_service_factory
factory_method: get
arguments: [other_service_param] # arguments are injected in "OtherFactoryServiceClass::get"
Source

Related

Symfony 4 - Convert XML to YAML

I'm trying to install FosMessageBundle, without FosUserBundle.
For that, in the doc, we have to create a new service and use it into our services.yaml file
But in the doc, their declaration is in XML, and I can't translate him to YAML:
<!-- app/config/services.xml -->
<service id="app.user_to_username_transformer" class="AppBundle\Form\DataTransformer\UserToUsernameTransformer">
<argument type="service" id="doctrine" />
</service>
<service id="fos_user.user_to_username_transformer" alias="app.user_to_username_transformer" />
I tried this :
app.user_to_username_transformer:
class: 'App\Form\DataTransformer\UserToUsernameTransformer'
arguments:
type: "service"
id: "doctrine"
fos_user.user_to_username_transformer:
alias: "app.user_to_username_transformer"
But I don't know if it's good
in yaml a service type="service" is prefixed with #. So your xml definition translates to
app.user_to_username_transformer:
class: App\Form\DataTransformer\UserToUsernameTransformer
arguments:
- '#doctrine'
fos_user.user_to_username_transformer:
alias: "#app.user_to_username_transformer"
More details in the docs
But if you have autowire configured and your argument is typehinted properly with Doctrine\Bundle\DoctrineBundle\Registry all you need is to alias your transformer
fos_user.user_to_username_transformer:
alias: "#App\Form\DataTransformer\UserToUsernameTransformer"

Service not recognized by Symfony

I have a concern with the following service in my project:
app.security.guardAuthenticatorLoginPassword:
class: AppBundle\Security\LoginPasswordAuthenticator
arguments: ["#router"]
app.jwt_token_authenticator:
class: AppBundle\Security\JwtAuthenticator
arguments: ['#doctrine.orm.entity_manager', '#lexik_jwt_authentication.encoder']
I feel that whatever I do it is not recognized by my program ..
I have been looking for a few hours already but I do not understand why it does not work. While I have both my LoginPasswordAuthenticator and JwtAuthenticator classes in the specified path ..
Thank you in advance for your help
Here is some potentials issues:
_ Clear the cache
_ Check if you didn't forget a 'use' for your differents classes
_ Give to your services a name (and why not an alias) and use it when you call your service:
app.security.guardAuthenticatorLoginPassword:
class: AppBundle\Security\LoginPasswordAuthenticator
arguments: ["#router"]
tags:
- { name: login.password.authenticator, alias: login.auth }
app.jwt_token_authenticator:
class: AppBundle\Security\JwtAuthenticator
arguments:['#doctrine.orm.entity_manager','#lexik_jwt_authentication.encoder']
tags:
- { name: security.authenticator, alias: security.auth }

How do I override the first argument of a parent service in yaml?

From monolog.xml:
<service id="monolog.logger" parent="monolog.logger_prototype" public="false">
<argument index="0">app</argument>
</service>
<service id="logger" alias="monolog.logger" />
<service id="monolog.logger_prototype" class="%monolog.logger.class%" abstract="true">
<argument /><!-- Channel -->
</service>
How do I accomplish the same overriding of the 0th argument in Yaml?
My colleague created a bundle that allows you to easily convert from XML to YML and it came up with:
services:
monolog.logger:
public: false
arguments: { index_0: app }
monolog.logger_prototype:
class: %monolog.logger.class%
arguments: ['']
logger: #monolog.logger
Never would have guessed that.
One of defining logger with custom channel as service way:
# app/config/config.yml
monolog:
channels: [custom_channel]
When in a controller:
$logger = $this->get('monolog.logger.custom_channel');
or when defining a service:
services:
app.logger.custom_channel:
parent: monolog.logger.custom_channel

Symfony 2: Creating a service from a Repository

I'm learning Symfony and I've been trying to create a service, using a repository.
I've created my repositories and entities from generate:entity, so they should be fine.
So far what I got in my services.yml is:
parameters:
mytest.entity: TestTestBundle:Brand
mytest.class: Test\TestBundle\Entity\Brand
default_repository.class: Doctrine\ORM\EntityRepository
services:
myservice:
class: %default_repository.class%
factory-service: doctrine.orm.default_entity_manager
factory-method: getRepository
arguments:
- %mytest.entity%
But when I try to call the service, I get this error:
Catchable Fatal Error: Argument 2 passed to Doctrine\ORM\EntityRepository::__construct() must be an instance of Doctrine\ORM\Mapping\ClassMetadata, none given, called in
Then I tried to create the service just using an entity. My services.yml would look like:
services:
myservice:
class: %mytest.class%
factory-service: doctrine.orm.default_entity_manager
factory-method: getRepository
arguments:
- %mytest.entity%
But for this, I get:
Error: Call to undefined method
Test\TestBundle\Entity\Brand::findAll
Does anybody know what am I doing wrong?
Thanks
DEPRECATION WARNING: No more factory_service and factory_method. This is how you should do it since Symfony 2.6 (for Symfony 3.3+ check below):
parameters:
entity.my_entity: "AppBundle:MyEntity"
services:
my_entity_repository:
class: AppBundle\Repository\MyEntityRepository
factory: ["#doctrine", getRepository]
arguments:
- %entity.my_entity%
The new setFactory() method was introduced in Symfony 2.6. Refer to older versions for the syntax for factories prior to 2.6.
http://symfony.com/doc/2.7/service_container/factories.html
EDIT: Looks like they keep changing this, so since Symfony 3.3 there's a new syntax:
# app/config/services.yml
services:
# ...
AppBundle\Email\NewsletterManager:
# call the static method
factory: ['AppBundle\Email\NewsletterManagerStaticFactory', createNewsletterManager]
Check it out: http://symfony.com/doc/3.3/service_container/factories.html
Here is how we did it in KnpRadBundle: https://github.com/KnpLabs/KnpRadBundle/blob/develop/DependencyInjection/Definition/DoctrineRepositoryFactory.php#L9
Finally it should be:
my_service:
class: Doctrine\Common\Persistence\ObjectRepository
factory_service: doctrine # this is an instance of Registry
factory_method: getRepository
arguments: [ %mytest.entity% ]
UPDATE
Since 2.4, doctrine allows to override the default repositor factory.
Here is a possible way to implement it in symfony: https://gist.github.com/docteurklein/9778800
You may have used the wrong YAML-Keys. Your first configuration works fine for me using
factory_service instead of factory-service
factory_method instead of factory-method
Since 2017 and Symfony 3.3+ this is now much easier.
Note: Try to avoid generic commands like generate:entity. They are desined for begginers to make project work fast. They tend to bare bad practises and take very long time to change.
Check my post How to use Repository with Doctrine as Service in Symfony for more general description.
To your code:
1. Update your config registration to use PSR-4 based autoregistration
# app/config/services.yml
services:
_defaults:
autowire: true
Test\TestBundle\:
resource: ../../src/Test/TestBundle
2. Composition over Inheritance - Create own repository without direct dependency on Doctrine
<?php
namespace Test\TestBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
class BrandRepository
{
private $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(Brand::class);
}
public function findAll()
{
return $this->repository->findAll();
}
}
3. Use in any Service or Controller via constructor injection
use Test\TestBundle\Repository\BrandRepository;
class MyController
{
/**
* #var BrandRepository
*/
private $brandRepository;
public function __construct(BrandRepository $brandRepository)
{
$this->brandRepository = $brandRepository;
}
public function someAction()
{
$allBrands = $this->brandRepository->findAll();
// ...
}
}
I convert service.yml to service.xml, and update DependencyInjection Extension, everything is working for me. I don't know why, but yml config will thrown Catchable Fatal Error. You can try using xml config for service config.
service.yml:
services:
acme.demo.apikey_userprovider:
class: Acme\DemoBundle\Entity\UserinfoRepository
factory-service: doctrine.orm.entity_manager
factory-method: getRepository
arguments: [ AcmeDemoBundle:Userinfo ]
acme.demo.apikey_authenticator:
class: Acme\DemoBundle\Security\ApiKeyAuthenticator
arguments: [ "#acme.demo.apikey_userprovider" ]
service.xml:
<services>
<service id="acme.demo.apikey_userprovider" class="Acme\DemoBundle\Entity\UserinfoRepository" factory-service="doctrine.orm.entity_manager" factory-method="getRepository">
<argument>AcmeDemoBundle:Userinfo</argument>
</service>
<service id="acme.demo.apikey_authenticator" class="Acme\DemoBundle\Security\ApiKeyAuthenticator">
<argument type="service" id="acme.demo.apikey_userprovider" />
</service>
</services>
Symfony 3.3 and doctrine-bundle 1.8 there is a Doctrine\Bundle\DoctrineBundle\Repository\ContainerRepositoryFactory
which helps to create repository as service.
Example
What we want
$rep = $kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(Brand::class);
ORM description
# Brand.orm.yaml
...
repositoryClass: App\Repository\BrandRepository
...
Service description
# service.yaml
App\Repository\BrandRepository:
arguments:
- '#doctrine.orm.entity_manager'
- '#=service("doctrine.orm.entity_manager").getClassMetadata("App\\Entity\\Brand")'
tags:
- { name: doctrine.repository_service }
calls:
- method: setDefaultLocale
arguments:
- '%kernel.default_locale%'
- method: setRequestStack
arguments:
- '#request_stack'
sf 2.6+
parameters:
mytest.entity: TestTestBundle:Brand
mytest.class: Test\TestBundle\Entity\Brand
default_repository.class: Doctrine\ORM\EntityRepository
services:
myservice:
class: %default_repository.class%
factory: ["#doctrine.orm.default_entity_manager", "getRepository"]
arguments:
- %mytest.entity%

Inject SwiftMailer into symfony2 service

I have a service which extends UserManager, so when I do:
$message = \Swift_Message::newInstance()
->setSubject('~')
->setFrom('~')
->setTo('~')
->setBody('~', 'text/html');
$this->get('mailer')->send($message);
I get the error:
Fatal error: Call to undefined method My\MyBundle\Service\ServiceClass::get()
I know this is because I need to inject the swiftmailer into here, but how?
(usually the service class extends 'Generic' so the swift mailer is included.)
Depending on what kind of service file you are using you need to inject it into your service directly like you said.
XML:
<services>
<service id="sample.service" class="%sample.service.class%">
<argument type="service" id="mailer" />
</service>
</services>
YAML:
services:
sample.service:
class: %sample.service.class%
arguments: [#mailer]
You can simply grab the service in your constructor like this.
Or if you really want, you can inject the service_container. But that's really dirty, since you can just inject the services you need.
Injection the service_container is only needed if you need a dynamic service call.
In services.yml (symfony 4 example)
mailer:
class: \Swift_Mailer
myClass:
class: x\x
arguments:
- "#mailer"

Resources