29

How can I generate a link from a service? I've injected "router" inside my service, however generated links are /view/42 instead of /app_dev.php/view/42. How can I solve this?

My code is something like this:

services.yml

services: myservice: class: My\MyBundle\MyService arguments: [ @router ] 

MyService.php

<?php namespace My\MyBundle; class MyService { public function __construct($router) { // of course, the die is an example die($router->generate('BackoffUserBundle.Profile.edit')); } } 
8
  • Could you please paste the code where you generate the URLs? Commented Apr 7, 2012 at 18:59
  • If you access your site through http://test/app_dev.php, the links will be with app_dev.php. For http://test they will be without app_dev.php... Commented Apr 7, 2012 at 19:00
  • @meze : I access to the page threw app_dev.php, but links haven't got this part in the url. That's the problem. Commented Apr 7, 2012 at 19:19
  • Is the URL generated correctly if you try it in a template? Commented Apr 7, 2012 at 19:29
  • @kuba, yes. Someone told me to set a context with $urlgenerator->getContext()->setHost($host), is there a way to get context and/or host using dependency injection ? Commented Apr 7, 2012 at 19:37

3 Answers 3

32

So : you will need two things.

First of all, you will have to have a dependency on @router (to get generate()).

Secondly, you must set the scope of your service to "request" (I've missed that). http://symfony.com/doc/current/cookbook/service_container/scopes.html

Your services.yml becomes:

services: myservice: class: My\MyBundle\MyService arguments: [ @router ] scope: request 

Now you can use the @router service's generator function !


Important note regarding Symfony 3.x: As the doc says,

The "container scopes" concept explained in this article has been deprecated in Symfony 2.8 and it will be removed in Symfony 3.0.

Use the request_stack service (introduced in Symfony 2.4) instead of the request service/scope and use the shared setting (introduced in Symfony 2.8) instead of the prototype scope (read more about shared services).

Sign up to request clarification or add additional context in comments.

9 Comments

I don't get it. How did it help? Scope has nothing to do with app_dev.php.
If the request is not available when the router is used, the context (getContext()) of the router won't use the request informations (f.e. the host), and the path won't be fully generated. Setting the scope ensure that the request will be alive when my service will be created Note that there was a second specific problem : I was loading my services at the bundle's boot, so the request wasn't loaded yet.
I am getting this error when doing as you suggest: ScopeCrossingInjectionException: Scope Crossing Injection detected: The definition "myservice" references the service "router.default" which belongs to another scope hierarchy. This service might not be available consistently. Generally, it is safer to either move the definition "myservice" to scope "container", or declare "router" as a child scope of "container". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.
@Toskan: In your service please add: use Symfony\Component\Routing\RouterInterface; In service constructor add RouterInterface $variableName, And at the end remove scope=router from service.yml.
Sidenote: if you want to use myservice as a dependency in other services, propably you will have to pass it with = at the end (like arguments: [ @myservice= ]), it's yml syntax to set strict=false. Otherwise ScopeWideningInjectionException could be thrown. However, the =-syntax does not work when defining services as Twig's globals.
|
25

For Symfony 4.x, it's much easier follow the instructions in this link Generating URLs in Services

You only need to inject UrlGeneratorInterface in your service, and then call generate('route_name') in order to retrieve the link.

// src/Service/SomeService.php use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class SomeService { private $router; public function __construct(UrlGeneratorInterface $router) { $this->router = $router; } public function someMethod() { // ... // generate a URL with no route arguments $signUpPage = $this->router->generate('sign_up'); } // ... } 

Comments

5

I had a similar issue, but using Symfony 3. While eluded to in the previous answer, it was a bit tricky to find out how exactly one would use request_stack to achieve the same thing as scope: request.

In this question's case, it would look something like this:

The services.yml config

services: myservice: class: My\MyBundle\MyService arguments: - '@request_stack' - '@router' 

And the MyService Class

<?php namespace My\MyBundle; use Symfony\Component\Routing\RequestContext; class MyService { private $requestStack; private $router; public function __construct($requestStack, $router) { $this->requestStack = $requestStack; $this->router = $router; } public doThing() { $context = new RequestContext(); $context->fromRequest($this->requestStack->getCurrentRequest()); $this->router->setContext($context); // of course, the die is an example die($this->router->generate('BackoffUserBundle.Profile.edit')); } } 

Note: Accessing RequestStack in the constructor is advised against since it could potentially try to access it before the request is handled by the kernel. So it may return null when trying to fetch the request object from RequestStack.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.