PHPポケモン「コントローラー編」〜POSTとSESSIONの活用〜 10
2020年9月6日 (最終更新日:2020/9/9 14:33)

PHPポケモン「コントローラー編」〜POSTとSESSIONの活用〜 10

 

今回のPHPポケモンでは、今まで作った機能用のコントローラーになるインターフェースを作成します。ポケモンやメソッドを選択できるようにして、よりゲーム性の高いアプリケーションを実装しましょう。

 

第1回から学習したい方はコチラ

 

 

コントローラーの実装

 

それでは実装したアクションをインターフェースから操作できるように、コントローラーを作成します。

コントローラーといっても、本来のPHP(フレームワーク等)のControllerとは少し違った使い方をします。あくまで、ゲームのコントローラーに近い立ち位置として、選択したアクションを処理するためのクラスです。

 

それではまず、新しくControllerのクラスを作成しましょう。

 

コントローラー(/Classes/Controller.php
<?php
 
require_once(__DIR__.'/Pokemon/Pikachu.php');
require_once(__DIR__.'/Pokemon/Fushigidane.php');
 
// コントローラー
class Controller
{
 
    /**
    * ポケモン
    * @return object
    */
    public $pokemon;
 
    /**
    * @return void
    */
    public function __construct()
    {
    }
 
    /**
    * 配列のHTML出力用メソッド
    *
    * @param array
    * @var void
    */
    protected function echoKeyToVal($array)
    {
        foreach($array as $key => $val){
            echo '<p>'.$key.':'.$val.'</p>';
        }
    }
}

 

準備として、ポケモンの格納用プロパティ(pokemon)と出力ファイルで使っていたechoKeyToValの関数をメソッドを作成しておきます。ポケモンの格納プロパティは出力ファイルから呼び出しをすることになるので、アクセス修飾子はpublicです。

 

 

POSTフォームの活用

 

今回はPHPで実装するので、POSTフォームでデータの受け渡しをしながらアクションを選択します。

※ゲーム性を追求する方は、JavaScriptでajaxを使うと良いでしょう。今回は簡易のコントローラーを実装するため、PHPだけでできるようのPOSTを活用します

 

 

ポケモンの選択

 

ではまずポケモンの選択ができるように、プルダウンを作成しましょう。

 

出力用ファイル(/index.php
<?php
 
require_once(__DIR__.'/Classes/Controller.php');
 
$controller = new Controller($_POST);
 
?>
 
<form action="/" method="post">
    <select name="pokemon">
        <option value="Fushigidane">フシギダネ</option>
        <option value="Pikachu">ピカチュウ</option>
    </select>
    <input type="submit">
</form>

 

まずはコントローラーのクラスをインスタンス化します。$_POSTはグローバル変数ですが、今回はクラス内でそのまま呼び出さずに引数として渡して活用します。

 

フォームでは、pokemonというキー(name)で各ポケモンを選択できるようにします。ポケモンのデータはクラスのため、valueにはクラス名をセットします。

<option value="Fushigidane">フシギダネ</option>
<option value="Pikachu">ピカチュウ</option>

 

次に、コントローラーで送信データに合わせた分岐を作成しましょう。

 

コントローラー(/Classes/Controller.php
/**
* @return void
*/
public function __construct($post)
{
    if(empty($post)){
        // ポケモンをゲットする前
        echo '<p>ポケモンを選んでください</p>';
    }elseif(!isset($post['action'])){
        // ポケモンをゲットした
        $this->checkPokemon($post['pokemon']);
    }else{
        // アクションを選択した
    }
}
 
/**
* ポケモンクラスの存在チェック
*
* @param string $pokemon(class_name)
* @var void
*/
private function checkPokemon($pokemon)
{
    if(class_exists($pokemon)){
        $this->pokemon = new $pokemon;
    }else{
        echo '選択されたポケモンは存在しません';
    }
}

 

それではまず、コンストラクタの分岐から確認していきましょう。

if(empty($post)){
    // ポケモンをゲットする前
    echo '<p>ポケモンを選んでください</p>';
}else{
    // ポケモンをゲットした
    $this->checkPokemon($post['pokemon']);
}

 

初期状態(ページ起動時)は引数で受け取った送信データ$postは空です。なので、emptyで空判定をして、ポケモンも選択メッセージを出力します。

もし空でなければ、ポケモンをゲット(選択されたポケモンのインスタンス化)を実行します。存在しないポケモンが選択されてしまわないように、合わせてコントローラー無いに作成したcheckPokemonというメソッドを使ってポケモンを判別します。

private function checkPokemon($pokemon)
{
    if(class_exists($pokemon)){
        $this->pokemon = new $pokemon;
    }else{
        echo '選択されたポケモンは存在しません';
    }
}

 

引数で受け取った$pokemonにはポケモンのクラス名が入っています。なので、class_existsの関数を仕様して、対象のポケモンクラスが存在しているかをチェックしています。

 

もし存在していれば、pokemonのプロパティにインスタンス化します。

$this->pokemon = new $pokemon;

 

クラス名に変数を使いたい場合は、「new + 変数」と宣言すれば該当クラスを呼び出すことができます。

 

それでは、フォームの挙動を確認してみましょう。

 

フシギダネを選択した場合

ピカチュウを選択した場合

 

 

それぞれをインスタンス化した際のメッセージが表示されていますね。これでフォームを使ったポケモンの選択ができるようになりました。

 

 

セッションの活用

 

次に作成したメソッドの呼び出しをフォームからできるようにします。それには、インスタンス化したポケモンのデータを引き継がなければなりません

ですが、postデータにオブジェクトは選択できず、json形式で送信するにしてもpublicしか引き継がれないという問題が残ります。

なので、今回は簡単に実装できるようにセッションを活用してポケモンのインスタンスを受け渡します

 

出力用ファイル(/index.php
<?php
 
require_once(__DIR__.'/Classes/Controller.php');
 
session_start();

 

セッションを使うため、session_startを追記しておきます。session_startはhtml出力前に記述するようにしておきましょう。 

 

 

アクションの実装

 

それでは、メソッドを呼び出せるようにフォームを追加していきます。まずはgetDetailsgetStatsの2つを呼び出せるようにしましょう。

 

出力用ファイル(/index.php
<?php
 
require_once(__DIR__.'/Classes/Controller.php');
 
session_start();
 
$controller = new Controller($_POST, $_SESSION);
$action_list = [
    'getStats' => 'ステータス',
    'getDetails' => '詳細',
];
?>
<form action="/" method="post">
    <?php if(is_object($controller->pokemon ?? null)): ?>
        <?php $_SESSION['pokemon'] = $controller->pokemon; # ポケモンのインスタンスをセッションに格納 ?>
        <ol>
            <?php foreach($action_list as $action => $title): ?>
                <li>
                    <input type="radio" name="action" id="<?=$action?>" value="<?=$action?>">
                    <label for="<?=$action?>"><?=$title?></label>
                </li>
            <?php endforeach; ?>
        </ol>
    <?php else: ?>
        <select name="pokemon">
            <option value="Fushigidane">フシギダネ</option>
            <option value="Pikachu">ピカチュウ</option>
        </select>
    <?php endif; ?>
    <input type="submit">
</form>

 

まずはコントローラーのインスタンス化の引数に、セッションを追加します。

$controller = new Controller($_POST, $_SESSION);

 

$_SESSIONもグローバル変数ですが、$_POST同様に直接呼び出しをせずに引数で渡して管理します。

 

次に、メソッドを配列で用意します。

$action_list = [
    'getStats' => 'ステータス',
    'getDetails' => '詳細',
];

 

キーにメソッド名、値にタイトルとしておきましょう。用意した$action_listはフォームの選択肢として活用します。

 

次に、フォームの内容を分岐させます。

<form action="/" method="post">
    <?php if(is_object($controller->pokemon ?? null)): ?>
        <?php $_SESSION['pokemon'] = $controller->pokemon; # ポケモンのインスタンスをセッションに格納 ?>
        <ol>
            <?php foreach($action_list as $action => $title): ?>
                <li>
                    <input type="radio" name="action" id="<?=$action?>" value="<?=$action?>">
                    <label for="<?=$action?>"><?=$title?></label>
                </li>
            <?php endforeach; ?>
        </ol>
    <?php else: ?>
        <?php
        // ポストとセッションをリセット
        $_POST = [];
        $_SESSION = [];
        ?>
        <select name="pokemon">
            <option value="Fushigidane">フシギダネ</option>
            <option value="Pikachu">ピカチュウ</option>
        </select>
    <?php endif; ?>
    <input type="submit">
</form>

 

初期状態(ポケモンを捕まえる前)はメソッドを選択できません。なので、publicで準備したコントローラークラスのpokemonプロパティをis_objectでチェックしています。

もしポケモンをゲットできていれば、セッション($_SESSION [‘pokemon’])インスタンス化したポケモンのデータ($controller->pokemon)をセットします。

 

メソッドの選択は複数選択が出来ないようにラジオボタンで作成します。

<ol>
    <?php foreach($action_list as $action => $title): ?>
        <li>
            <input type="radio" name="action" id="<?=$action?>" value="<?=$action?>">
            <label for="<?=$action?>"><?=$title?></label>
        </li>
    <?php endforeach; ?>
</ol>

 

$action_listforeachで回しながら、nameactionにして出力します。

 

それでは、コントローラー側にアクション用のメソッドを追加しましょう。

 

コントローラー(/Classes/Controller.php
/**
* @return void
*/
public function __construct($post, $session)
{
    if(empty($post)){
        // ポケモンをゲットする前
        echo '<p>ポケモンを選んでください</p>';
    }elseif(!isset($post['action'])){
        // ポケモンをゲットした
        $this->checkPokemon($post['pokemon']);
    }else{
        // アクションを選択した
        $this->pokemon = $session['pokemon'];
        $this->action($post['action']);
    }
}
 
/**
* アクション
*
* @param string $action(method_name)
* @var void
*/
private function action($action)
{
    $result = $this->pokemon->$action();
    switch ($action) {
        case 'getDetails':
        $this->echoKeyToVal($result);
        break;
 
        case 'getStats':
        $this->echoKeyToVal($result);
        break;
 
        default:
        break;
    }
}

 

まずはコンストラクタにアクションの分岐を追加します。アクションがなければポケモンをゲットした状態、あればアクションが選択された状態という判定をしています。もしアクションが選択されていれば、第2引数で渡したセッション($session)をポケモンプロパティ($this->pokemon)にセットして、新しく作成したアクションメソッド(action)を呼び出しています。

/**
* アクション
*
* @param string $action(method_name)
* @var void
*/
private function action($action)
{
    $result = $this->pokemon->$action();
    switch ($action) {
        case 'getDetails':
        $this->echoKeyToVal($result);
        break;
 
        case 'getStats':
        $this->echoKeyToVal($result);
        break;
 
        default:
        break;
    }
}

 

変数を使用してメソッドを呼び出す際は「-> + 変数 + ()」とすることで呼び出すことができます。メソッドによっては、返り値が合ったり出力方法が異なるものもあるため、switchを使い、メソッドによって分岐させています。今回実装するgetDetailsgetStatsはどちらも返り値は配列のため、echoKeyToValのメソッドを使って出力しています。

※今回はTraitを使用しているため、現在はメソッドの判定を追加していません。もし気になる人は、try-cacthなどを使用して判定するようにしてください。

 

それでは、ポケモンを選択してメソッドを呼び出してみましょう。

 

フシギダネを選択

 

 

getStatsのメソッドを呼び出し

 

getDetailsのメソッドを呼び出し

 

 

これで、ポケモンの情報を引き継いだ状態でgetStatsgetDetailsのメソッドを呼び出すことができました。

 

 

リセット機能

 

最後にリセット機能を作成しましょう。今のままだと、ポケモンを選択してしまうとウィンドウ(タブ)を閉じない限りポケモンを変更することができません。なので、アクションに「リセット」を追加します。

 

出力用ファイル(/index.php
$action_list = [
    'getStats' => 'ステータス',
    'getDetails' => '詳細',
    'reset' => 'リセット',
];
 
--省略
 
<?php else: ?>
    <?php
    // ポストとセッションをリセット
    $_POST = [];
    $_SESSION = [];
    ?>
    <select name="pokemon">
        <option value="Fushigidane">フシギダネ</option>
        <option value="Pikachu">ピカチュウ</option>
    </select>
<?php endif; ?>

 

$action_listにリセット(reset)と、初期画面用の分岐内に$_POSTと$_SESSIONを初期化する処理を追加しました。リセットのアクションが選択された場合、初期画面のフォームを表示させ、既に格納されたセッションとポストデータを空にしています。

 

resetというメソッドは用意されていないため、このまま呼び出せばエラーが発生してしまいます。そうならないように、コントローラーのアクションメソッドにreset用の分岐を追加します。

/**
* アクション
*
* @param string $action(method_name)
* @var void
*/
private function action($action)
{
    if($action === 'reset'){
        // 初期化
        $this->pokemon = null;
        return;
    }
   
    $result = $this->pokemon->$action();
    switch ($action) {
        case 'getDetails':
        $this->echoKeyToVal($result);
        break;
 
        case 'getStats':
        $this->echoKeyToVal($result);
        break;
 
        default:
        break;
    }
}

 

もしアクションがresetであれば、pokemonプロパティにセットされたインスタンスを初期化して処理を終了させています。これで、出力されるフォーム分岐で初期画面が表示され、$_POST$_SESSIONも初期化することができます。

 

それでは動きを確認してみましょう。

  

リセットを実行

 

 

これでリセット機能が実装されました。これでポケモンを選択し直すことができます。

 

 

まとめ

 

いかがだったでしょうか。

今回のPHPポケモンでは「コントローラー」を実装しました。操作する機能が追加されたので、今までと比べるとゲーム性が出て楽しくなりましたね。

POSTフォームはお問い合わせ等でよく使用されますが、このようにデータの受け渡しにも使えるため便利です。ただし、リリースする際はサニタイズするなどして、悪意ある入力を防ぐようにしておきましょう

  

Copyright © 2016-2020 YQUAL All Rights Reserved.