5月 142013
 

メール配信には、「Yiiでメール周りの設定をする」にも書きましたが、mailerというエクステンションを利用しています。
今回、consoleコマンドから、メールを送信しようとした場合、

  • Yii::app()->controllerは設定されていない。
  • renderPartialが使えない。

という問題に遭遇したので、対処方法を書いておきます。
修正するのはmailerエクステンションのEMailerクラスのgetView関数です。具体的には、

public function getView($view, $vars = array(), $layout = null)
{
   $body = Yii::app()->controller->renderPartial($this->pathViews.'.'.$view, array_merge($vars, array('content'=>$this->_myMailer)), true); 
   list($subject,$body)=explode("\n",$body,2);
   $this->_myMailer->Subject=$subject;
   if ($layout === null) {
      $this->_myMailer->Body = $body;
   }
   else {
      $this->_myMailer->Body = Yii::app()->controller->renderPartial($this->pathLayouts.'.'.$layout, array_merge($vars, array('content'=>$body)), true);
   }
}

public function getView($view, $vars = array(), $layout = null)
{
  //Yii::app()->controllerが設定されているかチェック
  //設定されてなければsiteコントローラをコントローラとして利用
  $controller=Yii::app()->controller;
  if(!$controller)
    $controller = new CController('site');

  //renderPartialのかわりにrenderInternalを利用
  $body = $controller->renderInternal(YiiBase::getPathOfAlias($this->pathViews.'.'.$view).'.php', array_merge($vars, array('content'=>$this->_myMailer)), true);
  list($subject,$body)=explode("\n",$body,2);
  $this->_myMailer->Subject=$subject;
  if ($layout === null) {
    $this->_myMailer->Body = $body;
  }
  else {
    $this->_myMailer->Body = $controller->renderInternal(YiiBase::getPathOfAlias($this->pathLayouts.'.'.$layout).'.php', array_merge($vars, array('content'=>$body)), true);
  }
}

のようにしたらOKです。

ちょっと解説しておきます。
まず、Yii::app()->controllerが設定されているかチェックして、設定されていないようなら、siteコントローラを利用することにします。(siteコントローラでなくても構いません)

次にrenderPartialですが、

CConsoleApplication does not have a method named "getTheme"

のようなエラーが出るので、かわりにrenderInternalを利用します。
ただし、renderInternalは、viewファイルの設定をフルパスでする必要があるので、

YiiBase::getPathOfAlias($this->pathViews.'.'.$view).'.php'

のようにYiiBase::getPathOfAlias関数を利用して、「$this->pathViews.’.’.$view」をYiiのパスエイリアスからフルパスに変換し、最後にファイルのエクステンションである「.php」を付加するようにします。

 Posted by at 5:27 PM  Tagged with:
5月 142013
 

YiiのconsoleコマンドでcreateAbsoluteUrlを利用すると

Undefined index: SERVER_NAME

のようなエラーがでて期待する動作になりません。
解消するには、config/console.phpで

   'components'=>array(no

     'request' => array(
       'hostInfo' => 'http://eventjam.jp',
       'baseUrl' => '',
       'scriptUrl' => '',
     ),

のような感じにhostInfoを設定するとよいです。
ちなみにこうした場合、

$url=Yii::app()->createAbsoluteUrl('event/v',array('id'=>456));

を実行すると$urlには、

http://eventjam.jp/event/v?id=456

が設定されるようになります。

 Posted by at 4:25 PM  Tagged with:
4月 182013
 

YiiのCJuiTabsでタブを用意し、タブ内でajaxを使って、CListViewのデータを表示しようとしたとき、ページネーションがうまくいかなかったので、注意点を書いておきます。

まず、タブを表示するCjuiTabsのwidgetは以下のような感じにします。

<?php 
$gcode=(isset($gcode) && !empty($gcode)) ? $gcode: null;

$this->widget('zii.widgets.jui.CJuiTabs', array(
  'tabs' => array(
    'お勧め' => array('ajax' => $this->createUrl('search/rec',array('mc'=>$gcode))),
    'まもなく' => array('ajax' => $this->createUrl('search/soon',array('mc'=>$gcode))),
    '人気' => array('ajax' => $this->createUrl('search/pop',array('mc'=>$gcode))),
    '新着' => array('ajax' => $this->createUrl('search/new',array('mc'=>$gcode))),
    'メンバー' => array('ajax' => $this->createUrl('search/member',array('mc'=>$gcode))),
    'レッスン' => array('ajax' => $this->createUrl('search/lesson',array('mc'=>$gcode))),
  ),
  // additional javascript options for the tabs plugin
  'options' => array(
    'collapsible' => true,
  ),
  // set id for this widgets
  'id'=>'dataTabs',
));

動作ですが、「お勧め」や「新着」などのタブをクリックすると、SearchController.phpのactionRecやactionNewがajaxで呼び出されるという感じです。

CjuiTabsの使い方やリファレンスは
http://www.yiiframework.com/doc/api/1.1/CJuiTabs/
を参考にしてください。

呼び出されるactionRecやactionNew関数は以下のような感じです。
両方共、ほぼ処理が同じなので、内部で_getData関数を呼び出しています。

動作としては、モデルからdataProviderを用意し、ajax経由の場合は、renderPartialで書きだす、それ以外はrenderで書きだすという感じです。

private function _getData($cssid,$order=null,$mc=null,$top=true,$soon=false)
{
  $this->cn=new CNumberFormatter('ja');
  $view=$top ? 'view4top' : 'view4detail';
  if($mc && !Category::mcategory($mc))
  {
    if (Yii::app()->request->isAjaxRequest)
    {
      Yii::app()->end(200, true);
    }
    else
      throw new CHttpException(404,'The requested page does not exist.');
  }

  $event=new Event();
  $dataProvider = $event->cache(Search::SEARCH_CACHE_SECONDS)->load4Top($order,$mc,$top,null,true,$soon);

  if (Yii::app()->request->isAjaxRequest)
  {
    $this->renderPartial($view, array('dataProvider'=>$dataProvider,'dispCategory'=>($mc?false:true),'cssid'=>$cssid), false, true);
    Yii::app()->end(200, true);
  }
  else
    $this->render($view,array('dataProvider'=>$dataProvider,'dispCategory'=>($mc?false:true),'cssid'=>$cssid));
}

public function actionNew($mc=null,$top=true)
{
  $cssid='new_'.($mc?$mc:'0').'_'.($top?'1':'0');
  $this->_getData($cssid,'t.id desc',$mc,$top);
}

public function actionRec($mc=null,$top=true)
{
  $cssid='rec_'.($mc?$mc:'0').'_'.($top?'1':'0');
  $this->_getData($cssid,'t.rank desc, t.use_ej asc,t.id desc',$mc,$top);
}

まず、ここで、注意するのは、

$this->renderPartial($view, array('dataProvider'=>$dataProvider,'dispCategory'=>($mc?false:true),'cssid'=>$cssid), false, true);

の4番目の引数のtrueです。これを設定していないとページネーションの際にajaxとして動作しません。(設定していると、actionNewなどを呼び出した際に、Yii::app()->clientScript->registerScriptで登録したスクリプトや動的に生成されたスクリプトを適切な場所に出力してくれます)

renderPartialのリファレンスは
http://www.yiiframework.com/doc/api/1.1/CController/#renderPartial-detail
です。

ついで、actionRecやactionNewで呼び出されるview4topなどのビューについてです。

<?php $this->widget('bootstrap.widgets.TbListView', array(
  'id'=>'lview_'.$cssid,
  'dataProvider' => $dataProvider,
  'itemView' => '_search4top',
  'viewData'=>array('dispCategory'=>$dispCategory),
  'template'=>'{items} {pager}',
)); ?>

ここで2つ目の注意点です。注意するのは以下のようにidを設定するということです。

'id'=>'lview_'.$cssid,

idを設定しない場合、Yiiは自動的に「yw0」のようなidを割り当てます。
この場合、idがかぶってしまい、ajaxの処理がうまくいきません。

上記2つの点、とくに1番目の点にたどり着くまで4時間程度かかりました。
辛かった‥。

 Posted by at 7:18 PM  Tagged with: