From f6d5f0481ee1c3d9723e172ce1de8b25dba161ce Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 30 Nov 2011 23:01:10 +0100 Subject: [PATCH] [DDC-551] Initial support for filters in the JoinedSubclassPersister Still some things to do. --- .../ORM/Persisters/BasicEntityPersister.php | 2 +- .../Persisters/JoinedSubclassPersister.php | 31 ++++++ lib/Doctrine/ORM/Query/Filter/SQLFilter.php | 2 +- .../Tests/ORM/Functional/SQLFilterTest.php | 97 ++++++++++++++++++- 4 files changed, 125 insertions(+), 7 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index 1f4550d8c..08252c420 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -1584,7 +1584,7 @@ class BasicEntityPersister ); } - private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { $filterSql = ''; diff --git a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php index d7e79e285..1a5bd8e51 100644 --- a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php @@ -328,8 +328,17 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn; } + + // Filters for each parent table + $filterSql = $this->generateFilterConditionSQL($parentClass, $tableAlias, $parentClass->table['name']); + if('' !== $filterSql) { + if (!$first) $joinSql .= ' AND '; + $joinSql .= $filterSql; + } } + //@todo: filters for the sub tables of childs + // OUTER JOIN sub tables foreach ($this->_class->subClasses as $subClassName) { $subClass = $this->_em->getClassMetadata($subClassName); @@ -389,6 +398,13 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $lockSql = ' ' . $this->_platform->getWriteLockSql(); } + // Filters for the base table + $filterSql = $this->generateFilterConditionSQL($this->_class, $baseTableAlias, $this->_class->table['name']); + if('' !== $filterSql) { + if($conditionSql) $conditionSql .= ' AND '; + $conditionSql .= $filterSql; + } + return $this->_platform->modifyLimitQuery('SELECT ' . $this->_selectColumnListSql . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql @@ -473,4 +489,19 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister $value = $this->fetchVersionValue($this->_getVersionedClassMetadata(), $id); $this->_class->setFieldValue($entity, $this->_class->versionField, $value); } + + private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + $filterSql = ''; + + $first = true; + foreach($this->_em->getFilters()->getEnabledFilters() as $filter) { + if("" !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias, $targetTable)) { + if ( ! $first) $filterSql .= ' AND '; else $first = false; + $filterSql .= '(' . $filterExpr . ')'; + } + } + + return $filterSql; + } } diff --git a/lib/Doctrine/ORM/Query/Filter/SQLFilter.php b/lib/Doctrine/ORM/Query/Filter/SQLFilter.php index 81cae335a..6ffe2b6de 100644 --- a/lib/Doctrine/ORM/Query/Filter/SQLFilter.php +++ b/lib/Doctrine/ORM/Query/Filter/SQLFilter.php @@ -73,5 +73,5 @@ abstract class SQLFilter /** * @return string The constraint if there is one, empty string otherwise */ - abstract public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias); + abstract public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = ''); } diff --git a/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php b/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php index aed2dbaf1..92016bc69 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SQLFilterTest.php @@ -15,6 +15,10 @@ use Doctrine\Tests\Models\CMS\CmsGroup; use Doctrine\Tests\Models\CMS\CmsArticle; use Doctrine\Tests\Models\CMS\CmsComment; +use Doctrine\Tests\Models\Company\CompanyPerson; +use Doctrine\Tests\Models\Company\CompanyManager; +use Doctrine\Tests\Models\Company\CompanyEmployee; + require_once __DIR__ . '/../../TestInit.php'; /** @@ -30,6 +34,7 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase public function setUp() { $this->useModelSet('cms'); + $this->useModelSet('company'); parent::setUp(); } @@ -444,6 +449,44 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals(1, count($user->groups->slice(0,10))); } + public function testJoinSubclassPersister_FilterOnBaseTable() + { + $this->loadCompanyFixtureData(); + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll())); + + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("manager_title", "\Doctrine\Tests\ORM\Functional\CompanyManagerTitleFilter"); + $this->_em->getFilters() + ->enable("manager_title") + ->setParameter("title", "devlead", \Doctrine\DBAL\Types\Type::getType(\Doctrine\DBAL\Types\Type::STRING)->getBindingType()); + + $this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $managers = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll(); + $this->assertEquals(1, count($managers)); + $this->assertEquals("Guilherme", $managers[0]->getName()); + } + + public function testJoinSubclassPersister_FilterOnParentTable() + { + $this->loadCompanyFixtureData(); + $this->assertEquals(2, count($this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll())); + + // Enable the filter + $conf = $this->_em->getConfiguration(); + $conf->addFilter("employee_department", "\Doctrine\Tests\ORM\Functional\CompanyEmployeeDepartmentFilter"); + $this->_em->getFilters() + ->enable("employee_department") + ->setParameter("department", "parsers", \Doctrine\DBAL\Types\Type::getType(\Doctrine\DBAL\Types\Type::STRING)->getBindingType()); + + $this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); + + $managers = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll(); + $this->assertEquals(1, count($managers)); + $this->assertEquals("Guilherme", $managers[0]->getName()); + } + private function loadFixtureData() { $user = new CmsUser; @@ -507,11 +550,31 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->groupId = $group->id; $this->groupId2 = $group2->id; } + + private function loadCompanyFixtureData() + { + $manager = new CompanyManager; + $manager->setName('Roman'); + $manager->setTitle('testlead'); + $manager->setSalary(42); + $manager->setDepartment('persisters'); + + $manager2 = new CompanyManager; + $manager2->setName('Guilherme'); + $manager2->setTitle('devlead'); + $manager2->setSalary(42); + $manager2->setDepartment('parsers'); + + $this->_em->persist($manager); + $this->_em->persist($manager2); + $this->_em->flush(); + $this->_em->clear(); + } } class MySoftDeleteFilter extends SQLFilter { - public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { if ($targetEntity->name != "MyEntity\SoftDeleteNewsItem") { return ""; @@ -523,7 +586,7 @@ class MySoftDeleteFilter extends SQLFilter class MyLocaleFilter extends SQLFilter { - public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { if (!in_array("LocaleAware", $targetEntity->reflClass->getInterfaceNames())) { return ""; @@ -535,7 +598,7 @@ class MyLocaleFilter extends SQLFilter class CMSCountryFilter extends SQLFilter { - public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsAddress") { return ""; @@ -547,7 +610,7 @@ class CMSCountryFilter extends SQLFilter class CMSGroupPrefixFilter extends SQLFilter { - public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsGroup") { return ""; @@ -558,7 +621,7 @@ class CMSGroupPrefixFilter extends SQLFilter } class CMSArticleTopicFilter extends SQLFilter { - public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') { if ($targetEntity->name != "Doctrine\Tests\Models\CMS\CmsArticle") { return ""; @@ -567,3 +630,27 @@ class CMSArticleTopicFilter extends SQLFilter return $targetTableAlias.'.topic = ' . $this->getParameter('topic'); // getParam uses connection to quote the value. } } + +class CompanyManagerTitleFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyManager") { + return ""; + } + + return $targetTableAlias.'.title = ' . $this->getParameter('title'); // getParam uses connection to quote the value. + } +} + +class CompanyEmployeeDepartmentFilter extends SQLFilter +{ + public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '') + { + if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyEmployee") { + return ""; + } + + return $targetTableAlias.'.department = ' . $this->getParameter('department'); // getParam uses connection to quote the value. + } +}