Symfony 2 bundles have a nice feature for autoloading/extending the application configuration files, such as services.yml. However, this is not true for routing, since i have to manually edit the routing.yml of my application in order to load the routing data from my Bundle (the Controller or the routing.yml itself).
Is it possible to load such routing configuration this seamlessly?
---- EDIT
I ended up doing this, but it's ugly as hell:
<?php
use Symfony\Component\Routing\RouteCollection;
$collection = new RouteCollection();
foreach (glob(__DIR__.'/../../src/Vendor/MySystem/Plugins/*Bundle/Controller/', GLOB_ONLYDIR) as $controller) {
$controller = str_replace(__DIR__.'/../../src/Vendor/MySystem/Plugins/', '', $controller);
$collection->addCollection($loader->import("#$controller"));
}
return $collection;
i think you should look after the "routing.loader" dependency injection tag
It let you define a class to define routes with your logic
http://symfony.com/doc/current/reference/dic_tags.html#routing-loader
I think You could also define an dependencyInjection extension in your bundle.
In your load method, you can alter the container definitions and so your routes..
Related
I search for a way to change the configuration of the Symfony twig bundle in order to register additional twig namespaces.
I tripped over prepend extension but this would just solve the problem half way. When I write code like this:
public function prepend(ContainerBuilder $container)
{
$bundles = $container->getParameter('kernel.bundles');
if (isset($bundles['TwigBundle'])) {
$config = $container->getExtensionConfig('twig')[0];
$paths = ['/path/to/cms' => 'cms'];
if (array_key_exists('path', $config)) {
$paths = array_merge($config['paths'], $paths);
}
$config['paths'] = $paths;
$container->prependExtensionConfig('twig', $config);
}
}
This would mean that no other bundle could ever change the twig configuration again:
How to add twig namespaces from inside a bundle without obstructing a way for other bundles to do the same?
You can do this by creating a Compiler Pass within your Bundle:
class CustomCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if ($container->hasDefinition('twig.loader.native_filesystem')){
$bundleDirectory = \dirname(__DIR__,2);
$twigFilesystemLoaderDefinition = $container->getDefinition('twig.loader.native_filesystem');
$twigFilesystemLoaderDefinition->addMethodCall('addPath', [$bundleDirectory.'/templates/admin', 'admin']);
}
}
}
Twig namespaces are an application concern, not a bundle concern.
Registering new namespaces from within the bundle could clash with already defined namespaces by the application that consumes the bundle.
Furthermore, it's not necessary, because Symfony already auto-crates a namespace for each bundle:
If you install packages/bundles in your application, they may include their own Twig templates (in the Resources/views/ directory of each bundle). To avoid messing with your own templates, Symfony adds bundle templates under an automatic namespace created after the bundle name.
For example, the templates of a bundle called AcmeFooBundle are available under the AcmeFoo namespace. If this bundle includes the template <your-project>/vendor/acmefoo-bundle/Resources/views/user/profile.html.twig, you can refer to it as #AcmeFoo/user/profile.html.twig.
You shouldn't mess with that configuration. Leave it up to the application developer or the framework to deal with it.
I was reviewing the symfony 3.4 routing page. I have a misunderstanding if anyone can help me. So say you have the following:
In Your controller:
class BlogController extends Controller
{
/**
* Matches /blog exactly
*
* #Route("/blog", name="blog_list")
*/
public function listAction()
{
// ...
}
}
And in your routing.yml:
blog_list:
path: /blog
defaults: { _controller: AppBundle:Blog:list }
Would you be able to delete the route annotation above the function. Because now the routing is being handled by the routing.yml?
Many thanks
You must choose one of this methods to set route for current url "/blog"
In Symfony Routing can be declare using YAML, XML, PHP or annotation. It is recommended you stick with only one but you can use multiple approaches in a single project.
Official doc for routing Symfony Routing
and the answer to your question is, I would say yes you could delete the annotation.
Because now the routing is being handled by the routing.yml
for the big project, I prefer YML routing.
I want to use symfony routing as standalone routing for my project, I have the following structure:
app
|--project
|----controller
|------catalog
|--------category.php
|--config
|----routes.yml
|--bootstrap
|----application.php
inside category.php I have a class named Category, that has a method named index().
The router is called from boostrap\application.php
How would can I specify the path to the category file in the routes.yml?
Right now it look like below
search:
path: /search
defaults: { _controller: 'app\project\controller\catalog\category\category::index' }
Loading files is not the responsibility of the routing component. This component is just used to match routes to functions inside a class.
If you want classes to be found, you can use two methods:
add an autoloader which loads the specified classes
Follow PSR-0 (with namespaces matching the filenames and directory structure) and use composer's classloader.
I'd suggest to use the second way. This is the standard in PHP, and you're probably already using the autoloader if you fetched the routing component trough composer.
I'm trying the framework ZF2 and I try to do very independant modules like bundles in SF2.
I've got ZfcTwig to have Twig to render my views. This worked until I've created a second module.
-Application (default module)
-Admin
-view
index.twig
-layout
base.twig
-Blog
-view
index.twig
-layout
base.twig
The problem is that my Blog layout extend the Admin base layout then !
I've done my structure layout based on http://blog.evan.pro/module-specific-layouts-in-zend-framework-2
So in both Module.php I've this:
public function init($moduleManager)
{
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
$controller = $e->getTarget();
$controller->layout('layout/base.twig');
}, 100);
}
Plus I don't understand why I've to define twice the layout, one time in the init function of Module.php, the second on extend function of twig views.
For sure its work if I've different names.
And I see for this module: https://github.com/EvanDotPro/EdpModuleLayouts
But I think it should be possible without this to have really independant module since its the philosophy of the framework.
By default, ZfcTwig works in "zf way", using the two-step view pattern.
If you want to use the original twig system (for extends), you must specify it in your config file.
It is well commented :
/**
* If set to true disables ZF's notion of parent/child layouts in favor of
* Twig's inheritance model.
*/
'disable_zf_model' => true,
This way, you will control yous layouts with extends instructions.
I'm creating a control panel application that has a base bundle with some basic functionality and specific bundles for advanced and specific functionality.
for example the base bundle handles user authentication and holds all the template assets and other bundles add functionalities to config different parts of the operating system.
I need to be able to add menu links in the layout of the base bundle to each of the other bundles. and I prefer to do it in each bundles configuration so I can mix and match features for different clients.
I read all about Compiler Passes, Extensions and dependency injection with no luck. is there correct of doing it ?
If you are using Twig this should do the trick...
{% render "DifferentBundle:ControllerName:functionalityName" with {'argument_name': 3} %}
You should have a functionalityNameAction method in your DifferentBundle controller for this to work.
Take a look at the Creating and using Templates - Embedding Controllers section in the doc.
Hope it helps.
Just in case anyone has a similar problem, here is how I achieved this:
I created a service in my BaseBundle that implements the __get , __set, __isset and __unset magic methods and has an extra append method. it stores variables in a static variable inside the class.
I then added Listeners to all my bundles :
namespace Mbs\OtherBundle\Listener;
use Mbs\BaseBundle\Services\GlobalVars;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class ControllerListener
{
protected $_global_vars;
public function __construct(GlobalVars $global_vars)
{
$this->_global_vars = $global_vars;
}
public function onKernelController(FilterControllerEvent $event)
{
$this->_global_vars->append('bundles', 'mbs.other');
}
}
This is my services.yml for one of the bundles. GlobalVars is the class I mentioned earlier.
services:
mbs.base_controller_listener:
class: Mbs\OtherBundle\Listener\ControllerListener
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
arguments: [ #mbs.global_vars ]