dev/core#1093: Add Custom Fields to Logging Tables
[civicrm-core.git] / CRM / Core / Smarty.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * Fix for bug CRM-392. Not sure if this is the best fix or it will impact
38 * other similar PEAR packages. doubt it
39 */
40if (!class_exists('Smarty')) {
41 require_once 'Smarty/Smarty.class.php';
42}
43
44/**
45 *
46 */
47class CRM_Core_Smarty extends Smarty {
7da04cde 48 const
6a488035
TO
49 // use print.tpl and bypass the CMS. Civi prints a valid html file
50 PRINT_PAGE = 1,
da3c7979 51 // this and all the below bypasses the CMS html surrounding it and assumes we will embed this within other pages
6a488035
TO
52 PRINT_SNIPPET = 2,
53 // sends the generated html to the chosen pdf engine
54 PRINT_PDF = 3,
55 // this options also skips the enclosing form html and does not
56 // generate any of the hidden fields, most notably qfKey
57 // this is typically used in ajax scripts to embed form snippets based on user choices
58 PRINT_NOFORM = 4,
59 // this prints a complete form and also generates a qfKey, can we replace this with
60 // snippet = 2?? Does the constant _NOFFORM do anything?
61 PRINT_QFKEY = 5,
fc05b8da
CW
62 // Note: added in v 4.3 with the value '6'
63 // Value changed in 4.5 to 'json' for better readability
64 // @see CRM_Core_Page_AJAX::returnJsonResponse
65 PRINT_JSON = 'json';
6a488035
TO
66
67 /**
68 * We only need one instance of this object. So we use the singleton
69 * pattern and cache the instance in this variable
70 *
71 * @var object
6a488035
TO
72 */
73 static private $_singleton = NULL;
74
17f267d6 75 /**
e97c66ff 76 * Backup frames.
77 *
78 * A list of variables ot save temporarily in format (string $name => mixed $value).
79 *
80 * @var array
17f267d6 81 */
be2fb01f 82 private $backupFrames = [];
17f267d6 83
6a488035 84 /**
f9e31d7f 85 * Class constructor.
6a488035
TO
86 *
87 * @return CRM_Core_Smarty
6a488035 88 */
6ef04c72 89 public function __construct() {
6a488035
TO
90 parent::__construct();
91 }
92
2aa397bc 93 private function initialize() {
6a488035
TO
94 $config = CRM_Core_Config::singleton();
95
96 if (isset($config->customTemplateDir) && $config->customTemplateDir) {
be2fb01f 97 $this->template_dir = array_merge([$config->customTemplateDir],
6a488035
TO
98 $config->templateDir
99 );
100 }
101 else {
102 $this->template_dir = $config->templateDir;
103 }
635f0b86
TO
104 $this->compile_dir = CRM_Utils_File::addTrailingSlash(CRM_Utils_File::addTrailingSlash($config->templateCompileDir) . $this->getLocale());
105 CRM_Utils_File::createDir($this->compile_dir);
106 CRM_Utils_File::restrictAccess($this->compile_dir);
6a488035
TO
107
108 // check and ensure it is writable
109 // else we sometime suppress errors quietly and this results
110 // in blank emails etc
111 if (!is_writable($this->compile_dir)) {
112 echo "CiviCRM does not have permission to write temp files in {$this->compile_dir}, Exiting";
113 exit();
114 }
115
116 //Check for safe mode CRM-2207
117 if (ini_get('safe_mode')) {
118 $this->use_sub_dirs = FALSE;
119 }
120 else {
121 $this->use_sub_dirs = TRUE;
122 }
123
124 $customPluginsDir = NULL;
125 if (isset($config->customPHPPathDir)) {
e7483cbe
J
126 $customPluginsDir
127 = $config->customPHPPathDir . DIRECTORY_SEPARATOR .
353ffa53
TO
128 'CRM' . DIRECTORY_SEPARATOR .
129 'Core' . DIRECTORY_SEPARATOR .
130 'Smarty' . DIRECTORY_SEPARATOR .
131 'plugins' . DIRECTORY_SEPARATOR;
6a488035
TO
132 if (!file_exists($customPluginsDir)) {
133 $customPluginsDir = NULL;
134 }
135 }
136
94dbed1f
TO
137 $smartyDir = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'packages' . DIRECTORY_SEPARATOR . 'Smarty' . DIRECTORY_SEPARATOR;
138 $pluginsDir = __DIR__ . DIRECTORY_SEPARATOR . 'Smarty' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR;
139
6a488035 140 if ($customPluginsDir) {
be2fb01f 141 $this->plugins_dir = [$customPluginsDir, $smartyDir . 'plugins', $pluginsDir];
6a488035
TO
142 }
143 else {
be2fb01f 144 $this->plugins_dir = [$smartyDir . 'plugins', $pluginsDir];
6a488035
TO
145 }
146
d938f496
LS
147 $this->compile_check = $this->isCheckSmartyIsCompiled();
148
6a488035
TO
149 // add the session and the config here
150 $session = CRM_Core_Session::singleton();
151
152 $this->assign_by_ref('config', $config);
153 $this->assign_by_ref('session', $session);
154
98466ff9 155 $tsLocale = CRM_Core_I18n::getLocale();
6a488035
TO
156 $this->assign('tsLocale', $tsLocale);
157
158 // CRM-7163 hack: we don’t display langSwitch on upgrades anyway
159 if (!CRM_Core_Config::isUpgradeMode()) {
921ed8ae 160 $this->assign('langSwitch', CRM_Core_I18n::uiLanguages());
6a488035
TO
161 }
162
be2fb01f 163 $this->register_function('crmURL', ['CRM_Utils_System', 'crmURL']);
d9aa1c6b 164 $this->load_filter('pre', 'resetExtScope');
abbf7b48
TO
165
166 $this->assign('crmPermissions', new CRM_Core_Smarty_Permissions());
6a488035
TO
167 }
168
169 /**
170 * Static instance provider.
171 *
172 * Method providing static instance of SmartTemplate, as
173 * in Singleton pattern.
174 */
00be9182 175 public static function &singleton() {
6a488035 176 if (!isset(self::$_singleton)) {
481a74f4
TO
177 self::$_singleton = new CRM_Core_Smarty();
178 self::$_singleton->initialize();
6a488035
TO
179
180 self::registerStringResource();
181 }
182 return self::$_singleton;
183 }
184
185 /**
100fef9d 186 * Executes & returns or displays the template results
6a488035
TO
187 *
188 * @param string $resource_name
189 * @param string $cache_id
190 * @param string $compile_id
6a0b768e 191 * @param bool $display
77b97be7
EM
192 *
193 * @return bool|mixed|string
6a488035 194 */
00be9182 195 public function fetch($resource_name, $cache_id = NULL, $compile_id = NULL, $display = FALSE) {
481a74f4 196 if (preg_match('/^(\s+)?string:/', $resource_name)) {
7155133f
ND
197 $old_security = $this->security;
198 $this->security = TRUE;
199 }
200 $output = parent::fetch($resource_name, $cache_id, $compile_id, $display);
201 if (isset($old_security)) {
202 $this->security = $old_security;
203 }
204 return $output;
6a488035
TO
205 }
206
9b7526a8
TO
207 /**
208 * Fetch a template (while using certain variables)
209 *
210 * @param string $resource_name
6a0b768e
TO
211 * @param array $vars
212 * (string $name => mixed $value) variables to export to Smarty.
9b7526a8
TO
213 * @throws Exception
214 * @return bool|mixed|string
215 */
00be9182 216 public function fetchWith($resource_name, $vars) {
9b7526a8
TO
217 $this->pushScope($vars);
218 try {
219 $result = $this->fetch($resource_name);
0db6c3e1
TO
220 }
221 catch (Exception $e) {
9b7526a8
TO
222 // simulate try { ... } finally { ... }
223 $this->popScope();
224 throw $e;
225 }
226 $this->popScope();
227 return $result;
228 }
229
a0ee3941 230 /**
100fef9d 231 * @param string $name
a0ee3941
EM
232 * @param $value
233 */
00be9182 234 public function appendValue($name, $value) {
6a488035
TO
235 $currentValue = $this->get_template_vars($name);
236 if (!$currentValue) {
237 $this->assign($name, $value);
238 }
239 else {
240 if (strpos($currentValue, $value) === FALSE) {
241 $this->assign($name, $currentValue . $value);
242 }
243 }
244 }
245
00be9182 246 public function clearTemplateVars() {
6a488035
TO
247 foreach (array_keys($this->_tpl_vars) as $key) {
248 if ($key == 'config' || $key == 'session') {
249 continue;
250 }
251 unset($this->_tpl_vars[$key]);
252 }
253 }
254
00be9182 255 public static function registerStringResource() {
6a488035
TO
256 require_once 'CRM/Core/Smarty/resources/String.php';
257 civicrm_smarty_register_string_resource();
258 }
259
a0ee3941
EM
260 /**
261 * @param $path
262 */
00be9182 263 public function addTemplateDir($path) {
481a74f4
TO
264 if (is_array($this->template_dir)) {
265 array_unshift($this->template_dir, $path);
0db6c3e1
TO
266 }
267 else {
be2fb01f 268 $this->template_dir = [$path, $this->template_dir];
6a488035
TO
269 }
270
271 }
17f267d6
TO
272
273 /**
274 * Temporarily assign a list of variables.
275 *
276 * @code
277 * $smarty->pushScope(array(
278 * 'first_name' => 'Alice',
279 * 'last_name' => 'roberts',
280 * ));
281 * $html = $smarty->fetch('view-contact.tpl');
282 * $smarty->popScope();
283 * @endcode
284 *
6a0b768e
TO
285 * @param array $vars
286 * (string $name => mixed $value).
17f267d6
TO
287 * @return CRM_Core_Smarty
288 * @see popScope
289 */
290 public function pushScope($vars) {
291 $oldVars = $this->get_template_vars();
be2fb01f 292 $backupFrame = [];
17f267d6
TO
293 foreach ($vars as $key => $value) {
294 $backupFrame[$key] = isset($oldVars[$key]) ? $oldVars[$key] : NULL;
295 }
296 $this->backupFrames[] = $backupFrame;
297
298 $this->assignAll($vars);
299
300 return $this;
301 }
302
303 /**
304 * Remove any values that were previously pushed.
305 *
306 * @return CRM_Core_Smarty
307 * @see pushScope
308 */
309 public function popScope() {
310 $this->assignAll(array_pop($this->backupFrames));
311 return $this;
312 }
313
314 /**
6a0b768e
TO
315 * @param array $vars
316 * (string $name => mixed $value).
17f267d6
TO
317 * @return CRM_Core_Smarty
318 */
319 public function assignAll($vars) {
320 foreach ($vars as $key => $value) {
321 $this->assign($key, $value);
322 }
323 return $this;
324 }
96025800 325
f2ac86d1 326 /**
327 * Get the locale for translation.
328 *
329 * @return string
330 */
635f0b86 331 private function getLocale() {
98466ff9 332 $tsLocale = CRM_Core_I18n::getLocale();
635f0b86
TO
333 if (!empty($tsLocale)) {
334 return $tsLocale;
335 }
336
337 $config = CRM_Core_Config::singleton();
338 if (!empty($config->lcMessages)) {
339 return $config->lcMessages;
340 }
341
342 return 'en_US';
343 }
344
d938f496
LS
345 /**
346 * Get the compile_check value.
347 *
348 * @return bool
349 */
350 private function isCheckSmartyIsCompiled() {
351 // check for define in civicrm.settings.php as FALSE, otherwise returns TRUE
352 return CRM_Utils_Constant::value('CIVICRM_TEMPLATE_COMPILE_CHECK', TRUE);
353 }
354
6a488035 355}