Ik ben een Request class aan het maken. Via deze class kan ik bijv. het domein van de opgevraagde URL opvragen, of het subdomein, en of het een beveiligde (https) verbinding betreft. De gegevens haal ik op uit de $_SERVER array. Nu had ik gewoon allemaal public funtcions gemaakt. Echter... ik realiseer me ineens dat gedurende 1 request de $_SERVER array altijd hetzelfde is. Het zou dan raar zijn als ik telkens als ik de Request class nodig heb "new Request()" zou doen.
Nu vraag ik me af wat volgens jullie de beste oplossing is. Ik zou een singleton kunnen maken, zodat je niet "$request = new Request()" doet, maar "$request = Request::getInstance()". Wat ik ook kan doen is iedere functie in de Request class static maken, zodat ik het domein bijv. als volgt opvraag: $domain = Request::getDomain();
Door de contstructor private te maken, dwing je jezelf om altijd de makkelijke functie te gebruiken.
Dus alleen omdat je zelf geen goed beeld hebt van je klassen wil je toepassing onmogelijk maken? Vind het een erg klein argument als ik eerlijk mag zijn. Maar goed, heb wel weer genoeg gediscussieerd, schrijf je framework gewoon zoals jij het wilt, ik heb genoeg gedaan je over te halen....
Haha, ja dat heb je zeker. Het geeft mij in ieder geval weer stof tot nadenken :)
Iedereen heeft z'n eigen stijl en ik sta ook zeker open voor alle argumenten. Ik heb in ieder geval weer een hoop dingen gehoord waar ik mee aan de slag kan. Thanks! ;)
Ah, oke thanks... dat is inderdaad precies wat ik bedoelde.
Kun je misschien met een (simpel) code voorbeeldje eens laten zien hoe dit in elkaar steekt?
Hoe je zeg maar die session manager in de container stopt en hoe het setten en getten in z'n werk gaat?
(Hoeft niet heel uitgebreid hoor. Ik ben met name benieuwd hoe de session manager (ik neem aan dat dat een class is) in de container terecht komt en hoe de set en get functies werken Die zijn denk ik onderdeel van de session manager class?)
We nemen aan dat de container een heel simpel klasje is, zoals:
<?php
class Container
{
// ...
/**
* Sets a parameter.
*
* @param string $id The name of the parameter
* @param mixed $value
*/
public function setParameter($id, $value)
{}
/**
* Gets a parameter.
*
* @param string $id The name of the parameter
*
* @return mixed
*/
public function getParameter($id)
{}
/**
* Sets a factory which builds a service.
*
* @param string $id The name of the service
* @param \Closure $factory
* @param boolean $shared Optional, default is `true`, which means that it always returns the same instance
*/
public function set($id, \Closure $factory, $shared = true)
{}
/**
* Gets a service.
*
* @param string $id The name of the service
* @param boolean $raw Optional, default is `false`. If true, the factory is returned and not called
*
* @return object The result of the factory
*/
public function get($id, $raw = false)
{}
}
?>
De klassen zelf ga ik hier niet maken, we houden het even kort. We gaan hier alleen de Container configureren en vervolgens gebruiken.
Allereerst moet je natuurlijk nadenken wat een service 'moet' zijn. Ik ben van mening dat elke globale klasse het verdient een service te zijn, hiermee bedoel ik dat bijv. SessionManager een service is, Database, maar niet globale klassen zoals Controller klassen moeten geen services zijn.
Dan de concepten van iedere Container. Je hebt namelijk 2 typen code die je kunt opslaan in een container: parameters en factories. De parameters zijn gewoon variabele die een waarde vasthouden, factories zijn Closures (anonymous functions) die ervoor zorgen dat de klasse aangemaakt wordt. Het voordeel van deze factories is dat hij pas wordt uitgevoerd als je hem opvraagt, dit betekend dat als je hem niet gebruikt hij geen tijd verspilt aan het aanmaken (speciaal voor jou ;-).
Wat ik altijd doe, en dat heb ik weer van symfony, is dat ik de klasse van de service opsla in een parameter. Mocht ik de klasse willen veranderen, maar de rest hetzelfde houden, dan hoef ik niet aan de factory te knoeien maar alleen 1 parameter (wat veel simpeler is).
Daarnaast moeten we bedenken wat voor dependencies the SessionManager in ons geval zou moeten hebben, in ieder geval een raw Session factory die een Session klasse aanmaakt, deze kunnen we dan gebruiken als we een nieuwe sessie willen aanmaken met de Manager. Daarnaast is het ook handig om een array te krijgen van de huidige sessies. Dit betekend dus dat we 1 service factory en 1 parameter moeten krijgen.
Dan vragen we ons af of we deze via de constructor of via een getter meegeven, aangezien de SessionManager niks kan zonder de Session factory moeten we die via de constructor meegeven en de huidige sessies moet ook via de constructor (die hebben we immers meteen nodig).
Tot zover het nadenken, aan de slag:
<?php
$container = new Container();
// session service factory
$container->set('session', function ($c) {
return $c->getParameter('session.class')();
});
// de SessionManager klasse
$container->setParameter('session_manager.class', 'Ozzie\Framework\Session\SessionManager');
// de huidige sessies
$container->setParameter('session_manager.current_sessions', $_SESSION);
// de SessionManager factory
$container->set('session_manager', function ($c) {
return $c->getParameter('session_manager.class')(
$c->get('session', true),
$c->getParameter('session_manager.current_sessions')
);
});
?>
Nu hebben we de container helemaal geconfigureerd (dit doen we nu met PHP, later wil je hier misschien XML of Yaml voor gebruiken).
Tijd om hem te gebruiken:
<?php
use Ozzie\Framework\Controller\Controller;
use Ozzie\Framework\Controller\Http\Response;
class WelcomeController extends Controller
{
public function indexAction()
{
$html = '<!doctype html><meta charset=utf-8><title>hello world</title>';
$sm = $this->getContainer()->get('session_manager');
if (!$sm->has('visitor_name') {
// new visitor
$html .= '<h3>Welkom op deze website!</h3>';
} else {
// returning visitor
$html .= '<h3>Welkom terug, '.$sm->get('visitor_name').'!</h3>';
}
return new Response($html);
}
}
?>
In dit geval gaan ik ervan uit dat de Controller klasse van je framework de ContainerAware klasse overerft (die weer ContainerAwareInterface implementeerd) die ervoor zorgt dat we toegang hebben tot de getContainer en setContainer methods.
[edit]Sorry, niet erg kort geworden. Naja, als je er wat aan hebt, nu heb ik tenminste ook weer een mooi bericht om vaker naar te linken.[/edit]
Poeh... heftig... wat is dit eigenlijk? 'Ozzie\Framework\Session\SessionManager' Is dat het pad naar de Session Class?
Bedoel je met "current_sessions" de inhoud (array velden) van de huidige sessie? Of bedoel je hier echt de afzonderlijke sessiebestanden op de server mee?
Ik moet nog even doorkrijgen wat nu precies het verschil is tussen session en session_manager.
(Merk dat ik niet heel scherp meer ben momenteel...)
wat is dit eigenlijk? 'Ozzie\Framework\Session\SessionManager' Is dat het pad naar de Session Class?
Dit is de SessionManager klasse in de Ozzie\Framework\Session namespace.
Bedoel je met "current_sessions" de inhoud (array velden) van de huidige sessie? Of bedoel je hier echt de afzonderlijke sessiebestanden op de server mee?
Kijk maar naar de definitie van current_sessions op regel 17.
Ik moet nog even doorkrijgen wat nu precies het verschil is tussen session en session_manager.
Session is 1 enkele sessie en SessionManager is de DataMapper voor deze sessies.
De session klasse is toch maar 1 sessie? Daar kun je dan alleen de gegeven uit halen voor 1 sessie. Je hebt dan nog een klasse nodig die alle sessies groepeert en die ervoor zorgt dat je sessies kunt aanmaken, updaten, verwijderen en uitlezen?