How to access paths and configuration outside Controller in Symfony 2? - php

I have a problem of not being able to access configuration and path information outside controller context. I am in a Assetic Filter class that has no methods to help me, and I need to know the kernel path along with some configuration. How do I do the Symfony 1 sfContext::getInstance() call in Symfony 2?

If you are writing an assetic filter you are writing a service. In the service definition you can pass parameters from the DIC. For example you can pass the AppKernel absolute path writing:
<argument>%kernel.root_dir%</argument>
If you want to have a semantic configuration for your filter (and for any service in general) it would reside in a DIC extension. By default "MyNamespaceMyBundle" will register the "MyNamespaceMyExtension" extension class inside the DependencyInjection subpackage and this extension will handle configuration from the "my_namespace_my" top level configuration key creating services or setting DIC parameters.
Moreover you would want to have a Configuration class that handles validation, normalization and merging of your configuration. Sadly all of this is more or less not documented anywhere, so best way to achieve your goal is to look at some other bundle (e.g. I learned very much reading FOSUserBundle).

You don't. You must use depency injection somehow. See here why it might have been removed.

Related

Config files in a custom Symfony compatible library

Ok, so I am working on creating a custom standalone library that I intend to use in a Drupal 8 site. Drupal 8 runs on Symfony 2.8.x. I want this code to be usable outside Drupal. So I have focused on making it more Symfony oriented than Drupal oriented.
What I have found, thus far, with all my searching, is that Symfony requires you to write a bunch of config declarations in DependencyInjection/Configuration.php. As well as service declarations in a MyBundleExtension.php file.
What I have NOT found is a simple way to say "Hey, I want this config parameter in this standalone (not at all a controller) class". So I wrote the class you see below.
Is there a better way to handle this?
Code: http://pastebin.com/pdp53kxe
Also, will this create any problems with loading services?
At some point I have to deal with dependency injection and actually new up what we want to inject. Still not sure how I will work that into this standalone library while utilizing the Symfony framework. So suggestions as to how to have Symfony wire that up for me would be great.
My basic question here is about using Symfony in a library setting. Where you would not expect to just need the variables within a controller context.
Like you said if you want to import configuration you need to use your DependecyInjection/MyBundleExtension.php class to load the config (maybe even parse) yourself.
Another way is to use compiler passes to directly manipulate the container but this looks like it would be an overkill for your case.
The main reason is that the Dependency Injection Container (wich contains all your service definitions and config parameters) is compiled.
So you have to inject your extra config before the compilation.
Helpful links:
http://symfony.com/doc/current/service_container/import.html
http://symfony.com/doc/current/service_container/compiler_passes.html

Override parameters.yml in each bundle symfony2

I'm working on a complex Symfony project. In the project, we have a core bundle which uses the parameters.yml located in app/config.
Each other AppBundle will inherit this CoreBundle and will correspond to a website.
What I need is to have specific parameters in each bundle that will override the default parameters one: when I'll use a route that will bring me into a controller's bundle, the parameters of this specific bundle have to override all the other ones.
I've tried the preprend method but it doesn't fit to this need. It only allows me to create new parameters for this bundle, but not to override the other ones.
I think you misunderstand the idea of bundles in Symfony. Bundle by design should be a reusable module, therefore the configuration placed inside a bundle is the default one. Then it is possible to override parameters (and not only!) in configuration in app folder.
The basic idea is:
Bundles don't use application. Application uses bundles.
So it's completely the opposite to what you expect it to be. Acutally it makes no sense to condition whole application configuration depending on current route since bundles can use one another. What if your currenct action will internally (without redirect) call another bundle's service or even controller?
Also it's worth mentioning that the app folder is the final folder for your application, therefore you can override in it not only bundle's configuration but also other things like services, view templates and so on.
Edit: I forgot to suggest a solution for you :)
Since you want to use custom parameters inside bundle, why do you need the default value in first place? Just create separate parameter namespace for each bundle that won't be overridden by application config. Then use it only inside that bundle.
Solution found thanks to dragoste's asking about separated kernels.
To solve my problem, I had to split the kernels : one for each website.
Documentation can be found here :
http://jolicode.com/blog/multiple-applications-with-symfony2

Symfony 2/3 Get Classes in Directory that Implement an Interface

Is there a nice way in Symfony 2 or 3 to load all classes within a directory that implements a particular interface?
Since Symfony 3.3/3.4 it is possible by using configuration only (without a need to write custom CompilerPass):
# config/services.yaml
services:
# ...
_instanceof:
App\HandlerInterface:
tags: ['app.handler']
App\HandlerCollection:
# inject all services tagged with app.handler as first argument
arguments: [!tagged app.handler]
and if you need to restrict services to register from a single directory see importing with resource
references:
https://symfony.com/doc/current/service_container/3.3-di-changes.html#auto-configure-with-instanceof
https://symfony.com/doc/3.4/service_container/tags.html#reference-tagged-services
http://symfony.com/doc/3.4/service_container.html#importing-many-services-at-once-with-resource
Short answer is: you can't.
You don't know, what is in a file until you load it.
Long answer (taking into account what you have wrote in the comment under the question):
The only thing you know before you load a file is its name. So one of solution is to name your modules' classes (and files) with a fixed pattern like UserModule, ProductModule and so on. That way you can load all modules by their names. But this is the solution that I wouldn't suggest.
I my opinion you should change the approach and inverse the workflow. Create a class in which you will define all modules that need to be loaded. In Symfony it's called by default AppKernel, in which you define bundles (modules) to be loaded and initialized.
This has a few advantages.
You can have multiple entry points to your application and configure each one with different modules.
You may have a few different environments (like production and development) with different modules loaded in both of them. (e.g. add some modules in development like profiler)
Also dependency managment is much easier, since you can load defined modules and add their dependencies also with autoloading.
In general I think that you should avoid manual loading any php files (except autoload.php or similar that contains autoloaders) at all.

How to handle config files in PHP library

I wrote a small library (https://github.com/dborsatto/php-giantbomb) that acts as a wrapper for an API. In order to work, the library needs 2 basic configuration options:
An API key
A file that describes the API options
What is the suggested way to handle these two files?
The API key is of course personal so it can't be added to the repository. But by doing so, I can't write a functional test for the library as a whole, thus limiting myself to only unit tests for the single parts. Do I give up the functional tests altogether or is there a way to make this work?
About the other config, basically it's a YAML file (https://github.com/dborsatto/php-giantbomb/blob/master/api_config.yml) that includes the base API endpoint, and configuration for each data repository. At the moment this is handled by a Config class that is decoupled in a way that the user must write glue code and inject data into the Config. This way it's easier to test, but as a whole I feel like it's creating a bigger disadvantage than just letting the Config class load the file, parse it and behave accordingly. What is the best way to do this? At the moment there are no tests in the repository, but I'm working on it (along with some code refactoring).
I would suggest to leave the configuration outside your library; I've done something similar for the Mandrill mailing service, where I left to the developer the management of the configuration (I was working in a Symfony 2 project). For me there is no Config class, just the service constructor that accepts the API key and an (optional) array of options:
public function __construct($api, $options = array())
{
// My code
}
When I need to use my service inside the Symfony 2 application, I take the needed parameters and configuration from a place (Symfony's config files) external to my service; this way I can decouple the library from the configuration. Of course the service contructor throws an exception if the mandatory parameters are missing.

Common lib on symfony2

Before using Symfony2, I used to have a common lib with a lot of simple but useful functions (for instance, a function which takes "Azè_rtï" in argument and returns "aze-rti").
So, well, I created a Bundle: CommonLibsBundle.
But.. I have only one or two php files. It does not make sense to me to use a controller / view / model in this kind of situation.
What should I do? May I erase all folders in my new bundle (Controller, DependencyInjection, Resources, Tests... + CommonLibsBundle.php) and just put my lib.php in it?
Many thanks,
Bliss
Unless you need to tap into the Symfony framework itself - for configuration or to define services, it doesn't need to be a bundle - it's just a library. Give it a reasonable namespace, and call as required as you would any other component or library.
Even if you wanted to add Symfony-specific services that you could call, there is something to be said to still have an external simple library - usable anywhere, which then is wrapped by a very thin bundle which would only add the Symfony-specific (or Laravel, or ZF, or whatever) services and configuration as required.

Categories