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