I am building an app with Symfony 4 that can be extended by plugins. Plugins are essentially bundles, but they are just dropped into a folder and don't have to be activated (for example, in config/bundles.php or in config/routes/).
In order for plugins to register routes automatically, I have CMF chain router override the default symfony #router service. Each plugin can then have a service tagged router, which the chain router adds to the chain. This part works.
In order to make it easier for plugins to register routes, the core app provides an AnnotationRouter class, which takes a path to look for annotated controllers in. The plugins would then register a service like this:
sample_plugin.router:
class: MyApp\Routing\AnnotationRouter
arguments: ['#service_container', '##SamplePlugin/Controller']
tags:
- { name: router, priority: 20 }
However, these routes behave very strangely. In fact, they only work on the first request after clearing the cache! All subsequent requests return 404 errors. This is what the 'Routing' tab in the symfony profiler looks like.
On the top it says it doesn't match a route, but on the bottom it matches! I don't know what to make of this.
Also, bin/console router:match /test2 matches the route and bin/console debug:router lists the route. All the routes of the default symfony router (which is the only other router in the chain besides the plugin's router) work as they should.
Interestingly, all of this has worked before, when still using symfony 3.
Ok, turns out this is not an issue with CMF Routing chain router after all, but rather with the implementation of the actual router.
My router implementation is as described in this question. The problem had to do with Doctrine's annotation reader and annotation autoloading. I ended up installing indigophp/doctrine-annotation-autoload, which apparently is only a workaround though.
See also Autoloading annotation classes on GitHub.
Related
I'm using the FOSRestBundle and would like to modify the routes it creates.
I intend to add default parameters to each route the Rest Bundle creates. I've looked through the symfony docs on routing and have found nothing covering this use case.
If there is no way I would either have to
modify the FOS Rest Bundle directly
Or copy its route loader code, make my changes, and add it to my own bundle (and not use the Rest Bundle routing at all.)
I don't like either option.
Does Symfony offer a hook that allow for post processing of routes?
FosRestBundle have a custom route loader. If you look in the github repository you will see that the routes are defined in the RestActionReader.php file. So the only solution is to override it and replace the class associate to the service fos_rest.routing.loader.reader.action
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 a symfony project where i have seperated my code into two different bundles lets say HomeBundle and AppBundle however the routes are commonly accessible inside both bundle.
eg:- /home defined in HomeBundle can also be accessed from AppBundle
and
/App defined in AppBundle can also be accessed from HomeBundle
what i want is to access /home ONLY from HomeBundle and /App from Only AppBundle I'm looking for 'structuring' my code in a way where i dont have to write any logic to accomplish this, but instead leverage symfony frameworks structure to do this for me, something along the lines of restricting routing to only within the bundle, or some way where the route definition goes 'out of scope' when inside the wrong bundle
im using annotaions for routing, and defined in app/config/routing.yml
edit: the application requires subomain partitions so i'm also using this host/default with placeholder
any help would be appreciated :) thanks
Unfortunately this isn't going to be possible, primarily because of the architecture of Symfony bundles. While separating your code into bundles is good from a cognitive point of view, Symfony doesn't have the concept of being "in" a bundle; what code is run (specifically your controller actions) is usually handled by routes, and routes have to be compiled together from ALL bundles to ensure that a request can be routed successfully.
You would have to write extra code to accomplish what you're asking - my initial thought would be your own Controller class (maybe extending from FrameworkBundle\Controller\Controller) that ran some code before a request (see documentation that may achieve this).
Fundamentally this is an architectural decision for you and my question would be - why do you not want to be able to access /home from the AppBundle? Would a security / role set up work as well or are you trying to sandbox code?
EDIT After some further detail, it turns out that the requirement is for two different actions for the same URL path (e.g. /home) but on different domains e.g. www.example.com/home and subdomain.example.com/home. In this instance it wasn't about code sharing but URLs so Symfony's host/domain based routing solution worked.
I was under the assumption that business logic inside bundles are isolated and would not be 'aware' of routes defined inside other bundles, turns out the routes are globally available to all bundles, i wanted to use the framework of symfony to achieve what i asked for, it happens so there is no way to do it. i probably should use Listeners or before filters etc to achieve this. John Noel answered this.
Luckily for me, the bundles happen to operate on separate Domains (one on the main domain and the other on the subdomain) i noticed this after a chat with #John Noel he suggested matching the Route Based on the Host/Domain. i had this in place previously, upon a second look i figured out i have to -based on the domain redirect all (except for a white list of routes) routes to a controller that throws a 404 exception. Here is what i mean.
Home_restrict:
path: /{slug}
host: "{domain}"
defaults:
_controller: HomeBundle:Home:notfound
requirements:
domain: example.com|www.example.com
slug: ^(?!.*(admin|login)$).*
Routes that appear on top of the list on the page takes precedence, so this should be placed appropriately
You can add a routing.yml per bundle, and include these in your "global" routing:
# src/HomeBundle/Resources/config/routing.yml
home:
resource: "#HomeBundle/Controller/HomeController.php"
type: annotation
and
# src/AppBundle/Resources/config/routing.yml
home:
resource: "#AppBundle/Controller/AppController.php"
type: annotation
then import them in app/config/routing.yml, and maybe even prefix it over there?
# app/config/routing.yml
app:
resource: "#AppBundle/Resources/config/routing.yml"
prefix: /app
After installing and configuring successfully FOSUserBundle for Symfony 2.3.4, I observed that the two routes (path/register and path/register/) both work. In my routing configuration, I only have the route path/register/.
I don't have any .htaccess file associated with my project (which runs under Apache server).
When I inspect under developement tools, I see that path/register gives a 301 Moved Permanently status code and redirects to path/register/ with 200 status code. What is the mechanism/code that allowed this?
Any explanations are highly appreciated.
Edit based on first answer:
I am not trying to understand how routing works, or how to customize my routing. I am trying to understand the mechanism behind redirection (from /register to /register/); Is it implemented somewhere in the core Symfony2 or is it a browser related?
Thank you
Fos user bundle routing is explained in detail here:
https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/routing.md
Here you find a answer
How to customize FOS UserBundle URLs
Generally:
Routing is handled in different ways in Symfony (config files, annotations,...)
Check your routing.yml as a first entry point. Get all available routes by using the console tool:
php app/console route:debug
Annotations usage:
* #Route("/hello/{name}", name="hello")
Is there any way to register bundle's routing from within bundle itself and not importing it in the main routing file?
Now my routing.yml looks like this:
my_route:
resource: "#MyExampleAdhocBundle/Resources/config/routing.yml"
prefix: /
However, I would like to somehow enable bundle routing in ExampleBundle class or bundle config, so it will be on only if bundle is registered in AppKernel.
Have you tried to do this inside your bundle extension file (AcmeDemoExtension for the AcmeBudle) ?
I think you should look inside Kernel::buildContainer to understand how it's done and how you can handle this.
I think custom route loader is the answer.
A custom route loader allows you to add routes to an application without including them, for example, in a Yaml file. This comes in handy when you have a bundle but don't want to manually add the routes for the bundle to app/config/routing.yml. This may be especially important when you want to make the bundle reusable, or when you have open-sourced it as this would slow down the installation process and make it error-prone.
Alternatively, you could also use a custom route loader when you want your routes to be automatically generated or located based on some convention or pattern.
No. For every bundle the routing must be imported in routing.yml. Every popular bundle (like FOSUserBundle) have to do this also.
So no bundle can override users routing. Importing the routes in routing.yml offers the option to define a prefix or host option on this imported routes.