Merge pull request #23870 from eileenmcnaughton/offline
[civicrm-core.git] / CRM / Core / Block.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 */
17
18/**
8eedd10a 19 * Defines a simple implementation of a drupal block.
6a488035 20 *
8eedd10a 21 * Blocks definitions and html are in a smarty template file.
6a488035
TO
22 */
23class CRM_Core_Block {
24
25 /**
fe482240 26 * The following blocks are supported.
6a488035
TO
27 *
28 * @var int
29 */
7da04cde 30 const
6a488035
TO
31 CREATE_NEW = 1,
32 RECENTLY_VIEWED = 2,
33 DASHBOARD = 3,
34 ADD = 4,
35 LANGSWITCH = 5,
36 EVENT = 6,
37 FULLTEXT_SEARCH = 7;
38
39 /**
fe482240 40 * Template file names for the above blocks.
518fa0ee 41 * @var array
6a488035 42 */
518fa0ee 43 public static $_properties = NULL;
6a488035
TO
44
45 /**
fe482240 46 * Class constructor.
6a488035 47 */
2aa397bc
TO
48 public function __construct() {
49 }
6a488035
TO
50
51 /**
100fef9d 52 * Initialises the $_properties array
6a488035 53 */
00be9182 54 public static function initProperties() {
6a488035
TO
55 if (!defined('BLOCK_CACHE_GLOBAL')) {
56 define('BLOCK_CACHE_GLOBAL', 0x0008);
57 }
58
59 if (!defined('BLOCK_CACHE_PER_PAGE')) {
60 define('BLOCK_CACHE_PER_PAGE', 0x0004);
61 }
62
63 if (!defined('BLOCK_NO_CACHE')) {
64 define('BLOCK_NO_CACHE', -1);
65 }
66
67 if (!(self::$_properties)) {
68 $config = CRM_Core_Config::singleton();
69 self::$_properties = array(
70 // set status item to 0 to disable block by default (at install)
71 self::CREATE_NEW => array(
72 'template' => 'CreateNew.tpl',
73 'info' => ts('CiviCRM Create New Record'),
ba8f6a69 74 'subject' => '',
6a488035
TO
75 'active' => TRUE,
76 'cache' => BLOCK_CACHE_GLOBAL,
77 'visibility' => 1,
78 'weight' => -100,
79 'status' => 1,
80 'pages' => "civicrm\ncivicrm/*",
81 'region' => $config->userSystem->getDefaultBlockLocation(),
82 ),
83 self::RECENTLY_VIEWED => array(
84 'template' => 'RecentlyViewed.tpl',
85 'info' => ts('CiviCRM Recent Items'),
86 'subject' => ts('Recent Items'),
87 'active' => TRUE,
88 'cache' => BLOCK_NO_CACHE,
89 'visibility' => 1,
90 'weight' => -99,
91 'status' => 1,
92 'pages' => "civicrm\ncivicrm/*",
93 'region' => $config->userSystem->getDefaultBlockLocation(),
94 ),
95 self::DASHBOARD => array(
96 'template' => 'Dashboard.tpl',
97 'info' => ts('CiviCRM Contact Dashboard'),
98 'subject' => '',
99 'active' => TRUE,
100 'cache' => BLOCK_NO_CACHE,
101 'visibility' => 1,
102 'weight' => -98,
103 'status' => 1,
104 'pages' => "civicrm\ncivicrm/*",
105 'region' => $config->userSystem->getDefaultBlockLocation(),
106 ),
107 self::ADD => array(
108 'template' => 'Add.tpl',
109 'info' => ts('CiviCRM Quick Add'),
110 'subject' => ts('New Individual'),
111 'active' => TRUE,
112 'cache' => BLOCK_NO_CACHE,
113 'visibility' => 1,
114 'weight' => -97,
115 'status' => 1,
116 'pages' => "civicrm\ncivicrm/*",
117 'region' => $config->userSystem->getDefaultBlockLocation(),
118 ),
119 self::LANGSWITCH => array(
120 'template' => 'LangSwitch.tpl',
121 'info' => ts('CiviCRM Language Switcher'),
122 'subject' => '',
affcc9d2 123 'templateValues' => [],
6a488035
TO
124 'active' => TRUE,
125 'cache' => BLOCK_NO_CACHE,
126 'visibility' => 1,
127 'weight' => -96,
128 'status' => 1,
129 'pages' => "civicrm\ncivicrm/*",
130 'region' => $config->userSystem->getDefaultBlockLocation(),
131 ),
132 self::EVENT => array(
133 'template' => 'Event.tpl',
134 'info' => ts('CiviCRM Upcoming Events'),
135 'subject' => ts('Upcoming Events'),
affcc9d2 136 'templateValues' => [],
6a488035
TO
137 'active' => TRUE,
138 'cache' => BLOCK_NO_CACHE,
139 'visibility' => 1,
140 'weight' => -95,
141 'status' => 0,
142 'pages' => "civicrm\ncivicrm/*",
143 'region' => $config->userSystem->getDefaultBlockLocation(),
144 ),
145 self::FULLTEXT_SEARCH => array(
146 'template' => 'FullTextSearch.tpl',
147 'info' => ts('CiviCRM Full-text Search'),
148 'subject' => ts('Full-text Search'),
149 'active' => TRUE,
fd0bc470 150 'cache' => BLOCK_NO_CACHE,
6a488035
TO
151 'visibility' => 1,
152 'weight' => -94,
153 'status' => 0,
154 'pages' => "civicrm\ncivicrm/*",
155 'region' => $config->userSystem->getDefaultBlockLocation(),
156 ),
157 );
158
159 ksort(self::$_properties);
160 }
161 }
162
163 /**
100fef9d 164 * Returns the desired property from the $_properties array
6a488035 165 *
6a0b768e
TO
166 * @param int $id
167 * One of the class constants (ADD, SEARCH, etc.).
168 * @param string $property
169 * The desired property.
da6b46f4 170 *
a6c01b45
CW
171 * @return string
172 * the value of the desired property
6a488035 173 */
00be9182 174 public static function getProperty($id, $property) {
6a488035
TO
175 if (!(self::$_properties)) {
176 self::initProperties();
177 }
2e1f50d6 178 return self::$_properties[$id][$property] ?? NULL;
6a488035
TO
179 }
180
181 /**
100fef9d 182 * Sets the desired property in the $_properties array
6a488035 183 *
6a0b768e
TO
184 * @param int $id
185 * One of the class constants (ADD, SEARCH, etc.).
186 * @param string $property
187 * The desired property.
71d59b8d 188 * @param mixed $value
6a0b768e 189 * The value of the desired property.
6a488035 190 */
00be9182 191 public static function setProperty($id, $property, $value) {
6a488035
TO
192 if (!(self::$_properties)) {
193 self::initProperties();
194 }
195 self::$_properties[$id][$property] = $value;
196 }
197
198 /**
8eedd10a 199 * Returns the whole $_properties array.
6a488035 200 *
a6c01b45
CW
201 * @return array
202 * the $_properties array
6a488035 203 */
00be9182 204 public static function properties() {
6a488035
TO
205 if (!(self::$_properties)) {
206 self::initProperties();
207 }
208 return self::$_properties;
209 }
210
211 /**
fe482240 212 * Creates the info block for drupal.
6a488035
TO
213 *
214 * @return array
6a488035 215 */
00be9182 216 public static function getInfo() {
6a488035 217
affcc9d2 218 $block = [];
6a488035
TO
219 foreach (self::properties() as $id => $value) {
220 if ($value['active']) {
221 if (in_array($id, array(
353ffa53 222 self::ADD,
3bdca100 223 self::CREATE_NEW,
353ffa53 224 ))) {
6a488035
TO
225 $hasAccess = TRUE;
226 if (!CRM_Core_Permission::check('add contacts') &&
227 !CRM_Core_Permission::check('edit groups')
228 ) {
229 $hasAccess = FALSE;
230 }
231 //validate across edit/view - CRM-5666
232 if ($hasAccess && ($id == self::ADD)) {
233 $hasAccess = CRM_Core_Permission::giveMeAllACLs();
234 }
235 if (!$hasAccess) {
236 continue;
237 }
238 }
239
240 if ($id == self::EVENT &&
241 (!CRM_Core_Permission::access('CiviEvent', FALSE) ||
242 !CRM_Core_Permission::check('view event info')
243 )
244 ) {
245 continue;
246 }
247
248 $block[$id] = array(
249 'info' => $value['info'],
250 'cache' => $value['cache'],
6a488035
TO
251 'region' => $value['region'],
252 'visibility' => $value['visibility'],
253 'pages' => $value['pages'],
254 'status' => $value['status'],
255 'weight' => $value['weight'],
256 );
257 }
258 }
259
260 return $block;
261 }
262
263 /**
100fef9d 264 * Set the post action values for the block.
6a488035
TO
265 *
266 * php is lame and u cannot call functions from static initializers
267 * hence this hack
268 *
100fef9d 269 * @param int $id
6a488035
TO
270 */
271 private static function setTemplateValues($id) {
272 switch ($id) {
273 case self::CREATE_NEW:
274 self::setTemplateShortcutValues();
275 break;
276
277 case self::DASHBOARD:
278 self::setTemplateDashboardValues();
279 break;
280
281 case self::ADD:
282 $defaultLocation = CRM_Core_BAO_LocationType::getDefault();
283 $defaultPrimaryLocationId = $defaultLocation->id;
2aa397bc 284 $values = array(
353ffa53 285 'postURL' => CRM_Utils_System::url('civicrm/contact/add', 'reset=1&ct=Individual'),
6a488035
TO
286 'primaryLocationType' => $defaultPrimaryLocationId,
287 );
288
289 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
290 $values[$greeting . '_id'] = CRM_Contact_BAO_Contact_Utils::defaultGreeting('Individual', $greeting);
291 }
292
293 self::setProperty(self::ADD,
294 'templateValues',
295 $values
296 );
297 break;
298
2aa397bc 299 case self::LANGSWITCH:
bf2ab287 300 // gives the currentPath without trailing empty lcMessages to be completed
301 $values = array('queryString' => CRM_Utils_System::getLinksUrl('lcMessages', TRUE, FALSE, FALSE));
302 self::setProperty(self::LANGSWITCH, 'templateValues', $values);
303 break;
2aa397bc 304
6a488035
TO
305 case self::FULLTEXT_SEARCH:
306 $urlArray = array(
307 'fullTextSearchID' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue',
308 'CRM_Contact_Form_Search_Custom_FullText', 'value', 'name'
3bdca100 309 ),
353ffa53 310 );
6a488035
TO
311 self::setProperty(self::FULLTEXT_SEARCH, 'templateValues', $urlArray);
312 break;
313
314 case self::RECENTLY_VIEWED:
315 $recent = CRM_Utils_Recent::get();
316 self::setProperty(self::RECENTLY_VIEWED, 'templateValues', array('recentlyViewed' => $recent));
317 break;
318
319 case self::EVENT:
320 self::setTemplateEventValues();
321 break;
322 }
323 }
324
325 /**
fe482240 326 * Create the list of options to create New objects for the application and format is as a block.
6a488035
TO
327 */
328 private static function setTemplateShortcutValues() {
affcc9d2 329 static $shortCuts = [];
6a488035
TO
330
331 if (!($shortCuts)) {
332 if (CRM_Core_Permission::check('add contacts')) {
333 if (CRM_Core_Permission::giveMeAllACLs()) {
334 $shortCuts = CRM_Contact_BAO_ContactType::getCreateNewList();
335 }
336 }
337
338 // new activity (select target contact)
339 $shortCuts = array_merge($shortCuts, array(
340 array(
341 'path' => 'civicrm/activity',
342 'query' => 'action=add&reset=1&context=standalone',
343 'ref' => 'new-activity',
344 'title' => ts('Activity'),
3bdca100 345 ),
353ffa53 346 ));
6a488035
TO
347
348 $components = CRM_Core_Component::getEnabledComponents();
349
e46f73c7 350 if ($components) {
6a488035 351 // check if we can process credit card contribs
9be1374d 352 $newCredit = CRM_Core_Config::isEnabledBackOfficeCreditCardPayments();
fd0bc470 353
e46f73c7
CW
354 foreach ($components as $obj) {
355 $obj->creatNewShortcut($shortCuts, $newCredit);
6a488035
TO
356 }
357 }
358
359 // new email (select recipients)
360 $shortCuts = array_merge($shortCuts, array(
2aa397bc 361 array(
353ffa53
TO
362 'path' => 'civicrm/activity/email/add',
363 'query' => 'atype=3&action=add&reset=1&context=standalone',
364 'ref' => 'new-email',
365 'title' => ts('Email'),
3bdca100 366 ),
353ffa53 367 ));
6a488035
TO
368
369 if (CRM_Core_Permission::check('edit groups')) {
370 $shortCuts = array_merge($shortCuts, array(
2aa397bc 371 array(
353ffa53
TO
372 'path' => 'civicrm/group/add',
373 'query' => 'reset=1',
374 'ref' => 'new-group',
375 'title' => ts('Group'),
3bdca100 376 ),
353ffa53 377 ));
6a488035
TO
378 }
379
eaaaef83 380 if (CRM_Core_Permission::check('manage tags')) {
6a488035 381 $shortCuts = array_merge($shortCuts, array(
2aa397bc 382 array(
eaaaef83 383 'path' => 'civicrm/tag',
353ffa53
TO
384 'query' => 'reset=1&action=add',
385 'ref' => 'new-tag',
386 'title' => ts('Tag'),
3bdca100 387 ),
353ffa53 388 ));
6a488035
TO
389 }
390
391 if (empty($shortCuts)) {
392 return NULL;
393 }
394 }
395
affcc9d2 396 $values = [];
6a488035 397
7acb9b33 398 // Deprecated hook with typo. Please don't use this!
6a488035
TO
399 CRM_Utils_Hook::links('create.new.shorcuts',
400 NULL,
401 CRM_Core_DAO::$_nullObject,
1273d77c 402 $values
6a488035 403 );
79ba796c
CW
404 if ($values) {
405 CRM_Core_Error::deprecatedWarning('hook_civicrm_links "create.new.shorcuts" deprecated in favor of "create.new.shortcuts"');
406 }
407
408 foreach ($shortCuts as $key => $short) {
409 $values[$key] = self::setShortCutValues($short);
410 }
e65cf508 411
7acb9b33
WM
412 // Hook that enables extensions to add user-defined links
413 CRM_Utils_Hook::links('create.new.shortcuts',
414 NULL,
415 CRM_Core_DAO::$_nullObject,
416 $values
417 );
418
727b675c 419 foreach ($values as $key => $val) {
71d59b8d
EM
420 $values[$key]['name'] = $val['name'] ?? $val['title'];
421 $values[$key] += ['shortCuts' => []];
727b675c 422 }
6a488035 423
71d59b8d 424 self::setProperty(self::CREATE_NEW, 'templateValues', ['shortCuts' => $values]);
6a488035
TO
425 }
426
a0ee3941 427 /**
3fd42bb5 428 * @param array $short
a0ee3941
EM
429 *
430 * @return array
431 */
7926b999 432 private static function setShortcutValues($short) {
affcc9d2 433 $value = [];
7926b999 434 if (isset($short['url'])) {
435 $value['url'] = $short['url'];
436 }
437 elseif (isset($short['path'])) {
438 $value['url'] = CRM_Utils_System::url($short['path'], $short['query'], FALSE);
439 }
440 $value['title'] = $short['title'];
2e1f50d6 441 $value['ref'] = $short['ref'] ?? '';
ceccc741 442 $value['shortCuts'] = [];
7926b999 443 if (!empty($short['shortCuts'])) {
444 foreach ($short['shortCuts'] as $shortCut) {
445 $value['shortCuts'][] = self::setShortcutValues($shortCut);
446 }
447 }
448 return $value;
449 }
450
6a488035 451 /**
fe482240 452 * Create the list of dashboard links.
6a488035
TO
453 */
454 private static function setTemplateDashboardValues() {
affcc9d2 455 static $dashboardLinks = [];
6a488035
TO
456 if (CRM_Core_Permission::check('access Contact Dashboard')) {
457 $dashboardLinks = array(
2aa397bc 458 array(
353ffa53 459 'path' => 'civicrm/user',
6a488035
TO
460 'query' => 'reset=1',
461 'title' => ts('My Contact Dashboard'),
3bdca100 462 ),
353ffa53 463 );
6a488035
TO
464 }
465
affcc9d2 466 $values = [];
6a488035 467 foreach ($dashboardLinks as $dash) {
affcc9d2 468 $value = [];
6a488035
TO
469 if (isset($dash['url'])) {
470 $value['url'] = $dash['url'];
471 }
472 else {
473 $value['url'] = CRM_Utils_System::url($dash['path'], $dash['query'], FALSE);
474 }
475 $value['title'] = $dash['title'];
9c1bc317 476 $value['key'] = $dash['key'] ?? NULL;
353ffa53 477 $values[] = $value;
6a488035
TO
478 }
479 self::setProperty(self::DASHBOARD, 'templateValues', array('dashboardLinks' => $values));
480 }
481
482 /**
fe482240 483 * Create the list of mail urls for the application and format is as a block.
6a488035
TO
484 */
485 private static function setTemplateMailValues() {
486 static $shortCuts = NULL;
487
488 if (!($shortCuts)) {
489 $shortCuts = array(
2aa397bc 490 array(
353ffa53 491 'path' => 'civicrm/mailing/send',
6a488035
TO
492 'query' => 'reset=1',
493 'title' => ts('Send Mailing'),
494 ),
495 array(
496 'path' => 'civicrm/mailing/browse',
497 'query' => 'reset=1',
498 'title' => ts('Browse Sent Mailings'),
499 ),
500 );
501 }
502
affcc9d2 503 $values = [];
6a488035 504 foreach ($shortCuts as $short) {
affcc9d2 505 $value = [];
353ffa53 506 $value['url'] = CRM_Utils_System::url($short['path'], $short['query']);
6a488035 507 $value['title'] = $short['title'];
353ffa53 508 $values[] = $value;
6a488035
TO
509 }
510 self::setProperty(self::MAIL, 'templateValues', array('shortCuts' => $values));
511 }
512
6a488035 513 /**
fe482240 514 * Create the event blocks for upcoming events.
6a488035
TO
515 */
516 private static function setTemplateEventValues() {
517 $config = CRM_Core_Config::singleton();
518
519 $info = CRM_Event_BAO_Event::getCompleteInfo(date("Ymd"));
520
521 if ($info) {
522 $session = CRM_Core_Session::singleton();
523 // check if registration link should be displayed
524 foreach ($info as $id => $event) {
e2d09ab4
EM
525 //@todo FIXME - validRegistraionRequest takes eventID not contactID as a param
526 // this is called via an obscure patch from Joomla event block rendering (only)
6a488035
TO
527 $info[$id]['onlineRegistration'] = CRM_Event_BAO_Event::validRegistrationRequest($event,
528 $session->get('userID')
529 );
530 }
531
532 self::setProperty(self::EVENT, 'templateValues', array('eventBlock' => $info));
533 }
534 }
535
536 /**
537 * Given an id creates a subject/content array
538 *
6a0b768e
TO
539 * @param int $id
540 * Id of the block.
6a488035
TO
541 *
542 * @return array
6a488035 543 */
00be9182 544 public static function getContent($id) {
6a488035
TO
545 // return if upgrade mode
546 $config = CRM_Core_Config::singleton();
547 if ($config->isUpgradeMode()) {
3bdca100 548 return NULL;
6a488035 549 }
faed105b 550 CRM_Core_Smarty::singleton()->ensureVariablesAreAssigned(['langSwitch', 'breadcrumb', 'pageTitle']);
6a488035
TO
551
552 if (!self::getProperty($id, 'active')) {
553 return NULL;
554 }
555
556 if ($id == self::EVENT &&
557 CRM_Core_Permission::check('view event info')
558 ) {
559 // is CiviEvent enabled?
560 if (!CRM_Core_Permission::access('CiviEvent', FALSE)) {
561 return NULL;
562 }
563 // do nothing
564 }
550b2acf 565 // require 'access CiviCRM' permissons, except for the language switch block
2aa397bc 566 elseif (!CRM_Core_Permission::check('access CiviCRM') && $id != self::LANGSWITCH) {
6a488035
TO
567 return NULL;
568 }
569 elseif ($id == self::ADD) {
570 $hasAccess = TRUE;
571 if (!CRM_Core_Permission::check('add contacts') &&
572 !CRM_Core_Permission::check('edit groups')
573 ) {
574 $hasAccess = FALSE;
575 }
576 //validate across edit/view - CRM-5666
577 if ($hasAccess) {
578 $hasAccess = CRM_Core_Permission::giveMeAllACLs();
579 }
580 if (!$hasAccess) {
581 return NULL;
582 }
583 }
584
585 self::setTemplateValues($id);
586
587 // Suppress Recent Items block if it's empty - CRM-5188
588 if ($id == self::RECENTLY_VIEWED) {
589 $recent = self::getProperty($id, 'templateValues');
590 if (CRM_Utils_Array::crmIsEmptyArray($recent)) {
591 return NULL;
592 }
593 }
594
595 // Suppress Language switcher if language is inherited from CMS - CRM-9971
596 $config = CRM_Core_Config::singleton();
0acb7f15 597 if ($id == self::LANGSWITCH && $config->inheritLocale) {
6a488035
TO
598 return NULL;
599 }
600
affcc9d2 601 $block = [];
353ffa53
TO
602 $block['name'] = 'block-civicrm';
603 $block['id'] = $block['name'] . '_' . $id;
6a488035
TO
604 $block['subject'] = self::fetch($id, 'Subject.tpl',
605 array('subject' => self::getProperty($id, 'subject'))
606 );
607 $block['content'] = self::fetch($id, self::getProperty($id, 'template'),
608 self::getProperty($id, 'templateValues')
609 );
610
6a488035
TO
611 return $block;
612 }
613
614 /**
615 * Given an id and a template, fetch the contents
616 *
6a0b768e
TO
617 * @param int $id
618 * Id of the block.
619 * @param string $fileName
620 * Name of the template file.
621 * @param array $properties
622 * Template variables.
6a488035
TO
623 *
624 * @return array
6a488035 625 */
00be9182 626 public static function fetch($id, $fileName, $properties) {
6a488035
TO
627 $template = CRM_Core_Smarty::singleton();
628
629 if ($properties) {
630 $template->assign($properties);
631 }
632
633 return $template->fetch('CRM/Block/' . $fileName);
634 }
96025800 635
6a488035 636}