そろそろ本格的に symfony を...と勉強を始めて2日目。情報を漁っていくうちにメール周りがだいぶ面倒くさいことを知ったので、勉強がてらおやぢ組さんの jpMailPlugin に手を入れてみました。
調べた結果わかったこと
- 今後はPHPMailerでなくSwift Mailerに切り替わっていく → MLのログ
 - jpMailPluginはsymfony1.1.5に対応してないっぽい&これから作ろうとしてる
 - sfMailerを使う場合はsettings.ymlのcompat_10をonにしないとだめ
 - sfMailerを使うとcontroller::sendEmail()でエラーログを吐く。なんか気持ち悪い
 - sfMailerを使うとメール送りたいだけなのにHTTPヘッダが出てる。なんか気持ち悪い
 
調べた結果予想できたこと
"俺たちはSwift Mailerが使いたいんじゃない、PHPMailerが使いたいんだ"
"俺たちはSwift Mailerが使いたいんじゃない、PHPMailerが使いたいんだ"
"俺たちはSwift Mailerが使いたいんじゃない、PHPMailerが使いたいんだ"
...symfonyのメール周りで悩んでる(日本語圏の)人の多くが思っていそうだった。
目標にしたこと
- 慣れてるsfMailer / PHPMailerが使える
 - compat_10がoffでも使える
 - controller::sendEmail()でエラーログを吐かない
 - HTTPヘッダは出さない
 
ということで、おやぢ組さんの jpMailPlugin をベースにsymfony1.1.5に対応して作ってみたプラグインはこちら。パッケージ方法がよくわからないので、とりあえずアーカイブで。
※制限事項として、メール処理を一つのモジュールに集約した場合しか動作確認してないというのがあります。
以下、アプリケーション名をfrontend、メール関連モジュールをmailとしてざっくり解説してみます。
インストール方法
plugins以下にjpMailPluginディレクトリを作って展開。
設定方法
apps/frontend/config/factories.yml に以下を追記
all:
  controller:
    class: sfFrontWebJpMailController
apps/frontend/modules/mail/config/module.ymlに以下を追記
all: is_internal: on ← 必要であればこれも view_class: jpMail
apps/frontend/modules/mail/config/view.yml に以下を追記
all: has_layout: off
呼び出し側
アクション(apps/frontend/modules/default/actions/actions.class.php)
public function executeIndex($request)
{
  $this->getController()->sendEmail('mail', 'index');
}
呼び出される側
アクション(apps/frontend/modules/mail/actions/actions.class.php)
public function executeIndex($request)
{
  $this->hoge = 'ほげ~';
  $this->mail = new jpMail;
  $this->mail->initialize();
  $this->mail->setFrom('info@example.com', '山田 太郎');
  $this->mail->setSubject('お問い合わせありがとうございました');
  $this->mail->addAddress('info@example.net', '山田 花子');
}
テンプレート(apps/frontend/modules/mail/templates/indexSuccess.php)
メール本文がここに。
変数が使える。
<?php echo $hoge ?>
パーシャルも。
<?php include_partial('signature') ?>
内容物の解説
jpMailPlugin/config/config.php
$sf_symfony_lib_dir/plugins/sfCompat10Plugin/confg/config.php から必要そうな箇所だけ持ってきました。
<?php
// register config handler for config/mailer.yml files
sfProjectConfiguration::getActive()->getConfigCache()->registerConfigHandler('modules/*/config/mailer.yml', 'sfDefineEnvironmentConfigHandler', array('prefix' => 'sf_mailer_', 'module' => 'yes'));
jpMailPlugin/config/mailer.yml
おなじみのmailer.yml。apps/frontend/modules/mail/config/mailer.ymlでオーバーライドできます。
default:
  deliver:           on
  mailer:            smtp
  domain:            localhost.localdomain
  hostname:          localhost
  port:              25
  username:          ''
  password:          ''
  wordwrap:          0
  .headers:
    priority:        3
    content_type:    text/plain
    charset:         iso-2022-jp
    encoding:        7bit
jpMailPlugin/lib/controller/sfFrontWebJpMailController.class.php
sfFrontWebController から sendEmail() だけオーバーライドしました。
- エラーログを吐かない(infoログを吐く)
 - HTTPヘッダを出さない
 
に対応してます。
2つめのやつが厄介でしたが、sfWebResponseを見る限りではメール送信処理中のみsf_testをtrueにすればHTTPヘッダが出ないようなので、トリッキーですがgetPresentationFor() の間だけsf_testをtrueに設定するようにしてみました。
根本的な解決策はmailモジュールのときだけresponseオブジェクトをsfWebResponse以外のものに変えることでは?と思いはしたものの、factories.ymlでモジュールごとにresponseオブジェクトを変える方法がわからず...そもそもモジュールごとに変えられるような設計じゃないような気も...
<?php
/**
 *
 * @package    jpMail.plugin
 * @subpackage controller
 * @author     Yoshinori Ishii <ishii.yoshinori@itra.jp>
 */
class sfFrontWebJpMailController extends sfFrontWebController
{
  /**
   * Sends and email.
   *
   * This methods calls a module/action with the sfMailView class.
   *
   * @param  string  $module  A module name
   * @param  string  $action  An action name
   *
   * @return string The generated mail content
   *
   * @see sfMailView, getPresentationFor(), sfController
   */
  public function sendEmail($module, $action)
  {
    if (sfConfig::get('sf_logging_enabled'))
    {
      $this->dispatcher->notify(new sfEvent($this, 'application.log', array('sendEmail method called')));
    }
    $sf_test = sfConfig::get('sf_test');
    sfConfig::set('sf_test', true);
    $retval = $this->getPresentationFor($module, $action);
    sfConfig::set('sf_test', $sf_test);
    return $retval;
  }
}
jpMailPlugin/lib/vendor/phpmailer/*
PHPMailerがゴソっと入っています。class.pop3.phpはいらないかな...
jpMailPlugin/lib/view/jpMailView.class.php
symfony1.1.5の $sf_symfony_lib_dir/plugins/sfCompat10Plugin/lib/view/sfMailView.class.php の 'sfMail' を 'jpMail' に変えてコメントをいじりました。
jpMailPlugin/lib/jpMail.class.php
jpMailPluginのものをそのまま持ってきました。
jpMailPlugin/lib/sfMail.class.php
$sf_symfony_lib_dir/plugins/sfCompat10Plugin/lib/sfMail.class.php のものをそのまま持ってきました。
お願い
個人的にはjpMailPluginの新バージョンの元ネタにでもなったらいいなと思っています。が、ライセンス的なものを全く考慮せずにいろんなところからコードを持ってきているので、コレやっちゃダメなどとご指摘いただけると助かります。
また、symfonyの作法的にNGだろ、という事をやってましたら教えて頂けると助かります。

1.1対応ありがとうございます。
これで1.1版は大丈夫ですね。
でも、1.2になるとgetPresentationForメソッドが廃止されているんですよね。。どうしたものやら^^;
コメントありがとうございます。
ちょうど今、メール送ろうと書いていた最中でした…
symfony1.2だとgetPresentationFor()がなくなっちゃうんですか。それはマズい。これから1.2を入れてこねくりまわしてみます。
おっと、廃止されたのではなくControllerに移ったんですね。失敬 ><
あ、じゃあ1.1系と同じだから問題なさそうですね。
となると、1.0系で動かないのか…
バージョンを見て、sfFrontWebJpMailController::sendEmail()内でコールするgetPresentationFor()を変えればよさげですね。
あ、controllerでactionインスタンスってどうやってアクセスすればいいんだろう…?