コーディングガイド
プロジェクト
vendor
は会社の名前やチームの名前または個人の名前(excite
, koriym
等)を指定して、package
にはアプリケーション(サービス)の名前(blog
, news
等)を指定します。
プロジェクトはアプリケーション単位で作成し、Web APIとHTMLを別ホストでサービスする場合でも1つのプロジェクトにします。
スタイル
<?php
namespace Koriym\Blog\Resource\App;
use BEAR\RepositoryModule\Annotation\Cacheable;
use BEAR\Resource\Annotation\Embed;
use BEAR\Resource\Annotation\Link;
use BEAR\Resource\Code;
use BEAR\Resource\ResourceObject;
#[CacheableResponse]
class Entry extends ResourceObject
{
public function __construct(
private readonly ExtendPdoInterface $pdo,
private readonly ResourceInterface $resource
) {}
#[Embed(rel: "author", src: "/author{?author_id}")]
public function onGet(string $author_id, string $slug): static
{
// ...
return $this;
}
#[Link(rel: "next_action1", href: "/next_action1")]
public function onPost(
string $tile,
string $body,
string $uid,
string $slug
): static {
// ...
$this->code = Code::CREATED;
return $this;
}
}
リソースのdocBlockコメントはオプションです。リソースURIや引数名だけで説明不十分な時にメソッドの要約(一行)、説明(複数行可)、@params
を付加します。
/**
* A summary informing the user what the associated element does.
*
* A *description*, that can span multiple lines, to go _in-depth_ into the details of this element
* and to provide some background information or textual references.
*
* @param string $arg1 *description*
* @param string $arg2 *description*
*/
リソース
リソースについてのベストプラクティスはリソースのベストプラクティスをご覧ください。
コード
適切なステータスコードを返します。テストが容易になり、botやクローラーにも正しい情報が伝えることができます。
100
Continue 複数のリクエストの継続200
OK201
Created リソース作成202
Accepted キュー/バッチ 受付204
No Content bodyがない場合304
Not Modified 未更新400
Bad Request リクエストに不備401
Unauthorized 認証が必要403
Forbidden 禁止404
Not Found405
Method Not Allowed503
Service Unavailable サーバーサイドでの一時的エラー
304
は#[Cacheable]
アトリビュートを使っていると自動設定されます。404
はリソースクラスがない場合、405
はリソースのメソッドがない場合に自動設定されます。またDBの接続エラーなどは必ず503
で返しクローラーに伝えます。
HTMLのFormメソッド
BEAR.SundayはHTMLのWebフォームでPOST
リクエストの時にX-HTTP-Method-Override
ヘッダーや_method
クエリーを用いてメソッドを上書きする事ができますが、推奨しているわけではありません。PageリソースではonGet
とonPost
以外を実装しない方針でも問題ありません。
ハイパーリンク
- リンクを持つリソースは
#[Link]
で示すことが推奨されます。 - リソースは意味のまとまりのグラフにして
#[Embed]
で埋め込む事が推奨されます。
グローバル
グローバルな値をリソースやアプリケーションのクラスで参照することは推奨されません。(Modulesでのみ使用します)
- スーパーグローバルの値を参照しない
- defineは使用しない
- 設定値を保持する
Config
クラスを作成しない - グローバルなオブジェクトコンテナ(サービスロケータ)を使用しない
- date関数やDateTimeクラスで現在時刻を直接取得することは推奨されません。外部から時刻をインジェクトします。1
- スタティックメソッドなどのグローバルなメソッドコールも推奨されません。
- アプリケーションコードが必要とする値は設定ファイルなどから取得するのではなく、全てインジェクトします。2
クラスとオブジェクト
DI
- 実行コンテキスト(prod, devなど)の値そのものをインジェクトしてはいけません。代わりにコンテキストに応じたインスタンスをインジェクトします。アプリケーションはどのコンテキストで動作しているのか無知にします。
- ライブラリコードではセッターインジェクションは推奨されません。
Provider
束縛を可能な限り避けtoConstructor
束縛を優先することが推奨されます。Module
で条件に応じて束縛をすることを避けます。(AvoidConditionalLogicInModules)- モジュールの
configure()
から環境変数を参照しないで、コンストラクタインジェクションにします。
AOP
- インターセプターの適用を必須にしてはいけません。例えばログやDBのトランザクションなどはインターセプターの有無でプログラムの本質的な動作は変わりません。
- メソッド内の依存をインターセプターがインジェクトしないようにします。メソッド実装時にしか決定できない値は
@Assisted
インジェクションで引数にインジェクトします。 - 複数のインタセプターがある場合にその実行順に可能な限り依存しないようにします。
- 無条件に全メソッドに適用するインターセプターであれば
bootstrap.php
での記述を考慮してください。 - 横断的関心事と、本質的関心事を分けるために使われるものです。特定のメソッドのhackのためにインターセプトするような使い方は推奨されません。
スクリプトコマンド
composer setup
コマンドでアプリケーションのセットアップが完了することが推奨されます。このスクリプトではデータベースの初期化、必要ライブラリの確認が含まれます。.env
の設定などマニュアルな操作が必要な場合はその手順が画面表示されることが推奨されます。
環境
- Webだけでしか動作しないアプリケーションは推奨されません。テスト可能にするためにコンソールでも動作するようにします。
.env
ファイルをプロジェクトリポジトリに含まない事が推奨されます。.env
の代わりにスキーマを記述するKoriym.EnvJsonの利用を検討してください。
テスト
- リソースクライアントを使ったリソーステストを中心にし、必要があればリソースの表現のテスト(HTMLなど)を加えます。
- ハイパーメディアテストはユースケースをテストとして残すことができます。
prod
はプロダクション用のコンテキストです。テストでprod
コンテキストの利用は最低限、できれば無しにしましょう。
HTMLテンプレート
- 大きなループ文を避けます。ループの中のif文はジェネレーターで置き換えれないか検討しましょう。
-
Web APIなど外部のシステムの値を利用する時には、クライアントクラスやWeb APIアクセスリソースなど1つにの場所に集中させDIやAOPでモッキングが容易にするようにします。 ↩
-
ResourceInject
などのインジェクション用トレイトはインジェクションのボイラープレートコードを削減するために存在しましたが、PHP8で追加されたコンストラクタの引数をプロパティへ昇格させる機能により意味を失いました。コンストラクタインジェクションを使いましょう。 ↩