生産からのパターン
Nibiruアプリケーションで使用されている具体的なパターン — コピーペースト可能なものです。
ニブルの生産アプリケーションで繰り返し現れる7つのパターン。それぞれが小さく、コピー&ペーストできるもので、実際のコードベースに基づいています。
1. 細かいコントローラー → モジュールプラグインの委譲
Section titled “1. 細かいコントローラー → モジュールプラグインの委譲”コントローラーを小さく保ちましょう。ロジックはモジュールプラグインに押し込んでください。
// thinclass erpController extends Controller { public function syncAction(): void { View::forwardToJsonHeader(); $result = \Nibiru\Module\Erp\Plugin\Sync::run(); View::assign(['data' => $result]); }}``````php// fatclass Sync extends Erp { public static function run(): array { $svc = AlphaplanSyncService::getInstance(); try { return ['success' => true, 'changes' => $svc->syncAbDocuments()]; } catch (\Throwable $e) { return ['success' => false, 'error' => $e->getMessage()]; } }}コントローラーは5秒でレビューできます;プラグインは単体テスト可能です。
2. コンテンツソースとしてのCMS
Section titled “2. コンテンツソースとしてのCMS”テキストとレイアウトを分離します。エディターはCMSモジュールのUI経由でコピーアップデートを行います;テンプレートは開発者所有のままです。
public function pageAction() { $path = $this->getController() . '/' . $this->getRequest('_action', 'page'); foreach (Cms::init($this->getController()) ->loadCmsTemplateTextsByControllerPath($path, $this->language) as $t) { View::assign([ $t['cms_template_texts_text_identifier'] => $t['cms_template_texts_text_content'] ]); }}テンプレートは識別子を通常の変数のように参照します。
<h1>{$hero_title}</h1><p>{$hero_intro}</p>3. オブザーバー駆動型分析
Section titled “3. オブザーバー駆動型分析”複数のトラッカーとコントローラーの結合なし。
$analytics = new Analytics();$analytics->attach(new Plugin\Matomo());$analytics->attach(new Plugin\Plausible());$analytics->trackPageView(); / calls notify() internally各観察者の update($subject) は、関心のあるフィールドのみを取得します。トラッカーの追加は1行の変更です。
4. マルチナビゲーション構成
Section titled “4. マルチナビゲーション構成”複数の名前付きナビゲーション配列を使用してページを構築する代わりに、1つのモノリス構造を使用します。
public function navigationAction() { foreach (['head', 'main', 'social', 'footer'] as $name) { JsonNavigation::getInstance()->loadJsonNavigationArray($name); }}``````smarty<header>{include file="navigation.tpl" array=$head}</header><aside>{include file="navigation.tpl" array=$main}</aside><footer>{include file="navigation.tpl" array=$footer}</footer>各 JSON ファイルは小さく、スコープが明確で、編集しやすいです。また、PR での競合もありません。
5. JSON エンドポイントと forwardToJsonHeader
Section titled “5. JSON エンドポイントと forwardToJsonHeader”AJAXの標準契約:
public function searchAction() { View::forwardToJsonHeader(); $q = trim($_REQUEST['q'] ?? ''); if (strlen($q) < 2) { View::assign(['data' => ['results' => []]]); return; } View::assign(['data' => [ 'results' => MachineryScout::index()->search($q), ]]);}ヘッダーは自動的に設定されます;手動で header('Content-Type: application/json') を行わないでください。
6. アクションを経由したマルチステージワークフロー
Section titled “6. アクションを経由したマルチステージワークフロー”コントローラーアクションにマッピングされたステートマシン:
class quotesController extends Controller { public function pageAction() { /* list view */ } public function detailAction() { /* one quote */ } public function acceptAction() { /* state transition: open → accepted */ } public function rejectAction() { /* state transition: open → rejected */ } public function archiveAction() { /* state transition: any → archived */ }}/quotes/accept/42 は acceptAction() を実行し、$_REQUEST['id'] = 42 です。各トランジションは小さなアクションであり、永続化と通知は QuotesService プラグインを介して行われます。
7. スキーマファーストモデルと各インテントごとの1つのカスタムメソッド
Section titled “7. スキーマファーストモデルと各インテントごとの1つのカスタムメソッド”スキーマからモデルを生成し、その後クエリをラップする意図名のメソッドを追加します。
class users extends Db{ const TABLE = ['table' => 'users', 'field' => [/* … */]]; public function __construct() { self::initTable(self::TABLE); }
public function findByLogin(string $login): ?array { return Pdo::fetchRow('SELECT * FROM users WHERE user_login = :l', [':l' => $login]) ?: null; }
public function activeStandardUsers(): array { return Pdo::fetchAll( 'SELECT * FROM users WHERE user_account_active = 1 AND user_role = :r', [':r' => 'standard'] ); }}将来的な自分は、findByLogin($login) — 意図 — ではなく生のSQLを読むことになります。
避けるべきアンチパターン
Section titled “避けるべきアンチパターン”- フォームでの静的バッファリー漏洩。 常に
Form::create()を実行してから構築してください。 navigationAction()内のロジック。 すべてのリクエストで実行され、JSON エンドポイントも含まれます。- 構造化された配列なしでの大量の
View::assign()。 一度にView::assign(['…'])を使用してください。 - SEO URL がすでに処理するカスタムルート。
/products/<slug>/<id>は無料です。 - 生成されたモデルの編集。 それらは上書きされます。カスタムメソッド → 子クラスまたは
database.overwrite = false。