public function process_db_object($id, wpdb $db) { global $EZSQL_ERROR; $rows = array(); $types = array(); $total_time = 0; $has_result = false; $has_trace = false; $i = 0; foreach ((array) $db->queries as $query) { # @TODO: decide what I want to do with this: if (false !== strpos($query[2], 'wp_admin_bar') and !isset($_REQUEST['qm_display_admin_bar'])) { continue; } $sql = $query[0]; $ltime = $query[1]; $stack = $query[2]; $has_trace = isset($query['trace']); $has_result = isset($query['result']); if (isset($query['result'])) { $result = $query['result']; } else { $result = null; } $total_time += $ltime; if (isset($query['trace'])) { $trace = $query['trace']; $component = $query['trace']->get_component(); $caller = $query['trace']->get_caller(); $caller_name = $caller['id']; $caller = $caller['display']; } else { $trace = null; $component = null; $callers = explode(',', $stack); $caller = trim(end($callers)); if (false !== strpos($caller, '(')) { $caller_name = substr($caller, 0, strpos($caller, '(')) . '()'; } else { $caller_name = $caller; } } $sql = trim($sql); $type = QM_Util::get_query_type($sql); $this->log_type($type); $this->log_caller($caller_name, $ltime, $type); $this->maybe_log_dupe($sql, $i); if ($component) { $this->log_component($component, $ltime, $type); } if (!isset($types[$type]['total'])) { $types[$type]['total'] = 1; } else { $types[$type]['total']++; } if (!isset($types[$type]['callers'][$caller])) { $types[$type]['callers'][$caller] = 1; } else { $types[$type]['callers'][$caller]++; } $row = compact('caller', 'caller_name', 'stack', 'sql', 'ltime', 'result', 'type', 'component', 'trace'); if (is_wp_error($result)) { $this->data['errors'][] = $row; } if (self::is_expensive($row)) { $this->data['expensive'][] = $row; } $rows[$i] = $row; $i++; } if ('$wpdb' === $id && !$has_result && !empty($EZSQL_ERROR) && is_array($EZSQL_ERROR)) { // Fallback for displaying database errors when wp-content/db.php isn't in place foreach ($EZSQL_ERROR as $error) { $row = array('caller' => 'Unknown', 'caller_name' => 'Unknown', 'stack' => '', 'sql' => $error['query'], 'result' => new WP_Error('qmdb', $error['error_str']), 'type' => '', 'component' => false, 'trace' => null); $this->data['errors'][] = $row; } } $total_qs = count($rows); $this->data['total_qs'] += $total_qs; $this->data['total_time'] += $total_time; # @TODO put errors in here too: # @TODO proper class instead of (object) $this->data['dbs'][$id] = (object) compact('rows', 'types', 'has_result', 'has_trace', 'total_time', 'total_qs'); }
public function output() { $data = $this->collector->get_data(); if (empty($data['dupes'])) { return; } $colspan = empty($data['dupe_components']) ? 4 : 5; echo '<div class="qm" id="' . esc_attr($this->collector->id()) . '">'; echo '<table cellspacing="0">'; echo '<thead>'; echo '<tr>'; echo '<th colspan="' . absint($colspan) . '">' . esc_html($this->collector->name()) . '</th>'; echo '</tr>'; echo '<tr>'; echo '<th>' . esc_html__('Query', 'query-monitor') . '</th>'; echo '<th class="qm-num">' . esc_html__('Count', 'query-monitor') . '</th>'; echo '<th>' . esc_html__('Callers', 'query-monitor') . '</th>'; if (!empty($data['dupe_components'])) { echo '<th>' . esc_html__('Components', 'query-monitor') . '</th>'; } echo '<th>' . esc_html__('Potential Troublemakers', 'query-monitor') . '</th>'; echo '</tr>'; echo '</thead>'; echo '<tbody>'; /* translators: %s: Number of calls to a PHP function */ $call_text = _n_noop('%s call', '%s calls', 'query-monitor'); foreach ($data['dupes'] as $sql => $queries) { // This should probably happen in the collector's processor $type = QM_Util::get_query_type($sql); $sql_out = self::format_sql($sql); if ('SELECT' !== $type) { $sql_out = "<span class='qm-nonselectsql'>{$sql_out}</span>"; } echo '<tr>'; echo '<td class="qm-row-sql qm-ltr qm-wrap">'; echo $sql_out; // WPCS: XSS ok; echo '</td>'; echo '<td class="qm-num">'; echo esc_html(number_format_i18n(count($queries), 0)); echo '</td>'; echo '<td class="qm-row-caller qm-nowrap qm-ltr">'; foreach ($data['dupe_callers'][$sql] as $caller => $calls) { printf('<a href="#" class="qm-filter-trigger" data-qm-target="db_queries-wpdb" data-qm-filter="caller" data-qm-value="%s">%s</a><br><span class="qm-info"> %s</span><br>', esc_attr($caller), esc_html($caller), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; if (isset($data['dupe_components'][$sql])) { echo '<td class="qm-row-component qm-nowrap">'; foreach ($data['dupe_components'][$sql] as $component => $calls) { printf('%s<br><span class="qm-info"> %s</span><br>', esc_html($component), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; } echo '<td class="qm-row-caller qm-nowrap qm-ltr">'; foreach ($data['dupe_sources'][$sql] as $source => $calls) { printf('%s<br><span class="qm-info"> %s</span><br>', esc_html($source), esc_html(sprintf(translate_nooped_plural($call_text, $calls, 'query-monitor'), number_format_i18n($calls)))); } echo '</td>'; echo '</tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; }