PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/mishal-iless/lib/ILess/Exception/Exception.php

https://github.com/ratbird/hope
PHP | 382 lines | 179 code | 40 blank | 163 comment | 29 complexity | a0fd8849c9cde8c98e0ea5e31c0ff723 MD5 | raw file
Possible License(s): LGPL-2.1, CC-BY-SA-3.0, MIT, BSD-3-Clause, GPL-2.0
  1. <?php
  2. /*
  3. * This file is part of the ILess
  4. *
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. namespace ILess\Exception;
  9. use ILess\FileInfo;
  10. use ILess\Util;
  11. use ILess\ImportedFile;
  12. /**
  13. * Base exception
  14. *
  15. * @package ILess\Exception
  16. */
  17. class Exception extends \Exception
  18. {
  19. /**
  20. * The current file
  21. *
  22. * @var ImportedFile|FileInfo|string
  23. */
  24. private $currentFile;
  25. /**
  26. * The current parser index
  27. *
  28. * @var integer
  29. */
  30. private $index;
  31. /**
  32. * Current line
  33. *
  34. * @var integer|null
  35. */
  36. private $errorLine;
  37. /**
  38. * Current column
  39. *
  40. * @var integer|null
  41. */
  42. private $errorColumn;
  43. /**
  44. * Excerpt from the string which contains error
  45. *
  46. * @var Util\StringExcerpt
  47. */
  48. private $excerpt;
  49. /**
  50. * File editor link. Allows variable holders:
  51. *
  52. * * `%file` or `%f` - current file
  53. * * `%line` or `%l` - current line
  54. *
  55. * @var string
  56. */
  57. protected static $fileEditUrlFormat = 'editor://open?file=%f&line=%l';
  58. /**
  59. * File excerpt line number
  60. *
  61. * @var integer|false
  62. */
  63. protected static $fileExcerptLineNumber = 3;
  64. /**
  65. * Constructor
  66. *
  67. * @param string $message The exception message
  68. * @param integer $index The current parser index
  69. * @param FileInfo|ImportedFile|string $currentFile The file
  70. * @param \Exception $previous Previous exception
  71. * @param integer $code The exception code
  72. */
  73. public function __construct(
  74. $message = null,
  75. $index = null,
  76. $currentFile = null,
  77. \Exception $previous = null,
  78. $code = 0
  79. ) {
  80. $message = $this->formatMessage($message, $previous);
  81. parent::__construct($message, $code, $previous);
  82. $this->currentFile = $currentFile;
  83. $this->index = $index;
  84. if ($currentFile && $this->index !== null) {
  85. $this->updateFileErrorInformation();
  86. }
  87. }
  88. /**
  89. * Formats the message
  90. *
  91. * @param string $message The exception message
  92. * @param \Exception $previous Previous exception
  93. * @return string
  94. */
  95. private function formatMessage($message, \Exception $previous = null)
  96. {
  97. $messageFormatted = $message;
  98. if ($previous && $previous->getMessage() !== $message) {
  99. $messageFormatted .= ': '.$previous->getMessage();
  100. }
  101. return $messageFormatted;
  102. }
  103. /**
  104. * Returns the current line and column
  105. *
  106. * @param FileInfo|ImportedFile|string $currentFile The file
  107. * @param integer $index Current position index
  108. * @param boolean $excerpt Include the string excerpt?
  109. * @return array
  110. */
  111. protected function getLocation($currentFile, $index, $column = null, $excerpt = true)
  112. {
  113. $line = $col = $excerptContent = null;
  114. if ($index !== null && $currentFile) {
  115. $content = null;
  116. if ($currentFile instanceof FileInfo
  117. && $currentFile->importedFile
  118. ) {
  119. $content = $currentFile->importedFile->getContent();
  120. } elseif (is_string($currentFile) && Util::isPathAbsolute($currentFile)
  121. && is_readable($currentFile)
  122. ) {
  123. $content = file_get_contents($currentFile);
  124. }
  125. if ($content) {
  126. list($line, $col, $excerptContent) = Util::getLocation($content, $index, $column, $excerpt);
  127. }
  128. }
  129. return [
  130. $line,
  131. $col,
  132. $excerptContent,
  133. ];
  134. }
  135. /**
  136. * Updates the line, column and excerpt
  137. *
  138. * @return void
  139. */
  140. protected function updateFileErrorInformation()
  141. {
  142. // recalculate the location
  143. list($this->errorLine, $this->errorColumn, $this->excerpt) =
  144. $this->getLocation($this->currentFile, $this->index, $this->errorColumn, self::getFileExcerptLineNumber());
  145. }
  146. /**
  147. * Sets the editor url format
  148. *
  149. * @param string $format
  150. * @return void
  151. */
  152. public static function setFileEditorUrlFormat($format)
  153. {
  154. self::$fileEditUrlFormat = (string)$format;
  155. }
  156. /**
  157. * Returns the editor url format
  158. *
  159. * @return string
  160. */
  161. public static function getFileEditorUrlFormat()
  162. {
  163. return self::$fileEditUrlFormat;
  164. }
  165. /**
  166. * Sets the number of lines to display in file excerpts when an exception is displayed
  167. *
  168. * @param integer|false $number
  169. */
  170. public static function setFileExcerptLineNumber($number)
  171. {
  172. self::$fileExcerptLineNumber = $number;
  173. }
  174. /**
  175. * Returns the number of lines to display in file excerpts
  176. *
  177. * @return integer|false
  178. */
  179. public static function getFileExcerptLineNumber()
  180. {
  181. return self::$fileExcerptLineNumber;
  182. }
  183. /**
  184. * Returns the file
  185. *
  186. * @return ImportedFile|FileInfo|null
  187. */
  188. public function getCurrentFile()
  189. {
  190. return $this->currentFile;
  191. }
  192. /**
  193. * Sets the current file
  194. *
  195. * @param ImportedFile|FileInfo|string $file
  196. * @param integer $index The current index
  197. */
  198. public function setCurrentFile($file, $index = null)
  199. {
  200. $this->currentFile = $file;
  201. if ($index !== null) {
  202. $this->index = $index;
  203. }
  204. $this->updateFileErrorInformation();
  205. }
  206. /**
  207. * Returns the current index
  208. *
  209. * @return integer
  210. */
  211. final public function getIndex()
  212. {
  213. return $this->index;
  214. }
  215. /**
  216. * Returns the excerpt from the string which contains the error
  217. *
  218. * @return Util\StringExcerpt|null
  219. */
  220. final public function getExcerpt()
  221. {
  222. return $this->excerpt;
  223. }
  224. /**
  225. * Sets index
  226. *
  227. * @param integer $index
  228. */
  229. final public function setIndex($index)
  230. {
  231. $this->index = $index;
  232. $this->updateFileErrorInformation();
  233. }
  234. /**
  235. * Returns current line from the file
  236. *
  237. * @return integer|null
  238. */
  239. final public function getErrorLine()
  240. {
  241. return $this->errorLine;
  242. }
  243. /**
  244. * Returns the error column
  245. *
  246. * @return integer|null
  247. */
  248. final public function getErrorColumn()
  249. {
  250. return $this->errorColumn;
  251. }
  252. /**
  253. * Returns file editor link. The link format can be customized.
  254. *
  255. * @param FileInfo|string $file The current file
  256. * @param integer $line
  257. * @return string|void
  258. * @see setFileEditorUrlFormat
  259. */
  260. protected function getFileEditorLink($file, $line = null)
  261. {
  262. if ($file instanceof FileInfo) {
  263. $path = $file->filename;
  264. if ($file->importedFile) {
  265. $path = $file->importedFile->getPath();
  266. }
  267. if (strpos($path, '__string_to_parse__') === 0) {
  268. $path = '[input string]';
  269. }
  270. } else {
  271. $path = $file;
  272. }
  273. // when in cli or not accessible via filesystem, don't generate links
  274. if (PHP_SAPI == 'cli' || !Util::isPathAbsolute($path)) {
  275. return $path;
  276. }
  277. return sprintf('<a href="%s" class="file-edit">%s</a>', htmlspecialchars(strtr(self::$fileEditUrlFormat, [
  278. // allow more formats
  279. '%f' => $path,
  280. '%file' => $path,
  281. '%line' => $line,
  282. '%l' => $line,
  283. ])), $path);
  284. }
  285. /**
  286. * Converts the exception to string
  287. *
  288. * @return string
  289. */
  290. public function __toString()
  291. {
  292. return $this->toString(true, php_sapi_name() !== 'cli');
  293. }
  294. /**
  295. * Converts the exception to string
  296. *
  297. * @param boolean $includeExcerpt Include excerpt?
  298. * @param boolean $html Convert to HTML?
  299. * @return string
  300. */
  301. public function toString($includeExcerpt = true, $html = true)
  302. {
  303. $string = [];
  304. if ($this->currentFile) {
  305. // we have an line from the file
  306. if (($line = $this->getErrorLine()) !== null) {
  307. $string[] = sprintf('%s in %s on line: %s, column: %s', $this->message,
  308. $this->getFileEditorLink($this->currentFile, $line), $line, $this->errorColumn);
  309. if ($includeExcerpt && $this->excerpt) {
  310. if ($html) {
  311. $string[] = sprintf('<pre>%s</pre>', $this->excerpt->toHtml());
  312. } else {
  313. $string[] = $this->excerpt->toText();
  314. }
  315. }
  316. } else {
  317. $string[] = sprintf('%s in %s on line: ?', $this->message,
  318. $this->getFileEditorLink($this->currentFile));
  319. }
  320. } else {
  321. $string[] = $this->message;
  322. }
  323. return join("\n", $string);
  324. }
  325. /**
  326. *
  327. * @return string
  328. */
  329. public function prettyPrint($trace = false)
  330. {
  331. $error = sprintf('<h2>%s</h2>%s', get_class($this), $this->__toString());
  332. if ($trace) {
  333. $error .= sprintf('<h3>Trace</h3><pre class="exception-trace">%s</pre>', $this->getTraceAsString());
  334. }
  335. if ($previous = $this->getPrevious()) {
  336. $error .= '<h3>Caused by: '.get_class($previous).'</h3>';
  337. $error .= $previous->getMessage();
  338. $error .= '<pre class="exception-trace">'.$previous->getTraceAsString().'</pre>';
  339. }
  340. return $error;
  341. }
  342. }