Commit 336367ca authored by Jochen Rau's avatar Jochen Rau
Browse files

[+FEATURE] Extbase (Persistence): Implemented Query::count() supplementary to...

[+FEATURE] Extbase (Persistence): Implemented Query::count() supplementary to Query::execute(). Resolves #4991.
parent 04208538
......@@ -115,7 +115,7 @@ class Tx_Extbase_Persistence_LazyObjectStorage extends Tx_Extbase_Persistence_Ob
if ($this->columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
$parentKeyFieldName = $this->columnMap->getParentKeyFieldName();
if (!empty($parentKeyFieldName)) {
$numberOfElements = $this->fieldValue;
$numberOfElements = $this->fieldValue; // The field value in TYPO3 normally contains the number of related elements
} else {
$this->initializeStorage();
$numberOfElements = count($this->storage);
......
......@@ -295,6 +295,15 @@ class Tx_Extbase_Persistence_QOM_QueryObjectModel implements Tx_Extbase_Persiste
return t3lib_div::makeInstance('Tx_Extbase_Persistence_QueryResult', $this->storageBackend->getRows($this));
}
/**
* Executes this query and returns the number of tuples matching the query.
*
* @return int The number of tuples matching the query
*/
public function count() {
return $this->storageBackend->countRows($this);
}
/**
* Returns the statement defined for this query.
* If the language of this query is string-based (like JCR-SQL2), this method
......@@ -309,7 +318,7 @@ class Tx_Extbase_Persistence_QOM_QueryObjectModel implements Tx_Extbase_Persiste
* @return string the query statement.
*/
public function getStatement() {
$this->storageBackend->parseQuery($this);
$this->storageBackend->getStatement($this);
}
}
......
......@@ -181,6 +181,26 @@ class Tx_Extbase_Persistence_Query implements Tx_Extbase_Persistence_QueryInterf
* @api
*/
public function execute() {
$result = $this->getPreparedQueryObjectModel()->execute();
return $this->dataMapper->map($this->className, $result->getRows());
}
/**
* Executes the query against the database and returns the number of matching objects
*
* @return integer The number of matching objects
* @api
*/
public function count() {
return $this->getPreparedQueryObjectModel()->count();
}
/**
* Prepares and returns a Query Object Model
*
* @return Tx_Extbase_Persistence_QOM_QueryObjectModelInterface The prepared query object
*/
protected function getPreparedQueryObjectModel() {
if ($this->source === NULL) {
$this->source = $this->QOMFactory->selector($this->className, $this->dataMapper->convertClassNameToTableName($this->className));
}
......@@ -212,10 +232,7 @@ class Tx_Extbase_Persistence_Query implements Tx_Extbase_Persistence_QueryInterf
$query->bindValue($name, $this->valueFactory->createValue($value));
}
$query->setQuerySettings($this->getQuerySettings());
$result = $query->execute();
return $this->dataMapper->map($this->className, $result->getRows());
return $query;
}
/**
......
......@@ -72,5 +72,13 @@ interface Tx_Extbase_Persistence_Storage_BackendInterface {
*/
public function getRows(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query);
/**
* Returns the number of tuples matching the query.
*
* @param Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query
* @return int The number of matching tuples
*/
public function countRows(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query);
}
?>
\ No newline at end of file
<?php
/***************************************************************
* Copyright notice
*
* (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
* All rights reserved
*
* This class is a backport of the corresponding class of FLOW3.
* All credits go to the v5 team.
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* An Bad Constraint exception
*
* @package Extbase
* @subpackage Persistence\Storage\Exception
* @version $ID:$
*/
class Tx_Extbase_Persistence_Storage_Exception_BadConstraint extends Tx_Extbase_Persistence_Exception {
}
?>
\ No newline at end of file
......@@ -171,71 +171,103 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
* @return array The matching tuples
*/
public function getRows(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query) {
$statement = $this->parseQuery($query);
// debug($statement, -2); // FIXME remove debug code
$constraint = $query->getConstraint();
if($constraint instanceof Tx_Extbase_Persistence_QOM_StatementInterface) {
if ($constraint->getLanguage() === Tx_Extbase_Persistence_QOM_QueryObjectModelInterface::TYPO3_SQL_MYSQL) {
$statement = $constraint->getStatement();
$parameters = $query->getBoundVariableValues();
} else {
throw new Tx_Extbase_Persistence_Exception('Unsupported query language.', 1248701951);
}
} else {
$parameters = array();
$statement = $this->getStatement($query, $parameters);
}
$this->replacePlaceholders($statement, $parameters);
$result = $this->databaseHandle->sql_query($statement);
$this->checkSqlErrors();
if ($result) {
$tuples = $this->getRowsFromResult($query->getSource(), $result);
}
return $tuples;
return $this->getRowsFromResult($query->getSource(), $result);
}
/**
* Returns an array with tuples matching the query.
* Returns the number of tuples matching the query.
*
* @param Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query
* @return array The matching tuples
* @return int The number of matching tuples
*/
public function parseQuery(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query) {
$statement = '';
$parameters = array();
public function countRows(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query) {
$constraint = $query->getConstraint();
if($constraint instanceof Tx_Extbase_Persistence_QOM_StatementInterface) {
if ($constraint->getLanguage() === Tx_Extbase_Persistence_QOM_QueryObjectModelInterface::TYPO3_SQL_MYSQL) {
$statement = $constraint->getStatement();
$parameters= $query->getBoundVariableValues();
} else {
throw new Tx_Extbase_Persistence_Exception('Unsupported query language.', 1248701951);
}
} else {
$sql = array();
$sql['tables'] = array();
$sql['fields'] = array();
$sql['where'] = array();
$sql['additionalWhereClause'] = array();
$sql['orderings'] = array();
$sql['limit'] = array();
$tuples = array();
$source = $query->getSource();
$this->parseSource($query, $source, $sql, $parameters);
$statement = 'SELECT ' . implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']);
$this->parseConstraint($constraint, $source, $sql, $parameters, $query->getBoundVariableValues());
if (!empty($sql['where'])) {
$statement .= ' WHERE ' . implode('', $sql['where']);
if (!empty($sql['additionalWhereClause'])) {
$statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']);
}
} elseif (!empty($sql['additionalWhereClause'])) {
$statement .= ' WHERE ' . implode(' AND ', $sql['additionalWhereClause']);
}
if($constraint instanceof Tx_Extbase_Persistence_QOM_StatementInterface) throw new Tx_Extbase_Persistence_Storage_Exception_BadConstraint('Could not execute count on queries with aconstraint of type Tx_Extbase_Persistence_QOM_StatementInterface', 1256661045);
$parameters = array();
$statementParts = $this->parseQuery($query, $parameters);
$statementParts['fields'] = array('COUNT(*)');
$statement = $this->buildStatement($statementParts, $parameters);
$this->replacePlaceholders($statement, $parameters);
$result = $this->databaseHandle->sql_query($statement);
$this->checkSqlErrors();
$tuples = $this->getRowsFromResult($query->getSource(), $result);
return current(current($tuples));
}
/**
* Returns the statement, ready to be executed.
*
* @param Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query
* @return string The SQL statement
*/
public function getStatement(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, array &$parameters) {
$statementParts = $this->parseQuery($query, $parameters);
$statement = $this->buildStatement($statementParts);
return $statement;
}
/**
* Parses the query and returns the SQL statement parts.
*
* @param Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query
* @return array The SQL statement parts
*/
public function parseQuery(Tx_Extbase_Persistence_QOM_QueryObjectModelInterface $query, array &$parameters) {
$sql = array();
$sql['tables'] = array();
$sql['fields'] = array();
$sql['where'] = array();
$sql['additionalWhereClause'] = array();
$sql['orderings'] = array();
$sql['limit'] = array();
$this->parseOrderings($query->getOrderings(), $source, $sql);
if (!empty($sql['orderings'])) {
$statement .= ' ORDER BY ' . implode(', ', $sql['orderings']);
}
$source = $query->getSource();
$this->parseSource($query, $source, $sql, $parameters);
$this->parseConstraint($query->getConstraint(), $source, $sql, $parameters, $query->getBoundVariableValues());
$this->parseOrderings($query->getOrderings(), $source, $sql);
$this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $sql);
return $sql;
}
$this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $sql);
if (!empty($sql['limit'])) {
$statement .= ' LIMIT ' . $sql['limit'];
/**
* Returns the statement, ready to be executed.
*
* @param array $sql The SQL statement parts
* @return string The SQL statement
*/
public function buildStatement(array $sql) {
$statement = 'SELECT ' . implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']);
if (!empty($sql['where'])) {
$statement .= ' WHERE ' . implode('', $sql['where']);
if (!empty($sql['additionalWhereClause'])) {
$statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']);
}
} elseif (!empty($sql['additionalWhereClause'])) {
$statement .= ' WHERE ' . implode(' AND ', $sql['additionalWhereClause']);
}
if (!empty($sql['orderings'])) {
$statement .= ' ORDER BY ' . implode(', ', $sql['orderings']);
}
if (!empty($sql['limit'])) {
$statement .= ' LIMIT ' . $sql['limit'];
}
$this->replacePlaceholders($statement, $parameters);
return $statement;
}
......@@ -613,12 +645,12 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
* workspace overlay before.
*
* @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source (selector od join)
* @param resource &$sql The resource
* @param resource $result The result
* @return array The result as an array of rows (tuples)
*/
protected function getRowsFromResult(Tx_Extbase_Persistence_QOM_SourceInterface $source, $res) {
protected function getRowsFromResult(Tx_Extbase_Persistence_QOM_SourceInterface $source, $result) {
$rows = array();
while ($row = $this->databaseHandle->sql_fetch_assoc($res)) {
while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
if ($source instanceof Tx_Extbase_Persistence_QOM_SelectorInterface) {
// FIXME The overlay is only performed if we query a single table; no joins
$row = $this->doLanguageAndWorkspaceOverlay($source->getSelectorName(), $row);
......
......@@ -61,7 +61,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend_testcase extends Tx_Extbase_
/**
* @test
*/
public function parseQueryWorksWithMinimalisticQueryObjectModel() {
public function getStatementWorksWithMinimalisticQueryObjectModel() {
$mockSource = $this->getMock('Tx_Extbase_Persistence_QOM_Selector', array(), array(), '', FALSE);
$mockSource->expects($this->any())->method('getSelectorName')->will($this->returnValue('selector_name'));
$mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('nodetype_name'));
......@@ -71,11 +71,11 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend_testcase extends Tx_Extbase_
$mockQueryObjectModel->expects($this->any())->method('getBoundVariableValues')->will($this->returnValue(array()));
$mockQueryObjectModel->expects($this->any())->method('getOrderings')->will($this->returnValue(array()));
$mockTypo3DbBackend = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Storage_Typo3DbBackend'), array('parseOrderings'), array(), '', FALSE);
$mockTypo3DbBackend->expects($this->any())->method('parseOrderings');
$resultingStatement = $mockTypo3DbBackend->parseQuery($mockQueryObjectModel);
$parameters = array();
$resultingStatement = $mockTypo3DbBackend->getStatement($mockQueryObjectModel, $parameters);
$expectedStatement = 'SELECT selector_name.* FROM selector_name';
$this->assertEquals($expectedStatement, $resultingStatement);
}
......@@ -83,7 +83,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend_testcase extends Tx_Extbase_
/**
* @test
*/
public function parseQueryWorksWithBasicEqualsCondition() {
public function getStatementWorksWithBasicEqualsCondition() {
$mockSource = $this->getMock('Tx_Extbase_Persistence_QOM_Selector', array(), array(), '', FALSE);
$mockSource->expects($this->any())->method('getSelectorName')->will($this->returnValue('selector_name'));
$mockSource->expects($this->any())->method('getNodeTypeName')->will($this->returnValue('nodetype_name'));
......@@ -93,15 +93,29 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend_testcase extends Tx_Extbase_
$mockQueryObjectModel->expects($this->any())->method('getBoundVariableValues')->will($this->returnValue(array()));
$mockQueryObjectModel->expects($this->any())->method('getOrderings')->will($this->returnValue(array()));
$mockTypo3DbBackend = $this->getMock($this->buildAccessibleProxy('Tx_Extbase_Persistence_Storage_Typo3DbBackend'), array('parseOrderings'), array(), '', FALSE);
$mockTypo3DbBackend->expects($this->any())->method('parseOrderings');
$resultingStatement = $mockTypo3DbBackend->parseQuery($mockQueryObjectModel);
$parameters = array();
$resultingStatement = $mockTypo3DbBackend->getStatement($mockQueryObjectModel, $parameters);
$expectedStatement = 'SELECT selector_name.* FROM selector_name';
$this->assertEquals($expectedStatement, $resultingStatement);
}
/**
* @test
* @expectedException Tx_Extbase_Persistence_Storage_Exception_BadConstraint
*/
public function countRowsWithStatementConstraintResultsInAnException() {
$mockStatementConstraint = $this->getMock('Tx_Extbase_Persistence_QOM_Statement', array(), array(), '', FALSE);
$mockQueryObjectModel = $this->getMock('Tx_Extbase_Persistence_QOM_QueryObjectModel', array('getConstraint'), array(), '', FALSE);
$mockQueryObjectModel->expects($this->once())->method('getConstraint')->will($this->returnValue($mockStatementConstraint));
$mockTypo3DbBackend = $this->getMock('Tx_Extbase_Persistence_Storage_Typo3DbBackend', array('dummy'), array(), '', FALSE);
$mockTypo3DbBackend->countRows($mockQueryObjectModel);
}
/**
* @test
*/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment