<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>digital matter</title>
	<atom:link href="http://blog.loadlimits.info/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.loadlimits.info</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 22 Jun 2010 10:46:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Symfonyで外部のプログラムを実行する</title>
		<link>http://blog.loadlimits.info/2010/06/symfony%e3%81%a7%e5%a4%96%e9%83%a8%e3%81%ae%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%a0%e3%82%92%e5%ae%9f%e8%a1%8c%e3%81%99%e3%82%8b/</link>
		<comments>http://blog.loadlimits.info/2010/06/symfony%e3%81%a7%e5%a4%96%e9%83%a8%e3%81%ae%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%a0%e3%82%92%e5%ae%9f%e8%a1%8c%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Tue, 22 Jun 2010 10:46:39 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/symfony%e3%81%a7%e5%a4%96%e9%83%a8%e3%81%ae%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%a0%e3%82%92%e5%ae%9f%e8%a1%8c%e3%81%99%e3%82%8b/</guid>
		<description><![CDATA[Symfony 1.4でシェルのプログラムを呼び出すときに、PHPのexec関数に代わる便利なメソッドがあったのでメモ。 
sfFilesystem::execute()がそれです。   symfony API » sfFilesystem Class &#124; symfony &#124; Web PHP Framework
内部的にはproc_openで   戻り値は、標準出力と標準エラー出力が分離されて配列で返ってきます。 
タスクから、呼び出すとこんな感じになります。

    protected
        $outputBuffer = '';

    protected function execute($arguments = array(), $options = array())
    {
       [...]]]></description>
			<content:encoded><![CDATA[<p>Symfony 1.4でシェルのプログラムを呼び出すときに、PHPのexec関数に代わる便利なメソッドがあったのでメモ。 </p>
<p>sfFilesystem::execute()がそれです。   <br /><a href="http://www.symfony-project.org/api/1_4/sfFilesystem" target="_blank">symfony API » sfFilesystem Class | symfony | Web PHP Framework</a></p>
<p>内部的にはproc_openで   <br />戻り値は、標準出力と標準エラー出力が分離されて配列で返ってきます。 </p>
<p>タスクから、呼び出すとこんな感じになります。</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>    protected
        $outputBuffer = '';

    protected function execute($arguments = array(), $options = array())
    {
        // initialize the database connection
        $databaseManager = new sfDatabaseManager($this-&gt;configuration);
        $connection = $databaseManager-&gt;getDatabase($options['connection'] ? $options['connection'] : null)-&gt;getConnection();

        // 処理待ちリストから一行取得
        $process = Doctrine::getTable('Processes')-&gt;findOneByStatus('WAIT');
        $command = $process['command'];

        // バッファクリア
        $this-&gt;outputBuffer = '';
        try {
            // 実行。第二引数は標準出力、第三引数は標準エラー出力を受け取るコールバック関数
            list($output, $err) = $this-&gt;getFilesystem()-&gt;execute($command, array($this, 'setBuffer'), array($this, 'setBuffer'));
            $process['status'] = 'SUCCESS';
            $process['message'] = $output;
            $process-&gt;save();
        } catch (RuntimeException $e) {
            // コマンドが実行できなかった場合と、終了時エラーの場合はRuntimeExceptionがthrowされる
            $process['status'] = 'FAILED';
            // エラー時はexecuteの戻り値を取得できないのでコールバックの結果からメッセージを取得
            $process['message'] = $this-&gt;outputBuffer;
            // 必要なら$e-&gt;getCode();でエラーコード取得できます
            $process-&gt;save();
        }
    }

    public function setBuffer($output)
    {
        $this-&gt;outputBuffer .= $output;
    }
</pre>
</div>
<p>/vendor/pear/php/symfony/task/project/sfProjectDeployTask.class.phpがサンプルとして使えます。 </p>
<p>もちろん、PHPのexec関数を使って<br />
  <br />exec($command, $output = array(), $return_var = 0);</p>
<p>とかしてもいいと思います。 </p>
<p>多分プラグインのインストール段階でmakeとかするときに使うんじゃないですかね。<br />
  <br />標準出力を段階的に画面に表示できるので。 </p>
<p>ただし、出力バッファの読み取り単位ごとに、0.1秒のディレイをかけているようなので、速度重視なところでは注意が必要です。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/symfony%e3%81%a7%e5%a4%96%e9%83%a8%e3%81%ae%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%a0%e3%82%92%e5%ae%9f%e8%a1%8c%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfonyのクライアントサイドバリデータ</title>
		<link>http://blog.loadlimits.info/2010/06/symfony%e3%81%ae%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%83%90%e3%83%aa%e3%83%87%e3%83%bc%e3%82%bf/</link>
		<comments>http://blog.loadlimits.info/2010/06/symfony%e3%81%ae%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%83%90%e3%83%aa%e3%83%87%e3%83%bc%e3%82%bf/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 14:13:45 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/symfony%e3%81%ae%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%83%90%e3%83%aa%e3%83%87%e3%83%bc%e3%82%bf/</guid>
		<description><![CDATA[SymfonyでjQueryを使ったクライアントサイドのバリデーションを簡単に実現できるjnAjaxFormValitatorというプラグインがあったので、試してみました。
このプラグインはフォームが変更された際に、Ajaxでサーバにバリデーションルールと値を送ってサーバサイドでバリデーションをかけ、その結果を表示します。
結論から言うと、簡単に導入できて便利ですが、一部セキュリティ的に難あり、
1.2用ですが、ちょっとの修正で1.4でも使えます。
まずはダウンロード。
Plugins &#124; jnAjaxFormValidatorPlugin &#124; 1.0.2 &#124; symfony &#124; Web PHP Framework
 
ダウンロードしなくてもサーバから直接インストールできるらしいのですが、今回はtgzファイルをダウンロードしてきてインストールしました。
$ ./symfony plugin:install ./jnAjaxFormValidatorPlugin-1.0.2.tgz   &#62;&#62; plugin&#160;&#160;&#160; installing plugin &#34;./jnAjaxFormValidatorPlugin-1.0.2.tgz&#34;    &#62;&#62; sfSymfonyPluginManager Installation successful for plugin &#34;./jnAjaxFormValidatorPlugin-1.0.2.tgz&#34;
インストール成功したら、アプリケーション以下のconfig/setting.ymlを開いてモジュールを有効にする設定を書きます。
all:   &#160; .settings:    &#160;&#160;&#160; enabled_modules:&#160;&#160;&#160;&#160;&#160;&#160;&#160; [default, jnAjaxFormValidator]
READMEは全部スペルミスでjnAjaxFormValitatorになっているのでコピペすると間違えます。
次はアプリケーション以下のconfig/routing.ymlに以下を追加します。
 # &#8212;&#8211; jnAjaxFormValidator &#8212;&#8211;  jnAjaxFormValidator_validateJSON:  &#160; url:&#160;&#160; /jnAjaxFormValidator/validateJSON  &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>SymfonyでjQueryを使ったクライアントサイドのバリデーションを簡単に実現できる<a href="http://www.symfony-project.org/plugins/jnAjaxFormValidatorPlugin" target="_blank">jnAjaxFormValitator</a>というプラグインがあったので、試してみました。</p>
<p>このプラグインはフォームが変更された際に、Ajaxでサーバにバリデーションルールと値を送ってサーバサイドでバリデーションをかけ、その結果を表示します。</p>
<p>結論から言うと、簡単に導入できて便利ですが、一部セキュリティ的に難あり、</p>
<p>1.2用ですが、ちょっとの修正で1.4でも使えます。</p>
<p>まずはダウンロード。</p>
<p><a href="http://www.symfony-project.org/plugins/jnAjaxFormValidatorPlugin" target="_blank">Plugins | jnAjaxFormValidatorPlugin | 1.0.2 | symfony | Web PHP Framework</a></p>
<p><a href="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617223542.png"><img style="border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px" border="0" alt="20100617223542" src="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617223542_thumb.png" width="496" height="313" /></a> </p>
<p>ダウンロードしなくてもサーバから直接インストールできるらしいのですが、今回はtgzファイルをダウンロードしてきてインストールしました。</p>
<p>$ ./symfony plugin:install ./jnAjaxFormValidatorPlugin-1.0.2.tgz   <br />&gt;&gt; plugin&#160;&#160;&#160; installing plugin &quot;./jnAjaxFormValidatorPlugin-1.0.2.tgz&quot;    <br />&gt;&gt; sfSymfonyPluginManager Installation successful for plugin &quot;./jnAjaxFormValidatorPlugin-1.0.2.tgz&quot;</p>
<p>インストール成功したら、アプリケーション以下のconfig/setting.ymlを開いてモジュールを有効にする設定を書きます。</p>
<p>all:   <br />&#160; .settings:    <br />&#160;&#160;&#160; enabled_modules:&#160;&#160;&#160;&#160;&#160;&#160;&#160; [default, jnAjaxFormValidator]</p>
<p>READMEは全部スペルミスでjnAjaxFormVali<strong>t</strong>atorになっているのでコピペすると間違えます。</p>
<p>次はアプリケーション以下のconfig/routing.ymlに以下を追加します。</p>
<p> # &#8212;&#8211; jnAjaxFormValidator &#8212;&#8211;  <br />jnAjaxFormValidator_validateJSON:  <br />&#160; url:&#160;&#160; /jnAjaxFormValidator/validateJSON  <br />&#160; param: { module: jnAjaxFormValidator, action: validateJSON }  <br /> 
<p>その後、キャッシュをクリアします。</p>
<p>$ ./symfony cc</p>
<p>バリデーションを使用するテンプレートの先頭にでも、</p>
<p> &lt;?php use_helper(&#8216;ajaxFormValidator&#8217;) ?&gt;  <br />&lt;?php echo ajaxAllFieldsValidators($form) ?&gt;  <br /> 
<p>と書いておけばOKです。</p>
<p>インストール手順はこれで完了ですが、このままだとSymfony 1.4で動かないので、actions.class.phpを修正します。</p>
<p>/plugins/jnAjaxFormValidatorPlugin/modules/jnAjaxFormValidator/actions/actions.class.php 29行目   <br />sfLoader::loadHelpers(&#8216;I18N&#8217;);    <br />↓    <br />sfContext::getInstance()-&gt;getConfiguration()-&gt;loadHelpers(array(&#8216;I18N&#8217;));</p>
<p>以上で完了です。</p>
<p><a href="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617225540.png"><img style="border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px" border="0" alt="20100617225540" src="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617225540_thumb.png" width="439" height="176" /></a> </p>
<p>あと、書き出されるエラーが   <br />&lt;ul class=&quot;error_list&quot;&gt;&lt;li&gt;エラーメッセージ&lt;/li&gt;&lt;/ul&gt;    <br />の構造に固定されているので、必要であればヘルパー側を修正する必要があります。</p>
<p>難点は、バリデーションのルールをブラウザ側に一度保持することです。単純にバリデータクラス名とバリデーションルール、値をJSからサーバに送信してバリデータを実行しているだけなので。</p>
<p><a href="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617225648.png"><img style="border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px" border="0" alt="20100617225648" src="http://blog.loadlimits.info/wp-content/uploads/2010/06/20100617225648_thumb.png" width="463" height="165" /></a></p>
<p>上の図はリクエスト時のパラメータです。GETで送られます。何が問題かというと、サーバ内のバリデーションルールが表に流れるので、攻撃者が穴を見つけやすくなるということですね。</p>
</p>
<p>バリデーションは完璧で、特にクリティカルな要件でないなら使えると思います。</p>
<p>あと、返されるエラーメッセージはformで定義したものを使えないので、デフォルトのエラーメッセージになります。</p>
<p>デフォルトのエラーメッセージは、アプリケーションのConfigurationなどで</p>
<p>sfValidatorBase::setDefaultMessage(&#8216;max_length&#8217;, &#8216;%max_length%文字までにしてください&#8217;);</p>
<p>などとしておくか、カタログファイルでも変更できます。</p>
<p>ちなみにソースコードはびっくりするくらいシンプル。チェコ人が作ったらしく、I18Nも意識されてます。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/symfony%e3%81%ae%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%82%b5%e3%82%a4%e3%83%89%e3%83%90%e3%83%aa%e3%83%87%e3%83%bc%e3%82%bf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfWidgetFormInputCheckboxの正負を反転させる その２</title>
		<link>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%92/</link>
		<comments>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%92/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 09:53:54 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%92/</guid>
		<description><![CDATA[前回のエントリで、モデルを拡張して読み出し時と保存時に正負反転させる方法を紹介しましたが、カラム名と実際の動作が逆になってしまって紛らわしいので、widgetとvalidatorで反転させることにしました。Symfony 1.4+Doctrineです。
既存のsfWidgetFormInputCheckboxとsfValidatorBooleanを継承して実装します。
lib/widget/sfWidgetFormInputCheckboxInverse.class.php

&#60;?php

class sfWidgetFormInputCheckboxInverse extends sfWidgetFormInputCheckbox
{
    public function render($name, $value = null, $attributes = array(), $errors = array())
    {

        if (!(null !== $value &#38;&#38; $value !== false))
        {
         [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%E3%81%AE%E6%AD%A3%E8%B2%A0%E3%82%92%E5%8F%8D%E8%BB%A2%E3%81%95%E3%81%9B%E3%82%8B-%E3%81%9D%E3%81%AE%EF%BC%91/" target="_blank">前回のエントリ</a>で、モデルを拡張して読み出し時と保存時に正負反転させる方法を紹介しましたが、カラム名と実際の動作が逆になってしまって紛らわしいので、widgetとvalidatorで反転させることにしました。Symfony 1.4+Doctrineです。</p>
<p>既存のsfWidgetFormInputCheckboxとsfValidatorBooleanを継承して実装します。</p>
<p>lib/widget/sfWidgetFormInputCheckboxInverse.class.php</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>&lt;?php

class sfWidgetFormInputCheckboxInverse extends sfWidgetFormInputCheckbox
{
    public function render($name, $value = null, $attributes = array(), $errors = array())
    {

        if (!(null !== $value &amp;&amp; $value !== false))
        {
            $attributes['checked'] = 'checked';
        }

        if (!isset($attributes['value']) &amp;&amp; null !== $this-&gt;getOption('value_attribute_value'))
        {
            $attributes['value'] = $this-&gt;getOption('value_attribute_value');
        }

        return parent::render($name, null, $attributes, $errors);
    }
}
</pre>
</div>
<p>lib/validator/sfValidatorBooleanInverse.class.php</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>&lt;?php

class sfValidatorBooleanInverse extends sfValidatorBoolean
{

    protected function configure($options = array(), $messages = array())
    {
        parent::configure($options, $messages);
        $this-&gt;setOption('empty_value', true);
    }

    protected function doClean($value)
    {
        if (in_array($value, $this-&gt;getOption('true_values')))
        {
          return false;
        }

        if (in_array($value, $this-&gt;getOption('false_values')))
        {
          return true;
        }

        throw new sfValidatorError($this, 'invalid', array('value' =&gt; $value));
    }

}
</pre>
</div>
<p>ほぼ、逆にしたメソッドでオーバーライドしただけです。チェックボックスにチェックを入れなかった場合の挙動がデフォルトではfalseなので、trueに変更しています。</p>
<p>これをformクラスから</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>        $this-&gt;widgetSchema['show_flag'] = new sfWidgetFormInputCheckboxInverse();
        $this-&gt;validatorSchema['show_flag'] = new sfValidatorBooleanInverse();
</pre>
</div>
<p>のように定義してやればいいだけです。</p>
<p>例によってカラムのタイプがbooleanになっていることを確認してください。なっていないと0でも1でもtrueと判断されてしまうので。</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>        $this-&gt;hasColumn('show_flag', 'boolean', null, array(
             'type' =&gt; 'boolean',
             'notnull' =&gt; true,
             'default' =&gt; 0,
             ));
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%92/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfWidgetFormInputCheckboxの正負を反転させる その１</title>
		<link>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%91/</link>
		<comments>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%91/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 09:39:01 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%91/</guid>
		<description><![CDATA[symfony 1.4にて。データベースの定義は「表示」フラグなのに、フォームでは「非表示」時にチェックを入れさせたい場合などがありまして。
データベースのカラム自体の意味を変えるのは、逆にフォームの意味が今後変わったときにどうするんだという話なので、今回はモデルでの入出力時点で値を変更する方法を試してみました。
actAsで各モデルの好きなカラムを反転できる拡張にしてみました。
lib/InvertBoolean.class.php


&#60;?php

class InvertBoolean extends Doctrine_Template
{
    protected $_options = array(
        'columns' =&#62; array()
    );

    public function setTableDefinition()
    {
        $this-&#62;addListener(new InvertBooleanListener($this-&#62;_options));
    }

    public function setUp()
 [...]]]></description>
			<content:encoded><![CDATA[<p>symfony 1.4にて。データベースの定義は「表示」フラグなのに、フォームでは「非表示」時にチェックを入れさせたい場合などがありまして。</p>
<p>データベースのカラム自体の意味を変えるのは、逆にフォームの意味が今後変わったときにどうするんだという話なので、今回はモデルでの入出力時点で値を変更する方法を試してみました。</p>
<p>actAsで各モデルの好きなカラムを反転できる拡張にしてみました。</p>
<p>lib/InvertBoolean.class.php</p>
<p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>&lt;?php

class InvertBoolean extends Doctrine_Template
{
    protected $_options = array(
        'columns' =&gt; array()
    );

    public function setTableDefinition()
    {
        $this-&gt;addListener(new InvertBooleanListener($this-&gt;_options));
    }

    public function setUp()
    {
    }
}
</pre>
</div>
<p>lib/model/invert_boolean/InvertBooleanListener.class.php</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>&lt;?php

class InvertBooleanListener extends Doctrine_Record_Listener
{
    protected $_options;

    public function __construct(array $options)
    {
        $this-&gt;_options = $options;
    }

    public function postHydrate(Doctrine_Event $event)
    {
        $obj = $event-&gt;data;
        foreach ($this-&gt;_options['columns'] as $column) {
            $obj-&gt;$column = !($obj-&gt;$column);
        }
        $event-&gt;set('data', $obj);
    }

    public function preSave(Doctrine_Event $event)
    {
        foreach ($this-&gt;_options['columns'] as $column) {
            $value = !($event-&gt;getInvoker()-&gt;get($column));
            $event-&gt;getInvoker()-&gt;set($column, $value);
        }
    }
}
</pre>
</div>
<p>postHydrateでデータをデータベースから読み出してきてハイドレートした後に、preSaveで保存する前にそれぞれデータを反転しています。</p>
<p>カラムのタイプはあらかじめbooleanにしておく必要があります。schema.ymlからデータベース生成した場合は問題ないかと思います。そうでないなら、モデルのsetUpメソッドにでも</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>        $this-&gt;hasColumn('show_flag', 'boolean', null, array(
             'type' =&gt; 'boolean',
             'notnull' =&gt; true,
             'default' =&gt; 0,
             ));
</pre>
</div>
<p>など。</p>
<p>これを使用できるようにするために、同じくモデルのsetUpメソッドに</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>$this-&gt;actAs('InvertBoolean', array('columns'=&gt;array('show_flag')));</pre>
</div>
<p>とすればOKです。actAsのcolumnsオプションに複数カラム名設定すれば複数カラムを一括で指定できます。</p>
<p>これで、sfWidgetFormInputCheckboxを使ったチェックボックスにチェックを入れたときにデータベースに0が保存され、チェックを外すと1が保存されるカラムができあがりました。</p>
<p>問題点として、カラム名と反対の動きをすることになるので、うっかりする可能性が高まります。</p>
<p>なので、動作は確認しましたが、結局この案は使ってません。次のエントリーで紹介するカスタムウィジェットの方法を使っています。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/sfwidgetforminputcheckbox%e3%81%ae%e6%ad%a3%e8%b2%a0%e3%82%92%e5%8f%8d%e8%bb%a2%e3%81%95%e3%81%9b%e3%82%8b-%e3%81%9d%e3%81%ae%ef%bc%91/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WSH用の便利関数</title>
		<link>http://blog.loadlimits.info/2010/06/wsh%e7%94%a8%e3%81%ae%e4%be%bf%e5%88%a9%e9%96%a2%e6%95%b0/</link>
		<comments>http://blog.loadlimits.info/2010/06/wsh%e7%94%a8%e3%81%ae%e4%be%bf%e5%88%a9%e9%96%a2%e6%95%b0/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 07:51:34 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/wsh%e7%94%a8%e3%81%ae%e4%be%bf%e5%88%a9%e9%96%a2%e6%95%b0/</guid>
		<description><![CDATA[整理のために古いディスクを漁っていたら、汎用的に使えそうなWSH(VBScript)の関数群が出てきたのでメモ。
機能はファイルコピー、テンポラリディレクトリの取得、ファイルリストの取得、テキストファイルの中身を配列に読み込む、ファイルとディレクトリの存在確認、正規表現のマッチ。当時のことはよく覚えていないけど、とりあえずPHPライクに便利関数が欲しかったんだと思います。


Function FileCopy(src,dst,overwrite)

	Dim objFS, objWshShell
	Set objWshShell = WScript.CreateObject("WScript.Shell")
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")

	objFS.CopyFile src,dst,overwrite

End Function

Function GetTemporaryDirectory

	Dim objWshShell
	Set objWshShell = WScript.CreateObject("WScript.Shell")

	GetTemporaryDirectory = objWshShell.ExpandEnvironmentStrings("%TEMP%")

End Function

Function GetFileList(dir, reg)

	Dim objFS, objFolder
	Dim fileCol,tmpFile,fileNames
	Dim i
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")
	Set objFolder = objFS.GetFolder(dir)
	Set fileCol = objFolder.Files

	fileNames = Array(1)
	i = 0
	For Each tmpFile in fileCol
		If RegMatch(reg, tmpFile.name, False) Then
			fileNames(i) = tmpFile.name
			i = i + 1
			Redim Preserve fileNames(i)
		End [...]]]></description>
			<content:encoded><![CDATA[<p>整理のために古いディスクを漁っていたら、汎用的に使えそうなWSH(VBScript)の関数群が出てきたのでメモ。</p>
<p>機能はファイルコピー、テンポラリディレクトリの取得、ファイルリストの取得、テキストファイルの中身を配列に読み込む、ファイルとディレクトリの存在確認、正規表現のマッチ。当時のことはよく覚えていないけど、とりあえずPHPライクに便利関数が欲しかったんだと思います。</p>
<p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>Function FileCopy(src,dst,overwrite)

	Dim objFS, objWshShell
	Set objWshShell = WScript.CreateObject("WScript.Shell")
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")

	objFS.CopyFile src,dst,overwrite

End Function

Function GetTemporaryDirectory

	Dim objWshShell
	Set objWshShell = WScript.CreateObject("WScript.Shell")

	GetTemporaryDirectory = objWshShell.ExpandEnvironmentStrings("%TEMP%")

End Function

Function GetFileList(dir, reg)

	Dim objFS, objFolder
	Dim fileCol,tmpFile,fileNames
	Dim i
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")
	Set objFolder = objFS.GetFolder(dir)
	Set fileCol = objFolder.Files

	fileNames = Array(1)
	i = 0
	For Each tmpFile in fileCol
		If RegMatch(reg, tmpFile.name, False) Then
			fileNames(i) = tmpFile.name
			i = i + 1
			Redim Preserve fileNames(i)
		End If
	Next

	GetFileList = fileNames

End Function

Function FileReadArray(filename)

	Const ForReading = 1, ForWriting = 2

	Dim objFS, objFileStream
	Dim lines
	Dim i
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")
	Set objFileStream = objFS.OpenTextFile(filename, ForReading)

	lines = Array(1)
	i = 0
	Do While objFileStream.AtEndOfStream &lt;&gt; True
		lines(i) = objFileStream.ReadLine
		i = i + 1
		Redim Preserve lines(i)
	Loop

	FileReadArray = lines

End Function

Function FileExists(filepath)

	Dim objFS
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")

	FileExists = objFS.FileExists(filepath)

End Function

Function DirectoryExists(dir)

	Dim objFS
	Set objFS = WScript.CreateObject("Scripting.FileSystemObject")

	DirectoryExists = objFS.FolderExists(dir)

End Function

Function SetRegistry(strName, anyValue ,strType)

	Dim objWshShell
	Set objWshShell = WScript.CreateObject("WScript.Shell")

	objWshShell.RegWrite strName, anyValue, strType

End Function

Function RegMatch(pattern, string, ignoreCase)

	Dim regEx, Matches
	Set regEx = New RegExp
	regEx.Pattern = pattern
	regEx.IgnoreCase = ignoreCase
	regEx.Global = True
	Set Matches = regEx.Execute(string)

	If Matches.Count = 0 Then
		RegMatch = False
	Else
		RegMatch = True
	End If

End Function
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/wsh%e7%94%a8%e3%81%ae%e4%be%bf%e5%88%a9%e9%96%a2%e6%95%b0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows Live Essentialsのアップデート</title>
		<link>http://blog.loadlimits.info/2010/06/windows-live-essentials%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%83%87%e3%83%bc%e3%83%88/</link>
		<comments>http://blog.loadlimits.info/2010/06/windows-live-essentials%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%83%87%e3%83%bc%e3%83%88/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 07:43:27 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[疑問]]></category>
		<category><![CDATA[Windows Live Essentials]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/06/windows-live-essentials%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%83%87%e3%83%bc%e3%83%88/</guid>
		<description><![CDATA[いつものようにブログを書こうと思ってWindows Live Writerを起動してみたら、最新版があるから更新しろというメッセージ。それならばとLive Essentials全体を更新かけてみたのだけど、Windows Live Writerはバージョン番号変わらず…えー。
ちなみにアップデート前のバージョン番号：Build 14.0.8089.726 ja
アップデート後のバージョン番号：Build 14.0.8089.726 ja
The Windows Blog
上記記事見る限り、小さなバグフィックスがあったということだけど…？
]]></description>
			<content:encoded><![CDATA[<p>いつものようにブログを書こうと思ってWindows Live Writerを起動してみたら、最新版があるから更新しろというメッセージ。それならばとLive Essentials全体を更新かけてみたのだけど、Windows Live Writerはバージョン番号変わらず…えー。</p>
<p>ちなみにアップデート前のバージョン番号：Build 14.0.8089.726 ja</p>
<p>アップデート後のバージョン番号：Build 14.0.8089.726 ja</p>
<p><a href="http://windowsteamblog.com/windows_live/b/windowslive/archive/2010/05/12/minor-update-to-essentials-released-today.aspx" target="_blank">The Windows Blog</a></p>
<p>上記記事見る限り、小さなバグフィックスがあったということだけど…？</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/06/windows-live-essentials%e3%81%ae%e3%82%a2%e3%83%83%e3%83%97%e3%83%87%e3%83%bc%e3%83%88/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VAIOのリカバリー時に、「エラー305: 64」表示</title>
		<link>http://blog.loadlimits.info/2010/05/vaio%e3%81%ae%e3%83%aa%e3%82%ab%e3%83%90%e3%83%aa%e3%83%bc%e6%99%82%e3%81%ab%e3%80%81%e3%80%8c%e3%82%a8%e3%83%a9%e3%83%bc305-64%e3%80%8d%e8%a1%a8%e7%a4%ba/</link>
		<comments>http://blog.loadlimits.info/2010/05/vaio%e3%81%ae%e3%83%aa%e3%82%ab%e3%83%90%e3%83%aa%e3%83%bc%e6%99%82%e3%81%ab%e3%80%81%e3%80%8c%e3%82%a8%e3%83%a9%e3%83%bc305-64%e3%80%8d%e8%a1%a8%e7%a4%ba/#comments</comments>
		<pubDate>Sat, 22 May 2010 22:17:59 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[解決]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/05/vaio%e3%81%ae%e3%83%aa%e3%82%ab%e3%83%90%e3%83%aa%e3%83%bc%e6%99%82%e3%81%ab%e3%80%81%e3%80%8c%e3%82%a8%e3%83%a9%e3%83%bc305-64%e3%80%8d%e8%a1%a8%e7%a4%ba/</guid>
		<description><![CDATA[リカバリーを進めていくと、   エラー305: 64    とダイアログが表示されてリカバリーが17%くらいで止まる、というVAIOが持ち込まれてきました。    相談者はCDの焼きミスを疑い、SONYからリカバリディスクを取り寄せて試してみるも現象変わらず。 
リカバリのメニューからコマンドプロンプトが起動できるので、中を見てみると、Cドライブは完全に空の状態。 
試しにリカバリの推奨設定を無視して、パーティション設定でCドライブを50GBにして、残りをシステム復元用のパーティションにしてみたら、なぜかあっさり通って、CDの２枚目に入れ替えるようにというメッセージが表示されるまで進みました。   ということでメッセージに従うとあっさり復元成功。    何だろうこのバグ…
どうも復元用のパーティションが規定値では確保できないのが問題っぽいです。が、一度上記で成功すると２回目からは規定値でも復元可能になるという不思議な現象。
一応エラーコードの内容に関しては以下に掲載されているので参考までに。   http://www.kb.sony.com/selfservice/microsites/search.do?cmd=displayKC&#38;externalId=C1000995&#38;fes=true
]]></description>
			<content:encoded><![CDATA[<p>リカバリーを進めていくと、   <br />エラー305: 64    <br />とダイアログが表示されてリカバリーが17%くらいで止まる、というVAIOが持ち込まれてきました。    <br />相談者はCDの焼きミスを疑い、SONYからリカバリディスクを取り寄せて試してみるも現象変わらず。 </p>
<p>リカバリのメニューからコマンドプロンプトが起動できるので、中を見てみると、Cドライブは完全に空の状態。 </p>
<p>試しにリカバリの推奨設定を無視して、パーティション設定でCドライブを50GBにして、残りをシステム復元用のパーティションにしてみたら、なぜかあっさり通って、CDの２枚目に入れ替えるようにというメッセージが表示されるまで進みました。   <br />ということでメッセージに従うとあっさり復元成功。    <br />何だろうこのバグ…</p>
<p>どうも復元用のパーティションが規定値では確保できないのが問題っぽいです。が、一度上記で成功すると２回目からは規定値でも復元可能になるという不思議な現象。</p>
<p>一応エラーコードの内容に関しては以下に掲載されているので参考までに。   <br /><a href="http://www.kb.sony.com/selfservice/microsites/search.do?cmd=displayKC&amp;externalId=C1000995&amp;fes=true">http://www.kb.sony.com/selfservice/microsites/search.do?cmd=displayKC&amp;externalId=C1000995&amp;fes=true</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/05/vaio%e3%81%ae%e3%83%aa%e3%82%ab%e3%83%90%e3%83%aa%e3%83%bc%e6%99%82%e3%81%ab%e3%80%81%e3%80%8c%e3%82%a8%e3%83%a9%e3%83%bc305-64%e3%80%8d%e8%a1%a8%e7%a4%ba/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>admin generatorの編集後のリダイレクト先変更</title>
		<link>http://blog.loadlimits.info/2010/05/admin-generator%e3%81%ae%e7%b7%a8%e9%9b%86%e5%be%8c%e3%81%ae%e3%83%aa%e3%83%80%e3%82%a4%e3%83%ac%e3%82%af%e3%83%88%e5%85%88%e5%a4%89%e6%9b%b4/</link>
		<comments>http://blog.loadlimits.info/2010/05/admin-generator%e3%81%ae%e7%b7%a8%e9%9b%86%e5%be%8c%e3%81%ae%e3%83%aa%e3%83%80%e3%82%a4%e3%83%ac%e3%82%af%e3%83%88%e5%85%88%e5%a4%89%e6%9b%b4/#comments</comments>
		<pubDate>Wed, 19 May 2010 04:31:06 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[admin generator]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/05/admin-generator%e3%81%ae%e7%b7%a8%e9%9b%86%e5%be%8c%e3%81%ae%e3%83%aa%e3%83%80%e3%82%a4%e3%83%ac%e3%82%af%e3%83%88%e5%85%88%e5%a4%89%e6%9b%b4/</guid>
		<description><![CDATA[admin generatorのeditアクションで、編集後に再度編集画面ではなく、リストに飛ばしたい要件があったのでメモ。例によってSymfony 1.4+Doctrine+admin generator。

class hogeActions extends autoHogeActions
{
    public function executeUpdate(sfWebRequest $request)
    {
        $this-&#62;forward404Unless($request-&#62;isMethod('put'));

        $this-&#62;hoge = $this-&#62;getRoute()-&#62;getObject();
        $this-&#62;form = $this-&#62;configuration-&#62;getForm($this-&#62;hoge);

        if ($this-&#62;form-&#62;bindAndSave($request-&#62;getParameter($this-&#62;form-&#62;getName()), [...]]]></description>
			<content:encoded><![CDATA[<p>admin generatorのeditアクションで、編集後に再度編集画面ではなく、リストに飛ばしたい要件があったのでメモ。例によってSymfony 1.4+Doctrine+admin generator。</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>class hogeActions extends autoHogeActions
{
    public function executeUpdate(sfWebRequest $request)
    {
        $this-&gt;forward404Unless($request-&gt;isMethod('put'));

        $this-&gt;hoge = $this-&gt;getRoute()-&gt;getObject();
        $this-&gt;form = $this-&gt;configuration-&gt;getForm($this-&gt;hoge);

        if ($this-&gt;form-&gt;bindAndSave($request-&gt;getParameter($this-&gt;form-&gt;getName()), $request-&gt;getFiles($this-&gt;form-&gt;getName()))) {
            $this-&gt;redirect('hoge');
        }

        $this-&gt;setTemplate('edit');
    }
}
</pre>
</div>
<p>executeUpdateをオーバーライドすればOKのようです。ここではisMethodがputなことに注意。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/05/admin-generator%e3%81%ae%e7%b7%a8%e9%9b%86%e5%be%8c%e3%81%ae%e3%83%aa%e3%83%80%e3%82%a4%e3%83%ac%e3%82%af%e3%83%88%e5%85%88%e5%a4%89%e6%9b%b4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfonyでのsave時に独自の処理を挟む</title>
		<link>http://blog.loadlimits.info/2010/05/symfony%e3%81%a7%e3%81%aesave%e6%99%82%e3%81%ab%e7%8b%ac%e8%87%aa%e3%81%ae%e5%87%a6%e7%90%86%e3%82%92%e6%8c%9f%e3%82%80/</link>
		<comments>http://blog.loadlimits.info/2010/05/symfony%e3%81%a7%e3%81%aesave%e6%99%82%e3%81%ab%e7%8b%ac%e8%87%aa%e3%81%ae%e5%87%a6%e7%90%86%e3%82%92%e6%8c%9f%e3%82%80/#comments</comments>
		<pubDate>Wed, 19 May 2010 02:12:16 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[admin generator]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/05/symfony%e3%81%a7%e3%81%aesave%e6%99%82%e3%81%ab%e7%8b%ac%e8%87%aa%e3%81%ae%e5%87%a6%e7%90%86%e3%82%92%e6%8c%9f%e3%82%80/</guid>
		<description><![CDATA[Symfony 1.4+Doctrineで、admin generatorな環境です。editなど、自動生成なので、どこをオーバーライドすれば目的の動作になるのかわかりにくいことがありますね。
例えば、あるモデルのステータスを変更すると同時に、他のモデルに対しても操作したい場合があるとします。
まぁ、mergeFormとかembedFormとか使ってもいいのですが、今回は他テーブルのプライマリキーをフォームから選択させたかったので、汎用性のあるdoSaveでの処理を追加してみました。
symfony Forms in Action &#124; 第11章 &#8211; Doctrine との統合 &#124; symfony &#124; Web PHP Framework

class BackendHogeForm extends HogeForm
{
    public function configure()
    {
        parent::configure();

        // 使用するフィールドを指定
        $this-&#62;useFields(array('status'));

 [...]]]></description>
			<content:encoded><![CDATA[<p>Symfony 1.4+Doctrineで、admin generatorな環境です。editなど、自動生成なので、どこをオーバーライドすれば目的の動作になるのかわかりにくいことがありますね。</p>
<p>例えば、あるモデルのステータスを変更すると同時に、他のモデルに対しても操作したい場合があるとします。</p>
<p>まぁ、mergeFormとかembedFormとか使ってもいいのですが、今回は他テーブルのプライマリキーをフォームから選択させたかったので、汎用性のあるdoSaveでの処理を追加してみました。</p>
<p><a href="http://www.symfony-project.org/forms/1_2/ja/11-Doctrine-Integration" target="_blank">symfony Forms in Action | 第11章 &#8211; Doctrine との統合 | symfony | Web PHP Framework</a></p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>class BackendHogeForm extends HogeForm
{
    public function configure()
    {
        parent::configure();

        // 使用するフィールドを指定
        $this-&gt;useFields(array('status'));

        // 別モデルのIDリストを選択するフォームを作成する
        $choices = array(100 =&gt; '100:value1', 101 =&gt; '101:value2');
        $this-&gt;widgetSchema['other_model_id'] = new sfWidgetFormSelect(array('choices' =&gt; $choices));
        $this-&gt;validatorSchema['other_model_id'] = new sfValidatorChoice(array('choices' =&gt; array_keys($choices)));
    }

    protected function doSave($con = null)
    {
        if ($this-&gt;getValue('status') == 'DONE') {
            Doctrine::getTable('OtherModel')-&gt;find($this-&gt;getValue('other_model_id'))
                -&gt;setIsSelected(TRUE)
                -&gt;save();
        }
        return parent::doSave($con);
    }
}
</pre>
</div>
<p>基本的にはdoSaveをオーバーライドするだけです。ちなみにuseFieldsメソッドを使うと必要なフィールド以外を全部unsetしてくれるので便利です。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/05/symfony%e3%81%a7%e3%81%aesave%e6%99%82%e3%81%ab%e7%8b%ac%e8%87%aa%e3%81%ae%e5%87%a6%e7%90%86%e3%82%92%e6%8c%9f%e3%82%80/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHPのDateTimeの結果が-0001-11-30 00:00:00になる現象について</title>
		<link>http://blog.loadlimits.info/2010/05/php%e3%81%aedatetime%e3%81%ae%e7%b5%90%e6%9e%9c%e3%81%8c-0001-11-30-000000%e3%81%ab%e3%81%aa%e3%82%8b%e7%8f%be%e8%b1%a1%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/</link>
		<comments>http://blog.loadlimits.info/2010/05/php%e3%81%aedatetime%e3%81%ae%e7%b5%90%e6%9e%9c%e3%81%8c-0001-11-30-000000%e3%81%ab%e3%81%aa%e3%82%8b%e7%8f%be%e8%b1%a1%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/#comments</comments>
		<pubDate>Fri, 14 May 2010 10:04:33 +0000</pubDate>
		<dc:creator>hotpi</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[疑問]]></category>
		<category><![CDATA[解決]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://blog.loadlimits.info/2010/05/php%e3%81%aedatetime%e3%81%ae%e7%b5%90%e6%9e%9c%e3%81%8c-0001-11-30-000000%e3%81%ab%e3%81%aa%e3%82%8b%e7%8f%be%e8%b1%a1%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/</guid>
		<description><![CDATA[mySQLなどで、日時を0000-00-00 00:00:00としてデータベースに格納しておくことがありますが、これを読み込んでそのままPHPのDateTimeオブジェクトに渡すと、出力が-0001-11-30 00:00:00になってしまいます。

$a = new DateTime('0000-00-00 00:00:00');
echo $a-&#62;format('Y-m-d H:i:s');
// Output: -0001-11-30 00:00:00


PHP :: Bug #42971 :: DataTime::format(): not well formated data &#8216;0000-00-00 00:00:00&#8242;
で、これはバグではないと言われているので、どういうことかと考えてみると、0000-00-00は存在しない0月0日を指定しているので、0月は繰り下がって-1年12月0日、さらに0日も繰り下がって-1年11月30日、となるわけですね。
データベースとPHPの文化の違い、というところでしょうか。
ちなみにDateTime型、コンストラクタにNULLを渡すと現在時刻のインスタンスが生成されるので、データベースの値をNULLにしておくと、現在時刻になってしまいます。うーん…symfonyのDoctrineでNULL判定したい場合はどうすればいいんだ…

$row-&#62;getDateTimeObject('deleted_at')

みたいなことがやりたいのですが。
sfDoctrineRecordも

    $type = $this-&#62;getTable()-&#62;getTypeOf($dateFieldName);
    if ($type == 'date' &#124;&#124; $type == 'timestamp')
    {
      return new DateTime($this-&#62;get($dateFieldName));
    [...]]]></description>
			<content:encoded><![CDATA[<p>mySQLなどで、日時を0000-00-00 00:00:00としてデータベースに格納しておくことがありますが、これを読み込んでそのままPHPのDateTimeオブジェクトに渡すと、出力が-0001-11-30 00:00:00になってしまいます。</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>$a = new DateTime('0000-00-00 00:00:00');
echo $a-&gt;format('Y-m-d H:i:s');
// Output: -0001-11-30 00:00:00
</pre>
</div>
<p><a href="http://bugs.php.net/bug.php?id=42971" target="_blank">PHP :: Bug #42971 :: DataTime::format(): not well formated data &#8216;0000-00-00 00:00:00&#8242;</a></p>
<p>で、これはバグではないと言われているので、どういうことかと考えてみると、0000-00-00は存在しない0月0日を指定しているので、0月は繰り下がって-1年12月0日、さらに0日も繰り下がって-1年11月30日、となるわけですね。</p>
<p>データベースとPHPの文化の違い、というところでしょうか。</p>
<p>ちなみにDateTime型、コンストラクタにNULLを渡すと現在時刻のインスタンスが生成されるので、データベースの値をNULLにしておくと、現在時刻になってしまいます。うーん…symfonyのDoctrineでNULL判定したい場合はどうすればいいんだ…</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>$row-&gt;getDateTimeObject('deleted_at')</pre>
</div>
<p>みたいなことがやりたいのですが。</p>
<p>sfDoctrineRecordも</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<pre>    $type = $this-&gt;getTable()-&gt;getTypeOf($dateFieldName);
    if ($type == 'date' || $type == 'timestamp')
    {
      return new DateTime($this-&gt;get($dateFieldName));
    }
</pre>
</div>
</p>
<p>こうなってるからオーバーライドするしかないのかな。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.loadlimits.info/2010/05/php%e3%81%aedatetime%e3%81%ae%e7%b5%90%e6%9e%9c%e3%81%8c-0001-11-30-000000%e3%81%ab%e3%81%aa%e3%82%8b%e7%8f%be%e8%b1%a1%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
