digital matter

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。

DELLモニタ2407WFP電源ボタンの直し方

DELLの2407WFPというモニタをずっと使っているのだけど、1年くらい前から電源ボタンを押しても反応しない状況になって困っていました。

幸い電源は入った状態だったので、以降は入力切替をS-VIDEOなどにして、自動スタンバイさせていました。

電源ボタンは、押してもクリック感がなく、最初から押し込まれているような状態。

分解して直そうと試みるも、裏のネジを外した後の分解方法がわからず…

同等の現象を検索してみたところ、

価格.com – 『皆さんのモニターの主電源ボタン壊れませんか?』 DELL 2408WFP のクチコミ掲示板

電源ボタンマークの「|」の部分が
時計でいう12時の向きにぴったりあってないとクリック
できません。

!?

確かに自分のモニタを見ると電源ボタンのマークが斜めになっている…

P1030002_s

テープなどで電源ボタンを粘着させて回転させてみる…

P1030001_s

できたーーーー!

発見した人すごいな。

今はポストイットで固定してます。

P1030003_s

Linuxで複数ユーザで使えるリモートデスクトップ環境を作る

今回やりたかったのは、社内で複数の人が一台の共有マシンを使って、とある時間のかかる処理をするための環境作成です。

最初はxinetd+Xvfb+x11vncでgdmをあーやってこーやって…って色々試していたのですが、Windowsのリモートデスクトップ接続をクライアントに使えた方が便利だなぁとか思ってRDPで転送する方法がないか調べたところ、むしろさっきまで小難しくやろうとしていたすべてをまるっとまとめてやってくれるxrdpというものを発見!

これならシンクライアントっぽいものが一瞬で作れる!ということでさっそく導入してみたので手順解説します。

WS000001

このxrdp、デフォルトのままならリモートデスクトップユーザからシステムに変更を加える作業はできないので、今回の用途に最適です。

xrdp | Get xrdp at SourceForge.net

ユーザの追加も、通常通りLinuxにユーザ追加するだけで、リモートデスクトップログインできるようになります。

VNCに対する利点は多分こんなところ

  • 画像解像度がクライアント側から変更できる
    WS000000
  • Windowsユーザに追加クライアントをインストールしてもらう必要がない

設定にあたってはこちらのブログのエントリが大変参考になりました。これがないとまともにキーボード使えませんでした。

サーバはUbuntu Server 9.10(Karmic Koala)を使いました。別にUbuntuデスクトップ版でも良かった説。

とりあえずインストール時にこれらを選択しておきます。インストール後なら$ sudo taskselでもOK。

  • Basic Ubuntu server
  • OpenSSH Server
  • Ubuntu desktop

xrdpですが、aptやSourceForgeからtar.gzでダウンロードできるものはバージョンが古く、Windows7のリモートデスクトップ接続クライアントに対応していません。なので、cvsレポジトリから最新を持ってくる必要があります。

今回チェックアウトしたものは2009-12-26に最終更新されたバージョンです。

まずは下準備とチェックアウトまで。

$ sudo aptitude update
$ sudo aptitude install cvs autoconf libtool libssl-dev libpam0g-dev libx11-dev libxfixes-dev tightvncserver scim scim-anthy
$ cd ~/
$ mkdir xrdp
$ cd xrdp
$ cvs -d:pserver:anonymous@xrdp.cvs.sourceforge.net:/cvsroot/xrdp login
$ cvs -z3 -d:pserver:anonymous@xrdp.cvs.sourceforge.net:/cvsroot/xrdp co .
$ cd xrdp

で、前述のブログを参考にいくつかファイルを修正します。

$ vi xrdp/lang.c
          if ((code >= 0) && (code < 128))


          if ((code >= 0) && (code < 135))

に。

$ vi xrdp/xrdp_types.h
    struct xrdp_key_info keys_noshift[128];
    struct xrdp_key_info keys_shift[128];
    struct xrdp_key_info keys_altgr[128];
    struct xrdp_key_info keys_capslock[128];
    struct xrdp_key_info keys_shiftcapslock[128];

    struct xrdp_key_info keys_noshift[135];
    struct xrdp_key_info keys_shift[135];
    struct xrdp_key_info keys_altgr[135];
    struct xrdp_key_info keys_capslock[135];
    struct xrdp_key_info keys_shiftcapslock[135];

に。

$ ./bootstrap
$ ./configure
$ make
$ sudo make install

次は日本語キーボード用にキーマップを作成します。キーマップファイルは/usr/local/bin/xrdp-genkeymapを使って作ることもできるのですが、「\」や「_」のキーが効かなくなる現象があるので、さきほどのエントリからコピーしてきます。

とは言ってもファイル単体では公開されていないので、xrdp-0.5.0-instfiles.patchから当該部分を引っこ抜いてくる形になります。

ちなみに自分で生成する場合は、GUI上の端末から(ここ重要)
$ sudo /usr/local/bin/xrdp-genkeymap /etc/xrdp/km-0411.ini
でOKです。

それ以外は普通にSSHから作業できます。認識する名前別にキーマップの複製。lnでもいいかも。

$ cd /etc/xrdp/
$ sudo cp km-0411.ini km-e0200411.ini
$ sudo cp km-0411.ini km-e0210411.ini
$ sudo cp km-0411.ini km-e0010411.ini
$ sudo vi /etc/xrdp/startwm.sh

startwm.shの内容は前述のエントリからまるごとコピペして上書きします。が、Ubuntuで試したところ、ログイン後にキー配列がめちゃくちゃになる現象(「qwerty」が「c.gvn 」になる)があるので、一行追加して対策します。

export XKL_XMODMAP_DISABLE=1

を、for WindowManager in $SESSIONSの前にでも入れておきます。

で、あとは起動するだけです。

$ sudo /etc/xrdp/xrdp.sh start

WS000002

複数のユーザが同時にログインしても問題なく動作します。1200×1920とかの解像度でもストレスなく作業できました。

Mac OS Xな人々にはRemote Desktop Connection Client for Mac 2もあるのでばっちりです。

追記:あ、右シフトキーが効かない現象がありました。謎。

Virtual PC上でdebianのeth0が消えた現象

Windows Vista Ultimate x32上のMicrosoft Virtual PCからWindows 7 Enterprise x64のWindows Virtual PCにDebian lennyの仮想マシンのデータをそっくり移して使おうとしたら、eth0がなぜか消えてしまった…

loしか残ってないという状況。

結論から言うと、/etc/udev/rules.d/70-persistent-net.rulesを削除した後、rebootしたら直りました。

/etc/init.d/networking restartとかでは直らず。

ゲストOSが64bitじゃないからいけないのかとか思ってdebianの64bit版とか別にインストールしようと試みて、ゲストOSには32bitしか受け付けないことを知ったり。なので、そこは問題ではなかった。

iPhoneな人への地図URLの送り方

iPhone/iPod touchでもPCでも共通で見られるGoogleマップのURLを作りたくなったのでメモ。

というか、iPhone上のSafariから、Googleで場所を検索すると出てくるリンクですね。iPhoneの場合、このURLを開くと地図アプリが開きます。

http://maps.google.co.jp/?q=東京都新宿区西新宿2丁目8−1

http://maps.google.co.jp/?q=248-0006

PCのGoogleマップで地図のURL開くとめちゃくちゃ長くなってしまうので、こういう指定の仕方覚えておくと便利かも。

何がやりたかったかって言うと、twitterで○○の場所どこ?って聞かれて、とっさに住所だけ答えてしまったけど、iPhoneで使える地図のURLにしたほうが便利だったな、って思って。

Silverlight3とBlend3とビヘイビア

Silverlightの開発、ビヘイビアが結構便利なのだけど、あまりまだ洗練されてないのと情報少ないので発見したこと共有しておきます。

まとめを書きたいけどちょっと時間取れないので、ざっくり、どんなものかを書いておきます。

とにかくコードを書かなくて良くなる

コード書く量が減れば、コードをビジネスロジックに集中できるので、見通しが良くなります。デザイナに渡すのも楽かもしれないですね。

簡単な処理はストーリーボードも不要

全部ストーリーボードでやろうとしていたら、結局制御のためにプログラムを書かなきゃいけない事態になっていたので、これも便利ですね。イージングもかけられます。

ときどき動かない条件があるらしい?

マウスオーバーで画像を切り替える処理をやりたくて、ChangePropertyActionに親コントロール(Image)のSourceを切り替える処理をやらせたら、Silverlight自体表示されなくなってしまいました。ローディング100%の状態で先に進まない…。

他にもHyperlinkActionに直接http://から始まるURLを書いたら同じ現象になりました。使い方間違ってるだけだとは思うけど。これについての情報はこっちで解決。

Blend 3 silverlight application & website

<HyperlinkButton Tag="/Views/Page1.xaml" Background="Black" Height="47" HorizontalAlignment="Left" VerticalAlignment="Top" Width="133" NavigateUri="/Page1.xaml" Cursor="Stylus" />

ビヘイビア使わずにHyperlinkButtonにするってことですね…

状態を制するとインターフェースの設計が楽になる

やっぱりインターフェースを重点的に考えられているだけあって、状態を作ってしまえば、あとは状態の遷移だけ意識すればいいという点で便利。

マウスオーバーでずるっと出てくるメニューとか、GoToStateActionを使うと簡単に作れます。状態を先に保存しておいて、それぞれの状態を切り替える処理をクリックイベントだのチェックボックスのチェックだののイベントに関連付けられます。

ただし、「状態」を使うために別コントロールにしておく必要あり。あと、別コントロールにしたあと、一度ビルドしないとプロジェクト内の他のXAMLから使えないっぽい?アセットにコントロールが出てこないと焦ったときはとりあえずビルド。

マウスオーバーでずるっと出てくるメニューはストーリーボードでやらないほうがいい

なぜならアニメーション中にフォーカス外れたとき、MouseLeaveイベントにストーリーボードのBeginとか書いてあると、メニューが出きっていないのにストーリーボードのスタート地点で出きった位置に飛ばされるからです。

その点、GoToStateActionはその辺もきれいに処理してくれるので便利。

ずるずる並び替えられる処理もビヘイビアで

FluidMoveBehaviorを使えばパネルの中の要素をドラッグアンドドロップで変更する処理を一発で設定できるらしいです。試してないけど。

動画あった。これかな?

Animated WPF Panels (animating collection views) | Software and UX

トリガーはビヘイビアを選択したときにプロパティに出てくる

もう一度言う、「トリガーはビヘイビアを選択したときにプロパティに出てくる」。わかりにくい探しにくい…一度覚えてしまえば大丈夫なのだろうけど…

ついでに言うと、状態の選択を解除するには状態タブの中のベースを選択しておけばいいと思う。

その他、デモとか

色々解説してくれているサイトがあったので、紹介しておきます。

kirupa.com – Using Custom Visual States, Page 1 (Visual StatesとGoToStateActionの話)

kirupa.com – Using the FluidMove Behavior, Page 1 (FluidMoveBehaviorのデモあり)

サイト上で全部のデモを見られないのが残念だけど、ソース公開してくれているので、一度ダウンロードして動きを見てみるといいと思いますよ。

SilverlightのTestPage.htm自動生成をやめる

やめる、というか、HTMLのobject要素内にparamとか追加したかったので、別ページを用意して、そのファイルをビルド時に実行してくれるようにしたいのです。

ASP.NETのプロジェクトがくっついている場合はそちらを修正すればいいのですが、Silverlightプロジェクトを単体で作ってしまった場合用。

環境はVisual Studio 2010 ベータを使っています。

メニューの[プロジェクト]から、[新しい項目の追加]、[HTMLファイル]を選択して1ページ作成してやります。

スケルトンのHTMLがエディタに表示されるので、Silverlightを呼び出すタグを書きます。自動生成されたTestPage.htmの内容でもコピーして作ると楽。

ちなみに実行自体はプロジェクトのルートフォルダにできるので、xapファイルのパスの前にBin/debug/などをつけてやる必要あり。(出力ディレクトリにコピーできるけど、コピーしてもそちらが実行されるわけではない)

で、プロジェクトのプロパティで、デバッグ→開始動作のラジオボタンを[テスト ページを動的に生成する]から[ページを指定する]に変更して、htmlファイルを選択。完了。

Encoding.GetString(Byte[])はSilverlightで使えない

今日のびっくり。

‘System.Text.Encoding.GetString(byte[])’ はアクセスできない保護レベルになっています。

Encoding.UTF8.GetString(data);

こんなコードを書くとビルド時エラーになります。

なぜか、Encoding.GetString(Byte[], Int32, Int32)は使えます。

Encoding.UTF8.GetString(data, 0, data.Length);

こうしておけばOK。何だろう、この仕様。

今日の微妙エラー

コントロールはひとつの case ラベル (‘default:’) から別のラベルへ流れ落ちることはできません。

switch (message)
{
    case "hoge":
        funcA();
        break;
    default:
        funcB();
        break; // これがないとエラー
}

他の言語のクセでbreak書かなかったら起きた。

「フォールスルー」ってことなんですね。

ちなみにcaseのあとのブロックにコードを書かなければフォールスルーはできるという話。

Windowsフォームへの、やたら簡単なSilverlightホスティング方法

  1. VisualStudioでフォームをひとつ作ります。
  2. WebBrowserコントロールを配置します。
  3. フォームのLoadイベントに以下を記述。
        private void Form1_Load(object sender, EventArgs e)
        {
            string html = @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">
<!-- saved from url=(0014)about:internet -->

<html xmlns=""http://www.w3.org/1999/xhtml"" >
 <head>
  <title>Test</title>

  <script type=""text/xaml"" id=""testXaml"">
<?xml version=""1.0""?>
<Canvas xmlns=""http://schemas.microsoft.com/client/2007"">
 <Ellipse Fill=""Pink"" Width=""200"" Height=""100"" Canvas.Left=""40"" Canvas.Top=""30"" />
 <Rectangle Fill=""Orange"" Width=""100"" Height=""160"" Canvas.Left=""150"" Canvas.Top=""50"" />
 <TextBlock Text=""This is text on Silverlight"" Canvas.Left=""10"" Canvas.Top=""150"">
  <TextBlock.RenderTransform>
   <RotateTransform Angle=""-30"" />
  </TextBlock.RenderTransform>
 </TextBlock>
</Canvas>
  </script>
 </head>

 <body>
   <object type=""application/x-silverlight-2"" width=""800"" height=""600"">
   <param name=""source"" value=""#testXaml""/>
  </object>
 </body>
</html>";
            if (webBrowser1.Document == null)
            {
                webBrowser1.Navigate("about:blank");
            }
            webBrowser1.Document.OpenNew(true);
            webBrowser1.Document.Write(html);
        }

結果

20100127103949

XAMLソースはこちらから拝借。

【コラム】The Silverlight Times (16) 覚えておきたい「インラインXAML」 | ネット | マイコミジャーナル

WebBrowserの使い方はこちらを参考にしました。

WebBrowserコントロールのコンテンツを文字列により設定するには?[2.0、C#、VB] - @IT