大家好,祝大家节日快乐。
最近,我的任务是将beta应用程序从纯PHP / jQuery转换为CakePHP / ExtJS(我是新手)。
我的问题是填充主网格的最复杂查询。
为简单起见,有3个表格包含正确的烘焙关系和模型:Projects
,ToDo
,ExtraToDo
Projects
hasMany ToDo
和ExtraToDo
。
ToDo
和ExtraToDo
列Title
和Complete
。
我的目标是根据这三个表格获得每个项目的完成百分比。
我的方法是Complete
列的 SUM 除以Complete
列的 COUNT 。我正在尝试使用CakePHP方式获取可读性/性能/ otherstuffIdontknowyet。
最初,在原始SQL中,我这样做了:
SELECT
`idProject`,
(SELECT
ROUND((SUM(`Complete`) / COUNT(`Complete`)) * 100),
FROM
(SELECT `Complete`, `ProjectID` FROM `ToDo`
UNION ALL
SELECT `Complete`, `ProjectID` FROM `ExtraToDo`) orders
WHERE
`ProjectID` = `idProject`
) AS 'Completion'
FROM
`Projects`
在决定使用CakePHP之前,我也很容易在Kohana PHP MVC框架中使用它。我知道他们的查询是如何创建的......:
private function get_completion() {
$Query = DB::select('ProjectID', array(DB::expr('ROUND((SUM(`Complete`) / COUNT(`Complete`)) * 100)'), 'Completion'))
->from(array('ToDo', 'ExtraToDo'))
->group_by('ProjectID');
return $Query;
}
public function get_all() {
$Query = DB::select()
->from('Projects')
->join(array(self::get_completion(), 'Completion'))
->on('projects.id', '=', 'Completion.ProjectID')
->execute()
->as_array();
return $Query;
}
不幸的是,在使用CakePHP方式时,我已经完全努力让它在CakePHP中运行。
我漂亮确定virtualFields是我答案的关键,但在阅读文档并尝试x,y和AND之后。我无法理解它们以及它们之间的联系。
提前谢谢你 -T6
答案 0 :(得分:1)
我建议为Project模型类创建一个afterFind()函数,或者只是添加一个在需要执行此计算时调用的函数。
执行计算的功能如下:
getPercentageComplete($project){
{
$total_todos = count($project['ToDo']);
$completed_todos = 0;
foreach($project['ToDo'] as $todo){
if($todo['Complete']) //assuming this is a boolean field
$completed_todos++;
}
return $completed_todos / $total_todos;
}
然后,你的afterFind看起来像这样:
function afterFind(&$results)
{
foreach ($results as &$project)
{
$project['Project']['percentageComplete'] = $this->Project->getPercentageComplete($project);
}
return $results;
}
上查看有关afterFind()的更多信息
答案 1 :(得分:1)
这是很多嵌套选择。 IMO你最好建立一个更好的查询。
这应该让你去。
class Project extends AppModel {
public $findMethods = array(
'completion' => true
);
// other code
protected function _findCompletion($state, $query, $results = array()) {
if ($state == 'before') {
$this->virtualFields['total'] = 'ROUND((SUM(Todo.Complete + TodoExtra.Complete) / (COUNT(Todo.Complete) + COUNT(TodoExtra.Complete))) * 100)';
$query['fields'] = array(
$this->alias . '.' . $this->primaryKey,
'total'
);
$query['joins'] = array(
array(
'table' => 'todos',
'alias' => 'Todo',
'type' => 'left',
'foreignKey' => false,
'conditions'=> array('Todo.project_id = ' , $this->alias . '.' . $this->primaryKey)
),
array(
'table' => 'todo_extras',
'alias' => 'TodoExtra',
'type' => 'left',
'foreignKey' => false,
'conditions'=> array('TodoExtra.project_id = ' . $this->alias . '.' . $this->primaryKey)
),
);
$query['group'] = array(
$this->alias . '.' . $this->primaryKey
);
return $query;
}
return $results;
}
// other code
}
现在您有了一个可以像find('first')
或find('all')
一样使用的自定义查找方法。
来自控制器:
$this->Project->find('completion');
或在项目模型中
$this->find('completion');
应该返回这样的内容:
$results = array(
0 => array(
'Project' => array(
'id' => 1,
'total' => 50
)
),
1 => array(
'Project' => array(
'id' => 2,
'total' => 75
)
)
);