xref: /webtrees/app/View.php (revision 210dfef2b733195f1b6bdc67fcfa8fed99e6bac4)
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