3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
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
24 if (!class_exists('Smarty')) {
25 require_once 'Smarty/Smarty.class.php';
31 class CRM_Core_Smarty
extends Smarty
{
33 // use print.tpl and bypass the CMS. Civi prints a valid html file
35 // this and all the below bypasses the CMS html surrounding it and assumes we will embed this within other pages
37 // sends the generated html to the chosen pdf engine
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
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?
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
52 * We only need one instance of this object. So we use the singleton
53 * pattern and cache the instance in this variable
57 static private $_singleton = NULL;
62 * A list of variables ot save temporarily in format (string $name => mixed $value).
66 private $backupFrames = [];
71 * @return CRM_Core_Smarty
73 public function __construct() {
74 parent
::__construct();
77 private function initialize() {
78 $config = CRM_Core_Config
::singleton();
80 if (isset($config->customTemplateDir
) && $config->customTemplateDir
) {
81 $this->template_dir
= array_merge([$config->customTemplateDir
],
86 $this->template_dir
= $config->templateDir
;
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
);
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";
100 //Check for safe mode CRM-2207
101 if (ini_get('safe_mode')) {
102 $this->use_sub_dirs
= FALSE;
105 $this->use_sub_dirs
= TRUE;
108 $customPluginsDir = NULL;
109 if (isset($config->customPHPPathDir
)) {
111 = $config->customPHPPathDir
. DIRECTORY_SEPARATOR
.
112 'CRM' . DIRECTORY_SEPARATOR
.
113 'Core' . DIRECTORY_SEPARATOR
.
114 'Smarty' . DIRECTORY_SEPARATOR
.
115 'plugins' . DIRECTORY_SEPARATOR
;
116 if (!file_exists($customPluginsDir)) {
117 $customPluginsDir = NULL;
121 $pkgsDir = Civi
::paths()->getVariable('civicrm.packages', 'path');
122 $smartyDir = $pkgsDir . DIRECTORY_SEPARATOR
. 'Smarty' . DIRECTORY_SEPARATOR
;
123 $pluginsDir = __DIR__
. DIRECTORY_SEPARATOR
. 'Smarty' . DIRECTORY_SEPARATOR
. 'plugins' . DIRECTORY_SEPARATOR
;
125 if ($customPluginsDir) {
126 $this->plugins_dir
= [$customPluginsDir, $smartyDir . 'plugins', $pluginsDir];
129 $this->plugins_dir
= [$smartyDir . 'plugins', $pluginsDir];
132 $this->compile_check
= $this->isCheckSmartyIsCompiled();
134 // add the session and the config here
135 $session = CRM_Core_Session
::singleton();
137 $this->assign_by_ref('config', $config);
138 $this->assign_by_ref('session', $session);
140 $tsLocale = CRM_Core_I18n
::getLocale();
141 $this->assign('tsLocale', $tsLocale);
143 // CRM-7163 hack: we don’t display langSwitch on upgrades anyway
144 if (!CRM_Core_Config
::isUpgradeMode()) {
145 $this->assign('langSwitch', CRM_Core_I18n
::uiLanguages());
148 $this->register_function('crmURL', ['CRM_Utils_System', 'crmURL']);
149 $this->load_filter('pre', 'resetExtScope');
151 $this->assign('crmPermissions', new CRM_Core_Smarty_Permissions());
155 * Static instance provider.
157 * Method providing static instance of SmartTemplate, as
158 * in Singleton pattern.
160 public static function &singleton() {
161 if (!isset(self
::$_singleton)) {
162 self
::$_singleton = new CRM_Core_Smarty();
163 self
::$_singleton->initialize();
165 self
::registerStringResource();
167 return self
::$_singleton;
171 * Executes & returns or displays the template results
173 * @param string $resource_name
174 * @param string $cache_id
175 * @param string $compile_id
176 * @param bool $display
178 * @return bool|mixed|string
180 public function fetch($resource_name, $cache_id = NULL, $compile_id = NULL, $display = FALSE) {
181 if (preg_match('/^(\s+)?string:/', $resource_name)) {
182 $old_security = $this->security
;
183 $this->security
= TRUE;
185 $output = parent
::fetch($resource_name, $cache_id, $compile_id, $display);
186 if (isset($old_security)) {
187 $this->security
= $old_security;
193 * Fetch a template (while using certain variables)
195 * @param string $resource_name
197 * (string $name => mixed $value) variables to export to Smarty.
199 * @return bool|mixed|string
201 public function fetchWith($resource_name, $vars) {
202 $this->pushScope($vars);
204 $result = $this->fetch($resource_name);
206 catch (Exception
$e) {
207 // simulate try { ... } finally { ... }
216 * @param string $name
219 public function appendValue($name, $value) {
220 $currentValue = $this->get_template_vars($name);
221 if (!$currentValue) {
222 $this->assign($name, $value);
225 if (strpos($currentValue, $value) === FALSE) {
226 $this->assign($name, $currentValue . $value);
231 public function clearTemplateVars() {
232 foreach (array_keys($this->_tpl_vars
) as $key) {
233 if ($key == 'config' ||
$key == 'session') {
236 unset($this->_tpl_vars
[$key]);
240 public static function registerStringResource() {
241 require_once 'CRM/Core/Smarty/resources/String.php';
242 civicrm_smarty_register_string_resource();
248 public function addTemplateDir($path) {
249 if (is_array($this->template_dir
)) {
250 array_unshift($this->template_dir
, $path);
253 $this->template_dir
= [$path, $this->template_dir
];
259 * Temporarily assign a list of variables.
262 * $smarty->pushScope(array(
263 * 'first_name' => 'Alice',
264 * 'last_name' => 'roberts',
266 * $html = $smarty->fetch('view-contact.tpl');
267 * $smarty->popScope();
271 * (string $name => mixed $value).
272 * @return CRM_Core_Smarty
275 public function pushScope($vars) {
276 $oldVars = $this->get_template_vars();
278 foreach ($vars as $key => $value) {
279 $backupFrame[$key] = $oldVars[$key] ??
NULL;
281 $this->backupFrames
[] = $backupFrame;
283 $this->assignAll($vars);
289 * Remove any values that were previously pushed.
291 * @return CRM_Core_Smarty
294 public function popScope() {
295 $this->assignAll(array_pop($this->backupFrames
));
301 * (string $name => mixed $value).
302 * @return CRM_Core_Smarty
304 public function assignAll($vars) {
305 foreach ($vars as $key => $value) {
306 $this->assign($key, $value);
312 * Get the locale for translation.
316 private function getLocale() {
317 $tsLocale = CRM_Core_I18n
::getLocale();
318 if (!empty($tsLocale)) {
322 $config = CRM_Core_Config
::singleton();
323 if (!empty($config->lcMessages
)) {
324 return $config->lcMessages
;
331 * Get the compile_check value.
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);