I have a service that needs to access the current application base URL (what's returned by app.request.getBaseURL() in Twig views). Currently, my config is like this:
services:
WidgetModel:
class: AppBundle\Model\WidgetModel
scope: prototype
arguments: ['%widgets%']
So as a second argument, I would like to inject the base URL. Is it possible? If not, what would be proper solution?
As far as I know there is no builtin base url service. Which is actually a bit of a red flag that maybe having your component depending on it might not be such a good idea. But I can't think of a good reason why.
So normally, one would just inject the request object. But that has it's own problems as documented here: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack
Instead, inject the #request_stack service and pull the url from it:
class WidgetModel
{
public __construct($widgets,$requestStack)
{
$this->baseUrl = $requestStack->getCurrentRequest()->getBaseUrl();
If you do find yourself needing the baseUrl in multiple services then you could define your own factory type service to generate it. But again, that might mean your design needs rethinking.
You can use the expression language in your service definition.
This example should do what you want:
services:
WidgetModel:
class: AppBundle\Model\WidgetModel
scope: prototype
arguments: [%widgets%, "#=service('request').getBaseUrl()"]
It fetches the request service and then executes the getBaseUrl method.
You will need to add a second parameter in your WigetModel for the base URL.
To complete the answer, in Symfony 3 you can use request_stack to get the base url using expressions languages (updated link) such as:
services:
WidgetModel:
class: AppBundle\Model\WidgetModel
scope: prototype
arguments: [%widgets%,"#=service('request_stack').getCurrentRequest().getBaseUrl()"
Related
Problem:
I tried to register a CustomErrorRenderer on Symfony 5 to render my CustomException, but all the time the TwigErrorRenderer is called. I thought probably self-defined renderers might be preferred?
CustomErrorRenderer.php:
namespace App\ErrorRenderer;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface;
class CustomErrorRenderer implements ErrorRendererInterface
{
public function render(\Throwable $exception): FlattenException
{
dd('CustomErrorRenderer.render() called');
// TODO check if CustomException, else refer to preset renderer...
}
}
services.yaml:
services:
App\ErrorRenderer\CustomErrorRenderer:
tags: ['error_renderer.renderer']
# also tried: ['error_renderer.renderer', 'error_renderer.html','error_handler.error_renderer' , 'error_handler.error_renderer.html']
What is wrong with that?
Background:
I have a web application and want to handle exceptions that are related to my internal business logic separately. E.g., a user wants to book a resource but it is currently not available. While current errors/exceptions are handled by the TwigErrorRenderer (or default HtmlErrorRenderer), I would like to add my own Renderer (ideally just extending the TwigErrorRenderer, so that I can use some specific, self-defined twig templates). By that, I aim to have a better UI, e.g., my custom exceptions being rendered while still the menu of the web application is shown. As my exceptions are not related to how the data is accessed (e.g. http), I do not want to use HttpExceptions and their status code.
This was not particularly easy to figure out.
I made a copy of vendor/symfony/twig-bridge/ErrorRenderer/TwigErrorRenderer.php into my app src\CustomerErrorRenderer.php.
Then override the error_renderer in services.yaml:
services:
error_renderer:
class: App\CustomErrorRenderer
arguments: ['#twig', '#error_handler.error_renderer.html','%kernel.debug%']
Of course, that's not exactly how they call in their code when I tried to test using /_error/404 for instance.
They actually use arguments more like:
error_renderer:
class: App\Twig\CustomErrorRenderer
arguments:
- '#twig'
- '#error_handler.error_renderer.html'
- !service
factory: [ 'Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer', 'getAndCleanOutputBuffer' ]
arguments: ['#request_stack']
I use this library https://github.com/smsapi/smsapi-php-client to send sms from site. But I had a problem when I try to handle base class in service. So my question is there is the way to call a static method with with argument? I try to do it this by factory but this doesn't work for me. This is my code:
smsapi.client:
class: SMSApi\Client
factory: ['SMSApi\Client', createFromToken]
properties:
attributes: '%smsapi_token%'
But I got error below:
Warning: Missing argument 1 for SMSApi\Client::createFromToken(), called in ../cache/dev/appDevDebugProjectContainer.php on line 5073 and defined
As described in the doc: Passing Arguments to the Factory Method:
you can use the arguments options inside the service container.
As Example:
smsapi.client:
class: SMSApi\Client
factory: ['SMSApi\Client', createFromToken]
arguments:
attributes: '%smsapi_token%'
Hope this help
PS: please share the repo of the library you are using or the main part of the source code in order to handle the situation.
I renamed a service from Notifications to Notification (Because I have already a class called Notifications), but when I tried to call it I have the following error:
ParameterNotFoundException in ParameterBag.php line 106:
The service "notification" has a dependency on a non-existent parameter "app.bundle.notification.class". Did you mean one of these: "app.bundle.utils.class", "app.bundle.notifications.class"?
In my Bundle/Services I have 2 files:
- Notification.php
- Utils.php
In Notification.php the class is called class Notification {...}
In my config file services.yml
notification:
class: %app.bundle.notification.class%
arguments: [#templating]
I don't know where it can found the suggest value app.bundle.notifications.class
I tried to clear the cache but I have the same error.
You have to declare your service by this way:
parameters:
your.service.class: ACME\YourBundle\Services\ServiceName
services:
your.service:
class: "%your.service.class%"
arguments: [#templating]
Hope it will help you :)
Symfony errors on container mistakes are - IMO - one of the best thing of this stack. Look closer:
Did you mean one of these: "app.bundle.utils.class", "app.bundle.notifications.class"?
Compiler tells you probable parameters you can use (and which exist). Check the ones of your bundle and rename this param to the new convention.
The simpliest thing to do: search whole project if it looks a bit hidden.
PS. Don't forget to delete cache.
I'm trying to use the method described on this other question and I wasn't able to make it work:
Symfony2: How to inject ALL parameters in a service?
In summary, I would like to define the arguments of my service in a unique file using a variable. I would then only pass this variable as an argument to my service. If one day, I decide to change the arguments, I don't have to change all the calls on my service. I would just change the content of this variable. However, I'm having the following error:
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException You cannot dump a container with parameters that contain references to other services (reference to service "doctrine.orm.entity_manager" found in "/company.usermanagerservice/em").
Was anybody able to make it work? Or do you have other ideas?
Edit:
services.yml:
company.user_manager:
class: Company\CoreBundle\Model\UserManager
arguments: [%company.userManagerService%]
Then on config.yml:
parameters:
company.userManagerService:
em: 'doctrine.orm.entity_manager'
user_helper: 'company.helper.user'
fos_manipulator: 'fos_user.util.user_manipulator'
I'm working on a Symfony2 project and am trying to figure out how to pass parameters from the route configuration to the controller. I know I can configure default values in the route configuration, and retrieve the values in the controller using the appropriate var name in the function declaration, but that isn't exactly what I want.
My use case is the following. I have a standard method in my controller that I want to access from 2 or 3 different routes. Depending on which route is being called, I want to "configure" the method differently. I can accomplish this in a few ways:
In my controller, check the route name using `$this->container->get("request")->get("_route"), but that is ugly, and then I am hardcoded to the route name. Moves configuration to the controller, which should just be logic - not configuration.
Create a base controller class, and subclass each method for my different routes. Each subclassed method would then have the necessary configuration within the method. Cleaner soln than #1, but still "heavy" in the sense of having multiple classes for a simple need and still pushes configuration data into the business logic.
Put configuration data into the route configuration. In the controller, access the configuration data as required. Ideal solution, but don't know how.
I can use the route default array to specify my arguments, but then must make sure to use a regex to ensure that the params are not overridden at the URL level (security risk). This is functional, but still kinda cludgy and not a pretty hack.
I presume that there must a better way to do this, but I can't seem to figure it out. Is there a way to access the routing object from the controller, and access the different configuration parameters?
You can pull the actual route from the router service. Something like:
$routeName = $this->container->get("request")->get("_route");
$router = $this->container->get("router");
$route = $router->getRouteCollection()->get($routeName);
Not sure if this would be such a great design though. Consider passing a $configName to your controller method, adding a parameter with the same name in a config file then using getParameter to access it. That would eliminate the route stuff from the equation.
Something like:
zayso_arbiter_import:
pattern: /import
defaults: { _controller: ZaysoArbiterBundle:Import:index, configName: 'someConfigName' }
public function importAction(Request $request, $configName)