An Object-Relational Mapping and Data Persistence Solution for PHP
You are not logged in.
Hi.
Correct me if I'm wrong but I think that (basing on the definitions of inheritance and polymorphism in OOP) searching for objects of given base class should also return objects of child classes meeting given criteria.
I had class Client that extends Party and generated some objects of both classes, each of which had property address set to 'address'.
I tried something like that:
<code>
$result = $manager->find('from Party where address like \'%a%\'');
</code>
but got only objects of Party. The same for:
<code>
$result = $manager->find(new Party());
</code>
If it's possible, please add the functionality, maybe as an option(?).
Offline
this makes sense. just added a new request. in fact this option should work on other operations as well: deleteAll(), getAll(). thanks.
Offline
I've just checked the request for this and it says there was some support added at the end of last year, but I can't seem to get it working... is there anything additional I need to pass to the find() method?
Edit: Using nightly build from 2006-01-16
Last edited by Marcus (2006-01-17 08:16:44)
Offline
my bad. subclasses in ezoql are included, but not for the methods deleteAll() and getAll(). am going to work on it. to get the same effect for getAll(), you can do a query like this:
$m->find('from Base where 1');
Offline
I'm an idiot, I was using the wrong ezpdo codebase ;).
Have you looked at doing a UNION for the queries that use SELECT statements? I've noticed that it's doing a SELECT against all the different tables separately, which makes doing an ORDER BY very difficult. If I'm wrong in this feel free to laugh, it's very late hehe.
Offline
thanks marcus for suggesting using UNION. webbles is working on something similar to that effect to reduce the number of queries.
Offline
Hi,
I have a class GeneArchive that extends Gene. When I do the following query:
$ormMgr->find("from Gene");It returns all objects of type Gene AND GeneArchive. How can I have it return only the class that I'm asking for and not extended classes?
Steve
Offline
In response to my previous message, it seems that doing
$ormMgr->find("from Gene");
will return all instances of Gene and any subclasses (in my case, GeneArchive which is an audit log of edited genes). In order to return only data from specific classes and not their subclasses I needed to use the following query:
$g = $ormMgr->create('Gene');
$geneList = $ormMgr->find($g);
It would be great if there was a way to specify the same behavior in EZOQL, maybe by doing something like this to return only objects that are the parent class and no children...
$ormMgr->find("from Gene g where g is not child");
Steve
Offline
If I have a child class GeneArchive that extends parent class Gene and they contain a field lastUpdate containing a timestamp, how can I find the number of most recent updates to Gene in the database? If I use the following
$lastUpdate = $ormMgr->find("MAX(lastUpdate) FROM Gene");
$numUpdated = $ormMgr->find("COUNT(*) FROM Gene WHERE lastUpdate=$lastUpdate");
it will search both Gene and GeneArchive for the most recent update and return the number of Gene and GeneArchive entries that match that date, which is not desirable.
Offline
I have implemented a patch to the 2007-11-20 codebase that adds an "instanceof" keyword so that you can turn off this behavior in EZOQL and find(). So, in the original case this returns all objects of type Gene and any classes that extended Gene.
$ormMgr->find("from Gene");
The following code will return only objects of type Gene, no objects that extend Gene. Extended classes are also turned off in any WHERE clauses. This solves my problem for not returning archived objects.
$ormMgr->find("from instanceof Gene");
--- ezpdo.2007-11-20.orig/src/query/epQueryBuilder.php.orig Tue Nov 20 06:28:56 2007
+++ ezpdo.2007-11-20/src/query/epQueryBuilder.php Wed Jul 16 14:00:48 2008
@@ -391,7 +391,8 @@
// add the super root
$this->primary_class = $item->getParam('class');
$this->primary_alias = $item->getParam('alias');
- $this->pm->addPrimaryRoot($this->primary_class, $this->primary_alias);
+ $doClassRecursion = ! (TRUE == $item->getParam('instanceof'));
+ $this->pm->addPrimaryRoot($this->primary_class, $this->primary_alias, $doClassRecursion);
// go through the rest: secondary roots
foreach($items as &$item) {
--- ezpdo.2007-11-20.orig/src/query/epQueryLexer.php.orig Tue Nov 20 06:28:56 2007
+++ ezpdo.2007-11-20/src/query/epQueryLexer.php Wed Jul 16 11:38:49 2008
@@ -33,6 +33,7 @@
epDefine('EPQ_T_FALSE');
epDefine('EPQ_T_FLOAT');
epDefine('EPQ_T_FROM');
+epDefine('EPQ_T_FROM_INSTANCEOF');
epDefine('EPQ_T_IDENTIFIER');
epDefine('EPQ_T_IN');
epDefine('EPQ_T_INTEGER');
@@ -130,6 +131,7 @@
'desc' => EPQ_T_DESC,
'descending' => EPQ_T_DESC,
'from' => EPQ_T_FROM,
+ 'instanceof' => EPQ_T_FROM_INSTANCEOF,
'false' => EPQ_T_FALSE,
'in' => EPQ_T_IN,
'is' => EPQ_T_IS,
--- ezpdo.2007-11-20.orig/src/query/epQueryParser.php.orig Tue Nov 20 06:28:56 2007
+++ ezpdo.2007-11-20/src/query/epQueryParser.php Wed Jul 16 11:42:15 2008
@@ -680,11 +680,19 @@
// array to keep all from items
$items = array();
do {
+ $foundInstanceOf = FALSE;
+
// eat ','
if ($t == ',') {
$this->next();
}
+ // handle the instanceof and consume it if it exists
+ if (($t = $this->peek()) == EPQ_T_FROM_INSTANCEOF) {
+ $foundInstanceOf = TRUE;
+ $this->next();
+ }
+
// expect an identifier
if (($t = $this->peek()) != EPQ_T_IDENTIFIER) {
$this->syntax_error("A class name is expected");
@@ -724,6 +732,14 @@
}
$node->addChildren($items);
+ // If the "instanceof" keyword was found do not examine class
+ // children in the query.
+
+ if ( $foundInstanceOf )
+ {
+ $item->setParam('instanceof', TRUE);
+ }
+
return $node;
}
--- ezpdo.2007-11-20.orig/src/query/epQueryPath.php.orig Tue Nov 20 06:28:56 2007
+++ ezpdo.2007-11-20/src/query/epQueryPath.php Wed Jul 16 11:52:15 2008
@@ -594,6 +594,12 @@
protected $type = false;
/**
+ * Whether or not to do class recursion (include child classes in the SQL)
+ * @var integer
+ */
+ protected $doClassRecursion = true;
+
+ /**
* Constructor
* @param string|epClassMap $class
* @param string $alias
@@ -672,6 +678,22 @@
}
/**
+ * Should child classes be examined in the SQL?
+ * @return boolean
+ */
+ public function doClassRecursion() {
+ return $this->doClassRecursion;
+ }
+
+ /**
+ * Should child classes be examined in the SQL?
+ * @return boolean
+ */
+ public function setClassRecursion($flag) {
+ $this->doClassRecursion = ( is_bool($flag) ? $flag : true );
+ }
+
+ /**
* Returns field map
* Implements {@link epQueryPathNode::getMap()}
* @return epClassMap
@@ -771,6 +793,14 @@
// array to hold sql parts
$sql_parts = array();
+ // If we are not doing class recursion in the SQL generation
+ // set the specific class.
+
+ if ( ! $this->doClassRecursion() )
+ {
+ $this->specificClass($this->cm->getName());
+ }
+
// for each non-abstract class map
foreach($this->getClassMaps() as $cm) {
@@ -899,6 +929,13 @@
return false;
}
+ // If not doing class recursion when generating the SQL set the specific class here.
+
+ if ( ! $this->getParent()->doClassRecursion() )
+ {
+ $this->specificClass($base_b);
+ }
+
// check if spcific class is set. use it only if so.
if ($sc = $this->specificClass()) {
// get class map of specific class
@@ -1196,7 +1233,7 @@
* @param false|string $alias
* @return boolean
*/
- public function addPrimaryRoot($class, &$alias = false) {
+ public function addPrimaryRoot($class, &$alias = false, $doClassRecursion = true) {
// create primary root node
if (!($node = new epQueryPathRoot($class, $alias, epQueryPathRoot::PRIMARY, $this->am))) {
@@ -1203,6 +1240,8 @@
return false;
}
+ $node->setClassRecursion($doClassRecursion);
+
// put it into alias-root lookup
$this->proot = $this->alias2root[$alias = $node->getAlias()] = & $node;Offline