PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/system/traits/ViewMaker.php

https://gitlab.com/gideonmarked/PLCPortal
PHP | 317 lines | 161 code | 45 blank | 111 comment | 28 complexity | 8e7da7f2294db9457d1b985219da3967 MD5 | raw file
  1. <?php namespace System\Traits;
  2. use File;
  3. use Lang;
  4. use Event;
  5. use Block;
  6. use SystemException;
  7. use Exception;
  8. use Throwable;
  9. use Symfony\Component\Debug\Exception\FatalThrowableError;
  10. /**
  11. * View Maker Trait
  12. * Adds view based methods to a class
  13. *
  14. * @package october\backend
  15. * @author Alexey Bobkov, Samuel Georges
  16. */
  17. trait ViewMaker
  18. {
  19. /**
  20. * @var array A list of variables to pass to the page.
  21. */
  22. public $vars = [];
  23. /**
  24. * @var string|array Specifies a path to the views directory.
  25. */
  26. protected $viewPath;
  27. /**
  28. * @var string Specifies a path to the layout directory.
  29. */
  30. protected $layoutPath;
  31. /**
  32. * @var string Layout to use for the view.
  33. */
  34. public $layout;
  35. /**
  36. * @var bool Prevents the use of a layout.
  37. */
  38. public $suppressLayout = false;
  39. /**
  40. * Prepends a path on the available view path locations.
  41. * @param string|array $path
  42. * @return void
  43. */
  44. public function addViewPath($path)
  45. {
  46. $this->viewPath = (array) $this->viewPath;
  47. if (is_array($path)) {
  48. $this->viewPath = array_merge($path, $this->viewPath);
  49. }
  50. else {
  51. array_unshift($this->viewPath, $path);
  52. }
  53. }
  54. /**
  55. * Returns the active view path locations.
  56. * @return array
  57. */
  58. public function getViewPaths()
  59. {
  60. return (array) $this->viewPath;
  61. }
  62. /**
  63. * Render a partial file contents located in the views folder.
  64. * @param string $partial The view to load.
  65. * @param array $params Parameter variables to pass to the view.
  66. * @param bool $throwException Throw an exception if the partial is not found.
  67. * @return mixed Partial contents or false if not throwing an exception.
  68. */
  69. public function makePartial($partial, $params = [], $throwException = true)
  70. {
  71. if (!File::isPathSymbol($partial) && realpath($partial) === false) {
  72. $folder = strpos($partial, '/') !== false ? dirname($partial) . '/' : '';
  73. $partial = $folder . '_' . strtolower(basename($partial)).'.htm';
  74. }
  75. $partialPath = $this->getViewPath($partial);
  76. if (!File::exists($partialPath)) {
  77. if ($throwException) {
  78. throw new SystemException(Lang::get('backend::lang.partial.not_found_name', ['name' => $partialPath]));
  79. }
  80. else {
  81. return false;
  82. }
  83. }
  84. return $this->makeFileContents($partialPath, $params);
  85. }
  86. /**
  87. * Loads a view with the name specified. Applies layout if its name is provided by the parent object.
  88. * The view file must be situated in the views directory, and has the extension "htm".
  89. * @param string $view Specifies the view name, without extension. Eg: "index".
  90. * @return string
  91. */
  92. public function makeView($view)
  93. {
  94. $viewPath = $this->getViewPath(strtolower($view) . '.htm');
  95. $contents = $this->makeFileContents($viewPath);
  96. return $this->makeViewContent($contents);
  97. }
  98. /**
  99. * Renders supplied contents inside a layout.
  100. * @param string $contents The inner contents as a string.
  101. * @param string $layout Specifies the layout name.
  102. * @return string
  103. */
  104. public function makeViewContent($contents, $layout = null)
  105. {
  106. if ($this->suppressLayout || $this->layout == '') {
  107. return $contents;
  108. }
  109. // Append any undefined block content to the body block
  110. Block::set('undefinedBlock', $contents);
  111. Block::append('body', Block::get('undefinedBlock'));
  112. return $this->makeLayout($layout);
  113. }
  114. /**
  115. * Render a layout.
  116. * @param string $name Specifies the layout name.
  117. * If this parameter is omitted, the $layout property will be used.
  118. * @param array $params Parameter variables to pass to the view.
  119. * @param bool $throwException Throw an exception if the layout is not found
  120. * @return mixed The layout contents, or false.
  121. */
  122. public function makeLayout($name = null, $params = [], $throwException = true)
  123. {
  124. $layout = $name === null ? $this->layout : $name;
  125. if ($layout == '') {
  126. return '';
  127. }
  128. $layoutPath = $this->getViewPath($layout . '.htm', $this->layoutPath);
  129. if (!File::exists($layoutPath)) {
  130. if ($throwException) {
  131. throw new SystemException(Lang::get('cms::lang.layout.not_found_name', ['name' => $layoutPath]));
  132. }
  133. else {
  134. return false;
  135. }
  136. }
  137. return $this->makeFileContents($layoutPath, $params);
  138. }
  139. /**
  140. * Renders a layout partial
  141. * @param string $partial The view to load.
  142. * @param array $params Parameter variables to pass to the view.
  143. * @return string The layout partial contents
  144. */
  145. public function makeLayoutPartial($partial, $params = [])
  146. {
  147. if (!File::isLocalPath($partial) && !File::isPathSymbol($partial)) {
  148. $folder = strpos($partial, '/') !== false ? dirname($partial) . '/' : '';
  149. $partial = $folder . '_' . strtolower(basename($partial));
  150. }
  151. return $this->makeLayout($partial, $params);
  152. }
  153. /**
  154. * Locates a file based on its definition. The file name can be prefixed with a
  155. * symbol (~|$) to return in context of the application or plugin base path,
  156. * otherwise it will be returned in context of this object view path.
  157. * @param string $fileName File to load.
  158. * @param mixed $viewPath Explicitly define a view path.
  159. * @return string Full path to the view file.
  160. */
  161. public function getViewPath($fileName, $viewPath = null)
  162. {
  163. if (!isset($this->viewPath)) {
  164. $this->viewPath = $this->guessViewPath();
  165. }
  166. if (!$viewPath) {
  167. $viewPath = $this->viewPath;
  168. }
  169. $fileName = File::symbolizePath($fileName);
  170. if (File::isLocalPath($fileName) || realpath($fileName) !== false) {
  171. return $fileName;
  172. }
  173. if (!is_array($viewPath)) {
  174. $viewPath = [$viewPath];
  175. }
  176. foreach ($viewPath as $path) {
  177. $_fileName = File::symbolizePath($path) . '/' . $fileName;
  178. if (File::isFile($_fileName)) {
  179. return $_fileName;
  180. }
  181. }
  182. return $fileName;
  183. }
  184. /**
  185. * Includes a file path using output buffering.
  186. * Ensures that vars are available.
  187. * @param string $filePath Absolute path to the view file.
  188. * @param array $extraParams Parameters that should be available to the view.
  189. * @return string
  190. */
  191. public function makeFileContents($filePath, $extraParams = [])
  192. {
  193. if (!strlen($filePath) || !File::isFile($filePath)) {
  194. return '';
  195. }
  196. if (!is_array($extraParams)) {
  197. $extraParams = [];
  198. }
  199. $vars = array_merge($this->vars, $extraParams);
  200. $obLevel = ob_get_level();
  201. ob_start();
  202. extract($vars);
  203. // We'll evaluate the contents of the view inside a try/catch block so we can
  204. // flush out any stray output that might get out before an error occurs or
  205. // an exception is thrown. This prevents any partial views from leaking.
  206. try {
  207. include $filePath;
  208. }
  209. catch (Exception $e) {
  210. $this->handleViewException($e, $obLevel);
  211. }
  212. catch (Throwable $e) {
  213. $this->handleViewException(new FatalThrowableError($e), $obLevel);
  214. }
  215. return ob_get_clean();
  216. }
  217. /**
  218. * Handle a view exception.
  219. *
  220. * @param \Exception $e
  221. * @param int $obLevel
  222. * @return void
  223. *
  224. */
  225. protected function handleViewException($e, $obLevel)
  226. {
  227. while (ob_get_level() > $obLevel) {
  228. ob_end_clean();
  229. }
  230. throw $e;
  231. }
  232. /**
  233. * Guess the package path for the called class.
  234. * @param string $suffix An extra path to attach to the end
  235. * @param bool $isPublic Returns public path instead of an absolute one
  236. * @return string
  237. */
  238. public function guessViewPath($suffix = '', $isPublic = false)
  239. {
  240. $class = get_called_class();
  241. return $this->guessViewPathFrom($class, $suffix, $isPublic);
  242. }
  243. /**
  244. * Guess the package path from a specified class.
  245. * @param string $class Class to guess path from.
  246. * @param string $suffix An extra path to attach to the end
  247. * @param bool $isPublic Returns public path instead of an absolute one
  248. * @return string
  249. */
  250. public function guessViewPathFrom($class, $suffix = '', $isPublic = false)
  251. {
  252. $classFolder = strtolower(class_basename($class));
  253. $classFile = realpath(dirname(File::fromClass($class)));
  254. $guessedPath = $classFile ? $classFile . '/' . $classFolder . $suffix : null;
  255. return ($isPublic) ? File::localToPublic($guessedPath) : $guessedPath;
  256. }
  257. /**
  258. * Special event function used for extending within view files
  259. * @param string $event Event name
  260. * @param array $params Event parameters
  261. * @return string
  262. */
  263. public function fireViewEvent($event, $params = [])
  264. {
  265. // Add the local object to the first parameter always
  266. array_unshift($params, $this);
  267. if ($result = Event::fire($event, $params)) {
  268. return implode(PHP_EOL.PHP_EOL, (array) $result);
  269. }
  270. return '';
  271. }
  272. }