1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16namespace Fisharebest\Webtrees; 17 18use Exception; 19 20/** 21 * Simple view/template class. 22 */ 23class View 24{ 25 /** 26 * @var string The (file) name of the view. 27 */ 28 private $name; 29 30 /** 31 * @var mixed[] Data to be inserted into the view. 32 */ 33 private $data; 34 35 /** 36 * @var mixed[] Data to be inserted into all views. 37 */ 38 private static $shared_data = []; 39 40 /** 41 * @var string Implementation of Blade "stacks". 42 */ 43 private static $stack; 44 45 /** 46 * @var array[] Implementation of Blade "stacks". 47 */ 48 private static $stacks = []; 49 50 /** 51 * Createa view from a template name and optional data. 52 * 53 * @param $name 54 * @param array $data 55 */ 56 public function __construct($name, $data = []) 57 { 58 $this->name = $name; 59 $this->data = $data; 60 } 61 62 /** 63 * Shared data that is available to all views. 64 * 65 * @param string $key 66 * @param mixed $value 67 */ 68 public static function share(string $key, $value) 69 { 70 self::$shared_data[$key] = $value; 71 } 72 73 /** 74 * Implementation of Blade "stacks". 75 * 76 * @see https://laravel.com/docs/5.5/blade#stacks 77 * 78 * @param string $stack 79 */ 80 public static function push(string $stack) 81 { 82 self::$stack = $stack; 83 ob_start(); 84 } 85 86 /** 87 * Implementation of Blade "stacks". 88 */ 89 public static function endpush() 90 { 91 self::$stacks[self::$stack][] = ob_get_clean(); 92 } 93 94 /** 95 * Implementation of Blade "stacks". 96 * 97 * @param string $stack 98 * 99 * @return string 100 */ 101 public static function stack(string $stack): string 102 { 103 $content = implode('', self::$stacks[$stack] ?? []); 104 105 self::$stacks[$stack] = []; 106 107 return $content; 108 } 109 110 /** 111 * Render a view. 112 * 113 * @return string 114 */ 115 public function render() 116 { 117 extract($this->data + self::$shared_data); 118 119 ob_start(); 120 // Do not use require, so we can catch errors for missing files 121 include $this->getFilenameForView($this->name); 122 123 return ob_get_clean(); 124 } 125 126 /** 127 * Allow a theme to override the default views. 128 * 129 * @param string $view_name 130 * 131 * @return string 132 * @throws Exception 133 */ 134 public function getFilenameForView($view_name) 135 { 136 foreach ($this->paths() as $path) { 137 $view_file = $path . '/' . $view_name . '.php'; 138 139 if (is_file($view_file)) { 140 return $view_file; 141 } 142 } 143 144 throw new Exception('View not found: ' . e($view_name)); 145 } 146 147 /** 148 * Cerate and render a view in a single operation. 149 * 150 * @param string $name 151 * @param mixed[] $data 152 * 153 * @return string 154 */ 155 public static function make($name, $data = []) 156 { 157 $view = new static($name, $data); 158 159 DebugBar::addView($name, $data); 160 161 return $view->render(); 162 } 163 164 /** 165 * @return string[] 166 */ 167 private function paths(): array 168 { 169 static $paths = []; 170 171 if (empty($paths)) { 172 // Module views 173 // @TODO - this includes disabled modules. 174 $paths = glob(WT_ROOT . WT_MODULES_DIR . '*/resources/views'); 175 // Theme views 176 $paths[] = WT_ROOT . WT_THEMES_DIR . Theme::theme()->themeId() . '/resources/views'; 177 // Core views 178 $paths[] = WT_ROOT . 'resources/views'; 179 180 $paths = array_filter($paths, function (string $path) { return is_dir($path); }); 181 } 182 183 return $paths; 184 } 185} 186