データベースを使ったWebアプリケーションでは、テーブルに別のテーブルを結合して、仮想的な大きなテーブルとして利用する「JOIN」の機能が欠かせない。
また、レストランに対する料理の種類のように、1対多で関連づけられる可能性のあるものは、関連づけテーブルを別に用意すれば、容易に拡張できる。
この例では、Quictyの以下の機能の使い方を紹介する。
- Virtualフィールドの利用とバインドされていないデータセットの登録、更新
- list_optionsクラスモジュールを使ったテーブルのJOIN
- info.htmlとedit.htmlを分離し、部品テンプレートform_view.incを作成して読み込み
- info.htmlではform_view.incでlist_optionsによるJOINの結果を表示
今回は、以下のページとデータセットを作成する。
データセット | マスタメンテページクラス | ページクラスモジュール |
restaurant | restaurant | index.class.php |
category | category | category.class.php |
category2restaurant | category2restaurant | category2restaurant.class.php |
各データセットは以下のように設定する
restaurantデータセット
Name(カラム名) | タイトル | DB型 | Quicty型 |
id | - | int | id |
name | 店名 | text | text |
category_id | 料理の種類 | - | select_from_table(Virtual) |
category_idはVirtual指定なので、フォームに表示されるが、テーブルにカラムは作成されない。
categoryデータセット
Name(カラム名) | タイトル | DB型 | Quicty型 |
id | - | int | id |
name | 店名 | text | text |
category_id | 料理ID | int | int |
category2restaurantデータセット
Name(カラム名) | タイトル | DB型 | Quicty型 |
id | - | int | id |
restaurant_id | レストランID | int | int |
category_id | 料理ID | int | int |
サンプルコード:restaurant03.zip
展開したrestaurant03フォルダをQTフォルダの中において、「アプリケーションの読み込み」で読み込んでください。
ご注意:このブログのサンプルコードは、シングルクオートやダブルクオートなどがスマートクオートに変換されているため、コピペしてもそのままではエラーになることが多いです(エディタによる)。
なるべく、サンプルコードをダウンロードしてご利用ください。
アプリの登録
Qtビルダーのトップページで「アプリケーションの追加」をクリック。
サイト名「レストラン03」
Name「restaurant03」
で登録。
ページとデータセットの作成
アプリケーション「restaurant03」の設定画面で「ページの追加」をクリック。
タイトル「料理の種類」
Name「category」
ページの種類「マスタメンテ/マルチページ」
で登録。
データセット「category」にtext型フィールドを追加。
タイトル「料理名」
Name「name」
で登録。
データセット「category」にint型フィールドを追加。
タイトル「料理ID」
Name「category_id」
maxlength「4」
minlength「1」
で登録。
「料理名」と「料理ID」フィールドを確認し、テーブル関連設定ファイルの保存とテーブルの作成を実行。
アプリの設定画面に戻って「ページの追加」。
タイトル「レストランの料理の種類」
Name「category2restaurant」
ページの種類「マスタメンテ/マルチページ」
で登録。
データセット「category2restaurant」にint型フィールドを追加。
タイトル「レストランID」
Name「restaurant_id」
maxlength「4」
minlength「1」
で登録。
データセット「category2restaurant」にint型フィールドを追加。
タイトル「料理ID」
Name「category_id」
maxlength「4」
minlength「1」
で登録。
「レストランID」と「料理ID」フィールドを確認し、テーブル関連設定ファイルの保存とテーブルの作成を実行。
アプリ「restaurant03」のページで「トップページに機能を追加」をクリック。
タイトル「レストラン」
Name「restaurant」
ページの種類「マスタメンテ/マルチページ」
で登録。
データセット「restaurant」にtext型フィールドを追加。
タイトル「店名」
Name「name」
で登録。
データセット「restaurant」にselect_from_table型のフィールドを追加。
タイトル「料理の種類」
Name「category_id」
VirtualFieldをチェック
Value=>(key=>value)は以下の通り。
_TABLEの右の欄「category」
_VALUEの右の欄「category_id」
で登録。
登録が終わったら、restaurantデータセットのテーブル関連設定ファイルを保存。テーブルの作成を実行。
料理の種類を登録する
アプリケーション「restaurant03」を開き、右メニューの「料理の種類 追加」をクリック。
料理名「和食」、料理ID「100」で登録。
同様に、
料理名「西洋料理」、料理ID「200」
料理名「中華料理」、料理ID「300」
で登録しておく。
レストラン登録時にレストランIDと料理IDの関係を、「category2restaurant」データセットに登録するように変更
QTフォルダの下のrestauant03フォルダ。
lib/Pages/index_classes/_base.class.phpをテキストエディタ開き修正。
「function display_record」の「return $result;」の前に以下のコードを追加。
————————————————————-
require_once ‘Pages/category2restaurant.class.php';
$category2restaurant = new category2restaurant($this->home_dir);
$category2restaurant->QuictyStatus = $this->QuictyStatus;
if($this->QuictyStatus==’INSERT’ ) {
$_POST[‘restaurant_id’] = $this->restaurant[‘id’];
$category2restaurant->display_record();
} elseif ($this->QuictyStatus==’UPDATE’ OR $this->QuictyStatus==’DELETE’) {
$_POST[‘restaurant_id’] = $_POST[‘id’];
$condition = ‘restaurant_id=’.$_POST[‘id’];
$category2restaurant->display_record($condition);
}
————————————————————-
(追加した状態)
テーブルのJOINを設定
アプリケーション「restaurant03」の右メニューから「レストラン 追加」をクリック。
店名を登録し、料理の種類を選択する。
登録後の一覧。「料理の種類」が表示されない。
確認のため、右メニューから「レストランの料理の種類 一覧」をクリック。
category2restaurantには、ちゃんとレストランIDと料理IDの組み合わせが登録されている。
lib/Pages/indes_classes/list_options.class.phpをテキストエディタで開いて修正する。
以下の4つのメソッドを修正する。
- make_where_condition() 検索条件の設定
- make_join_condition() JOINの設定
- make_select_fields() 取得するカラム名(フィールド名)の設定
- make_sort_condition ソート(ORDER BY)の設定
make_where_condition
————————————————————-
function make_where_condition($add_condition=”,$cond=’AND’) {
$search_system_file = $this->page->home_dir.’/etc/search_view/restaurant.sys';
if(file_exists($search_system_file)) {
$search_system = read_data_array($search_system_file);
} else {
$search_system = array(
‘keyword’=>array(‘title’=>’restaurant.name’,’url’=>’restaurant.url’), // keyword search target column
‘condition’=>array(‘id’=>’restaurant.id’,’application_id’=>’restaurant.application_id’), // id search target column
//’period’=>array(‘start_date’=>array(‘column’=>’date’,’end’=>’end_date’))
);
}
return $this->list->make_condition($search_system,$add_condition,$cond);
}
————————————————————-
↓(修正)
————————————————————-
function make_where_condition($add_condition=”,$cond=’AND’) {
$search_system = array(
‘keyword’=>array(‘title’=>’restaurant.name’,’category’=>’category.name’),
‘condition’=>array(‘category_id’=>’category.category_id’),
);
return $this->list->make_condition($search_system,$add_condition,$cond);
}
————————————————————-
make_join_condition
————————————————————-
function make_join_condition() {
//$this->list->real_count = true; // set this flag if join other table
//$joins[] = “LEFT JOIN {table_name} ON restaurant.{table_name}_id={table_name}.id”;
//$join_condition = implode(‘ ‘,$joins);
return $join_condition;
}
————————————————————-
↓(修正)
————————————————————-
function make_join_condition() {
//$this->list->real_count = true; // set this flag if join other table
$joins[] = “LEFT JOIN category2restaurant ON restaurant.id=category2restaurant.restaurant_id”;
$joins[] = “LEFT JOIN category ON category2restaurant.category_id=category.category_id”;
$join_condition = implode(‘ ‘,$joins);
return $join_condition;
}
————————————————————-
make_select_fields
————————————————————-
function make_select_fields() {
$this->select_system = array(
‘restaurant’=>’*’, // specify all column
//’restaurant’=>array(‘id’,’name’,’url’), // specify each column
//’restaurant’=>array(‘id’=>’restaurant_id’), //specify another column name
);
return $this->list->make_select_fields($this->select_system);
}
————————————————————-
↓(修正)
————————————————————-
function make_select_fields() {
$this->select_system = array(
‘restaurant’=>’*’, // specify all column
‘category’=>array(‘category_id’=>’category_id’,’name’=>’category_name’,),
);
return $this->list->make_select_fields($this->select_system);
}
————————————————————-
make_sort_condition
————————————————————-
function make_sort_condition() {
$sort_system = array(
‘default’=>’ order by id’,
// sort keys
‘columns’=>’*’, // specify all column
//’columns’=>array(‘id’,’name’,’url’), // specify each column
);
if($this->page->sort_option) {
$this->list->set_sort_option($this->page->sort_option,$this->page->order_option);
}
return $this->list->make_order($sort_system);
}
————————————————————-
↓(修正)
————————————————————-
function make_sort_condition() {
$sort_system = array(
‘default’=>’ order by restaurant_id’,
‘columns’=>array(‘id’=>’restaurant.id’,’category_id’=>’category.category_id’,),
);
if($this->page->sort_option) {
$this->list->set_sort_option($this->page->sort_option,$this->page->order_option);
}
return $this->list->make_order($sort_system);
}
————————————————————-
(修正後の画面)
一覧でJOINの結果を確認
restaurant03のトップページを開くと、今度は「料理の種類」が表示されている。
詳細表示(データ別表示)にもJOINを適用
店名の前の番号をクリックし、詳細表示(データ別表示)画面を開く。
料理の種類が表示されていない。
表示用のview/info.htmlをカスタマイズして、JOINの結果を表示できるようにする。
現在インクルードしている「inbcludes/common/auto_input_form.inc」ではJOINに対応できないため、
カスタムの部品テンプレートを作成する。
「restaurant」データセットのページを開く。
一番下までスクロール。
「フォーム/テーブル表示テンプレートの作成」で
「input_form.inc」にチェックを入れて、「保存」をクリック。
「input_form.inc」を保存すると「form_view.inc」も同時に作成される。
今回は、「form_view.inc」を使う。
view/info.htmlを詳細表示画面専用にし、それ以外の登録、更新、削除は、edit.htmlに切り分けることにする。
view/info.htmlを複製し、edit.htmlとファイル名を変える。
view/info.htmlをテキストエディタで修正。
「includes/common/auto_input_form.inc」を呼び出しているところを
「includes/restaurant/form_view.inc」に変更する。
不要なコメントアウトも削除。
————————————————————-
<div id=”contents-main”>
{include file=’includes/common/auto_search_form.inc’}
{*include file=’includes/restaurant/search_form.inc’*}
{include file=’includes/common/messages.inc’}
{include file=’includes/common/auto_input_form.inc’}
{*include file=’includes/restaurant/input_form.inc’*}
</div>
————————————————————-
↓(修正)
————————————————————-
<div id=”contents-main”>
{include file=’includes/common/auto_search_form.inc’}
{*include file=’includes/restaurant/search_form.inc’*}
{include file=’includes/common/messages.inc’}
{include file=’includes/restaurant/form_view.inc’}
</div>
————————————————————-
info.htmlの表示を行う「dispatch_info()」を以下のように修正。
————————————————————-
function dispatch_info() {
$this->assign_search_form();
$result = $this->display_record();
$this->assign_form(‘input_form’,$this->form);
$this->assign_page_and_pathlist($this->W[‘restaurant’].’ ‘.$this->W[‘display’]);
return $this->display($this->current_template);
}
————————————————————-
↓(修正)
————————————————————-
function dispatch_info() {
$this->assign_search_form();
$result = $this->display_record();
$list_table = $this->list_records(‘restaurant.id=’.$_GET[‘id’]);
$this->assign_form(‘input_form’,$this->form);
$this->assign(‘restaurant_form_view’,$this->list->display_table_value($list_table));
$this->assign_page_and_pathlist($this->W[‘category’].’ ‘.$this->W[‘display’]);
return $this->display($this->current_template);
}
————————————————————-
(修正後)
修正後は、詳細ページでも「料理の種類」が表示された。
「フォーム/テーブル表示テンプレートの作成」で作成するカスタム部品テンプレートは、シンプルなSmartyのテンプレートファイルで、
複雑な条件分岐やループはないので手直ししやすい。
デザインの変更が必要な場合などはカスタム部品テンプレートで行う。
以上。