在cakeHP应用程序中自动运行不相关的操作


Automatically running an unrelated action in cakePHP application

我正在开发一个小型应用程序,为自定义产品提供报价。这是我的第一个cakeHP应用程序。

添加或保存产品时,会自动计算产品的许多字段。计算使用存储在"Rates"表中的valuse来执行运算。这些"费率"也可以由管理员更新,并有自己的模型、视图和控制器。然而,当费率更新时,我需要重新计算所有现有产品,就好像用户已经访问/products/edit并单击保存一样。

我真的不知道当利率被保存到数据库时如何触发

这是我的产品控制器编辑功能:

public function edit($id = null) {
    $this->Product->id = $id;
    if (!$this->Product->exists()) {
        throw new NotFoundException(__('Invalid product'));
    }
    if ($this->request->is('post') || $this->request->is('put')) {
        $this->loadModel('Rate', '1');
        $Od = $this->request->data['Product']['material_od'] / 2;
        $materialMass = $this->Rate->field('steel_mass') * $this->request->data['Product']['material_length'] * (pi() * $Od * $Od );
        $this->Product->saveField('material_mass', $materialMass);
        $materialCost = $materialMass * $this->Product->Material->field('cost', array('Material.id' => $this->request->data['Product']['material_id']));
        $this->Product->saveField('material_cost', $materialCost);
        $materialMarkupRate = $this->Rate->field('material_markup') + 1;
        $wasteMarkupRate = $this->Rate->field('waste_markup') + 1;
        $materialMarkupCost = $materialCost * $materialMarkupRate * $wasteMarkupRate;
        $this->Product->saveField('material_markup_cost', $materialMarkupCost);
        $setupCost = $this->request->data['Product']['number_tools'] * $this->Rate->field('tool_time') * $this->Rate->field('setup_rate');
        $this->Product->saveField('setup_cost', $setupCost);
        $cuttingCost = $this->request->data['Product']['cutting_time'] * $this->Rate->field('cutting_rate');
        $this->Product->saveField('cutting_cost', $cuttingCost);
        $machiningCost = $this->request->data['Product']['machining_time'] * $this->Rate->field('machining_rate');
        $this->Product->saveField('machining_cost', $machiningCost);
        $polishingCost = $this->request->data['Product']['polishing_time'] * $this->Rate->field('polishing_rate');
        $this->Product->saveField('polishing_cost', $polishingCost);
        if ($this->Product->save($this->request->data)) {
            $this->Session->setFlash(__('The product has been saved'));
            $this->redirect(array('action' => 'index'));
        } else {
            $this->Session->setFlash(__('The product could not be saved. Please, try again.'));
        }
    } else {
        $this->request->data = $this->Product->read(null, $id);
    }
    $materials = $this->Product->Material->find('list');
    $this->set(compact('materials'));
}

以及我的RatesController编辑功能:

public function edit($id = null) {
    $this->Rate->id = $id;
    if (!$this->Rate->exists()) {
        throw new NotFoundException(__('Invalid rate'));
    }
    if ($this->request->is('post') || $this->request->is('put')) {
        if ($this->Rate->save($this->request->data)) {
            $this->Session->setFlash(__('The settings have been saved.  Please update your products.'));
            $this->redirect(array('controller' => 'products', 'action' => 'index'));
        } else {
            $this->Session->setFlash(__('The rate could not be saved. Please, try again.'));
        }
    } else {
        $this->request->data = $this->Rate->read(null, $id);
    }
}

如何从第二个触发第一个?

我对此还很陌生,所以非常欢迎所有的建议和批评!

非常感谢,Ralph

有几个问题不仅可以帮助您清理要做的事情,还可以帮助您以更高效的方式完成。目前,每次调用$this->Product->saveField时,都会访问数据库。如果这是一个很少人使用的小应用程序,那也没什么大不了的。然而,您应该养成编写良好的干净代码的习惯。你的变量名很棒!易于理解。我首先建议计算所有的值,然后像这样访问数据库:

...
    $this->loadModel('Rate', '1');
    $materialMarkupRate = $this->Rate->field('material_markup') + 1;
    $wasteMarkupRate = $this->Rate->field('waste_markup') + 1;
    $Od = $this->request->data['Product']['material_od'] / 2;
    // make sure you have a hidden id form in the view, otherwise you will need to set it here
    $this->request->data['Product']['material_mass'] = $this->Rate->field('steel_mass') * $this->request->data['Product']['material_length'] * (pi() * $Od * $Od );
    $this->request->data['Product']['material_cost'] = $materialMass * $this->Product->Material->field('cost', array('Material.id' => $this->request->data['Product']['material_id']));
    $this->request->data['Product']['material_markup_cost'] = $materialCost * $materialMarkupRate * $wasteMarkupRate;
    $this->request->data['Product']['setup_cost'] = $this->request->data['Product']['number_tools'] * $this->Rate->field('tool_time') * $this->Rate->field('setup_rate');
    $this->request->data['Product']['cutting_cost'] = $this->request->data['Product']['cutting_time'] * $this->Rate->field('cutting_rate');
    $this->request->data['Product']['machining_cost'] = $this->request->data['Product']['machining_time'] * $this->Rate->field('machining_rate');
    $this->request->data['Product']['polishing_cost'] = $this->request->data['Product']['polishing_time'] * $this->Rate->field('polishing_rate');
    if ($this->Product->save($this->request->data)) {
...

其次,如果你需要从其他位置调用这个方法,这表明你需要移动它。因为这是数据,你应该将它移动到模型中。

然而,如果你说每次费率变化,数据库中的每个产品都需要更新,这仍然是一个问题。也许不是现在,但以后会。想想拥有100MM的记录。你改变了利率上的一件事,你就在数据库上翻腾了很长一段时间。这是大量的资源。

我的建议是将其更改为ProductModel中的onFind回调。它的工作方式是,每次提取记录时,它都会在值返回到视图之前对其进行数学运算。通常最好不要将计算值存储在数据库中。在某些情况下,你会想要,但在这种情况下,似乎你可以随时计算。这也将防止每次费率变化时都需要重新计算每个产品。它还将使代码更加简洁。