Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

<?php
/**
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @since         DebugKit 0.1
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 */

App::uses('DebugKitDebugger', 'DebugKit.Lib');
App::uses('AppHelper', 'View/Helper');
App::uses('ConnectionManager', 'Model');

/**
 * Provides Base methods for content specific debug toolbar helpers.
 * Acts as a facade for other toolbars helpers as well.
 *
 * @since         DebugKit 0.1
 */
class ToolbarHelper extends AppHelper {

/**
 * settings property to be overloaded. Subclasses should specify a format
 *
 * @var array
 */
        public $settings = array();

/**
 * flag for whether or not cache is enabled.
 *
 * @var boolean
 */
        protected $_cacheEnabled = false;

/**
 * Construct the helper and make the backend helper.
 *
 * @param $View
 * @param array|string $options
 * @return \ToolbarHelper
 */
        public function __construct($View, $options = array()) {
                $this->_myName = strtolower(get_class($this));
                $this->settings = array_merge($this->settings, $options);

                if ($this->_myName !== 'toolbarhelper') {
                        parent::__construct($View, $options);
                        return;
                }

                if (!isset($options['output'])) {
                        $options['output'] = 'DebugKit.HtmlToolbar';
                }
                $className = $options['output'];
                if (strpos($options['output'], '.') !== false) {
                        list($plugin, $className) = explode('.', $options['output']);
                }
                $this->_backEndClassName = $className;
                $this->helpers[$options['output']] = $options;
                if (isset($options['cacheKey']) && isset($options['cacheConfig'])) {
                        $this->_cacheKey = $options['cacheKey'];
                        $this->_cacheConfig = $options['cacheConfig'];
                        $this->_cacheEnabled = true;
                }

                parent::__construct($View, $options);
        }

/**
 * afterLayout callback
 *
 * @param string $layoutFile
 * @return void
 */
        public function afterLayout($layoutFile) {
                if (!$this->request->is('requested')) {
                        $this->send();
                }
        }

/**
 * Get the name of the backend Helper
 * used to conditionally trigger toolbar output
 *
 * @return string
 */
        public function getName() {
                return $this->_backEndClassName;
        }

/**
 * call__
 *
 * Allows method calls on backend helper
 *
 * @param string $method
 * @param mixed $params
 * @return mixed|void
 */
        public function __call($method, $params) {
                if (method_exists($this->{$this->_backEndClassName}, $method)) {
                        return $this->{$this->_backEndClassName}->dispatchMethod($method, $params);
                }
        }

/**
 * Allows for writing to panel cache from view.
 * Some panels generate all variables in the view by
 * necessity ie. Timer. Using this method, will allow you to replace in full
 * the content for a panel.
 *
 * @param string $name Name of the panel you are replacing.
 * @param string $content Content to write to the panel.
 * @return boolean Success of write.
 */
        public function writeCache($name, $content) {
                if (!$this->_cacheEnabled) {
                        return false;
                }
                $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
                $existing[0][$name]['content'] = $content;
                return Cache::write($this->_cacheKey, $existing, $this->_cacheConfig);
        }

/**
 * Read the toolbar
 *
 * @param string $name Name of the panel you want cached data for
 * @param integer $index
 * @return mixed Boolean false on failure, array of data otherwise.
 */
        public function readCache($name, $index = 0) {
                if (!$this->_cacheEnabled) {
                        return false;
                }
                $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
                if (!isset($existing[$index][$name]['content'])) {
                        return false;
                }
                return $existing[$index][$name]['content'];
        }

/**
 * Gets the query logs for the given connection names.
 *
 * ### Options
 *
 * - explain - Whether explain links should be generated for this connection.
 * - cache - Whether the toolbar_state Cache should be updated.
 * - threshold - The threshold at which a visual 'maybe slow' flag should be added.
 *   results with rows/ms lower than $threshold will be marked.
 *
 * @param string $connection Connection name to get logs for.
 * @param array $options Options for the query log retrieval.
 * @return array Array of data to be converted into a table.
 */
        public function getQueryLogs($connection, $options = array()) {
                $options += array('explain' => false, 'cache' => true, 'threshold' => 20);
                $db = ConnectionManager::getDataSource($connection);

                if (!method_exists($db, 'getLog')) {
                        return array();
                }

                $log = $db->getLog();

                $out = array(
                        'queries' => array(),
                        'count' => $log['count'],
                        'time' => $log['time']
                );
                foreach ($log['log'] as $i => $query) {
                        $isSlow = (
                                $query['took'] > 0 &&
                                $query['numRows'] / $query['took'] != 1 &&
                                $query['numRows'] / $query['took'] <= $options['threshold']
                        );
                        $query['actions'] = '';
                        $isHtml = ($this->getName() === 'HtmlToolbar');
                        if ($isSlow && $isHtml) {
                                $query['actions'] = sprintf(
                                        '<span class="slow-query">%s</span>',
                                        __d('debug_kit', 'maybe slow')
                                );
                        } elseif ($isSlow) {
                                $query['actions'] = '*';
                        }
                        if ($options['explain'] && $isHtml) {
                                $query['actions'] .= $this->explainLink($query['query'], $connection);
                        }
                        if ($isHtml) {
                                $query['query'] = h($query['query']);
                                if (!empty($query['params']) && is_array($query['params'])) {
                                        $bindParam = $bindType = null;
                                        if (preg_match('/.+ :.+/', $query['query'])) {
                                                $bindType = true;
                                        }
                                        foreach ($query['params'] as $bindKey => $bindVal) {
                                                if ($bindType === true) {
                                                        $bindParam .= h($bindKey) . " => " . h($bindVal) . ", ";
                                                } else {
                                                        $bindParam .= h($bindVal) . ", ";
                                                }
                                        }
                                        $query['query'] .= " [ " . rtrim($bindParam, ', ') . " ]";
                                }
                        }
                        unset($query['params']);
                        $out['queries'][] = $query;
                }
                if ($options['cache']) {
                        $existing = $this->readCache('sql_log');
                        $existing[$connection] = $out;
                        $this->writeCache('sql_log', $existing);
                }
                return $out;
        }

}