2012年6月18日月曜日

symfonyでnode.js/socket.io ブラウザでリアルタイム同期

nodeを使ってみたかったので調べたところ、
ブラウザからはsocket.ioを使うことでリアルタイム同期が行えるようでした。
様々な環境がいろいろあってやっとchromeで動きました。
なぜかiPhoneでは動かなかったので、もう疲れました。

まずは最新版のhttp://socket.io/をインストールしたところ、
巷にあるサンプルとちょっと違っていました。
また、symfonyを使っているためjsの置き場所が決まっているために
web/jsに
node_modules/socket.io/node_modules/socket.io-client/dist
のsocket.io.jsをコピーしてきました。
以下
https://github.com/arshad/CrossBrowse
のサンプルを動かすところまでです。
当方なぜか3000ポートがうまく機能しなかったので8000ポートを使ってみました。

修正した箇所は
サーバ側

server.listen(8000);

//Socket for listening to connect
var io = io.listen(server);
io.on('connection', function(client){
  //console.log(client.listener.clients.length);
  //On each ping data taken from one socket and broadcast to other systems
  client.on('message', function(message){
    //var el = JSON.parse(message);
    client.broadcast.send(message);
  });
});



クライアントでJSON.parseするのでJSON.parseを殺しています。
また、broadcast.sendにしなければならなくなったみたいです。
emitとsendが明示的に必要になったように見受けられますがよくわかりません。
emitはメッセージを指定して送るsendはメッセージを自動で'message'にしてくれるみたいでした。


クライアント側(script.js



var socket = io.connect(null,{port:8000});

socket.on('connect', function () {
    socket.on('message', function(msg) {
       var m =  JSON.parse(msg);
      $('#draggable').css({
        left : m.x,
        top : m.y
      });
    });
  });

$(document).ready(function() {
  $('h2').html($.browser.webkit);
  var el = new Object();
  $('#draggable').draggable({
    drag : function(event, obj) {
      var pos = $('#draggable').position();
        el.x = pos.left;
        el.y = pos.top;
      socket.send(JSON.stringify(el));
    }
  });
});

以前は
var socket =  new io.Socket(null,{port:8000});
socket.connect();
ってやっていたような記述を見るのですが
var socket = io.connect(null,{port:8000});
これでいいみたいです。

さらにurlが'http://localhost'つーのばっかり見るのですが
nullにすると、どうもこのjavascript自体を送信してくるサーバ側の情報がDOMに入ってくるみたいでそいつを勝手に取得してくれます。
つまり、http://amazon-ec2-test.comみたいな。
でポートのオプションはこうやって渡すみたいです。
肝心のxxxSuccess.php(twig使っているのでhtml)は以下のようになっています。

{{'socket.io.js'|use_javascript()}}
{{'json2.js'|use_javascript()}}
{{'script.js'|use_javascript()}}

<style type="text/css">
body {
  background : url(../images/pattern.png) repeat;
  overflow:hidden;
}

#draggable {
  background:#FFF;
  cursor:move;
  width:300px;
  height:100px;
  position:absolute;
}
</style>
<body>
    <h2></h2>
    <div id="draggable"></div>
</body>

たしかにchrome同士では箱のドラッグが同期してくれました。
iPhoneだとそもそもサーバ側につながっていないようでサーバ側に接続が来ません。
さっぱりわかりません。

iPhoneに関しては社内Wifiの設定で8000ポートを空けていないので通信が出来なかっただけみたいです。



2012年6月12日火曜日

javascript task table 2

javascriptのタスク管理ですが
http://www.supernifty.com.au/blog/2011/07/17/javascript-task-queue-hack-it-9/
これでいいじゃないですか。
外人は助かるなー。まあ、人間がいた場合外人である確率の方が高いから当然かも知れません。
で、少しシンプルになりました。



  var task = function(func_, interval_) {
    return {
      func: func_ || null,
      interval: interval_ || -1
    }
  }

  var taskTable = function( table ) {
    var queue = queue || table;

    return {
      start: function( table ) {
        queue = queue || table;
        this.next();
      },
      next: function() {
        var self = this;
        var task = queue.shift();
       
        if(void 0 !== task)
        {
          if(task.func)
          {
            task.func();
            if(0<=task.interval)
            {
              setTimeout(function(){self.next();}, task.interval);
            }
          }
        }
      }
    }
  }

で使い方は


  var tasktable = taskTable([ 


          task( function(){alert('test1')},1000 ),
          task( function(){alert('test2'); tasktable.next(); } ),
          task( function(){alert('test3')})
        ]);
  tasktable .start();
もうグループを文字列で指定しなくていいんです。
完了コールバックとかの処理に応じて次に行く処理は
var tasktable = taskTable(
の場合
tasktable.next()
とします。
デフォルト引数で処理しているので
引用元のオリジナルと同じように
  var q = taskTable(),
        table = [.....];
  q.start(table);


ともかけます。





jqueryrotateのアニメーションが再生されない?

要素を回転アニメーションできるjQueryプラグインが
http://code.google.com/p/jqueryrotate/
ありまして、使ってみたのですがアニメーションの連結を行うとはじめのアニメーションが再生されない問題がありました。
しかも、特定のページだけ。
アニメーションの連結は.rotateの完了コールバックに次のアニメーションを突っ込んでいたのですが、間違っているのかと思って先日のタスクマネージャを作ってみたりしたわけなのですが、一向に改善されない。
まあ、はじめっからデバッガで追えばよかったのですが、追ってみたところさっさと完了コールバックが返ってきていました。
バグかと思ってソースを見ているとアニメーションが実時間でのみ処理されていまして、いわゆるフレームスキップしまくってアニメーションが再生されていないように見えていたわけでした。

ゲームを作る際に経験があると思うのですが、各状況で処理負荷が不定なのでそれを考慮してデルタタイムで処理書きますよね。
その際に最低フレームレート設定しませんか?
例えば、フレームレートが60fpsより高い際は垂直同期とって、60-30fpsの時は垂直同期無視して、30fpsを切ったら処理落ちさせて内部のデルタタイムを33.3ms(30pfs)以下にしないとか(力学処理なんかはデルタの振れ幅を小さくしたり固定したいしますけども)。

それが必要なようでした。
なので、

    _animate:function()
    {
         var actualTime = +new Date;
         var checkEnd = actualTime - this._animateStartTime > this._parameters.duration;

         // TODO: Bug for animatedGif for static rotation ? (to test)
         if (checkEnd && !this._parameters.animatedGif)
         {
             clearTimeout(this._timer);
         }
         else
         {
             if (this._canvas||this._vimage||this._img) {
                 var angle = this._parameters.easing(0, actualTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
                 this._rotate((~~(angle*10))/10);
             }
のところを


     _animateStart:function()
    {
       .......

       this._animateLastTime = this._animateStartTime;

    }
     _animate:function()
    {
      var minTime = 33;
         var intervalTime = +new Date - this._animateLastTime;
         if(minTime<intervalTime) intervalTime = minTime;
         this._animateLastTime += intervalTime;
         var checkEnd = this._animateLastTime - this._animateStartTime > this._parameters.duration;

         // TODO: Bug for animatedGif for static rotation ? (to test)
         if (checkEnd && !this._parameters.animatedGif)
         {
            clearTimeout(this._timer);
         }
         else
         {
             if (this._canvas||this._vimage||this._img) {
                 var angle = this._parameters.easing(0, this._animateLastTime - this._animateStartTime, this._animateStartAngle, this._parameters.animateTo - this._animateStartAngle, this._parameters.duration);
                 this._rotate((~~(angle*10))/10);
             }


とかにいじってみました。
minTime =33ms以下の際は処理落ちさせていることを望んでいます。

ひとまず、軽く動作は確認できました。


2012年6月11日月曜日

javascriptでタスクマネージャつくりはじめ


jQueryのプラグインなどのいろんな機能で一連の処理を組み立てたいのですが、
どうも、連続処理のやり方が不慣れでしっくり来ないため。
タスクをタイムライン的に登録して実行出来ればいいなと思い
javascript自体がよくわかってないのですが、ちょっと挑戦中です。
http://developmentor.lrlab.to/postal/jquery/jquery.delay.html
こちらを参考にさせていただいています。

<script type="text/javascript">
  (function($) {
    $.taskTable =
    {
      queue: []
    };
    $.taskNext = function(group)
    {
      $.taskStart(group);
    }
    $.taskStart = function(group)
    {
      var self = this;
      var group = group || 'anonymous';
      var obj = $.taskTable.queue[group].shift();
      if(void 0 !== obj)
      {
        if(obj.func)
        {
          obj.func();
          if(0<=obj.interval)
          {
            setTimeout(function(){$.taskStart(group);}, obj.interval);
          }
        }
      }
    };

    $.fn.taskTable = function(fn,interval,group)
    {
      var self = this;
      var group = group || 'anonymous';
      if(void 0 === $.taskTable.queue[group])
      {
         $.taskTable.queue[group] = Array();
      }
      $.taskTable.queue[group].push(
      {'func': function()
        {
          self.each(fn);
        },
        'interval':interval
      });
    };
  })(jQuery);

  function test(name, fnc)
  {
    alert(name);
    if(void 0 !== fnc)
    {
      fnc();
    }
  }

  $(document).ready(function(){
    $('#test1').taskTable( function(){test('test1A',function(){$.taskNext('test')})},-1,'test' );
    $('#test1').taskTable( function(){test('anonymous',function(){$.taskNext('test')})},-1,'test' );
    $('#test2').taskTable( function(){test('test1B',function(){$.taskNext('test')})},-1,'test' );
    $('#test2').taskTable( function(){test('anonymous',function(){$.taskNext()})},-1 );
    $.taskStart('test');
  });
</script>
<body>
<div id="test1">test1</div>
<div id="test2">test2</div>
</body>
とか。

参考のページでは起動関数の引数で一定間隔の実行をしていますが、
今回はそれぞれで次に進むためのインターバルか次に進むためのコールバックにて次々に実行させています。

 $('selecter').taskTable( function(){alert('test1')},1000);
 $('selecter').taskTable( function(){alert('test'2)},1000);
 $.taskStart();

これが処理の登録で第一引数の無名関数が順番に行って欲しい処理自体です。
で第二引数の1000っつーのがつぎの処理まで1000m秒待てっつーことです。
で、ここで時間指定して先に進むんじゃなくて処理が終わったら次みたいのを

 $('#selecter').taskTable( function(){test('test1',function(){$.taskNext()})},-1);
 $('#selecter').taskTable( function(){test('test2',function(){$.taskNext()})},-1);
 $.taskStart();

testつーのは処理が割ったらコールバックを呼ぶ仕組みなのでそのコールバックから
$.taskNext()を呼ぶことで次に進むようにしてます。
最後の-1っつーブッサイクなのはコールバック使っているから時間とか指定しないっつー不細工です。
タスクの登録時にgroupを指定したりしていますが、これもブサイクな作りで
$.taskStart('group');はいいとしてもコールバックに
$.taskNext('group');と書かないといけないとかだっさくて、以下に初心者かよくわかるものとなっております。さっきの-1もそうです。

まあ、ひとまずはこれをもうちょっといい感じにしていこうかと思うのですが、
本当にこれ車輪の大発明であって欲しいのです。
めんどうなので、いい感じのjQueryプラグイン無いですか?
本当にだれか教えて欲しいのです。
ぐぐってもみつけられないのですが、キーワード何を入れればいいのでしょうか。
僕の方向性が間違っているんでしょうか。

助けてください。









2012年6月7日木曜日

テキストエリアの入力文字数のリアルタイムカウント

twitterの文字数のカウンタを実装します。
まあ、調べると以下の感じです。
<textarea></textarea>
<p id="counter">140</p>

   $("textarea").bind("keyup",(function(){
        var counter = 140 - $(this).val().length;
        $("#counter").text(counter);
     }));

色つけたりは調べてください。

んで、これ微妙に反応悪い。
キーリピートに反応しない。

んで、イベントをkeydownにすると今度はコピペが取れない。
じゃあkeydownとkeyupの両方を取るとキーリピートの一発目が取れない。
わけわかんねーですが、いろいろ調べていたら
ちょっと遅れて値をとればいいらしい。
完成したコードは

    $("textarea").bind("keydown focus",(function(){
      var self = $(this);
      setTimeout(function() {
        var counter = 140 - $(self).val().length;
        $("#counter").text(counter);
      }, 10);
    }));

でたーセルフハック。
なんかあとで処理するようなコールバックの処理ではthisが不明になります。
まあ、実際に呼ばれるときはこの関数抜けてるからね。
で、selfにthisを保存しておくと言う奴で切り抜ける。
selfはなぜ生きているのかといえばこれがクロージャーなんでしょうね。
thisは意味が特殊なのでシチュエイションでちゃんと意味が変わらないといけないでしょうね。
focusイベントも念のため入れて、これで本家twitterのカウンターにだいぶ近いんじゃないでしょうかね。

2012年6月6日水曜日

symfonyでobject配列をjavascriptに渡す

具体的にはajaxで適当な情報をオブジェクト配列で取得してきたものをjQueryを使ってギュンギュン表示したいのでjavascriptに取得してきたデータをオブジェクト配列で渡したかったのです。
しかも自分actionで処理してview(twig)を経由しないと何も組めないのでその流れを使っています。
まずjavascript側から
      $.ajax({
        url: "getlist",
        cache: false,
        type: "POST",
        data: {id: id},
        success: function(data){
          callback(data);
        },
        error: function(data){
          alert('失敗');
        },
        complete: function(){}
      });
こんな感じでurl:getlistとか適当なところにリクエストかけます。
getlistはまあ自分のactionなんですけれども
で、アクションですが

  public function executeGetlist (sfWebRequest $request)
  {
    $this->setLayout(false);
    /*なんらかのサービスにデータを問い合わせた結果が$data_listにオブジェクトの配列で   入ってると思って下さい
       $data_list = array( array('id'=>0,'text'=>'aaaaa'),array('id'=>1,'text'=>'bbbb'));
とかそんな感じ?
   */
    $this->data_list = json_encode( (array)$data_list );

  }
ってやってこいつのviewではgetlistSuccess.html(twig)
{{ data_list  }}
とだけ書いておいてですね。


     callback: function(data) {
          var self = this;
          var dataList = eval(data);
          if (dataList.length > 0) {
              var data = dataList.pop();
              alert(data.id+data.text);
          }
          setTimeout(function() {
               self.render(dataList);
          }, 2000);
      }

ってやると順次表示される感じでした。
とにかく
json_encode()してviewでそれをまんま表示してeval()で変数にすればいいようです。

その後の補足
どうもevalに関してはnew Functionを使う方法もあるみたいで

     var dataList = eval("("+data+")");
     var dataList = (new Function("return ("+data+")"))();
どっちでもいいみたい
速度とそのコードのスコープに差があるようです。
また、上では知らなかったのだがdataを文字列()でくくる必要があるみたい。


さらにviewの部分ですがviewを使わないでgetJsonで呼び出してactionでは

public function executeRefresh()
{
  $output = '{"title":"My basic letter","name":"Mr Brown"}';
  $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')');
 
  return sfView::HEADER_ONLY;
}

とやるのが一番良いようですがもう面倒なのでajaxでやったしまったのですが
{{ data_list  }}
とかviewでやるよりもactionで
    return $this->renderText(json_encode($result));  
とやってテンプレート使わないほうがいいみたい。



2012年5月24日木曜日

jquery.lettering.jsで改行を処理したい

jquery.lettering.animate.js
で文字列をかっこよく表示したいと思ったら、改行に関しては処理してくれないので
こいつが使っている
jquery.lettering.js
をちょっと都合よく改造してしまいました。


function injector(t, splitter, klass, after) {
    var html = t.html().split((/<*?.[Bb][Rr].*?>/g));
    var inject = '';
  if (html.length) {
        $(html).each(function(j, html_item) {
          var a = html_item.split(splitter);
          if (a.length) {
            $(a).each(function(i, item) {
              inject += '<span class="'+klass+(i+1)+'">'+item+'</span>'+after;
            });
            inject += '<BR />';

            t.empty().append(inject);
          }
        });
  t.empty().append(inject);
      }
}

一旦<br>をセパレータにして文字列の配列を分離してから
その中身を従来の処理にして従来の処理の最後で
<span></span>
を通さずに<br>を打つって感じですか。
苦労したのがIEだとsplit("<br>")をうまく処理してくれなくて
正規表現でまかないました。
IEはどうも大文字の<BR>を使うみたいですね。

2012年5月11日金曜日

TopUp jQueryプラグインにてウインドウを閉じるリンクを作成する方法の一つ

TopUp betaを使っています。
よく考えたらbetaなんですね。本番はなにか違う形で存在しているんでしょうか?
知りたいです。
とても、いいものだと思っていまして、採用しています。
http://gettopup.com/

ウインドウがpopupして来てかっこいいものですが、
まず前提としてページをまるまるウインドウに出したいのでiFrameにて運用しています。
すると、当然ウインドウ内にリンクやらの自前のコントロールが存在してきます。
そこで、このウインドウを閉じるボタン(リンク)と言う要望が出てきました。
いろいろ調べたのですが、jsとhtmlの仕様といろいろ知らない事だらけで難航していましたが、
ひとまず、ウインドウを閉じるリンクを実現できました。
方法の一つになりますでしょうか。

<a href = javascript:$(".te_close_link",parent.document).click();>ウインドウを閉じる</a>

って感じでしょうか。
もう何が何だかわからなかったので、chromeにてどういうタグが何をになっているのかを調べて
どうやらデフォルトで存在する×ボタンが上記のte_close_linkに記述されているようだったので、
iFrameの仕様を調べて親のte_close_linkをクリックすることで実現しました。

この動作をfunctionとしてtopup.js自体に
function topup_close()
とでも定義してしまって

呼び出す側は

<a href = javascript: topup_close();>ウインドウを閉じる</a>
みたいにして使っています。

追記
これ
parent.TopUp.でアクセスできるので素でclose呼んでも出来ますね。。。

以上。

2012年5月1日火曜日

symfony backendでファイルのアップロード管理 元のファイル名とアップロードしたファイルを消す

symfonyのbackendはいろいろ自動でやってくれるけれども、何がどう関係しているのかさっぱりわかりません。
わかるんですかね?
DBにファイル名だけを管理させ、実際のファイル自体は
web/image/xxxなどどっかにアップロードさせて管理したいです。


まず、backendでgenerator.ymlとかいじる系はやってしまって。
フォームでファイルをアップするのを付け加えるにはバリデータとかウィジットとか登録するらしい。
こんなの知るかよ。
class ImageForm extends BaseImageForm
{
  public function configure()
  {
    parent::configure();

    unset(
      $this['created_at'], $this['updated_at']
    );    

    $this->widgetSchema['fileName'] = new sfWidgetFormInputFileEditable(array(
      'label'     => 'fileName',
      'file_src'  => sfConfig::get('app_image_path').$this->getObject()->getFileName(),
      'is_image'  => true,
      'edit_mode' => !$this->isNew(),
      'with_delete' => true,
      'template'  => '
%file%
%input%
%delete% %delete_label%
',)); $this->validatorSchema['fileName'] = new sfValidatorFile(array( 'required' => true, 'path' => sfConfig::get('app_image_path'), 'validated_file_class' => 'CustomValidatedFile', 'mime_types' => 'web_images', )); } }
いろいろ細かいファイルパスとかはうまいことやってください。

で、勝手にぐちゃぐちゃしたファイル名を付けやがるので、オリジナルのファイル名で管理したければ

 sfValidatorFileのコンストラクタに
      'validated_file_class' => 'CustomValidatedFile',
を追加して
こうするらしいです。
class CustomValidatedFile extends sfValidatedFile {
    public function generateFilename()
    {
      return $this->getOriginalName();      
    }
}
知るか!


さらに、deleteしてもファイル自体は消えないので
class Image extends BaseImage
{

  public function postDelete($event)
  {
    $filename = $this->getFilename();

    $filepath = sfConfig::get('app_image_path') .  $filename;

    @unlink($filepath);
  }
}
とするらしいです。
知るか!


2012年4月9日月曜日

jparallaxをjquery-1.7.1.jsに対応させる&バグ?

jQueryのバージョンを対象のプラグインに合わせて切り替えるのが筋だと思うのですが、
逆に面倒になったのでjparallaxをjquery1.7.1に対応させました。

簡単です。
マウス情報の取得の部分
 jQuery().mousemove(function(mouse)

 jQuery('*').mousemove(function(mouse)
にするだけです。
画面全部のマウス情報を拾いますけど、そこは好きにしてください。

あと、よくわかんないですがやっぱりなんか範囲外にあるマウスが拾えないことがあるので
オプションで
 mouseActiveOutside:true
にするも、ソースコード内では使ってないように見えたので
そのすぐ階下のコード
 if(mouseport.xinside&&mouseport.yinside&&!mouseport.active)

 if(settings.mouseActiveOutside||(mouseport.xinside&&mouseport.yinside&&!mouseport.active))
って感じで
 settings.mouseActiveOutside
がtrueの際は常に通るようにすればイメージ通りな気がします。

以上

2012年3月19日月曜日

sfTwigPluginのぐぬぬぬぬ

sfTwigPluginを導入するとmodule.ymlを見て
ビューをsfTwigPartialViewとかsfPHPとか切り替わる仕組みが
あるわけですが

これモジュールを超えてパーシャルファイルを呼び出すと
{{ 'module/list'|include_partial() }}
とか殺るんですよね?
これおもいっきり動作しないわけでソース見て動作見ると

PartialHelper.phpとかにあったりするわけですが
get_partial()の中で


  $class = sfConfig::get('mod_'.strtolower($moduleName).'_partial_view_class', 'sf').'PartialView';
  $view = new $class($context, $moduleName, $actionName, '');

こんなんやってまして、
  'mod_content_view_class' => string 'sfTwig' (length=6)

  'mod_content_partial_view_class' => string 'sfTwig' (length=6)
こんなんなってんですよ。
こっちが欲しいのは

  'mod_module_view_class' => string 'sfTwig' (length=6)

  'mod_ module_partial_view_class' => string 'sfTwig' (length=6)
なんすよ。
自分のルートしかコンフィグ持ってないようでモジュールを超えると手に入らず
おもいっきりデフォルトのsfPHPに行っちゃうわけですよ。

仕方ないからTwigを必ず使うことにして


    $class = 'sfTwigPartialView';
ってしちゃいましたよ。

そしたらbackendでcacheが自動的にできる際にphpしかつくらねーわけで
そのせいでビューがTwigに対応してない。
backendのときはしょうがないのでsfPHPにする必要が出た。

if('frontend' == sfConfig::get('sf_app'))
  {
    $class = 'sfTwigPartialView';
  }

これで対処とか、もうやってられねー。
つかTwig使う利点に出くわせなくなってきたよ。。。


2012年3月13日火曜日

symfonyでjQueryによるAjax。 sfDoctrinePagerに対応とか自分自身を書き換える系

JobeetでJQueryを使ったAjaxの解説があるのだけれども、状況が特殊すぎてさっぱりわからなく、
自分で応用が効かなかった。
jQueryの記事をいろいろ見てやっと望みどおりの動作になりました。
ぶっちゃけ、Web開発経験ないので本当に辛い気がする。。。

リンククリックでAjaxを走らせるには

$(document).ready(function()
{
  $('#xxx a').live("click", function()
  {
    var page = getUrlVars($(this).attr('href'))['page'];
    $('#yyy').load(
          "search",
          {page: page}
          );
    return false;
  });
});

って感じになるんじゃないでしょうか。
まず、リンクをクリックするとそもそも、リンク先に飛んじゃうので
それを殺すのにreturn falseしてやる必要がある。

loadですげ変わる部分自体が
<div id=xxx>
<a href='search?page=x'>next</a>
って感じで<div id=xxx>自体を生成しなおすので
$('#xxx a').click(function()
でやると新しくすげ替えたタグを見つけられなくて通常のリンク処理が走ってしまう。
そこで、click関数では無くlive('click')にてイベントを処理すると行けるもんですね。
さらにloadにて投げるパラメータ?page=xはクリックした<a>タグの中の
href=に書いて有るためパラメータを自力で取得する必要がある。
href自体は
$(this).attr('href')で取れるのであとはパラメータを分解出来ればいいのだけれども
ぐぐったら現在のURLを分解するgetUrlVars()っつーサンプルがあったので改造して
引数でurlをわたして分解するように改造。(どう考えてもこっちのほうが汎用性あるとおもうんだけどな。。。)

function getUrlVars($url)
{
    var vars = [], hash;
    var hashes = $url.slice($url.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}
getUrlVars('http://www.jobeet.com/search?page=2')['page'];

とかするとはれて2と言う値がとれるようです。
でloadのパラメータに{page: page}とかって付け加えればOK。
この書き方はTwigでも同じなのでちょっと便利。

あとはpagerを含めてそのまんま処理すればOK。

例のaction.class.php内で

if ($request->isXmlHttpRequest())
{
  return $this->renderPartial('job/list', array(
    'pager' => $this->pager
   ));
}

とやって
searchSuccess.phpでは

<div id="yyy">
{{ 'job/list'|include_partial({pager: pager}) }}
</div>


とかyyy付けとけばそこ全体が変わると。

_listのページャ部分には
  <div id="xxx">

    <a href="<?php echo url_for('category', $category) ?>?page=1">
      <img src="/images/first.png" alt="First page" title="First page" />
    </a>
 といった感じで<div id="xxx">で囲っとけばページャだけにイベントが発生する仕組みと。

ぶっちゃけ、自分の処理はcategoryをモジュールで分けないで?category=hogeで処理するようにしているので、jobeetの処理まんまでは無いけれども、つまりは、そういった感じでやればいけるって話です。








2012年3月6日火曜日

sfTwigPluginに新しい関数を追加

 plugins\sfTwigPlugin\lib\view\sfTwigView.class.php
にある

class sfTwigView extends sfPHPView
{
 ....
 public function configure()
  {
    parent::configure();
    ....


    $this->twig->addFunction('test', new Twig_Function_Function('test'));
    function test(){echo 'test  function is called';}



とすれば

 <p> {{ test() }} </p>
 test  function is called
と表示される

ちなみに
 $this->twig->addFilter('test', new Twig_Filter_Function('test'));
とやると
 <p> {{ ''|test() }} </p>
と呼べる。

果たして、これを使ってPHPの組み込み関数を呼べるように出来るのか

2012年3月2日金曜日

プログラムの質問に「そもそも〇〇が問題だ」と答える意図

よく質問箱などで質問者に対して、
結構具体的なPGの質問に対して
「そもそもなぜそれが必要か考えなければいけません」って発言をみるんだが、
ちょっとした大きなお世話だ。(ちょっとと大きなが面白いところです)
問題をすべて解決して欲しいって頼んでいるわけではないのだから、
その質問に答えられる人が答えてあげればいいじゃないか。

回答する際に、何か間違ったことを言ったらいけないって思っているんだろうか。

根本的に問題点を考える事はとても重要で、そのアドバイスは正論だと思うけど、

おおきなお世話だ。

質問サイトのstack over flowはとても良いシステムだと思うよ。
「いいね!」 と 「いらね」 が選べるので、こう言うのは無視かいらねを選択できるわ。

2012年2月24日金曜日

sfTwigPluginの導入検証

symfony1.4を使っているのでテンプレートエンジンはphpのままなのですが、
Twigと言うのを導入検証してみました。
http://twig.sensiolabs.org/

プラグインは
https://github.com/henrikbjorn/sfTwigPlugin
にあり、docフォルダのインストレーションを参考にすればいけます。

ドキュメントにはデフォルトのlayoutを殺すように書いてありますが、
これは残したままでもよくて
layout.html
xxxSuccess.html
を新たに作成すればいいようです。

layout.hrml移行の際におもいっきり
<?php include_http_metas() ?>
と言うのが出てくるのでこれは
{{ ''|include_http_metas() }}
といった感じで置き換えます。


ちなみに
http://d.hatena.ne.jp/cocoiti/20091230
こちらを参考にさせていただいておりますので、
こちらを見れば全部わかると思います。




ここで、問題が出たのですが、

  <body>
ぼくはまちちゃん
{{ sf_content }}
  </body>
とすると
xxxSuccess.html
<p> こんにちは! こんにちは!</p>

と記述すると
<p>まで表示されてhtmlのタグがエスケープされてしまいます。

{% autoescape true %}
    Everything will be automatically escaped in this block
{% endautoescape %}

これで回避することが出来たのですがいちいちめんどくさかったので
new Twig_Extension_Escaper(false)
にしてしまったところエスケープがされなくなりましたがそれはそれで問題なので
必要なところに{{ name|e }}とエスケープを明示的に指示することになりました。

従来のsfPHPViewの感覚で使っては合わない形なのでしょうか。
従来のlayout.php
xxxxSuccess.php
の感じで適応していのですが、無理な相談なのでしょうか。

何かいい解決方法を知っている方がいたら教えてもらえないでしょうか。

ちなみに当方html php symfonyを最近いきなりまとめて始めたので
なにがなんだかさっぱりです。。。


2012年2月16日木曜日

Developers Game Party

http://kokucheese.com/event/index/27087/

ゲーム開発者がゲームを持ち寄り(複数本でも可)
みんなでゲームをプレイしながらワイワイと話し合う。

要はゲーム大会です。 

参加者は「ゲーム業界人」と言う事ですので
自分が作ったゲームを持ってきて、宣伝して頂いても構いません!

むしろ…

俺の作ったゲームのココを見てくれ!

とアピールして頂いた方が盛り上がります! 

もちろん、普通にゲームしたい人も歓迎いたします。


是非

2012年2月12日日曜日

インフルエンザ 都市伝説

自分を除く家族全員がインフルエンザにかかりました。 自分はインフルエンザを都市伝説だと思っているのでかかりません。 見たことないし。 そこでタミフルを処方される訳ですが 下の子が元々奇行が目立つのですが ちょっと奇行のクオリティが上がった感じになりました。 妙にテンション張ってるっつーか 見えない誰かと話したかと思えば カーテンに登ろうとしたり チャレンジャーでした。 上の子は普通です。

2012年2月6日月曜日

なんでもないです



フォロー/フォロワーが無く、非公開アカウントでつぶやく意味があるのだろうか
というところを見つめていきたい。

アカウントがあるといろいろ便利だからしばらく消さないでいようかと思う。

2012年2月2日木曜日

やっとJobeetのスタートラインに立てた

http://www.symfony-project.org/jobeet/1_4/Doctrine/ja/01
を参考にwindowsにApacheとMySQLとPHPと入れてやっていたのですが、
さっぱりうまくいかず
具体的には
\lib\vendor\symfony\lib\config\sfConfigCache?.class.php

 protected function loadConfigHandlers()
 {
   // manually create our config_handlers.yml handler
   $this->handlers['config_handlers.yml'] = new sfRootConfigHandler();

   // application configuration handlers
   require $this->checkConfig('config/config_handlers.yml');
の最後の部分でこけると言う現象でした。
仕方がないので 、ググッていたらxamppがxamppがと出てくるのでこれを入れてやってみることにしました。
http://blog.layer8.sh/ja/2011/12/21/windows%E4%B8%8A%E3%81%ABxampp%E3%82%92%E7%AB%8B%E3%81%A6%E3%81%A6symfony%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/
こちらを参考に
やったところ、symfonyの構成が
http://www.symfony-project.org/jobeet/1_4/Doctrine/ja/01
のjobeetと違うのでやり直し
symfonyのインストールをjobeetの方でやってみたらうまくいきました。

xamppをインストールすると案の定Apacheが起動しないので得意のSkype先生かと思いきや
PMB.exeというものが443ポートを奪っていて起動できないようでした。

これはLoLと言うゲームを試しに入れた際に入ったらしいのですが、こいつをアンイストールして(LoLはすでにアンインストールしてあった)無事起動したました。


svnでソースを管理するところまでを説明していますが、
今回はgit管理します。
http://www.symfony-project.org/jobeet/1_4/Doctrine/ja/01
ここの最後にも書いてありますが、

Yesod HelloWorld

http://www.yesodweb.com/book/
を一個ずつやってくことにします。
{-# LANGUAGE TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings #-}
import Yesod
data HelloWorld = Inputs
mkYesod "HelloWorld" [parseRoutes|
/ TestR GET
|]

instance Yesod HelloWorld where
  approot _ = ""
getTestR :: Handler RepHtml
getTestR = defaultLayout [whamlet|HelloWorld!|]

main :: IO()
main = warpDebug 3000 Inputs

ひとまず
http://localhost:3000/
で動作の確認は出来るのですが
文法もろくに分かってないので、なにしてるのかさっぱりです。

まず頭の{-# #-}ってなんなんでしょう?
こういうのってgoogleで対象にならないのでどうやって調べたらいいのかわからない。

2012年1月30日月曜日

今ここ

SymfonyでHPをつくることに
チュートリアルどおりにやろうとしても、環境が中途半端に構築されていたのでよくわからない
ローカルPCにSymfonyを入れよう
前提にApache,PHP,DBがいる
ApacheってWebServerソフトウエアーっつーのか
そういえばYesodってのがある
Yesod動かしてみたい
HaskellPlatformインストールYesodインストール
コンパイルエラー
調べる
Yesod動いた
何してたんだっけ?←今ここ

2012年1月29日日曜日

YesodがWindowsで動いたよ!

Yesodを勉強したくて下記の情報から手順どおりにやってもさっぱり起動まで行かなかったのですが
http://www.yesodweb.com/book/introduction
http://www.yesodweb.com/book/basics

やっと動きました。

手順どおりに行かなかったのは以下のとおりです。
cd my-first-project内でのcabal installが失敗します。
・perlが必要
ActivePerlをインストール

・alexのバージョンが古いと言われる
cabal install alex
で3.0以上のものを取得

・alex3.0を認識しない
よくわからないのですが
\Haskell Platform\2011.2.0.1\lib\extralibs\bin

\Users\xxxxx\AppData\Roaming\cabal\bin
に関連のファイルがありまして
cabal install alex して出来たものは
こっちに出来るのですが、 \Haskell Platform\2011.2.0.1\lib\extralibs\bin のほうが優先して見つけられて古いバージョンのalexに主導権が行ってしまうようでした。
仕方が無いので\Haskell Platform\2011.2.0.1\lib\extralibs\binの中にあるalex.exeを_alex.exeとかに変えてみたら
cabal install
が成功したので、ドキドキしながら
yesod devel
っすよ。
そんで
http://localhost:3000/
にアクセスしたら表示出るじゃないですか!
嬉しいです。
Hello Worldはまた次回!

2012年1月23日月曜日

VMWareでubuntuを入れる

windowsでyesodを試そうといろいろ格闘していたのですが、どうもうまくいかないのでubuntuでやってみることにします。
yesodで失敗するのはlanguage-javascriptのバージョンが違うってエラーで、cabal install language-javascriptすると今度はalexのバージョンが3じゃねーとか言われてalexを入れようとすると失敗。
わかんないのです。
ひとまずMVWarePlayerをインストールしてubuntuのisoをダウンロードして新規仮想マシンを作成したら出来た。
簡単なんだなー。

2012年1月16日月曜日

Unityコインプッシャーにて勉強

Unityコインプッシャー
Unityのラーニングに指定されたのでさくせいしました。

iPhoneゲームを20分間で作る【メダルプッシャー編】



Unity Web Player | WebPlayer

2012年1月12日木曜日

.*演算子 メンバポインタ?

http://d.hatena.ne.jp/redboltz/20120111/1326292284
をあきらさんがつぶやいているのを見て、だいぶわからなかったので調べてみました。
http://www.geocities.jp/ky_webid/cpp/language/034.html
にメンバ関数ポインタ.*演算子について書いてありました。

とにかく
struct A{ int value_; }
に対して
A a;
a.*&A::value_ = 20;
とアクセスできることがわかりました。
まあ、なんでも
a.* がメンバにアクセスする方法で
&A::value_ がクラスの先頭からのオフセット値なんだそうでした。
まだ、途中ですが、ものすごく気持ち悪かったのが
template <class MemPtr, MemPtr p>
MemPtr Access() { return p; }
a.*Access<int A::*, &A::value_>() = 40;
で、aのメンバではないものを呼び出しているようにしか見えませんでしたが
@hudepen先生に聞いたりいろいろしていたらなんとなくわかったのですが、

a.*(Access<int A::*, &A::value_>()) = 40;
っつーことらしく、
先に計算されてAccess<int A::*, &A::value_>()が&A::value_を返すので
a.*(&A::value_ ) = 40;
となるわけで問題ないですね。
よって
void A::set(int _value){ value_ = _value;}
を呼び出す際は
(a.*Access<int A::*, &A::value_>())(50);
です。
また、A内から呼ぶ際は
void A::call(){ (this->*&A::set)(50);}
とか
void A::call(){ (this->*Access<int A::*, &A::value_>())(50) ;}
となりますでしょうか。
ほんで、当のprivateに外部からアクセスする部分はまだ見てません。

2012年1月11日水曜日

遅延評価の把握

http://d.hatena.ne.jp/amachang/20061204/1165180769
こちらを参考にjavascriptで実験してみました。
Function.prototype.funcObj = function() { return { valueOf : this } };
var random = function()
{
  var res = Math.random();
  alert('randomL:'+res);
  return res;
}
function add(i, j) {
  alert('add');
  if(j>0){
    return i+j;
  }
  return j;
}

alert(add(random(), 1));
alert(add(random(), 0));
alert(add(random.funcObj(), 1));
alert(add(random.funcObj(), 0));
普通にrandom()を引数に渡すとadd()の第二引数に関係なく必ずrandom()が実行されますが、
random().funcObj()を引数に渡すと先にadd()が呼ばれて第二引数によってはrandom()が実行されないのを確認。

こんな感じでしょうか。
しかし、
Function.prototype.funcObj = function() { return { valueOf : this } };
これがいまいち理解出来ていなくて、連想配列としてvalueOfを誰かが自動的に呼んで、その際に関数を実行させないで、自分のオブジェクトを返すって事でいいのでしょうか。