首先让我介绍一下数据库结构
结构的顶部是Scope
。它为HAS_MANY Topics
。
Topic
HAS_MANY Problems
和Presets
。
Presets
和Problems
通过MANY_TO_MANY相关。
Groups
可被视为描述用户有权访问Problems
的内容的访问规则。
我尝试在单个查询中为一组Scopes
建立数据树(Topics
-> Groups
-> ...)。数据应包含Problems
,它属于确定的Groups
或根本不属于组(例如,匿名用户没有安全级别)。
一些关于Presets
的词。该实体用于为前端创建一些作业。几个Presets
可能在同一Problems
下包含相同的Topic
。此信息对于了解我的查询出了什么问题很有用;
首先,我为Problem
创建了一个范围 allowedForUser ,该范围对于使Problems
用户具有访问权限很有用;
public function allowedForUser($user) {
/* some stuff to get group id list for user */
return $this->allowedForGroupsAndGuests($user_group_ids);
}
/**
* Scope - allowed to groups and all
*
* @param $group_ids
* @return $this
*/
public function allowedForGroupsAndGuests($group_ids) {
$this->allowedForGroups($group_ids);
$criteria_no_group = new CDbCriteria();
$criteria_no_group->addCondition('group_id is NULL');
$this->getDbCriteria()->mergeWith(array(
'with' => array(
'groups' => $criteria_no_group->toArray()
)
), 'OR');
return $this;
}
/**
* Scope - allowed to groups
*
* @param $group_ids
* @return $this
*/
public function allowedForGroups($group_ids) {
// select allowed by groups
$criteria_by_group = new CDbCriteria();
$criteria_by_group->addInCondition('group_id', $group_ids);
$this->getDbCriteria()->mergeWith(array(
'with' => array(
'groups' => $criteria_by_group->toArray()
)
));
return $this;
}
如上所述,我需要从作用域开始获取一棵完整的树。因此,我为Scope
创建了一个范围:
/**
* Scope to get problem scopes with problems and topics with allowed problems only
*
* @param $user
* @return $this
*/
public function availableForUser($user) {
$this->getDbCriteria()->mergeWith(array(
'with' => array(
'topics' => array(
'with' => array(
'problems' => array(
'scopes' => array(
'allowedForUser' => $user,
)
)
)
)
)
));
return $this;
}
在这里,我要做的就是打电话给
ProblemScope::model()->availableForUser($user)->findAll()
...,所有树都在这里:Scopes
,它们的Topics
,Problems
对于当前用户;按计划不存在空白的Scopes
和Topics
。
但是根本没有Presets
,因此我认为很容易解决扩展范围标准的问题:
public function availableForUser($user) {
$this->getDbCriteria()->mergeWith(array(
'with' => array(
'topics' => array(
'with' => array(
'problems' => array(
'scopes' => array(
'allowedForUser' => $user,
)
),
'problemPresets' => array(
'with' => array(
'problems' => array(
'alias' => 'presetproblems',
'scopes' => array(
'allowedForUser' => $user,
)
)
)
)
)
)
)
));
return $this;
}
在这里我遇到了困难:语法错误或访问冲突:1066不是唯一的表/别名:'groups_groups'
SELECT t.id AS t0_c0,
t.title AS t0_c1,
t.description_info AS t0_c2,
t.sort_order AS t0_c3,
topics.id AS t1_c0,
topics.title AS t1_c1,
topics.description_info AS t1_c2,
topics.scope_id AS t1_c3,
problems.id AS t2_c0,
problems.title AS t2_c1,
problems.description_info AS t2_c2,
problems.topic_id AS t2_c3,
groups.id AS t3_c0,
groups.name AS t3_c1,
groups.comment AS t3_c2,
groups.access_files AS t3_c3,
groups.access_handbook AS t3_c4,
groups.access_lessons AS t3_c5,
groups.access_course AS t3_c6,
groups.access_uchebnik AS t3_c7,
problemPresets.id AS t4_c0,
problemPresets.title AS t4_c1,
problemPresets.topic_id AS t4_c2,
presetproblems.id AS t5_c0,
presetproblems.title AS t5_c1,
presetproblems.description_info AS t5_c2,
presetproblems.topic_id AS t5_c3,
groups.id AS t6_c0,
groups.name AS t6_c1,
groups.comment AS t6_c2,
groups.access_files AS t6_c3,
groups.access_handbook AS t6_c4,
groups.access_lessons AS t6_c5,
groups.access_course AS t6_c6,
groups.access_uchebnik AS t6_c7
FROM cp_problem_scopes t
LEFT OUTER JOIN cp_problem_scope_topics topics ON (topics.scope_id=t.id)
LEFT OUTER JOIN cp_problems problems ON (problems.topic_id=topics.id)
LEFT OUTER JOIN cp_problem_group groups_groups ON (problems.id=groups_groups.problem_id)
LEFT OUTER JOIN cp_groups groups ON (groups.id=groups_groups.group_id)
LEFT OUTER JOIN cp_problem_presets problemPresets ON (problemPresets.topic_id=topics.id)
LEFT OUTER JOIN cp_problem_preset_problem problems_presetproblems ON (problemPresets.id=problems_presetproblems.preset_id)
LEFT OUTER JOIN cp_problems presetproblems ON (presetproblems.id=problems_presetproblems.problem_id)
LEFT OUTER JOIN cp_problem_group groups_groups ON (presetproblems.id=groups_groups.problem_id)
LEFT OUTER JOIN cp_groups groups ON (groups.id=groups_groups.group_id)
WHERE ((group_id IN (:ycp4,
:ycp5,
:ycp6,
:ycp7))
OR (group_id IS NULL))
AND ((group_id IN (:ycp8,
:ycp9,
:ycp10,
:ycp11))
OR (group_id IS NULL))
可以解决“问题”范围并为其固定别名的问题:
public function availableForUser($user) {
$problems_criteria = Problem::model()->allowedForUser($user)->getDbCriteria();
$problems_criteria->alias = 'topic_problems';
$problems_criteria->with['groups']['alias'] = 'topic_problems_groups';
$topic_problems_criteria_arr = $problems_criteria->toArray();
$problems_criteria->alias = 'topic_presets_problems';
$problems_criteria->with['groups']['alias'] = 'topic_presets_problems_groups';
$topic_presets_problems_criteria_arr = $problems_criteria->toArray();
$this->getDbCriteria()->mergeWith(array(
'with' => array(
'topics' => array(
'with' => array(
'problems' => $topic_problems_criteria_arr,
'problemPresets' => array(
'with' => array(
'problems' => $topic_presets_problems_criteria_arr
)
)
)
)
)
));
return $this;
}
看上去很糟糕,但问题已解决。引入了新的内容:where子句中的列'group_id'不明确。
SELECT `t`.`id` AS `t0_c0`,
`t`.`title` AS `t0_c1`,
`t`.`description_info` AS `t0_c2`,
`t`.`sort_order` AS `t0_c3`,
`topics`.`id` AS `t1_c0`,
`topics`.`title` AS `t1_c1`,
`topics`.`description_info` AS `t1_c2`,
`topics`.`scope_id` AS `t1_c3`,
`topic_problems`.`id` AS `t2_c0`,
`topic_problems`.`title` AS `t2_c1`,
`topic_problems`.`description_info` AS `t2_c2`,
`topic_problems`.`topic_id` AS `t2_c3`,
`topic_problems_groups`.`id` AS `t3_c0`,
`topic_problems_groups`.`name` AS `t3_c1`,
`topic_problems_groups`.`comment` AS `t3_c2`,
`topic_problems_groups`.`access_files` AS `t3_c3`,
`topic_problems_groups`.`access_handbook` AS `t3_c4`,
`topic_problems_groups`.`access_lessons` AS `t3_c5`,
`topic_problems_groups`.`access_course` AS `t3_c6`,
`topic_problems_groups`.`access_uchebnik` AS `t3_c7`,
`problemPresets`.`id` AS `t4_c0`,
`problemPresets`.`title` AS `t4_c1`,
`problemPresets`.`topic_id` AS `t4_c2`,
`topic_presets_problems`.`id` AS `t5_c0`,
`topic_presets_problems`.`title` AS `t5_c1`,
`topic_presets_problems`.`description_info` AS `t5_c2`,
`topic_presets_problems`.`topic_id` AS `t5_c3`,
`topic_presets_problems_groups`.`id` AS `t6_c0`,
`topic_presets_problems_groups`.`name` AS `t6_c1`,
`topic_presets_problems_groups`.`comment` AS `t6_c2`,
`topic_presets_problems_groups`.`access_files` AS `t6_c3`,
`topic_presets_problems_groups`.`access_handbook` AS `t6_c4`,
`topic_presets_problems_groups`.`access_lessons` AS `t6_c5`,
`topic_presets_problems_groups`.`access_course` AS `t6_c6`,
`topic_presets_problems_groups`.`access_uchebnik` AS `t6_c7`
FROM `cp_problem_scopes` `t`
LEFT OUTER JOIN `cp_problem_scope_topics` `topics` ON (`topics`.`scope_id`=`t`.`id`)
LEFT OUTER JOIN `cp_problems` `topic_problems` ON (`topic_problems`.`topic_id`=`topics`.`id`)
LEFT OUTER JOIN `cp_problem_group` `groups_topic_problems_groups` ON (`topic_problems`.`id`=`groups_topic_problems_groups`.`problem_id`)
LEFT OUTER JOIN `cp_groups` `topic_problems_groups` ON (`topic_problems_groups`.`id`=`groups_topic_problems_groups`.`group_id`)
LEFT OUTER JOIN `cp_problem_presets` `problemPresets` ON (`problemPresets`.`topic_id`=`topics`.`id`)
LEFT OUTER JOIN `cp_problem_preset_problem` `problems_topic_presets_problems` ON (`problemPresets`.`id`=`problems_topic_presets_problems`.`preset_id`)
LEFT OUTER JOIN `cp_problems` `topic_presets_problems` ON (`topic_presets_problems`.`id`=`problems_topic_presets_problems`.`problem_id`)
LEFT OUTER JOIN `cp_problem_group` `groups_topic_presets_problems_groups` ON (`topic_presets_problems`.`id`=`groups_topic_presets_problems_groups`.`problem_id`)
LEFT OUTER JOIN `cp_groups` `topic_presets_problems_groups` ON (`topic_presets_problems_groups`.`id`=`groups_topic_presets_problems_groups`.`group_id`)
WHERE ((group_id IN (:ycp4,
:ycp5,
:ycp6,
:ycp7))
OR (group_id IS NULL))
AND ((group_id IN (:ycp4,
:ycp5,
:ycp6,
:ycp7))
OR (group_id IS NULL))
最后一个WHERE
子句使group_id检查加倍,使我认为我从根本上做错了;我该如何解决该问题?