1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * Class for rendering partial-views, which are useful for reusing the same partial-views or updating specific parts of 24 * the page asynchronously, i.e., partials can be included into a view initially and updated in AJAX manner, later. 25 */ 26class CPartial { 27 28 /** 29 * Directory list of MVC partials ordered by search priority. 30 * 31 * @static 32 * 33 * @var array 34 */ 35 private static $directories = ['local/app/partials', 'app/partials']; 36 37 /** 38 * Partial name. 39 * 40 * @var string 41 */ 42 private $name; 43 44 /** 45 * Data provided for partial. 46 * 47 * @var array 48 */ 49 private $data; 50 51 /** 52 * Directory where the partial file was found. 53 * 54 * @var string 55 */ 56 private $directory; 57 58 /** 59 * Create a partial based on partial name and data. 60 * 61 * @param string $name Partial name to search for. 62 * @param array $data Accessible data within the partial. 63 * 64 * @throws InvalidArgumentException if partial name not valid. 65 * @throws RuntimeException if partial not found or not readable. 66 */ 67 public function __construct($name, array $data = []) { 68 if (!preg_match('/^[a-z]+(\/[a-z]+)*(\.[a-z]+)*$/', $name)) { 69 throw new InvalidArgumentException(sprintf('Invalid partial name: "%s".', $name)); 70 } 71 72 $file_path = null; 73 74 foreach (self::$directories as $directory) { 75 $file_path = $directory.'/'.$name.'.php'; 76 if (is_file($file_path)) { 77 $this->directory = $directory; 78 break; 79 } 80 } 81 82 if ($this->directory === null) { 83 throw new RuntimeException(sprintf('Partial not found: "%s".', $name)); 84 } 85 86 if (!is_readable($file_path)) { 87 throw new RuntimeException(sprintf('Partial not readable: "%s".', $file_path)); 88 } 89 90 $this->name = $name; 91 $this->data = $data; 92 } 93 94 /** 95 * Render partial and return the output. 96 * Note: partial should only output textual content like HTML, JSON, scripts or similar. 97 * 98 * @throws RuntimeException if partial not found, not readable or returned false. 99 * 100 * @return string 101 */ 102 public function getOutput() { 103 $data = $this->data; 104 105 $file_path = $this->directory.'/'.$this->name.'.php'; 106 107 ob_start(); 108 109 if ((include $file_path) === false) { 110 ob_end_clean(); 111 112 throw new RuntimeException(sprintf('Cannot render partial: "%s".', $file_path)); 113 } 114 115 return ob_get_clean(); 116 } 117 118 /** 119 * Get the contents of a PHP-preprocessed JavaScript file. 120 * Notes: 121 * - JavaScript file will be searched in the "js" subdirectory of the partial file. 122 * - A copy of $data variable will be available for using within the file. 123 * 124 * @param string $file_name 125 * @param array $data 126 * 127 * @throws RuntimeException if the file not found, not readable or returned false. 128 * 129 * @return string 130 */ 131 public function readJsFile(string $file_name, ?array $data = null): string { 132 $data = ($data === null) ? $this->data : $data; 133 134 $file_path = $this->directory.'/js/'.$file_name; 135 136 ob_start(); 137 138 if ((include $file_path) === false) { 139 ob_end_clean(); 140 141 throw new RuntimeException(sprintf('Cannot read file: "%s".', $file_path)); 142 } 143 144 return ob_get_clean(); 145 } 146 147 /** 148 * Include a PHP-preprocessed JavaScript file inline. 149 * Notes: 150 * - JavaScript file will be searched in the "js" subdirectory of the partial file. 151 * - A copy of $data variable will be available for using within the file. 152 * 153 * @param string $file_name 154 * @param array $data 155 * 156 * @throws RuntimeException if the file not found, not readable or returned false. 157 */ 158 public function includeJsFile(string $file_name, array $data = null) { 159 echo $this->readJsFile($file_name, $data); 160 } 161 162 /** 163 * Register custom directory of MVC partials. The last registered will have the first priority. 164 * 165 * @param string $directory 166 */ 167 public static function registerDirectory($directory) { 168 if (!in_array($directory, self::$directories)) { 169 array_unshift(self::$directories, $directory); 170 } 171 } 172 173 /** 174 * Get partial file name. 175 * 176 * @return string 177 */ 178 public function getName(): string { 179 return $this->name; 180 } 181} 182