Lydia: En gemensam basklass för kontrollers

  • Författare
  • Meddelande
Användarvisningsbild

mos

dbwebb

  • Inlägg: 11180
  • Blev medlem: 10 nov 2011, 09:52
  • Ort: Ronneby / Bankeryd

Lydia: En gemensam basklass för kontrollers

Inlägg15 feb 2012, 10:05

Detta är en del i tutorialen Lydia: ett PHP-baserat, MVC-inspirerat CMF. Senast uppdaterad 2012-03-22.

En gemensam basklass för kontroller och modeller, CObject, ger tillgång till de gemensammaresurserna i $ly.

Åtkomst till gemensamma resurser i CLydia

När vi skriver kod för kontrollers och modeller så vill vi vara så effektiva som möjligt. En del i kodskrivandet innebär att man använder gemensamma resurser som finns i CLydia. Där finns redan data-arrayen, $ly->data[], dit innehåll som skall skrivas u i webbsidan läggs till. Där finns informationen om själva requesten, $ly->request, och du finner all konfiguration i $ly->config. Dessa gemensamma resurser är nödvändiga och används för att hantera varje request.

Som det är nu finns det två sätt olika sätt att få tag i informationen i CLydia, antingen som global variabel $ly eller via dess instans-metod, CLydia::Instance(), som returnerar instansen av CLydia enligt singleton design mönster.


Åtkomst som global variabel

I filer som site/config.php, theme/functions.php och theme/core/functions.php finns $ly som en variabel i det globala scoopet eftersom den definerats på filnivå i index.php. Där kan man använda den som en vanlig variabel.

Exempel från theme/core/functions.php
Kod: Markera allt
$ly->data['header'] = '<h1>Header: Lydia</h1>';



Åtkomst via instans-metoden.

CLydia är implementerat enligt singleton design mönster vilket innebär att det kan endast finnas en instans av klassen. De som vill ha tag i den instansen, objektet, måste gå via CLydia::Instance() som returnerar själva objektet. Via denna metod kan man då få tag på objektet om man är i en klass eller i en funktion. Det är en form av global tillgång till ett objekt.

Se ett exempel från index-kontrollern, src/CCIndex/CCIndex.php
Kod: Markera allt
   private function Menu() {   
      $ly = CLydia::Instance();

      // ... some code removed
        $html .= "<li><a href='" . $ly->request->CreateUrl($val) . "'>$val</a>"; 

      // ... some code removed
      $ly->data['title'] = "The Index Controller";



Åtkomst via $this

Det finns ju faktiskt ytterligare ett sätt att komma åt resurserna i $ly. Om man är inuti själva klassen så används $this för att komma åt dem.

Exempel från CLydia, src/CLydia/CLydia.php
Kod: Markera allt
   // ... some code removed
   $this->request = new CRequest($this->config['url_type']);

   // ... some code removed
    $themeName    = $this->config['theme']['name'];

   // ... some code removed
    $themeUrl      = $this->request->base_url . "themes/{$themeName}";


Det trevligt att man skulle kunna använda $this som åtkomstmöjlighet när man utvecklar kontrollers och modeller. Kanske kan man få lite renare kod. Ett sätt att öppna för sådan åtkomst vore om kontroller och moduler ärver från en gemensam basklass som innehåller, eller har tillgång till de gemensamma resurserna från $ly.


En gemensam basklass för kontrollers och moduler

Låt oss skapa en gemensam basklass vars primära syfte är att ge tillgång till Lydias gemensamma resurser via $this. Ett utkast till en sådan klass kan se ut som följer.

src/CObject/CObject.php
Kod: Markera allt
<?php
/**
* Holding a instance of CLydia to enable use of $this in subclasses.
*
* @package LydiaCore
*/
class CObject {

   public $config;
   public $request;
   public $data;

   /**
    * Constructor
    */
   protected function __construct() {
    $ly = CLydia::Instance();
    $this->config   = &$ly->config;
    $this->request  = &$ly->request;
    $this->data     = &$ly->data;
  }

}


Bra, där har vi en klass som kan hålla de vitala delarna av de gemensamma resurserna från CLydia. För att testa konceptet så uppdaterar jag min developer-kontroller med en ny metod som skriver ut allt innehåll i klassen CObject. Dessutom måste jag låta CCDeveloper ärva från CObject. Det innebär att jag behöver en konstruktor i CCDeveloper som också anropar konstruktorn i basklassen. Så här blev det.

CCDeveloper ärver från CObject
Kod: Markera allt
class CCDeveloper extends CObject implements IController {

  /**
   * Constructor
   */
  public function __construct() {
    parent::__construct();
  }


Nu uppdaterar jag all kod i CCDeveloper till att använda $this istället för $ly som jag fick från CLydia::Instance().

CCDeveloper använder $this för åtkomst till gemensamma resurser.
Kod: Markera allt
   public function Links() {   

      // some code removed
      $this->request->cleanUrl = false;
      $this->request->querystringUrl = true;      
      $querystring  = $this->request->CreateUrl($url);
      
      $this->data['title'] = "The Developer Controller";


Blev det bättre eller sämre? Resultatet är det samma men koden skiljer sig. I slutändan blir det du som bestämmer vilket sätt du tycker verkar bäst. Fundera och ta ett beslut hur du vill göra i ditt ramverk. Det är inte ovanligt att andra ramverk har detta beteende med basklasser till kontroller och modeller.

Jag skapar också en metod för att skriva ut allt innehåll i CObject, det känns bra att ha vid debugging och felsökning.

CCDeveloper::DisplayObject()
Kod: Markera allt
/**
    * Display all items of the CObject.
    */
   public function DisplayObject() {   
      $this->Menu();
      
      $this->data['main'] .= <<<EOD
<h2>Dumping content of CDeveloper</h2>
<p>Here is the content of the controller, including properties from CObject which holds access to common resources in CLydia.</p>
EOD;
      $this->data['main'] .= '<pre>' . htmlentities(print_r($this, true)) . '</pre>';
   }


Det är trevligt med en visuell översikt av vad objektet innehåller.


Stödja länkar och metoder av typen display-object och display_object

Jag gjorde en extra liten uppdatering till CLydia::FrontControllerRoute() i samband med detta. Metoden heter ju DisplayObject vilket skulle ge den länken: developer/displayobject. Men, för att kunna skapa bättre länkar så gjorde jag det möjligt att även länkar av typen developer/display-object och developer/display_object leder till exakt samma metod. Det räckte att lägga till en rad för att uppnå denna trivsamma effekt.

CLydia::FrontControllerRoute()
Kod: Markera allt
         $formattedMethod = str_replace(array('_', '-'), '', $method);



Konfigurerbara debug-utskrifter

När jag ändå höll på så uppdaterade jag temafunktionen get_debug() i theme/functions.php och gjorde det konfigurerbart i site/config.php om debug-informationen skulle skrivas ut eller ej. Det blir nog en behändig konstruktion som jag kommer ha mycket nytta av framöver.


Wrappa systemets funktioner till egna helpers

Ytterligare en sak jag gjorde var att wrappa funktionen htmlentities() till min egna htmlent(). Syftet är att ta tillvara inställningen av teckenkodning som görs i site/config.php. Så här blev resultatet och jag lade funktionen i src/bootstrap.php.

src/bootstrap.php: htmlent()
Kod: Markera allt
/**
* Helper, wrap html_entites with correct character encoding
*/
function htmlent($str, $flags = ENT_COMPAT) {
  return htmlentities($str, $flags, CLydia::Instance()->config['character_encoding']);
}


En del sådana helpers kan vara oumbärliga och nödvändiga för att hålla ordning i koden. Men jag vill inte ha fler än nödvändigt, det vore att uppfinna hjulet igen.


Exempelkod

Då var vi klara för denna gången. Koden kan du som vanligt provköra på dbwebb.se och de ändringar som gjorts finns taggade på github.

http://dbwebb.se/lydia/tags/v0.1.2
http://dbwebb.se/lydia/tags/v0.1.2/deve ... lay-object
http://dbwebb.se/lydia/tags/v0.1.2/deve ... lay_object
http://dbwebb.se/lydia/tags/v0.1.2/deve ... playobject

https://github.com/mosbth/lydia/tree/v0.1.2

Fortsätt med nästa tutorial.
...
..:
.... /mos

Vilka är online

Användare som besöker denna kategori: Google [Bot] och 31 gäster