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.
Related
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
I have created a bundle that provide default functionality for some use case.
No I want to direct X URLs to this project. No problem up to this point, all URLs point to the /web folder.
But now I want to create child bundles to modify some functionality / behavior / appearance for each URL. What is the best way to load different child bundles for different URLs?
My approach would be to detect URL in AppKernel and load at this point the specific child bundle. Does it make sense or is there a better way?
Indeed placing your code in the AppKernel seems a good way to handle that but you'll have a cache issue.
Example :
If your Request A loads bundle A, it will be cached.
If your Request B loads bundle B but not bundle A, you'll get an error related to the loading of bundle A's classes.
Another issue will be your routing, you'll have to create separate routing files for your different bundle sets.
My approach would be environment dependent, in your front controller, you'll catch the host and then use a different environment (hosta_dev / hosta_prod / hostb_dev / hostb_prod) for each URL. This will create separate cache and allow you to have separate config / routing files.
You'll still have to make modifications in your AppKernel anyway (for example you'll have to load the "dev" bundles not only if the environment is "dev" or "test" but also if the environment contains "dev" or "test").
Hope it helps.
You can create three services:
main
A which inherited from main
B which inherited from main
Then define in your configuration my_service to main by default.
On Service initialization for controller with url A reconfigure it to A. same for B.
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.
As the subject says, really.
Assume I have two apps, namespaced as App_A and App_B. App_A has App_B imported as a git submodule and then autoloaded via its composer.json.
When I call App_B\SomeModel->someMethod() from an App_A controller, will the model query the database configured in App_B's config files, or will it inherit the config values from App_A?
Short answer: it won't inherit App_B's config files.
Expanded answer: App_A is loaded with it's config files. You call App_B\SomeModel::someMethod() from App_A, App_A's configuration will be used. To have two independent applications with 'knowledge' of each others state you would need to define a communication method between the two such as Message Queues(MQ), HTTP, Sockets, Streams etc etc. You would also never import App_B as a submodule of App_A and vice versa unless you're ok with App_*'s classes being used in the context of the loaded application stack.
Another option is to look at the HMVC or Heirarchical MVC pattern. This could possibly give you a solution to this problem without keeping the applications separate. There was a bundle in Laravel 3 enabling HMVC but I haven't looked into it since then as it (imo) is an anti-pattern. I don't know if one exists for Laravel 4 or 5.
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.