Skip to content

Instantly share code, notes, and snippets.

@Leko
Last active April 7, 2019 08:48
Show Gist options
  • Save Leko/7645597 to your computer and use it in GitHub Desktop.
Save Leko/7645597 to your computer and use it in GitHub Desktop.
FuelPHPのRestコントローラをgenerateするタスクを作りました

Rest task

概要

FuelPHPでRestコントローラ(WebAPI)を作成するタスクを作成しました。

インストール

  1. ↓のrest.phpをfuel/app/tasks/の中に置く
  2. タスクを実行するコマンド(php oil r rest [name])を叩く

オプション

書式

rest [name] (--format) (--prefix=api) (<optionalMethod:http>...)

name

生成されるファイル名を小文字の単数形で指定する
このnameがコントローラ名になり、内部で扱うモデル名になり、追加されるルーティングの名前になります。 モデルはModel_Crudもしくは\Orm\Modelを継承したものを想定しています。

--format

デフォルトフォーマットを指定する
省略した場合にはデフォルトフォーマットの指定は行われません。

--prefix (default api)

コントローラを配置する配置するディレクトリを指定する
指定すれば、生成されるディレクトリと生成されるクラス名も変更されるが、このオプションを空にすることは出来ない。
(できるけど現在の実装上コントローラ名や諸々がController__Hoge)みたいになるので動きません)

optionalMethod:http

更に追加で実装したいメソッドを、メソッド名:受け付けるHTTPメソッド形式で列挙する。
このオプションで生成されるのは、メソッドを定義した空のメソッドです。

生成されるコード

  1. モデルの全件(1件)取得
  2. モデルの作成
  3. モデルの更新
  4. モデルの削除

のべーシックなコードはデフォルトで生成されます。

また、fuel/app/config/routes.phpに追記を行います。

oil r rest letter show:get update:put create:post --format=json
とコマンドを実行した際に生成されるコードが以下のようになっています。

ルーティングの追記

'api/letter/(:num)' => 'api/letter/index/$1',

fuel/app/classes/controller/api/letter.php

<?php
/**
 * Generated rest controller
 * 
 * Auto generated methods:
 * GET    /api/letter(/:id) => get_index($id = 'all')
 * POST   /api/letter       => post_index()
 * PUT    /api/letter/:id   => put_index($id)
 * DELETE /api/letter/:id   => delete_index($id)
 *
 * User defined methods:
 * GET /api/letter/show => get_show()
 * PUT /api/letter/update => put_update()
 * POST /api/letter/create => post_create()
 */

class Controller_Api_Letter extends Controller_Rest
{
	// default format
	protected $format = 'json';

	/**
	 * GET /api/letter(/:id)
	 * @param number $id (optional) default is 'all'
	 */
	public function get_index($id = 'all')
	{
		$letters = Model_Letter::find($id);
		return $this->response($letters);
	}

	/**
	 * POST /api/letter
	 */
	public function post_index()
	{
		$letter = Model_Letter::forge(Input::post());
		$letter->save();
		return $this->response($letter, 201);	// created
	}

	/**
	 * PUT /api/letter/:id
	 * @param number $id
	 */
	public function put_index($id)
	{
		$letter = Model_Letter::find($id);
		$letter->set(Input::put());
		$letter->save();

		return $this->response($letter);
	}

	/**
	 * DELETE /api/letter/:id
	 * @param number $id
	 */
	public function delete_index($id)
	{
		$letter = Model_Letter::find($id);
		$letter->delete();

		return $this->response(array(), 204);	// no content
	}

	/**
	 * GET /api/letter/show
	 */
	public function get_show()
	{

	}


	/**
	 * PUT /api/letter/update
	 */
	public function put_update()
	{

	}


	/**
	 * POST /api/letter/create
	 */
	public function post_create()
	{

	}
}
<?php
namespace Fuel\Tasks;
class Rest
{
const CONFIG_GROUP = 'GENERATE_TASK';
/**
* @param string[] `a:b`形式の文字列の配列
* @return array[array] 'a' => 'b'形式の連想配列
*/
private function parseCoronArgs(array $args) {
$ret = array();
foreach($args as $arg) {
list($key, $val) = explode(':', $arg);
$ret[$key] = $val;
}
return $ret;
}
public function help() {
echo "\n===========================================";
echo "\nGenerate task help";
echo "\n";
echo "\nCommand: oil refine generate(:task)";
echo "\n";
echo "\rest [name] --format --prefix=api (<methodName:httpMethod> ...)";
echo "\rest:help";
echo "\n-------------------------------------------\n\n";
}
/**
* This method gets ran when a valid method name is not used in the command.
*
* Usage (from command line):
*
* php oil r rest
*
* @return string
*/
public function run($name)
{
echo "\n===========================================";
echo "\nRunning task [Rest]";
echo "\n-------------------------------------------\n";
$format = \Cli::option('format');
$prefix = \Cli::option('prefix', 'api');
$opts = $this->parseCoronArgs(array_slice(func_get_args(), 1));
echo "Add to app/config/routes.php\n";
echo "\t".\Cli::color("$prefix/$name/(:num) => $prefix/$name/index/\$1", 'green')."\n\n";
// ルーティングをロード
// /$name/:numのルーティングを上書き
\Config::load('routes', Rest::CONFIG_GROUP, true);
\Config::set(Rest::CONFIG_GROUP.".$prefix/$name/(:num)", "$prefix/$name/index/\$1");
\Config::save('routes', Rest::CONFIG_GROUP);
// コード生成の用意
$name = strtolower($name);
$names = \Inflector::pluralize($name);
$capital_prefix = ucfirst($prefix);
$capital_name = ucfirst($name);
$model = \Inflector::words_to_upper("model_$name");
$format = is_null($format) ? '' : "protected \$format = '$format';\n";
// custom methods
$methods = array();
$docs = array();
foreach($opts as $methodName => $httpMethod) {
$upper_http = strtoupper($httpMethod);
array_push($methods, <<<METHOD
/**
* {$upper_http} /{$prefix}/{$name}/{$methodName}
*/
public function {$httpMethod}_{$methodName}()
{
}
METHOD
);
array_push($docs, <<<DOC
* {$upper_http} /{$prefix}/{$name}/{$methodName} => {$httpMethod}_{$methodName}()
DOC
);
}
if(count($docs)) array_unshift($docs, " *\n * User defined methods:");
$optionalMethod = implode("\n", $methods);
$optionalDocs = implode("\n", $docs);
$content = <<<CONTROLLER
<?php
/**
* Generated rest controller
*
* Auto generated methods:
* GET /{$prefix}/{$name}(/:id) => get_index(\$id = 'all')
* POST /{$prefix}/{$name} => post_index()
* PUT /{$prefix}/{$name}/:id => put_index(\$id)
* DELETE /{$prefix}/{$name}/:id => delete_index(\$id)
{$optionalDocs}
*/
class Controller_{$capital_prefix}_{$capital_name} extends Controller_Rest
{
// default format
{$format}
/**
* GET /{$prefix}/{$name}(/:id)
* @param number \$id (optional) default is 'all'
*/
public function get_index(\$id = 'all')
{
\${$names} = {$model}::find(\$id);
return \$this->response(\${$names});
}
/**
* POST /{$prefix}/{$name}
*/
public function post_index()
{
\${$name} = {$model}::forge(Input::post());
\${$name}->save();
return \$this->response(\${$name}, 201); // created
}
/**
* PUT /{$prefix}/{$name}/:id
* @param number \$id
*/
public function put_index(\$id)
{
\${$name} = {$model}::find(\$id);
\${$name}->set(Input::put());
\${$name}->save();
return \$this->response(\${$name});
}
/**
* DELETE /{$prefix}/{$name}/:id
* @param number \$id
*/
public function delete_index(\$id)
{
\${$name} = {$model}::find(\$id);
\${$name}->delete();
return \$this->response(array(), 204); // no content
}
{$optionalMethod}
}
CONTROLLER;
// 保存
$base = APPPATH.'classes'.DS.'controller';
$path = $base.DS.$prefix;
if(!file_exists($path)) {
\File::create_dir($base, $prefix);
echo "Create directory $prefix...\n";
echo "\t".\Cli::color($path.DS, 'green')."\n";
}
\File::create($path, $name.'.php', $content);
echo "Generate controller...\n";
echo "\t".\Cli::color($path.DS.$name.'.php', 'green')."\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment