Changing Zend_Db_Select's output to Zend_Db_Table_Rowset - zend-framework

I have the following code inside a class that extends Zend_Db_Table_Abstract:
public function fetchByFriends($id) {
/*
* SELECT * FROM list
* INNER JOIN friendship ON
* list.user_id = friendship.friend_id
* WHERE friendship.user_id = ?
*/
$select = $this->select()
->from("list")
->join("friendship", "list.user_id = friendship.friend_id")
->where("friendship.user_id = ?", $id);
$select->setIntegrityCheck(false); // allows joins within a DbTable
$stmt = $select->query();
return $this->fetchAll($stmt);
}
While the query works fine the data returned is of an array. Is there some way to refactor this so that fetchAll returns it as a Zend_Db_Table_Rowset, rather than an array?

Poor research on my part. I found the answer in Zend's reference manual:
Advanced usage
Example #27 Using a lookup table to refine the results of fetchAll()
$table = new Bugs();
// retrieve with from part set, important when joining
$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false)
->where('bug_status = ?', 'NEW')
->join('accounts', 'accounts.account_name =
bugs.reported_by')
->where('accounts.account_name = ?', 'Bob');
$rows = $table->fetchAll($select);

Related

Is there a way to search in Extbase and the TYPO3 query builder for words which have a "&shy" inside?

I have the problem that the backend users can set a word with a "­" character, for example something like "Test&shy ;labor".
If someone uses the frontend search with the word "Testlabor" no match will be found.
In the extbase repository I used this:
$query->like('name', '%' . $searchWord . '%')
I can change that to something like this:
$query->statement("SELECT * FROM table WHERE hidden = 0 AND REPLACE(name,'­', '') LIKE '%$searchWord%'")
Then the word will be found but I have to check all the things the framework normally does, like check if it's hidden and deleted and more complicated, if the result is in the right site tree. Now I just get everything that matches the searchword.
Is there a better way to search for words which have "­" inside? Can I use something like that within the TYPO3 query builder?
Many thanks in advance.
You can try with QueryBuilder interface
public function findShy($searchWord)
{
/** #var ConnectionPool $pool */
$pool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $pool->getConnectionForTable('table');
$queryBuilder = $connection->createQueryBuilder();
$query = $queryBuilder
->select('*')
->from('table')
->where("REPLACE(name,'­', '') like :name")
->setParameter('name', "%{$searchWord}%");
// for debug only
echo($query->getSQL());
print_r($query->getParameters());
return $query->execute()->fetchAll();
}
and call it somewhere i.e. in your controller:
DebuggerUtility::var_dump(
$this->yourRepository->findShy('Testlabor'),
'findShy() sample'
);
it will create a query with named parameter like (according to your TCA of course):
SELECT *
FROM `table`
WHERE (REPLACE(name, '­'­, '') like :name)
AND ((`table`.`deleted` = 0) AND (`table`.`hidden` = 0) AND
(`table`.`starttime` <= 1596363840) AND
((`table`.`endtime` = 0) OR (`table`.`endtime` > 1596363840)))
Note that returns associative array with the record not a mapped object of your model.
Optional
If you need mapped model objects anyway, you can mix these two solutions, i.e. first select only the pids of your records with QueryBuilder and then fetch them with Query which implements QueryInterface like this:
public function findShy2($searchWord)
{
/** #var ConnectionPool $pool */
$pool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $pool->getConnectionForTable('table');
$queryBuilder = $connection->createQueryBuilder();
$preQuery = $queryBuilder
->select('uid')
->from('table')
->where("REPLACE(name,'­', '') like :name")
->setParameter('name', "%{$searchWord}%");
// for debug only
echo($query->getSQL());
print_r($query->getParameters());
$uids = [];
foreach ($preQuery->execute()->fetchAll() as $item) {
$uids[] = $item['uid'];
}
if(count($uids) > 0){
$interfaceQuery = $this->createQuery();
$interfaceQuery->matching(
$interfaceQuery->in('uid', $uids)
);
return $interfaceQuery->execute();
}
return [];
}

Zend Db query to select all IDs

How would I write an Zend DB query to select all from the column ID?
So far I have tried:
public function getLatestUserID()
{
$ids = $this->select()
->where('id = ?');
return $ids;
}
But to no avail.
You just want the id column,
You failed to call an execute command.
try:
//assuming you are using a DbTable model
public function getLatestUserID()
{
$ids = $this->fetchAll('id');
return $ids;
}
I would do it like this, because I use the select() object for everything:
public function getLatestUserID()
{
$select = $this->select();
//I'm not sure if $this will work in this contex but you can out the table name
$select->from(array($this), array('id'));
$ids = $this->fetchAll($select);
return $ids;
}
The first two examples should return just the id column of the table, now if you actually want to query for a specific id:
public function getLatestUserID($id)
{
$select = $this->select();
$select->where('id = ?', $id);
//fetchAll() would still work here if we wanted multiple rows returned
//but fetchRow() for one row and fetchRowset() for multiple rows are probably
//more specific for this purpose.
$ids = $this->fetchRow($select);
return $ids;
}
make sure your class containing getLatestUserID does extend Zend_Db_Table_Abstract also :
$ids = $this->select()->where('id = ?'); can't work because where('id = ?'); expects an id value like where('id = ?', $id);
if what you want is the latest inserted row's Id use :
$lastInsertId = $this->getAdapter()->lastInsertId();
(however if you are using an oracle database this will not work and you should use $lastInsertId = $this->getAdapter()->lastSequenceId('USER_TABLE_SEQUENCE'); )

Zend Framework Table Relationships - select from multiple tables within app

I hope I'm asking this question in an understandable way. I've been working on an app that has been dealing with 1 table ( jobschedule ). So, I have models/Jobschedule.php, models/JobscheduleMapper.php, controllers/JobscheduleController.php, view/scripts/jobschedule/*.phtml files
So in my controller I'll do something like this:
$jobnumber = $jobschedule->getJobnum();
$jobtype = $jobschedule->getJobtype();
$table = $this->getDbTable();
public function listAction()
{
$this->_helper->layout->disableLayout();
$this->view->jobnum = $this->getRequest()->getParam( 'jobnum', false );
$this->view->items = array();
$jobschedule = new Application_Model_Jobschedule();
$jobschedule->setJobnum( $this->view->jobnum );
$mapper = new Application_Model_JobscheduleMapper();
$this->view->entries = $mapper->fetchAll ( $jobschedule );
}
and then in my mapper I I do something like:
$resultSet = $table->fetchAll($table->select()->where('jobnum = ?', $jobnumber)->where('jobtype = ?', $jobtype) );
$entries = array();
foreach ($resultSet as $row) {
$entry = new Application_Model_Jobschedule();
$entry->setJobnum($row->jobnum)
->setJobtype($row->jobtype)
->setJobdesc($row->jobdesc)
->setJobstart($row->jobstart)
->setJobend($row->jobend)
->setJobfinished($row->jobfinished)
->setJobnotes($row->jobnotes)
->setJobid($row->jobid);
$entries[] = $entry;
}
return $entries;
}
Then in my view I can manipulate $entries. Well, the problem I'm coming across now is that there is also another table called 'jobindex' that has a column in it called 'jobno'. That 'jobno' column holds the same record as the 'jobnum' column in the 'jobschedule' table. I need to find the value of the 'store_type' column in the 'jobindex' table where jobindex.jobno = joschedule.jobnum ( where 1234 is the jobno/jobnum for example ). Can someone please help me here? Do I need to create a jobindex mapper and controller? If so, that's done ... I just don't know how to manipulate both tables at once and get the record I need. And where to put that code...in my controller?
If I understand you correctly this is the SQL query you need to extract the data from database:
SELECT `jobschedule`.* FROM `jobschedule` INNER JOIN `jobindex` ON jobindex.jobno = jobschedule.jobnum WHERE (jobindex.jobtype = 'WM')
Assembling this SQL query in Zend would look something like this:
$select->from('jobschedule', array('*'))
->joinInner(
'jobindex',
'jobindex.jobno = jobschedule.jobnum',
array())
->where('jobindex.jobtype = ?', $jobtype);
Let us know if that's what you are looking for.
If I'm understanding you correctly, you'll want to join the 'jobindex' table to the 'jobschedule' table.
...
$resultSet = $table->fetchAll(
$table->select()->setIntegrityCheck(false)
->from($table, array('*'))
->joinLeft(
'jobindex',
'jobindex.jobno = jobschedule.jobnumber',
array('store_type'))
->where('jobnum = ?', $jobnumber)
->where('jobtype = ?', $jobtype)
->where('jobindex.store_type = ?', $_POST['store_num'])
);
....
Depending on how 'jobschedule' is related to 'jobindex', you may want an inner join (joinInner()) instead.
The setIntegrityCheck(false) disables referential integrity between the tables, which is only important if you are writing to them. For queries like this one, you can just disable it and move on (else it will throw an exception).

Zend DB returning NULL value

I have the following query that extends from Zend_DB_Table_Abstract
$select = $this->select()
->from('expense_details',
array('SUM(expense_details_amount) AS total'))
->where('YEAR(expense_details_date) = ?', '2010')
->where('MONTH(expense_details_date) = ?', '01')
->where('expense_details_linkemail = ?', 'xxxx#gmail.com');
However it returning a NULL value despite its "equivalent" returning the desired value
SELECT SUM(expense_details_amount) AS total FROM expense_details
WHERE
YEAR(expense_details_date) = '2010'
AND MONTH(expense_details_date) = '01'
AND expense_details_linkemail = 'xxxx#gmail.com'
Is my Zend_DB_Table construct above correct?
One thing that might be a problem is the 'AS' statement within this string literal.
array('SUM(expense_details_amount) AS total'))
Try changing it to this:
array('total' => 'SUM(expense_details_amount)'))
I believe this is how Zend_Db_Select handles AS.
After searching hard for a solution I found where the problem is.
I changed
$value = $this->fetchAll($select);
$data[] = $value->total;
to
$value = $this->fetchRow($select);
$data[] = $value->total;

Grouping WHERE clauses with Zend_Db_Table_Abstract

Does anyone know of a way to group where clauses with Zend_Db? Basically I have this query
$sql = $table->select()
->where('company_id = ?', $company_id)
->where('client_email = ?', $client_email)
->orWhere('client_email_alt = ?', $client_email);
Which is giving me this:
SELECT `clients`.* FROM `clients` WHERE (company_id = '1') AND (client_email = 'email#address.com') OR (client_email_alt = 'email#address.com')
But I need it to give me this, where the OR statement is grouped:
SELECT `clients`.* FROM `clients` WHERE (company_id = '1') AND ((client_email = 'email#address.com') OR (client_email_alt = 'email#address.com'))
In order to achieve this, you have to construct the grouped clause within a single call to the where method.
If both values of conditions are the same, you can do this:
$select->where('client_email = ? OR client_email_alt = ?', $client_email)
If there are multiple placeholders within the string, the DB adapter's quoteInto method will replace all placeholders with the provided value.
If you need to group an OR with different values for each field, you have to manually quote the values. It's a bit more complex:
$select->where(
$db->quoteInto('client_email = ?', $email1) . ' OR ' . $db->quoteInto('client_email_alt = ?', $email2)
); // $db is your instance of Zend_Db_Adapter_*
// You can get it from a Zend_Db_Table_Abstract
//subclass by calling its getAdapter() method
You can use getPart() to get WHERE statement and then connect sub-queries.
$select->where('client_email = ?', $client_email)
->orWhere('client_email_alt = ?', $client_email);
$subquery = $select->getPart(Zend_Db_Select::WHERE);
$select ->reset(Zend_Db_Select::WHERE);
$select ->where('company_id = ?', $company_id)
->where(implode(' ',$subquery));
For Zend Framework Version 2, things differ a bit:
See http://framework.zend.com/apidoc/2.2/classes/Zend.Db.Sql.Predicate.Predicate.html#nest
$table->select()
->where(['company_id'=> $company_id])
->nest
->where('client_email = ?', $client_email)
->or
->where('client_email_alt = ?', $client_email)
->unnest();
works fine and feels much cleaner than the ZF1 methods.
I needed to combine AND/OR statements but including OR statements conditionally, adding them only in some cases. This solution is an adaptation of what I did, based on small modifications of the accepted answer.
$sql = $table->select()
->where('company_id = ?', $company_id);
$orWhereClauses = [];
// We could add a conditional statement to add this statement
$orWhereClauses[] = $db->quoteInto('client_email = ?', $email1);
// Same applies to this statement
$orWhereClauses[] = $db->quoteInto('client_email_alt = ?', $email2);
$sql->where(implode(" OR ", $orWhereClauses));
In first you can generate subquery, then get "WHERE" part and insert into main query
$subquery = $db->select();
$subquery->orWhere('a>10');
$subquery->orWhere('b<20');
etc..
$subquery = $subquery->getPart(Zend_Db_Select::WHERE);
$select->where(implode(' ',$subquery));