この記事を三行にまとめると
空の値が返って来てしまいます何とかする方法って、ないんですかね?
時代遅れってことなんでしょうか……
データをPOSTする際、配列をシリアライズしてVARCHAR型とかTEXT型のデータをDBに突っ込みたいってとき。
newentity()だけじゃなくて、patchentity()のときも同様なのですが、エンティティを生成するとき、データを配列で飛ばすと、空の値が返って来てしまいます。
例えば、こんな場合を想定してみる。
postsテーブルにtagというカラムがあって、その中に、3つのタグをベタ書きで入れようとしてる感じです。普通はこういうとき、タグテーブルを別に作ってidを入れるようにした方が良いですが、今回は説明し易いようにってことで。
今ここで「ブログ、CakePHP3、あかつき」というタグを入力したとしたら、POSTされるデータは、以下のようになりますね。
このデータをVARCHAR型やTEXT型のフィールドに突っ込もうと思っても、配列のままでは登録できないので、シリアライズしてから登録するってのが、基本的なやり方になると思います。もちろん、serialize()の代わりにjson_encode()を使っても良いし、シリアライズをするのではなくて、implode()を使って、コンマ区切りとかにしても良いです。要は配列を一つの文字列データにするってことですね。
一見、問題はなさそうに見えます。
……が、実は上記のコードそのままだと、上手くデータが入りません。
何でかってーと、実際やってみりゃ分かるんですが、newentity()でエンティティを生成すると、$post->tagには、空の値が入ってしまいます。
どうやらCakePHP3の仕様で、フィールドの型がVARCHAR型だったりTEXT型の場合、配列のデータが飛んできたら、エンティティ生成時に空の値を返すようになっているようです。コアライブラリのDatabaseってフォルダの中に「Type.php」というファイルがあるんですが、その中を見れば分かります。
Type.phpを見ると、VARCHARやTEXTだけではなく、他の型に関しても、ある程度それぞれの型にあったデータかどうか判定して、弾くような仕組みになっているみたいですね。たとえばINT型だったら数字とか。ちなみにINT型のカラムに配列データをPOSTした場合、エンティティ生成時に1が返るみたいです。
で、ここからは半分相談みたいな感じになるんですが、これを何とかする方法って、ないんですかね?
今のところ僕の中では、エンティティ生成前にシリアライズしてしまうか、そもそもそういう仕様を避けるかのどっちかって結論になってるんですけど……あとは苦肉の策として、Type.phpを改造してしまうか。推奨はできないっすけど。
でもエンティティ生成前にシリアライズしてしまうと、notEmptyのバリデーションとかしたい時に、シリアライズしたものをもう一度配列に戻して判定……みたいなことしなきゃいけないんで、何か二度手間な感じしますよね。空の値をシリアライズすると、シリアライズ後のデータはempty()じゃ判定できなくなるし。
どうして配列を受けつけない仕様になったんですかね? Cakeさん的には、シリアライズしたデータを入れること自体、推奨はできないってことなんでしょうか?
俺、ちょっとデータの入れ方に困ると、シリアライズすれば良いじゃんってすぐに思っちゃうんですけど、そういう考え方は時代遅れってことなんでしょうか……。
その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め
newentity()だけじゃなくて、patchentity()のときも同様なのですが、エンティティを生成するとき、データを配列で飛ばすと、空の値が返って来てしまいます。
例えば、こんな場合を想定してみる。
//テンプレート
<?= $this->Form->create('Post') ?>
<?= $this->Form->text('Post.tag.0') ?>
<?= $this->Form->text('Post.tag.1') ?>
<?= $this->Form->text('Post.tag.2') ?>
<?= $this->Form->end() ?>
//コントローラー
$post = $this->Posts->newEntity($this->request->data['Post']);
if(!$post->errors()) {
//タグデータをシリアライズ
$post->tag = serialize($post->tag);
$this->Posts->save($post);
}
postsテーブルにtagというカラムがあって、その中に、3つのタグをベタ書きで入れようとしてる感じです。普通はこういうとき、タグテーブルを別に作ってidを入れるようにした方が良いですが、今回は説明し易いようにってことで。
今ここで「ブログ、CakePHP3、あかつき」というタグを入力したとしたら、POSTされるデータは、以下のようになりますね。
array(
[tag] => array(
[0] => ブログ
[1] => CakePHP3
[2] => あかつき
)
)
このデータをVARCHAR型やTEXT型のフィールドに突っ込もうと思っても、配列のままでは登録できないので、シリアライズしてから登録するってのが、基本的なやり方になると思います。もちろん、serialize()の代わりにjson_encode()を使っても良いし、シリアライズをするのではなくて、implode()を使って、コンマ区切りとかにしても良いです。要は配列を一つの文字列データにするってことですね。
一見、問題はなさそうに見えます。
……が、実は上記のコードそのままだと、上手くデータが入りません。
何でかってーと、実際やってみりゃ分かるんですが、newentity()でエンティティを生成すると、$post->tagには、空の値が入ってしまいます。
どうやらCakePHP3の仕様で、フィールドの型がVARCHAR型だったりTEXT型の場合、配列のデータが飛んできたら、エンティティ生成時に空の値を返すようになっているようです。コアライブラリのDatabaseってフォルダの中に「Type.php」というファイルがあるんですが、その中を見れば分かります。
Type.phpを見ると、VARCHARやTEXTだけではなく、他の型に関しても、ある程度それぞれの型にあったデータかどうか判定して、弾くような仕組みになっているみたいですね。たとえばINT型だったら数字とか。ちなみにINT型のカラムに配列データをPOSTした場合、エンティティ生成時に1が返るみたいです。
で、ここからは半分相談みたいな感じになるんですが、これを何とかする方法って、ないんですかね?
今のところ僕の中では、エンティティ生成前にシリアライズしてしまうか、そもそもそういう仕様を避けるかのどっちかって結論になってるんですけど……あとは苦肉の策として、Type.phpを改造してしまうか。推奨はできないっすけど。
でもエンティティ生成前にシリアライズしてしまうと、notEmptyのバリデーションとかしたい時に、シリアライズしたものをもう一度配列に戻して判定……みたいなことしなきゃいけないんで、何か二度手間な感じしますよね。空の値をシリアライズすると、シリアライズ後のデータはempty()じゃ判定できなくなるし。
どうして配列を受けつけない仕様になったんですかね? Cakeさん的には、シリアライズしたデータを入れること自体、推奨はできないってことなんでしょうか?
俺、ちょっとデータの入れ方に困ると、シリアライズすれば良いじゃんってすぐに思っちゃうんですけど、そういう考え方は時代遅れってことなんでしょうか……。
その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め