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