digital matter

‘PHP’ カテゴリーのアーカイブ

Symfonyでメール送信のデバッグをする

Symfony1.4で、メールを送信するコードで、開発中にテンプレートの動作確認をしたい場合があります。Swift Mailerを使っているなら、すべての送信メールのあて先を上書きして特定のメールアドレスにすることができるので、やり方メモ。

The More with symfony book | メール | symfony | Web PHP Framework

設定の仕方は簡単で、アプリケーションのconfig\factories.ymlにdelivery_strategy: single_addressを指定すればOK。同時にdelivery_addressに、あて先メールアドレスを記述します。

dev:
  mailer:
    param:
      delivery_strategy: single_address
      delivery_address: dev@localhost

これで開発環境のローカルユーザdevにメールが送られます。

元々のヘッダ指定 toccbcc のどれに送られたメールなのかを確認できるよう、それぞれ X-Swift-ToX-Swift-CcX-Swift-Bcc というヘッダが追加されます。

あとはローカルのメールをMewとかで読めばOKです。

もちろんdelivery_addressを外部のメールアドレスに指定してもいいですよ。

PayPalの開発環境みたいにメールのSandBoxとか統合されないかなぁ。

複数の入力欄にまたがるValidationのエラーを特定の入力欄に表示させたい場合

sfFormでSymfony 1.4のお話。

PostValidatorのエラーメッセージをどこに出せばいいんだ?という状況で使用できます。

class SomethingInputForm extends BaseForm
{
    public function configure()
    {
        // ...
        $this->validatorSchema->setPostValidator(
            new sfValidatorCallback(array('callback' => array($this, 'myCallbackFunc')))
        );
    }

    public function myCallbackFunc($validator, $values) {
        // 何かバリデーション
        if (!($values['input1'] == $values['input2'] == $values['input3'])) {
            $error = new sfValidatorError($validator, 'error message ...');
            throw new sfValidatorErrorSchema($validator, array('input1' => $error));
        }

        return $values;
    }
}

こんな感じで、input1のエラーとして出力できるので、テンプレートのエラー表示が楽になります。

Doctrine_Collectionをループする

Symfony 1.4+Doctrine
やたら不便(だと個人的には思っている)なDoctrineの、SELECTに関するメモ。

やりたかったことは、ある条件で抽出した複数行に1行ずつ処理を加えて書き戻すというフロー。
fetchArray()とかでは配列しか返ってこないので意味がなく、fetchOne()では先頭行しか返ってこない。
fetchOne()を複数回実行すればいいのかと思ったら無限ループに陥った。

findByではorderByをするのにフックを使わないといけないらしいのでパス。

一応、以下の方法で解決しました。

$collection = Doctrine_Query::create()
    ->select('u.*')
    ->from('Users u')
    ->where('u.flag = ?', '1')
    ->orderBy('u.id')
    ->execute();

var_dump(get_class($collection)); // Doctrine_Collection

$iter = $collection->getIterator();
var_dump(get_class($iter)); // ArrayIterator

while ($record = $iter->current()) {
    var_dump(get_class($record)); // Users
    var_dump($record->getId());
    $iter->next();
}

next()呼ばないといけないのは面倒だなと思ったら、foreachで使えたらしい。

$collection = Doctrine_Query::create()
    ->select('u.*')
    ->from('Users u')
    ->where('u.flag = ?', '1')
    ->orderBy('u.id')
    ->execute();

var_dump(get_class($collection)); // Doctrine_Collection

$iter = $collection->getIterator();
var_dump(get_class($iter)); // ArrayIterator

foreach ($iter as $record) {
    var_dump(get_class($record)); // Users
    var_dump($record->getId());
}

これでかなりマシになった。

最終的にはこれで。

$collection = Doctrine_Query::create()
    ->select('u.*')
    ->from('Users u')
    ->where('u.flag = ?', '1')
    ->orderBy('u.id')
    ->execute();

var_dump(get_class($collection)); // Doctrine_Collection

foreach ($collection->getIterator() as $record) {
    var_dump(get_class($record)); // Users
    var_dump($record->getId());
}

あとはループ内で$record['data'] = ‘hoge’;$record->save();とかしておけばOK。

追記:2010/03/30

全然違った。もっと簡単にできました。getIterator不要でした。

foreach ($collection as $record) {
    $record['data'] = 'hoge';
    $record->save();
}

慣れてくると意外と便利な気がしなくもないDoctrine。結合系と特に。

CakePHPのPaginator逆ルーティング設定をビューで行う

CakePHP 1.2で、/hoge/Controller/page:1とかにしたページングがしたかったので調べた。

超参考になったのはこちらの記事。スライドの26~27ページあたり。逆ルーティング。

極める routes.php (CakePHP 1.2) : akiyan.com

routes.phpでゴチャゴチャにしたURLに対してもPaginatorにOptionsを渡してやればできるという話だったので実験。

Controllerのvar $paginateに書いてみたのだけどなぜか効かない…

色々試した末、viewに書くことで解決。

<?php
$paginator->options(array('url'=>array(
    'controller' => 'pages',
    'action' => 'display',
    'target' => 'hoge',
)));
?>

routesはこれ。

Router::connect('/hoge/pages/*', array('controller' => 'pages', 'action' => 'display', 'target' => 'hoge'));

これはこれで使い勝手いいかもしれんね。

CakePHP 1.2でオーバーライドが効かなくなる

レアケースだし、何かしらのミスだと思うのだけど一応。

app_controller.phpをはじめ、app/側に何を置いてもcake/側のファイルが優先されてしまって処理が効かないという現象があった。

app/tmp/cache/以下のキャッシュファイルを全部消したら直った。

直らなくて数時間無駄にしてしまった…

CakePHP 1.2でXML-RPCサーバを作る

CakePHPでXML-RPCを受取る方法を調べていたら、タイムリーに超便利な方法が紹介されていた。

How to create an XML-RPC server with CakePHP (Articles) | The Bakery, Everything CakePHP

やることは2つ。

  1. xmlrpc.zipをダウンロードして、解凍してapp/vendorsに置く
  2. コントローラを書く

てっとり早く、上記サイトからxml_rpc_controller.phpをコピーして作成すると、設置も簡単に行える。

メソッドごとにコールバックを定義していけばOK。

前回のエントリ[Pythonで簡単にXML-RPCクライアント : blog.loadlimits - digital matter -]で書いたPython版のクライアントの場合はこんな感じで受け取れる。

<?phpApp::import('Vendor', 'xmlrpc');
class AddController extends AppController {
var $name = 'Add';
var $uses = array();
// The XML-RPC server object
var $server = null;
function index() {
// Disable debug information
// Required to generate valid XML output
Configure::write('debug', 0);
// Avoids render() call
$this->autoRender = false;
// XML-RPC callbacks settings
// Use this parameter to map XML-RPC methods to your protected or private controller methods
$callbacks = array();
$callbacks['sample.hogehogeAPI'] = array(&$this, '_saveData');
// Handle XML-RPC request
$this->server = new IXR_Server($callbacks);
}
function _saveData($data = array()) {
ob_start();
var_dump($data);
$str = ob_get_contents();
ob_end_clean();
return $str;
}
}
?>

結果はこんな感じ。

array(6) {
  [0]=>
  array(1) {
    ["image"]=>
    string(4) "hoge"
  }
  [1]=>
  array(1) {
    ["username"]=>
    string(4) "name"
  }
  [2]=>
  array(1) {
    ["title"]=>
    string(10) "item title"
  }
  [3]=>
  array(1) {
    ["mail"]=>
    string(11) "user e-mail"
  }
  [4]=>
  array(1) {
    ["comment"]=>
    string(12) "item comment"
  }
  [5]=>
  array(1) {
    ["itemlist"]=>
    array(4) {
      [0]=>
      int(3)
      [1]=>
      int(2)
      [2]=>
      int(3)
      [3]=>
      int(1)
    }
  }

非常に便利。

CakePHP 1.2でオーバーライドが効かなくなる

レアケースだし、何かしらのミスだと思うのだけど一応。

app_controller.phpをはじめ、app/側に何を置いてもcake/側のファイルが優先されてしまって処理が効かないという現象があった。

app/tmp/cache/以下のキャッシュファイルを全部消したら直った。

直らなくて数時間無駄にしてしまった…

Delphi for PHP 2.0発注

発売されたもののSEShopにもなくて、ずっとどこで買えるか謎だったDelphi for PHP 2.0がAmazonに入ってた。

ぉ?じゃあもしやと思ってヨドバシのサイトで検索したところ、ヨドバシでも取り扱いを開始していた。

そんなわけで早速ポチってみました。取り寄せで、いつ届くのかわからないけど。

Delphi for PHP 2.0 発表

CodeGear™、PHPで初めてドラッグ&ドロップ開発を実現したビジュアル統合開発環境の新バージョン「Delphi® for PHP 2.0」を発表
http://www.codegear.com/jp/article/37886/

キ・キ・キ・キタ━━━━━━(゚∀゚)━━━━━━!!!!

1.0は結局見送ってしまったが、2.0になって日本語対応になったし、色々情報も貯まってきたっぽいので今度こそ買う!

ZendFrameworkも使えるし、デザイン連携も可能。テンプレートエンジンとかどうなってるんだろう。

そして相変わらずどこで買えるのかがイマイチわからない仕組み。

ZendFrameworkでPicasa

Zend Framework: Documentation

ZendFrameworkって結構色々ニッチな機能取り揃えているなぁと思っていたけど、Picasa Web Albumsに対応していることを知ってびっくりした。

これならやりたかったことができそう。
自宅のファイルサーバに保存されている写真を携帯から選択してPicasaにアップロード→携帯とかiPod touchで人に見せるとか、そういう使い方がしたい。

あとは撮った写真をその場でPicasaにあげる手段が欲しいなぁ…Eye-fiはちょっと微妙。
写真撮る→CFカードの内容を無線経由でPicasaにアップロード→アルバムのアドレスを他の人にも送って、見てもらうとか。公衆無線がない環境でも使いたい。
EM ONEとかって話になってくるな…