2.3. Onderklassen

2.3.1. Inleiding

Het Zend_Controller systeem werd gebouwd met uitbreiding in het hoofd, ofwel door het onderklassen van de bestaande klassen of door het schrijven van nieuwe klassen die de interfaces van Zend_Controller_Router_Interface en Zend_Controller_Dispatcher_Interface implementeren.

Mogelijke redenen om een nieuwe router of dispatcher te implementeren kunnen zijn:

  • Het bestaande URI routing systeem is niet toepasbaar om één of andere reden, zoals de integratie in een bestaande website die zijn eigen conventies voor routing heeft en die niet overeenkomen met het routing systeem van het Zend Framework.

  • Je moet een routing systeem implementeren voor iets volledig anders. De Zend_Controller_Router klasse kan alleen URIs afhandelen. Het is mogelijk --en waarschijnlijk-- dat je het MVC patroon wil gebruiken om een ander type programma te ontwikkelen, zoals een console toepassing. In het geval van een console toepassing zou een aangepaste router argumenten van de commandoregel moeten kunnen verwerken om de route te determineren.

  • Het mechanisme dat door Zend_Controller_Dispatcher wordt verstrekt is niet toepasbaar. De standaard configuratie neemt een overeenkomst aan die zegt dat controllers klassen zijn en acties methodes van die klassen. Er zijn evenwel vele andere strategiën om dit te doen. Eén voorbeeld zou zijn waar de controllers mappen zijn en de acties bestanden in die mappen.

  • Je wil bijkomende mogelijkheden verstrekken die door al je controllers worden geërfd. Bijvoorbeeld, Zend_Controller_Action kan niet standaard geïntegreerd worden met Zend_View. Wat je evenwel wèl kan doen is je eigen controller aanpassen zodat die kan integreren met Zend_View. Die gebruiken vermijdt het wijzigen van de verstrekte Zend_Controller_Router of Zend_Controller_Dispatcher.

Wees voorzichtig met het wijzigen van belangrijke delen van het systeem, en in het bijzonder de dispatcher. Een van de voordelen van Zend_Controller is dat het algemene overeenkomsten vestigt voor het bouwen van toepassingen. Indien teveel van dit standaard gedrag wordt gewijzigd, zal een deel van deze voordelen verloren gaan. Er zijn evenwel vele verschillende benodigdheden en één enkele oplossing is niet ideaal voor alle situaties. De vrijheid om te wijzigen is dus verstrekt indien nodig.

2.3.2. Overeenkomsten

Bij het onderklassen van een Zend_Controller klasse is het sterk aangeraden de volgende overeenkomsten te respecteren bij de benaming en het opslaan van bestanden. Door dit te doen verzeker je ervan dat een andere programmeur die het Zend Framework kent gemakkelijk je project kan begrijpen.

2.3.2.1. Prefix

Klassen die inbegrepen zijn in het Zend Framework volgen een overeenkomst waarbij elke klasse geprefixed wordt door "Zend_". Dat is de prefix. We raden sterk aan dat jij al jouw klassen op een gelijkaardige wijze benoemd, bv: als je bedrijf Widget NV noemt, zou de prefix "Widget_" kunnen zijn.

2.3.2.2. Mappen Lay-out

Zend_Controller klassen worden als volgt in de bibliotheekmap opgeslaan:

/library
  /Zend
    /Controller
      Action.php
      Dispatcher.php
      Router.php

Bij het onderklassen van Zend_Controller klassen is het aangeraden dat de nieuwe klassen opgeslagen worden in een gelijkaardige structuur onder jouw prefix. Dat maakt het gemakkelijk om ze te vinden voor iemand gedurende dat leerprocess dat het nakijken van de code van jouw project is.

Bijvoorbeeld, een project Widget NV dat alleen een aangepaste router implementeerd zou op het volgende kunnen lijken:

/library
  /Zend
  /Widget
    /Controller
      Router.php
      README.txt

Merk in dit voorbeeld op dat de Widget/Controller/ map de Zend/Controller/ weerspiegelt waar dat ook maar enigzins mogelijk is. In dit geval verstrekt het een Widget_Controller_Router klasse die een onderklasse of een vervanging is voor Zend_Controller_Router en die de Widget_Controller_Router_Interface implementeert.

Merk ook op in het voorbeeld hierboven dat een README.txt bestand is opgeslaan in Widget/Controller. Zend moedigt je sterk aan je projecten te documenteren door afzonderlijke tests en documentatie te verstrekken voor je klanten. We moedigen je ook sterk aan een eenvoudig README.txt bestand te plaatsen in de map om kort je veranderingen uit te leggen en hoe ze werken.

2.3.3. Router Interface

De interface Zend_Controller_Router_Interface verstrekt een definitie voor één enkele methode:

<?php
				
  /**				
   * @param  Zend_Controller_Dispatcher_Interface
   * @throws Zend_Controller_Router_Exception
   * @return Zend_Controller_Dispatcher_Token|boolean
   */
  public function route(Zend_Controller_Dispatcher_Interface $dispatcher);

?>

Routing gebeurt slecht één enkele keer: wanneer het verzoek voor het eerst door het systeem wordt ontvangen. Het doel van de router is een Zend_Controller_Dispatch_Token aan te maken dat een controller en een actie van die controller definieert. Dit wordt dan doorgegeven aan de dispatcher. Indien het niet mogelijk is een route naar een dispatch token te mappen (nonsensical route) dan moet er een boolean, FALSE worden teruggestuurd.

Sommige routers kunnen dynamische elementen verwerken en hebben een manier nodig om de determineren of het aldus gegenereerde token inderdaad dispatchbaar is voordat het wordt teruggestuurd. Om deze reden ontvangt de router de object handle van de dispatcher als enig argument voor zijn route() methode. De dispatcher verstrekt een methode, isDispatchable() om dit te testen.

2.3.4. Dispatcher Interface

Zend_Controller_Front zal eerst de router benaderen om een eerste dispatch token te ontvangen en zal dit doorgeven aan de dispatcher. De dispatcher zal de actie (de controller instantiëren, zijn actie oproepen) dispatchen en dan ofwel een boolean, FALSE, teruggeven, of een ander dispatch token.

Zend_Controller_Front roept herhaaldelijk de dispatcher op tot deze geen dispatch token meer terug stuurt. Dit staat bekend als de dispatch loop. Het laat toe acties opeenvolgend te verwerken tot al het werk gedaan is.

De Zend_Controller_Dispatcher_Interface interface verstrekt definities voor twee methodes:

<?php
				
/**
 * @param  Zend_Controller_Dispatcher_Token $route
 * @return boolean
 */
public function isDispatchable(Zend_Controller_Dispatcher_Token $route);

?>

isDispatchable() gaat na of een dispatch token gedispatched kan worden. Indien dat zo is geeft het TRUE terug. Anders geeft het FALSE terug. In het geval van de standaard implementatie, Zend_Controller_Dispatcher, betekent dit dat het controller bestand bestaat, dat de klasse in het bestand bestaat en dat de actiemethode in de klasse bestaat.

<?php
			
/**
 * @param  Zend_Controller_Dispatcher_Token $route
 * @return Zend_Controller_Dispatcher_Token|boolean
 */
public function dispatch(Zend_Controller_Dispatcher_Token $route);

?>

dispatch() is waar het echte werk wordt gedaan. Deze methode moet de actie van de controller uitvoeren. Het moet ofwel een dispatch token teruggeven of een boolean, FALSE, om aan te geven dat er geen werk meer te doen is.