Symfony2 bundles
Nu bestaat deze website uit verschillende delen, namelijk een nieuws-, download-, rooster- en administratiegedeelte. Het probleem waar ik nu tegen aan loop is de bundles. Moet ik deze allemaal in aparte bundles zetten zoals MyNewsBundle, MyDownloadBundle, MyTimetableBundle en MyAdministrationBundle, of moet ik 1 bundle maken genaamd MySiteBundle?
Als ik de eerste structuur zou gebruiken, dan is de MyAdministrationBundle heel erg afhankelijk van de andere bundles, omdat deze de enige is die content kan toevoegen.
Ik kan voor deze bundle natuurlijk ook een al bestaande bundle gebruiken, zoals de AdmingeneratorGeneratorBundle. Dit zou ik denk ik ook wel kunnen doen voor het nieuws- en downloadgedeelte, maar waarschijnlijk niet voor het roostergedeelte.
Hoe kan ik het beste dit alles opdelen?
Dit is eigenlijk een vraag voor Wouter want die weet zo een beetjes alles over Symfony2 geloof ik.
Maar wat ik denk is dat het idee achter de Bundles is dat je ze later later heel erg makkelijk kan hergebruiken. Als je dan dus een hele site in één bundle gaat stoppen dan raakt dat effect weg. Maar wanneer je inderdaad een downloadbundle maakt en in je gedachte houd dat je die later voor een ander project wilt hergebruiken dan ben je naar mijn idee goed bezig.
Dat een Bundle afhankelijk is/wordt van een andere Bundle is heel normaal. En met Composer - als ik het goed heb - kun je alle "dependencies" instellen zodat die later automatisch met jouw eigen bundel worden geinstalleerd.
Gewijzigd op 24/06/2013 10:17:49 door Koen Vlaswinkel
Bundles moeten zo flexible en standalone mogelijk. Je zal merken dat er in Symfony2 erg veel mogelijkheid is om dit te doen doormiddel van goed gebruik van de container en de configuratie.
Altijd meerdere bundles maken voor een website waarbij iedere bundle zijn eigen unieke feature implementeert. En elke bundle zo bouwen dat je er oog voor hebt dat het straks in een ander project nog steeds moet werken. Ik zou er nog 1 bundle bij doen: de UserBundle.
Hoe maak je dan bundles flexibel? Laten we eerst je adminbundle pakken. Hoe kunnen we ervoor zorgen dat elke bundle zelf de klassen bevat voor de admin en dat je die in de adminbundle kunt opvragen en kunt omtoveren naar een admin interface? Dat doen we door van deze klassen een service te maken. Services kun je taggen met tags. In de KoenAdminBundle kun je dan de services opvragen met de koen_admin.admin tag en die kun je dan meegeven aan de service die het admin panel maakt. Voorbeeld:
Code (php)
1
2
3
4
5
2
3
4
5
services:
koen_blog.admin.article:
class: Koen\BlogBundle\Admin\ArticeAdmin
tags:
- { name: koen_admin.admin }
koen_blog.admin.article:
class: Koen\BlogBundle\Admin\ArticeAdmin
tags:
- { name: koen_admin.admin }
Het verkrijgen van services by tag gebeurd in een compiler pass:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
// src/Koen/AdminBundle/DependencyInjection/Compiler/AdminClassesPass.php
namespace Koen\AdminBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class AdminClassesPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$adminClasses = $container->findTaggedServiceIds('koen_admin.admin');
$adminPool = $container->get('koen_admin.pool'); // de klasse die de admin panel maakt
foreach ($adminClasses as $id => $attributes) {
$adminPool->addMethodCall('addAdminSection', new Reference($id)); // roep bij het aanmaken van de service de method addAdminSection aan met de service met de tag (voor elke service)
}
}
}
?>
// src/Koen/AdminBundle/DependencyInjection/Compiler/AdminClassesPass.php
namespace Koen\AdminBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class AdminClassesPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$adminClasses = $container->findTaggedServiceIds('koen_admin.admin');
$adminPool = $container->get('koen_admin.pool'); // de klasse die de admin panel maakt
foreach ($adminClasses as $id => $attributes) {
$adminPool->addMethodCall('addAdminSection', new Reference($id)); // roep bij het aanmaken van de service de method addAdminSection aan met de service met de tag (voor elke service)
}
}
}
?>
Ik zou je aanraden deze adminbundle niet zelf te maken, maar de SonataAdminBundle te gebruiken.
Een andere mogelijkheid voor static strings is het maken van eigen configuratie. Dat is een beetje te ingewikkeld om hier even uit te leggen. http://symfony.com/doc/current/cookbook/bundles/extension.html
Als je met Doctrine2 ORM werkt definieer je de tabelnaam per entity. Waarom zou je deze globaal willen instellen?
En met de tabelnaam voor Doctrine bedoel ik dat als ik een bundle met entity wil hergebruiken, en ik wil bijvoorbeeld de tabelnaam van articles naar blogposts wijzigen, dan zou ik dus de bundle moeten aanpassen.
En nu wil ik ook nog een API aan mijn website koppelen. Deze bundle zal dan erg afhankelijk worden van mijn andere bundles, is dat erg?
Als je echter een api bundle gaat maken is het weer verstandig dat die bundle heel flexibel is en dat je in de mainbundle de api voor je website maakt. Kijk anders eens naar de FosUserBundle.
En een tabelnaam wil je niet kunnen veranderen. Wat maakt het uit hoe dat ding heet in de database? Als je maar makkelijk je entities kunt gebruiken. Voor dynamische relaties kun je eens kijken naar de resolve target entity feature van Doctrine2.
Maar nu zouden sommige bundles maar 1 controller hebben, wat wel erg kleine bundles zijn. Met een NewsBundle heb je alleen maar een indexAction en een showAction, de rest heb je niet nodig. Ik neem aan dat je hier niet 2 controllers gaat maken, dus de NewsBundle is erg klein. Maar je kan dus ook erg kleine bundles in je website hebben?
Ja, dat kan. Nu zou de nieuwsbundle ook al een admin klasse nodig hebben, en misschien support voor comments, ect. Dus al met al is die bundle niet heel klein. Maar ookal was hij klein, het is en blijft een bundle.