1. sfWebDebugPanelView.class.php
  2. /** * sfWebDebugPanelView adds a panel to the web debug toolbar with information about the view layer. * * @package symfony * @subpackage debug * @author Kris Wallsmith * @version SVN: $Id: sfWebDebugPanelView.class.php 24069 2009-11-17 06:59:01Z Kris.Wallsmith $ */
  3. class sfWebDebugPanelView extends sfWebDebugPanel
  4. {
  5. protected
  6. $actions = array(),
  7. $partials = array();
  8. /**
  9. * Constructor.
  10. *
  11. * @param sfWebDebug $webDebug The web debug toolbar instance
  12. */
  13. public function __construct(sfWebDebug $webDebug)
  14. {
  15. parent::__construct($webDebug);
  16. $this->webDebug->getEventDispatcher()->connect('controller.change_action', array($this, 'listenForChangeAction'));
  17. $this->webDebug->getEventDispatcher()->connect('template.filter_parameters', array($this, 'filterTemplateParameters'));
  18. }
  19. /**
  20. * Resets the parameter collections.
  21. *
  22. * @param sfEvent $event
  23. */
  24. public function listenForChangeAction(sfEvent $event)
  25. {
  26. $this->actions = array();
  27. $this->partials = array();
  28. }
  29. /**
  30. * Stacks action and partial parameters in the template.filter_parameters event.
  31. *
  32. * @param sfEvent $event
  33. * @param array $parameters
  34. *
  35. * @return array
  36. */
  37. public function filterTemplateParameters(sfEvent $event, $parameters)
  38. {
  39. $entry = array('parameters' => $parameters);
  40. if ('action' == $parameters['sf_type'] && $file = $this->getLastTemplate())
  41. {
  42. $this->actions[] = $entry + array('file' => $file);
  43. }
  44. else if ('partial' == $parameters['sf_type'] && $file = $this->getLastTemplate('sfPartialView'))
  45. {
  46. $this->partials[] = $entry + array('file' => $file);
  47. }
  48. return $parameters;
  49. }
  50. /**
  51. * Returns the path to the last template rendered.
  52. *
  53. * @param string $class Name of the rendering view class
  54. *
  55. * @return string|null
  56. */
  57. protected function getLastTemplate($class = 'sfPHPView')
  58. {
  59. foreach (array_reverse($this->webDebug->getLogger()->getLogs()) as $log)
  60. {
  61. if (
  62. ($class == $log['type'] || (class_exists($log['type'], false) && is_subclass_of($log['type'], $class)))
  63. &&
  64. preg_match('/^Render "(.*)"$/', $log['message'], $match)
  65. )
  66. {
  67. return $match[1];
  68. }
  69. }
  70. }
  71. /**
  72. * @see sfWebDebugPanel
  73. */
  74. public function getTitle()
  75. {
  76. if (count($this->actions) || count($this->partials))
  77. {
  78. return '<img src="'.$this->webDebug->getOption('image_root_path').'/view.png" alt="View Layer" /> view';
  79. }
  80. }
  81. /**
  82. * @see sfWebDebugPanel
  83. */
  84. public function getPanelTitle()
  85. {
  86. return 'View Layer';
  87. }
  88. /**
  89. * @see sfWebDebugPanel
  90. */
  91. public function getPanelContent()
  92. {
  93. $html = array();
  94. foreach ($this->actions as $action)
  95. {
  96. $html[] = $this->renderTemplateInformation($action['file'], $action['parameters']);
  97. }
  98. foreach ($this->partials as $partial)
  99. {
  100. $html[] = $this->renderTemplateInformation($partial['file'], $partial['parameters'], 'Partial');
  101. }
  102. return join("\n", $html);
  103. }
  104. /**
  105. * Renders information about the passed template and its parameters.
  106. *
  107. * The rendered HTML for each parameter is filtered through the "debug.web.view.filter_parameter_html" event.
  108. *
  109. * @param string $file The template file path
  110. * @param array $parameters
  111. * @param string $label
  112. *
  113. * @return string
  114. */
  115. protected function renderTemplateInformation($file, $parameters, $label = 'Template')
  116. {
  117. static $i = 0;
  118. $parameters = $this->filterCoreParameters($parameters);
  119. $i++;
  120. $html = array();
  121. $html[] = sprintf('<h2>%s: %s %s</h2>', $label, $this->formatFileLink($file, null, $this->shortenTemplatePath($file)), $this->getToggler('sfWebDebugViewTemplate'.$i));
  122. $html[] = '<div id="sfWebDebugViewTemplate'.$i.'" style="display:'.(1 == $i ? 'block' : 'none').'">';
  123. if (count($parameters))
  124. {
  125. $html[] = '<p>Parameters:</p>';
  126. $html[] = '<ul>';
  127. foreach ($parameters as $name => $parameter)
  128. {
  129. $presentation = '<li>'.$this->formatParameterAsHtml($name, $parameter).'</li>';
  130. $html[] = $this->webDebug->getEventDispatcher()->filter(new sfEvent($this, 'debug.web.view.filter_parameter_html', array('parameter' => $parameter)), $presentation)->getReturnValue();
  131. }
  132. $html[] = '</ul>';
  133. }
  134. else
  135. {
  136. $html[] = '<p>No parameters were passed to this template.</p>';
  137. }
  138. $html[] = '</div>';
  139. return join("\n", $html);
  140. }
  141. /**
  142. * Formats information about a parameter as HTML.
  143. *
  144. * @param string $name
  145. * @param mixed $parameter
  146. *
  147. * @return string
  148. */
  149. protected function formatParameterAsHtml($name, $parameter)
  150. {
  151. if (!method_exists($this, $method = 'format'.ucwords(gettype($parameter)).'AsHtml'))
  152. {
  153. $method = 'getParameterDescription';
  154. }
  155. return $this->$method($name, $parameter);
  156. }
  157. /**
  158. * Formats object information as HTML.
  159. *
  160. * @param string $name
  161. * @param object $parameter
  162. *
  163. * @return string
  164. */
  165. protected function formatObjectAsHtml($name, $parameter)
  166. {
  167. if ($parameter instanceof sfForm)
  168. {
  169. return $this->formatFormAsHtml($name, $parameter);
  170. }
  171. else
  172. {
  173. return $this->getParameterDescription($name, $parameter);
  174. }
  175. }
  176. /**
  177. * Formats form information as HTML.
  178. *
  179. * @param string $name
  180. * @param sfForm $form
  181. *
  182. * @return string
  183. */
  184. protected function formatFormAsHtml($name, sfForm $form)
  185. {
  186. static $i = 0;
  187. $i++;
  188. if ($form->hasErrors() && sfLogger::NOTICE < $this->getStatus())
  189. {
  190. $this->setStatus(sfLogger::NOTICE);
  191. }
  192. $html = array();
  193. $html[] = $this->getParameterDescription($name, $form, $form->hasErrors() ? '<code class="sfWebDebugWarning">$%s</code>' : null);
  194. $html[] = $this->getToggler('sfWebDebugViewForm'.$i);
  195. $html[] = '<div id="sfWebDebugViewForm'.$i.'" style="display:none">';
  196. foreach ($form->getGlobalErrors() as $error)
  197. {
  198. $html[] = sprintf('<p><span class="sfWebDebugWarning">%s</span></p>', $error);
  199. }
  200. $html[] = '<ul>'.$this->formatFormFieldSchemaAsHtml($form->getFormFieldSchema(), $name.'[%s]').'</ul>';
  201. $html[] = '</div>';
  202. return join("\n", $html);
  203. }
  204. /**
  205. * Formats form field schema information as HTML.
  206. *
  207. * @param sfFormFieldSchema $fieldSchema
  208. * @param string $nameFormat
  209. *
  210. * @return string
  211. */
  212. protected function formatFormFieldSchemaAsHtml(sfFormFieldSchema $fieldSchema, $nameFormat = '%s')
  213. {
  214. $html = array();
  215. foreach ($fieldSchema as $field)
  216. {
  217. $name = sprintf($nameFormat, $this->varExport($field->getName()));
  218. if ($field instanceof sfFormFieldSchema)
  219. {
  220. $html[] = $this->formatFormFieldSchemaAsHtml($field, $name.'[%s]');
  221. }
  222. else
  223. {
  224. $html[] = '<li>';
  225. $html[] = $this->getParameterDescription($name, $field->getWidget());
  226. if ($field->hasError())
  227. {
  228. $html[] = sprintf('<p><span class="sfWebDebugWarning">%s</span></p>', $field->getError());
  229. }
  230. $html[] = '</li>';
  231. }
  232. }
  233. return join("\n", $html);
  234. }
  235. /**
  236. * Formats information about a parameter as HTML.
  237. *
  238. * @param string $name
  239. * @param mixed $parameter
  240. *
  241. * @return string
  242. */
  243. protected function getParameterDescription($name, $parameter, $nameFormat = null, $typeFormat = null)
  244. {
  245. if (null === $nameFormat)
  246. {
  247. $nameFormat = '<code>$%s</code>';
  248. }
  249. if (null === $typeFormat)
  250. {
  251. $typeFormat = '<span class="sfWebDebugDataType">(%s)</span>';
  252. }
  253. return sprintf($nameFormat.' '.$typeFormat, $name, is_object($parameter) ? $this->formatFileLink(get_class($parameter)) : gettype($parameter));
  254. }
  255. /**
  256. * Shortens an action's template path.
  257. *
  258. * @param string $path
  259. *
  260. * @return string
  261. */
  262. protected function shortenTemplatePath($path)
  263. {
  264. $path = realpath($path);
  265. // application module
  266. $sep = preg_quote(DIRECTORY_SEPARATOR);
  267. if (preg_match('#modules'.$sep.'(\w+)'.$sep.'templates'.$sep.'(.*)$#', $path, $match))
  268. {
  269. return $match[1].'&nbsp;&hellip;&nbsp;'.$match[2];
  270. }
  271. return str_replace('SF_ROOT_DIR'.DIRECTORY_SEPARATOR, '', sfDebug::shortenFilePath($path));
  272. }
  273. /**
  274. * Removes parameters prefixed with "sf_" from the array.
  275. *
  276. * @param array $parameters
  277. *
  278. * @return array
  279. */
  280. protected function filterCoreParameters($parameters)
  281. {
  282. $filtered = array();
  283. foreach ($parameters as $name => $value)
  284. {
  285. if (0 !== strpos($name, 'sf_'))
  286. {
  287. $filtered[$name] = $value;
  288. }
  289. }
  290. return $filtered;
  291. }
  292. /**
  293. * Returns a string representation of a value.
  294. *
  295. * @param string $value
  296. *
  297. * @return string
  298. */
  299. protected function varExport($value)
  300. {
  301. if (is_numeric($value))
  302. {
  303. $value = (integer) $value;
  304. }
  305. return var_export($value, true);
  306. }
  307. }

Debug toolbar