cakephp1.2 Shellからモデルとコンポーネントを呼ぶ方法
コントローラーであれば$usesと$componentsを使うけど、Shellの場合は$usesは使えるけど$componentsは使えない、というなんとも中途半端な感じだったのでメモ。以下のようにする。
<?php App::import('Component', 'Sample'); class TestShell extends Shell { var $uses = array('Hoge'); function initialize() { parent::initialize(); $this->Sample = new SampleComponent($this); } }
資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html
mysql group_concatにorder byを指定する時の注意事項
group_concatにorder byを指定しても意図したソートにならないケースがある。
まず以下のように、group_concatに指定したcategory_idをそのカラム順でソートするケースの場合は問題ない。
group_concat(category_id order by category_id)
問題となるのは以下のようなgroup_concatの対象(category_name)とソートの基準となるカラム(category_id)が異なるケース。この場合、category_nameがcategory_id順に並ばない場合がある。
group_concat(category_name order by category_id)
これを防ぐには【group by-group_concatする前に、データをorder byでソートしておく】ことが必要。なので一つのSQLではできない(はず)ため、サブクエリ等を使う必要がある。
select group_concat(category_name order by category_id) from ( select item_id,category_id,category_name from item i inner join item_category ic on i.id = ic.item_id inner join category c on i.id = ic.category_id order by category_id ) as tmp_tb group by item_id
資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html
php csrf対策
参考サイト
PHPでクロスサイトリクエストフォージェリ(CSRF)対策するときのメモ - Qiita
<?php //トークンをセッションにセット function setToken(){ $token = sha1(uniqid(mt_rand(), true)); $_SESSION['token'] = $token; } //トークンをセッションから取得 function checkToken(){ //セッションが空か生成したトークンと異なるトークンでPOSTされたときは不正アクセス if(empty($_SESSIOIN['token']) || ($_SESSION['token'] != $_POST['token'])){ echo '不正なPOSTが行われました', PHP_EOL; exit; } } //GETでアクセスされたとき if($_SERVER['REQUEST_METHOD'] != 'POST'){ setToken(); } //POSTでアクセスされたとき else{ checkToken(); }
html
<form method="post" action=""> ... <!--hiddenで生成したワンタイムトークンの文字列をPOST送信--> <input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"> <input type="submit" value="登録"> ... </form>
post時にtokenをポストする必要がある
cakephp1.2 componentの$enabledでNoticeが出る件
本来componentを使うと$enabledがセットされるんだけど、beforeFilter()の中でcomponentをnewしてしまうと、$enabledが定義される前にstarup()とかを呼んでしまい、Noticeが出るのでcomponentをbeforeFilter()の中でnewしないこと。
$enabledはcomponentのstartupやらのcallbackを実行するかどうかのフラグ。falseにするとそれらが実行されない。
追記
アホだった。controllerであれば「var $components」でcomponent設定するからcomponentをnewする必要ないの忘れてた。バッチと完全にごっちゃになっていた。注意すること。
mysql テーブル設計 カンマ区切りのカラムについて考察
例えば商品の属性とかレコードに紐づくデータが沢山あってレコード毎にデータ作ると色々面倒なケース。
DB設計の基本について 例えば一つのレコードが複数のカテゴリに… - 人力検索はてな
MySQLでカンマ区切りの値を登録してみる | シスデイズ技術ブログ
まさにこういうケース。基本はやはり忠実に正規化するのがベターらしいが、場合によってはカンマ区切りにするのもあり。ただカンマ区切りにしてしまうとjoinが面倒になるぽい。柔軟なのはやはり正しく正規化する方なんだと思う。
正規化した場合の問題について
まず正規化した場合、上の例でいうとAカテゴリとBカテゴリに属するレコードを取得する(AのみBのみは除く)となった場合、一番シンプルなのがgroup_concatでカンマ区切りにした結果に対してfind_in_setで絞り込む方法では無いかと思う。
しかし他のテーブルと結合したいと(group_concatでgroup byしてさらにの他のテーブルのカラムでgroup byしたい場合等)なった場合、いったんgroup_concatして、その結果を副問合せとかで結合、という手順を踏まないといけなくなるため、最初からカンマ区切りのデータであればその辺がシンプルになるはず。
データが膨大な場合は、「いったんgroup_concatして」すら出来なくなると思うので、最初からカンマ区切りならそのまま別テーブルと結合して、別テーブルの条件で絞り込んだデータに対してfind_in_setをすれば良い訳だから、データ量によってはパフォーマンスが圧倒的に変わると思う。
とはいえjoinが出来ない(面倒な)のも痛いしな~、両方用意して使い分けるのもありかもしれんけどな。片方更新したらもう片方も更新しないといけないから、その辺は覚悟せなあかんくなる。
全ての要件を満たす方法が無いとなると、後は何を優先させるかだな。パフォーマンスなのか開発工数なのか保守性なのか。ただ絶対に守らないといけないことが1つあって、それは「シンプルである」ということ。これだけは絶対に外してはいけない。
よく考えた結果、テーブル結合が発生する場合は副問合せはどうしても必要になるけど、サブクエリにするタイミングをずらすことで正規化でもパフォーマンス落とさずにできるかも。もうちょっと検証してみる。
結論
自分のSQLがダメだっただけで、やっぱり正規化でパフォーマンス落とさずに対応することができた。なので正規化のデメリットはデータ数が増えることくらいではないかな。でもそれはシステム化すれば大した問題ではない。なのでカンマ区切りにはやっぱりしないこと。
資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html
cakephp1.2 database.phpのdefaultに設定されているDBのテーブルはModelファイルの作成が必須ではない
ClassRegistry::init('ModelName');
こんな感じでmodelsフォルダに存在しないModelを読み込んでいた場合に、何故かエラーになる場合とならない場合があって1時間くらいはまってしまったのでメモ。
どうやらdatabase.phpで$defaultに設定されたDBのテーブルだとModelファイルが無くてもエラーにならないっぽい。(もちろん実際のテーブルが存在しなかったらエラーになるが。)
defaultのDBであればModelファイルが無くともfindとかも普通に使える。
今までModelファイルが必須だと思い込んでいたのでもう二度と忘れないこと。
php sqlのIN句をarray_fillでキレイにまとめる
以下のようにすれば一行で$idの数だけ?を記述するin句が作れる
i.id in ('. implode(',', array_fill(0, count($id), '?')). ')
str_repeatを使う方法もあるようだけどこっちの方がキレイ