PHP Routing - Component maken
Home

PHP Routing - Component maken

PHP Routing - Component maken

Tot nu toe hebben we de routing logica in de index.html geplaatst. Tijd om de code daaruit weg te halen en op zichzelf staande component te maken.

Stappenplan

  1. We gaan ervan uit dat je de PHP Routing - Voorbereiding doornomen hebt.
  2. We maken een nieuwe workspace in het team Programmeren4 met de naam jef-competion.
    1. Je gebruikt wel je eigen voornaam.
    2. je maakt je workspace zichtbaar voor alle leden van het team.
  3. We maken het project lokaal en gebruiken PHPStorm als IDE. Het is genoeg geweest met de beperkte editor op Cloud9. We willen gebruik kunnen maken van de geavanceerde features van PHPStorm:
    1. Installeer PHPStorm lokaal op je computer (Download PhpStorm).
    2. Gebruik je e-mail adres van de school om eerst jezelf te registreren en daarna jouw kopie van PHPStorm.
    3. Maak een map Programmeren4 met daarin een submap met de naam jef-competition (gebruik je eigen voornaam).
    4. Veriefieer als je composer geïnstalleerd hebt. Indien niet doe je dat eerst. Meer info hierover op PHP Composer voor ontwikkeling eigen component.
  4. De router klasse behoort tot het project MVC van de vendor ModernWays. We voegen de link tussen de namespace en de map waarin de klassen staan toe aan het composer.json bestand:
    {
      "name": "modernways/competition",
      "description": "Competition Library",
      "type": "library",
      "license": "Modern Ways November 2018",
      "authors": [{
        "name": "jefinghelbrecht",
        "email": "jef.inghelbrecht@telenet.be"
      }],
      "require": {
        "php": ">=5.5.0"
      },
      "autoload": {
        "psr-4": {
          "ModernWays\\Competition\\": "vendor/modernways/competition/src/",
          "ModernWays\\MVC\\": "vendor/modernways/mvc/src/"
        }
      }
    }
  5. We updaten de Composer bestanden door in de terminal te typen:
    composer dumpautoload
  6. Routing maakt deel uit een MVC framework, dat we het Three Penny MVC Framework noemen:
    Three Penny MVC Architecture
    Three Penny MVC Architecture
    De Three Penny MVC-architectuur is gebaseerd op het model-view-controller patroon. Bovenstaande figuur illustreert de verschillende Three Penny MVC-componenten en hoe ze zich tot elkaar verhouden. Hier maken we de routing-engine die zich vóór de andere MVC-componenten bevindt. De routing-engine ontvangt inkomende HTTP-aanvragen en koppelt deze naar aan een methode van een controllerklasse. De routing-engine vertrouwt op een reeks routes die volgens de afspraak entity/action worden gedefinieerd.

    De routes definiëren toewijzingen tussen URL-patronen en specifieke controllermethoden en -argumenten. Wanneer je koppelingen maakt (links), gebruik je deze routes in de uri's van de koppelingen.

    Het is de taak van de controller om informatie uit de binnenkomende request te halen, bijvoorbeeld post of get parameters en die om te zetten naar de geschikte modelklassen (modellaag). De modellaag kan van alles zijn. Linq tot SQL, ADO.NET Entity Framework, NHibernate, enzovoort. Wij gaan PDO gebruiken. Het is de laag die bedrijfslogica uitvoert en met de onderliggende database praat. Nadat de controller het werk op het model heeft voltooid, wordt er een view gemaakt en wordt de view voorzien van modelgegevens die in de view getoond moeten worden.

  7. In de Routing klasse passen we de Convention over configuration (ook bekend als coding by convention) software design paradigma toe dat ook door ASP.NET MVC wordt gebruikt (jullie hebben dat in Programmeren 3 geleerd: Conventie boven configuratie in .NET). De afspraak bestaat erin dat het eerste deel de naam van de napespace, het tweede de naam van de entiteit, het derde de naam van de action en het vierde een id bevat, bijvooorbeeld:
    ModernWays\Competition/Game/Update/1
    Threepenny MVC volgt conventie als voor Composer.
  8. De keuze voor de namen van de private fields komen uit DDD - Domain-Driven Design.
  9. In de map vendor/modernways/mvc/src maken we het klassenbestand met de naam Routing.php.
    1. Alle eigenschappen en methoden zijn static. Dit wil zeggen dat de eigenschappen en de methoden tot de klasse behoren. Je hebt dus geen instantie of exemplaar van de klasse nodig om toegang te krijgen tot de eigenschappen en methoden. We doen dit omdat we geen verschillende instanties van die klasse nodig hebben.Je kan je dan terecht afvragen waarom we geen singleton gebruiken (Singleton Pattern Versus Static Class).
    2. Deze klasse heeft vier static eigenschappen:
      1. namespace
      2. entity
      3. action
      4. id
      5. route: de route volgens de Three Penny conventie
      6. default: de default route voor een app, voor competition is dat: ModernWays\Competition/Admin/Index
    3. We voorzien verschillende manieren om de route te initialiseren:
      1. De setRouteFromUrl functie neemt twee parameters, de scriptName en de redirectUrl. Op basis daarvan worden de route geëxtraheerd uit de global $_SERVER dictionary:
        public static function setRouteFromUrl($scriptName, $redirectUrl) {
            // echo $scriptName;
            $pos = strrpos($scriptName, '/');
            $path = substr($scriptName, 0, $pos + 1);
            self::setRoute(str_replace($path, '', $redirectUrl));
        }
      2. De setRoute functie initialiseert de route rechtstreeks zoals ze is. De setter verwijdert wel de begin schuine streep als die er is:
        public static function setRoute($route)
        {
            if (substr($route, 0, 1) == '/') {
                $route = substr($route, 1);
            }
            self::$route = $route;
        }
    4. Met de init functie initialiseren we private velden. De init methode aanvaardt 1 argument, namelijk de default route:
      public static function init($default)
      {
          self::$default = $default;
          $ucArray = explode('/' , isset(self::$route) ? self::$route : self::$default);
          self::$namespace = isset($ucArray[0]) ? $ucArray[0] : 'None';
          self::$entity = isset($ucArray[1]) ? $ucArray[1] : 'None';
          self::$action = isset($ucArray[2]) ? $ucArray[2] : 'None';
          self::$id = isset($ucArray[3]) ? $ucArray[3] : 'None';
      }
    5. Om de klasse te testen voegen we .NET-achtige methode toString toe:
      public static function toString() {
          $info = 'Namespace: ' . self::$namespace . '<br/>';
          $info .= 'Entity: ' . self::$entity . '<br/>';
          $info .= 'Action: ' . self::$action . '<br/>';
          $info .= 'Id: ' . self::$id . '<br/>';
          $info .= 'Route: ' . self::$route . '<br/>';
          $info .= 'Default: ' . self::$default;
          return $info;
      }
    6. We proberen de functionaliteit van de klasse, die we tot nu toe hebben geïmplementeerd, uit. In de index.php pagina in de root:
      <?php
      /**
       * Created by PhpStorm.
       * User: jefinghelbrecht
       * Date: 24/10/18
       * Time: 20:11
       */
      include __DIR__ . '/vendor/autoload.php';
      // \ModernWays\MVC\Routing::setRouteFromUrl($_SERVER['SCRIPT_NAME'], $_SERVER['REDIRECT_URL']);
      \ModernWays\MVC\Routing::setRoute($_SERVER['PATH_INFO']);
      $defaultRoute = 'ModernWays\Competition/Admin/Index';
      \ModernWays\MVC\Routing::init($defaultRoute);
      ?>
      <!doctype html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport"
                content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>Jef's Competitie</title>
      </head>
      <body>
      <h1>Is de pagina die wordt opgeroepen als de bezoeker op onze Competition pagina komt</h1>
      <pre id="feedback">
          <?php echo \ModernWays\MVC\Routing::getInfo(); ?>
          <?php echo var_dump($_SERVER);?>
      </pre>
      </body>
      </html>
  10. In een vorige les implementeerden we Routing Switch met behulp van een switch statement in de index.php pagina in de root van onze website:
    switch (\ModernWays\MVC\Routing::getEntity())
    {
        case 'player' : {
            switch (\ModernWays\MVC\Routing::getAction()) {
                case 'create' :
                    echo 'je gaat een speler aanmaken';
                    break;
                case 'readingone' :
                    $player = new \ModernWays\Competition\Model\Player();
                    $player->setLastName('Inghelbrecht');
                    $player->setFirstName('Jef');
                    $player->setAddress('Monaco');
                    $player->setShirtNumber('1');
                    $view = __DIR__ . '/vendor/modernways/competition/src/View/Player/ReadingOne.php';
                    break;
                case 'updatingone' :
                    // in het echt lezen we de gegevens uit de database in
                    // connectie met mysql
                    $player = new \ModernWays\Competition\Model\Player();
                    $player->setLastName('Inghelbrecht');
                    $player->setFirstName('Jef');
                    $player->setAddress('Monaco');
                    $player->setShirtNumber('1');
                    $view = __DIR__ . '/vendor/modernways/competition/src/View/Player/UpdatingOne.php';
                    break;
                case 'creatingone' :
                    $view = __DIR__ . '/vendor/modernways/competition/src/View/Player/CreatingOne.php';
                    break;
                case 'editing' :
                    $view = __DIR__ . '/vendor/modernways/competition/src/View/Player/Editing.php';
                    break;
                case 'delete' :
                    echo 'je gaat een speler deleten';
                    break;
            }
        }
        case 'liga' : {
            switch ($action) {
                case 'create' :
                    echo 'je gaat een speler aanmaken';
                    break;
                case 'read' :
                    echo 'je gaat een speler inlezen';
                    break;
                case 'update' :
                    echo 'je gaat een speler updaten';
                    break;
                case 'delete' :
                    echo 'je gaat een speler deleten';
                    break;
            }
        }
    }
    Zoals je zelf kan zien is dat een zeer omslachtige manier om een Routing Switch te implementeren. Vooral als je nog wat keuzen hebt. Tijd om een andere techniek dat de switch te leren gebruiken, namelijk Reflection.

JI
2018-11-06 23:10:42