几年前,我用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中,一切都只存储在关联数组中。因此,我真的没有看到如何添加一个计算这个“完成”属性的复杂函数。
有什么明智的方法可以解决这个问题?
答案 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
模型的关联查询的一部分。
应该注意的是,这个例子可能存在陷阱,因为唯一的条件是“父模型=人模型”。您可能需要实施进一步的措施,以避免重复/非唯一联接和内容等问题,具体取决于您的应用程序中发生的情况。
另见