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