3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2019
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
40 if (!class_exists('Smarty')) {
41 require_once 'Smarty/Smarty.class.php';
47 class CRM_Core_Smarty
extends Smarty
{
49 // use print.tpl and bypass the CMS. Civi prints a valid html file
51 // this and all the below bypasses the CMS html surrounding it and assumes we will embed this within other pages
53 // sends the generated html to the chosen pdf engine
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
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?
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
68 * We only need one instance of this object. So we use the singleton
69 * pattern and cache the instance in this variable
73 static private $_singleton = NULL;
78 * A list of variables ot save temporarily in format (string $name => mixed $value).
82 private $backupFrames = [];
87 * @return CRM_Core_Smarty
89 public function __construct() {
90 parent
::__construct();
93 private function initialize() {
94 $config = CRM_Core_Config
::singleton();
96 if (isset($config->customTemplateDir
) && $config->customTemplateDir
) {
97 $this->template_dir
= array_merge([$config->customTemplateDir
],
102 $this->template_dir
= $config->templateDir
;
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
);
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";
116 //Check for safe mode CRM-2207
117 if (ini_get('safe_mode')) {
118 $this->use_sub_dirs
= FALSE;
121 $this->use_sub_dirs
= TRUE;
124 $customPluginsDir = NULL;
125 if (isset($config->customPHPPathDir
)) {
127 = $config->customPHPPathDir
. DIRECTORY_SEPARATOR
.
128 'CRM' . DIRECTORY_SEPARATOR
.
129 'Core' . DIRECTORY_SEPARATOR
.
130 'Smarty' . DIRECTORY_SEPARATOR
.
131 'plugins' . DIRECTORY_SEPARATOR
;
132 if (!file_exists($customPluginsDir)) {
133 $customPluginsDir = NULL;
137 $smartyDir = dirname(dirname(__DIR__
)) . DIRECTORY_SEPARATOR
. 'packages' . DIRECTORY_SEPARATOR
. 'Smarty' . DIRECTORY_SEPARATOR
;
138 $pluginsDir = __DIR__
. DIRECTORY_SEPARATOR
. 'Smarty' . DIRECTORY_SEPARATOR
. 'plugins' . DIRECTORY_SEPARATOR
;
140 if ($customPluginsDir) {
141 $this->plugins_dir
= [$customPluginsDir, $smartyDir . 'plugins', $pluginsDir];
144 $this->plugins_dir
= [$smartyDir . 'plugins', $pluginsDir];
147 // add the session and the config here
148 $session = CRM_Core_Session
::singleton();
150 $this->assign_by_ref('config', $config);
151 $this->assign_by_ref('session', $session);
153 $tsLocale = CRM_Core_I18n
::getLocale();
154 $this->assign('tsLocale', $tsLocale);
156 // CRM-7163 hack: we don’t display langSwitch on upgrades anyway
157 if (!CRM_Core_Config
::isUpgradeMode()) {
158 $this->assign('langSwitch', CRM_Core_I18n
::uiLanguages());
161 $this->register_function('crmURL', ['CRM_Utils_System', 'crmURL']);
162 $this->load_filter('pre', 'resetExtScope');
164 $this->assign('crmPermissions', new CRM_Core_Smarty_Permissions());
168 * Static instance provider.
170 * Method providing static instance of SmartTemplate, as
171 * in Singleton pattern.
173 public static function &singleton() {
174 if (!isset(self
::$_singleton)) {
175 self
::$_singleton = new CRM_Core_Smarty();
176 self
::$_singleton->initialize();
178 self
::registerStringResource();
180 return self
::$_singleton;
184 * Executes & returns or displays the template results
186 * @param string $resource_name
187 * @param string $cache_id
188 * @param string $compile_id
189 * @param bool $display
191 * @return bool|mixed|string
193 public function fetch($resource_name, $cache_id = NULL, $compile_id = NULL, $display = FALSE) {
194 if (preg_match('/^(\s+)?string:/', $resource_name)) {
195 $old_security = $this->security
;
196 $this->security
= TRUE;
198 $output = parent
::fetch($resource_name, $cache_id, $compile_id, $display);
199 if (isset($old_security)) {
200 $this->security
= $old_security;
206 * Fetch a template (while using certain variables)
208 * @param string $resource_name
210 * (string $name => mixed $value) variables to export to Smarty.
212 * @return bool|mixed|string
214 public function fetchWith($resource_name, $vars) {
215 $this->pushScope($vars);
217 $result = $this->fetch($resource_name);
219 catch (Exception
$e) {
220 // simulate try { ... } finally { ... }
229 * @param string $name
232 public function appendValue($name, $value) {
233 $currentValue = $this->get_template_vars($name);
234 if (!$currentValue) {
235 $this->assign($name, $value);
238 if (strpos($currentValue, $value) === FALSE) {
239 $this->assign($name, $currentValue . $value);
244 public function clearTemplateVars() {
245 foreach (array_keys($this->_tpl_vars
) as $key) {
246 if ($key == 'config' ||
$key == 'session') {
249 unset($this->_tpl_vars
[$key]);
253 public static function registerStringResource() {
254 require_once 'CRM/Core/Smarty/resources/String.php';
255 civicrm_smarty_register_string_resource();
261 public function addTemplateDir($path) {
262 if (is_array($this->template_dir
)) {
263 array_unshift($this->template_dir
, $path);
266 $this->template_dir
= [$path, $this->template_dir
];
272 * Temporarily assign a list of variables.
275 * $smarty->pushScope(array(
276 * 'first_name' => 'Alice',
277 * 'last_name' => 'roberts',
279 * $html = $smarty->fetch('view-contact.tpl');
280 * $smarty->popScope();
284 * (string $name => mixed $value).
285 * @return CRM_Core_Smarty
288 public function pushScope($vars) {
289 $oldVars = $this->get_template_vars();
291 foreach ($vars as $key => $value) {
292 $backupFrame[$key] = isset($oldVars[$key]) ?
$oldVars[$key] : NULL;
294 $this->backupFrames
[] = $backupFrame;
296 $this->assignAll($vars);
302 * Remove any values that were previously pushed.
304 * @return CRM_Core_Smarty
307 public function popScope() {
308 $this->assignAll(array_pop($this->backupFrames
));
314 * (string $name => mixed $value).
315 * @return CRM_Core_Smarty
317 public function assignAll($vars) {
318 foreach ($vars as $key => $value) {
319 $this->assign($key, $value);
325 * Get the locale for translation.
329 private function getLocale() {
330 $tsLocale = CRM_Core_I18n
::getLocale();
331 if (!empty($tsLocale)) {
335 $config = CRM_Core_Config
::singleton();
336 if (!empty($config->lcMessages
)) {
337 return $config->lcMessages
;