実装サンプル
Naifyを最小構成で動かすためのコード例を紹介します。ブートストラップ、ルート定義、BaseController、コントローラー の順に見れば、最初の1本を組み立てられます。
最小Hello World
Hello Worldのファイル配置と公開入口を使い、プロジェクト直下の SampleAppBootstrap.php でNaifyを起動します。以下のControllerは app/Controllers にクラス名と同じ名前のPHPファイルで置きます。
// SampleAppBootstrap.php(プロジェクト直下)
use Naify\Naify;
require __DIR__ . '/libs/Naify/Naify.php';
Naify::boot();
Naify::autoload('App', __DIR__ . '/app');
$config = Naify::createConfig()
->setAppId('sample-app')
->setSystemDir(__DIR__)
->setPublicDir(__DIR__ . '/public')
->setConfigDir(__DIR__ . '/config')
->setBasePath($_SERVER['SCRIPT_NAME'] ?? '/');
$app = Naify::createWebApp($config);
$app->loadRoute('routes/routes.php');
$app->run();
ルートの書き方
routes/routes.php はPHPコードとして定義します。createRouteFactory() でコントローラーの名前空間を指定しておきます。
use Naify\Router\Router;
return static function (Router $router): void
{
$to = $router->createRouteFactory('App\\Controllers\\');
$router->any('/', $to('HelloWorldController::index'));
$router->any('/hello/{name}', $to('HelloWorldController::index'));
$router->any('/users', $to('UserController::index'));
$router->any('/users/{id}', $to('UserController::detail'));
};
Naifyでは、設定ファイルもPHPで記述します。
IDEのコード補完や構文チェック、クラス・メソッドの定義への移動を活用でき、設定の内容と呼び出す処理を確認しやすくするためです。
IDEのコード補完や構文チェック、クラス・メソッドの定義への移動を活用でき、設定の内容と呼び出す処理を確認しやすくするためです。
BaseController戦略
共通処理はBaseControllerに薄く集約します。認証、共通初期化、描画、JSON出力などの入口をここに置きます。
namespace App\Controllers;
use Naify\Router\RequestContext;
use Naify\Router\RequestContextHandlerInterface;
abstract class BaseController implements RequestContextHandlerInterface
{
protected RequestContext $context;
public function handle(RequestContext $context, ?string $action): void
{
$this->context = $context;
$method = ($action ?? 'index') . 'Action';
$this->onActionBefore();
$this->{$method}();
$this->onActionAfter();
}
protected function onActionBefore(): void
{
// 認証や共通初期化を置く
}
protected function onActionAfter(): void
{
// View描画や共通出力を置く
}
protected function outputJson(array $payload): void
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
}
}
BaseControllerが神クラスにならないよう、規模や機能に応じてファイルを分けるのが望ましいです。Web用、API用、認証済み画面用など、役割ごとに薄く分けると追いやすいです。
BaseControllerは必須ではなく、共通処理のまとめやすさと見通しのよさから、この実装例で採用している構成です。アプリケーションの規模や要件に応じて、より小さな構成や役割ごとに分けた実装を選べます。
参考:小さく始める
HelloWorldコントローラー
BaseControllerで基本処理が行われるので、アプリケーション層の実装はシンプルになります。ここではURLパラメータの {name} を取得して、そのまま画面へ返します。
namespace App\Controllers;
final class HelloWorldController extends BaseController
{
public function indexAction(): void
{
$name = $this->context->getUrlParam('name', 'Naify');
echo '<h1>Hello, ' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '!</h1>';
}
}
URLパラメータを使うコントローラー
ルートで定義した {id} は RequestContext から取得できます。
namespace App\Controllers;
final class UserController extends BaseController
{
public function indexAction(): void
{
$this->outputJson([
'users' => [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
],
]);
}
public function detailAction(): void
{
$id = $this->context->getUrlParam('id');
$this->outputJson([
'id' => $id,
'name' => 'Alice',
]);
}
}