time 2017/10/17
前回の記事、『CakePHP サニタイズでエスケープされた改行コードを元に戻す簡単なコンポーネントを作ってみる』で簡単なコンポーネントを作成したのですが、色々考えた結果「データの加工などの処理はモデルで行うべきだ」との考えに至ったので、前回作成したコンポーネントと同じ処理をするビヘイビアを作成してみたいと思います。
作成するビヘイビアのメソッドとしては、『サニタイズでエスケープされた改行コードを元に戻す』『HTMLエンティティを特殊文字に置き換える』です。
ビヘイビアは、『ModelBehavior』クラスを継承して作成します。
▼『ModelBehavior』クラスを継承
class HtmlDecodeBehavior extends ModelBehavior {
public $name = 'HtmlDecode';
}
CakePHPの命名規則に則り、『/app/models/behaviors』に保存します。
ビヘイビアの準備ができたので、メソッドを追加していきます。
コンポーネントの作成との違いは、モデルから呼び出せるメソッドの『第1引数がモデルの参照になる』ことです。
private宣言やprotected宣言のメソッドは『第1引数がモデルの参照になる』ことはありません。
▼作成したビヘイビアにメソッドを追加
class HtmlDecodeBehavior extends ModelBehavior {
public $name = 'HtmlDecode';
// 置き換え対象のHTMLエンティティ
protected $_patterns = array(
'before' => array(
"/¥&/", // 『&』
"/¥</", // 『<』
"/¥>/", // 『>』
"/¥"/", // 『'』
"/¥'/", // 『"』
),
'after' => array(
"&", // 『&』
"<", // 『<』
">", // 『>』
"'", // 『"』
'"', // 『'』
)
);
/**
* HTMLエンティティを特殊文字に置き換える
*
* @param string or array $data HTMLエンティティを特殊文字に置き換えたい配列、または文字列
* @param pool $script 置き換え後の特殊文字がScriptタグになった場合、削除するなら『true』を指定
* @param pool $space 置き換え後の文字列からスペースを削除するなら『true』を指定
*
* @return string or array 処理後、引数に指定された形式で返す。
*/
public function htmlCheck(&$model, $data, $script = true, $image = true, $space = true) {
if(is_array($data)) {
$cnvData = array();
foreach($data as $key => $item) {
if(isset($item)) {
// 特殊文字へ置き換え
$cnvData[$key] = $this->_htmlDecode($item);
// スクリプトタグの削除
if($script) $cnvData[$key] = Sanitize::stripScripts($cnvData[$key]);
// 画像の削除
if($image) $cnvData[$key] = Sanitize::stripImages($cnvData[$key]);
// スペースの削除
if($space) $cnvData[$key] = Sanitize::stripWhitespace($cnvData[$key]);
}
}
} else {
if(isset($data)) {
// 特殊文字へ置き換え
$cnvData = $this->_htmlDecode($data);
// スクリプトタグの削除
if($script) $cnvData = Sanitize::stripScripts($cnvData);
// 画像の削除
if($image) $cnvData = Sanitize::stripImages($cnvData);
// スペースの削除
if($space) $cnvData = Sanitize::stripWhitespace($cnvData);
}
}
return $cnvData;
}
/**
* 配列、または文字列に含まれる『///n』を『/n』に置き換える
*
* @param string or array $data 『///n』を『/n』に置き換えたい配列、または文字列
* @param pool $conversion 置き換え後の『/n』を『
』タグに変更する場合、trueを指定
*
* @return string or array 処理後、引数に指定された形式で返す。
*
*/
public function nlCheck(&$model, $data, $conversion = false) {
if(is_array($data)) {
$cnvData = array();
foreach($data as $key => $item) {
if(isset($item)) {
// 『/n』へ置き換え
$cnvData[$key] = $this->_nlDecode($item);
// 『
』へ置き換え
if($conversion) $cnvData[$key] = nl2br($cnvData[$key]);
}
}
} else {
if(isset($data)) {
// 『/n』へ置き換え
$cnvData = $this->_nlDecode($data);
// 『
』へ置き換え
if($conversion) $cnvData = nl2br($cnvData);
}
}
return $cnvData;
}
/**
* HTMLエンティティを特殊文字に置き換える
*
* @param string $data 置き換えたい文字列
*
* @return string 置き換え後の文字列
*/
protected function _htmlDecode($data) {
return preg_replace($this->_patterns['before'], $this->_patterns['after'], $data);
}
/**
* 『///n』を『/n』に置き換える
*
* @param string $data 置き換えたい文字列
*
* @return string 置き換え後の文字列
*/
protected function _nlDecode($data) {
return preg_replace('/\\\n/', "\n", $data);
}
}
内容は、前回作成したコンポーネントと同じで、『preg_replace』関数を使用し文字を置き換えていくだけです。
後は、モデルから作成したビヘイビアを読み込み処理をしていきます。
ビヘイビアを読み込む場合は、メンバ変数『$actsAs』に使用したいビヘイビア名を指定します。
注意しなければならないのが、ビヘイビア側の第1引数はモデルの参照になっていますが、モデル側では第1引数を省略し第2引数から指定していくことです。
また、コンポーネントの『$this->コンポーネント名->コンポーネントのメソッド名』とは違い、『$this->ビヘイビアのメソッド名』となります。
class HtmlDecodeBehavior extends ModelBehavior {
public function nlCheck(&$model, $data, $conversion = false) {
/*
* 処理は省略します
*/
}
}
class Post extends AppModel {
public $name = 'Post';
public $actsAs = 'HtmlDecode';
public function find($type, $options = array()) {
/*
* 処理は省略します
*/
$data = $this->nlCheck($data, true);
}
このことに注意しながら、実装していきます。
▼モデル
class Post extends AppModel {
public $name = 'Post';
public $actsAs = 'HtmlDecode';
public function find($type, $options = array()) {
switch($type) {
case 'show':
// データの取得
$data = parent::find('first', $options);
$data['Post'] = $this->nlCheck($data['Post'], true);
return $data;
break;
default:
return parent::find($type, $options);
break;
}
}
}
▼コントローラー
class PostsController extends AppController {
public $name = 'Posts';
public $users = array('Post');
public function show($id = null) {
if (!$id) $this->referer($this->referer());
// データの取得
$post = $this->Post->find('show', array('conditions' => array('Post.id = ?' => $id)));
$this->set('post', $post);
}
}
これでビヘイビアの作成は終了です。
いくつか注意点はありますが、基本的には簡単に作成することができました。