symfony1.4+Doctrineで配列をカンマ区切りで保存する
最近チェックボックスの項目が大量あるフォームを実装していて、綺麗に正規化して実装するのも大変だなーと思って、valueを「,」区切りで文字列保存することにしたのでメモ。
valueに「,」が入る可能性などは考えてないのであくまでもシンプルに。
config/doctrine/scheme.yml
schemeの定義例は以下。interestに「,」区切りで保存する。
Question: columns: name: string(255) interest: string(255)
config/ProjectConfiguration.class.php
sfDoctrineRecordを継承して、myDoctrineRecordを定義するのでそちらをmodel生成で読み込むように。
<?php require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php'; sfCoreAutoload::register(); class ProjectConfiguration extends sfProjectConfiguration { public function setup() { $this->enablePlugins('sfDoctrinePlugin'); } public function configureDoctrine(Doctrine_Manager $manager) { sfConfig::set('doctrine_model_builder_options', array( 'baseClassName' => 'myDoctrineRecord', )); } }
lib/doctrine/myDoctrineRecord.class.php
implode, explodeするメソッドを定義。
<?php class myDoctrineRecord extends sfDoctrineRecord { protected function _getExplode($key, $separator = ',', $load = true) { $value = $this->_get($key, $load); if ($value === '' || $value === null) { return array(); } return array_map('trim', explode($separator, $value)); } protected function _setImplode($key, $value, $separator = ',', $load = true) { if (is_array($value)) { $this->_set($key, implode($separator, array_map('trim', $value)), $load); } else { $this->_set($key, '', $load); } } }
コマンドラインでモデルとCRUD画面生成
$ symfony doctrine:build --all $ symfony doctrine:generate-module frontend question question
lib/model/doctrine/Question.class.php
interestのgetter,setterは前述のmethodを通すようにする。
<?php class Question extends BaseQuestion { public function getInterest() { return $this->_getExplode('interest'); } public function setInterest($value) { $this->_setImplode('interest', $value); } }
lib/model/doctrine/QuestionTable.class.php
interestの定義
<?php class QuestionTable extends Doctrine_Table { protected static $interests = array( '1' => 'Music', '2' => 'Sports', '3' => 'Programming', ); public static function getInterests() { return self::$interests; } public static function getInstance() { return Doctrine_Core::getTable('Question'); } }
lib/form/doctrine/QuestionForm.class.php
intersetのwidget,validatorをQuestionTable::getInterests()にする。
<?php class QuestionForm extends BaseQuestionForm { public function configure() { $intersets = QuestionTable::getInterests(); $this->setWidget('interest', new sfWidgetFormChoice(array( 'choices' => $intersets, 'multiple' => true, 'expanded' => true, ))); $this->setValidator('interest', new sfValidatorChoice(array( 'choices' => array_keys($intersets), 'multiple' => true, ))); } }
getter,setterをオーバライドしているので、form側で特に意識することなくデフォルト値のセット、データの保存ができて便利かなと思っています。
他のプロジェクトでも使えそうな気がするので、scheme.ymlに書いたら自動的にやってくれるようにDoctrineのBehaviorにしてみたい。