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(): string 122 { 123 $variables_for_view = $this->data + self::$shared_data; 124 extract($variables_for_view); 125 126 ob_start(); 127 // Do not use require, so we can catch errors for missing files 128 include $this->getFilenameForView($this->name); 129 130 return ob_get_clean(); 131 } 132 133 /** 134 * Allow a theme to override the default views. 135 * 136 * @param string $view_name 137 * 138 * @return string 139 * @throws Exception 140 */ 141 public function getFilenameForView($view_name): string 142 { 143 foreach ($this->paths() as $path) { 144 $view_file = $path . '/' . $view_name . '.php'; 145 146 if (is_file($view_file)) { 147 return $view_file; 148 } 149 } 150 151 throw new Exception('View not found: ' . e($view_name)); 152 } 153 154 /** 155 * Cerate and render a view in a single operation. 156 * 157 * @param string $name 158 * @param mixed[] $data 159 * 160 * @return string 161 */ 162 public static function make($name, $data = []): string 163 { 164 $view = new static($name, $data); 165 166 DebugBar::addView($name, $data); 167 168 return $view->render(); 169 } 170 171 /** 172 * @return string[] 173 */ 174 private function paths(): array 175 { 176 static $paths = []; 177 178 if (empty($paths)) { 179 // Module views 180 // @TODO - this includes disabled modules. 181 $paths = glob(WT_ROOT . WT_MODULES_DIR . '*/resources/views'); 182 // Theme views 183 $paths[] = WT_ROOT . WT_THEMES_DIR . Theme::theme()->themeId() . '/resources/views'; 184 // Core views 185 $paths[] = WT_ROOT . 'resources/views'; 186 187 $paths = array_filter($paths, function (string $path): bool { 188 return is_dir($path); 189 }); 190 } 191 192 return $paths; 193 } 194} 195