4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

株式会社デジタルクエスト エンジニアAdvent Calendar 2016

Day 14

FuelPHP Hybridを拡張してリクエスト先が`action_`ならAjaxリクエストでも`template`が使える様にする

Posted at

はじめに

FuelPHPにはTemplateREST、そしてその両方の特性を併せ持つHybridというベースコントローラーがありますが、その中でHybridを継承元とし色々と参考にさせて頂きつつ拡張してみたので紹介です。:open_hands:

前提

  • PCはMacを使ってます
  • FuelPHPのバージョンは1.8
  • ざっくり作るページをご説明させて頂きますと、
    スクリーンショット 2016-12-13 19.19.59.png
    こんな感じ

準備

実装するにあたり決めた自分ルール

HybridRESTの機能も持っているので、HTTPメソッドに応じてコントローラのメソッドを限定する事が出来ます。
また、Ajaxによる通信が主になりそうだったので、下記の自分ルールを決めて場合分けしました。

  1. Ajaxリクエストの場合→HTTPメソッドに対応したコントローラメソッドに投げる

    • action_〇〇の場合はviewファイルの中身(<body>とかは含まない)を返却
    • その他の場合はjsonオブジェクトを返却
  2. Ajaxリクエストでない場合→対応するviewファイル(<body>とかも含む)を返却

  3. 何ならjscssはviewオブジェクトを返却する場合はコントローラ名及びアクション名に対応するファイルがあれば勝手に読み込まれる様にしたい...!!

やってみる

自分ルール1と2の事を考えてまずは./fuel/app/views/配下に以下の2ファイルを作っておきます。

template.php

<!DOCTYPE html>
<html lang="ja">
	<head><!-- 省略 --></head>
	<body>
		<?php echo $content; ?>
	</body>
</html>

contents.php

<?php echo $content; ?>

Hybridには元々そのリクエストがRESTFulか否かを判断するis_restful()というメソッドがありますが、メソッド内ではAjaxリクエストか否かを判断しています。
Hybridbefore()でコレに引っかからないと、このタイミングでview関連の処理が出来ません。
自分ルール1でajaxリクエストでもviewファイルを返却したかったので、以下の様にしました。

before

public function is_restful()
{
	return \Input::is_ajax();
}

after

public function is_restful()
{
	// Ajaxリクエスト 且つ "HTTPメソッド_アクション名"というメソッドがリクエスト先のコントローラにあるか
	return \Input::is_ajax() && method_exists(Request::main()->controller, mb_strtolower(\Input::method()) . '_' . Request::active()->action);
}

これはrouter()でも同じ様な記述がありますが、
RESTFulに対応したメソッドがあるか否かまでチェックを入れる様にしました。


この処理を入れた事でbefore()の処理をAjaxリクエストじゃなくても通ってしまうケースがありますので、以下の様に補填しました。

before

public function before()
{
	if (!$this->is_restful()) {
		if (!empty($this->template) and is_string($this->template)) {
			$this->template = \View::forge($this->template);
		}
	}
	return parent::before();
}

after

public function before()
{
	if (!$this->is_restful()) {
		if (!empty($this->template) && is_string($this->template)) {
			// Ajaxリクエストなら`contents.php`を読む
			if (Input::is_ajax() === TRUE) {
				$this->template = View::forge('contents');
			// Ajaxリクエストでなければ`template.php`を読む
			} else {
				$this->template = View::forge($this->template);
			}
			// `./fuel/app/views/`配下に"コントローラ名/アクション名.php"のファイルがあれば、`template.php`の`$content`へ
			if (File::exists(APPPATH . 'views/' . strtolower(ltrim(mb_strstr(Request::main()->controller, '_'), '_')) . '/' . Request::active()->action . '.php') === TRUE) {
				$this->template->content = View::forge(strtolower(ltrim(mb_strstr(Request::main()->controller, '_'), '_')) . '/' . Request::active()->action);
			}
		}
	}
	return parent::before();
}

これでaction_〇〇はAjaxリクエストでcontents.phpを返してくれる様になりました。
Ajaxリクエストで無ければtemplate.phpがそのまま返却されます。
元々のRESTの機能はget_〇〇post_〇〇とキッチリ各コントローラでメソッドを定義しておけば特に影響は無いかと思います。


最後に自分ルール3について、これについては
【FuelPHP】コントローラーやアクション毎に自動でcss、jsを読み込む
を参考にさせて頂き、
contents.phptemplate.phpの両方にAsset::render()を記述しておきます。


最後にコントローラ側のメソッドについてですが、最終的に以下の様な感じになりました。

/**
 * viewファイルを返却する処理
 */
public function action_index() {
	// viewファイルへ値を渡す
	$this->template->content->foo = "bar";
}

/**
 * データを取得する処理
 */
public function get_record() {
	// データを取得して返却
	return $this->response(/* 返却するデータ */);
}

/**
 * データを追加する処理
 */
public function post_record() {
	// データを追加してその結果を返却
	return $this->response(/* 成功 or 失敗 とか */);
}

/* ...etc */

最後に

要件次第な所もありますが、最初にルールを決めて
これらのロジックを組んでたお陰で後々楽出来たかなと思います。

Ajaxリクエストでなければ通常の画面遷移でviewファイルも返ってくるし、
Ajaxリクエストでviewを書き換えたりする必要がある時でも
特に意識しなくて良くなったので:raised_hands:バンザーイ:raised_hands:

ただ、もっとスマート:dancer_tone1:なやり方がありそうな気もします:kissing:

が、何かのご参考になれば幸いです...:wave:

Created by 株式会社デジタルクエスト 杉田 允
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?