我有一些叫做节点的东西,它们之间是HABTM相关的。每个单独的关系由用户在前端指定。
创建新节点时,前端UI以以下形式发送数据:
$exampleData = [
'Node' => [
'title' => 'The title of a new node',
'body' => 'The body of a new node'],
'NodeRequireNode' => [ // This is the HABTM-relation
0 => [
'title' => 'The title of a required node'],
1 => [
'title' => 'The title of another required node']];
我需要在保存关系之前将所需节点的标题解析为数据库中的ID。也就是说,我需要这样的数据:
$exampleData = [
'Node' => [
'title' => 'The title of a new node',
'body' => 'The body of a new node'],
'NodeRequireNode' => [ // This is the HABTM-relation
0 => [
'required_id' => 34],
1 => [
'required_id' => 82]];
这是安全的,因为没有两个节点可能具有相同的标题。问题是,我应该在哪里解决这个问题?
起初,我是在NodesController
:
// app/Controller/NodesController.php
public function add() {
if ($this->request->is('post')) {
$data = $this->request->data;
$thereExistRequiredNodes = (count($data['NodeRequiringNode']) > 0);
if ($thereExistRequiredNodes) {
// Some long, clumsy code to do the thing. Removed for brevity.
}
$this->Node->create();
$this->Node->saveAssociated($data)
}
}
我不喜欢这样,因为它创造了一个冗长的方法。我简单地考虑过简单地将它拆分成辅助方法,但是我已经读过我应该尝试让我的控制器变薄并且我的模型很胖。所以我尝试将解析代码重构为我的NodeRequiringNode
模型:
// app/Model/NodeRequiringNode.php
// This method takes care of a couple forms the data might come in, relying on
// the protected method beneath it to do the actual work.
public function prepareRequiredNodesWithTitlesForSave($requiredNodes) {
if(isset($requiredNodes['title'])) {
$requiredNodes = $this->_prepareRequiredNodeWithTitleForSave($requiredNodes);
} elseif (isset($requiredNodes[0])) {
foreach ($requiredNodes as $index => &$requiredNode) {
$requiredNode = $this->_prepareRequiredNodeWithTitleForSave($requiredNode);
}
}
return $requiredNodes;
}
protected function _prepareRequiredNodeWithTitleForSave($requiredNode) {
$title = $requiredNode['title'];
unset($requiredNode['title']);
$conditions = ['title =' => $title];
$required_id = $this->Node->field( // This line is a problem
'id',
$conditions);
$requiredNode['required_id'] = $required_id;
return $requiredNode;
}
这似乎更好,但它不起作用。我上面标记的行尝试使用Nodes
模型,而NodeRequiringNode
模型似乎无法使用该模型。
所以现在我很困惑。将标题解析为ID的任务似乎是清洁工具,应该是模型的范畴,而控制器则关注业务逻辑。然而,我无法从模型对象中做到这一点,因为模型对象需要从另一个模型获取数据,这是控制器应该做的事情。
那么我应该如何构建我的程序的这一部分呢?请注意,这一点特别适用于CakePHP,不是 MVC。
答案 0 :(得分:0)
这对我来说看起来不像是对控制器的调用,更像是对Model::field()
的调用,所以你实际上并没有尝试访问控制器,只是另一个模型?
显然模型是相关的,据我所知,Node HABTM Node
NodeRequireNode
是关联的别名?
无论如何,由于模型是相关的,它们互相访问是完全正常的,这就是为什么CakePHP会自动创建适当的属性并引用相关模型,也就是说它是如何在CakePHP中工作的。
如果可能的话我会更改前端,以便它传递ID而不是标题(这就是表单助手提供的CakePHP自动魔法的工作方式),但如果我需要解析标题,那么,因为模型实际上正在解决自己,我会在beforeSave()
和/或beforeValidate()
(在验证需要ID的情况下)回调中正确准备Node
模型中的数据,或者在自定义或重写的保存方法中。
更新关于评论中的其他问题 - 我不是100%确定它是怎么回事,但是我们说不,相关的模型参考仅在模型上创建。将模型加载到控制器中时(无论是显式使用loadModel()
还是隐式使用CakePHPs auto-magic),只会创建对该特定模型的引用(模型本身将保存对相关模型的引用)。
另请参阅 http://book.cakephp.org/2.0/en/models.html#understanding-models