Modular application structure in Symfony2

时间:2016-10-20 12:45:28

标签: symfony architecture modularity

I'm building a tax office self-service application with Symfony2 that will have a modular structure.

These modules are contained within separate bundles, for example a TaxBillsBundle, DirectDebitBundle and PersonalDataBundle. These bundles contain the frontend/backend functionality, entities, etc.

The idea is to have the AppBundle glue the modules together. Now, since this is my first application in Symfony2, I'm not sure how to approach this.

This is the main screen of the application:

Tax Office application mock-up

Each tile represents a module. What is the best way to compose this screen? The AppBundle is responsible for displaying the tiles, but not for their contents. I don't want to touch the AppBundle when adding new modules.

A co-worker suggested to use the event system. The AppBundle could 'broadcast' a request for tile contents, to which the modules (subscribers) can respond. Once all tile contents are collected, the AppBundle could compose the page. Is this a reasonable approach? Any other ideas?

2 个答案:

答案 0 :(得分:1)

我建议在每个非AppBundle捆绑包中使用订阅者类,实现symfony的事件调度程序并向其添加订阅者。

http://symfony.com/doc/current/components/event_dispatcher.html

答案 1 :(得分:0)

If they're static tiles, I would just create a twig template for each in the views directory for the whole app: app/Resources/views/modules/dashboard-tiles/module-x.html.twig and include it in the dashboard app/Resources/views/pages/dashboard.html.twig view file. If they're similar in content, you could refactor to use a single twig module file and pass it the data:

// DashboardController.php
public function dashboardAction()
{
    /** You could use an entity and create new objects for tiles instead of building an array like this. Or a method to return each one. **/
    $tiles = [];
    $tiles[] = [
        'name' => 'Personal Data',
        'links' => [
             {
                 'text' => 'Show data',
                 'icon' => 'fa-user',
                 'href' => '#'
             },
             {
                 'text' => 'Edit data',
                 'icon' => 'fa-edit',
                 'href' => '#'
             }
        ]
    ];

    return $this->templating->renderResponse(
        'PathTo/dashboard.html.twig', [ 'tiles' => $tiles ]);
}

// dashboard.html.twig
{% for tile in tiles %}
    {% include 'modules/dashboard-tiles/tile.html.twig' with { 
        'tile': tile 
    } %}
{% endfor %}

# tile.html.twig
<div class="tile">
    <h2>{{ name }}</h2>
    {% for link in links %}
        <a href="{{ href }}"><i class="fa {{ icon }}"></i> {{ text }}
    {% endfor %}
</div>

If they're dynamic, I would set up a service in each bundle with a method to return the required data for the view which can be called from your controller and sent to twig. You'd probably want to use Dependency Injection to get the services into your controller and then use them as such:

$tiles[] = $this->personalDataService->getDashboardTile();

But it looks like the tiles just contain buttons so why not keep it simple.