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 string $name 54 * @param array $data 55 */ 56 public function __construct(string $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 * @return void 69 */ 70 public static function share(string $key, $value) 71 { 72 self::$shared_data[$key] = $value; 73 } 74 75 /** 76 * Implementation of Blade "stacks". 77 * 78 * @see https://laravel.com/docs/5.5/blade#stacks 79 * 80 * @param string $stack 81 * 82 * @return void 83 */ 84 public static function push(string $stack) 85 { 86 self::$stack = $stack; 87 ob_start(); 88 } 89 90 /** 91 * Implementation of Blade "stacks". 92 * 93 * @return void 94 */ 95 public static function endpush() 96 { 97 self::$stacks[self::$stack][] = ob_get_clean(); 98 } 99 100 /** 101 * Implementation of Blade "stacks". 102 * 103 * @param string $stack 104 * 105 * @return string 106 */ 107 public static function stack(string $stack): string 108 { 109 $content = implode('', self::$stacks[$stack] ?? []); 110 111 self::$stacks[$stack] = []; 112 113 return $content; 114 } 115 116 /** 117 * Render a view. 118 * 119 * @return string 120 */ 121 public function render() 122 { 123 extract($this->data + self::$shared_data); 124 125 ob_start(); 126 // Do not use require, so we can catch errors for missing files 127 include $this->getFilenameForView($this->name); 128 129 return ob_get_clean(); 130 } 131 132 /** 133 * Allow a theme to override the default views. 134 * 135 * @param string $view_name 136 * 137 * @return string 138 * @throws Exception 139 */ 140 public function getFilenameForView($view_name) 141 { 142 foreach ($this->paths() as $path) { 143 $view_file = $path . '/' . $view_name . '.php'; 144 145 if (is_file($view_file)) { 146 return $view_file; 147 } 148 } 149 150 throw new Exception('View not found: ' . e($view_name)); 151 } 152 153 /** 154 * Cerate and render a view in a single operation. 155 * 156 * @param string $name 157 * @param mixed[] $data 158 * 159 * @return string 160 */ 161 public static function make($name, $data = []) 162 { 163 $view = new static($name, $data); 164 165 DebugBar::addView($name, $data); 166 167 return $view->render(); 168 } 169 170 /** 171 * @return string[] 172 */ 173 private function paths(): array 174 { 175 static $paths = []; 176 177 if (empty($paths)) { 178 // Module views 179 // @TODO - this includes disabled modules. 180 $paths = glob(WT_ROOT . WT_MODULES_DIR . '*/resources/views'); 181 // Theme views 182 $paths[] = WT_ROOT . WT_THEMES_DIR . Theme::theme()->themeId() . '/resources/views'; 183 // Core views 184 $paths[] = WT_ROOT . 'resources/views'; 185 186 $paths = array_filter($paths, function (string $path): bool { 187 return is_dir($path); 188 }); 189 } 190 191 return $paths; 192 } 193} 194