0

この種の問題を解決するためのより良い解決策を探しています。キーワード、カテゴリ、開始日、終了日、価格帯(最小価格、最大価格)、その他のフィールドなど、多くの検索オプションを使用してアパートの高度な検索をページングする必要があります... 2 つの日付を選択した場合、各アパートの家賃。価格を計算するには、virtualField や 1 つ以上のサブクエリを使用できませんが、多くの計算を実行するため、Apartment モデルの関数を使用する必要があります...

そこで、コールバック afterFind を使用してレンタル価格を計算し、「列」 Rental_price をクエリ結果の配列に追加することにしました。

public function afterFind($results, $primary){
   if($this->dateFrom && $this->dateTo){
      foreach ($results as $key => $val) {
         if(isset($val['Apartment']['id'])){
            $results[$key]['Apartment']['rental_price'] = $this->calculateRentalPrice($val['Apartment']['id'], $this->dateFrom, $this->dateTo);
         }
      }
   }
   return $results;
}

コントローラー上:

$this->paginate = array( ... ); // Array with the query
$apartments = $this->paginate('Apartment');

// EDIT
foreach ($apartments as $key => &$apartment) {
   if($apartment['Apartment']['rental_price'] < $priceMin || $apartment['Apartment']['rental_price'] > $priceMax){
      unset($apartments[$key]);
   }
}
$this->set('apartments', $apartments);

問題は、最小価格と最大価格で配列 $apartments を再フィルター処理したいということですが、$apartments を直接操作すると、ページネーションに問題があります。この種のシナリオを解決する最善の方法は何ですか?

   // EDIT
   public function calculateRentalPrice($apartmentId, $dateFrom, $dateTo){
      $from = new DateTime($dateFrom);
      $to = new DateTime($dateTo);
      $period = new DatePeriod($from, DateInterval::createFromDateString('1 day'), $to);
      $rentalPrice = 0;
      foreach ($period as $day){
         $date = $day->format("Y-m-d");
         $dailyPrice = $this->ApartmentSeason->getDailyPrice($apartmentId, $date);
         $rentalPrice += $dailyPrice; 
      }
      return $rentalPrice;
   }

   public function getDailyPrice($apartmentId, $date){
      $apartmentSeason = $this->find('first', array(
         'conditions' => array(
            'ApartmentSeason.apartment_id' => $apartmentId,
            "'{$date}' BETWEEN ApartmentSeason.date_from AND ApartmentSeason.date_to", 
            "ApartmentSeason.date_to != " => $date, 
         )
      ));
      $dailyPrice = $apartmentSeason['ApartmentSeason']['price'] / 7;
      return $dailyPrice;
   }
4

1 に答える 1

0

これを解決する 1 つの方法は、日付範囲内にある各価格のモデルをバインドし、それらを仮想フィールドで合計することです。この問題を解決するためのよりエレガントな方法があるかもしれませんが、プロシージャを使用しない方法は考えられません。これは、再利用可能でテスト可能な部分に分割することもできます。

$from = new DateTime($this->dateFrom);
$to = new DateTime($this->dateTo);
$period = new DatePeriod($from, DateInterval::createFromDateString('1 day'), $to);
$i = 0;
$sums = array();
// bind a new model for each "season" price
foreach ($period as $day) {
  $date = $day->format("Y-m-d");
  // create a new alias
  $alias = "ApartmentSeasonPrice$i";
  $params = array(
    'className' => 'ApartmentSeason',
    'foreign_key' => 'apartment_id',
    'conditions' => array(
      "'{$date}' BETWEEN $alias.date_from AND $alias.date_to",
      "$alias.date_to != " => $date
  );
  // attach the model
  $this->Apartment->bindModel(array(
    'hasOne' => array(
      $alias => $params;
    )
  ));
  // save the column we want to sum
  $sums[] = "$alias.price";
}
// total them up in a virtual field
$this->Apartment->virtualFields['rental_price'] = 'COALESCE(SUM('+implode(',', $sums).', 0))';
// paginate
$this->set('apartments', $this->paginate());
于 2012-10-08T15:16:30.657 に答える