POPSブログ

BaserCMSブログに機能を付加する/5

17

  Category:  basercms2012/02/08 pops 

少し改造して、簡単な「複数タグの検索機能」を作るです。意外と使えそうな気もする?


BaserCMSブログに機能を付加する/5


複数タグの簡単な検索機能を作る

BaserCMSには1個のタグを検索表示する機能はありますが、複数タグによる検索はありません。タグで分類しておけば、簡単な不動産、商品などの検索が出来るわけです。(前からこれがほしかった)
但し、私、CakePHPで作る能力はありませんので、既存の処理で出来ないものかと考えてみました。


思考方法

1. 新規の処理で新たな画面をつくるのは、既存の「tag検索」で「archives表示画面」を表示しているのを工夫するのが手っ取り早い。1個のタグ検索で取り出したものを、ブログ「ページごとの登録タグ」と比較し分別表示すれば良い。

2. BaserCMS標準の「タグ絞込み表示」を使用すれば、リンクつきのタイトルが得られる。これを組み合わせれば良い。

3. 「archives表示画面」に入り、別の処理をすると言う「浅ましい」考えです。通常別の処理をするにはコントローラーを作らねばなりませんが、既存のコントローラーから「tag検索を装って」はいります。スパイか泥棒みたいだ。


http://ドメイン名/サブフォルダ名/ブログID/archives/tags/php-jquery-basercms
のような決まりで入ります。tags は複数タグの検索を意味します。(名前は自由ですがとりあえず)


  • /archives/tags/ではいります。
  • php-jquery-basercmsは複数のタグです。必ず - で区切ります。
  • BaserCMS Helper 「記事一覧の出力」で1度タグ絞込み処理します。
  • 残りタグを、記事毎の登録タグと比較して「表示するか」を判定します
  • 正規の処理ではありませんのでページングはありません。(jqueryで可能)
  • 複数タグ送信の規則の決め方次第では、複合的な処理も可能でしょう。

簡潔に言えば、 [archives画面拝借] > [archives表示で1度タグ絞込み] > [残りタグをposts.ctpで分類]



タグの検索の動きを見てみますと
blog_controller.phpに入り
http://ドメイン名/サブフォルダ名/ブログID/archives/tag/タグ名
で処理すると(BaserCMS Helper 「記事一覧の出力」とほぼ同様の処理をしています)
表示のために
archives.ctp
でレイアウト、ページング、表示されれているのがわかります

コントローラーで1個のタグを検索することは可能ですが、ページングされてしまいますので、ここでは処理しません。ページングさせないようにすればarchives.ctpでさらに絞り込む処理をすることができますが、書き換えが多くなるのでやめます。

CakePHPには標準で複数タグの検索機能はありません。そのためは「記事一覧の出力」で1個のタグ検索でデータを求め、ブログ記事登録のタグを比較して絞りこむもので、完全なデータベース処理ではありません。

コントローラーに入った時点でタグ処理はできますが、その後比較絞りこみをしますと歯抜け状態のページングになりますので、ここではスルーします。archives.ctpの画面を借りるだけです。


もし複数のタグ(tags)の場合だけ「ページング」させないで出力させることが出来るなら(ここだけページ当たり10記事設定、を100000位に変更できないか?)、既存のタグ(tag)表示と「表示レイアウト」を同じにできます。でもここでの修正は危険ですからやめました(WAKARAN)。ページングはjqueryですることは可能です。


実際の表示例 (タグ series memo basercms での検索結果)

複数タグ検索記事一覧: series-memo-basercms

投稿記事題目登録タグ投稿日
FLASH表示TEST/4series, memo, basercms, flash2012.01.31
FLASH表示テスト/3series, memo, basercms, flash, jquery2011.12.23
FLASH表示テスト/2series, memo, basercms, flash2011.12.20
FLASH表示テスト/1series, memo, basercms, flash2011.12.15

簡単ですが、実用には十分です。


現在のパスを取得する

../archives/ 以降のパスを取得して、これを判定の目安として、現在利用する画面が同じなため、既存の処理(category tag など)と分岐させることにします。
コントローラーでも可能でしょうが。私は、知識がないので現在は出来ない。


パスが取れる、これは重要、但しctpの階層によっては取得できない
$pass = $this->params['pass'];
$pass[0]はtagsが入る
$pass[count($pass)-1];はphp-jquery-basercmsが入る
archives.ctpは色々な処理を表示する画面ですから、$pass[0]は判定に利用しています
取得できない場合は、別の方法をとります

複数のタグの区分けには - を使用しました。CakePHPでは & / # は使用できません。ここチョットつらい。


【注意】、修正箇所をメモする、ルートをメモする、またはテーマの中にコピーしておくなどの対処が必要です。
controller、以外の archives.ctp、等はテーマ層のほうにコピー移動書き換え推奨
baser/plugins/blog/views/blog/default/ の中のarchives.ctp、posts.ctp、などを
app/webroot/themed/{テーマ}/blog/default/ に


blog_controller.phpの修正

blog_controller.phpをだます。tagsで入りarchives.ctpに行くことだけが目的。


baser/plugins/blog/controllers/blog_controller.php
function archives()を書き換える

追加1
elseif($pass[0] == 'tags') {$type = 'tags';}
追加2 tag tagsに注意
/* タグ別記事一覧2 */
case 'tags':
	$tags = h($pass[count($pass)-1]);
	if(empty($this->blogContent['BlogContent']['tag_use']) || empty($tags)) {
		$this->notFound();
	}
	//archives.ctpのタイトルに入れる文字を作っているだけ
	$tags3=split("-",$tags);
	$tag=$tags3[0];

	//タグ検索しないでスルーする/検索してからはいるとページングされるので、検索しないで入る
	//$posts = $this->_getBlogPosts(array('conditions' => array('tag' => $tag)));
	$this->pageTitle = urldecode($tags);
	$template = $this->blogContent['BlogContent']['template'].DS.'archives';
	break;

-------------------------------------------------
前後略す

/**
 * [PUBLIC] ブログアーカイブを表示する
 *
 * @param mixed	blog_post_id / type
 * @param mixed	blog_post_id / ""
 * @return void
 * @access public
 */
	function archives() {

		// パラメーター処理
		$pass = $this->params['pass'];
		$type = $year = $month = $day = $id = '';
		$navis = $posts = array();
		$single = false;
		$posts = array();
		
		if($pass[0] == 'category') {
			$type = 'category';
		}elseif($pass[0] == 'tag') {
			$type = 'tag';
		}elseif($pass[0] == 'tags') {
			$type = 'tags';
		}elseif($pass[0] == 'date') {
			$type='date';
		}

		switch($type) {
			
			/* カテゴリ一覧 */
			case 'category':

				//略す

			/* タグ別記事一覧 */
			case 'tag':
				$tag = h($pass[count($pass)-1]);
				if(empty($this->blogContent['BlogContent']['tag_use']) || empty($tag)) {
					$this->notFound();
				}
				$posts = $this->_getBlogPosts(array('conditions' => array('tag' => $tag)));
				$this->pageTitle = urldecode($tag);
				$template = $this->blogContent['BlogContent']['template'].DS.'archives';
				break;

			/* タグ別記事一覧2 */
			case 'tags':
				$tags = h($pass[count($pass)-1]);
				if(empty($this->blogContent['BlogContent']['tag_use']) || empty($tags)) {
					$this->notFound();
				}

				$tags3=split("-",$tags);
				$tag=$tags3[0];

				//検索しないでスルーする/検索してからはいるとページングされるので、検索しないで入る
				//$posts = $this->_getBlogPosts(array('conditions' => array('tag' => $tag)));
				$this->pageTitle = urldecode($tags);
				$template = $this->blogContent['BlogContent']['template'].DS.'archives';
				break;

				//略す

		}
前後略す

-------------------------------------------------

archives.ctpの修正

archives.ctpを既存の処理と新たな処理と分離するため、少し修正します

コントローラーで1個のタグ絞込みをして、ここで比較処理を出来ればよいのだが、ページングされているので歯抜けページになってしまう。(1.2ページに何もなし、3ページ目に分類されたものがあったとか、とても使えない)


baser/plugins/blog/views/blog/default/archives.ctp
検索してからはいるとページングされるので、検索しないで入る

追加1
既存の処理とtags処理を分離する、$pass[0]で判定
追加2
$baser->blogPosts('ブログID', 1000,array('tag' => $tags3[0]));
をいれて、1番目のタグで絞り込む、表示はposts.ctpになる

-------------------------------------------------

前後略す

$baser->setDescription($blog->getTitle().'|'.$baser->getContentsTitle().'のアーカイブ一覧です。');
?>

<!-- title contents-head -->
<h2 class="blog-head"><?php $blog->title() ?></h2>

<!-- archives title -->
<?php $pass = $this->params['pass'];if($pass[0] != 'tags'): ?>
<h3 class="contents-head"> ブログ記事一覧: <?php $baser->contentsTitle() ?></h3>
<!-- list -->
<?php if(!empty($posts)): ?>
<?php foreach($posts as $post): ?>
<div class="post">
<h4 class="contents-head"><?php $blog->postTitle($post) ?></h4>
<?php $blog->postContent($post,true,true) ?>
<div class="meta corner5"><span><?php $blog->category($post) ?> <?php $blog->postDate($post) ?> <?php $blog->author($post) ?></span></div>
<?php $baser->element('blog_tag', array('post' => $post)) ?>
</div>

<?php endforeach; ?>
<?php else: ?>
<p class="no-data">記事がありません。</p>
<?php endif; ?>

<!-- pagination -->
<?php $baser->pagination('simple'); ?>
<?php endif; ?>

<?php
$pass = $this->params['pass'];
//通常の位置
$tags=$pass[count($pass)-1];
//最後ページを含む場合はずれる
if(ereg('page',$tags)) {$tags=$pass[count($pass)-2];}
$tags3=split("-",$tags);
$tagscount=count($tags3);
$tagtext=$tags;

if($pass[0] == 'tags') {
echo('<h3 class="contents-head">');
echo(' 複数タグ検索記事一覧: ');
$baser->contentsTitle();
echo('</h3>');

$baser->blogPosts('pops', 1000,array('tag' => $tags3[0]));

echo('<p class="align-center">[ 全ての記事を検索した結果を表示しています ]</p>');
echo('<br /><div id="tags_pagination"></div>');
}
?>
-------------------------------------------------

posts.ctpの修正 (多重検索と共用の場合)

詳細の表示と残りタグの比較をして分類します。検索出力 posts を分離する場合はこの下に書いてあります

ページングを解除して、ここの比較処理をarchives.ctpで出来ればよいのだが、出来ない知識のなさ、、ああ。
IE以外で、JSのページング処理(TR要素を表示非表示のごまかしページング)を行うとメチャ崩れるのでテーブル2つの構成にした。CSSが複雑怪奇だ、、


baser/plugins/blog/views/blog/default/posts.ctp

追加1
既存の処理とtags処理を分離する、$pass[0]で判定
追加2
$baser->blogPosts('pops', 1000,array('tag' => $tags3[0]));
をいれて、1番目のタグで絞り込む、表示はposts.ctpになる
追加3
$passが取得できないため$pass[0]の判定が出来ない
ヘルパーを新たに作りどこからでも$pass[0]の値が取れるようにする
function tagsPass() {} 
呼び出し
$baser->tagsPass();

ブログ記事に登録されたタグとマッチ比較しているだけ、確実に捕らえるため工夫した
登録データ ,BaserCMS,baser,CMS,basercms, を baser でマッチさせると不正確だ ,baser, で比較させた

-------------------------------------------------
前後略す

<?php $pass = $baser->tagsPass();if($pass[0] != 'tags'): ?>
<?php if($posts): ?>
<table class="list_table">
<?php foreach($posts as $key => $post): ?>
 <tr>
	<td class="list_td1"><?php $blog->postTitle($post) ?></td><td class="list_td2"><?php $blog->postDate($post, 'Y.m.d') ?></td>
 </tr>
<?php endforeach ?>
</table>
<?php else: ?>
<p class="no-data">記事がありません</p>
<?php endif ?>
<?php endif ?>

<?php $pass = $baser->tagsPass();if($pass[0] == 'tags'): ?>
<?php if($posts): ?>
<table class="title_table"><tr><td class="list_td1">投稿記事題目</td><td class="list_td3">登録タグ</td><td class="list_td2">投稿日</td></tr></table>
<table class="list_table">
<?php
//通常の位置
$tags=$pass[count($pass)-1];
$tags3=split("-",$tags);
$tagscount=count($tags3);
$tagtext=$tags;
//$spter=',';
$spter=', ';//間隔の見えるよう、問題がある場合は上のスペースなしを使う
$data_none=true;//絞り込み後の記事の有無

foreach($posts as $key => $post) {

	//複数の場合比較する
	if ($tagscount>1) {
		$count_flag=0;
		$taglist="";
		//spterを前後にはさむことにより完全一致を装う
		$taglist2=$spter;

		//記事登録タグLISTを取り出す、精度は悪いが簡単
		//精度上げる場合は区切り文も含めて判定すればよい
		foreach($post['BlogTag'] as $tag) {
			$taglist .=$tag['name'].$spter;
			$taglist2 .=$tag['name'].$spter;//現在こちらを使用
		}
		$taglist = rtrim($taglist,$spter);//最後の区切り文字を除去

		//複数タグと比較、1番目は終わっているのでその他を調べる
		for ($i=1; $i<=$tagscount;$i++) {
			//spterを前後にはさんで検索するので途中のマッチを防げる
			$tagxx=$spter.$tags3[$i].$spter;
			//タグがあればカウントUP
			//if (ereg($tagxx,$taglist2)){$count_flag ++;}
			//簡易の場合不正確
			if (ereg($tags3[$i],$taglist)){$count_flag ++;}
		}
	}
	//タグが複数でない場合/表示をあわせるためtaglistを取得する
	//検索はおわっている
	if ($tagscount==1) {
		$taglist="";
		foreach($post['BlogTag'] as $tag) {
			$taglist .=$tag['name'].$spter;
		}
		$taglist = rtrim($taglist,$spter);//最後の区切り文字を除去
	}

	//比較タグ数が合えば条件クリアで記事を出力/breakしていない
	if ($count_flag == $tagscount-1 && $breakflag==0) {
		$data_none=false;
		echo('<tr>');
		echo('<td class="list_td1">');
		$blog->postTitle($post);
		echo('</td><td class="list_td3">');
		//echo($blog->tag($post));//LINK付きのリスト
		echo($taglist);//ただのリスト
		echo('</td><td class="list_td2">');
		$blog->postDate($post, 'Y.m.d');
		echo('</td></tr>');
	}

}

?>
</table><br />
<?php
if ($data_none) {echo('<p class="no-data">複数タグ検索記事がありません</p>');}
?>

<?php else: ?>
<p class="no-data">複数タグ検索記事がありません</p>
<?php endif ?>
<?php endif ?>
-------------------------------------------------

blog_baser.phpの修正

ヘルパーの追加
blog_baser.phpでparams['pass']が取れるので、それを取得するだけのヘルパー
これが無い場合は、通常の1個のタグ検索表示をします。

posts.ctpでparams['pass']が何故か取得できない。取得する別の方法があれば、ここでの追加は不要だ。


baser/plugins/blog/views/helpers/blog_baser.php
-------------------------------------------------

前後略す
class BlogBaserHelper extends AppHelper {
	function blogPosts ($contentsName, $num = 5, $options = array()) {
	前後略す
	}
	//追加
	//tagsの場合のparamsを取得する posts.ctpでは直接取得できない
	function tagsPass() {
		return $this->params['pass'];
	}
}

ヘルパーなど書いてあるphpでは、名前がダブらない限りヘルパーの追加を簡単にできますが、バージョンUPで上書きされると、消えてしまいますので要注意です。


検索出力postsを分離する場合

archives.ctp の方は分離できません。

archives.ctp の検索出力ctpを、posts_tags に指定する。新たに posts_tags.ctp を作り保存する。(名前は自由ですが、posts.ctp と同じ[デフォルト階層]の中に作る)


archives.ctp の検索出力 blogPosts() 部分を変更
分離のため、posts_tags にエレメント(template)を指定する
$baser->blogPosts('pops', 1000,array('tag' => $tags3[0],'template'=>'posts_tags'));

通常検索用 posts.ctp
通常用途では tagsPass() の部分はここでは要らない。


baser/plugins/blog/views/blog/default/posts.ctp

前後略す

<?php if($posts): ?>
<table class="list_table">
<?php foreach($posts as $key => $post): ?>
 <tr>
	<td class="list_td1"><?php $blog->postTitle($post) ?></td><td class="list_td2"><?php $blog->postDate($post, 'Y.m.d') ?></td>
 </tr>
<?php endforeach ?>
</table>
<?php else: ?>
<p class="no-data">記事がありません</p>
<?php endif ?>

検索出力ctp/多重検索用 posts_tags.ctp


posts.ctp と同じ default フォルダの中に保存
もう少し省略可能ですが、問題の出ないように2重に処理しました
通常、$pass[0]の値が'tag'ではここには進入しない、もしtagsPass()の値が取得出来ない、
または異常な場合を想定した書き方

<?php
/* posts_tags.ctp */
?>

<?php $pass = $baser->tagsPass();if($pass[0] == '!tags'): ?>
<p class="align-center">PASSの取得が出来ません</p>
<?php endif ?>

<?php $pass = $baser->tagsPass();if($pass[0] == 'tags'): ?>
<?php if($posts): ?>
<table class="title_table"><tr><td class="list_td1">投稿記事題目</td><td class="list_td3">登録タグ</td><td class="list_td2">投稿日</td></tr></table>
<table class="list_table">
<?php
//通常の位置
$tags=$pass[count($pass)-1];
$tags3=split("-",$tags);
$tagscount=count($tags3);
$tagtext=$tags;
//$spter=',';
$spter=', ';//間隔の見えるよう、問題がある場合は上のスペースなしを使う
$data_none=true;//絞り込み後の記事の有無

foreach($posts as $key => $post) {

	//複数の場合比較する
	if ($tagscount>1) {
		$count_flag=0;
		$taglist="";
		//spterを前後にはさむことにより完全一致を装う
		$taglist2=$spter;

		//記事登録タグLISTを取り出す、精度は悪いが簡単
		//精度上げる場合は区切り文も含めて判定すればよい
		foreach($post['BlogTag'] as $tag) {
			$taglist .=$tag['name'].$spter;
			$taglist2 .=$tag['name'].$spter;//現在こちらを使用
		}
		$taglist = rtrim($taglist,$spter);//最後の区切り文字を除去

		//複数タグと比較、1番目は終わっているのでその他を調べる
		for ($i=1; $i<=$tagscount;$i++) {
			//spterを前後にはさんで検索するので途中のマッチを防げる
			$tagxx=$spter.$tags3[$i].$spter;
			//タグがあればカウントUP
			//if (ereg($tagxx,$taglist2)){$count_flag ++;}
			//簡易の場合不正確
			if (ereg($tags3[$i],$taglist)){$count_flag ++;}
		}
	}
	//タグが複数でない場合/表示をあわせるためtaglistを取得する
	//検索はおわっている
	if ($tagscount==1) {
		$taglist="";
		foreach($post['BlogTag'] as $tag) {
			$taglist .=$tag['name'].$spter;
		}
		$taglist = rtrim($taglist,$spter);//最後の区切り文字を除去
	}

	//比較タグ数が合えば条件クリアで記事を出力/breakしていない
	if ($count_flag == $tagscount-1 && $breakflag==0) {
		$data_none=false;
		echo('<tr>');
		echo('<td class="list_td1">');
		$blog->postTitle($post);
		echo('</td><td class="list_td3">');
		//echo($blog->tag($post));//LINK付きのリスト
		echo($taglist);//ただのリスト
		echo('</td><td class="list_td2">');
		$blog->postDate($post, 'Y.m.d');
		echo('</td></tr>');
	}

}

?>
</table><br />
<?php
if ($data_none) {echo('<p class="no-data">複数タグ検索記事がありません</p>');}
?>

<?php else: ?>
<p class="no-data">複数タグ検索記事がありません</p>
<?php endif ?>
<?php endif ?>

posts.ctp用のCSS

CSS、複数タグ検索のページャー部分も含む。


/*table list IE以外線がでるので修正、複雑*/

.title_table,.title_table td {
border-style:none;
background-color:#CCCCCC;
}

.list_table {
width:640px;
margin-top:5px;
padding:2px;
border-collapse:separate;
border0;
}
.list_table tr{
width:640px;
border:0;
}
.list_td1 {
width:390px;
border:0;
border-bottom:#F5F5F5 1px solid;
}
.list_td2 {
width:70px;
border:0;
border-bottom:#F5F5F5 1px solid;
}
.list_td3 {
width:180px;
border:0;
border-bottom:#F5F5F5 1px solid;
background-color:#FFFFFF;
}

/*table no-border*/
.no-border,.no-border tr,.no-border td{
border-style:none;
}

/*tags-pagination*/
#tags_pagination {
width:100%;
height:22px;
text-align:center;
background-color:none;
}
#tags_pagination .number {
width:20px;
height:14px;
padding:4px;
margin-left:4px;
background-color:#CCCCCC;
cursor:pointer;
}
#tags_pagination .actived {
background-color:#EBB7B7;
}

注意、書き換えなどを伴いますので、十分なローカルでのテストが必要です。また実際使用するには、入力のセレクターなどが必要ですし、jqueryなどの操作で送信データ(URLを作る)をチェック、整形する必要があります。

いつの日か、誰かが簡単なプラグインなど作ってくれる事を期待しましょう。実際不動産屋の「BaserCMS利用のサイト」に業者が「検索システム」作っていますのであるはずなんですが。タダじゃだめ?。


適当にいじくると出来るものなのですね、効率、良いか悪いかなどは別としてです、、。これはプラグインではありませんので、訂正箇所などは詳しくメモして置きましょう。忘れたらあとで大変なことになりますよ。


次ページでは実際にセレクターを配置して簡単なテストをして見ましょう。TEST: BaserCMSブログに機能を付加する/6


以上です。



[ この記事のURL ]


タグ:series , basercms , php

[ BaserCMSブログに機能を付加する シリーズ記事 ]

BaserCMSブログに機能を付加する/62012.02.10
BaserCMSブログに機能を付加する/52012.02.08
BaserCMSブログに機能を付加する/42012.02.07
BaserCMSブログに機能を付加する/32012.02.06
BaserCMSブログに機能を付加する/22012.02.05
BaserCMSブログに機能を付加する/12012.02.04

 

ブログ記事一覧



[1]