1

私は2つのテーブルを持っています:

注文

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 モデルのデフォルトの注文プロパティを追加しようとしましたが、containable では機能しないようで、デフォルトのlimitプロパティを追加できません。

class OrderPrice extends AppModel {

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

2 に答える 2

1

これは、それを行う方法に関する特定の問題ではなく、コードを配置する場所に関する問題だと思います。(私の意見では、あなたと同じように Containable を使用するのが理想的です)

「しかし、これは毎回それを追加する必要があることを意味します。これは、注文価格を大量に取得するので理想的ではありません。これを可能な限りモデルに入れる方法で実際に行うことができるので、私は繰り返さなくていい。」

これは、コントローラーの複数の場所にあなたを入れていると思いますfind()...あなたのポイントには、いつでも任意のコントローラーからアクセスできるモデルにメソッドが必要です...次のようなもの:

//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()度も繰り返す必要がなくなります。メソッドを拡張して、制限、注文、日付範囲などに渡されるさまざまなパラメーターを許可することもできますが、モデル内の 1 つの場所にメソッドがあります。

補足: 私はしばしば 2 つの方法を持っています - この場合getOrder()getOrders()- 1 つ目は 1 つの注文を取得するための非常に単純な方法で、2 つ目は多くの異なる方法 (方向、制限、結合) で注文を引き出すことを可能にするすべてのパラメーターを備えています。 ..etc.これが理想的かどうかはわかりませんが、私にはぴったりです。

于 2013-01-07T17:19:29.140 に答える
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
);

アプリ/モデル/注文.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'
    )
)

履歴価格に対してこれと同じことを行う方法を理解する必要があるだけで、注文履歴の最初または最後だけでなく、いつでも価格に参加できるようになります。

于 2013-01-08T11:10:06.510 に答える