Extbase - get created sql from query - sql

i want to get some database tables from my typo3 extensions.
The Extension is based on extbase.
The query always returns nothing but the data exists
I've tried this:
$query = $this->createQuery();
$query->statement('SELECT * FROM `my_table`
WHERE field = ? ORDER BY date DESC LIMIT 1',
array($condition));
$results = $query->execute();
and this:
$query = $this->createQuery();
$query->matching($query->equals('field', $condition));
$query->setOrderings(array('date' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING));
$query->setLimit(1);
$results = $query->execute();
both returns null as result.
Is it possible to get the sql that the class creates to look where the bug is?
I've looked in some extbase persistent classes but didn't find a clue
EDIT:
For those who are interested.. i found a "solution".
If you create the query with the statement() method, you can print the query with this function
echo $query->getStatement()->getStatement();
It doesn't replace the placeholder.
But you can get the Variables with this method
var_dump($query->getStatement()->getBoundVariables());
Thats the best Solution that i found, without editing the extbase extenstions

In TYPO3 6.2 you can use Extbase DebuggerUtility to debug the query.
Add this code before $query->execute():
$queryParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbQueryParser');
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->parseQuery($query));
For TYPO3 8.7+ use this code instead:
$queryParser = \TYPO3\CMS\Core\Utility\GeneralUtilityGeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
$doctrineQueryBuilder = $queryParser->convertQueryToDoctrineQueryBuilder($query);
$doctrineQueryBuilderSQL = $doctrineQueryBuilder->getSQL();
$doctrineQueryBuilderParameters = $doctrineQueryBuilder->getParameters();

Check this snippet, although it's not very comfortable in use it helps a lot:
in general you need this code at the end of the buildQuery(array $sql) method (*) - right before return $statement;
if (in_array("your_table_name", $sql['tables'])) {
var_dump($statement);
print_r($statement);
}
(*) Class file:
TYPO3 ver.: 4.x: typo3/sysext/extbase/Classes/Persistence/Storage/Typo3DbBackend.php
TYPO3 ver.: 6.x: typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php
In 6.2.x ...
You can try within \TYPO3\CMS\Core\Database\DatabaseConnection::exec_SELECTquery method, just add the condition after fetching the $query, like (trim is important!):
public function exec_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '') {
$query = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
if (trim($from_table) == 'fe_users') {
DebuggerUtility::var_dump($query);
}
// rest of method

An easy way without changing any Typo3 core code and not mentioned in any forum so far is using the php "serialize()" method:
$result = $query->execute();
echo (serialize($result));
In the result object you find the SQL query ("statement;" ...)

Improvement to biesiors answer:
As Extbase replaces some placeholders after calling buildQuery(), you might prefer to place the debug output into getObjectDataByQuery(), just after $this->replacePlaceholders($sql, $parameters, $tableName);
if (strpos($sql, "your_table_name.")) {
debug($sql, 'my debug output');
};
Also, better use debug() instead of var_dump().
[File: typo3\sysext\extbase\Classes\Persistence\Generic\Storage\Typo3DbBackend.php. Line 339 in version 6.1]:

$query = $this->createQuery();
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
$getHotelInfo = 'SELECT * FROM `my_table` WHERE field = ? ORDER BY date DESC LIMIT 1';
return $query->statement($getHotelInfo)->execute();
For executing query you have to write 'setReturnQueryResult' on your repository

I just extended the above snippet, with a $_GET condition.
for debugging, just append "?dbg_table=tx_some_of_my_tables" to your address, and you're ready to go ;-)
if (in_array($_GET['dbg_table'], $sql['tables'])) {
echo('<div style="background: #ebebeb; border: 1px solid #999; margin-bottom: 20px; padding: 10px;"><pre style="white-space: normal">'.$statement.'</pre></div>');
}

A cleaner way to debug your statements when using TYPO3 6.1 is to use the query parser of Typo3DbBackend.
$parser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbBackend');
$params = array();
$queryParts = $parser->parseQuery($query, $params);
\TYPO3\CMS\Core\Utility\GeneralUtility::devLog('query', 'my_extension', 1, array('query' => $queryParts, 'params' => $params));
The parser returns an array containing the different parts of the generated SQL statement.
With TYPO3 6.2 the parseQuery method was moved to Typo3DbQueryParser and lost its second parameter.

i suggest set this in typo3conf/LocalConfiguration.php file under 'SYS' array
'SYS' => array(
......
'displayErrors' => 1,
'sqlDebug' => 1
.......
)
and then write wrong field name in query intentionally and then execute code.
this will show last query execute with error.

Related

Typo3 9.5 - Custom flexform ordering, wrong backquotes in sql

i have an custom extension, where you can select the different entries at the backend, to show them at the list view. I have a custom sorting at my backend, but the system always sort them Descending.
I implemented an "orderBy" function, which doesnt work, because the system uses wrong backspaces.
My code looks like this:
I call the sort function in my "findByUid($uid)" function like this:
$query->setOrderings($this->orderByKey('uid', $uidArray));
protected function orderByKey($key, $uidlist) {
$order = array();
foreach ($uidlist as $uid) {
//$order["$key=$uid"] = \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING;
$order["$key=$uid"] = "ASC";
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($order);
}
return $order;
}
The result at the sql query is:
ORDER BY `tx_MYEXTENSION_domain_model_FIELD`.`uid=3` DESC
But it must be:
ORDER BY `tx_MYEXTENSION_domain_model_FIELD`.`uid` = 3 DESC
Is there a way to change this?
After a lot of search, I found this solution on an stackoverflow entry:
$ids = explode(',',$this->settings['entries'])
foreach($ids as $key => $id){
$entries[$id] = $this->entriesRepository->findByUid($id);
}
This code snippet has to be intergrated at the controller.
For me its working.

ZF2: Is there a more efficient way to do this Zend\Db Update query?

Here's some ZF1 code for an update query:
$this->getAdapter()->update(
'users', $data, $this->getAdapter()->quoteInto('node_id = ?', $user->nodeId)
);
Here's the same query with ZF2:
$param = $this->getAdapter()->platform->quoteValue($user->nodeId);
$sqlOj = new Sql($this->getAdapter());
$update = $sqlOj->update('users')->set($data)->where('node_id = ' . $param);
$updateString = $sqlOj->getSqlStringForSqlObject($update);
$this->getAdapter()->query($updateString, Adapter::QUERY_MODE_EXECUTE);
As you can see, one line of ZF1 code has become 5 lines of ZF2 code, (actually without the fluent interface it would be 7 lines...)
Am I missing something? Or is ZF2's DB component just more verbose that ZF1?
BTW, I have found the same scenario with select and insert queries too...
I managed to limit it to 3 lines.
use \Zend\Db\Sql\Sql;
$sql = new Sql ($adapter);
$update = $sql->update ('users')->set ($data)->where (['id = ?' => 1]);
$adapter->query ($sql->getSqlStringForSqlObject ($update), $db::QUERY_MODE_EXECUTE);
The problem is they didn't expect you to run your updates like that. Instead, you are expected to use a table gateway.
This way it becomes one line again:
$this->tableGateway->update($data, array('id' => $id));

codeigniter change complex query into active record

I have a codeigniter app.
My active record syntax works perfectly and is:
function get_as_09($q){
$this->db->select('m3');
$this->db->where('ProductCode', $q);
$query = $this->db->get('ProductList');
if($query->num_rows > 0){
foreach ($query->result_array() as $row){
$row_set[] = htmlentities(stripslashes($row['m3'])); //build an array
}
return $row_set;
}
}
This is effectively
select 'm3' from 'ProductList' where ProductCode='$1'
What I need to do is convert the below query into an active record type query and return it to the controller as per above active record syntax:
select length from
(SELECT
[Length]
,CONCAT(([width]*1000),([thickness]*1000),REPLACE([ProductCode],concat(([width]*1000),([thickness]*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options
FROM [dbo].[dbo].[ProductList]) as p
where options='25100cr' order by length
I picture something like below but this does not work.
$this->db->select(length);
$this->db->from(SELECT [Length],CONCAT(([width]*1000),([thickness]*1000),REPLACE[ProductCode],concat(([width]*1000),([thickness]*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options
FROM [dbo].[dbo].[ProductList]);
$this->db->where(options, $q);
$this->db->order(length, desc);
Help appreciated as always. Thanks again.
You can use sub query way of codeigniter to do this for this purpose you will have to hack codeigniter. like this
Go to system/database/DB_active_rec.php Remove public or protected keyword from these functions
public function _compile_select($select_override = FALSE)
public function _reset_select()
Now subquery writing in available And now here is your query with active record
$select = array(
'Length'
'CONCAT(([width]*1000)',
'thickness * 1000',
'REPLACE(ProductCode, concat((width*1000),(thickness*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options'
);
$this->db->select($select);
$this->db->from('ProductList');
$Subquery = $this->db->_compile_select();
$this->db->_reset_select();
$this->db->select('length');
$this->db->from("($Subquery)");
$this->db->where('options','25100cr');
$this->db->order_by('length');
And the thing is done. Cheers!!!
Note : While using sub queries you must use
$this->db->from('myTable')
instead of
$this->db->get('myTable')
which runs the query.
Source

Yii CDbCommand create query

I can't create the following query using Yii:
SELECT recipientId as broadcasterId, SUM(quantity) as quantity FROM `creditlog`
WHERE websiteId=3 AND timeAdded>='2013-01-17'
AND timeAdded<='2013-02-17'
AND recipientId IN (10000024, 10000026, 1000028) GROUP BY `recipientId`
I tried:
$command = Yii::app()->db->createCommand();
$command->select('recipientId as broadcasterId, SUM(quantity) as quantity');
$command->from('creditlog');
$command->where('websiteId=:websiteId AND timeAdded>=:dateStart AND timeAdded<=:dateEnd AND recipientId IN (:recipients)',array(':websiteId' => $websiteId, ':dateStart' => $dateStart, ':dateEnd' => $dateEnd, ':recipients' => $broadcasterIds));
$command->group('recipientId');
also the andWhere() function which is in the docs seems to be missing.
The issue is that IN condition but I can't find a way to rewrite it.
Since you don't have access to andWhere, which would make life much simpler, you have to express the parameters with where like this:
$command->where(array(
array('and',
'websiteId=:websiteId',
array('and',
'timeAdded>=:dateStart',
array('and',
// ...
), $parameters);
This is done so that you can at some point use the proper array('in', 'recipientId', $values) syntax to produce the IN(...) SQL.
However, this is ugly and difficult to manage. As long as all the conditions are simply joined together with AND you can construct the data structure programmatically from a saner data representation like this (in effect this is a workaround for the missing andWhere):
$conditions = array(
'websiteId=:websiteId',
'timeAdded>=:dateStart',
'timeAdded<=:dateEnd',
array('in', 'recipientId', $broadcasterIds),
);
$where = null;
foreach ($conditions as $condition) {
if (!$where) {
$where = $condition;
}
else {
$where = array('and', $where, $condition);
}
}
$command->where($where, $parameters);
For more information on why this way of expressing things has to be used you can refer to the documentation for CDbCommand::where.

sql update codeigniter

I am using codeIgniter..
I want to update a table column is_close when id=$ticket_id of my table= tbl_tickets.
I am doing this :-
$data=array(
'is_close'=>1
);
$this->db->where('id',$title_id);
$this->db->update('tbl_tickets',$data);
and I have also done this :-
$sql = "UPDATE tbl_tickets SET is_close={1} WHERE id='$title_id'";
$this->db->query($sql);
both are not working,i.e., my table is not updating the value to 1 and also no error is being shown in the broswer. :(
Edited: Included my model part :
function setClosePost($title_id){
$sql = "UPDATE tbl_tickets SET is_close=0 WHERE id='$title_id'";
$this->db->query($sql);
// $data=array(
// 'is_close'=>1
// );
// $this->db->where('id',$title_id);
// $this->db->update('tbl_tickets',$data);
}
My controller :-
function closePost(){
$this->load->model('helpdesk_model');
$this->helpdesk_model->setClosePost($this->input->post('title_id'));
}
first of all use a get method to check if ticket_id is exist or not.
another thing is always use return in your functions in models so you can check them by if(function_name){...}else{...}
then if your get method returned data correctly try
Model Method
public function set_closed($ticket_id){
$this->db->set(array(
'is_close'=>1
)); // pass fields in array
$this->db->where('id',$ticket_id);
$this->db->update('tbl_tickets'); // table name
return true;
}
then check that in your controller
if($this->Ticket_model->set_closed($ticket_id) == true){
echo 'ticket set to closed correctly';
}else{
echo 'there is some error on updating database'.$this->db->error(); // to checkout db error .
}
First, check $title_id before passing:
var_dump($title_id);
Then, try do "select a row with this id" before updating and after.
$query = $this->db->get_where('tbl_tickets', array('id' => $id));
foreach ($query->result() as $row)
{
var_dump($row->is_close);
}
$data=array(
'is_close'=>1
);
$this->db->where('id',$title_id);
$this->db->update('tbl_tickets',$data);
$query = $this->db->get_where('tbl_tickets', array('id' => $id));
foreach ($query->result() as $row)
{
var_dump($row->is_close);
}
Then, give your table structure.
Just try like this
$sql = "UPDATE tbl_tickets SET is_close='1' WHERE id=".$title_id;
$this->db->query($sql);
just try like this
**function edit($close,$id) {
$sql = "UPDATE tbl_tickets SET is_close= ? WHERE id = ? ";
$this->db->query($sql, array($close,$id));
}**
To handle this type of errors, i mean if reflection is not happen in database, then use below steps to resolve this type of error.
1) use $this->db->last_query() function to print query, using this we can make sure our variable have correct value (should not null or undefined), using that we can make sure also SQL query is valid or not.
2) If SQL query is valid then open phpmyadmin & fire same query into phpmyadmin, it will return error if query columns or table names are invalid.
Use this way, its best way to cross check our SQL queries issues.
I hope it will work.
Thanks
You are trying to update integer(INT) type value, just cross check with your column datatype if that is varchar then you have to put value in a single or double quote.
Like this
$data=array('is_close'=> '1');