I am trying to pass my service, defined in other bundle to controller which is defined as a service but getting null in contractor.
I know we can do it by passing the service_container but need to know if I can pass only specific service to the controller.
If the name is unique, no problem here.
namespace Yourapp\OneBundle\Controller;
class OneController extends Controller
{
public function oneAction()
{
$otherControllerManager = $this->get('youappOtherbundle.the_manager');
}
}
EDIT : Okay, it seemed to me that you could extend controller even it was a controller as service.
Why don't just "transmit" your required services as usual ?
In your services.yml
OneController.controller.service:
class: Yourapp\OneBundle\Controller\OneController
arguments: ["#templating", "#router"]
In your Controller:
public function __construct(EngineInterface $templating, UrlGeneratorInterface $router)
{
$this->templating = $templating;
$this->router = $router;
}
Related
Aware that there is a lot of information around the net regarding this, I am still having a lot of trouble getting this to work.
I have created a custom service:
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\AccommodationType;
use App\Entity\Night;
class AvailabilityChecks {
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function nightAvailable(string $RoomCode, string $NightDate) {
$GetRoom = $this->em->getDoctrine()->getRepository(AccommodationType::class)->findOneBy([
'RoomCode' => $RoomCode
]);
$RoomQnt = $GetRoom->getNightlyQnt();
$GetNight = $this->em->getDoctrine()->getRepository(Night::class)->findOneBy([
'RoomCode' => $RoomCode,
'NightDate' => $NightDate
]);
$NumberOfNights = $GetNight->count();
if($NumberOfNights<$RoomQnt) {
return true;
}
else {
return false;
}
}
}
and have put this in services.yaml:
AvailabilityChecks.service:
class: App\Service\AvailabilityChecks
arguments: ['#doctrine.orm.entity_manager']
So when I try and use this in my controller, I get this error:
Too few arguments to function App\Service\AvailabilityChecks::__construct(), 0 passed in /mypath/src/Controller/BookController.php on line 40 and exactly 1 expected
I just can't figure out why it's not injecting the ORM stuff into the constructor! Any help greatly appreciated
The problem is in your BookController. Even though you didn't posted its code I can assume you create new AvailabilityChecks in it (on line 40).
In Symfony every service is intantiated by service container. You should never intantiate service objects by yourself. Instead BookController must ask service container for AvailabilityChecks service. How should it do it ?
In Symfony <3.3 we used generally :
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller
{
public function myAction()
{
$em = $this->get('doctrine.orm.entity_manager');
// ...
}
}
Nowadays services can be injected in controllers using autowiring which is way easier:
use Doctrine\ORM\EntityManagerInterface;
class MyController extends Controller
{
public function myAction(EntityManagerInterface $em)
{
// ...
}
}
You are using the wrong service for what you want to do. The alias doctrine that is used, e.g. in the AbstractController when you call getDoctrine() is bound to the service Doctrine\Common\Persistence\ManagerRegistry.
So the code you wrote fits better with that and you should either add #doctrine or #Doctrine\Common\Persistence\ManagerRegistry to the service definition.
Both with your current configuration or the changed one, you don't have to call $this->em->getDoctrine(), because $this->em is already equivalent to $this->getDoctrine() from your controller. Instead you could create a (private) method to make it look more like that code, e.g.:
private function getDoctrine()
{
return $this->em;
}
Then you can call $this->getDoctrine()->getRepository(...) or use $this->em->getRepository(...) directly.
In Symfony 4, you dont need to create it as services. This is automatically now. Just inject the dependencies what you need in the constructor. Be sure that you have autowire property with true value in services.yml (it is by default)
Remove this from services.yml:
AvailabilityChecks.service:
class: App\Service\AvailabilityChecks
arguments: ['#doctrine.orm.entity_manager']
You dont need EntityManagerInterface because you are not persisting anything, so inject repositories only.
<?php
namespace App\Service;
use App\Entity\AccommodationType;
use App\Entity\Night;
use App\Repository\AccommodationTypeRepository;
use App\Repository\NightRepository;
class AvailabilityChecks {
private $accommodationTypeRepository;
private $nightRepository
public function __construct(
AcommodationTypeRepository $acommodationTypeRepository,
NightRepository $nightRepository
)
{
$this->acommodationTypeRepository = $acommodationTypeRepository;
$this->nightRepository = $nightRepository;
}
public function nightAvailable(string $RoomCode, string $NightDate) {
$GetRoom = $this->acommodationTypeRepository->findOneBy([
'RoomCode' => $RoomCode
]);
$RoomQnt = $GetRoom->getNightlyQnt();
$GetNight = $this->nightRepository->findOneBy([
'RoomCode' => $RoomCode,
'NightDate' => $NightDate
]);
$NumberOfNights = $GetNight->count();
if($NumberOfNights<$RoomQnt) {
return true;
}
else {
return false;
}
}
}
In SF4, you no longer need to specify dependencies required by your custom service in the service.yaml file. All you have to do is to use dependency injection.
So remove config lines, and call your service directly in the controller method :
<?php
namespace App\Controller;
use App\Service\AvailabilityChecks ;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class AppController extends AbstractController
{
public function index(AvailabilityChecks $service)
{
...
}
}
Having said that, i think you don't need custom service to do simple operations on database. Use repository instead.
I'm trying to create a manager to handle basic requests of a controller (list, new, edit, delete). I need to inject the form factory within the constructor of this service. By what name should I call?
I need something like this:
lp_ExpedienteManager:
class: AppBundle\Services\ExpedienteManager\ExpedienteManager
arguments: [ "#doctrine.orm.entity_manager", "#security.token_storage", "#form_factory" ]
Thanks for your time!
For future references, since Symfony 3.3 this service is available as Symfony\Component\Form\FormFactoryInterface. So you can inject in your services like
use Symfony\Component\Form\FormFactoryInterface;
class AccountBridge
{
private $formFactory;
public function __construct(FormFactoryInterface $formFactory)
{
$this->formFactory = $formFactory;
}
public function accountCreateAction(Account $account)
{
$form = $this->formFactory->create(AccountType::class, $account);
}
}
So far I was getting the cache directory from some controller. but as I want to set it in a specific service I would like to know which dependancy injection I should do to access it from a service.
Of course I could inject the container (as I settled here below as an exemple) but I guess there is some more spécific dependancy injection that I could use.
Here my code so far in my service
class mycache
{
private $container;
public function __construct($container){
$this->container = $container;
}
public function transf($text, $code)
{
$filename = $this->container->getParameter('kernel.cache_dir') . '/MyCACHE/langue.txt';
}
}
// service configuration
service
cache_langue:
class: MySite\BlogBundle\Services\mycache
arguments: ["#service_container"]
You can inject the kernel.cache_dir parameter as follows:
services:
cache_langue:
class: MySite\BlogBundle\Services\mycache
arguments: ["%kernel.cache_dir%"]
I've got two services: OrderManager and CouponManager. OrderManager has a dependency on CouponManager. This works fine.
I'm trying to add functionality to CouponManager which relies on a method in OrderManager. However, I cannot inject OrderManager into CouponManager without getting a circular reference error.
For example:
OrderManager:
public function foo() {
return $this->couponManager->bar();
}
CouponManager:
public function fubar() {
if($this->something()) {
return $this->orderManager->barfu();
}
}
How should I structure this so each service has access to the other?
Inject service container and get required service directly from the container only in methods that rely on it.
In the services config:
services:
...
arguments: [#service_container]
And in the service class:
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
Manager call example:
Class OrderManager
...
public function foo()
{
$this->container->get('project.bundle.manager.coupon_manager')->bar();
}
my constructor of my Controller looks like:
function __construct(){#
var_dump($this->get('translator'));
exit();
}
this will give a FatalErrorException: Error: Call to a member function get() on a non-object. But why? If I use it inside a action it will work.
Base controller's method get() is a shortcut for $this->container->get($id);. $this->container is set in one of the controller's parent - abstract class ContainerAware. So,
until object construction is finished, there is no Controller object that would have get() method. In general, container is not available in Controller's constructor.
This is because Controller method get needs the container property. Controller extends ContainerAware which has a method setContainer. This method let the property container be aware of the Container.
Upon instanciation, no method are called, here is the workflow
$controller = new MyController($parameters);
$controller->setContainer($container);
Before calling __construct, controller has no property $container
public function __construct($parameters)
{
var_dump($this->container); // NULL
}
So, by calling $this->get() you are doing
$this->get('translator');
// =
$this->container->get('translator');
// =
null->get('translator');
Hence the error.
If you need the validator, you'll have to ask it in your constructor (and respect the Law of Demeter).
To do so, you'll need to declare your controller as a service
services.yml
services:
my_controller:
class: Acme\FooBundle\Controller\MyController
arguments:
- "#translator"
calls:
- [ "setContainer", [ "#service_container" ] ]
routing.yml
bar_route:
path: /bar
defaults: { _controller: my_controller:barAction }
MyController
class MyController extends Controller
{
protected $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
}