---
title: "コントローラー"
description: "Nibiru コントローラーの作成 — アクションライフサイクル、View::assign、および生産コードからのパターン。"
---

ニビルコントローラーは、`Nibiru\Adapter\Controller` を拡張したクラスで、`application/controller/<name>Controller.php` に存在し、URL が `/<name>/...` のようなものにアクセスすると [Dispatcher](/core/dispatcher/) によって自動的に読み込まれます。

## コントローラの構造
```php
<?php
namespace Nibiru;
use Nibiru\Adapter\Controller;

class productsController extends Controller
{
    public function pageAction() {
        View::assign([
            'title'    => 'Products',
            'products' => $this->loadProducts(),
        ]);
    }

    public function navigationAction() {
        JsonNavigation::getInstance()->loadJsonNavigationArray();
    }

    public function detailAction() {
        $id = (int) ($_REQUEST['id'] ?? 0);
        View::assign(['product' => $this->loadProduct($id)]);
    }

    private function loadProducts(): array { /* ... */ return []; }
    private function loadProduct(int $id): array { /* ... */ return []; }
}
```
## アクションのライフサイクル

ディスパッチャがコントローラを呼び出すと、以下の固定の順序でメソッドを呼び出します：

1. **`navigationAction()`** — グローバルメニュー、パンくず、役割に応じたナビゲーションを設定します。
2. **`<動詞>Action()`** — `?_action=<動詞>` がセットされている場合や、URL のセグメントにアクション名がある場合のみ実行されます。
3. **`pageAction()`** — レンダリングの直前に呼び出されます。

`navigationAction()` と `pageAction()` は、**常に呼び出されます**。未知のアクションでも同様です。これは便利ですが（チェックする必要がありません）、アクションが排他的であると仮定すると驚くことがあります。

## ビューとの対話

`View::assign(['key' => $value, ...])` はデータがテンプレートに到達する方法です。これは静的であり、必要なだけ呼び出すことができます — 後の呼び出しは前のものを上書きします。
```php
View::assign(['title' => 'Products']);
View::assign(['products' => $list]);

// In templates/products.tpl:
//   {$title}     →  "Products"
//   {$products}  →  the array
```
ベースコントローラーからの便利ヘルパー：
```php
$this->getRequest('id', false);   // $_REQUEST['id'] ?? false
$this->getPost('email', '');      // $_POST['email']  ?? ''
$this->getGet('page', 1);         // $_GET['page']    ?? 1
$this->getServer('REQUEST_URI');  // $_SERVER['REQUEST_URI']
$this->getFiles('upload');        // $_FILES['upload']
$this->getSession('auth');        // $_SESSION['auth']
```
これらは存在する理由は、`Controller`が`final`に耐えられるように設計されていることです：テストで子クラスを置き換えてモックすることができます。

## 転送

アクション内でリダイレクトするには：
```php
View::forwardTo('/login');             // 302 to the URL, exits
View::forwardToJsonHeader();           // sets Content-Type: application/json
```
`forwardToJsonHeader()` は、JSON エンドポイントの標準的なパターンです。ヘッダーを設定し、`data` を割り当ててから返す。その後、表示層が残りの処理を行います。

## コントローラーごとに複数のアクション

Nibiruはコントローラーごとに任意の数のアクションをホストすることができます。プロダクション環境のTPMS `erpController`には、`pageAction`、`navigationAction`、さらに`syncAction`、`statusAction`、`dryRunAction`、`cancelAction`などがあります — 各アクションは`?_action=sync`または`/erp/sync`で呼び出されます。
```php
// /erp/sync  →  $_REQUEST['_action'] = 'sync'
public function syncAction(): void
{
    View::forwardToJsonHeader();
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        View::assign(['data' => ['success' => false, 'error' => 'POST method required']]);
        return;
    }
    $result = AlphaplanSyncService::getInstance()->syncAbDocuments();
    View::assign(['data' => $result]);
}
```
## モジュールを使用する方法

コントローラーは薄いです。ほとんどのロジックはモジュールとそのプラグインに存在すべきです：
```php
namespace Nibiru;
use Nibiru\Adapter\Controller;
use Nibiru\Module\Users\Plugin\User;

class loginController extends Controller
{
    private User $user;

    public function __construct() {
        parent::__construct();
        $this->user = new User();
    }

    public function authAction() {
        if (!$this->user->isAuthorized()) {
            View::assign(['loginForm' => $this->user->loginForm()]);
        } else {
            View::forwardTo('/index');
        }
    }
}
```
この*委譲*パターンは、デモンストレーションアプリケーション全体で一貫しています：コントローラーがオーケストレーションを行い、モジュールが作業を行います。

## 多言語 / コンテンツ管理システム（CMS）ドライブコンテンツ

`prod.maschinen-stockert.de` からのパターン — コントローラー パスでキー付けされた CMS テーブルからすべてのページ上のテキストを読み込む:
```php
public function pageAction() {
    $controllerPath = $this->getController()
        . '/' . $this->getRequest('_action', 'page');

    $texts = Cms::init($this->getController())
        ->loadCmsTemplateTextsByControllerPath($controllerPath, $this->language);

    foreach ($texts as $t) {
        View::assign([
            $t['cms_template_texts_text_identifier'] =>
            $t['cms_template_texts_text_content']
        ]);
    }
}
```
結果：非開発者はコードに触れずにコピーテキストを変更できます。CMSモジュールがテーブルとエディタUIを所有し、コントローラは単に文字列を読み込みます。

## コントローラーの生成

CLI はコントローラーとそのテンプレートを一発で生成します：
```bash
./nibiru -c products
```
→ `application/controller/productsController.php`
→ `application/view/templates/products.tpl`

両方とも正規のスケルトンで埋められています。書く準備ができています。
