依赖于其他表/模型

时间:2016-07-22 19:59:59

标签: cakephp cakephp-2.2

几年前,我用CakePHP 2.2开发了一些东西。在我的Bill模型中,我有一个virtualField来计算某个帐单是否已“完成”:

scheduled_payment = 1
&& (payed_beihilfe IS NOT NULL && payed_beihilfe > 0)
&& (payed_pkv IS NOT NULL && payed_pkv > 0)

这种情况很好,直到出现payed_beihilfe始终为零的情况,因为这部分不再发挥作用。有关分布的信息在字段Person.beihilfe_part中,范围从0到100.如果它是极端之一,我不想考虑那里的数量。所以我首先尝试了这个:

scheduled_payment = 1
&& ((payed_beihilfe IS NOT NULL && payed_beihilfe > 0) || Person.beihilfe_part = 0)
&& ((payed_pkv IS NOT NULL && payed_pkv > 0) || Person.beihilfe_part = 100)

当查看单个Bill对象时,这是有效的。但是,只要查看Person,我就会收到are mentioned in the manual的SQL错误。基本上这表示一个人不能virtualFields需要JOIN操作。这真是令人失望,因为我真的需要扩展我所拥有的“完成”属性。

这是我的Bill课程:

class Bill extends AppModel {
    public $displayField = 'amount';

    public $virtualFields = array(
            # XXX There is a limitation in the `virtualFields` that it cannot
            # use any sort of `JOIN`. Therefore I have to make due with the
            # data that is available in the `bills` table. This is a real
            # kludge but it seems to work.
            "done" =>
                "scheduled_payment = 1
                && ((payed_beihilfe IS NOT NULL && payed_beihilfe > 0) || (person_id = 7 && date > '2016-06-01'))
                && (payed_pkv IS NOT NULL && payed_pkv > 0)"
    );

    public $validate = array(
        'amount' => array(
            "rule" => array("comparison", ">", 0),
            "message" => "Der Rechnungsbetrag muss größer als € 0 sein."
        )
    );


    public $belongsTo = array(
        'Doctor' => array(
            'className' => 'Doctor',
            'foreignKey' => 'doctor_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'Person' => array(
            'className' => 'Person',
            'foreignKey' => 'person_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );
}

这是Person型号:

class Person extends AppModel {
    public $displayField = 'name';

    public $hasMany = array(
        'Bill' => array(
            'className' => 'Bill',
            'foreignKey' => 'person_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        )
    );
}

查询发生在例如PeopleController::view函数:

public function view($id = null) {
    $this->Person->id = $id;
    if (!$this->Person->exists()) {
        throw new NotFoundException(__('Invalid person'));
    }
    $this->set('person', $this->Person->read(null, $id));
}

这也会在相关的Bill对象中进行绘制,并且由于Person表未JOIN进入获取与Bill相关的Person对象的查询,因此崩溃给定的<?php //MySQLi connection $con = mysqli_connect("-","-","-","users"); if (mysqli_connect_errno()) { echo "MySQLi Connection was not established: " . mysqli_connect_error(); } //Reading the userdata from the registerp.php page $usr = mysqli_real_escape_string($con,$_POST['username']); $email = mysqli_real_escape_string($con,$_POST['email']); $pass_unhashed = mysqli_real_escape_string($con,$_POST['pass']); $pass = password_hash($pass_unhashed, PASSWORD_DEFAULT); //Checking if user exists $check_usr = mysqli_query($con,"SELECT FROM users WHERE user_name = $usr"); if (mysqli_num_rows($con,$check_usr)>=1) { echo "This Username already exists"; } else { echo "This Username is available"; } ?> 。这在CakePHP中隐式发生,我只是使用了脚手架。

我在很长一段时间内没有使用过CakePHP,因为我已经远离了Web开发。在一个非常小的Django项目中,我看到SQL表中的行被实例化为真正的Python对象。在那里添加一个函数或字段真的很容易。在CakePHP中,一切都只存储在关联数组中。因此,我真的没有看到如何添加一个计算这个“完成”属性的复杂函数。

有什么明智的方法可以解决这个问题?

1 个答案:

答案 0 :(得分:2)

不幸的是,没有过于干净的方法来克服这个限制。对于关联没有Model.beforeFind事件,其中可以修改查询,并且在没有完全重新实现数据源逻辑的部分的情况下,无法完全重新实现数据源逻辑的部分,而无法构建关联数据的查询的点(DboSource::generateAssociationQuery() )。

我过去通过使用带有覆盖buildStatement()方法的自定义数据源来解决类似问题,该方法将调度Model.beforeBuildStatement事件。将为所有查询分派该事件,因此关联模型可以监听它并在必要时修改查询。

这样的事情:

应用/型号/数据源/数据库/ AppMysql.php

<?php
App::uses('CakeEvent', 'Event');
App::uses('Mysql', 'Model/Datasource/Database');

class AppMysql extends Mysql
{
    public function buildStatement($query, Model $Model)
    {
        $targetModel = $Model;
        $linkedModel = $Model->{$query['alias']};
        if ($linkedModel !== null) {
            $targetModel = $linkedModel;
        }

        $event = new CakeEvent('Model.beforeBuildStatement', $this, array($query, $Model));
        $targetModel->getEventManager()->dispatch($event);

        if (is_array($event->result)) {
            $query = $event->result;
        }

        return parent::buildStatement($query, $Model);
    }
}

然后在模型中,可以添加连接,以便虚拟字段可以访问它们。在你的情况下,它可能是

的内容
class Bill extends AppModel
{
    // ...

    public function implementedEvents()
    {
        return parent::implementedEvents() + array(
            'Model.beforeBuildStatement' => array(
                'callable' => 'beforeBuildStatement',
                'passParams' => true
            )
        );
    }

    public function beforeBuildStatement(array $query, Model $Model)
    {
        if ($Model->name === 'Person') {
            $query['joins'][] = array(
                'table' => 'persons',
                'alias' => 'Person',
                'type' => 'LEFT',
                'conditions' => array(
                    'Person.id = Bill.person_id',
                )
            );
        }

        return $query;
    }
}

如果$Model不是当前模型,则表示当前模型正在作为关联查询的一部分进行查询。每次查询帐单表时,此片段都会加入persons表,作为Person模型的关联查询的一部分。

应该注意的是,这个例子可能存在陷阱,因为唯一的条件是“父模型=人模型”。您可能需要实施进一步的措施,以避免重复/非唯一联接和内容等问题,具体取决于您的应用程序中发生的情况。

另见