2013-01-07 34 views
1

最新的入门我有两个表:查询加盟关联模型表(CakePHP的)

订单

id | timestamp 
-------------------------- 
1 | 2013-05-01 12:56:33 

order_prices订单价格的

此表存储快照。订单下达后,第一个条目将以原始价格制成。之后,价格可以通过管理系统进行更改,所以当价格改变时,会记录新的价格。

id | order_id | price | timestamp 
-------------------------------------------------- 
1 | 1   | 400.00 | 2013-05-01 12:56:33 
1 | 1   | 450.00 | 2013-06-01 18:07:35 
1 | 1   | 300.00 | 2013-07-01 17:42:16 

模式

class Order extends AppModel { 

    public $hasMany = array('OrderPrice'); 
} 


class OrderPrice extends AppModel { 

    public $belongsTo = array('Order'); 
} 

所以我的问题是如何在订单执行查找,而在“当前”的价格(拉即在order_prices表的最新条目的订单),还是原始价格,或任何历史时间点的价格?

我想以最轻松的方式做到这一点,以便重复使用。我不知道这是否可以通过虚拟领域完成,但这是理想的,因为那样我就可以在需要的时候提供当前的订单价格。

我的解决方案,到目前为止,使用中可容纳的行为:

$this->Order->find('first', array(
    'contain' => array(
     'OrderPrice' => array(
      'order' => 'OrderPrice.timestamp DESC', 
      'limit' => 1 
     ) 

)); 

但是,这意味着我必须每一次,这是不理想的,因为我会得到订单价格增添了不少。我真的可以用尽可能多的方式将这些内容加入到模型中,这样我就不必重复它了。

我试着为OrderPrice模型添加一个默认的订单属性,但它似乎不适用于可容纳的,并且您不能添加默认的limit属性。

class OrderPrice extends AppModel { 

    // Doesn't work from containable 
    public $order = 'ObeOrderPrice.timestamp DESC'; 
+0

看看可遏制的行为。然后你就可以为第二个表添加条件,比如比较时间戳等... http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html –

+0

是的,我使用可容纳很多。我将重新阅读本书,看看是否有一种简单的方法可以使用易于理解的方式来完成。不幸的是,这将需要重复的代码很多,总是得到我的订单的价格。 – BadHorsie

+0

如果我得到时间,当我回到家,生病看看我能不能制定我如何想象你可以解决这个问题 –

回答

0

好的,我有我认为是最好的解决方案,除非任何人有任何其他想法。

我将OrderPrice的可容纳选项作为变量存储在模型中,这样我就不必在任何时候将订单价格加入当前/原始价格时重写它们。我可以从任何模型中使用它们。

然后,我有一些自定义查找类型,允许我使用任何参数执行普通查询,同时自动加入自定义/原始价格。

应用/型号/ OrderPrice.php

/** 
* Containable array options for finding current price 
* 
* @var array 
*/ 
public $containCurrent = array(
    'fields' => 'OrderPrice.price', 
    'order' => 'OrderPrice.timestamp DESC', 
    'limit' => 1 
); 

/** 
* Containable array options for finding the original price 
* 
* @var array 
*/ 
public $containOriginal = array(
    'fields' => 'OrderPrice.price', 
    'order' => 'OrderPrice.timestamp', 
    'limit' => 1 
); 

应用/型号/ Order.php

/** 
* Custom find type which automatically joins the current order price 
* 
* @param string $state 
* @param array $query 
* @param array $results 
* @return array 
* @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#creating-custom-find-types 
*/ 
protected function _findJoinCurrentPrice($state, $query, $results = array()) { 
    if ($state == 'before') { 
     $query['contain']['OrderPrice'] = $this->OrderPrice->containCurrent; 
     return $query; 
    } else { 
     $results = $this->_refinePriceFindResults($query, $results); 
    } 
    return $results; 
} 

/** 
* Custom find type which automatically joins the original order price 
* 
* @param string $state 
* @param array $query 
* @param array $results 
* @return array 
* @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#creating-custom-find-types 
*/ 
protected function _findJoinOriginalPrice($state, $query, $results = array()) { 
    if ($state == 'before') { 
     $query['contain']['OrderPrice'] = $this->OrderPrice->containOriginal; 
     return $query; 
    } else { 
     $results = $this->_refinePriceFindResults($query, $results); 
    } 
    return $results; 
} 

/** 
* Refine the results of a custom price find 
* 
* If the find returns only one order and/or one price, the data for both 
* models will be returned as element [0] of an otherwise empty array. 
* This method modifies the results array by removing the redundant wrapper 
* array, so that the model data is structured like a normal find('first'). 
* 
* @param array $query The query array from the custom find method 
* @param array $results The results array from the custom find method 
* @return array The modified results 
*/ 
protected function _refinePriceFindResults($query, $results) { 
    if (empty($results)) { 
     return false; 
    } 
    if (isset($query['conditions']['id']) || isset($query['conditions']['Order.id'])) { 
     $results = array_shift($results); 
    } 
    if (isset($results['OrderPrice']['0'])) { 
     if (count($results['OrderPrice']) == 1) { 
      $results['OrderPrice'] = array_shift($results['OrderPrice']); 
     } 
    } 
    return $results; 
} 

控制器

// I can perform a normal find, using any number of complex parameters. 

$this->Order->find('joinCurrentPrice', array(
    'fields' => array('Order.type_id'), 
    'conditions' => array('Order.id' => $id), 
    'contain' => array(
     'Customer' => array(
      'fields' => array('Customer.first_name', 'Customer.last_name') 
     ) 
    ) 
)); 


// And the result is the same as the normal find, but the price model is 
// automatically joined without any extra work. 

array(
    'Order' => array(
     'type_id' => 2, 
     'id' => '843654' 
    ), 
    'Customer' => array(
     'id' => 7348, 
     'first_name' => 'Joe', 
     'last_name' => 'Bloggs' 
    ), 
    'OrderPrice' => array(
     'price' => '549.00', 
     'order_id' => '843654' 
    ) 
) 

我只需要弄清楚如何为历史价格做同样的事情,所以我可以在订单的历史中随时加入价格,而不仅仅是第一个或最后一个。

1

我认为这不是一个特定的问题,你做这件事的方式和更多的问题与你放置代码的位置有关。 (使用中可容纳就像你是在我看来,理想的)

“不过,这意味着我要补充一点,每一次,这是不理想的 我会得到订单价格很多。我真的可以用 的方式将尽可能多的这一点放到模型中,所以我没有 来重复它。“

这让我觉得你把你的find()在多个地方的控制器(S)...你的观点,你应该在你的模型,可以从任何控制器在任何时候访问方法。 ..是这样的:

//OrdersController 
public function view($id) { 
    $order = $this->Order->getOrder($id); 
    $this->set(compact('order')); 
} 

//Order model 
public function getOrder($id) { 
    return $this->Order->find('first', array(
     'contain' => array(
      'OrderPrice' => array(
       'order' => 'OrderPrice.timestamp DESC', 
       'limit' => 1 
      ) 
    )); 
} 

这将使所以你从字面上就不必重复你contain()不止一次。您还可以扩展该方法,以允许通过限制,顺序,日期范围等等的不同参数 - 但您仍然在模型中的单个位置上使用该方法。注意:我通常有两种方法 - 在这种情况下,getOrder()getOrders() - 第一种方法是获得单一订单的非常简单的方法,第二种方法的所有参数允许我以多种不同的方式提取订单,方向,限制,加入等等等等。我不确定这是否理想,但它适合我。

+0

我在我的代码中非常整洁,并且讨厌重复代码,所以我通常使用胖模型,瘦控制器原理。这就是为什么我想要最好的可重用解决方案。我目前正在研究一种使用可重用模型方法的解决方案,但这种解决方案比我想的要复杂得多。例如,如果我想获得当前订单价格,但是我正在执行与订单模型不同的模型的查找?我有一个解决方案,但它不是完美的(将发布一点)。 – BadHorsie

+0

@BadHorsie:我很困惑 - 如果你想获得“当前订单价格”,为什么你会“在不同的模型上执行查找,而不是订单模型”? – Dave

+0

因为我可能会在不同的模型上进行查找,该模型将连接Order模型。如果我需要价格以及该订单,我需要能够将OrderPrice模型加入到该订单中。 – BadHorsie