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を使う方法もあるようだけどこっちの方がキレイ

cakephp1.2 通常のSQLとO/Rマッパーとのselectの結果の違い

今更だけどメモ。cakephpでO/Rマッパーというかfindとかした時の結果と、通常のsql(query)を実行した時の結果の違いについて。

通常のsqlを使用した場合
sql

$sql =<<<SQL
select * from users u
inner join posts p on p.user_id = u.id
where u.id=1
SQL;
pr($this->User->query($sql));

結果

Array
(
    [0] => Array
        (
            [u] => Array
                (
                    [id] => 1
                    [user_name] => ユーザー1
                )

            [p] => Array
                (
                    [id] => 1
                    [post_date] => 2016-11-19
                )
        )

    [1] => Array
        (
            [u] => Array
                (
                    [id] => 1
                    [user_name] => ユーザー1
                )

            [p] => Array
                (
                    [id] => 2
                    [post_date] => 2016-11-20
                )
        )
)

O/Rマッパーを使用した場合
sql

$this->User->bindModel(array('hasMany'=>array('Post')));
pr($this->User->findById(1));

結果

Array
(
    [User] => Array
        (
            [id] => 1
            [user_name] => ユーザー1
        )

    [Post] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [post_date] => 2016-11-19
                )

            [1] => Array
                (
                    [id] => 2
                    [post_date] => 2016-11-20
                )
        )
)

こんな感じでO/Rマッパーを使うと、重複しているUserデータが統合されることで結果がスマートになるという違いがある。

ただ通常のSQLの場合でもGROUP_CONCATとか使えば重複を省くことが可能。

資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html

mysql group_concatとfind_in_setのまとめ

group_concatはgroup byで複数行をまとめた際に、まとめられた列のデータをカンマ区切りで表示する機能。

find_in_setはカンマ区切りのデータを絞り込む機能。

この2つを組み合わせることで、本来なら副問合せ等の複数のSQLに分けないと出来ないようなことが一つのSQLで完結できることが分かった。

ただ速度的なメリットがあるのかどうかは不明。

参考ページの例を使うと以下のようなsqlでmarketとsalesに所属するempを一発で取得できる。

select dept_emp.empid, emp.name, GROUP_CONCAT(dept.name order by dept.id) as dept_n
from dept_emp left join emp on dept_emp.empid=emp.id
left join dept on dept_emp.deptid=dept.id
group by dept_emp.empid
having find_in_set('market', dept_n) and find_in_set('sales', dept_n);

結果

+-------+-------+------------------+
| empid | name  | dept_n           |
+-------+-------+------------------+
|     3 | smith | market,hrm,sales |
+-------+-------+------------------+
1 row in set (0.00 sec)

参考ページ
GROUP_CONCAT関数の便利さは異常 - 開発の風景 〜KKZのSE日記〜
MySQL :: find_in_set() 関数 [Tipsというかメモ]
商品とそれに紐付けされた複数のカテゴリ情報を一つのSQLで取得する - Qiita

bootstrap ハンバーガーメニューを常に表示する方法

bootstrapのハンバーガーメニューをどのサイズでも常に表示させたい場合

Customize and download · Bootstrap
@grid-float-breakpoint
=> 9999pxとか大きい値にする

※9999とか気持ち悪いんだけど他に方法が無さそうだったので仕方なくこうする