Skip to content

Commit

Permalink
Update DatabaseQuery class to support a getDebugQuery() method that r…
Browse files Browse the repository at this point in the history
…eturns the query (string) with all bind variables populated into the SQL
  • Loading branch information
ryancramerdesign committed May 29, 2020
1 parent 44405ee commit b475148
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 18 deletions.
58 changes: 42 additions & 16 deletions wire/core/DatabaseQuery.php
Expand Up @@ -77,7 +77,8 @@ abstract class DatabaseQuery extends WireData {
*
*/
protected $bindOptions = array(
'prefix' => 'pw', // prefix for auto-generated keys
'prefix' => 'pw', // prefix for auto-generated global keys
'suffix' => 'X', // 1-character suffix for auto-generated keys
'global' => false // globally unique among all bind keys in all instances?
);

Expand Down Expand Up @@ -249,43 +250,45 @@ public function bindTypes($bindTypes = null) {
*/
public function getUniqueBindKey(array $options = array()) {

static $alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

if(empty($options['key'])) {
// auto-generate key
$key = ':';
$prefix = (isset($options['prefix']) ? $options['prefix'] : $this->bindOptions['prefix']);
$suffix = isset($option['suffix']) && $options['suffix'] ? $options['suffix'] : $this->bindOptions['suffix'];
$value = isset($options['value']) ? $options['value'] : null;
$global = isset($options['global']) ? $options['global'] : $this->bindOptions['global'];

if($global) $key .= $prefix . $this->instanceNum;

if($value !== null) {
if(is_int($value)) {
$key .= "int";
$key .= "i";
} else if(is_string($value)) {
$key .= "str";
$key .= "s";
} else if(is_array($value)) {
$key .= "arr";
$key .= "a";
} else {
$key .= "oth";
$key .= "o";
}
} else if($prefix && !$global) {
$key .= $prefix;
} else {
$key .= "v";
}

$k = $key;

$n = 0;
while(isset($this->bindKeys[$key])) {
$key = $k . (isset($alpha[$n]) ? $alpha[$n] : $n);
$n++;
$k = $key;
$key = $k . '0' . $suffix;

while(isset($this->bindKeys[$key]) && ++$n) {
$key = $k . $n . $suffix;
}

} else {
// provided key, make sure it is valid and unique
$key = ltrim($options['key'], ':');
// provided key, make sure it is valid and unique (this part is not typically used)
$key = ltrim($options['key'], ':') . 'X';
if(!ctype_alnum(str_replace('_', '', $key))) $key = $this->wire('database')->escapeCol($key);
if(empty($key) || ctype_digit($key) || isset($this->bindKeys[":$key"])) {
if(empty($key) || ctype_digit($key[0]) || isset($this->bindKeys[":$key"])) {
// if key is not valid, then auto-generate one instead
unset($options['key']);
$key = $this->getUniqueBindKey($options);
Expand Down Expand Up @@ -331,7 +334,9 @@ public function getBindValues($options = array()) {

if(!empty($options['inSQL'])) {
foreach(array_keys($bindValues) as $bindKey) {
if(!preg_match('/' . $bindKey . '\b/', $options['inSQL'])) {
if(strpos($options['inSQL'], $bindKey) === false) {
unset($bindValues[$bindKey]);
} else if(!preg_match('/' . $bindKey . '\b/', $options['inSQL'])) {
unset($bindValues[$bindKey]);
}
}
Expand Down Expand Up @@ -577,10 +582,31 @@ public function merge(DatabaseQuery $query) {

/**
* Generate the SQL query based on everything set in this DatabaseQuery object
*
* @return string
*
*/
abstract public function getQuery();

/**
* Get SQL query with bind params populated for debugging purposes (not to be used as actual query)
*
* @return string
*
*/
public function getDebugQuery() {
$sql = $this->getQuery();
$suffix = $this->bindOptions['suffix'];
foreach($this->bindValues as $bindKey => $bindValue) {
if($bindKey[strlen($bindKey)-1] === $suffix) {
$sql = str_replace($bindKey, $bindValue);
} else {
$sql = preg_replace('/' . $bindKey . '\b/', $bindValue, $sql);
}
}
return $sql;
}

/**
* Return generated SQL for entire query or specific method
*
Expand Down
5 changes: 3 additions & 2 deletions wire/core/FieldsTableTools.php
Expand Up @@ -126,8 +126,9 @@ public function setUniqueIndex(Field $field, $add = true) {
// remove requested
if($uniqueIndexName === $requireIndexName) {
// remove the unique index
$sql = "ALTER TABLE $table DROP INDEX `$requireIndexName`";
try {
$result = $database->exec("ALTER TABLE $table DROP INDEX `$requireIndexName`");
$result = $database->exec($sql) !== false;
if($result) $action = 'remove';
} catch(\Exception $e) {
$result = false;
Expand All @@ -144,7 +145,7 @@ public function setUniqueIndex(Field $field, $add = true) {
$col = $database->escapeCol($col);
$sql = "ALTER TABLE $table ADD UNIQUE `$requireIndexName` (`$col`)";
try {
$result = $database->exec($sql);
$result = $database->exec($sql) !== false;
if($result) $action = 'add';
} catch(\Exception $e) {
$action = 'remove';
Expand Down

2 comments on commit b475148

@adrianbj
Copy link
Contributor

@adrianbj adrianbj commented on b475148 May 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryancramerdesign - excited to see this implemented - thanks for getting it in so quickly. I know @BernhardBaumrock will also be happy.

I just tried to implement into Tracy's "Selector Queries" table, but not sure how. Currently I hook into PageFinder::getQuery. Does the PageFinder class need to change to allow me to do PageFinder::getDebugQuery (or similar), or is there a better way to do this already that I am not thinking of?

Thanks.

Just to note that this is now being discussed here: processwire/processwire-issues#1173 (comment)

@BernhardBaumrock
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm VERY happy :) :) :)

Please sign in to comment.