1f3281ad6SGreg Roach<?php 2f3281ad6SGreg Roach/** 3f3281ad6SGreg Roach * webtrees: online genealogy 41062a142SGreg Roach * Copyright (C) 2018 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 function ob_end_clean; 2270f31542SGreg Roachuse Throwable; 2350c68a25SGreg Roach 24f3281ad6SGreg Roach/** 25f3281ad6SGreg Roach * Simple view/template class. 26f3281ad6SGreg Roach */ 27c1010edaSGreg Roachclass View 28c1010edaSGreg Roach{ 29dd6b2bfcSGreg Roach // Where do our templates live 30dd6b2bfcSGreg Roach const TEMPLATE_PATH = 'resources/views/'; 31dd6b2bfcSGreg Roach 32dd6b2bfcSGreg Roach // File extension for our template files. 33dd6b2bfcSGreg Roach const TEMPLATE_EXTENSION = '.phtml'; 34dd6b2bfcSGreg Roach 35f3281ad6SGreg Roach /** 36f3281ad6SGreg Roach * @var string The (file) name of the view. 37f3281ad6SGreg Roach */ 38f3281ad6SGreg Roach private $name; 39f3281ad6SGreg Roach 40f3281ad6SGreg Roach /** 41f3281ad6SGreg Roach * @var mixed[] Data to be inserted into the view. 42f3281ad6SGreg Roach */ 43f3281ad6SGreg Roach private $data; 44f3281ad6SGreg Roach 45f3281ad6SGreg Roach /** 4608d24c7aSGreg Roach * @var mixed[] Data to be inserted into all views. 4708d24c7aSGreg Roach */ 4808d24c7aSGreg Roach private static $shared_data = []; 4908d24c7aSGreg Roach 5008d24c7aSGreg Roach /** 51ecf66805SGreg Roach * @var string Implementation of Blade "stacks". 52ecf66805SGreg Roach */ 53ecf66805SGreg Roach private static $stack; 54ecf66805SGreg Roach 55ecf66805SGreg Roach /** 56ecf66805SGreg Roach * @var array[] Implementation of Blade "stacks". 57ecf66805SGreg Roach */ 58ecf66805SGreg Roach private static $stacks = []; 59ecf66805SGreg Roach 60ecf66805SGreg Roach /** 61f3281ad6SGreg Roach * Createa view from a template name and optional data. 62f3281ad6SGreg Roach * 63fa4036e8SGreg Roach * @param string $name 64f3281ad6SGreg Roach * @param array $data 65f3281ad6SGreg Roach */ 66fa4036e8SGreg Roach public function __construct(string $name, $data = []) 67c1010edaSGreg Roach { 68f3281ad6SGreg Roach $this->name = $name; 69f3281ad6SGreg Roach $this->data = $data; 70f3281ad6SGreg Roach } 71f3281ad6SGreg Roach 72f3281ad6SGreg Roach /** 7308d24c7aSGreg Roach * Shared data that is available to all views. 74962e29c9SGreg Roach * 75962e29c9SGreg Roach * @param string $key 76962e29c9SGreg Roach * @param mixed $value 77fa4036e8SGreg Roach * 78fa4036e8SGreg Roach * @return void 7908d24c7aSGreg Roach */ 80c1010edaSGreg Roach public static function share(string $key, $value) 81c1010edaSGreg Roach { 8208d24c7aSGreg Roach self::$shared_data[$key] = $value; 8308d24c7aSGreg Roach } 8408d24c7aSGreg Roach 8508d24c7aSGreg Roach /** 86ecf66805SGreg Roach * Implementation of Blade "stacks". 87ecf66805SGreg Roach * 88ecf66805SGreg Roach * @see https://laravel.com/docs/5.5/blade#stacks 89962e29c9SGreg Roach * 90962e29c9SGreg Roach * @param string $stack 91fa4036e8SGreg Roach * 92fa4036e8SGreg Roach * @return void 93ecf66805SGreg Roach */ 94c1010edaSGreg Roach public static function push(string $stack) 95c1010edaSGreg Roach { 96ecf66805SGreg Roach self::$stack = $stack; 97ecf66805SGreg Roach ob_start(); 98ecf66805SGreg Roach } 99ecf66805SGreg Roach 100ecf66805SGreg Roach /** 101ecf66805SGreg Roach * Implementation of Blade "stacks". 102fa4036e8SGreg Roach * 103fa4036e8SGreg Roach * @return void 104ecf66805SGreg Roach */ 105c1010edaSGreg Roach public static function endpush() 106c1010edaSGreg Roach { 107ecf66805SGreg Roach self::$stacks[self::$stack][] = ob_get_clean(); 108ecf66805SGreg Roach } 109ecf66805SGreg Roach 110ecf66805SGreg Roach /** 111ecf66805SGreg Roach * Implementation of Blade "stacks". 112ecf66805SGreg Roach * 113962e29c9SGreg Roach * @param string $stack 114962e29c9SGreg Roach * 115ecf66805SGreg Roach * @return string 116ecf66805SGreg Roach */ 117c1010edaSGreg Roach public static function stack(string $stack): string 118c1010edaSGreg Roach { 119ecf66805SGreg Roach $content = implode('', self::$stacks[$stack] ?? []); 120ecf66805SGreg Roach 121ecf66805SGreg Roach self::$stacks[$stack] = []; 122ecf66805SGreg Roach 123ecf66805SGreg Roach return $content; 124ecf66805SGreg Roach } 125ecf66805SGreg Roach 126ecf66805SGreg Roach /** 127f3281ad6SGreg Roach * Render a view. 128f3281ad6SGreg Roach * 129f3281ad6SGreg Roach * @return string 13070f31542SGreg Roach * @throws Throwable 131f3281ad6SGreg Roach */ 1328f53f488SRico Sonntag public function render(): string 133c1010edaSGreg Roach { 1344a86d714SGreg Roach $variables_for_view = $this->data + self::$shared_data; 1354a86d714SGreg Roach extract($variables_for_view); 136f3281ad6SGreg Roach 13770f31542SGreg Roach try { 138f3281ad6SGreg Roach ob_start(); 139bc241c54SGreg Roach // Do not use require, so we can catch errors for missing files 140bc241c54SGreg Roach include $this->getFilenameForView($this->name); 14175d70144SGreg Roach 142f3281ad6SGreg Roach return ob_get_clean(); 14370f31542SGreg Roach } catch (Throwable $ex) { 14470f31542SGreg Roach ob_end_clean(); 14570f31542SGreg Roach throw $ex; 14670f31542SGreg Roach } 147f3281ad6SGreg Roach } 148f3281ad6SGreg Roach 149f3281ad6SGreg Roach /** 15075d70144SGreg Roach * Allow a theme to override the default views. 151f3281ad6SGreg Roach * 152f3281ad6SGreg Roach * @param string $view_name 153f3281ad6SGreg Roach * 15475d70144SGreg Roach * @return string 15550c68a25SGreg Roach * @throws Exception 156f3281ad6SGreg Roach */ 1578f53f488SRico Sonntag public function getFilenameForView($view_name): string 158c1010edaSGreg Roach { 15950c68a25SGreg Roach foreach ($this->paths() as $path) { 160dd6b2bfcSGreg Roach $view_file = $path . $view_name . self::TEMPLATE_EXTENSION; 16175d70144SGreg Roach 16250c68a25SGreg Roach if (is_file($view_file)) { 16350c68a25SGreg Roach return $view_file; 164f21917b2SGreg Roach } 165f3281ad6SGreg Roach } 166f3281ad6SGreg Roach 16750c68a25SGreg Roach throw new Exception('View not found: ' . e($view_name)); 16850c68a25SGreg Roach } 16950c68a25SGreg Roach 170f3281ad6SGreg Roach /** 171f3281ad6SGreg Roach * Cerate and render a view in a single operation. 172f3281ad6SGreg Roach * 173f3281ad6SGreg Roach * @param string $name 174f3281ad6SGreg Roach * @param mixed[] $data 175f3281ad6SGreg Roach * 176f3281ad6SGreg Roach * @return string 177f3281ad6SGreg Roach */ 1788f53f488SRico Sonntag public static function make($name, $data = []): string 179c1010edaSGreg Roach { 180f3281ad6SGreg Roach $view = new static($name, $data); 181f3281ad6SGreg Roach 18244116e73SGreg Roach DebugBar::addView($name, $data); 18344116e73SGreg Roach 184f3281ad6SGreg Roach return $view->render(); 185f3281ad6SGreg Roach } 18650c68a25SGreg Roach 18750c68a25SGreg Roach /** 18850c68a25SGreg Roach * @return string[] 18950c68a25SGreg Roach */ 19050c68a25SGreg Roach private function paths(): array 19150c68a25SGreg Roach { 19250c68a25SGreg Roach static $paths = []; 19350c68a25SGreg Roach 19450c68a25SGreg Roach if (empty($paths)) { 19550c68a25SGreg Roach // Module views 19650c68a25SGreg Roach // @TODO - this includes disabled modules. 197*8d0ebef0SGreg Roach $paths = glob(WT_ROOT . Webtrees::MODULES_PATH . '*/' . self::TEMPLATE_PATH); 19850c68a25SGreg Roach // Theme views 199*8d0ebef0SGreg Roach $paths[] = WT_ROOT . Webtrees::THEMES_PATH . Theme::theme()->themeId() . self::TEMPLATE_PATH; 20050c68a25SGreg Roach // Core views 201dd6b2bfcSGreg Roach $paths[] = WT_ROOT . self::TEMPLATE_PATH; 20250c68a25SGreg Roach 203bdb3725aSGreg Roach $paths = array_filter($paths, function (string $path): bool { 204bdb3725aSGreg Roach return is_dir($path); 205bdb3725aSGreg Roach }); 20650c68a25SGreg Roach } 20750c68a25SGreg Roach 20850c68a25SGreg Roach return $paths; 20950c68a25SGreg Roach } 210f3281ad6SGreg Roach} 211