Published on

cakePHPとDjango比較しながら、セットアップ備忘録

Authors
  • Name
    Twitter

目的

下記クイックスタートを完了し、設計思想を一通り学習する。

要約

  • DRFはフロント、バックが明確に分かれる設計。APIから取得したデータを表示し、ユーザーの操作を処理。フロントエンドの変更がバックエンドに影響を与えない。
  • CakePHPは、バックエンドとフロントエンドを同じシステムで管理が基本。一応、APIルーティングの設定はできて、DRFと同じ運用はできる。
  • フルスタックフレームワークを使ったことなかったため、慣れが必要。フロントとバックを同時に開発できるのは、開発スピードの観点で優位か。
  • CakePHPでは、アプリケーションロジックをできるだけモデル層に配置し、コントローラーのアクションを簡潔に保つという設計方針がある。ファインダーメソッドをテーブル(モデル)に書く。
  • コントローラーは本来、リクエストを受け取り、適切なモデルを呼び出し、ビューに渡すという責務に限定するべき
  • CakePHPの設計原則では、モデル(テーブルやエンティティ)にビジネスロジックを集中させ、コントローラーをシンプルに保つことが推奨
  • 「Fat Models, Skinny Controllers」:モデル(テーブル)がビジネスロジックやデータ操作の責任を持つ。コントローラーはそのロジックを呼び出し、結果をビューに渡すだけにする。

要約2(DRFとの比較抽出)

CakePHPの設計思想

  • Fat Models, Skinny Controllers(太いモデル、薄いコントローラー)
    • ビジネスロジックやデータ処理をモデル(テーブル)に集中させる。
    • コントローラーは、リクエストを受け取り、モデルを呼び出し、ビューに渡すだけの責務。

Django REST Frameworkの設計思想

  • Thin Models, Fat Views(薄いモデル、太いビュー)
    • Djangoではモデルはデータ定義に留める。
    • ビジネスロジックやデータ処理は、ビューやシリアライザで記述。
    • DRFでは、ビューセットやシリアライザがCakePHPのモデルのような役割を一部引き継ぐ。

CakePHPのファイル構成と責務

ファイル/ディレクトリ役割具体例
src/Model/Tableビジネスロジックとデータ処理を記述。テーブルごとの関連付けやファインダーメソッドを定義。ArticlesTable.phpfindTagged を定義し、タグで記事を検索するロジックを記述。
src/Controllerリクエストを受け取り、適切なモデルやビューを呼び出す。ロジックはモデル(テーブル)に委譲。ArticlesController.phptags() アクションを定義し、findTagged を呼び出して結果をビューに渡す。
templatesビューのテンプレートを配置。データの表示に集中。templates/Articles/tags.php で、$articles をループして記事一覧を表示。
config/routes.phpURLとコントローラー・アクションのマッピング。/articles/tagged/*ArticlesController::tags() にマッピング。

Django REST Frameworkのファイル構成と責務

ファイル/ディレクトリ役割具体例
models.pyデータ構造を定義。データ処理はほとんど記述しない。Article モデルに ManyToManyField(Tag) を定義し、記事とタグを多対多で関連付け。
serializers.pyデータの整形(JSON化)や入力検証を担当。ArticleSerializer にタグを含む記事のデータをシリアライズ。
views.pyビジネスロジックとデータ処理を記述。リクエストを処理し、シリアライザやクエリセットを利用。ArticleByTagsView を定義し、タグで記事を検索して結果を返す。
urls.pyURLとビューのマッピング。/articles/tagged/<tags>ArticleByTagsView にマッピング。

CakePHPとDRFの比較表

項目CakePHPDjango REST Framework (DRF)
データ定義モデル(ArticlesTable.php)に関連付けやカスタムクエリを記述。モデル(models.py)はデータ構造の定義のみ。
データ処理モデル(テーブル)内のファインダーメソッドでデータ処理を実装。ビュー(views.py)でクエリロジックを実装。
JSONレスポンス生成ビューではなくテンプレートを使用しHTML出力がメイン。JSONは明示的に設定が必要。シリアライザでJSONレスポンスを生成。REST API向けに最適化。
ルートの定義routes.php でURLとコントローラーアクションをマッピング。urls.py でURLとビューをマッピング。
利便性自動化(Bake)でファイル構成を迅速に生成可能。手動で構成を記述するが柔軟性が高い。
設計思想Fat Models, Skinny Controllers。モデルが中心。Thin Models, Fat Views。ビューが中心。

  • CakePHP:

    • モデル中心でロジックを再利用可能。
    • Bake による迅速なスケルトン生成が可能。
    • テンプレートエンジンを使用しHTMLレンダリングに適している。
  • Django REST Framework:

    • ビュー中心でREST API開発に最適。
    • シリアライザによる柔軟なJSONデータ処理。
    • APIエコシステム全体を簡単に構築可能。

チュートリアル開始

composerインストール

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"

cakePHPプロジェクト作成

django startprojectと同じ。

php composer.phar create-project --prefer-dist cakephp/app:"4.*" my_app_name

compposer install

pip install requirements.pyや、npm installのようなもの

composer install

20,30分低スペックPCだと時間がかかる

開発用サーバー

アプリケーションに対し、GUIで操作できるようなGUIツールらしい。XAMPPがあるならApacheサーバーでいい。

cakeの簡易サーバーで進める場合、下記。

bin/cake server

Apacheの場合。

  • Apache をXAMPPで起動でもいい。

http://localhost:8080/phpmyadmin/ にアクセス。

DB作成

  • phpMyAdminの「SQL」から、下記URLのSQL実行しサンプル用テーブル作成
  • 参考
  • モデルの作成
    • Table オブジェクトは、指定されたテーブルの中に保存されたエンティティーの集合へのアクセスを提供
    • bakeコマンドで生成するもの
    • bakeはDjango REST Framework (DRF) におけるモデル定義とシリアライザの自動生成にあたる。
  • その前に、各種設定必要
    • app_local.php
    'Security' => [
        // 'salt' => env('SECURITY_SALT', '__SALT__'),
        'salt' => env('SECURITY_SALT', 'default_salt_key'),
    ],
  • そのあと
    • .env
export SECURITY_SALT=
  • そのあと
    • config/bootstrap.phpで書きコメントイン
if (!env('APP_NAME') && file_exists(CONFIG . '.env')) {
  • XAMPPの場合Datasourcesの設定で進める。app_local.phpを修正
    'Datasources' => [
        'default' => [
            'className' => Cake\Database\Connection::class, // 正しいクラス名
            'driver' => Mysql::class,
            'persistent' => false,
            'host' => 'localhost',
            'username' => 'root',
            'password' => '', // XAMPPデフォルトの場合
            'database' => 'cake_cms',
            'encoding' => 'utf8mb4',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
        ],
    ]
  • bake コマンドで、下記出力続く
bin/cake bake model all
bin/cake bake model all
One moment while associations are detected.

Baking table class for Articles...

Creating file C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Table\ArticlesTable.php
Wrote `C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Table\ArticlesTable.php`
Deleted `C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Table\.gitkeep`

Baking entity class for Article...

Creating file C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Entity\Article.php
Wrote `C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Entity\Article.php`
Deleted `C:\Users\user\source\learning\php_practice\my_app_name\src\Model\Entity\.gitkeep`

Baking test fixture for Articles...

Creating file C:\Users\user\source\learning\php_practice\my_app_name\tests\Fixture\ArticlesFixture.php
Wrote `C:\Users\user\source\learning\php_practice\my_app_name\tests\Fixture\ArticlesFixture.php`
Deleted `C:\Users\user\source\learning\php_practice\my_app_name\tests\Fixture\.gitkeep`
Bake is detecting possible fixtures...

Baking test case for App\Model\Table\ArticlesTable ...

Creating file C:\Users\user\source\learning\php_practice\my_app_name\tests\TestCase\Model\Table\ArticlesTableTest.php
Wrote `C:\Users\user\source\learning\php_practice\my_app_name\tests\TestCase\Model\Table\ArticlesTableTest.php`
Done
One moment while associations are detected.
Bake cannot generate associations for composite primary keys at this time.

Baking table class for ArticlesTags...

3. 規約と構成の違い

項目CakePHPDjango(DRF)
モデル定義Tableクラスを使用Modelクラスを使用
タイムスタンプ管理ビヘイビアで管理(Timestampフィールド設定(auto_now_addなど)
フィールド定義SQLスキーマに従いテーブル操作モデル内で直接定義
規約と設定規約優先(クラス名とテーブル名をマッピング)設定重視(明示的にモデルを定義)

CakePHPのbin/cake bake model allは、Django REST Framework (DRF) におけるモデル定義とシリアライザの自動生成に相当します。ただし、CakePHPのbakeコマンドは、さらに広範囲な機能をカバーします。

項目CakePHP (bake)Django REST Framework
モデル生成bin/cake bake model all コマンドで自動生成models.py に手動記述。またはinspectdb
シリアライザ生成Entityクラスが自動生成されるシリアライザは手動で記述 (serializers.py)
リレーション定義Tableクラスで定義モデル内でForeignKeyManyToManyField
対応する自動化範囲データベーススキーマからモデルと関連クラスの生成inspectdb + 手動でシリアライザ作成

CakePHPはbakeコマンドで多数のファイルを一気に生成できるのが強みで、開発の初期段階で非常に効率的。一方で、DRFは自由度が高く、個別に調整しやすい設計が特徴

コントローラーの作成

1. コントローラーの役割

CakePHP:

  • コントローラーはリクエストを処理し、データベース操作を行うモデルと、HTMLを生成するビューをつなぐ役割を果たす。
  • リクエストごとにアクション(メソッド)を定義。
  • 例えばコントローラーでは、リクエストもとにデータベースから記事を取得して、テンプレートにデータを変数で渡す。その後、CakePHPではテンプレート(HTML含むPHP)を探し、そこに格納されるというわけ。そのHTMLがサーバーからブラウザに送信されユーザに表示。
  • DRFだったら、viewからjsonでレスポンスは返し、フロントエンドがjsonで受け取り、いかようにするといった流れ。

DRF:

  • DRFでは、コントローラーに相当するのはビュークラスビューセット
  • モデルやシリアライザと連携して、APIリクエストを処理し、データを返す責任がある。

2. CakePHPとDRFの基本的な対応関係

CakePHPDjango REST Framework説明
コントローラービュー(クラスまたは関数)リクエストを処理し、レスポンスを生成する部分。
アクション(メソッド)関数ベースビュー/メソッドHTTPリクエスト(GET, POST, PUTなど)ごとに処理を記述。
テンプレートHTMLレスポンス/テンプレートHTMLを生成する部分。ただし、DRFではAPIのためHTMLを扱うことは少ない。
ヘルパーDjangoテンプレートタグや関数フォームやリンクの生成、HTMLタグの簡素化など。

3. HTML返却とAPI返却の違い

項目HTML返却 (MVC従来構成)API返却 (JSON構成)
リクエスト例http://example.com/articles/indexhttp://example.com/api/articles
ルーティングArticlesController@indexArticlesController@index
レスポンス内容HTML(テンプレートで生成)JSONデータ(直接生成)
ビュー (View)templates/Articles/index.phpでHTML生成不要_serializeでデータを直返し)
フロントエンド処理サーバーからHTMLを受け取り、直接表示フロントエンド(例: React)がJSONを処理してUI更新
例外処理CakePHPがテンプレートを探せない場合にエラーページを表示APIレスポンスにHTTPステータスコードでエラーを返す

4.処理の流れを図示

HTML返却(従来MVC)

リクエスト: GET /articles/index
ルーティング: routes.php → ArticlesController@index
コントローラー: ArticlesControllerがモデルからデータ取得
ビュー: templates/Articles/index.phpでHTML生成
レスポンス: HTMLを返却

API返却

リクエスト: GET /api/articles
ルーティング: routes.php → ArticlesController@index
コントローラー: ArticlesControllerがモデルからデータ取得
JSON生成: _serializeオプションでJSONレスポンス生成
レスポンス: JSONを返却

コントローラーtutorial

  • 注意点、特定のURLを取得できるように、コントローラとアクションの命名はせず、CakePHPの規約に従うこと
  • クラス名: 複数形 + パスカルケース + Controller
  • ファイル名とクラス名、データベース、モデル、ビュー、プラグインそれぞれ
データベース: articles テーブル
Controller: ArticlesController(src/Controller/ArticlesController.php)
Table クラス: ArticlesTable(src/Model/Table/ArticlesTable.php)
Entity クラス: Article(src/Model/Entity/Article.php)
ビュー: templates/Articles/index.php
URL例: http://example.com/articles → ArticlesController::index() にマップ。

作成

  • CakePHP は、 コントローラーのアクションが完了した後、自動的にテンプレートを描画

テンプレート

  • CakePHP のテンプレートファイルは、 templates の中で 対応するコントローラーの名前をつけたフォルダーの中に保存。 今回の場合、 'Articles' という名前のフォルダーを作成する必要があり
  • $this->Html->link CAKEPHPのヘルパー関数でリンク生成

xamppの設定変更

  • httpd.confを修正する
  • アプリの場所をApacheに教える
  • DocumentRoot(ウェブサイトの入口)を、CakePHPのwebrootフォルダに変更
  • Apacheに「このフォルダの中身をウェブで公開してOK」と設定
  • CakePHPでは、URLを自由にデザインできる「ルーティング」という仕組み.Apacheの「mod_rewrite」という機能が必要.
  • 「どの窓口でウェブサイトを提供するか」を決めるので、Apcheサーバーのポートを確認
  • ブラウザで以下のURLにアクセスすれば、CakePHPのアプリが表示http://localhost:8080
  • CakePHPアプリは「家」,Apacheはその家に手紙を届ける「郵便配達員」
# 元の設定
DocumentRoot "C:/xampp/htdocs"
<Directory "C:/xampp/htdocs">

# 修正後の設定
DocumentRoot "C:/Users/user/source/learning/php_practice/my_app_name/webroot"
<Directory "C:/Users/user/source/learning/php_practice/my_app_name/webroot">

# 修正箇所を確認して有効化
LoadModule rewrite_module modules/mod_rewrite.so

view テンプレート作成

  • templates/Articles/view.php
  • レスポンスで返すHTML
  • $this->Articles->find() を使うことで、記事の検索条件やソート順を柔軟に設定可能

POSTリクエスト処理(addメソッドをコントローラに追加)

  • CakePHP のリクエストは、 $this->request を使用してアクセス可能なリクエストオブジェクト
  • POST データは、 $this->request->getData() で利用可能
    • データを保存するために、まず POST データを Article エンティティーに 「変換 (marshal)」
    • 新しい記事を保存した後、セッションにメッセージをセットするために FlashComponent の success() メソッドを使用
    • レイアウトの中に、フラッシュメッセージを表示し、対応するセッション変数をクリア
    • パラメーター ['action' => 'index'] は、例えば ArticlesController の index アクションの場合、 URL /articles に変換

POSTのテンプレート

  • add.phpを追加
  • edit.phpを追加

バリデーション

  • Table.phpに追加すること

複数の作成者が、CMSで作業できるように。

  • Bake はCakePHPのコード生成ツールで、モデル、コントローラー、テンプレートを迅速に生成するためのもの。
  • Django/DRF では、モデルやビューセットを手動で記述するが、makemigrationsDefaultRouter によって効率化できる。

bakeコマンド

cd /path/to/our/app

bin/cake bake model users
bin/cake bake controller users
bin/cake bake template users

これらの3つのコマンドは次を生成。

  • テーブル、エンティティー、フィクスチャーファイル
  • コントローラー
  • CRUD テンプレート
  • 生成された各クラスのテストケース

BakeとDjango/DRFの違い

機能CakePHP BakeDjango/DRF
モデル生成bin/cake bake model usersモデルを手動で定義 + makemigrations + migrate
コントローラー生成bin/cake bake controller usersViewSet を手動で定義
ビュー生成bin/cake bake template usersDRFでは自動的にJSON形式のレスポンスを提供
ルーティング自動で生成されるDefaultRouter を使用して簡単に設定
CLIツール自動生成に特化(Bake)CLIでマイグレーションや管理が可能(manage.py

タグ追加

タグによる検索

  • ルートに追加config/routes.php
  • タグを使って記事を検索できる機能を実装
  • 特定のタグが付けられた記事を検索するための ルート(URLとアクションのマッピング)、コントローラーのアクション、および検索用の ファインダーメソッド を作成

計算フィールドの追加

  • 記事に関連付けられているタグをまとめた文字列(tag_string) を生成する計算フィールド
  • タグ一覧をカンマ区切りの文字列として取得できるようにする
  • _getTagString メソッドは、tag_string プロパティが呼び出されたときに自動的に実行(CakePHP の命名規則に基づく)
  • フロントエンドに使いやすい形に整形する。価格であれば税込み価格に変換する。データの文字列化。人間が読みやすい形にする。
データベース
Table (Model) -----------------+    (全体の操作を管理)
↓                              |
Entity (1レコード)             |    (仮想プロパティを生成)
↓                              |
仮想プロパティ (例: tag_string) |    (動的に生成された値を提供)
↓                              |
テンプレート (View)             |    (仮想プロパティを使って表示)


データベース
ArticlesTable (Model/Table)
Article (Model/Entity) ── 仮想プロパティを生成
ArticlesController (Controller)
テンプレート (View) ── HTML レスポンスを作成


DRFだと

クライアント (ブラウザ/アプリ)
  ↓ HTTP リクエスト
ビュー (APIView)
  ↓ モデルからデータ取得
モデル (Article)
  ↓ データをシリアライザに渡す
シリアライザ (ArticleSerializer)
  - 仮想プロパティ (tag_string) を生成
レスポンス (加工済みJSON)
  ↓ HTTP レスポンス
クライアントが表示
{
    "id": 1,
    "title": "First Post",
    "body": "Hello World",
    "created": "2024-11-30T12:00:00Z",
    "tag_string": "Funny, Cat"
}



処理のステップCakePHPDRF
モデル定義役割: 記事テーブル全体の構造と操作を定義する。
該当ファイル: src/Model/Table/ArticlesTable.php
役割: 記事モデルを定義し、データベース構造を記述する。
該当ファイル: articles/models.py
具体例記事一覧を取得するクエリメソッドを定義する。
例: 公開済みの記事を取得するメソッドを作成する。
記事のタイトルや本文を含むフィールドを定義する。
例: 公開状態を示すフィールドを持つモデルを作成する。
個別データ操作役割: 記事ごとにデータを操作するためのエンティティを定義。
該当ファイル: src/Model/Entity/Article.php
役割: モデルインスタンスを取得してデータを操作。
該当ファイル: articles/models.py
具体例記事のタイトルを取得、または加工したデータを返すメソッドを定義する。特定の記事のタイトルを取得して、クライアントで表示するデータを準備する。
仮想プロパティの定義役割: 動的なプロパティをエンティティに定義。
例: 記事のタグをカンマ区切りで取得する仮想プロパティ。
該当ファイル: src/Model/Entity/Article.php
役割: シリアライザで動的プロパティを定義し、レスポンスデータを整形。
該当ファイル: articles/serializers.py
データの加工役割: テーブルやエンティティでデータを加工。
例: タグ付きの記事一覧を取得するクエリを作成する。
該当ファイル: src/Model/Table/ArticlesTable.php
役割: シリアライザで加工処理を記述し、クライアントに適したデータ形式に整形。
該当ファイル: articles/serializers.py
レスポンス生成役割: コントローラーでデータを取得し、テンプレートに渡す。
例: タグ付きの記事一覧を取得して HTML を生成する。
該当ファイル: src/Controller/ArticlesController.php
役割: APIView でデータを取得し、シリアライザを通して加工したデータを返す。
該当ファイル: articles/views.py
クライアントへの出力役割: テンプレートで加工済みデータを HTML として生成。
該当ファイル: templates/Articles/tags.php
役割: JSON フォーマットで加工済みデータをクライアントに返す。
該当ファイル: テンプレートは不要。

タグの永続化(テーブルへの保存)

  • CakePHP の ORM
記事保存リクエストを受け取る:

ユーザーがフォームで記事を投稿または編集してリクエストを送信します。
エンティティにデータがセットされる:

フォームから送信されたデータが記事エンティティ($entity)に格納されます。
beforeSave() がフックされる:

ORM がデータを保存する直前に beforeSave() メソッドが自動的に呼び出されます。
_buildTags() の実行:

beforeSave() 内でタグ文字列(tag_string)が渡され、_buildTags() が呼び出されます。
タグ文字列を分解し、既存のタグとの照合、新しいタグの作成を行います。
タグエンティティの設定:

_buildTags() の結果であるタグエンティティのリストが $entity->tags に設定されます。
タグと記事の関連を保存:

ORM が自動的に中間テーブル(articles_tags)への保存を処理。

認証

CMSチュートリアル認証

  • パスワードハッシュ化。平文だったらセキュリティとしてだめ。
  • チュートリアル通り authentication:2.0では依存関係の衝突あったので、2.11
composer require "cakephp/authentication"