/** * Convert all ModulePlaceholders to Fieldtype modules * */ protected function preload() { if ($this->preloaded) { return; } $debug = $this->wire('config')->debug; if ($debug) { Debug::timer('Fieldtypes.preload'); } foreach ($this->data as $key => $module) { if ($module instanceof ModulePlaceholder) { $fieldtype = $this->wire('modules')->get($module->className()); $this->data[$key] = $fieldtype; } } if ($debug) { Debug::saveTimer('Fieldtypes.preload'); } $this->preloaded = true; }
/** * Overrides default mysqli query method so that it also records and times queries. * */ public function query($sql, $resultmode = MYSQLI_STORE_RESULT) { static $timerTotalQueryTime = 0; static $timerFirstStartTime = 0; if (is_object($sql) && $sql instanceof DatabaseQuery) { $sql = $sql->getQuery(); } if (wire('config')->debug) { $timerKey = Debug::timer(); if (!$timerFirstStartTime) { $timerFirstStartTime = $timerKey; } } else { $timerKey = null; } $result = parent::query($sql, $resultmode); if ($result) { if (wire('config')->debug) { if (isset($result->num_rows)) { $sql .= " [" . $result->num_rows . " rows]"; } if (!is_null($timerKey)) { $elapsed = Debug::timer($timerKey); $timerTotalQueryTime += $elapsed; $timerTotalSinceStart = Debug::timer() - $timerFirstStartTime; $sql .= " [{$elapsed}s, {$timerTotalQueryTime}s, {$timerTotalSinceStart}s]"; } self::$queryLog[] = $sql; } } else { if ($this->throwExceptions) { throw new WireDatabaseException($this->error . (wire('config')->debug ? "\n{$sql}" : '')); } } return $result; }
/** * Execute the process and return the resulting content generated by the process * * @return string * @throws ProcessController404Exception * */ public function ___execute() { $content = ''; $debug = $this->wire('config')->debug; $breadcrumbs = $this->wire('breadcrumbs'); $headline = $this->wire('processHeadline'); $numBreadcrumbs = $breadcrumbs ? count($breadcrumbs) : null; if ($process = $this->getProcess()) { if ($method = $this->getProcessMethodName($this->process)) { $className = $this->process->className(); if ($debug) { Debug::timer("{$className}.{$method}()"); } $content = $this->process->{$method}(); if ($debug) { Debug::saveTimer("{$className}.{$method}()"); } if ($method != 'execute') { // some method other than the main one if (!is_null($numBreadcrumbs) && $numBreadcrumbs === count($breadcrumbs)) { // process added no breadcrumbs, but there should be more if ($headline === $this->wire('processHeadline')) { $process->headline(str_replace('execute', '', $method)); } $moduleInfo = $this->wire('modules')->getModuleInfo($process); $href = substr($this->wire('input')->url(), -1) == '/' ? '../' : './'; $process->breadcrumb($href, $moduleInfo['title']); } } } else { throw new ProcessController404Exception("Unrecognized path"); } } else { throw new ProcessController404Exception("The requested process does not exist"); } return $content; }
/** * Provides the gateway for calling hooks in ProcessWire * * When a non-existant method is called, this checks to see if any hooks have been defined and sends the call to them. * * Hooks are defined by preceding the "hookable" method in a descending class with 3 underscores, like __myMethod(). * When the API calls $myObject->myMethod(), it gets sent to $myObject->___myMethod() after any 'before' hooks have been called. * Then after the ___myMethod() call, any "after" hooks are then called. "after" hooks have the opportunity to change the return value. * * Hooks can also be added for methods that don't actually exist in the class, allowing another class to add methods to this class. * * See the Wire::runHooks() method for the full implementation of hook calls. * * @param string $method * @param array $arguments * @return mixed * @throws WireException * */ public function __call($method, $arguments) { if (self::___debug) { static $timers = array(); $timerName = get_class($this) . "::{$method}"; $notes = array(); foreach ($arguments as $argument) { if (is_object($argument)) { $notes[] = get_class($argument); } else { if (is_array($argument)) { $notes[] = "array(" . count($argument) . ")"; } else { if (strlen($argument) > 20) { $notes[] = substr($argument, 0, 20) . '...'; } } } } $timerName .= "(" . implode(', ', $notes) . ")"; if (isset($timers[$timerName])) { $timers[$timerName]++; $timerName .= " #" . $timers[$timerName]; } else { $timers[$timerName] = 1; } Debug::timer($timerName); $result = $this->runHooks($method, $arguments); Debug::saveTimer($timerName); } else { $result = $this->runHooks($method, $arguments); } if (!$result['methodExists'] && !$result['numHooksRun']) { if ($this->wire('config')->disableUnknownMethodException) { return null; } throw new WireException("Method " . $this->className() . "::{$method} does not exist or is not callable in this context"); } return $result['return']; }
/** * Provides the gateway for calling hooks in ProcessWire * * When a non-existant method is called, this checks to see if any hooks have been defined and sends the call to them. * * Hooks are defined by preceding the "hookable" method in a descending class with 3 underscores, like __myMethod(). * When the API calls $myObject->myMethod(), it gets sent to $myObject->___myMethod() after any 'before' hooks have been called. * Then after the ___myMethod() call, any "after" hooks are then called. "after" hooks have the opportunity to change the return value. * * Hooks can also be added for methods that don't actually exist in the class, allowing another class to add methods to this class. * * See the Wire::runHooks() method for the full implementation of hook calls. * * @param string $method * @param array $arguments * @return mixed * @throws WireException * */ public function __call($method, $arguments) { if (self::___debug) { static $timers = array(); $timerName = get_class($this) . "::{$method}"; $notes = array(); foreach ($arguments as $argument) { if (is_object($argument)) { $notes[] = get_class($argument); } else { if (is_array($argument)) { $notes[] = "array(" . count($argument) . ")"; } else { if (strlen($argument) > 20) { $notes[] = substr($argument, 0, 20) . '...'; } } } } $timerName .= "(" . implode(', ', $notes) . ")"; if (isset($timers[$timerName])) { $timers[$timerName]++; $timerName .= " #" . $timers[$timerName]; } else { $timers[$timerName] = 1; } Debug::timer($timerName); $result = $this->runHooks($method, $arguments); Debug::saveTimer($timerName); } else { $result = $this->runHooks($method, $arguments); } if (!$result['methodExists'] && !$result['numHooksRun']) { return $this->callUnknown($method, $arguments); } return $result['return']; }
/** * Hookable ready for anyone that wants to hook immediately before any autoload modules ready or after all modules ready * */ protected function ___ready() { if ($this->debug) { Debug::timer('boot.modules.autoload.ready'); } $this->wire('modules')->triggerReady(); if ($this->debug) { Debug::saveTimer('boot.modules.autoload.ready'); } }
/** * Given a Selector string, return the Page objects that match in a PageArray. * * Non-visible pages are excluded unless an include=hidden|unpublished|all mode is specified in the selector string, * or in the $options array. If 'all' mode is specified, then non-accessible pages (via access control) can also be included. * * @param string|int|array $selectorString Specify selector string (standard usage), but can also accept page ID or array of page IDs. * @param array|string $options Optional one or more options that can modify certain behaviors. May be assoc array or key=value string. * - findOne: boolean - apply optimizations for finding a single page and include pages with 'hidden' status (default: false) * - getTotal: boolean - whether to set returning PageArray's "total" property (default: true except when findOne=true) * - loadPages: boolean - whether to populate the returned PageArray with found pages (default: true). * The only reason why you'd want to change this to false would be if you only needed the count details from * the PageArray: getTotal(), getStart(), getLimit, etc. This is intended as an optimization for Pages::count(). * Does not apply if $selectorString argument is an array. * - caller: string - optional name of calling function, for debugging purposes, i.e. pages.count * - include: string - Optional inclusion mode of 'hidden', 'unpublished' or 'all'. Default=none. Typically you would specify this * directly in the selector string, so the option is mainly useful if your first argument is not a string. * - loadOptions: array - Optional assoc array of options to pass to getById() load options. * @return PageArray * */ public function ___find($selectorString, $options = array()) { if (is_string($options)) { $options = Selectors::keyValueStringToArray($options); } if (is_array($selectorString)) { if (ctype_digit(implode('', array_keys($selectorString))) && ctype_digit(implode('', $selectorString))) { // if given a regular array of page IDs, we delegate that to getById() method, but with access/visibility control return $this->filterListable($this->getById($selectorString), isset($options['include']) ? $options['include'] : ''); } else { // some other type of array/values that we don't yet recognize // @todo add support for array selectors, per Selectors::arrayToSelectorString() return new PageArray(); } } $loadPages = true; $loadOptions = isset($options['loadOptions']) && is_array($options['loadOptions']) ? $options['loadOptions'] : array(); $debug = $this->wire('config')->debug; if (array_key_exists('loadPages', $options)) { $loadPages = (bool) $options['loadPages']; } if (!strlen($selectorString)) { return new PageArray(); } if ($selectorString === '/' || $selectorString === 'path=/') { $selectorString = 1; } if ($selectorString[0] == '/') { // if selector begins with a slash, then we'll assume it's referring to a path $selectorString = "path={$selectorString}"; } else { if (strpos($selectorString, ",") === false && strpos($selectorString, "|") === false) { // there is just one param. Lets see if we can find a shortcut. if (ctype_digit("{$selectorString}") || strpos($selectorString, "id=") === 0) { // if selector is just a number, or a string like "id=123" then we're going to do a shortcut $s = str_replace("id=", '', $selectorString); if (ctype_digit("{$s}")) { $value = $this->getById(array((int) $s), $loadOptions); if (empty($options['findOne'])) { $value = $this->filterListable($value, isset($options['include']) ? $options['include'] : ''); } if ($debug) { $this->debugLog('find', $selectorString . " [optimized]", $value); } return $value; } } } } if (isset($options['include']) && in_array($options['include'], array('hidden', 'unpublished', 'all'))) { $selectorString .= ", include={$options['include']}"; } // see if this has been cached and return it if so $pages = $this->getSelectorCache($selectorString, $options); if (!is_null($pages)) { if ($debug) { $this->debugLog('find', $selectorString, $pages . ' [from-cache]'); } return $pages; } // check if this find has already been executed, and return the cached results if so // if(null !== ($pages = $this->getSelectorCache($selectorString, $options))) return clone $pages; // if a specific parent wasn't requested, then we assume they don't want results with status >= Page::statusUnsearchable // if(strpos($selectorString, 'parent_id') === false) $selectorString .= ", status<" . Page::statusUnsearchable; $caller = isset($options['caller']) ? $options['caller'] : 'pages.find'; $selectors = new Selectors($selectorString); $pageFinder = $this->getPageFinder(); if ($debug) { Debug::timer("{$caller}({$selectorString})", true); } $pagesInfo = $pageFinder->find($selectors, $options); // note that we save this pagination state here and set it at the end of this method // because it's possible that more find operations could be executed as the pages are loaded $total = $pageFinder->getTotal(); $limit = $pageFinder->getLimit(); $start = $pageFinder->getStart(); if ($loadPages) { // parent_id is null unless a single parent was specified in the selectors $parent_id = $pageFinder->getParentID(); $idsSorted = array(); $idsByTemplate = array(); // organize the pages by template ID foreach ($pagesInfo as $page) { $tpl_id = $page['templates_id']; if (!isset($idsByTemplate[$tpl_id])) { $idsByTemplate[$tpl_id] = array(); } $idsByTemplate[$tpl_id][] = $page['id']; $idsSorted[] = $page['id']; } if (count($idsByTemplate) > 1) { // perform a load for each template, which results in unsorted pages $unsortedPages = new PageArray(); foreach ($idsByTemplate as $tpl_id => $ids) { $opt = $loadOptions; $opt['template'] = $this->templates->get($tpl_id); $opt['parent_id'] = $parent_id; $unsortedPages->import($this->getById($ids, $opt)); } // put pages back in the order that the selectorEngine returned them in, while double checking that the selector matches $pages = new PageArray(); foreach ($idsSorted as $id) { foreach ($unsortedPages as $page) { if ($page->id == $id) { $pages->add($page); break; } } } } else { // there is only one template used, so no resorting is necessary $pages = new PageArray(); reset($idsByTemplate); $opt = $loadOptions; $opt['template'] = $this->templates->get(key($idsByTemplate)); $opt['parent_id'] = $parent_id; $pages->import($this->getById($idsSorted, $opt)); } } else { $pages = new PageArray(); } $pages->setTotal($total); $pages->setLimit($limit); $pages->setStart($start); $pages->setSelectors($selectors); $pages->setTrackChanges(true); if ($loadPages) { $this->selectorCache($selectorString, $options, $pages); } if ($this->config->debug) { $this->debugLog('find', $selectorString, $pages); } if ($debug) { $count = $pages->count(); $note = ($count == $total ? $count : $count . "/{$total}") . " page(s)"; if ($count) { $note .= ": " . $pages->first()->path; if ($count > 1) { $note .= " ... " . $pages->last()->path; } } Debug::saveTimer("{$caller}({$selectorString})", $note); } if ($this->hasHook('found()')) { $this->found($pages, array('pageFinder' => $pageFinder, 'pagesInfo' => $pagesInfo, 'options' => $options)); } return $pages; }
/** * Stop a debug timer, only works when module debug mode is on ($this->debug) * * @param int $key The key returned by debugTimerStart * */ protected function debugTimerStop($key) { if (!$this->debug) { return; } $log = $this->debugLog[$key]; $timerKey = $log[0]; $log[0] = Debug::timer($timerKey); $this->debugLog[$key] = $log; Debug::removeTimer($timerKey); }
for ($counter = 0; $counter < 1000; $counter++) { // write $ok = $storage->write(rand(0, COUNT_FILES), randomStr(), array()); if ($ok === FALSE) { $hits['cantwrite']++; } // remove //$ok = $storage->remove(rand(0, COUNT_FILES)); //if (!$ok) $hits['cantdelete']++; // read $res = $storage->read(rand(0, COUNT_FILES)); // compare if ($res === NULL) { $hits['notfound']++; } elseif (checkStr($res)) { $hits['ok']++; } else { $hits['error']++; } } $time = Debug::timer(); echo "Results:\n"; Debug::dump($hits); // expected results are: // [ok] => 1000 // should be 1000. If unlink() is used, sum [ok] + [notfound] should be 1000 // [notfound] => 0 // means "file not found", should be 0 if delete() is not used // [error] => 0, // means "file contents is damaged", MUST be 0 // [cantwrite] => ?, // means "somebody else is writing this file" // [cantdelete] => 0 // means "delete() has timeout", should be 0 echo $hits['error'] == 0 ? 'PASSED' : 'NOT PASSED!'; echo "\ntakes {$time} ms";
<a href="http://www.processwire.com">ProcessWire <?php echo $config->version . '.' . $config->systemVersion; ?> </a> <span>/</span> Copyright © <?php echo date("Y"); ?> by Ryan Cramer </div> <div id="right"> <div id="code"> <?php echo "This page was created in <span>" . Debug::timer('futura_timer') . "</span> seconds"; ?> </div> </div> </div> </div> </body> <?php } ?>
<div id="left"> <a href="http://www.processwire.com">ProcessWire <?php echo $config->version . ' <!--v' . $config->systemVersion; ?> --></a> <span>/</span> Develop by <a href="http://www.bungamata.com/">Bunga Mata</a> </div> <div id="right"> <div id="code"> <?php echo "This page was created in <span>" . Debug::timer('ergo') . "</span> seconds"; ?> </div> <div id="top"><a href="#">Top</a></div> </div> </div> </div><!-- Footer END--> </div><!-- Right END--> <div class="clear"></div>
/** * Execute the process and return the resulting content generated by the process * * @return string * @throws ProcessController404Exception * */ public function ___execute() { $content = ''; $method = ''; $debug = $this->wire('config')->debug; $breadcrumbs = $this->wire('breadcrumbs'); $headline = $this->wire('processHeadline'); $numBreadcrumbs = $breadcrumbs ? count($breadcrumbs) : null; if ($process = $this->getProcess()) { if ($method = $this->getProcessMethodName($this->process)) { $className = $this->process->className(); if ($debug) { Debug::timer("{$className}.{$method}()"); } $content = $this->process->{$method}(); if ($debug) { Debug::saveTimer("{$className}.{$method}()"); } if ($method != 'execute') { // some method other than the main one if (!is_null($numBreadcrumbs) && $numBreadcrumbs === count($breadcrumbs)) { // process added no breadcrumbs, but there should be more if ($headline === $this->wire('processHeadline')) { $process->headline(str_replace('execute', '', $method)); } $moduleInfo = $this->wire('modules')->getModuleInfo($process); $href = substr($this->wire('input')->url(), -1) == '/' ? '../' : './'; $process->breadcrumb($href, $moduleInfo['title']); } } } else { throw new ProcessController404Exception("Unrecognized path"); } } else { throw new ProcessController404Exception("The requested process does not exist"); } if (empty($content) || is_bool($content)) { $content = $this->process->getViewVars(); } if (is_array($content)) { // array of returned content indicates variables to send to a view if (count($content)) { $viewFile = $this->getViewFile($this->process, $method); if ($viewFile) { // get output from a separate view file $template = new TemplateFile($viewFile); foreach ($content as $key => $value) { $template->set($key, $value); } $content = $template->render(); } } else { $content = ''; } } return $content; }
<h1>Nette\Debug timer test</h1> <?php require_once '../../Nette/loader.php'; /*use Nette\Debug;*/ Debug::timer(); sleep(1); Debug::timer('foo'); sleep(1); Debug::dump(round(Debug::timer(), 1)); Debug::dump(round(Debug::timer('foo'), 1));