スポンサーサイト

0

    一定期間更新がないため広告を表示しています


    • 2014.12.23 Tuesday
    • -
    • -
    • -
    • -
    • -
    • by スポンサードリンク

    Doctrine(1.x)でのLEFT OUTER JOIN実現方法

    0
       公式のドキュメント
      http://www.doctrine-project.org/projects/orm/1.2/docs/manual/dql-doctrine-query-language/ja#join%E3%81%AE%E6%A7%8B%E6%96%87:on%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89
      によると、ONキーワードでリレーション条件がカスタム指定できるようなことが書いてありますが、実際には効きませんorz

      試行錯誤の末、無理やりLEFT OUTER JOINぽいことを実行させることができたので忘れないようにメモ。
      実験しながらエラーMSGでググると、symfony公式のフォーラムでも世界各国の方々がLEFT OUTER JOINができないと悩んでいた。

      なんでONを自分で指定したいかと言うとモデルを次のように定義してあるとして、
      Able:
      columns:
      id: { type: integer(1), primary: true }
      Baker:
      columns:
      id: { type: integer(1), primary: true }
      out_class: string(4)
      out_id: integer(1)
      Cat:
      columns:
      id: { type: integer(1) }
      Bakerはout_classの値によりAbleかCatどちらかにJOIN先が変わります。
      なんでこんな変な構造にするか詳細は聞かないでください(笑

      【実験1】
      まず公式のドキュメント通りに。
      $q = Doctrine::getTable("Baker")->createQuery("b")->leftJoin("Able a ON a.id ON b.out_id");
      ⇒...FROM Baker b, Able a...
      ONどこいった??単にFROMにカンマ区切りで入れられると、SQL側でAble.idとBaker.idで勝手にJOINされちゃって都合が悪い。

      【実験2】
      公式ドキュメントにWITHというのも書いてあるので使ってみた。
      $q = Doctrine::getTable("Baker")->createQuery("b")->leftJoin("Able a ON a.id =b.out_id");
      ⇒...FROM Baker b, Able a...
      WITHどこいった??

      【実験3】
      無理を承知でINNER JOINにしてみる。Linux系OSのMySQLで、MyISAMテーブル(=外部キー制約なし)だとBaker.out_idとA.idのINNER JOINとか普通に成立した記憶が。
      $q = Dcotrine::getTable("Baker")->createQuery("b")->innerJoin("Able a ON a.id = b.out_id");
      ⇒エラー。AbleとBakerの間にリレーションが定義されてないとか何とか。まあ当然。


      ここで公式APIドキュメントを読みに行く。
      Doctrine_Query_Abstruct::leftJoin($join, $params=array())
      色々場合分けはあるが、要は最後に $this->dqlQueryPart['from']に 'LEFT JOIN '.$joinをセットする仕組みのよう。
      【実験4】
      とりあえずセットした後にちゃんとセットされているかどうかチェックしてみる。
      $q = Doctrine::getTable("Baker")->createQuery("b")->leftJoin("Able a ON a.id = b.out_id");
      var_dump($q->getDql());
      ⇒FROM Baker b LEFT JOIN Able a ON a.id = b.out_id
      ちゃんとDQLにはセットされていることが確認できた。
      が、$q->getSqlQuery()すると相変わらず FROM Baker b, Able aのみ。どうやらDQLからSQLを生成する時にONが無視されてしまう様子。

      ここでふと思い出した。Pear::DBを使ってSQLを勉強し始めた頃、FROMにテーブルを羅列してWHEREでJOIN条件書いてもほしいデータが取れてたなー。その後SQL実行速度の問題でちゃんとJOINを書くようになったんだけど。
      【実験5】
      だめもとで。
      $q = Doctrine::getTable("Baker")->createQuery("b")->addFrom("Able a")->addWhere("b.out_id = a.id");
      ⇒実験3と同じエラー。でも、$q->getSqlQuery()ではちゃんとSQLが出て来るし、それをコピペしてphpmyadminに実行させたらちゃんと想定通りのデータが出た。

      【実験6】
      実験5ではAbleのデータを入れるコンポーネント(プロパティ)がないよ!って怒られてる気がしてきた。同時にBakerとJOINするAbleまたはCatのデータはBakerに取得用のメソッドを作ってあるのでAbleのデータを最初のSELECTで取らなくてもいいよね、と考える。
      $q = Doctrine::getTable("Baker")->createQuery("b")->addFrom("Able a")->addWhere("b.out_id = a.id")->select("b.*");
      ⇒成功!!

      ここまで来るのに休み休み(家事育児やりながら^^;)で4時間近くかかってしまった(汗
      【結論】
      スマートじゃない&MySQLエンジンがんばって!なSQLだけど、上記の方法でLEFT OUTER JOINっぽいことはできることがわかりました。



      [OpenPNE3.x]op_include_yesnoヘルパーがすごい

      0
         超便利なヘルパーを見つけた(発掘した)ので感動が冷めないうちにまとめておきます。
        何かに書いておかないとまた忘れちゃいそうなのでw

        function op_include_yesno($id, $yesForm, $noForm, $options)
        #定義はopPartsHelper内にあります。

        $id…formを囲むdivに付けたいid名。HTMLのid名なので同一ページ内の他のidと干渉しなければ自由につけられます。例えばスケジュール削除確認の画面ならscheduleDeleteConfirmFormとか。まぁ好みで。

        $yesForm…「はい」の場合に送信するformインスタンス。予めアクション側で作ってビューに渡しておく。⇒私はこのyesnoを主に<削除確認画面>で使ってるので、大抵の場合は単なるsfFormなのですが。何かのパラメータをhiddenで渡したいときにはhiddenFieldsを持ってるformを作って値をセットして渡せばOK。

        $noForm…「いいえ」の場合に送信するformインスタンス。$yesFormと以下同文。

        $options…オプションの連想配列。op_include_formを使ったことがあればほぼ同じオプション内容が使えます。ただし、送信先URLの指定がyes,no2つ分あるのでそれぞれ指定すべし。⇒前述の通り私は<削除確認画面>で使ってるので、yes_urlを削除実行のアクションのURL、no_urlを表示のアクションのURLにしてます。
        yes_url…yesの場合($yesForm)の送信先URL
        no_url…noの場合($noForm)の送信先URL
        title…formを囲むdivのpartsHeading>h3に入るテキスト。無指定だとタイトルなしのブロックになる。⇒<削除確認画面>だと「予定削除の確認」とか。
        body…yes,noボタンの上に表示したいテキスト。⇒<削除確認画面>なら「本当に削除しますか?」とか「削除します。よろしいですか?」とか。
        yes_button…yesのボタンのvalue。「はい」とか「削除する」とか「出席する」とか。デフォルトは「はい」。
        no_button…noのボタンのvalue。「いいえ」とか「中止する」とか「欠席する」とか。デフォルトは「いいえ」

        op_include_formとの違いは、view.ymlによるカスタマイズの読み込み機構は付いてないところぐらい?まぁどうしても必要なら足せばいいけど。


        すごい便利なのにバンドルされてるプラグインでもほとんど使われてないのが不思議。
        皆さんもお試しあれ。


        sfWidgetFormSelectCheckbox, sfWidgetFormSelectRadioの日本語value対応(何年ぶりのsf記事??

        0
          sfWidgetFormSelectCheckbox, sfWidgetFormSelectRadioでchoicesのvalue値(label値ではなく)としてマルチバイト文字列を使うと、いくつかの選択肢が表示されなくなる現象がありました。
          原因としては、inputタグを作るとき(render?)にinputタグのid値をユニークなキーとして使うらしく、そのid値はnameとvalueを「_」で繋いで作るんだけど、sfWidgetForm内でマルチバイト文字列(まぁ日本語の文字列)は「_」に変更されてしまうので、偶々複数のchoicesのvalue値の中に文字列長が同じのがあると、1つにまとまってしまうみたい。
          長々と文章で説明するより実例のほうがわかりやすいかな。

          $choices = array("ほげ"=>"ほげ", "ふが"=>"ふが");
          をcheckboxやradioのchoicesとして指定すると、出力は
          checkboxなら □ふが <input type="checkbox" name="check" value="ふが" id="check___" />&nbsp;ふが
          radioなら ○ふが <input type="radio" name="radio" value="ふが" id="radio___" />
          のみになります。つまり最後の1個だけ。

          で、これを回避するためにはid値の生成メソッド=sfWidgetForm::generateId()を下記のように変更してみました。
          /lib/vender/symfony/lib/widget/sfWidgetForm.class.php
          255行目〜オリジナル
              // remove illegal characters
              $name = preg_replace(array('/^[^A-Za-z]+/', '/[^A-Za-z0-9¥:_¥.¥-]/'), array('', '_'), $name);
          255行目〜私の修正版
              // remove illegal characters
              //$name = preg_replace(array('/^[^A-Za-z]+/', '/[^A-Za-z0-9¥:_¥.¥-]/'), array('', '_'), $name);
              $name = preg_replace('/^[^A-Za-z]+/', '', $name);
              if(preg_match('/[^A-Za-z0-9¥:_¥.¥-]/', $name)>0)
              {
                $name = md5($name);
              }
          一見してわかるとおりマルチバイト文字を「_」×文字数に置換してしまうのではなく、マルチバイト文字列を含むname + _ + value をmd5ハッシュ化してしまっただけです。
          デメリットはinputのid値を使ってCSSでデザインを指定したいときには厳しい(出力されたinputタグをみて頑張って><)ことぐらい?
          まぁ個々のinputにデザイン決めたいぐらいの時はchoicesのkey(value値として渡す値)をアスキー文字だけにして使ってください。
          今回の私の案件ように、運営者が自分でフォームの選択肢を編集する(しかも、運営者は、言語ファイル未アップでtitle, bodyとフォームのラベルが表示されたら「プログラムのコードが出ってます!!」と泡食って連絡してくるぐらい英語オンチ)とか、そういう特殊な状況じゃなければ多分使わないと思いますが。
          #そういえば、mysqlのenumってマルチバイト文字使えたっけ。enumに日本語文字列を指定して、doctrineのschemaからフォームを自動生成させたらどうなるんだろう。そういう時この修正方法が生きるかも???誰か人柱お願いします(笑)


          何年ぶりにsymfony記事を書いたんだろう、自分…。


          xserverでCodeIgniterアプリを入れたら延々404に[解決済み]

          0
            正月早々ですが、また次回ハマったらいやなのでメモ。

             xserverに開発済みのCIアプリを入れて、一通りページを表示して確認していたところ、homeコントローラ配下の画面がことごとく404エラーになっていました。

            なんでなんでー?とlogレベルをdebugに変更して/index.php/home/indexと直打ちしてアクセス
            URI class initialized
            404 notfound --> index
            どうやらURIクラス初期化までOK、次のROUTERの初期化がうまくいってない(ここで404?)。

            で、system/libraries/Router.phpを見る。
            Router class initializedをログ出力する前に呼んでいるRouter::_set_routing()内で、URIクラスから渡されたURIを見てみる。…??あれ??/home/indexにアクセスしたのに/indexになってる。そりゃ404にもなる罠。

            Routerクラスを元に戻して、system/libraries/URI.phpを見る。
            URI::_fetch_uri_string()→URI::_parse_request_uri()と実際の処理部分を探して見る。
            $_SERVER['REQUEST_URI']は/home/indexが入っている。OK。
            その次、$fc_pathというのと$_SERVER['REQUEST_URI']を/でexplodeしたものを比較して、array_sliceしている。ここアヤシイ!!
            $fc_pathってなに?と値を見てみたところ、index.php(フロントコントローラ)のパスが入っていました。
            要するに、xserverのドキュメントルートのパスが/home/hogehoge/public_htmlのようになっているのに、デフォルトコントローラ名としてhomeを使ったのが原因。CIアプリをドキュメントルートでなく物理フォルダを切って配置した場合に対するCI側の対策が仇になっていた。
            とりあえず、今回のブツは他へ移植する予定のないアプリなので、$fc_pathとの比較&array_sliceしている箇所をURI.php内で勝手にコメントアウト。

            私はデフォルトコントローラをhomeとすることが多いのですが、前回xserver使ったときはCI使い初期に作ったアプリでデフォルトコントローラはwelcomeのままだったので、これにひっかからなかった模様。
            この問題はURIルーティング方法としてREQUEST_URIを選択した場合のみ出てくるので、他の方法(PATH_INFOとかQUERY_STRING)にすれば問題ない模様。


            さくらインターネットpython2.6にアップ&django1.0対応

            0
               ひっさしぶりにdjangoとpythonを触りました。

              というのも、さくらインターネットさんがpythonを2.5→2.6とバージョンアップされて、自サイトが万年500エラー状態になってたのを発見したため、virtual-python環境構築しなおしの必要があり、ついでにdjangoのバージョンアップもやってしまえ!という状態になったからです^^

              参考URL
              http://djangoproject.jp/doc/ja/1.0/releases/1.0-porting-guide.html
              ドキュメント翻訳のymasudaさん&その他のdjango-jaの皆様、ありがとうございますm(_ _)m

              ・文字列をユニコードにする。特に日本語の文字列。("にほんご"→u"にほんご")
              ・models.pyで使わなれなくなったオプションを削除(edit_inlineとか;admin用のオプションを削れば取りあえずそのまま動くっぽい)
              ・(contrib.adminを使っている場合のみ)admin.pyを新しく作る
              ・(contrib.adminを使っている場合のみ)urls.pyを修正
              ・(form関係を使っている場合のみ)新しいdjango.forms対応で書き直す?

              とりあえず公開サイトとadminは元通り(?)動くようになりました。
              このサイトはmodel定義5個のみ&formとか使ってないので、修正はmodelとurlsのみで非常に簡単でした。
              作業時間15分ぐらい。

              感想:
              モデル数少なくてジェネリックビューor単純なビューだけなら移行は大したことない。
              form使ってたりmodel定義が多いと大変そう。
              リクエストとかレスポンスとか、DB APIを直接触ってたりとかすると、もっと大変そうーー;
              (まだ0.97preのまま放置中のモデル大量の自サイトがもう一個あるのよね…仕事暇になったらやろう…)


              さくらインターネットdjangoが突然500エラー!?(Pythonバージョンアップされてた

              0
                 なってたのでびっくりしました。

                SSHで入ってpython -vしてみて納得。
                pythonが2.4.3→2.5.2になってました。いつからだったんだろう…
                独自ビルドをせずにvirtual-pythonを使ってたので、
                ・pythonのバイナリは2.5.2
                ・各種ライブラリは$HOME/lib/python2.4以下にあるので読めず
                な状態になっていた。

                1.とりあえず$HOMEでvirtual-pythonを再度実行。
                $HOME/lib/python2.5以下に標準ライブラリが配置されます。

                2.PIL,pysqlite2を再度インストール。

                3.$HOME/django_src/djangoへのシンボリックリンクを、$HOME/lib/python2.5以下に生成しなおし


                これでとりあえず回復しました。
                どーせだからdjango1.x系に変更しようかと一瞬思ったのですが、連休のため子供達の遊んでコールを無視できず断念……

                今のプロジェクト終わったら…といつものセリフを吐いて終わりにします(ダメ人間)


                MySQL⇔PHPベンチマーク(mysql_・PDO・mysqli)+おまけ

                0
                  ご無沙汰です。
                  ちょっと思いつきでやってみました。


                  create table testtable
                  (
                    code varchar(10),
                    name varchar(10),
                    PRIMARY(code)
                  )

                  | code | name |
                  |00001|hoge  |
                  |    …          |
                  |10000|hoge  |
                  というテスト用のデータを用意。

                  SQLは
                   select name from testtable where code='09999'
                  PRIMARYとしてINDEXされているcodeカラムを対象に、1万件のデータを検索してたった1行×1カラムのデータを探します。

                  (一般的なベンチの手法とはかなり違うと思いますが)
                  DB接続の時間は含まずSQLを実行して、結果をフェッチして、その結果をvar_dumpするところまでの時間を計りました。
                  私の場合、WEBアプリでの利用が目的であって、実際にデータを取り出して使い回せる状態にするところまでDBアクセス層のお仕事だと思っているので。

                  また、自鯖ですがコマンドラインでなくApacheモジュール版PHPをブラウザから呼んで実行させています。
                  数字はPHPのmicrotime関数の出力を処理したもの。10回やった平均です。
                  PHP全体・鯖全体の負荷の問題もあるので数値としては全然正確じゃないと思いますが、一応の速度比較にはなるかと。
                  ■結果
                  mysql関数:73.44マイクロ秒
                  PDO:113.49マイクロ秒
                  mysqli(クラス):51.28マイクロ秒
                  ???:28.08マイクロ秒 ←



                  「???」って何だと思います?
                  実は、codeをキーに、nameを値に持つ連想配列を作って、$array['09999']が存在するかどうか調べて(isset)、存在すれば返す。という古典的な(?)方法のベンチです。
                  1万件の配列をメモリに読み込む方が、DBに問い合わせ投げるより早い!というのが意外でした。
                  (くだらなくてすみません;;)

                  今回扱いたいモノが、更新頻度があまり高くなく、読み込み頻度が圧倒的に高いデータなもので、こんな比較をしてみました。
                  更新のほうの処理を書くのがちと面倒ですが、配列ベースで実装しようかな、という結論に至りました。




                  pychart使いたいよう…(泣

                  0
                    「WEBシステム上でリアルタイムにグラフ描きたい!」なお客様が出て来たので、見積もりの参考としてまず有名な?pychartを使ってテストしてみようと思い立ちました。

                    pychartのサイト
                    http://home.gna.org/pychart/
                    サンプル集
                    http://home.gna.org/pychart/examples/index.html

                    pychartをインストールして、早速サンプルを試してみました。
                    …エラー(泣)。


                    ghostscriptとかいうのが無い、と怒られてます。
                    ghostscript
                    http://www.ghostscript.com/
                    寡聞にして初めて知りました(汗
                    よーし、これをインスコ……しようと思ったら、makeでコケて入りません。
                    configureをいろいろ変えてみてもダメ、バージョン1つ前(8.63→8.62)に戻してもダメでした。
                    諦めました。

                    代替案
                    ・PILで線を引かせる?
                    ・phpとImageMagickにやらせる?
                    ・flashを使う?

                    代替案をいろいろ検討してみても、一旦使える環境さえ作ってしまえば、pychartが一番楽に使えると思うんだけどなぁ。


                    HTMLの表(TABLE)のセル(TD)に斜線を引くjavascriptライブラリ slash.js 作っちゃいました

                    0
                      毎度毎度、大変ご無沙汰しております…
                      相変わらず育児と仕事に追われる毎日を過ごしています。
                      といってもPHPの仕事だけなので、django1.0以降はまだ追えていません(涙)

                      で、そんな中で、業務系システムの帳票フォーマット作りで悩んだ結果生まれた作品を突然公開しに来ました。←変人


                      どんなものかというと…

                      HTMLで作成した表(TABLE)でセルに斜線を引くjavascriptライブラリです!
                      ハイ、JavaとかC++とか高度な言語で開発されている方々には全く無意味です(爆)
                      PHPで業務系システムを開発して、PHPに吐き出させるHTMLのテンプレートで帳票フォーマットを作っている私のような人間だけが必要とするシロモノです。

                      使い方解説


                      1.ダウンロードしたslashjsフォルダをサーバー上の適当な位置にアップロードしてください。

                      cssとjavascriptは別々のフォルダに入れてしまっても構いません。



                      2.斜線を描きたいテーブルを配置するHTML内に下記の記述を入れて下さい。

                      *ファイル名は変更して構いませんし、フォルダ名等は実際の環境に合わせて下さい。


                      <script type="text/javascript" src="slashjs/prototype.js"></script>

                      <script type="text/javascript" src="slashjs/slash.js"></script>

                      <link rel="stylesheet" href="slashjs/slash.css" type="text/css" media="screen" />




                      3.斜線を描きたいセル(td)にwithSlashというクラスを付加します。


                      例:
                      <td class="withSlash"></td>




                      右上から左下に向かって斜線を付けたいときはslashRightというクラスも付加してください。


                      例:

                      <td class="withSlash slashRight"></td>




                      対象セルに、無関係な別のクラス名が付いても関係なく動きます。


                      例:

                      <td class="hogehoge withSlash slashRight"></td>




                      ダウンロードはこちらから。


                      動作確認状況なんですが、
                      ○Win IE6
                      ○Win IE7
                      ○Win Firefox3
                      ×Win Safari
                      こんな感じです。特にSafariは「どうしちゃったの?」って感じの表示になります(悲)。
                      取り急ぎこれを使いたいというクライアントさんがWindows環境のみなので、見切り発車してしまいました(汗)

                      ★動作「×」のものの修正対応、私が確認できていないブラウザでの動作確認にご協力いただける方を募集中ですm(_ _)m
                      このページを見て、「サンプル」の表示がどうなったか↓コメントくださいm(_ _)m


                      復活^^;

                      0
                        ご無沙汰でした。

                        実はわたくし今年初めに2人目を出産しまして^^;
                        既に仕事復帰してるのですが、2か月産休した分仕事がたまって大変なことになっております><

                        しばらくdjango触れそうにもないです(涙)
                        エントリー書くとしたらCIの記事中心になると思いますが、一応復活宣言しておきます。

                        しばらくぶりに自分のブログを開いたら、jugemさんに「60日以上更新していない」と怒られたのでちょっと書いてみました。



                        PR

                        calendar

                        S M T W T F S
                              1
                        2345678
                        9101112131415
                        16171819202122
                        23242526272829
                        30      
                        << April 2017 >>

                        twitter

                        selected entries

                        categories

                        archives

                        recent comment

                        • 結局CodeIgniter用汎用Modelクラス&汎用CRUDスクリプトを書きました
                          プログラマー
                        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
                          よし
                        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
                          ななうぇぶ
                        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
                          よし
                        • icu4.4以上が用意できないサーバーでSymfony2.3以上を使う方法
                          よし
                        • WindowsのPCで開発するphperがxhprofを使う方法
                          ななうぇぶ
                        • WindowsのPCで開発するphperがxhprofを使う方法
                          川本
                        • [バッドノウハウ]Symfony2で別テーブルの集計項目を一覧に含めたいとき
                          よし
                        • Symfony Advent Calendar JP 2012 day 14 - vendorをcomposerで管理しているプロジェクトにcomposerを使わずにバンドルを追加したときのautoloadの書き方
                          77web
                        • Symfony Advent Calendar JP 2012 day 14 - vendorをcomposerで管理しているプロジェクトにcomposerを使わずにバンドルを追加したときのautoloadの書き方
                          ktz

                        recent trackback

                        • HTMLの表(TABLE)のセル(TD)に斜線を引くjavascriptライブラリ slash.js 作っちゃいました
                          常山日記
                        • django対symfony 日本語メール送信(その1 symfony編)
                          CPA-LABテクニカル
                        • CodeIgniterでユーザー認証
                          されどLAMPな日々
                        • 久々にdjangoを最新版にしたらHTMLがエスケープされちゃった!!(解決済み)
                          常山日記
                        • FastCGIを諦めてmod_pythonを使う。Apacheのアップグレード
                          サーバー用語集
                        • さくらインターネット、sqlite3でdjango@CGI版を使う際の設定メモ
                          常山日記
                        • さくらインターネット スタンダードプランでdjango使ってる方、DBは?
                          mitszoの日記
                        • python多次元リストをsort(並べ替え)する方法?
                          mitszoの日記
                        • フォームから送信した値とrequest.POSTの挙動($_POST@PHPとの比較)
                          Humming Via Kitchen
                        • 日本語テキストをtruncate@django(Python全般にも??)
                          常山日記

                        recommend

                        links

                        profile

                        search this site.

                        others

                        mobile

                        qrcode

                        powered

                        無料ブログ作成サービス JUGEM