1f3281ad6SGreg Roach<?php 2f3281ad6SGreg Roach/** 3f3281ad6SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 5f3281ad6SGreg Roach * This program is free software: you can redistribute it and/or modify 6f3281ad6SGreg Roach * it under the terms of the GNU General Public License as published by 7f3281ad6SGreg Roach * the Free Software Foundation, either version 3 of the License, or 8f3281ad6SGreg Roach * (at your option) any later version. 9f3281ad6SGreg Roach * This program is distributed in the hope that it will be useful, 10f3281ad6SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f3281ad6SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f3281ad6SGreg Roach * GNU General Public License for more details. 13f3281ad6SGreg Roach * You should have received a copy of the GNU General Public License 14f3281ad6SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 15f3281ad6SGreg Roach */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 18f3281ad6SGreg Roachnamespace Fisharebest\Webtrees; 19f3281ad6SGreg Roach 2050c68a25SGreg Roachuse Exception; 2170f31542SGreg Roachuse Throwable; 22*d7952a34SGreg Roachuse function array_filter; 23*d7952a34SGreg Roachuse function extract; 24*d7952a34SGreg Roachuse function implode; 25*d7952a34SGreg Roachuse function is_dir; 26*d7952a34SGreg Roachuse function is_file; 27*d7952a34SGreg Roachuse function ob_end_clean; 28*d7952a34SGreg Roachuse function ob_start; 29*d7952a34SGreg Roachuse function sha1; 3050c68a25SGreg Roach 31f3281ad6SGreg Roach/** 32f3281ad6SGreg Roach * Simple view/template class. 33f3281ad6SGreg Roach */ 34c1010edaSGreg Roachclass View 35c1010edaSGreg Roach{ 36dd6b2bfcSGreg Roach // Where do our templates live 3716d6367aSGreg Roach private const TEMPLATE_PATH = 'resources/views/'; 38dd6b2bfcSGreg Roach 39dd6b2bfcSGreg Roach // File extension for our template files. 4016d6367aSGreg Roach private const TEMPLATE_EXTENSION = '.phtml'; 41dd6b2bfcSGreg Roach 42f3281ad6SGreg Roach /** 43f3281ad6SGreg Roach * @var string The (file) name of the view. 44f3281ad6SGreg Roach */ 45f3281ad6SGreg Roach private $name; 46f3281ad6SGreg Roach 47f3281ad6SGreg Roach /** 48f3281ad6SGreg Roach * @var mixed[] Data to be inserted into the view. 49f3281ad6SGreg Roach */ 50f3281ad6SGreg Roach private $data; 51f3281ad6SGreg Roach 52f3281ad6SGreg Roach /** 5308d24c7aSGreg Roach * @var mixed[] Data to be inserted into all views. 5408d24c7aSGreg Roach */ 5508d24c7aSGreg Roach private static $shared_data = []; 5608d24c7aSGreg Roach 5708d24c7aSGreg Roach /** 58ecf66805SGreg Roach * @var string Implementation of Blade "stacks". 59ecf66805SGreg Roach */ 60ecf66805SGreg Roach private static $stack; 61ecf66805SGreg Roach 62ecf66805SGreg Roach /** 63ecf66805SGreg Roach * @var array[] Implementation of Blade "stacks". 64ecf66805SGreg Roach */ 65ecf66805SGreg Roach private static $stacks = []; 66ecf66805SGreg Roach 67ecf66805SGreg Roach /** 68f3281ad6SGreg Roach * Createa view from a template name and optional data. 69f3281ad6SGreg Roach * 70fa4036e8SGreg Roach * @param string $name 71f3281ad6SGreg Roach * @param array $data 72f3281ad6SGreg Roach */ 73fa4036e8SGreg Roach public function __construct(string $name, $data = []) 74c1010edaSGreg Roach { 75f3281ad6SGreg Roach $this->name = $name; 76f3281ad6SGreg Roach $this->data = $data; 77f3281ad6SGreg Roach } 78f3281ad6SGreg Roach 79f3281ad6SGreg Roach /** 8008d24c7aSGreg Roach * Shared data that is available to all views. 81962e29c9SGreg Roach * 82962e29c9SGreg Roach * @param string $key 83962e29c9SGreg Roach * @param mixed $value 84fa4036e8SGreg Roach * 85fa4036e8SGreg Roach * @return void 8608d24c7aSGreg Roach */ 87c1010edaSGreg Roach public static function share(string $key, $value) 88c1010edaSGreg Roach { 8908d24c7aSGreg Roach self::$shared_data[$key] = $value; 9008d24c7aSGreg Roach } 9108d24c7aSGreg Roach 9208d24c7aSGreg Roach /** 93ecf66805SGreg Roach * Implementation of Blade "stacks". 94ecf66805SGreg Roach * 95ecf66805SGreg Roach * @see https://laravel.com/docs/5.5/blade#stacks 96962e29c9SGreg Roach * 97962e29c9SGreg Roach * @param string $stack 98fa4036e8SGreg Roach * 99fa4036e8SGreg Roach * @return void 100ecf66805SGreg Roach */ 101c1010edaSGreg Roach public static function push(string $stack) 102c1010edaSGreg Roach { 103ecf66805SGreg Roach self::$stack = $stack; 104*d7952a34SGreg Roach 105ecf66805SGreg Roach ob_start(); 106ecf66805SGreg Roach } 107ecf66805SGreg Roach 108ecf66805SGreg Roach /** 109ecf66805SGreg Roach * Implementation of Blade "stacks". 110fa4036e8SGreg Roach * 111fa4036e8SGreg Roach * @return void 112ecf66805SGreg Roach */ 113c1010edaSGreg Roach public static function endpush() 114c1010edaSGreg Roach { 11588de55fdSRico Sonntag $content = ob_get_clean(); 11688de55fdSRico Sonntag 117*d7952a34SGreg Roach self::$stacks[self::$stack][] = $content; 118*d7952a34SGreg Roach } 119*d7952a34SGreg Roach 120*d7952a34SGreg Roach /** 121*d7952a34SGreg Roach * Variant of push that will only add one copy of each item. 122*d7952a34SGreg Roach * 123*d7952a34SGreg Roach * @param string $stack 124*d7952a34SGreg Roach * 125*d7952a34SGreg Roach * @return void 126*d7952a34SGreg Roach */ 127*d7952a34SGreg Roach public static function pushunique(string $stack) 128*d7952a34SGreg Roach { 129*d7952a34SGreg Roach self::$stack = $stack; 130*d7952a34SGreg Roach 131*d7952a34SGreg Roach ob_start(); 132*d7952a34SGreg Roach } 133*d7952a34SGreg Roach 134*d7952a34SGreg Roach /** 135*d7952a34SGreg Roach * Variant of push that will only add one copy of each item. 136*d7952a34SGreg Roach * 137*d7952a34SGreg Roach * @return void 138*d7952a34SGreg Roach */ 139*d7952a34SGreg Roach public static function endpushunique() 140*d7952a34SGreg Roach { 141*d7952a34SGreg Roach $content = ob_get_clean(); 142*d7952a34SGreg Roach 143*d7952a34SGreg Roach self::$stacks[self::$stack][sha1($content)] = $content; 144ecf66805SGreg Roach } 145ecf66805SGreg Roach 146ecf66805SGreg Roach /** 147ecf66805SGreg Roach * Implementation of Blade "stacks". 148ecf66805SGreg Roach * 149962e29c9SGreg Roach * @param string $stack 150962e29c9SGreg Roach * 151ecf66805SGreg Roach * @return string 152ecf66805SGreg Roach */ 153c1010edaSGreg Roach public static function stack(string $stack): string 154c1010edaSGreg Roach { 155ecf66805SGreg Roach $content = implode('', self::$stacks[$stack] ?? []); 156ecf66805SGreg Roach 157ecf66805SGreg Roach self::$stacks[$stack] = []; 158ecf66805SGreg Roach 159ecf66805SGreg Roach return $content; 160ecf66805SGreg Roach } 161ecf66805SGreg Roach 162ecf66805SGreg Roach /** 163f3281ad6SGreg Roach * Render a view. 164f3281ad6SGreg Roach * 165f3281ad6SGreg Roach * @return string 16670f31542SGreg Roach * @throws Throwable 167f3281ad6SGreg Roach */ 1688f53f488SRico Sonntag public function render(): string 169c1010edaSGreg Roach { 1704a86d714SGreg Roach $variables_for_view = $this->data + self::$shared_data; 1714a86d714SGreg Roach extract($variables_for_view); 172f3281ad6SGreg Roach 17370f31542SGreg Roach try { 174f3281ad6SGreg Roach ob_start(); 175bc241c54SGreg Roach // Do not use require, so we can catch errors for missing files 176bc241c54SGreg Roach include $this->getFilenameForView($this->name); 17775d70144SGreg Roach 178f3281ad6SGreg Roach return ob_get_clean(); 17970f31542SGreg Roach } catch (Throwable $ex) { 18070f31542SGreg Roach ob_end_clean(); 18170f31542SGreg Roach throw $ex; 18270f31542SGreg Roach } 183f3281ad6SGreg Roach } 184f3281ad6SGreg Roach 185f3281ad6SGreg Roach /** 18675d70144SGreg Roach * Allow a theme to override the default views. 187f3281ad6SGreg Roach * 188f3281ad6SGreg Roach * @param string $view_name 189f3281ad6SGreg Roach * 19075d70144SGreg Roach * @return string 19150c68a25SGreg Roach * @throws Exception 192f3281ad6SGreg Roach */ 1938f53f488SRico Sonntag public function getFilenameForView($view_name): string 194c1010edaSGreg Roach { 19550c68a25SGreg Roach foreach ($this->paths() as $path) { 196dd6b2bfcSGreg Roach $view_file = $path . $view_name . self::TEMPLATE_EXTENSION; 19775d70144SGreg Roach 19850c68a25SGreg Roach if (is_file($view_file)) { 19950c68a25SGreg Roach return $view_file; 200f21917b2SGreg Roach } 201f3281ad6SGreg Roach } 202f3281ad6SGreg Roach 20350c68a25SGreg Roach throw new Exception('View not found: ' . e($view_name)); 20450c68a25SGreg Roach } 20550c68a25SGreg Roach 206f3281ad6SGreg Roach /** 207f3281ad6SGreg Roach * Cerate and render a view in a single operation. 208f3281ad6SGreg Roach * 209f3281ad6SGreg Roach * @param string $name 210f3281ad6SGreg Roach * @param mixed[] $data 211f3281ad6SGreg Roach * 212f3281ad6SGreg Roach * @return string 213f3281ad6SGreg Roach */ 2148f53f488SRico Sonntag public static function make($name, $data = []): string 215c1010edaSGreg Roach { 216f3281ad6SGreg Roach $view = new static($name, $data); 217f3281ad6SGreg Roach 21844116e73SGreg Roach DebugBar::addView($name, $data); 21944116e73SGreg Roach 220f3281ad6SGreg Roach return $view->render(); 221f3281ad6SGreg Roach } 22250c68a25SGreg Roach 22350c68a25SGreg Roach /** 22450c68a25SGreg Roach * @return string[] 22550c68a25SGreg Roach */ 22650c68a25SGreg Roach private function paths(): array 22750c68a25SGreg Roach { 22850c68a25SGreg Roach static $paths = []; 22950c68a25SGreg Roach 23050c68a25SGreg Roach if (empty($paths)) { 23150c68a25SGreg Roach // Module views 23250c68a25SGreg Roach // @TODO - this includes disabled modules. 233af9cb431SGreg Roach //$paths = glob(WT_ROOT . Webtrees::MODULES_PATH . '*/' . self::TEMPLATE_PATH); 23450c68a25SGreg Roach // Theme views 235af9cb431SGreg Roach // @TODO - this won't work during setup. 236cab242e7SGreg Roach //$paths[] = WT_ROOT . Webtrees::THEMES_PATH . app(ModuleThemeInterface::class)->name() . '/' . self::TEMPLATE_PATH; 23750c68a25SGreg Roach // Core views 238dd6b2bfcSGreg Roach $paths[] = WT_ROOT . self::TEMPLATE_PATH; 23950c68a25SGreg Roach 240bdb3725aSGreg Roach $paths = array_filter($paths, function (string $path): bool { 241bdb3725aSGreg Roach return is_dir($path); 242bdb3725aSGreg Roach }); 24350c68a25SGreg Roach } 24450c68a25SGreg Roach 24550c68a25SGreg Roach return $paths; 24650c68a25SGreg Roach } 247f3281ad6SGreg Roach} 248