オンラインヘルプの設定ページを表示すると、製品とカテゴリーを絞り込むドロップダウンリスト部分で、エラー表示されていることが分かります。これはドロップダウンリスト部分で使用する $settings
配列変数に、'product'
と 'category'
の要素が存在しないからです。
まだ新規作成部分を作成している途中ですが、今回は先に、製品とカテゴリーでリストを絞り込めるようにしていきます。
エラーが出ないようにする
まずはエラーが出ないようにコードを修正します。$settings のデフォルト値を定義している下記の部分に、コードを追加します(onlinehelp_admin.php : 34-35行目)。
private $settings = [
'sortlink' => '',
'itemlink' => '',
'sorted' => 0,
'sorted-order' => 0,
'row_begin' => 0,
'row_end' => -1,
'rows' => 25,
'pagination' => self::EMPTY_PAGINATION,
'product' => 0,
'category' => 0,
];
これでエラーが表示されなくなりました。
絞り込みの選択状態を取得する
絞り込みを行うには、ドロップダウンリストの状態を取得し、データベースからリストを取得する際の条件に設定する必要があります。状態を取得するのは設定画面からPOSTを受信したときになるので、validate_top 関数に処理を追加します。
validate_top 関数を以下のように修正します(onlinehelp.php : 206-216行目)。
public function validate_top($command)
{
// 現在の状態の取得
$product = filter_input(INPUT_POST, 'product');
$category = filter_input(INPUT_POST, 'category');
// 絞り込み状態
if ($product !== 'none') {
$this->settings['product'] = intval($product);
}
if ($category !== 'none') {
$this->settings['category'] = intval($category);
}
// 押されたボタンによって分岐
switch ($command) {
case 'new':
$this->form = 'new';
break;
}
}
なお、submitに設定されているどのボタンをユーザーがクリックしても、絞り込みの状態が変更できるようになります。[適用]ボタンを用意しているのに、[適用]ボタン以外でも絞り込みできるようにするのには理由があります。
たとえば、ページネーションでページの切り替えを行ったときを考えてみます。製品で絞り込みをすでに行っていて、ページネーションでページを切り替えたとします。このとき、製品で絞り込みを行っているという情報を取得しなかった場合、絞り込み状態がリセットされてしまいます。これを防ぐためには、現在のドロップダウンリストの状態を常に取得して、リストの表示に適用する必要があります。その副作用として、どのsubmitボタンでも絞り込みができてしまうという結果になります。
これはこれで問題があるのですが、当面は今の仕様で進めていきます。
[適用]ボタンだけで絞り込みを行い、リストを正しく(違和感なく)表示するには、hidden 属性の input 要素でデータを持たせるか、設定をセッションやデータベースなどに保存しておく方法があります。
絞り込みの設定に基づいてデータを取得する
データベースからレコードを取得する関数を以前作成したとき、すでに絞り込みに対応させていました。この関数へ、絞り込みの情報を渡してやれば、絞り込んだ結果が返ってきます。
print_admin_page関数を、以下のように修正します(onlinehelp_admin.php : 86行目)。
default:
$items = $onlinehelp_db->fetch_helps($this->settings['product'], $this->settings['category'],
$this->settings['sorted'], $this->settings['sorted-order']);
// データの設定
$pagination = $this->settings['pagination'];
バグの修正
SQL文のバグ
動作確認のため、ドロップダウンリストでカテゴリーや製品を選択して[適用]ボタンを押すと、エラーが表示されると思います。エラーメッセージによれば、SQL文に誤りがあるようです。このエラーを解決するため、以下のようにコードを修正しました(onlinehelp_db.php : 54行目)。
if (count($where) > 0) {
$sql .= " WHERE ";
for ($i = 0; $i < count($where); $i++) {
if ($i > 0) {
$sql .= " AND ";
}
$sql .= $where[$i];
}
}
for
ループの条件式が count($where) - 1
となっていたため、count($where)
が 1 だったときにループが一度も実行されず、SQL文の where 部分が不完全になっていました。
ドロップダウンリストのバグ
もう一つ、エラーメッセージが表示されないバグがあります。絞り込みのドロップダウンリストから製品(またはカテゴリー)を選択して、[適用]ボタンを押すと、再表示されたドロップダウンリストは何も選択されていない(「製品の選択」が選択された状態)になります。再表示されたときは、選択した製品(またはカテゴリー)が選択されていることが正しい結果です。
以下のように修正してください(top.php : 38、46行目)。
<span style="margin-right: 1rem;">
<select name="product">
<option value="none">製品の選択</option>
<?php foreach ($products as $_product): ?>
<option value="<?=esc_attr($_product->product_id)?>" <?=intval($this->settings['product']) === intval($_product->product_id) ? 'selected' : ''?>><?=esc_html($_product->prod_name)?></option>
<?php endforeach;?>
</select>
</span>
<span style="margin-right: 1rem;">
<select name="category">
<option value="none">カテゴリーの選択</option>
<?php foreach ($categories as $_category): ?>
<option value="<?=esc_attr($_category->cat_id)?>" <?=intval($this->settings['category']) === intval($_category->cat_id) ? 'selected' : ''?>><?=esc_html($_category->cat_name)?></option>
<?php endforeach;?>
</select>
</span>
$this->settings['product']
と $_product->product_id
、$this->settings['category']
と $_category->cat_id
が、それぞれ等しい場合、そのオプション項目が選択されていることになります。この比較に ===
(型を含むイコール) を使用しているため、型が異なると判断されていたようです。そこで、両辺を intval
で整数に変換し、型を合わせることにしました。なお、==
(型を含まないイコール)の場合、想定外の判断がなされることがあり、セキュリティ上の脆弱性にもつながりかねないため、使用しないことをおすすめします。
これで、ようやく絞り込みができるようになりました(ただし、データがないため実際にどう表示されるかは確認できませんが)。