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システムの課題提出を来週予定している。その際、同時に提出。