b. データベース設計演習(2/4)
2017年度資料
先週のブックマークチュートリアルの続き。ユーザ認証、ログイン画面の作成。
CakePHP の MVC について解説
https://book.cakephp.org/2.0/ja/index.html 2.0の説明。
https://book.cakephp.org/3.0/ja/intro.html 3.0の説明。
cake bake コマンドによる MVC の自動生成について
http://hijiriworld.com/web/cakephp-bake/
演習手順:
解説動画 ←作業内容のみ解説。CakePHPの全体的な話、Webサービスの設計方針MVCの話は授業で解説。
https://book.cakephp.org/3.0/ja/tutorials-and-examples/bookmarks/intro.html CakePHPのインストール と ブックマークチュートリアル
パスワードハッシュを追加 から先週に続いて bookmarkサービスを構築する。
phpMyAdmin で bookmarker データベース の users テーブルのレコードを確認する。
password フィールドにパスワードが平文でそのまま記録されていることを確認。
vs code で php ファイルを編集:
src/Model/Entity/User.php に 以下を追加
※赤字部分を元のコードに組み込む。
PHP のコードについて: $value のように $マークから始まる文字列は、変数。変数は変数宣言無しで使用できる。
オブジェクト指向の class の概念。 メソッドとメンバーを持てる。ハッシュテーブル(連想配列)というデータ構造を持つ。
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher; // この行を追加してください
use Cake\ORM\Entity;
class User extends Entity
{
// bake で生成されたコード
protected function _setPassword($value)
{
$hasher = new DefaultPasswordHasher();
return $hasher->hash($value);
}
}
↓のURLにブラウザでアクセスする。ユーザのパスワードを編集する(List Users -> Edit)
http://localhost/bookmarker/bookmarks
config/routes.php を以下のように編集
↓の赤文字の部分 /bookmarks スコープを追加( /bookmarks/tagged/ 以下へのアクセスを BookmarksController.php の function tags() に処理させる。引数は URL の * の部分の文字列になる。
<?php
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\Router;
Router::defaultRouteClass(DashedRoute::class);
// 新しいルートを tagged アクションのために追加します。
// 末尾の `*` は、渡された引数を持っていることを
// CakePHP に伝えます。
Router::scope(
'/bookmarks',
['controller' => 'Bookmarks'],
function ($routes) {
$routes->connect('/tagged/*', ['action' => 'tags']);
}
);
Router::scope('/', function ($routes) {
// デフォルトのホームと /pages/* ルートへの接続
$routes->connect('/', [
'controller' => 'Pages',
'action' => 'display', 'home'
]);
$routes->connect('/pages/*', [
'controller' => 'Pages',
'action' => 'display'
]);
// デフォルトのルートへ接続
$routes->fallbacks();
});
http://localhost/bookmarker/bookmarks/tagged/ にアクセスして確認。
src/Controller/BookmarksController.php を編集。
public function tags()
{
// CakePHP によって提供された 'pass' キーは全ての
// リクエストにある渡された URL のパスセグメントです。
$tags = $this->request->getParam('pass');
// タグ付きのブックマークを探すために BookmarksTable を使用
$bookmarks = $this->Bookmarks->find('tagged', [
'tags' => $tags
]);
// ビューテンプレートに変数を渡します
$this->set([
'bookmarks' => $bookmarks,
'tags' => $tags
]);
}
http://localhost/bookmarker/bookmarks/tagged/ にアクセスして確認。
500インターナルサーバーエラー: サーバ内部のエラー。プログラムにバグがある。BookmarksTable.phpに ↓の findTagged 関数が未定義のため。
※ $this->Bookmarks->find('tagged',['tags' => $tags]); と、Bookmarksクラスの find() メソッドを呼ぶと、 第1引数の 'tagged'キーワードにより、BookmarksTableクラスのfindTaggedメソッドが呼ばれるようにCakePHPは動作する。 カスタムFinderメソッド を参照。
※ PHPのクエリーの仕組み: find や where や select などCakePHPのメソッドは↓のコードの様にチェーンで接続して利用できる。クエリーは直接実行されるのではなく、遅延評価により、foreachなどで実際にレコードのフィールドにアクセスする必要がでるまで実行されない。カスタムFinderメソッドは、CakePHPのクエリーの仕組みに、開発者側でカスタマイズしたクエリーを導入するためのもの。
src/Model/Table/BookmarksTable.php を編集。
// $query 引数は、クエリービルダーのインスタンスです。
// $options 配列には、コントローラーのアクション中で find('tagged') に渡した
// 'tag' オプションが含まれます。
public function findTagged(Query $query, array $options)
{
$bookmarks = $this->find()
->select(['id', 'url', 'title', 'description']);
if (empty($options['tags'])) {
$bookmarks
->leftJoinWith('Tags')
->where(['Tags.title IS' => null]);
} else {
$bookmarks
->innerJoinWith('Tags')
->where(['Tags.title IN ' => $options['tags']]);
}
return $bookmarks->group(['Bookmarks.id']);
}
http://localhost/bookmarker/bookmarks/tagged/ にアクセスして確認。
Viewが未定義というエラーが出る。↓で検索結果表示画面用の ctpファイルを作成する。
src/Template/Bookmarks/tags.ctp を新規作成して編集。
<h1>
Bookmarks tagged with
<?= $this->Text->toList(h($tags)) ?>
</h1>
<section>
<?php foreach ($bookmarks as $bookmark): ?>
<article>
<!-- リンクを作成するために HtmlHelper を使用 -->
<h4><?= $this->Html->link($bookmark->title, $bookmark->url) ?></h4>
<small><?= h($bookmark->url) ?></small>
<!-- テキストを整形するために TextHelper を使用 -->
<?= $this->Text->autoParagraph(h($bookmark->description)) ?>
</article>
<?php endforeach; ?>
</section>
http://localhost/bookmarker/bookmarks/tagged/ にアクセスして確認。
http://localhost/bookmarker/bookmarks/tagged/検索用キーワード にアクセスして確認。
2016年度資料
先週に続いて、Blogシステムの構築を進める。
先回の作業で、記事を URL http://192.168.201.??/blog3114???/posts から投稿できるところまで進んだ。
画面の例)
↑これは、CakePHPの scaffold 機能で、フレームワークが自動的に生成したデータベースの動作確認用画面です。
このWebのデザインをBlogらしくカスタマイズすることが、今回の目的です。
準備:
XAMPP 起動。 Web サーバ と MySQL サーバを開始。
作業フォルダの確認 D:\XAMPP\htdocs\blog学籍番号\app
PHPMyAdmin の準備
http://192.168.201.??/blog31YYXXX/posts をブラウザで表示
・カスタマイズビューの作成
コントローラーを修正する。 http://192.168.111.??/blog31YYXXX/posts/index を処理するプログラムを追加する。
D:\XAMPP\htdocs\blog学籍番号\app\Controller
PostsController.php
<?php
class PostsController extends AppController {
// public $scaffold;
public $helpers = array('Html', 'Form');
public function index() {
$this->set('posts', $this->Post->find('all'));
}
}
ビューファイルの作成:
D:\XAMPP\htdocs\blog学籍番号\app\View\Posts
index.ctp
ファイル名の拡張子 ctp と 保存文字コードの指定 UTF-8
<h2>記事一覧</h2>
<ul>
<?php foreach ($posts as $post) : ?>
<li>
<?php
// debug($post);
echo h($post['Post']['title']);
?>
</li>
<?php endforeach; ?>
</ul>
動作確認
http://localhost/blog学籍番号/posts をブラウザで表示
・デバッグモードについて
D:\XAMPP\htdocs\blog学籍番号\app\Config
core.php の編集
Configure::write('debug', 0);
この設定変更で、cakePHPの動作時にSQLの実行内容や、エラー表示が抑制される。
debug設定が2の状態では、エラー発生時にプログラムのファイル名などが表示され、セキュリティ上問題となるので、実際にBlogの運用を始める際には、上記の設定変更が必要である。
※ システム開発中は、エラー表示が必要になるので、設定を元に戻す。 0 -> 2
・トップページの設定
D:\XAMPP\htdocs\blog\app\Config
routes.php
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'))
を以下に、修正
Router::connect('/', array('controller' => 'posts', 'action' => 'index'));
動作確認
http://localhost/blog/ を表示して、表示確認。上記の設定で、 blog学籍番号/ のアドレスがcakePHPの設定表示画面から blog記事の表示画面に切り替わる。
・デザインテンプレートのヘッダーの設定
D:\XAMPP\htdocs\blog\app\View\Layouts
default.ctp
内容を確認。 default.ctp は View のデザインテンプレートになっている。 html を編集して、デザインを変更可能。
(必要に応じて)
例1) デザインテンプレートのパラメータを修正
PostsController.php の編集
タイトルヘッダー用の変数の内容を、修正する。
ファイル名の拡張子 php と 保存文字コードの指定 UTF-8
$this->set('title_for_layout', 'こばしBlog');
例2) デザインテンプレート自体を編集
\app\View\Layouts の default.ctp
ヘッダーのHOME のリンク先を、 /blog学籍番号/ に修正
ファイル名の拡張子 ctp と 保存文字コードの指定 UTF-8
<div id="header">
<h1><?php echo $this->Html->link('HOME', 'http://192.168.201.??/blog学籍番号/'); ?></h1>
</div>
タイトルヘッダーの記述を削除
\app\View\Layouts の default.ctp の 25行目を削除
<?php echo $cakeDescription ?>: ←1行削除する
・URLからコントローラーに引数を渡し、特定の記事を表示する
PostsController.php に 記事番号を指定して 個別に記事を表示する機能 を追加する。
public function view($id = null) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
D:\XAMPP\htdocs\blog\app\View\Posts
view.ctp
ファイル名の拡張子 ctp と 保存文字コードの指定 UTF-8
<h2><?php echo h($post['Post']['title']); ?></h2>
<p><?php echo h($post['Post']['body']); ?></p>
動作確認
URLをブラウザに入力し、以下の形式で、記事番号を添えてアクセスする。
記事番号2を表示する例)
http://192.168.201.70/blog3114888/posts/view/2
・記事投稿機能の追加
以下のコントローラーで add() の部分が記事投稿処理である。 投稿用のフォームは、 add.ctp で構成する。
PostsController.php
index.ctp
view.ctp
<h2><?php echo h($post['Post']['title']); ?></h2>
<p><?php echo h($post['Post']['body']); ?></p>
add.ctp
<h2>投稿フォーム</h2>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body',array('rows'=>3));
echo $this->Form->end('投稿');
動作確認
TOPページのURLを表示した例)
確認項目: タイトル(タブの部分)表記、タイトル(ページヘッダー部分)の表記とリンク先、記事一覧のタイトルとリンク、投稿機能の動作
記事の表示例)
投稿画面例)
メモ:
データベース mytest の提出について。Blogシステムの課題提出を来週予定している。その際、同時に提出。