Symfony: Dynamic configuration file loading - symfony

Here is the context :
Each user of my application belongs to a company.
Parameters for each company are defined inside "company.yml" configuration files, all of them sharing the exact same structure.
These parameters are then used to tweak the application behavior.
It may sound trivial, but all I'm looking for is the proper way to load these specific YAML files.
From what I understood so far, using an Extension class isn't possible, since it has no knowledge about current user.
Using a custom service to manage these configurations rather than relying on Symfony's parameters seems more appropriate, but I can't find how to implement validation (using a Configuration class) and caching.
Any help would be greatly appreciated, thanks for your inputs!

Using the Yaml, Processor and Configuration components of Symfony2 should fit your needs.
http://symfony.com/doc/current/components/yaml/introduction.html
http://symfony.com/doc/current/components/config/definition.html
Define your "CompanyConfiguration" class as if you were in the DependencyInjection case
Create a new "CompanyLoader" service
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Config\Definition\Processor;
$companies = Yaml::parse('company.yml');
$processor = new Processor();
$configuration = new CompanyConfiguration();
$processor->processConfiguration($configuration, $companies);
Now you should be able to use your companies array to do what you want

Have a look at http://symfony.com/doc/current/cookbook/configuration/configuration_organization.html as well as http://symfony.com/doc/current/cookbook/configuration/environments.html. If that's not the correct answer you'll have to be more specific on what your company.yml configuration contains.

Related

How to test internal controllers without route in Symfony 2

I am trying to reduce redundant code by refactoring template and controller code into reusable components, which I then use via the render(controller('AppBundle:Foo/Bar:baz')) construct inside my other templates.
Of course I would like to test these components. In the examples regarding functional testing, however, an actual route is required to make fake test requests. But my BarController here is purely internal and has no routes attached to it. How can I test this controller?
Creating dummy routes is not always possible, because some of the arguments are model objects that cannot be passed via URL. Am I approaching this the wrong way?
The service approach sounds nice, but I am simply doing this now:
self::$kernel->getContainer()->get('router')->getContext()->setParameter('_locale', 'en');
$controller = new MyController();
$controller->setContainer(self::$kernel->getContainer());
$response = $controller->myAction($arg1, $arg2, $argWhatever);
// assertions here
Seems to work just fine.
If the controllers are setup as services, then they can be easily tested much as any other class would be unit-tested. Even before Symfony 3.3 started to make them services by default, I had altered some of my own to allow them to be more easily tested like this.

Where can Symfony services be useful?

There is the example of creating and using a service in the official documentation. At start we create some class, then register it in config/services.yml an then we can use it in our code like this:
$result = $this->get('app.myservice')->myMethod($arg);
//(In the [example][1] it is little bit other code:)
//$slug = $this->get('app.slugger')->slugify($post->getTitle());
But WHAT FOR? while I can just do the SAME like this:
use MyServiceNamespace/MyService
//...
$result = (new MyService())->myMethod($arg);
Where is profit of using Services? Is this just syntax sugar?
Nope. Far from syntax sugar.
You need to have a working understanding of what dependency injection means. Perhaps start by skimming through here: http://symfony.com/doc/current/book/service_container.html
Let's suppose your service needs a doctrine repository to do it's job. Which is better?
class MyController
{...
$userManager = $this->get('user.manager');
OR
$userRepository = $this->getDoctrine()->getManager()->getRepository('MyBundle::User');
$userManager = new UserManager($userRepository);
Your choice but once you have worked through the mechanics of how to add a service then you will never look back.
I should also point out that your sluglfy example requires a use statement and ties you code directly to a specific implementation. If you ever need to adjust your slugification then you need to go back and change all the places where it is used.
// These lines make your code more difficult to maintain
use Something\Slugify;
$slugify = new Slugify();
AS Opposed to
$slugify = $this->get('slugify');
'tIn this case, it's not really relevant. But from a simple design concern, services allow to make a better dependency management.
For instance, if you declare a service relaying on another one, then you won't have to instanciate both of them. Symfony will take care of it.
And since your declaration is centralized, any modification on the way you decide to create your service (= declare it), you won't have to change all the references to the services you changed since symfony will take care of the way it's instanciated when needed.
Another point is the scope of services. This information might be checked, but I think symfony instanciate service once (Singleton) which mean a better memory usage.

Access Session from EntityRepository

I'm using Symfony2 with Doctrine2. I want to achieve the following:
$place = $this->getDoctrine()->getRepository('TETestBundle:Place')->find($id);
And on that place will be the info of the place (common data + texts) on the user language (in session). As I am going to do that hundreds of times, I want to pass it behind the scenes, not as a second parameter. So an English user will view the place info in English and a Spanish user in Spanish.
One possibility is to access the locale of the app from an EntityRepository. I know it's done with services and DI but I can't figure it out!
// PlaceRepository
class PlaceRepository extends EntityRepository
{
public function find($id)
{
// get locale somehow
$locale = $this->get('session')->getLocale();
// do a query with the locale in session
return $this->_em->createQuery(...);
}
}
How would you do it? Could you explain with a bit of detail the steps and new classes I have to create & extend? I plan on releasing this Translation Bundle once it's ready :)
Thanks!
I don't believe that Doctrine is a good approach for accessing session data. There's just too much overhead in the ORM to just pull session data.
Check out the Symfony 2 Cookbook for configuration of PDO-backed sessions.
Rather than setting up a service, I'd consider an approach that used a Doctrine event listener. Just before each lookup, the listener would pick out the correct locale from somewhere (session, config, or any other place you like in the future), inject it into the query, and like magic, your model doesn't have to know those details. Keeps your model's scope clean.
You don't want your model or Repository crossing over into the sessions directly. What if you decide in the future that you want a command-line tool with that Repository? With all that session cruft in there, you'll have a mess.
Doctrine event listeners are magically delicious. They take some experimentation, but they wind up being a very configurable, out-of-the-way solution to this kind of query manipulation.
UPDATE: It looks like what you'd benefit from most is the Doctrine Translatable Extension. It has done all the work for you in terms of registering listeners, providing hooks for how to pass in the appropriate locale (from wherever you're keeping it), and so on. I've used the Gedmo extensions myself (though not this particular one), and have found them all to be of high quality.

how can i use structure map asp.net 3.5

I am new to the structure map but i want to use it in my asp.net site for dependency injection
can any one suggest me simple example to use structure map for the dependency injection
you will need to do something like this:-
StructureMapConfiguration
.ForRequestedType<IResourceA>()
.TheDefaultIsConcreteType<ResourceB>()
.CacheBy(InstanceScope.Singleton);
This tells StructureMap to inject ResourceB when there is a request for ResourceA.
Structure Map
You can configure programatically or via configuration file.
Programatical example (there are other ways):
StructureMap.StructureMapConfiguration.ForRequestedType<ISomething>().TheDefaultIsConcreteType<ConcreteSomething>();
then you can get an instance of the configured type using this sort of code:
//The concrete type will be ConcreteSomething
ISomething instance = ObjectFactory.GetInstance<ISomething>();
You can do it in a config file:
<StructureMap MementoStyle="Attribute">
<DefaultInstance PluginType="Blah.ISomething, Blah.SomethingDLL" PluggedType="Blah.Concrete.ConcreteSomething,Blah.ConcreteDLL"/>
</StructureMap>
and in the main method or Global.asax you can set this config by saying:
StructureMap.ObjectFactory.Initialize(x => { x.PullConfigurationFromAppConfig = true; });
and use it the same way as above:
ISomething instance = ObjectFactory.GetInstance<ISomething>();
If the concrete class has a constructor that needs instances injected in it, and you have those configured, the concrete types will get injected by the framework.
There are ways of passing parameters to constructors, dealing with Gereric types, creating named instances that are configured with specific constructor/property values. I use this framework and like it very much.

How do I access GetGlobalResourceObject function from a class that is not a page?

I have a class in my asp.net proj, I would like to get access GetGlobalResourceObject (that page exposes), from anywhere in the site, possible?
In other words I wanna access the global resources from a class that is not a page I don't care how.
Answer:
Yes, as following pseudo:
Resources.<The name of the resources file name>.<your resource key>;
Example:
lblTitle.Text = Resources.MySettings.WebsiteTitle;
Resources is an Visual-Studio auto generated namespace that exposes all the global resource classes and props in the project.
You should use
HttpContext.GetGlobalResourceObject("myResourceKey")
...because that way it will still work when using a custom ResourceProvider. The default type-generator for Resource files explicitely uses the Resx provider and won't work if you implement something like a database provider.
On some farms you'll need to wrap the call to
HttpContext.GetGlobalResourceObject("myResourceKey")
inside a try/catch block to get it over the "Could not find any resources appropriate for the specified culture or the neutral culture" error.
If you are in the site you have access to HttpContext and can use:
HttpContext.GetGlobalResourceObject("myResourceKey")
I kinda took this from the resource designer,
ResourceManager temp =
new ResourceManager("Resources.<<resource name>>",
System.Reflection.Assembly.Load("App_GlobalResources"));

Resources