I got a problem like this
I got a service to inject doctrine and use the entity manager to insert a user record into database: UsersService.php
And i got a service to send email: MyEmailService.php
All both services injected in the services.yml(follow this docs http://symfony.com/doc/current/book/service_container.html). All of them work fine.
So now my problem is: I have a class call UserFacade.php(not extends any controller). It has a method "addUser". In this function it will call to UserService.php to insert a record into database, then call the MyEmailService.php to send an email to user's email.
How can i do that in Symphony? I'm the newbie with bundle in Symphony.
Please help
Thanks
First you have to declare your dependencies in the constructor of the UserFacade class. This is one way to allow symfony to inject the dependencies:
class UserFacade
{
/** #var UserService */
private $userService;
/** #var EmailService */
private $emailService;
public function __construct(UserService $userService, MyEmailService $emailService)
{
$this->userService = $userService;
$this->emailService = $emailService;
}
public function addUser(User $user)
{
$this->userService->add($user);
$this->emailService->sendUserMail($user, ...);
}
}
Then you have to declare the dependencies in your service.yml (assuming your using YAML, XML is quite similar):
services:
user_service:
class: UserService
...
email_service:
class: EmailService
...
user_facade:
class: UserFacade
arguments: [#user_service, #email_service]
And then use the facade in your controller:
class UserController
{
public function addUserAction(Request $request)
{
// Do stuff with Request to populate the $user object
$this->get('user_facade')->addUser($user);
}
}
You have to register your UserFacade class as a service, inject into it UserService (and MyEmailService). Then call UserService and MyEmailService from UserFacade service as a property:
$this->userService-><methid>
// and so on
Related
I have a repository class called EmailRepository
class EmailRepository extends EntityRepository implements ContainerAwareInterface { ... }
I need to get a parameter injected into this repository class but I dont know how...
This is what I currently have inside of the repository, which is being called from my controller:
Controller:
$em->getRepository(Email::class)->getEmailApi();
Repository
class EmailRepository extends EntityRepository implements ContainerAwareInterface {
protected $container;
public function setContainer(ContainerInterface $container = null) {
$this->container = $container;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
echo $this->container->getParameter('email_api');
}
}
I always get this error:
Call to a member function getParameter() on null
The parameter is not null, it does have a value. I know it's telling me that $this->container is null. How do I fix this?
If I run this inside of my controller, it works fine and returns Google
echo $this->getParameter('email_api');
Inject container not a good idea. Try this
services.yaml
App\Repository\EmailRepository:
arguments:
$emailApi: '%env(EMAIL_API)%'
Repository
class EmailRepository
{
protected $emailApi;
public function __construct(string $emailApi)
{
$this->emailApi = $emailApi;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
return $this->emailApi;
}
}
Or via setter injection
services.yaml
App\Repository\EmailRepository:
calls:
- method: setEmailApi
arguments:
$emailApi: '%env(EMAIL_API)%'
Repository
class EmailRepository extends EntityRepository implements ContainerAwareInterface
{
protected $emailApi;
public function setEmailApi(string $emailApi)
{
$this->emailApi = $emailApi;
}
/**
* #param $array
*/
public function getEmailApi($array)
{
return $this->emailApi;
}
}
Your original code is not going to work because there is nothing calling EmailRepository::setContainer. Furthermore, using ContainerAware and injecting the full container is discouraged.
Fortunately, the Doctrine bundle has a new base repository class that the entity manager can use to pull the repository from container and allow you to inject additional dependencies as needed. Something like:
namespace App\Repository;
use App\Entity\Email;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class EmailRepository extends ServiceEntityRepository // Different class to extend from
{
private $emailApi;
public function __construct(RegistryInterface $registry, ParameterBagInterface $parameterBag)
{
parent::__construct($registry, Email::class);
$this->emailApi = $parameterBag->get('email_api');
}
So in this case we inject all the parameters and then store the ones we need.
Even injecting the parameter bag is a bit frowned upon. Better to inject individual parameters though this takes just a bit more configuration as we need to use services.yaml to explicitly inject the needed parameters:
public function __construct(RegistryInterface $registry, string $emailApi)
{
parent::__construct($registry, Email::class);
$this->emailApi = $emailApi;
}
#services.yaml
App\Repository\EmailRepository:
$emailApi: 'email_api_value'
I'm new in Symfony,
I try to use Dependency injection to get User in a service (i think)
services.yaml :
App\Service\Test\RESTAuthenticatedService:
calls:
- method: getTrigramme
arguments:
- '#security.token_storage'
In my RESTAuthenticatedService.php :
namespace App\Service\Test;
....
class RESTAuthenticatedService extends AbstractController {
protected $session;
private $user;
....
public function getTrigramme(){
$user = $this->token_storage->getToken()->getUser();
ERROR :
Notice: Undefined property: App\Service\Test\PrestataireService::$token_storage
Can you help me please ?
Ok, first thanks everyone now I try what you said and i have this error :
Too few arguments to function App\Service\Test\ClientService::__construct(), 0 passed in D:\www\Interface_SAT\src\Controller\RecherchePrestataires.php on line 60 and exactly 2 expected
In my Controller RecherchePrestataires.php I have :
.....
public function rechercher(Request $request) {
....
$recherchePresta = new PrestataireService();
In the file class PrestataireService I just have :
class PrestataireService extends ClientService {
In ClientService :
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class ClientService extends RESTAuthenticatedService
{
public $user;
public function __construct(SessionInterface $session, TokenStorageInterface $tokenStorage)
{
parent::__construct($session, $tokenStorage);
$this->setSession($session);
}
And in RESTAuthenticatedService : I've done :
public function __construct(SessionInterface $session, TokenStorageInterface $tokenStorage)
{
$this->token_storage = $tokenStorage;
Sorry , but i try so many things.
This seems that you didn't created the constructor in the class.
You have defined at your services.yaml that your class has a dependency, but you haven't done anything with that dependcy. You need to create the constructor and add the dependency as a parameter, and assign to a local variable.
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class RESTAuthenticatedService extends AbstractController
/**
* #var TokenStorageInterface
*/
private $token_storage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->token_storage = $tokenStorage;
}
}
Then you will be able to access $this->token_storage.
Edit: Change your services.yaml to inject the depenency in the constructor.
App\Service\Test\RESTAuthenticatedService:
class: App\Service\Test\RESTAuthenticatedService
arguments:
- '#security.token_storage'
I'm new in Symfony 2.
I have a function called "addNewTarjeta" in a personalized entity respository.
<?php
namespace Elkanogroup\ClientesBundle\Repository;
/**
* ClienteRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ClienteRepository extends \Doctrine\ORM\EntityRepository {
/**
* Asigna una tarjeta a este cliente.
*/
public function addNewTarjeta(Cliente $cliente) {
$tarjeta = new \Elkanogroup\ClientesBundle\Entity\Tarjeta();
$tarjeta->setNumeroTarjeta('5555 5555 5555 5555');
$tarjeta->setCliente($cliente);
$tarjeta->setFechaExpedicion(new \DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($tarjeta);
$flush = $em->flush();
if ($flush != null) {
return false;
}
return true;
}
I have a listener waiting for a doctrine event postPersist. I would like to call to "addNewTarjeta" from a postPersist function.
I'm trying to do something like this:
<?php
namespace Elkanogroup\ClientesBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Elkanogroup\ClientesBundle\Entity\Cliente;
use Elkanogroup\ClientesBundle\Repository\ClienteRepository;
class ClienteListener {
public function postPersist(Cliente $cliente, LifecycleEventArgs $args) {
$cliente->addNewTarjeta($cliente);
}
But it doesnt work. Symfony says:
Attempted to call an undefined method named "addNewTarjeta" of class
"Elkanogroup\ClientesBundle\Entity\Cliente".
Can anyone help me ?? Thanks and sorry for my bad english.
Everyone here says that you need to inject the entity manager but to me it's not true: you can retrive it from LifecycleEventArgs without inject anything.
Just do
$args->getObjectManager();
and you're done.
Just a note: usually repos are used to keep custom queries (via DQL or plain SQL or query builder). A logic like this should be fitted inside a service (a manager, helper or whatever).
As #dragoste said, you need to inject the entitymanager service into your listener.
It can be done in services.yml:
name.of.your.listener:
class: AppBundle\Listener\MyListener
arguments: ["#doctrine.orm.entity_manager"]
And then, add a public function __construct(\Doctrine\ORM\EntityManager $entityManager) method in your listener:
<?php
namespace AppBundle\Listener;
class MyListener
{
/**
* #var \Doctrine\ORM\EntityManager
*/
private $entityManager;
public function __construct(\Doctrine\ORM\EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
I am extending FOSAuthServerBundle and it has entities that are supermapped class and I need to extend them. Let's take one, AccessToken. When I extend AccessToken, I need all of its parent properties to be mapped in the database, such as $expiresAt and $scope but currently, they are not. Clearly, there is something I don't understand or am doing wrong.
Here's what I have in my own AccessToken yml:
OSC\OAuthServerBundle\Entity\AccessToken:
type: entity
id:
id:
type: integer
id: true
generator:
strategy: AUTO
manyToOne:
client:
targetEntity: Client
user:
targetEntity: Application\Sonata\UserBundle\Entity\User
lifecycleCallbacks: { }
Here's my Accesstoken php file:
<?php
namespace OSC\OAuthServerBundle\Entity;
use FOS\OAuthServerBundle\Document\AccessToken as BaseAccessToken;
use FOS\OAuthServerBundle\Model\ClientInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class AccessToken extends BaseAccessToken
{
/**
* #var integer
*/
protected $id;
protected $client;
protected $user;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getClient()
{
return $this->client;
}
public function setClient(ClientInterface $client)
{
$this->client = $client;
}
public function getUser()
{
return $this->user;
}
public function setUser(UserInterface $user)
{
$this->user = $user;
}
}
When I run php app/console doctrine:schema:update --force, the only fields that I have in my database are id, user_id and client_id. But I also need expiresAt and scope...
Here's what I have verified:
I am properly extending the FOSAuthServerBundle:
namespace OSC\OAuthServerBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class OSCOAuthServerBundle extends Bundle
{
public function getParent()
{
return 'FOSOAuthServerBundle';
}
}
The FOSOAuthServerBundle and OSCOAuthServerBundle are in the list of doctrine mappings in config.yml
I cleared the cache.
Is it normal that the fields are not mapped automatically ? Do I have to rewrite them all in the yml config? If yes, in my head, it defeats the purpose of a mapped superclass. Maybe I have to write in the yml that it inherits from a mapped superclass ?
Edit 1 : Maybe this does not work since the base class Token is not abstract ?
Solution:
I had to point to Entity and not Model as a tutorial was telling me. This is so since in the ORM mapping in the bundle files, the mapping is done for the entity and not the model !
<?php
namespace OSC\OAuthServerBundle\Entity;
use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken; //Entity here not model !
use FOS\OAuthServerBundle\Model\ClientInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class AccessToken extends BaseAccessToken
{
}
Did you try to extend this class : FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken instead of this one FOS\OAuthServerBundle\Document\AccessToken ?
You don't have to declare your properties twice (in super and sub class).
Do not redeclare $id, $client and $user
I've created my own service and I need to inject doctrine EntityManager, but I don't see that __construct() is called on my service, and injection doesn't work.
Here is the code and configs:
<?php
namespace Test\CommonBundle\Services;
use Doctrine\ORM\EntityManager;
class UserService {
/**
*
* #var EntityManager
*/
protected $em;
public function __constructor(EntityManager $entityManager)
{
var_dump($entityManager);
exit(); // I've never saw it happen, looks like constructor never called
$this->em = $entityManager;
}
public function getUser($userId){
var_dump($this->em ); // outputs null
}
}
Here is services.yml in my bundle
services:
test.common.userservice:
class: Test\CommonBundle\Services\UserService
arguments:
entityManager: "#doctrine.orm.entity_manager"
I've imported that .yml in config.yml in my app like that
imports:
# a few lines skipped, not relevant here, i think
- { resource: "#TestCommonBundle/Resources/config/services.yml" }
And when I call service in controller
$userservice = $this->get('test.common.userservice');
$userservice->getUser(123);
I get an object (not null), but $this->em in UserService is null, and as I already mentioned, constructor on UserService has never been called
One more thing, Controller and UserService are in different bundles (I really need that to keep project organized), but still: everyting else works fine, I can even call
$this->get('doctrine.orm.entity_manager')
in same controller that I use to get UserService and get valid (not null) EntityManager object.
Look like that I'm missing piece of configuration or some link between UserService and Doctrine config.
Your class's constructor method should be called __construct(), not __constructor():
public function __construct(EntityManager $entityManager)
{
$this->em = $entityManager;
}
For modern reference, in Symfony 2.4+, you cannot name the arguments for the Constructor Injection method anymore. According to the documentation You would pass in:
services:
test.common.userservice:
class: Test\CommonBundle\Services\UserService
arguments: [ "#doctrine.orm.entity_manager" ]
And then they would be available in the order they were listed via the arguments (if there are more than 1).
public function __construct(EntityManager $entityManager) {
$this->em = $entityManager;
}
Note as of Symfony 3.3 EntityManager is depreciated. Use EntityManagerInterface instead.
namespace AppBundle\Service;
use Doctrine\ORM\EntityManagerInterface;
class Someclass {
protected $em;
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
public function somefunction() {
$em = $this->em;
...
}
}
Since 2017 and Symfony 3.3 you can register Repository as service, with all its advantages it has.
Check my post How to use Repository with Doctrine as Service in Symfony for more general description.
To your specific case, original code with tuning would look like this:
1. Use in your services or Controller
<?php
namespace Test\CommonBundle\Services;
use Doctrine\ORM\EntityManagerInterface;
class UserService
{
private $userRepository;
// use custom repository over direct use of EntityManager
// see step 2
public function __constructor(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function getUser($userId)
{
return $this->userRepository->find($userId);
}
}
2. Create new custom repository
<?php
namespace Test\CommonBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
class UserRepository
{
private $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(UserEntity::class);
}
public function find($userId)
{
return $this->repository->find($userId);
}
}
3. Register services
# app/config/services.yml
services:
_defaults:
autowire: true
Test\CommonBundle\:
resource: ../../Test/CommonBundle