$query = $this->createQuery();
return $query->matching($query->like('linker', "$linkerKey=$linkerValue"))
->setOrderings(array('crdate' => $ordering))
->execute();
如何在extbase中调试这样生成的查询?当再次创建相同的查询(但没有execute())并尝试使用var_dump或内部t3lib_div :: debug显示它时,我只会收到一个空白页面。
答案 0 :(得分:20)
在版本 8.7 LTS 中,需要采取另一种方式:
$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL());
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters());
答案 1 :(得分:9)
此信息已在TYPO3 8.7中过时和弃用。有关调试extbase查询的更新方法,请参阅下面的@pgampe的答案。
Extbase现在有一个QueryParser。在您的存储库方法中,在返回执行的查询之前,插入:
$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');
结果是查询部分的表视图,由SQL关键字拆分,例如:
请记住,您的Repository返回的QueryResult可能仍然与SQL查询结果不同。 Extbase使用PropertyMapper尝试将每个结果行转换为ExtbaseObject。如果PropertyMapper配置错误或该行包含根据配置无法转换为数据类型的数据,则将默默跳过这些对象。
答案 2 :(得分:7)
$query = $this->createQuery();
$result = $query->matching($query->like('linker', "$linkerKey=$linkerValue"))
->setOrderings(array('crdate' => $ordering))
->execute();
$GLOBALS['TYPO3_DB']->debugOutput = true;
return $result;
答案 3 :(得分:5)
对extbase的这种破坏很脏,但很有用:
在typo3 / sysext / extbase / Classes / Persistence / Storage / Typo3DbBackend.php中 编辑方法buildQuery(array $ sql) 在return语句之前,添加:
t3lib_div::debug($statement, 'SQL Query Extbase');
使用后删除,不要忘记这会影响在extbase上运行的所有内容,因此仅在开发环境中使用
来源:http://sancer-media.net/2011/extbase-schneller-mysql-debug.html
答案 4 :(得分:1)
在v6.2x或更高版本中,您可以在extBase中调试结果对象,如:
在存储库中:
return $ query-> execute(true); //“true”将返回数组结果
或者您也可以在Controller中调试结果对象:
$ resultObject = $ this-> yourRepository-> findAll();
\ TYPO3 \ CMS \ Extbase \实用\ DebuggerUtility ::的var_dump($ resultObject);
答案 5 :(得分:1)
只要支持$ GLOBALS [' TYPO3_DB'],这就有效。 它将向您显示完整的构建SQL查询。
/**
* @param \TYPO3\CMS\Extbase\Persistence\QueryResultInterface $queryResult
* @param bool $explainOutput
* @return void
*/
public function debugQuery(
\TYPO3\CMS\Extbase\Persistence\QueryResultInterface $queryResult,
$explainOutput = false
) {
$GLOBALS['TYPO3_DB']->debugOuput = 2;
if ($explainOutput) {
$GLOBALS['TYPO3_DB']->explainOutput = true;
}
$GLOBALS['TYPO3_DB']->store_lastBuiltQuery = true;
$queryResult->toArray();
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
$GLOBALS['TYPO3_DB']->debug_lastBuiltQuery
);
$GLOBALS['TYPO3_DB']->store_lastBuiltQuery = false;
$GLOBALS['TYPO3_DB']->explainOutput = false;
$GLOBALS['TYPO3_DB']->debugOuput = false;
}
因此,使用该功能,您可以在控制器中执行以下操作:
$all = $this->repository->findAll();
$this->repository->debugQuery($all);
答案 6 :(得分:0)
一个简单的方法,不改变任何Typo3核心代码,到目前为止在任何论坛中都没有提到使用php“serialize()”方法:
$result = $query->execute();
echo (serialize($result));
在结果对象中,您可以找到SQL查询(查找“statement;”...)
答案 7 :(得分:0)
在这里,我发布了一个方法,您可以在任何类中输入该方法进行调试,当然也可以使其具有特征。评论中还提到了作者和来源,用法:
/**
* Render the generated SQL of a query in TYPO3 8
*
* @author wp_bube https://www.typo3.net/forum/user-profil/benutzer/zeige/benutzer/wp-bube/
* @src https://www.typo3.net/forum/thematik/zeige/thema/125747/
*
* Usage: $this->debugQuery($query);
*
* @param \TYPO3\CMS\Extbase\Persistence\QueryInterface $query
* @param bool $format
* @param bool $exit
*/
private function debugQuery($query, $format = true, $exit = true)
{
function getFormattedSQL($sql_raw)
{
if (empty($sql_raw) || !is_string($sql_raw)) {
return false;
}
$sql_reserved_all = array( 'ACCESSIBLE', 'ACTION', 'ADD', 'AFTER', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AND', 'AS', 'ASC', 'AUTOCOMMIT', 'AUTO_INCREMENT', 'AVG_ROW_LENGTH', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', 'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT', 'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', 'DEFINER', 'DELAYED', 'DELAY_KEY_WRITE', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DO', 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINES', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXECUTE', 'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FIELDS', 'FILE', 'FIRST', 'FIXED', 'FLUSH', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULL', 'FULLTEXT', 'FUNCTION', 'GEMINI', 'GEMINI_SPIN_RETRIES', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP', 'HAVING', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE', 'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INNER', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL', 'INTO', 'INVOKER', 'IS', 'ISOLATION', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEFT', 'LEVEL', 'LIKE', 'LIMIT', 'LINEAR', 'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE', 'MASTER_LOG_POS', 'MASTER_PASSWORD', 'MASTER_PORT', 'MASTER_USER', 'MATCH', 'MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR', 'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MODIFY', 'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NULL', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUTER', 'OUTFILE', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE', 'RAID_TYPE', 'RANGE', 'READ', 'READ_ONLY', 'READ_WRITE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT', 'RETURN', 'RETURNS', 'REVOKE', 'RIGHT', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SELECT', 'SEPARATOR', 'SERIALIZABLE', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT', 'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF', 'SQL_LOG_UPDATE', 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_NO_CACHE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES', 'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE', 'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TO', 'TRAILING', 'TRANSACTIONAL', 'TRUNCATE', 'TYPE', 'TYPES', 'UNCOMMITTED', 'UNION', 'UNIQUE', 'UNLOCK', 'UPDATE', 'USAGE', 'USE', 'USING', 'VALUES', 'VARIABLES', 'VIEW', 'WHEN', 'WHERE', 'WITH', 'WORK', 'WRITE', 'XOR', 'YEAR_MONTH' );
$sql_skip_reserved_words = array('AS', 'ON', 'USING');
$sql_special_reserved_words = array('(', ')');
$sql_raw = str_replace("\n", " ", $sql_raw);
$sql_formatted = "";
$prev_word = "";
$word = "";
for ($i = 0, $j = strlen($sql_raw); $i < $j; $i++) {
$word .= $sql_raw[$i];
$word_trimmed = trim($word);
if ($sql_raw[$i] == " " || in_array($sql_raw[$i], $sql_special_reserved_words)) {
$word_trimmed = trim($word);
$trimmed_special = false;
if (in_array($sql_raw[$i], $sql_special_reserved_words)) {
$word_trimmed = substr($word_trimmed, 0, -1);
$trimmed_special = true;
}
$word_trimmed = strtoupper($word_trimmed);
if (in_array($word_trimmed, $sql_reserved_all) && !in_array($word_trimmed, $sql_skip_reserved_words)) {
if (in_array($prev_word, $sql_reserved_all)) {
$sql_formatted .= '<b>' . strtoupper(trim($word)) . '</b>' . ' ';
} else {
$sql_formatted .= '<br/> ';
$sql_formatted .= '<b>' . strtoupper(trim($word)) . '</b>' . ' ';
}
$prev_word = $word_trimmed;
$word = "";
} else {
$sql_formatted .= trim($word) . ' ';
$prev_word = $word_trimmed;
$word = "";
}
}
}
$sql_formatted .= trim($word);
return $sql_formatted;
}
$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
$doctrineQueryBuilder = $queryParser->convertQueryToDoctrineQueryBuilder($query);
$preparedStatement = $doctrineQueryBuilder->getSQL();
$parameters = $doctrineQueryBuilder->getParameters();
$stringParams = [];
foreach ($parameters as $key => $parameter) {
$stringParams[':' . $key] = $parameter;
}
$statement = strtr($preparedStatement, $stringParams);
if ($format) {
echo '<code>' . getFormattedSQL($statement) . '</code>';
} else {
echo $statement;
}
if ($exit) {
exit;
}
}
答案 8 :(得分:0)
根据@pgampe的答案, @FranzHolzinger的注释中,我用一些提取的方法创建了AbstractonRepository,可以将其提取到自己的存储库中,以使调试的可能性更加舒适。
注意该功能已针对TYPO3版本10.x
进行了测试,并且可以正常工作,因为8.7+
也需要测试。
<?php
namespace VENDOR\Extkey\Domain\Repository;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
use TYPO3\CMS\Core\Exception;
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
/**
* Class AbstractRepository brings methods for query debugging in TYPO3 ver. 10.x
* Based on StackOverflow answer by `pgampe` answer and `FranzHolzinger` comment
* source https://stackoverflow.com/a/44286155/1066240
*
* All repositories in this extension should extend it.
*
* @author Marcus Biesioroff <biesior@gmail.com>
* @package VENDOR\Extkey\Domain\Repository
*/
abstract class AbstractRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
{
/**
* @param mixed $query TYPO3\CMS\Core\Database\Query\QueryBuilder | TYPO3\CMS\Extbase\Persistence\Generic\Query
* @param string|null $title Optional title for var_dump()
* @param bool $replaceParams if true replaces the params in SQL statement with values, otherwise dumps the array of params. @see self::renderDebug()
*
* @throws Exception
*/
protected function debugQuery($query, string $title = null, bool $replaceParams = true): void
{
if ($query instanceof \TYPO3\CMS\Core\Database\Query\QueryBuilder) {
$sql = $query->getSQL();
$params = $query->getParameters();
$this->renderDebug($sql, $params, $title, $replaceParams);
} elseif ($query instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Query) {
$this->parseTheQuery($query, $title, $replaceParams);
} else {
throw new Exception('Unhandled type for SQL query, curently only TYPO3\CMS\Core\Database\Query\QueryBuilder | TYPO3\CMS\Extbase\Persistence\Generic\Query can be debugged with ' . static::getRepositoryClassName() . '::debugQuery() method.', 1596458998);
}
}
/**
* Parses query and displays debug
*
* @param QueryInterface $query Query
* @param string|null $title Optional title
* @param bool $replaceParams if true replaces the params in SQL statement with values, otherwise dumps the array of params. @see self::renderDebug()
*/
private function parseTheQuery(QueryInterface $query, string $title = null, $replaceParams = true): void
{
/** @var Typo3DbQueryParser $queryParser */
$queryParser = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser::class);
$sql = $queryParser->convertQueryToDoctrineQueryBuilder($query)->getSQL();
$params = $queryParser->convertQueryToDoctrineQueryBuilder($query)->getParameters();
$this->renderDebug($sql, $params, $title, $replaceParams);
}
/**
* Renders the output with DebuggerUtility::var_dump()
*
* @param string $sql Generated SQL
* @param array $params Params' array
* @param string|null $title Optional title for var_dump()
* @param bool $replaceParams if true replaces the params in SQL statement with values, otherwise dumps the array of params.
*/
private function renderDebug(string $sql, array $params, string $title = null, bool $replaceParams = true): void
{
if ($replaceParams) {
$search = array();
$replace = array();
foreach ($params as $k => $v) {
$search[] = ':' . $k;
$type = gettype($v);
if (in_array($type, ['integer'])) {
$replace[] = $v;
} else {
$replace[] = '\'' . $v . '\'';
}
}
$sql = str_replace($search, $replace, $sql);
DebuggerUtility::var_dump($sql, $title);
} else {
DebuggerUtility::var_dump(
[
'SQL' => $sql,
'Parameters' => $params
],
$title);
}
}
}
它可以在您的存储库中使用,就像以下方式一样:
<?php
namespace VENDOR\Extkey\Domain\Repository;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
class FooRepository extends \VENDOR\Extkey\Domain\Repository\AbstractRepository
{
public function findByName($name)
{
$query = $this->createQuery();
$query->matching(
$query->equals('name', $name)
);
$this->debugQuery($query, 'Debug SQL in repository with QueryInterface');
return $query->execute();
}
public function queryByName($name)
{
/** @var ConnectionPool $pool */
$pool = GeneralUtility::makeInstance(ConnectionPool::class);
$connection = $pool->getConnectionForTable('tx_extkey_domain_model_yourmodel');
$queryBuilder = $connection->createQueryBuilder();
$query = $queryBuilder
->select('*')
->from('tx_extkey_domain_model_yourmodel')
->where("name like :name")
->setParameter('name', "%{$name}%");
$this->debugQuery($query, 'Debug SQL in my repository with QueryBuilder');
return $query->execute()->fetchAll();
}
答案 9 :(得分:0)
我构建了一个用于 TYPO3 9.5 的实用程序类的静态函数。 它应该在 TYPO3 10.4 中工作。和 TYPO3 11
<?php
namespace MyExtension\MyVendor\Utilities;
/**
* used in TYPO3 9.5.x
*/
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
class DebugQueryUtilities
{
public static function checkExtbaseQuery($query)
{
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$queryParser = $objectManager->get(Typo3DbQueryParser::class);
/** @var QueryBuilder $doctrineQuery */
$doctrineQuery = $queryParser->convertQueryToDoctrineQueryBuilder($query);
$result = $doctrineQuery->getSQL();
$params = $doctrineQuery->getParameters();
DebuggerUtility::var_dump(
$result
); // generate an output in the frontpage
DebuggerUtility::var_dump(
$params
);
return [$result, $params]; // make result vieable with xDebug
}
}
在存储库中使用
...
[$sql,$params] = DebugQueryUtilities::checkExtbaseQuery($query);
return $query->execute()->toArray();