我的项目中有很多对很多关系(user_role、grades、user_role_grades)。但我也有一个要求,不要从我的数据库中删除任何数据。因此,我在表中添加了一个状态列,连接两个表以创建多对多关系。现在我想要
$userRole->getGrades()
只获取联合表(user_role_grades)中没有状态"0"的记录。对于这些,我尝试使用条令sql过滤器。
namespace BisMpBundleFilter;
use DoctrineORMMappingClassMetaData;
class UserRoleGradeFilter extends DoctrineORMQueryFilterSQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if("BisDefaultBundleEntityUserRoleGrade" == $targetEntity->name){
return $targetTableAlias . '.status != 0';
}
return '';
}
}
因此,它被调用,用于Bis\DefaultBundle\Entity\UserRole,但不用于Bis\DfaultBundle\Entity\UserRoleGrade实体。有人有什么想法吗?
或者你可能有其他想法,我该怎么做?
我认为这是不可能的,因为它直接附加SQL。即使你尝试SQL注入:
return $targetTableAlias . '.status != 0)) LEFT join the_other_table ON '
. $targetTableAlias . '.grades HAVING the_other_table.status = 0 ((';
它可能会在类似(())
的语句中崩溃
您可以调用$targetEntity->getAssociationMappings()['yourFieldName']
如果存在joinTable
密钥,则表示您具有manyToMany
关系。其中yourFieldName
是您的字段与ManyToMany
的关系。
可以从DoctrineORMQuerySqlWalker::getSQLTableAlias()
获得正确的表别名。我用debug_backtrace
得到了SqlWalker
,这不是一个优雅的解决方案,但我还没有找到更好的解决方案。
/**
* Get SqlWalker with debug_backtrace
*
* @return null|SqlWalker
*/
protected function getSqlWalker()
{
$caller = debug_backtrace();
$caller = $caller[2];
if (isset($caller['object'])) {
return $caller['object'];
}
return null;
}
完全实现我的addFilterConstraint
方法
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if (empty($this->reader)) {
return '';
}
// The Doctrine filter is called for any query on any entity
// Check if the current entity is "pool aware" (marked with an annotation)
$poolAware = $this->reader->getClassAnnotation(
$targetEntity->getReflectionClass(),
PoolAware::class
);
if (!$poolAware) {
return '';
}
if (!$poolId = $this->getParameter('poolId')) {
return '';
}
$fieldName = $poolAware->getFieldName();
if (empty($fieldName)) {
return '';
}
if (!$sqlWalker = $this->getSqlWalker()) {
return '';
}
if (!isset($targetEntity->getAssociationMappings()[$fieldName])) {
return '';
}
$mapping = $targetEntity->getAssociationMappings()[$fieldName];
if (isset($mapping['joinColumns'])) {
// oneToMany relation detected
$table = $targetEntity->getTableName();
$columnName = $mapping['joinColumns'][0]['name'];
$dqlAlias = constant($targetEntity->getName() . '::MNEMO');
} elseif (isset($mapping['joinTable'])) {
// manyToMany relation detected
$dqlAlias = constant($mapping['targetEntity'] . '::MNEMO');
$component = $sqlWalker->getQueryComponent($dqlAlias);
// Only main entity in query is interesting for us,
// otherwise do not apply any filter
if ($component['parent']) {
return '';
}
$table = $mapping['joinTable']['name'];
$columnName = $mapping['joinTable']['inverseJoinColumns'][0]['name'];
} else {
return '';
}
$tableAlias = ($sqlWalker instanceof BasicEntityPersister)
? $targetTableAlias // $repository->findBy() has been called
: $sqlWalker->getSQLTableAlias($table, $dqlAlias);
$query = sprintf('%s.%s = %s', $tableAlias, $columnName, $this->getConnection()->quote(poolId));
return $query;
}
我们所有的条令模型都有MNEMO常数,这是一个模型的简单名称。CCD_ 11具有MNEMO CCD_。这个MNEMO相当于Repository类中的_alias
。这就是我们将此值应用于$dqlAlias
的原因
完整的代码说明,您可以在这里阅读