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