zend framework subquery - zend-framework

I am using zend framework 1.12. I have following query to run.
"SELECT name,(select count(*) from org_quote_template_items where org_quote_template_items.quote_template_id = org_quote_templates.`id` ) as total_line_item FROM `org_quote_templates`"
In my model file , I created it like this. following is my model file.
class default_Model_DbTable_QuoteTemplates extends Zend_Db_Table_Abstract
{
/**
* Name of the original db table
*
* #var string
*/
protected $_name = 'org_quote_templates';
public function getAllTemplate($where){
$select = $this->select();
$subquery = " (SELECT COUNT(*) FROM org_quote_template_items WHERE org_quote_template_items.quote_template_id = org_quote_templates.`id` )";
$select->from(array($this), array('org_quote_templates.*','total_line_items' => new Zend_Db_Expr($subquery)));
$select = $select->where('organization_id = ?',$where['org_id']);
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
$paginator->setItemCountPerPage(
Zend_Registry::get('config')->paginator->general);
pr($adapter);
exit;
}
}
I am getting following error when I run the code.
" exception 'Zend_Db_Table_Select_Exception' with message 'Select query cannot join with another table' "
please let me know what should I do ?

There is an error in your request. You should have:
$select = $this->select ();
$subquery = "(SELECT COUNT(*) FROM dtempls WHERE order_id = orders.id)";
$select->from ($this, array (
'id',
'total_line_items' => new Zend_Db_Expr ($subquery)
));

I think you have to use setIntegrityCheck(false) for accomplishing that. Check this link

You can try this way in zend
$this->select()
->setIntegrityCheck(false)
->from(array('oqt' => 'org_quote_templates'),array('total_line_item'))
->joinLeft(array('oqti' => 'org_quote_template_items'), 'oqti.quote_template_id = oqt.id', array(count(*) as count))

Related

Query an entity in a different Language

I'm trying to query entietes in a language, other than the system default one, my repository method looks like this,
public function findOneByMaterialnumber( $materialnumber, $sysLanguageUid ){
$query = $this->createQuery();
$query->matching($query->like('materialnumber',$materialnumber));
$query->getQuerySettings()->setIgnoreEnableFields(true);
$query->getQuerySettings()->setRespectStoragePage(false);
$query->getQuerySettings()->setLanguageUid($sysLanguageUid);
//$query->getQuerySettings()->setRespectSysLanguage(false);
//$query->getQuerySettings()->setLanguageMode('strict');
//$query->getQuerySettings()->setLanguageOverlayMode(false);
$parser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbQueryParser');
$queryParts = $parser->parseQuery($query);
//\TYPO3\CMS\Core\Utility\DebugUtility::debug($queryParts, 'Query');
print_r($queryParts);
exit;
return $query->execute()->getFirst();
}
but the query this results in still incorporates the sys_language_uid in the non-strict way. The debugged query object looks like this.
[keywords] => Array
(
)
[tables] => Array
(
[tx_productfinder_domain_model_product] => tx_productfinder_domain_model_product
)
[unions] => Array
(
)
[fields] => Array
(
[tx_productfinder_domain_model_product] => tx_productfinder_domain_model_product.*
)
[where] => Array
(
[0] => tx_productfinder_domain_model_product.materialnumber LIKE :
)
[additionalWhereClause] => Array
(
[0] => (tx_productfinder_domain_model_product.sys_language_uid IN (0,-1))
)
[orderings] => Array
(
[0] => tx_productfinder_domain_model_product.ordercode ASC
[1] => tx_productfinder_domain_model_product.title ASC
[2] => tx_productfinder_domain_model_product.materialnumber ASC
)
[limit] =>
[offset] =>
[tableAliasMap] => Array
(
[tx_productfinder_domain_model_product] => tx_productfinder_domain_model_product
)
This happens regardless of the sys_language_uid i query for. What am I doing wrong?
As you can see, I've tried combinations of all sorts of QuerySettings, setRespectSysLanguage, setLanguageMode and setLanguageOverlayMode. As I understand it, I have to query strictly and without language overlay. But none of those, nor their combinations, worked as intended.
This works with TYPO3 8.7.xx
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
/**
* The repository for Products
*/
class ProductRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
{
/*
* #param int $uid id of record
* #param int $langUid sys_language_uid of the record
* #return \ITSHofmann\ItsProductfile\Domain\Mpdell\Product
*/
public function findByUidAndLanguageUid($uid,$langUid)
{
$query = $this->createQuery();
$object = $query->matching(
$query->equals('uid', $uid)
)->execute()->getFirst();
if ($object) {
$className = get_class ($object);
$dataMapper = $this->objectManager->get(DataMapper::class);
$tableName = $dataMapper->getDataMap($className)->getTableName();
$transOrigPointerField = $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'];
$languageField = $GLOBALS['TCA'][$tableName]['ctrl']['languageField'];
$connection = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connection->getQueryBuilderForTable($tableName );
$statement = $queryBuilder->select('*')
->from($tableName )
->where(
$queryBuilder->expr()->eq(
$transOrigPointerField,$queryBuilder->createNamedParameter($object->getUid(), \PDO::PARAM_INT)),
$queryBuilder->expr()->eq(
$languageField,$queryBuilder->createNamedParameter($langUid, \PDO::PARAM_INT))
)->execute();
$objectRow = $statement ->fetch();
if ($objectRow) {
$langObject = $dataMapper->map($className,[$objectRow]);
if ($langObject ) {
return reset ($langObject );
}
}
}
return $object;
}
}
edit. The answer I posted here originally turned out not to work either. What I ended up doing instead, was to write a custom statement, execute it to return the raw data and map it, via DataMapper->map(); Refer to Christop Hofmanns answer for details.

PDOException Zf2 with Postgresql

Hi I have a problem with Zend Framework 2.
File:
/home/marketplace/htdocs/vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Statement.php:240
Message:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "users" does not exist
LINE 1: ...ELECT COUNT(1) AS "c" FROM (SELECT "users".* FROM "users") A...
^
In my model I have
public function fetchAll($paginated=false)
{
if($paginated) {
$select = new Select('users');
$select->order('id DESC');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
$paginatorAdapter = new DbSelect(
$select,
$this->tableGateway->getAdapter(),
$resultSetPrototype
);
$paginator = new Paginator($paginatorAdapter);
return $paginator;
}
$resultSet = $this->tableGateway->select(function(Select $select){
$select->limit('30')->order('id DESC');
});
return $resultSet;
}
What is strange is that in locale server everything is working...
Any suggestion where to find the problem?
Thanks
UPDATE:
If I do the same query directly,
$sql = 'SELECT COUNT(1) AS "c" FROM (SELECT "users".* FROM "users") AS "original_select"';
$resultSet = $this->tableGateway->getAdapter()->query($sql);
return $resultSet;
everything is ok.
I found the problem.
The search-path of Postgresql was setted to another Schema and not to main schema "public"
Thanks to Richard!

Identity and Credential in different tables. How to login user?

I'm using Zend Framework.
I save users information in two tables.
I have one table for his basic information and password, and in the other table I save his e-mails.
He can login with any e-mail.
My question is how should I extend Zend_Auth_Adapter_DbTable so that I can allow this?
I prefer not to use table views.
[edit]
I found a solution. What worked for me:
class My_Auth_Adapter_DbTable extends Zend_Auth_Adapter_DbTable
{
protected function _authenticateCreateSelect()
{
// build credential expression
if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) {
$this->_credentialTreatment = '?';
}
$credentialExpression = new Zend_Db_Expr(
'(CASE WHEN ' .
$this->_zendDb->quoteInto(
$this->_zendDb->quoteIdentifier($this->_credentialColumn, true)
. ' = ' . $this->_credentialTreatment, $this->_credential
)
. ' THEN 1 ELSE 0 END) AS '
. $this->_zendDb->quoteIdentifier(
$this->_zendDb->foldCase('zend_auth_credential_match')
)
);
// get select
//$dbSelect = clone $this->getDbSelect();
$mdl = new My_Model_Db_Table_Users();
$dbSelect = $mdl->select();
$dbSelect = $dbSelect->setIntegrityCheck(false);
$dbSelect = $dbSelect->from(array('u' => $this->_tableName), array('*', $credentialExpression));
$dbSelect = $dbSelect->joinInner(array('ue' => 'users_emails'), 'ue.id_user = u.user_id', array('user_email'));
$dbSelect = $dbSelect->where('ue.' . $this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity);
return $dbSelect;
}
}
I explained what did it for me in the question.
But, to repeat, easiest for me was to change Zend_Auth_Adapter_DbTable::_authenticateCreateSelect().
There are a method named Zend_Auth_Adapter_DbTable::getDbSelect returns Zend_Db_Select object.
Call it and then you can join those two tables.
Hope this help.
Regards,
Ahmed B.
Here's an alternate method.
Extend the Zend_Auth_Adapter_DbTable class.
class My_Auth_Adapter_DbTable extends Zend_Auth_Adapter_DbTable {
public function setDbSelect($select) {
$this->_dbSelect = $select;
return $this;
}
}
Create instance of your new adapter
$authAdapter = new My_Auth_Adapter_DbTable(
$this->dbTable->getAdapter()
, 'Users'
, 'Users.username'
, 'Users.password'
);
In your Application_Model_DbTable_Users class, create a method that returns the select object with the joined tables.
public function getSelectAuth() {
$select = $this
->select()
->setIntegrityCheck(false)
->from(array('SystemPeopleJoined' => $this->_name)
, array(
'id'
, 'person_id'
, 'system_role_id'
, 'created_on'
, 'expires_on'
)
)
->joinInner(
'People'
, 'People.id = SystemPeopleJoined.person_id'
, array(
'first_name' => 'first_name'
, 'last_name' => 'last_name'
, 'name' => "CONCAT_WS(' ', `People`.`first_name`, `People`.`last_name`)"
)
return $select;
}
Set the select object in your adapter
$select = $this->dbTable->getSelectAuth();
$authAdapter
->setDbSelect($select)
->setIdentity($params['username'])
->setCredential($params['password'])
->setCredentialTreatment("SHA1(?)")
;

Zend Framework: Zend_Db_Select - how to join custom subquery table?

$select->joinRight(array('i' => '(SELECT * FROM images ORDER BY image_id)'),'i.ad_id = '. $main .'.id',$imarray);
Like that doesn't work. Subquery getting inside quotes.
Like that:
RIGHT JOIN `(SELECT * FROM images ORDER BY image_id)` AS `i` ON i.ad_id = a.id
Thanks ;)
Use
$select->joinRight(
array('i' => new Zend_Db_Expr('(SELECT * FROM images ORDER BY image_id)')),
'i.ad_id = '. $main .'.id',
$imarray
);
I feel This is easier to read and navigate...
$sub = $this->select()
->setIntegrityCheck(false)
->from(array('i' => 'images'), array('*'))
->order('i.image_id');
$select = $this->select()
->setIntegrityCheck(false)
->from(array('m' => 'MAIN_TABLE'), array('*'))
->joinRight(array('i' => $sub), 'i.ad_id = m.id', array('*'));
return $this->select($select);

Zend framework group by

I'm trying to do a group by using Zend framework. Here's my code:
$table = new TableClass();
$select = $table->select();
$select->from ("table", array("date", "column1" => "sum(column1)"));
$select->group ( array ("date") );
$results = $table->fetchAll ($select);
$result = $results[0];
$date = $result->date;
$column1 = $result->column1;
TableClass extends 'Zend_Db_Table_Abstract'.
I can see the query by looking at the mysql query log. The query is well formed - column1 is named in the query and the results look correct if I run the query in mysql workbench.
I cannot access the data in 'column1' - I always get this exception:
Uncaught exception 'Zend_Db_Table_Row_Exception' with message 'Specified column "column1" is not in the row'
I can however access the date column without issue.
I tried:
accessing the columns by array index:
$result[0]
but you get an exception (can't access the columns by index).
not using a column alias:
$select->from ("table", array("date", "sum(column1)"));
$column1 = $result["sum(column1)"];
but you get an exception (no such column "sum(column1)").
throwing in a Zend_Db_Expr:
"column1" => new Zend_Db_Expr ( "sum(column1)" )
but this doesn't help.
Some other examples I have seen suggest the use of the column names without aggregate functions, ie. "column1" instead of "sum(column1)" but that doesn't seem to me to be the answer - the query doesn't have any aggregate functions in it so mysql won't know what to do with it.
Any help appreciated.
Firstly, a quick tip for working with Zend_Db_Select (and by extension Zend_Db_Table_Select), you can view the generated SQL by invoking the toString method. It is vital to verify that your code generates the correct query before working with a result set:
$select = $table->select();
$select->from ("table", array("date", "column1" => "sum(column1)"));
$select->group ( array ("date") );
$sql = (string) $select; //Retrieve SQL as a string
Or simply
die($select); //print SQL
I wrote the following test script using your example and have no problems:
class Table extends Zend_Db_Table_Abstract
{
protected $_primary = 'id';
protected $_name = 'table';
}
$db = Zend_Db::factory('Pdo_Mysql', array(
'dbname' => 'test',
'username' => 'root',
'password' => '',
'host' => 'localhost'
));
$table = new Table($db);
$select = $table->select();
$select->from ($table, array("date", "column1" => new Zend_Db_Expr("sum(column1)")));
$select->group ( array ("date") );
$sql = (string) $select;
echo $sql;
$results = $table->fetchAll ($select);
$result = $results[0];
$date = $result->date;
$column1 = $result->column1;
echo '<br>' . $date . ': ' . $column1;
Use Zend_Debug::dump($result); to inspect data inside the Zend_Db_Table_Row if necessary.
In my case the SQL generated is as follows:
SELECT `table`.`date`, sum(column1) AS `column1` FROM `table` GROUP BY `date`