スクラッチでルーティングファイルを作成してみる。PHPでSNSを作成してみる#07

ルーティングファイルを作成する PHP

今回は、ルーティングファイルの作成をします。

ルーティングファイルとは、リクエストのあったURIと表示するページを紐づけるファイルです。つまり、sns_training/loginにアクセスがあったからといってsns_training/login.phpを表示するのではなく、sns_training/testtest.phpを表示するように設定することができます。

では、下記のフォルダ構成でルーティングファイルを作成します。
フレームワークを真似てフォルダを作る。PHPでSNSを作成してみる#03

処理の流れ


今回は、前回作成したindex.phpからkernel、webの順に処理を流しweb内で
リクエストをコントローラに渡す仕組みにします。

下の画像は、web.php内に記述する入力例です。
このようにリクエストURIとコントローラを紐づけてビューを返す仕組みにします。

ルーティングフロー

では、上の仕組みを作るためにファイル作成と内部処理を作成しましょう。

必要なファイルを作成

今回、作成するファイルです。

sns_training
├── index.php(以前の章で作成した方は流用)
├── app
│   ├── auth
│   │    └── secure.php
│   ├── config
│   │    ├── .env
│   │    └── config.php
│   ├── controllers
│   │      └── homeController.php
│   ├── kernel
│   │        └── kernel.php
│   └── utill
│            └── network.php
└── routes
         ├── route.php
         └── web.php

(上記は、今回使用するファイルのみ記してます。)

autoloadを使用しているため、フォルダ階層も同じようにしてください。
Composerのautoloadを追加する方法。PHPでSNSを作成してみる#04

では、それぞれのファイルに記述していきます。

index.php

以前の章で記述した内容は全て削除して以下を入力してください。

<?php
require_once "vendor/autoload.php";
use App\Kernel\kernel;
new kernel();
?>

index.phpでは、require_onceでautoloadを呼び出しています。
これで名前空間での呼び出しが可能になります。

kernel.php

続いて、index.phpで呼び出されたkernelを以下のような内容にします。

<?php
namespace App\Kernel;

class kernel{
   function __construct(){
    require(__DIR__."/../../Routes/web.php");
   }
}
?>
namespace App\Kernel;

名前空間を有効にするためにnamespaceを記述します。
#04でcomposer.jsonに設定した通りにします。

function __construct(){ 
   require(__DIR__."/../../Routes/web.php"); 
}

インスタンス化した際に呼び出されるコンストラクタを使用します。
autoloadを使っておきながらイマイチな書き方ですが、
requireを使用してweb.phpを呼び出します。
web.phpでは名前空間を使用しないためです。

route.php

次に、route.phpに記述します。
route.phpはルーティングファイルのweb.phpの内部制御ファイルです。

 <?php
namespace Routes;
use App\Utill\network;
use App\Config\config;
use App\Auth\secure;

class route{ 
    private $requestUri;
    private $requestUriArr;
    private $requestPage;
    private $directoryArr;
    public $existsPage;
    function __construct(){ 
       $this->existsPage = false;
    }
    //リクエストされたURLの処理をします。
    public function getPath(){
        $this->requestUri = isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL']:null;
        $this->requestUriArr = explode('/',$this->requestUri);  
        if((new network())->isLocal()){
            //ローカル処理
            $this->directoryArr = explode('/',config::getEnv('SUB_DIRECTORY'));
        }else{
            $this->directoryArr = [];
        }

        //ドメイン、ディレクトリ調整
        $tempDirectory = "";
        $tempRequestUriArr = $this->requestUriArr;

        foreach($tempRequestUriArr as $key => $value){
            if(count($this->directoryArr) == count($tempRequestUriArr)){
               break;    
            }
            if($key == 0){
                $tempDirectory = array_pop($tempRequestUriArr);
            }else{
                $tempDirectory = array_pop($tempRequestUriArr)."/".$tempDirectory;
            }
        }
        if((new network())->isLocal()){
            //ローカル処理
            array_shift($this->requestUriArr);
            $this->requestPage = $tempDirectory;
        }else{
            //本番処理
            $this->requestPage = $tempDirectory;
        }
        return $this->requestPage;
    }

    //指定されたページに遷移します。
    public function call($req,$ctr){
        $secure = new secure;
        if($req == $this->getPath()){
            $this->existsPage = true;
            $ctr = explode("@",$ctr);
            $namespace =str_replace("-","\\","App-Controllers-");
            $class = $namespace.$ctr[0];
            $func = $ctr[1];
            return (new $class)->$func($secure->htmlEntity($_REQUEST));
        }else if($req == "*"){
            $this->existsPage = true;
            $ctr = explode("@",$ctr);
            $namespace =str_replace("-","\\","App-Controllers-");
            $class = $namespace.$ctr[0];
            $func = $ctr[1];
            return (new $class)->$func($secure->htmlEntity($_REQUEST));
        }
    }
}
?>

route.phpで呼び出している外部ファイルについては後述します。

getPath(){...}

このメソッドでは、リクエストURIからパスを返す仕組みになっています。
【localhost://sns_training/home】 ならば 【home】を返します。

また、構成が長々としているのはサブディレクトリを考慮しているからです。
【localhost://test/sns_training/home/page01】のとき、
【home/page01】を取得しますが、その際にサブディレクトリ情報が必要なのです。

call($req,$ctr){...}

引数の$reqはパス名で$ctrは”コントローラ名@メソッド名”です。
ここでは、getPath()の戻り値であるリクエストパスコントローラと紐づけたパスを比較して一致したら当該のコントローラメソッドを返すという仕組みです。

クラスをインスタンス化してメソッドを返してます。

if($req == "*"){...}

としているのは、web.phpに記述してあるパスとリクエストしたパスが一致しなかった場合にアスタリスクを返すように記述してあるからです。

それでは、route.phpにインポートしている各ファイルの内容も書いていきます。

network.php

<?php 
namespace App\Utill;
class network {
    public function isLocal(){
        return $_SERVER['HTTP_HOST'] == 'localhost' || '127.0.0.1';
    }
}
?>
isLocal(){...}

このメソッドでは、ローカル環境であればtrueを返し、それ以外だとfalseを返します。

secure.php

<?php 
namespace App\Auth;
  class secure {
     public function htmlEntity($ary){
       if(count($ary) <= 0){
         return;
       }
       $rtnAry = $this->htmlEntity_helper($ary);
       return $rtnAry;
     }
     private function htmlEntity_helper($ary){
       foreach($ary as $key => $value) {
         if (is_array($value)){
           $ary[$key] = $this->htmlEntity_helper($value);
         } else {
           $ary[$key] = htmlspecialchars($value,ENT_QUOTES);
         }
       }
       return $ary;
       }
     }
?>

XSS対策として、エスケープ処理を組み込みます。
route.phpは共通処理なのでviewからのリクエストに対して全てhtmlspecialcharsを行うようにします。

リクエストされる値は多次元配列も予想されますので上のような処理になっています。

.envファイル

シリーズで読んでいただいている方へ
下記リンクで作成した環境変数の内容は削除して構いません。
env(環境変数)ファイルを作成してみた。PHPでSNSを作成してみる#06

SUB_DIRECTORYの値を入力してください。

SUM_DIRECTORY=/sns_training

【localhost:// sns_training / … 】の方は、上記通り入力してください。

また、envを取り出すroute.phpに関してはPHPでSNSを作成してみる#06 をご参照ください。(内容は改変しませんので既に作成済みの方はそのままご使用ください。)

web.php

<?php
namespace Routes;
use Routes\route;
$router = new route();

//@ホーム画面
$router->call('home','homeController@index');//初期表示

if(!$router->existsPage){
  //$router->call('*','xxxxController@xxxx');
}
?>

テスト的に上のような記述をしました。

$router->call('home','homeController@index');//初期表示

まずは、「home」とリクエストがあれば、homeControllerのindexメソッドを呼びだす処理にしました。
ページが増やす場合は、
このような形で上から順に記述します。

ちなみに同じパスが複数ある場合、上位に指定した方で処理されます。

homeController.php

では、テスト的にhomeControllerを作成しましょう。

<?php
namespace App\Controllers;

class homeController{
  //@初期表示
  public function index($request){
    echo "表示のテストを確認。";
  }
}
?>

上のようにpublicでindexメソッドを作成すれば完成です。
仮に”表示のテストを確認”と入力してテストをしてみます。

テストをする

では、きちんと紐付けができているかテストをしましょう。
まずは、「localhost://sns_training/home」を表示します。

表示のテストを確認きちんと表示が確認できました。
次に、「localhost://sns_training/login」を試します。
何も表示されなければ成功です。

これで、ルーティングファイル(web.php)の作成が完了しました。
お疲れ様でした。

おわりに

今回は、長文の章になりました。
次回は、controllerからviewを取得する工程を作成します。

プログラミングは、取り組んだ分だけ力になります。

しかし、学び方学ぶ相手も重要です。
効率のよさと精度が変わってきます。というのも組織で開発をするのであれば、自分の書いたコードに対してレビューをされます。つまりフィードバックです。
しかし、独学の中でフィードバックされる機会は少ないでしょう。

そのため、フィードバックされる機会が少ないまま就職した際に苦労する場合も多いです。
コードの構文からインデントや変数名など。

やはり、プロから学ぶ機会を取り入れるのも一つの手です。
テックアカデミーでは、未経験から最短12週間で転職できるというプログラムも実施しております。ぜひ、フィードバックが欲しい。誰かに教わる必要のある方はご参考にしてみてください。

テックアカデミーについて詳しくみる
また、副業として稼ぎたい方向けにエンジニアを目指す。そんな方向けのコースもございますのでぜひチャレンジをしてみてください。

テックアカデミー「はじめての副業コース」を応募する

以上です。ありがとうございました。

コメント

タイトルとURLをコピーしました