Please look at the following code:
public function __construct($error_code)
{
$translator = new Translator('en');
$translator->addLoader('yaml', new YamlFileLoader());
$translator->addResource('yaml', dirname(__DIR__).'/Resources/translations/messages.en.yml', 'en');
$this->setErrorCode($translator->trans($error_code));
}
I am new to symfony. I have created a class MyProjectExceptions which extends Exception. Now when I have to throw a custom exception I call this class where I get the $error_code. Now this $error_code is a constant of another class which has its locale in MyBundle/Resources/transalations/messages.en.yml which will be used to throw as exception message.
Now my question are following:
How can I avoid addResource, so it can automatically add it based on Locale and find the string?
How to access serviceContainer in this class so that I can access session to set and get locales OR other services.
Can we set the default Loader as well.
In above code I am creating an instance of Translator class and manually passing 'en'. but it should pick default locale or user set locale.
I tried many solutions but not able to get the desired results.
Any help would be appreciated. Thanks in advance.
You need to register your class as Symfony service. Read the documentation: http://symfony.com/doc/current/book/service_container.html#creating-configuring-services-in-the-container
After that you can inject other services (like Translation) in your constructor. It will use all parameters that you have already set.
If you inject translator service it will pick the parameters that you have already set. For example, if you defined parameters for translator (including default locale) at config.yml, then you overrode this locale with parameter in route, you will get translator service set up with this locale. And it will automatically use resources that are lied in appropriate directories.
Related
I am using .NET ASP.NET MVC 4. For validation I am using Fluent validation. I am new to this. How can I override a method of the DefaultValidatorExtensions class?
I found one solution.
Create basevalidator class which inherited both IValidatorInterceptor and AbstractValidator. But I am not getting how to override validation methods.
Actually I want to change the default message of any validation method. The message is common for all attributes for some validations, so I want to override those validation methods rather to use 'WithMessage()'.
For example:
RuleFor(x => x.Name).NotEmpty(); will return " 'Name' should not be empty." But I want message 'Required'.
I found an answer on this link. I think it can help you:
https://fluentvalidation.net/localization#default-messages
If you want to replace all (or some) of FluentValidation’s default messages then you can do this by implementing a custom version of the ILanguageManager interface.
For example, the default message for the NotNull validator is '{PropertyName}' must not be empty. If you wanted to replace this message for all uses of the NotNull validator in your application, you could write a custom Language Manager:
public class CustomLanguageManager : FluentValidation.Resources.LanguageManager {
public CustomLanguageManager() {
AddTranslation("en", "NotNullValidator", "'{PropertyName}' is required.");
}
}
Here we have a custom class that inherits from the base LanguageManager. In its constructor we call the AddTranslation method passing in the language we’re using, the name of the validator we want to override, and the new message.
Once this is done, we can replace the default LanguageManager by setting the LanaguageManager property in the static ValidatorOptions class during your application’s startup routine:
ValidatorOptions.LanguageManager = new CustomLanguageManager();
This is a simple example that only replaces one validator’s message in English only, but could be extended to replace the messages for all languages. Instead of inheriting from the default LanguageManager, you could also implement the ILanguageManager interface directly if you want to load the messages from a completely different location other than the FluentValidation default (for example, if you wanted to store FluentValidation’s default messages in a database).
Of course, if all you want to do is replace this message for a single use of a validator, then you could just use WithMessage("'{PropertyName}' is required");
I have a spring-mvc application that is using java configuration, not xml. There are #Configuration annotations sprinkled through several files. In particular, there is a #PropertySources annotation in one file in a class that implements WebMvcConfigurerAdapter. There are two classes which contain an #Autowired Environment variable. One of these classes is itself a #Configuration class, and I would like it to have access to the fully-loaded Environment at the time it runs.
This isn't happening. When this code executes, the Environment is still null. I've tried reordering the #ComponentScan packages, tried moving the #PropertySources annotation, and nothing has helped me load the property sources in time.
I want this to happen first, before any other configuration.
What must I do to make it so?
UPDATE: After trying many things, including the Order annotation, I find the problem seems to be not so much that the #PropertySources are being loaded too late as that a class I have that is derived from org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer is being loaded too soon. Nothing in my code even references this class but Spring is somehow deciding that this, above all other classes, must be initialized first. No amount of messing around with #Order seems to change this. This in spite of the javadocs, which indicate that the behavior I want is the default:
Caveats
Subclasses of AbstractDispatcherServletInitializer will register their
filters before any other Filter. This means that you will typically
want to ensure subclasses of AbstractDispatcherServletInitializer are
invoked first. This can be done by ensuring the Order or Ordered of
AbstractDispatcherServletInitializer are sooner than subclasses of
AbstractSecurityWebApplicationInitializer.
You can use ContextInitializer, catch the moment when Boot prepared its environment and "inject" your property source programmatically as you want.
If you have a ConfigurableApplicationContext then it provides a ConfigurableEnvironment, which contains the propertySources as a list. If you want your PropertySource to rule all above the others than add it as first. If you want to place it to a special position then you can add it before an other, identified by its "name".
public class ConfigInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ctx) {
// rule over all the others:
ctx.getEnvironment().getPropertySources().
addFirst(new ResourcePropertySource("file:/etc/conf/your_custom.properties"));
// rule over application.properties but not argument or systemproperties etc
ctx.getEnvironment().getPropertySources().
addBefore("applicationConfig: [classpath:/application.properties]",
new ResourcePropertySource("classpath:your_custom.properties"));
// names can be discovered by placing a breakpoint somewhere here and watch
// ctx.getEnvironment().getPropertySources().propertySourceList members,
// each has a name ...
}
}
You can bring into play this class by:
registering it in the application.properties :
context.initializer.classes=a.b.c.ConfigInitializer
or from application start :
new SpringApplicationBuilder(YourApplication.class).
initializers(new ConfigInitializer()).
run(args);
By the way this is a proper way to inject more of your custom properties, like properties coming from a database or a different host etc...
Not that I am an expert in Java config but maybe:
Spring 4 utilizes this feature in its #PropertySource annotation. To
remind you, #PropertySource annotation provides a mechanism for adding
a source of name/value property pairs to Spring's Environment and it
is used in conjunction with #Configuration classes.
Taken from: http://blog.codeleak.pl/2013/11/how-to-propertysource-annotations-in.html
Are you using #PropertySource or #PropertySources?
Have You tried 'order' property for spring bean initialisation?
For example, let's say I have an interface 'IFeed' and two concrete types ('Feed1' and 'Feed2') that implement this interface. Now let's say I have a 'FeedManager' type that takes multiple parameters that will get resolved dynamically, two of which are of type 'IFeed' and I'd like both concrete type to be injected via constructor injection, not via manual resolve (I only use resolve once at the composition root). I have a feeling that I should be using a factory but I wanted to see what the proper way of doing this might be. Many thanks in advance.
If you want ALL implementations of IFeed, you can use array syntax in your constructor and then nothing special is needed at type registration time.
container.RegisterType<IFeedManager, FeedManager>();
container.RegisterType<IFeed, FeedA>("FeedA"); // The name doesn't matter
container.RegisterType<IFeed, FeedB>("FeedB"); // The name doesn't matter
Then the manager constructor...
public FeedManager(IFeed[] feeds) {...}
or if you want to add a little flare for calling the constructor directly...
public FeedManager(params IFeed[] feeds) {...}
Assuming you want to determine the actual concrete instances at runtime, you need to use named type registrations and then tell unity which one you want. So, use a factory method to construct the types required and pass those in as parameter overrides. Unity will use the overrides and resolve any remaining dependencies.
// register the types using named registrations
container.RegisterType<IFeedManager,FeedManager>()
container.RegisterType<IFeed, Feed1>("Feed1")
container.RegisterType<IFeed, Feed2>("Feed2")
Assuming your feed manager has the following named constructor parameters
class FeedManager : IFeedManager
{
public FeedManager (IFeed Feed1, IFeed Feed2, string someOtherDependency)
{
}
}
and create your feed manager:
static IFeedManager CreateFeedManager()
{
ParameterOverride feed1 = new ParameterOverride("Feed1"
,_container.Resolve<IFeed>("feed1"));
ParameterOverride feed2 = new DependencyOverride("Feed2"
,_container.Resolve<IFeed>("feed2"));
IFeedManager = _container.Resolve<IFeedManager>(feed1,feed2)
return IFeedManager;
}
Obviously this is overly simplified, but you you insert your own logic to determine which instance is to be resolved and then injected for each of the IFeed instances required by the FeedManager.
With Unity you would do this like so:
container.RegisterType<IFeed, Feed1>("Feed1");
container.RegisterType<IFeed, Feed2>("Feed2");
container.RegisterType<FeedManager>(new InjectionConstructor(new ResolvedParameter<IFeed>("Feed1"),
new ResolvedParameter<IFeed>("Feed2")));
This has now configured Unity so that when it needs to resolve a FeedManager, it will resolve Feed1 for the first parameter and Feed2 for the second parameter.
I have a class which I load via dependency injection within Symfony 2.
It has a number of default private variables which I can override with setters.
Problem is, once one of those default values are set to something else within a page, there is no way to set it back automatically.
I don't want to call the class again using new as it removes the usefulness of the dependency injection.
So, does Symfony2 support Object LifeStyle, or do I basically need to write a public function which resets all of the defaults back to normal and call it each time it is required.
As an example, I use a class to get remote files. It has defaults for UserAgent, Accepted Language/Encoding, Method etc. But if I set the Method to POST, instead of the default GET for one call in a page, the next time I call it, it is still POST, where as I wish it to be the default GET once more, which it would be if I used new instead of via dependency injection.
Add scope: prototype to your service definition. This will ensure you get a new instance from the container each time you request your class. And of course the instance will have the default values.
http://symfony.com/doc/current/cookbook/service_container/scopes.html
I have a class which needs a string as a parameter in its constructor but this parameter will be decided by the calling code. At the same point of time, the life time of this class has to be tied to per HTTP request. So, I created a custom PerWebRequestTimelineManager and used that for my target type in the config file. But since the string in the constructor has to be dynamically determined, I cannot use the ConstructorInjection via the config file. I can use an abstract factory to solve the problem of dynamic dependency, but I am not sure about the implementation: Can you check the code below and validate the approach. Specifically the RegisterType and Resolve calls seem a bit out of place though the successive Resolve calls across the application will be able to retrieve the same instance.:
public class PerformanceTracerFactory : IPerformanceTracerFactory
{
private readonly IPerformanceTracer tracer;
public IPerformanceTracer CreateInstance(string operationTitle)
{
_container.RegisterType<IPerformanceTracer, PerformanceTracer>(new InjectionConstructor(operationTitle));
return _container.Resolve<IPerformanceTracer>();
}
}
Relevant portion of config file:
<register type="IPerformanceTracer" mapTo="PerformanceTracer">
<lifetime type="PerWebRequest"/>
</register>
<register type="IPerformanceTracerFactory" mapTo="PerformanceTracerFactory"/>
I have another question. In case if the above way of configuring and injecting the dependency using code is correct, then I think I do not need the config entries. I can always use the suitable overload to push the custom lifetime manager. In case, I would want to achieve the same thing using only config file, then how do I code the solution?
If you use a container-based factory you don't have to register/resolve your IPerformanceTracer in each call.
Register the mapping IPerformanceTracer --> PerformanceTracer once in your config file and use a ParameterOverride when you resolve your interface.
public IPerformanceTracer CreateInstance(string operationTitle)
{
return _container.Resolve<IPerformanceTracer>(new ParameterOverride("nameOfTheParameterInTheConstructorOfPerformanceTracer", operationTitle);
}