ウェブインコ

インコの技術メモ

CakePHP2.3

ModelとHelperと日本語化ファイルを異なるappで共有
app_user から app の中を参照する例。
App::build(array(
  'Model' => array(ROOT.DS.'app'.DS.'Model'.DS),
  'View/Helper' => array(ROOT.DS.'app'.DS.'View'.DS.'Helper'.DS),
  'Locale' => array(ROOT.DS.'app'.DS.'Locale'.DS),
));
ln -s でも良いけど、引っ越しすることを想定すると極力シンボリックリンクは少ない方が良いので。

モデルから他のモデル、Modelから他のModel
App::import('Model','Product');
$Product= new Product;
$Product->find('all');

ページネートと検索
迷走中だけどとりあえずメモ。
条件をセッションに覚えさせておき、新たに条件が入ってきたら上書きします。
検索条件+タブ(有効・無効・ぜんぶ、とか、既読・未読・全部、等)を想定しています。
・その1
コントローラー(タブのみ)
  public function index() {
    $this->OrderHeader->recursive = 0;
//    $this->set('orderHeaders', $this->paginate());

    // 検索条件セット
    $setCconditions = $this->getCconditions('OrderHeader', null, null, 'status');
    // 返り血に選択済みタブがあればセット&オプションから削除
    $selectedStatus = '0';
    if(isset($setCconditions['tab'])){
      $selectedStatus = $setCconditions['tab'];
      unset($setCconditions['tab']);
    }
    $this->set('selectedStatus', $selectedStatus);
    $this->paginate = $setCconditions;
    $res = $this->paginate();
    $this->set('orderHeaders', $res);
  }

ビュー(タブ)
<div class="orderHeaders index">
  <h2><?php echo __('Order Headers'); ?></h2>
  <?php echo $this->element('statuspaginate'); ?>
?

エレメント(タブ)
statuspaginate.ctp
<?php
  if(!empty($status)){
    $paginator->options(array('url' => array('?' => array('status' => $status))));
  }
?>
<div class="status">
  <div style="float: right;">
    <?php   echo $this->Paginator->counter(array('format' => __('Page {:page} / {:pages}, ( {:start} - {:end} / {:count} )'))); ?>
  </div>
  <div style="float: left;">
    <?php echo (isset($selectedStatus)and($selectedStatus===0))?'<span style="color: #F00;">有効</span>' :$this->Html->link('有効', array('action' => 'index?status=0')); ?> 
    <?php echo (isset($selectedStatus)and($selectedStatus==='1'))?'<span style="color: #F00;">無効</span>' :$this->Html->link('無効', array('action' => 'index?status=1')); ?> 
    <?php echo (isset($selectedStatus)and($selectedStatus==='allstatus'))?'<span style="color: #F00;">全部</span>' :$this->Html->link('全部', array('action' => 'index?status=allstatus')); ?> 
  </div>
</div>

・その2
コントローラー(検索有り)
  public function index() {
    // 検索条件セット
    $setCconditions = $this->getCconditions('OrderHeader', null, null, 'status');
    if(!empty($setCconditions['data'])){
      $this->data = $setCconditions['data'];
    }
    // このページ独自のルールに成型
    if(!empty($setCconditions['conditions']['OrderHeader.date'])){
      $setCconditions['conditions']['OrderHeader.date LIKE'] = '%'.$setCconditions['conditions']['OrderHeader.date'].'%';
    }
    if(isset($setCconditions['conditions']['OrderHeader.date'])){
      unset($setCconditions['conditions']['OrderHeader.date']);
    }
    $this->OrderHeader->recursive = 0;
    $this->paginate = $setCconditions;
    $this->set('orderHeaders', $this->paginate());
  }

ビュー(検索)
<div class="orders index">
  <h2><?php echo __('Orders'); ?></h2>
<div>
<?php
  echo $this->Form->create('OrderHeader');
  echo $this->Form->input('level_id', $this->Html->selectLevels((isset($this->request->data['OrderHeader']['level_id']))?$this->request->data['OrderHeader']['level_id']:1));
  echo $this->Form->input('date');
  echo $this->Form->input('status', array('type'=>'hidden', 'value'=>'0'));
  echo $this->Form->end(__('Submit'));
?>
</div>
?

・その1、その2共通
AppController.php
  function getCconditions($model=null, $data=null, $params=null, $tabname=null) {

    $tab = 0; // ★デフォの status を 0 とします
    $all = 'allstatus'; // ★status条件エスケープ文字を allstatus とします
    $limit = 10; // ★表示数

    // セッション呼び出し
    $searchItems = $this->Session->read('searchItems');
    $searchItems = (empty($searchItems[$model]))?'':$searchItems[$model];

    // 入力値セット
    // 明示的に指定されていればそちらを優先
    // ($data があれば $data, 無ければ $this->request->data, 両方なら $data)
    $data = ((empty($data))and(!empty($this->request->data))) ?$this->request->data :$data;
    $params = ((empty($params))and(!empty($this->params))) ?$this->params :$params;
    // $this->request->data ハッシュで受け取ります
    // passの場合 ex.)/index/status/1/page/2 配列で受け取ります
    $pass = $params->params['pass'] ?$params->params['pass'] :'';
    // namedの場合 ex.) /index/status:1/page:2 ハッシュで受け取ります
    $named = $params->params['named'] ?$params->params['named'] :'';
    // queryの場合 ex.)/index?status=1&page=2 ハッシュで受け取ります
    $query = $params->query ?$params->query :'';

    // 入力値があれば上書き
    if((!empty($data[$model]))or(!empty($pass))or(!empty($named))or(!empty($query))){

      // 全ての入力値をハッシュ化 【http → $items】
      $items = array();
      if(!empty($data[$model])){
        $items = $data[$model];
      }
      // 混在していてもカバーできるよう elseif を使わない
      if(!empty($pass)){
        foreach($pass as $key => $val){if($key % 2 != 1){$items[$val] = $pass[$key+1];}}
      }
      if(!empty($named)){
        foreach($named as $key => $val){$items[$key] = $val;}
      }
      if(!empty($query)){
        foreach($query as $key => $val){$items[$key] = $val;}
      }

      // タブはstatusの値。明示的にタブ名が指定されていればそちらを優先。
      if(!empty($items['status'])){
        $tab = $items['status'];
      }
      if(isset($items['tabname'])){
        $tab = $items['tabname'];
      }

      // 検索項目以外を削除しつつセット 【$items → $searchItems】
//      if(isset($items['url'])){unset($items['url']);}
      // 順序
      if(isset($items['sort'])){
        $searchItems[$model][$tab]['sort'] = $items['sort'];
        unset($items['sort']);
      }
      if(isset($items['direction'])){
        $searchItems[$model][$tab]['direction'] = $items['direction'];
        unset($items['direction']);
      }
      // ページ
      if(isset($items['page'])){
        $searchItems[$model][$tab]['page'] = $items['page'];
        unset($items['page']);
      }

      // 条件だけになりました
      // 検索条件が無い場合でもセッションにあれば呼び出し(ページネート・出戻りと見なし)ます
      if(empty($items)){
        if(!empty($searchItems[$model][$tab]['data'][$model])){
          $items = $searchItems[$model][$tab]['data'][$model];
        }
      }else{
        // 検索条件有り:data以外ならクリア、dataなら入力内容復帰用に保存
        if(empty($data)){
          $searchItems[$model][$tab]['data'] = '';
        }else{
          $searchItems[$model][$tab]['data'] = $data;
        }
      }

      // 条件だけになったのでキーにモデル名を付加
      // 値がエスケープ値なら無視
      $itemsR = array();
      foreach($items as $key => $val){
        if($val != $all){$itemsR[$model.'.'.$key] = $val;}
      }
      $searchItems[$model][$tab]['conditions'] = $itemsR;

      // ページネート時にどのタブを引き継ぐかを保存
      $searchItems[$model]['selectingtab'] = $tab;

    } // 入力値があれば上書き

    // searchItems から成型 【$searchItems → $option】
    // 最低必要項目セット
    if(empty($searchItems)){
      $searchItems[$model][$tab]['conditions'] = array($model.'.status' => $tab);
      $searchItems[$model][$tab]['sort'] = 'id';
      $searchItems[$model][$tab]['direction'] = 'desc';
      $searchItems[$model]['selectingtab'] = $tab;
    }else{
      if((empty($searchItems[$model][$tab]['conditions']))and($tab != $all)){
        $searchItems[$model][$tab]['conditions'] = array($model.'.status' => $tab);
      }
      if(empty($searchItems[$model][$tab]['sort'])){$searchItems[$model][$tab]['sort'] = 'id';}
      if(empty($searchItems[$model][$tab]['direction'])){$searchItems[$model][$tab]['direction'] = 'desc';}
      $tab = $searchItems[$model]['selectingtab'];
    }

    // 順序
    $direction = (isset($searchItems[$model][$tab]['direction'])) ?$searchItems[$model][$tab]['direction'] :'';
    if((isset($searchItems[$model][$tab]['sort']))and($searchItems[$model][$tab]['sort'] != 'clear')){
      $options['order'] = $model.'.'.$searchItems[$model][$tab]['sort'].' '.$direction;
    }else{
      $options['order'] = $model.'.id DESC';
    }
    // ページ
    if(!empty($searchItems[$model][$tab]['page'])){
      $options['page'] = $searchItems[$model][$tab]['page'];
    }
    // 検索条件
    if(!empty($searchItems[$model][$tab]['conditions'])){
      $options['conditions'] = $searchItems[$model][$tab]['conditions'];
    }

    // 表示数
    $options['limit'] = $limit;

    // 選択タブ
    $options['tab'] = $tab;

    // 画面復帰用データ
    $options['data'] = (empty($searchItems[$model][$tab]['data']))?'':$searchItems[$model][$tab]['data'];

    // セッションに検索条件を保存
    if(!empty($searchItems)){
      $setSearchItems[$model] = $searchItems;
      $this->Session->write('searchItems', $setSearchItems);
    }

    return $options;
  }

Fatal error: Class 'AppController' not found in ディレクトリ名/lib/Cake/Controller/CakeErrorController.php on line 32
AppControllerが無い、とか一瞬びびるエラーですが嘘です。
AppController.php にプログラムを記述するときには、その文章が間違っている(文末の ; が抜けてる等)だけでこのエラーがでます。

ページネート(paginate)で有り得ないページを指定するとエラーになる
1.3とかだとエラーではなく空で返してくれてました。
基本無視して良いかと思いましたが、一覧閲覧中にデーターが変動してページが消失する事は有り得るので修正するとす。
/lib/Cake/Controller/Component/PaginatorComponent.php
237
/* エラーにしない
        if ($requestedPage > $page) {
            throw new NotFoundException();
        }
*/