[php+sql]ページャー機能を持った記事一覧を作るときのメモ

慣れないうちは組んだあと一旦睡眠を挟んでから見返さないとやばいこれ。

はじめに

要するに

  • 対象となる記事全件数
  • 指定数(+指定位置)の記事

これらを取得することが全てといってもいいくらい。

取得箇所を指定できればページャー機能を組み込める。

なお、今回のページャーはURLのパラメータ(?page=2みたいな)で管理することとする。

記事の取得・出力

こんな感じ。

    //表示件数指定
    $numLimit = 20;

    //表示位置指定
    $page = $_GET['page'];
    if(isset($page)){
        $numOffset = ($page - 1) * $numLimit;
    }else{
        $numOffset = 0;
    }

    //取得条件の指定
    $searchword = $_GET['searchword'];
    if(empty($searchword)){
        $sqlWhere = '';
    }else{
        $searchword= str_replace(" ", " ", $searcheword);
        $searchword_array = preg_split("/[ ]+/",$searchword);
        foreach( $searchword_array as $row ){
            if ($row === reset($searchword_array)) {
                $sqlWhere = " WHERE 1";
            }
            $sqlWhere .= " AND ( id LIKE '%{$row}%'
                            OR column1 LIKE '%{$row}%'
                            OR column2 LIKE '%{$row}%')";
        }
        print '検索ワード:'.$searchword;
    }

    //記事数取得
    $dbh = '【PDO省略】';
    $sql = "SELECT * FROM table_example{$sqlWhere}";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    $count = $stmt->rowCount();

    print '<p>記事数:'.$count.'</p>';

    //指定数・指定位置にある記事取得
    $sql = "SELECT * FROM table_example{$sqlWhere} LIMIT {$numLimit} OFFSET {$numOffset}";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    $dbh = null;

    //出力
    if(empty($stmt)){
        print '<p>データなし</p>';
    }else{
        print '<ul>';
        foreach ($stmt as $row) {
            $id = $row['id'];
            $example1 = $row['example1'];
            $example2 = $row['example2'];
            print '<li>'.$id.$example1.$example2.'</li>';
        }
        print '</ul>';
    }

記事をただ取得する場合と、絞り込み検索($_GET[‘searchword’])を通した場合を両立させた構築例。

sqlを2回走らせたのは個人的に気持ち悪いんだけど、思いつかなかったんで今回はしょうがない。

これの肝は地味にsql文のWHERE部分で、つまりここ。

table_example{$sqlWhere}

table名のあとにスペースを開けずに変数を続けてるけど、ここはわざと。

というのは、sql文の中にスペースが2回続くのは良しとされていない。続くと動かない。

なので、WHEREの変数内で、WHEREを書き込む(=検索条件を指定する)状況であれば、変数側でスペースを追加するようにしてある。ここ大事。

ここで作成した変数「$page」「$count」「$numLimit」はページャーでも使用する。

ページャーを作るよ

リンクは進む・戻るだけ作る。
合わせて、全ページ数と現在位置が分かるようにもする。

<?php
    //URLのパラメータを操作するための関数
    function url_param_change($par=Array(),$op=0){
        $url = parse_url($_SERVER["REQUEST_URI"]);
        if(isset($url["query"])) parse_str($url["query"],$query);
        else $query = Array();
        foreach($par as $key => $value){
            if($key && is_null($value)) unset($query[$key]);
            else $query[$key] = $value;
        }
        $query = str_replace("=&", "&", http_build_query($query));
        $query = preg_replace("/=$/", "", $query);
        return $query ? (!$op ? "?" : "").htmlspecialchars($query, ENT_QUOTES) : "";
    }
    //全ページ数を算出
    $pageMax = (ceil($count/$numLimit) < 1)? 1 :ceil($count/$numLimit);
    //現在の表示ページを設定
    if(isset($page)){
        $pageNow = $page;
    }else{
        $pageNow = 1;
    }
    //表示位置とページ数の条件分岐でリンクの内訳を設定(戻る)
    if($pageNow > 1){
        $prevUrl = url_param_change(Array("page"=> $pageNow - 1));
        $prevLink = '';
    }else{
        $prevUrl = '';
        $prevLink = 'nolink';
    }
    //表示位置とページ数の条件分岐でリンクの内訳を設定(進む)
    if($pageMax > $pageNow){
        $nextUrl = url_param_change(Array("page"=> $pageNow + 1));
        $nextLink = '';
    }else{
        $nextUrl = '';
        $nextLink = 'nolink';
    }
?>

<style>.pager a.nolink { pointer-events: none; }</style>

<div class="prev"><a href="https://example.jp/<?php print $prevUrl; ?>" class="<?php print $prevLink; ?>"><span>PREV</span></a></div>
<div class="num"><span><?php print $pageNow; ?></span> / <span><?php print $pageMax; ?></span></div>
<div class="next"><a href="https://example.jp/<?php print $nextUrl; ?>" class="<?php print $nextLink; ?>"><span>NEXT</span></a></div>

関数はこちらのものを使用。
パラメータの一部だけを変更したい場合にとても都合が良かった。

戻る・進む先のページがない場合は、リンク無効化のclass付与で対応。
なんだったら、そもそものhtmlタグの出力自体を操作してもいい。

ブログサイトでよくあるリンクをいっぱい並べるとかプルダウンでページ位置を指定するみたいなのは面倒くさすぎてやらなかった。でもまあ、必要な情報は取得できてるので調理方法を変えたら作れますね。

表示ページ位置の設定部分だけど、ここの内訳をいうと、urlのパラメータにpageがない(=ページ数を引っ張ってこられない)場合に1を代入しなきゃいけない的なあれがある。

そこ以外はコメントにある通りの内容を書いてます以上の解説というか掘り下げというかはできないというか必要なさげですかね。何行も使ってるけど内容としては大したことをしてない。

まとめ的な

現在の作業の集大成の一つ。
他にも色々やってんだけど、抽出関係はマジでめんどくさい。

作っててめっちゃ時間食ってたんで、とりあえずphpは文字列と数値の区別がヌルいところとか、手が抜けるところがあって助かった。逆に言うとそのところをきっちりフォローしてないから詰めなきゃダメなんだけど。

見返したらもっとスマートに書けそうなきがする。
後々に追加したりがあるから仕方ないんだけど、次に作るときはブラッシュアップできそう。
とはいえ、PHPでこういうのを作る機会って滅多にないから、今回みたいにかなり忘れてたり以前から仕様が変わってたりで、失ったものを取り返す作業が多かったりして、なかなか難しい。

コメント

タイトルとURLをコピーしました