Twig en namespaces
Een groot deel van m'n codebase is nu af, en nu is het tijd voor iets anders: templating! Heb eens gekeken naar Twig, heel mooi allemaal!
Nu zit ik toch met een probleem. Twig maakt geen gebruik van namespaces.
"Boeiend" denk je dan, maar voor m'n applicatie gebruik ik constant namespaces en om dan met Twig_X_X dingen te beginnen is een beetje raar.
Heeft twig iets als een aparte versie waar namespaces mee werken ofzo?
En als Twig dat echt niet gebruikt, is er dan een andere templating engine die met namespaces werkt?
Bedankt
Gewijzigd op 11/11/2012 18:20:53 door - Raoul -
Fabien Potencier, de maker van Twig, heeft al in 2 issues aangeven dit niet te gaan doen. Om 1 hele belangrijke reden: Het is een enorme BC break, alles zou aangepast moeten worden. Dat is bijna ondoenlijk en zal alleen gebeuren in een nieuwe major versie, maar om naar een nieuwe major versie te gaan voor alleen namespaces is het niet waard en dus is het wachten op nieuwe grote ideeën voor twig voordat we over namespaces kunnen denken.
En nog wat extra redenen:
- Twig zal niet meer werken met PHP5.2
- Twig support al de PSR-0 standaards, dat is het belangrijkste qua klassebenaming
- Klassenamen moeten opnieuw gemaakt worden, Twig_Filter_Function kan niet Twig\Filter\Function worden, hetzelfde geldt voor veel andere klassen.
Twig is de beste templating engine die je kan vinden in PHP wereld, dat zeg ik niet alleen, maar dat hoor je overal. Overstappen naar een slechtere templating engine alleen omdat hij geen namespaces support in de backend code vind ik een bar slechte rede. Je hebt maar 2 keer de niet namespace klassen nodig, voor de rest kun je alles met namespaces doen (ook twig extensies) en kun je ook in de template werken met namespaces. De enige plaats waar je even de underscore methode ziet is hier:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
'cache' => '/path/to/compilation_cache',
));
?>
$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
'cache' => '/path/to/compilation_cache',
));
?>
Gewijzigd op 11/11/2012 18:29:52 door Wouter J
Kan ik een soort van "Twig storage" class maken die mijn Storage class implements, waarmee ik die $twig variable kan returnen?
Is dat correct OO?
Gewijzigd op 11/11/2012 20:50:47 door - Raoul -
Niet dat ik overigens geen fan ben van Twig ofzo hoor, want ik gebruik het op me werk de laatste weken en ben er juist helemaal weg van omdat je embedding hebt template inheritence, macro's etc!
Raoul gebruik je een specifieke autoloader al momenteel? Bijvoorbeeld met Composer moet het geen problemen opleveren..
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
Dus wat bedoel je met "geen problemen opleveren"... dat ik gewoon namespaces kan gebruiken?
Bedankt voor je reactie Kees. Ik maak momenteel gebruik van deze autoloader: Dus wat bedoel je met "geen problemen opleveren"... dat ik gewoon namespaces kan gebruiken?
Ja dat je gemixed namespaces en libraries die nog de oude naamgevingen hanteren Dus_Zoals_Dit als classname :)
Mijn bootstrap code:
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<?php
namespace Whear\Components;
error_reporting(E_ALL ^ E_NOTICE);
require_once 'lib/Whear/Component/Autoloader.php';
\Twig\Autoloader::register(); // als testje, uitkomst => 'class not found'
?>
namespace Whear\Components;
error_reporting(E_ALL ^ E_NOTICE);
require_once 'lib/Whear/Component/Autoloader.php';
\Twig\Autoloader::register(); // als testje, uitkomst => 'class not found'
?>
:s
Gewijzigd op 11/11/2012 23:57:26 door - Raoul -
Je moet wel gewoon Twig_Autoloader gebruiken i.p.v. \Twig\Autoloader, het werkt niet met namespaces.
Kees, daar geef ik je half gelijk in. Ik denk dat je van een aantal libraries toch wel kan zeggen dat ze 'de beste in PHP' wereld zijn, het meest gebruikt, de meeste contributors, de meeste fans. Ik vind dat bijv. een rijtje met Doctrine, Twig, het Symfony2 Form component en bijv. de Zend Mailer, ect.
Wel leuk dat je nu toch vol lof bent over Twig, dat was je vroeger namelijk totaal niet :)
Ok, maar mag ik dan een soort van TwigStorage maken, zodat ik niet op iedere pagina moet typen? Is dat correct OO?
En telkens opnieuw moet typen? In je front controller maak je 1 Twig Environment aan en die sla je ergens op, in je Registery, DIC, variabele, ect. Vervolgens moet je die telkens gebruiken:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/*
* Ergens in je bootstrap/front controller
*/
$container->set('template_parser.loader.dir', '/path/to/templates');
$container->set('template_parser.loader', function ($c) {
return new Twig_Loader_Filesystem($c->get('template_parser.loader.dir'));
});
$container->set('template_parser.options', array(
'cache' => '/path/to/compilation_cache',
));
// maak deze shared
$container->set('template_parser', function ($c) {
new Twig_Environment($c->get('template_parser.loader', $c->get('template_parser.options'));
});
/*
* in je projecten
*/
$container->get('template_parser')->render('foo.html', array(
'bar' => 'lorem ipsum',
));
?>
/*
* Ergens in je bootstrap/front controller
*/
$container->set('template_parser.loader.dir', '/path/to/templates');
$container->set('template_parser.loader', function ($c) {
return new Twig_Loader_Filesystem($c->get('template_parser.loader.dir'));
});
$container->set('template_parser.options', array(
'cache' => '/path/to/compilation_cache',
));
// maak deze shared
$container->set('template_parser', function ($c) {
new Twig_Environment($c->get('template_parser.loader', $c->get('template_parser.options'));
});
/*
* in je projecten
*/
$container->get('template_parser')->render('foo.html', array(
'bar' => 'lorem ipsum',
));
?>
Gewijzigd op 12/11/2012 19:15:17 door Wouter J
Bedankt voor je reactie Wouter. Mag zo'n Registry class static zijn? Ik zie namelijk op het internet alleen maar voorbeelden van static classes.
Wat ik nu liet zien is een Service container/Dependency Injection Container (DIC). Dit is een beter pattern dan de Registry.
Wouter J op 12/11/2012 23:18:59:
Wat ik nu liet zien is een Service container/Dependency Injection Container (DIC). Dit is een beter pattern dan de Registry.
Hmm, dat klopt wel. Maar hoe maak ik dan die $container 'global'? Als ik op iedere pagina een $container variable maak, dan is iedere instance daarvan leeg... :s Ik kan het wel in de bootstrap doen maar dan moet ik op iedere pagina diezelfde $container gebruiken, wat nogal lelijk is. Is een Storage wel mogelijk in dit geval?
Die container geef je gewoon mee aan een klasse, behalve als het een service klasse is (zoals Twig in dit geval), dan mag je alleen de benodigde dependencies injecteren. Voorbeeldje van het eerst:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
interface ContainerAwareInterface
{
protected function getContainer();
private function setContainer(Container $container);
}
abstract class ContainerAware implements ContainerAwareInterface
{
private $container;
protected function getContainer()
{
return $this->container;
}
private function setContainer(Container $container)
{
$this->container = $container;
}
}
?>
interface ContainerAwareInterface
{
protected function getContainer();
private function setContainer(Container $container);
}
abstract class ContainerAware implements ContainerAwareInterface
{
private $container;
protected function getContainer()
{
return $this->container;
}
private function setContainer(Container $container)
{
$this->container = $container;
}
}
?>
Deze klasse kan nu elke klasse die zich bewust (aware) is van de container extenden en je hebt toegang tot de service container.
Wouter J op 12/11/2012 07:48:25:
Wel leuk dat je nu toch vol lof bent over Twig, dat was je vroeger namelijk totaal niet :)
Hihi, wil nog niet zeggen dat ik het gebruik voor mijn eigen projecten ;-). Wie weet dat ik dat nog wel ga doen maar voor bijvoorbeeld mijn e-commerce platform niet, die is sowieso op Zend Framework gebouwd en performance is van best groot belang :)
Twig is behoorlijk goed voor je performance, bij je allereerste bezoeker wordt de pagina gecached in een geoptimaliseerde PHP template die vervolgens bij elke request wordt aangeroepen. In je productie omgeving moet er dus geen verschil zijn, misschien juist wel minder. In je test omgeving zal het wel wat langzamer zijn.
Wouter J op 13/11/2012 07:56:55:
Wat bedoel je met iedere pagina? Als het goed is heb je 1 bootstrap/front controller die elke pagina request wordt aangeroepen en waar je alles in wordt geincluded.
Die container geef je gewoon mee aan een klasse, behalve als het een service klasse is (zoals Twig in dit geval), dan mag je alleen de benodigde dependencies injecteren. Voorbeeldje van het eerst:
Deze klasse kan nu elke klasse die zich bewust (aware) is van de container extenden en je hebt toegang tot de service container.
Die container geef je gewoon mee aan een klasse, behalve als het een service klasse is (zoals Twig in dit geval), dan mag je alleen de benodigde dependencies injecteren. Voorbeeldje van het eerst:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
interface ContainerAwareInterface
{
protected function getContainer();
private function setContainer(Container $container);
}
abstract class ContainerAware implements ContainerAwareInterface
{
private $container;
protected function getContainer()
{
return $this->container;
}
private function setContainer(Container $container)
{
$this->container = $container;
}
}
?>
interface ContainerAwareInterface
{
protected function getContainer();
private function setContainer(Container $container);
}
abstract class ContainerAware implements ContainerAwareInterface
{
private $container;
protected function getContainer()
{
return $this->container;
}
private function setContainer(Container $container)
{
$this->container = $container;
}
}
?>
Deze klasse kan nu elke klasse die zich bewust (aware) is van de container extenden en je hebt toegang tot de service container.
In de bootstrap dan dit ofzo:
En dan op andere pagina's dit:
Dat is toch lelijk?! Maar als ik dan een class extends met ContainerAware moet ik nog altijd setContainer() doen waardoor die Container instance altijd leeg is.
Gewijzigd op 13/11/2012 16:55:03 door - Raoul -
BUMP