John Davidson

php - Is it possible to automatically embed bundle templates in project templates?

0 comments
Message:


I am working on a Symfony 6 based project. Beside the project it self I have created some bundles which contain code I use in multiple projects.


TL;DR:


Is it possible to automatically embed templates from such a bundle in a project specific template?


In general I am looking for something like this pseudo code:


// .../SomeProject/config/routes.yaml
...
my_user_admin:
resource: '@MyUserBundle/config/admin_routes.yaml'
prefix: /admin
embed_in_template: 'admin_routes.yaml::content' <<< Is this possible?

Details:


Assume MyUserBundle contains shared code to handle users in different projects. For example it contains controllers to list all registered users or edit a single user:


// .../MyBundle/config/routes/admin_routes.yaml
my_user_admin_user_list:
path: /users
controller: MyUserBundle\Controller\AdminController::userList

my_user_admin_user_details:
path: /user/{user_id}
controller: MyUserBundle\Controller\AdminController::userDetails


// .../MyBundle/src/Controller
public function userList(Request $request): Response {
...
return $this->render('@MyUser/admin/user_list.html.twig', ['users' => $users]);
}

public function userDetails(Request $request): Response {
...
return $this->render('@MyUser/admin/user_details.html.twig', [...]);
}


// .../MyBundle/templates/admin/user_list.html.twig
<table>
{% for user in users %}
<tr><td>{{ user.name }}</td></tr>
{% endfor %}
</table>

In this example the userList controller does NOT output a complete page with header, body, etc. but only the HTML code of the user list itself.


This controller/route can easily be used in a projects which uses this bundle:


// .../SomeProject/config/routes.yaml
...
my_user_admin:
resource: '@MyUserBundle/config/admin_routes.yaml'
prefix: /admin

https://someproject.xx/admin/users will now show the user list. But again only the pure user list without any surrounding HTML code.


Question


Is it possible to tell Symfony to automatically embed the output of this controller/route with some other template?


For example the project specific template .../SomeProject/templates/admin_base.html.twig contains the HTML skeleton to be used for all admin backend pages of this project, including the nav menue, etc.


// .../SomeProject/templates/admin_base.html.twig
<!DOCTYPE html>
<html>
<head>...</head>
<body>
<nav class="adamin_nav">...</nav>
{% block content %}
// user list of MyUserBundle\Controller\AdminController::userList should be here...
{% endblock %}
</body>
</html>

Manual solutions


There a some solution to do this manually of course:



  • Override MyUserBundle\Controller\AdminController within the project and render a different, project specific template based on admin_base.html.twig

  • Do not import the routes from MyUserBundle but define a custom route and controller in SomeProject which uses {{ render(controller(MyUserBundle\Controller\AdminController::userList)) in its template

  • Override the bundle template by providing .../SomeProject/templates/bundles/MyUserBundle/user_list.html.twig which can then extend admin_base.html.twig. However, I do not know how to render the content of the parent template file in there.


While these solution would work, it would be very cumbersome. There is not only route/controller from one bundle which should be used in this way but multiple routes/controller from multiple bundles. One would have have to add a new route/controller/template override, etc. to the project for each bundle controller which should be added. Is this really the way to go?


Symfony is so flexible and provides so many options, I am not sure, that this is really the best option.


In general I am looking for something like this pseudo code:


// .../SomeProject/config/routes.yaml
...
my_user_admin:
resource: '@MyUserBundle/config/admin_routes.yaml'
prefix: /admin
embed_in_template: 'admin_routes.yaml::content' <<< Is this possible?


My Answer:
Unfortunately, Symfony does not provide a built-in feature to automatically embed the output of a controller/route from a bundle into a project-specific template. The manual solutions you mentioned are the common ways to achieve this functionality.

However, you can create a custom Twig function or extension to simplify the process of embedding the output of a controller/route from a bundle into a project-specific template. This custom function or extension can handle the rendering of the controller output within the project-specific template.

Here is an example of how you can create a custom Twig function to achieve this:

1. Create a custom Twig function in your project:
php
// .../SomeProject/src/Twig/EmbedControllerOutputExtension.php

namespace App\Twig;

use Symfony\Component\HttpKernel\KernelInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class EmbedControllerOutputExtension extends AbstractExtension
{
private $kernel;

public function __construct(KernelInterface $kernel)
{
$this->kernel = $kernel;
}

public function getFunctions()
{
return [
new TwigFunction('embed_controller_output', [$this, 'embedControllerOutput'], ['is_safe' => ['html']]),
];
}

public function embedControllerOutput(string $controller, array $parameters = [])
{
$request = Request::create($controller);
$response = $this->kernel->handle($request);

return $response->getContent();
}
}


2. Register the custom Twig function as a service in your project:
yaml
# .../SomeProject/config/services.yaml

services:
App\Twig\EmbedControllerOutputExtension:
arguments:
$kernel: '@kernel'
tags:
- { name: twig.extension }


3. Use the custom Twig function in your project-specific template:
twig
{# .../SomeProject/templates/admin_base.html.twig #}



...


{% block content %}
{{ embed_controller_output('MyUserBundle\Controller\AdminController::userList') }}
{% endblock %}




By using this custom Twig function, you can simplify the process of embedding the output of a controller/route from a bundle into a project-specific template. This approach can help reduce the manual effort required for each bundle controller that needs to be embedded in the project template.

Rate this post

4 of 5 based on 1913 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us