Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5基礎編③】MVC

B美

今回は「MVC」についての説明です

A子

えむぶいしい?

…って、何?

C菜

そんな英単語はありませんから、きっと何かの頭文字です~

B美

C菜正解!

Modelモデル
Viewビュー
Controllerコントローラー

の三つの頭文字を並べて「MVC」ね

A子

それが「CakePHP」と関係あるの?

B美

大ありよ
Webフレームワークって「MVC」パターンで作られていることが多いんだけど、「CakePHP」もそうだからね

要するに、「CakePHP」を学ぶには「MVC」を理解する必要があるってわけ

C菜

何だか難しそうです~

A子

だねー(苦笑)

B美

全然難しくないわよ
というか、めちゃくちゃ便利な仕組みだからね

まずブラウザからアクセスするのは、Controllerコントローラー(の役割を担うクラス)のメソッドよ

C菜

Controllerコントローラーと言うくらいですから、全体の「制御」を担当するんでしょうか~?

B美

その通り
ControllerコントローラーがWeb処理の中核ね

んで、その中では(必要に応じて)Modelモデルにアクセスするの

A子

必ずModelモデルを使うってわけじゃないの?

B美

ええ、そうよ
なぜならModelモデルの役割は「データベースアクセス」だからね

データベーステーブルへの読み書きを行わないのであれば、Modelモデルは必要ないわ

C菜

Viewビューは「見る」ですからブラウザへの表示を担当する…ってことでしょうか~?

B美

そういうこと

Controllerコントローラーのメソッドに対応するViewビューファイルをあらかじめ作っておいて、ブラウザにレスポンスされるのはそのViewビューファイルってことになるわね
もちろん、ControllerコントローラーからViewビューへ値(処理結果)を受け渡すこともできるわよ

A子

なんだか分かったような、分からないような…(苦笑)

B美

実際にやってみればすぐに理解できるわよ
(まさに「習うより慣れろ」ね)

それじゃ、いつものように「MATE端末」を開いて次のように入力してね

cd html/testapp[Enter]
bin/cake bake controller PostTest[Enter]

これによって新たなControllerコントローラーである「PostTestController.php」が自動生成されるわ
(「PostTest」の部分は自由だけど、その名前の付け方は「パスカルケース」でお願いね)

注:「○○ケース」という記法に関しては【コラム③】を参照のこと

B美

これによって自動的に生成されたファイルを確認してみましょう

ホームディレクトリから「html」→「testapp」→「src」→「Controller」とたどってね









A子

PostTestController.php」というファイルがあるね

B美

それじゃ、そのファイルを開いてね







C菜

なんだか、わけの分からないコードがいっぱいです~

B美

とりあえず不要な部分を削って、下記の状態にしちゃいましょう

「index」メソッドだけは残してね
(その中身は削除してもOK)

あ、あとすでに気付いているとは思うけど、「/*」から「*/」まではコメントだからね

A子

すっきりしたら全体像が見えてきたよ

これって「PostTestController」クラスがあって、その中に「index」メソッドがあるってことでしょう?

B美

その通り!

それじゃ次はViewビューを作りましょう
「testapp」ディレクトリの中に「templates」というディレクトリがあるから、それを表示してね

んで、右クリックしてから「フォルダの生成」を選んで、名前を「PostTest」にします



B美

そのディレクトリの中に移動してから、右クリックからの「文書の生成」→「空のファイル」をクリック

ファイル名を「index.php」にします
(これがViewビューファイルよ)



C菜

その名前(index.php)って、さっきのメソッド名(index)に合わせているんですか~?

B美

正解よ
いい勘してるー

それじゃ、ブラウザを起動してURLには「localhost/testapp/PostTest」と入力してね

A子

んん?
さっきの「index.php」って、まだ中身は空っぽよね?

なんで上のほうにタイトルっぽいものが出てるの?

B美

さっき、「templates」ディレクトリを表示したとき、「layout」ってディレクトリがあったでしょ?

あの中に「default.php」というファイルがあるんだけど、その内容がブラウザ上に表示されてるってわけ
(正確には、「default.php」の中に「index.php」の中身が埋め込まれる)

C菜

あれ?
ということは~

Webページの外枠というか、全体のデザインを「default.php」で決めて~
個別のコンテンツについては、メソッドで処理したものをViewビューファイルで表示するってことでしょうか~?

B美

大正解!
理解が早くて助かるわ

あ、ちなみにデフォルトのレイアウトは「default.php」なんだけど、別のレイアウトファイルを作って、ページによって切り替えて使うなんてこともできます

A子

その機能だけでも便利さが想像できるよ(なんとなくだけど…)

あ、そういえば、さっきのURLってメソッド名(index)を指定しなかったよね?

B美

「index」メソッドだけは省略できることになってるのよ

言い換えれば、メソッド名を省略した場合は自動的に「index」メソッドが指定されたものとみなす…ってこと

C菜

ControllerコントローラーViewビューの役割は分かったです~

最後はModelモデルですねぇ~

B美

さっきの「MATE端末」は開いてるわよね?
そこに次のように入力してちょうだい

bin/cake bake model Counters[Enter]
(データベーステーブルの名前が「counters」なので「Counters」という名前を指定)

あ、さっきのコントローラーと同様、「testapp」ディレクトリ上で実行してね
(事前に「pwd」を打ち込んで、カレントディレクトリを確認すること)

A子

うわっ!
これってエラー?

めっちゃ赤いんだけど…(苦笑)

B美

あー、忘れてた…(汗)

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p[Enter]

上記のコマンドを叩いたら(MariaDBの)rootパスワードを入力してね
(Linuxのrootパスワードじゃないわよ)

B美

そうしたらもう一度さっきのコマンドを実行よ

bin/cake bake model Counters[Enter]


A子

お、今度は成功したっぽい

で、結局「mysql_tzinfo_to_sql」って何だったのよ
意味不明なんだけど…

B美

前々回、「testapp/config/app.php」の285行目を「UTC」から「Asia/Tokyo」に変更したじゃない
でもね、MariaDBにはそのタイムゾーンが用意されていないのよ
なので、システム(Linux)に最初から用意されているタイムゾーンをMariaDB側にロードした(読み込んだ)ってわけ

あ、これって別にプロジェクトごとに毎回実行するわけじゃないからね
(一つのOSにつき、一回だけやればOKだから…)

C菜

要するに、サーバ設定のときにやらなきゃいけなかったのを忘れてたってことですね~?

B美

うぐっ
そ、そうよ

いや、でもこれって忘れるよね?

A子

覚えてるのが普通なのか、忘れちゃうのが普通なのか、私たちには判断できないけどね(苦笑)

B美

と~に~か~く

これによって「testapp/src/Model/Entity」の中に「Counter.php」が
「testapp/src/Model/Table」の中に「CountersTable.php」が作られたってわけ


B美

それではこのModelモデルを使って、データベースアクセスをやってみましょう
「testapp/src/Controller」の中にある「PostTestController.php」を開いてね

クラスのフィールドとして「$Counters」を追加します
class PostTestController extends AppController
{
  private $Counters;

新たなメソッドとして「initialize()」を記述します
  public function initialize(): void
  {
    parent::initialize();

    $this->Counters = $this->fetchTable('Counters');
  }

index」メソッド内に以下のコードを入力します
  public function index()
  {
    $counters = $this->Counters->find()->where(['id' => 1])->first();
    $this->set('count', $counters);

  }



B美

ざっくり説明すると…
必ず最初に実行されるメソッドが「initialize()」と決まっていて、その中で「counters」テーブル(のModelモデルへの参照)をprivateフィールドの「$Counters」に代入したの

これにより「$this->Counters」という形で、「counters」テーブルへの読み書きがModelモデル経由で行えるようになったってわけ

あ、「$this->set()」はControllerコントローラーからViewビューへ値を受け渡すやり方よ

A子

むー、頭がくらくらする…

B美

そういうパターンだと思っていれば良いわ(苦笑)

んじゃ、次は「testapp/templates/PostTest」の中にある「index.php」の中身を記述しましょう

<?php
echo $count['remarks']."の値は".$count['counter'];
?>

上のコードで分かると思うんだけど、データベースアクセスした結果は連想配列として取り扱うってことね



A子

ブラウザのURLに「localhost/testapp/PostTest」と入れたらこうなったよ
赤い矢印で指したところ)

C菜

環境構築編の4回目で作った「testdb」というデータベースと「counters」テーブルは次のようになってましたから、その値が取り出されたってことですね~?

B美

その通り
remarks」の値である「top」と「counter」の値である「0」がビューファイルに埋め込まれたってわけ

あ、ちなみにControllerコントローラーから渡された値を表示するときは、echoを使わずに次のように記述しても良いわよ
(というか、普通は下記のように記述します)

<?= $count['remarks']."の値は".$count['counter']; ?>

ちなみに、Modelモデルのファイル(「testapp/src/Model/Entity/Counter.php」及び「testapp/src/Model/Table/CountersTable.php」)を全くいじっていないのに、テーブルの項目フィールド名を連想配列のキーワード('remarks'や'counter')として使っている(いえ、使うことができている)のがすごいでしょ?

A子

うーん、たしかに便利よねー

B美

さて今回はここまでなんだけど、どうだった?

A子

さっきのコード中にあった「find」とか「where」とか、よく分からないところも多々あるんだけど、「MVC」についてはなんとなくは理解したよ

C菜

私もです~

ちなみに、細かい説明はまた後日ですか~?

B美

ええ、その予定よ

あくまでも今回は「MVC」の話だからね
(全体像を把握してほしいってだけだから)