Merge pull request #4809 from totten/master-cs2
[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 */
66 public function __construct() {}
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 one of the class constants (ADD, SEARCH, etc.)
186 * @param string $property the desired property
187 *
188 * @return string the value of the desired property
189 */
190 public static function getProperty($id, $property) {
191 if (!(self::$_properties)) {
192 self::initProperties();
193 }
194 return isset(self::$_properties[$id][$property]) ? self::$_properties[$id][$property] : NULL;
195 }
196
197 /**
198 * Sets the desired property in the $_properties array
199 *
200 * @param int $id one of the class constants (ADD, SEARCH, etc.)
201 * @param string $property the desired property
202 * @param string $value the value of the desired property
203 *
204 * @return void
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 the $_properties array
217 */
218 public static function properties() {
219 if (!(self::$_properties)) {
220 self::initProperties();
221 }
222 return self::$_properties;
223 }
224
225 /**
226 * Creates the info block for drupal
227 *
228 * @return array
229 */
230 public static function getInfo() {
231
232 $block = array();
233 foreach (self::properties() as $id => $value) {
234 if ($value['active']) {
235 if (in_array($id, array(
236 self::ADD, self::CREATE_NEW))) {
237 $hasAccess = TRUE;
238 if (!CRM_Core_Permission::check('add contacts') &&
239 !CRM_Core_Permission::check('edit groups')
240 ) {
241 $hasAccess = FALSE;
242 }
243 //validate across edit/view - CRM-5666
244 if ($hasAccess && ($id == self::ADD)) {
245 $hasAccess = CRM_Core_Permission::giveMeAllACLs();
246 }
247 if (!$hasAccess) {
248 continue;
249 }
250 }
251
252 if ($id == self::EVENT &&
253 (!CRM_Core_Permission::access('CiviEvent', FALSE) ||
254 !CRM_Core_Permission::check('view event info')
255 )
256 ) {
257 continue;
258 }
259
260 $block[$id] = array(
261 'info' => $value['info'],
262 'cache' => $value['cache'],
263 'status' => $value['active'],
264 'region' => $value['region'],
265 'visibility' => $value['visibility'],
266 'pages' => $value['pages'],
267 'status' => $value['status'],
268 'weight' => $value['weight'],
269 );
270 }
271 }
272
273 return $block;
274 }
275
276 /**
277 * Set the post action values for the block.
278 *
279 * php is lame and u cannot call functions from static initializers
280 * hence this hack
281 *
282 * @param int $id
283 *
284 * @return void
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('postURL' => CRM_Utils_System::url('civicrm/contact/add', 'reset=1&ct=Individual'),
300 'primaryLocationType' => $defaultPrimaryLocationId,
301 );
302
303 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
304 $values[$greeting . '_id'] = CRM_Contact_BAO_Contact_Utils::defaultGreeting('Individual', $greeting);
305 }
306
307 self::setProperty(self::ADD,
308 'templateValues',
309 $values
310 );
311 break;
312
313 case self::LANGSWITCH:
314 // gives the currentPath without trailing empty lcMessages to be completed
315 $values = array('queryString' => CRM_Utils_System::getLinksUrl('lcMessages', TRUE, FALSE, FALSE));
316 self::setProperty(self::LANGSWITCH, 'templateValues', $values);
317 break;
318 case self::FULLTEXT_SEARCH:
319 $urlArray = array(
320 'fullTextSearchID' => CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue',
321 'CRM_Contact_Form_Search_Custom_FullText', 'value', 'name'
322 ));
323 self::setProperty(self::FULLTEXT_SEARCH, 'templateValues', $urlArray);
324 break;
325
326 case self::RECENTLY_VIEWED:
327 $recent = CRM_Utils_Recent::get();
328 self::setProperty(self::RECENTLY_VIEWED, 'templateValues', array('recentlyViewed' => $recent));
329 break;
330
331 case self::EVENT:
332 self::setTemplateEventValues();
333 break;
334 }
335 }
336
337 /**
338 * Create the list of options to create New objects for the application and format is as a block
339 *
340 * @return void
341 */
342 private static function setTemplateShortcutValues() {
343 $config = CRM_Core_Config::singleton();
344
345 static $shortCuts = array();
346
347 if (!($shortCuts)) {
348 if (CRM_Core_Permission::check('add contacts')) {
349 if (CRM_Core_Permission::giveMeAllACLs()) {
350 $shortCuts = CRM_Contact_BAO_ContactType::getCreateNewList();
351 }
352 }
353
354 // new activity (select target contact)
355 $shortCuts = array_merge($shortCuts, array(
356 array(
357 'path' => 'civicrm/activity',
358 'query' => 'action=add&reset=1&context=standalone',
359 'ref' => 'new-activity',
360 'title' => ts('Activity'),
361 )));
362
363 $components = CRM_Core_Component::getEnabledComponents();
364
365 if (!empty($config->enableComponents)) {
366 // check if we can process credit card contribs
367 $newCredit = CRM_Core_Config::isEnabledBackOfficeCreditCardPayments();
368
369 foreach ($components as $componentName => $obj) {
370 if (in_array($componentName, $config->enableComponents)) {
371 $obj->creatNewShortcut($shortCuts, $newCredit);
372 }
373 }
374 }
375
376 // new email (select recipients)
377 $shortCuts = array_merge($shortCuts, array(
378 array('path' => 'civicrm/activity/email/add',
379 'query' => 'atype=3&action=add&reset=1&context=standalone',
380 'ref' => 'new-email',
381 'title' => ts('Email'),
382 )));
383
384 if (CRM_Core_Permission::check('edit groups')) {
385 $shortCuts = array_merge($shortCuts, array(
386 array('path' => 'civicrm/group/add',
387 'query' => 'reset=1',
388 'ref' => 'new-group',
389 'title' => ts('Group'),
390 )));
391 }
392
393 if (CRM_Core_Permission::check('administer CiviCRM')) {
394 $shortCuts = array_merge($shortCuts, array(
395 array('path' => 'civicrm/admin/tag',
396 'query' => 'reset=1&action=add',
397 'ref' => 'new-tag',
398 'title' => ts('Tag'),
399 )));
400 }
401
402 if (empty($shortCuts)) {
403 return NULL;
404 }
405 }
406
407 $values = array();
408 foreach ($shortCuts as $key => $short) {
409 $values[$key] = self::setShortCutValues($short);
410 }
411
412 // call links hook to add user defined links
413 CRM_Utils_Hook::links('create.new.shorcuts',
414 NULL,
415 CRM_Core_DAO::$_nullObject,
416 $values,
417 CRM_Core_DAO::$_nullObject,
418 CRM_Core_DAO::$_nullObject
419 );
420
421 foreach ($values as $key => $val) {
422 if (!empty($val['title'])) {
423 $values[$key]['name'] = CRM_Utils_Array::value('name', $val, $val['title']);
424 }
425 }
426
427 self::setProperty(self::CREATE_NEW, 'templateValues', array('shortCuts' => $values));
428 }
429
430 /**
431 * @param $short
432 *
433 * @return array
434 */
435 private static function setShortcutValues($short) {
436 $value = array();
437 if (isset($short['url'])) {
438 $value['url'] = $short['url'];
439 }
440 elseif (isset($short['path'])) {
441 $value['url'] = CRM_Utils_System::url($short['path'], $short['query'], FALSE);
442 }
443 $value['title'] = $short['title'];
444 $value['ref'] = $short['ref'];
445 if (!empty($short['shortCuts'])) {
446 foreach ($short['shortCuts'] as $shortCut) {
447 $value['shortCuts'][] = self::setShortcutValues($shortCut);
448 }
449 }
450 return $value;
451 }
452
453 /**
454 * Create the list of dashboard links
455 *
456 * @return void
457 */
458 private static function setTemplateDashboardValues() {
459 static $dashboardLinks = array();
460 if (CRM_Core_Permission::check('access Contact Dashboard')) {
461 $dashboardLinks = array(
462 array('path' => 'civicrm/user',
463 'query' => 'reset=1',
464 'title' => ts('My Contact Dashboard'),
465 ));
466 }
467
468 if (empty($dashboardLinks)) {
469 return NULL;
470 }
471
472 $values = array();
473 foreach ($dashboardLinks as $dash) {
474 $value = array();
475 if (isset($dash['url'])) {
476 $value['url'] = $dash['url'];
477 }
478 else {
479 $value['url'] = CRM_Utils_System::url($dash['path'], $dash['query'], FALSE);
480 }
481 $value['title'] = $dash['title'];
482 $value['key'] = CRM_Utils_Array::value('key', $dash);
483 $values[] = $value;
484 }
485 self::setProperty(self::DASHBOARD, 'templateValues', array('dashboardLinks' => $values));
486 }
487
488 /**
489 * Create the list of mail urls for the application and format is as a block
490 *
491 * @return void
492 */
493 private static function setTemplateMailValues() {
494 static $shortCuts = NULL;
495
496 if (!($shortCuts)) {
497 $shortCuts = array(
498 array('path' => 'civicrm/mailing/send',
499 'query' => 'reset=1',
500 'title' => ts('Send Mailing'),
501 ),
502 array(
503 'path' => 'civicrm/mailing/browse',
504 'query' => 'reset=1',
505 'title' => ts('Browse Sent Mailings'),
506 ),
507 );
508 }
509
510 $values = array();
511 foreach ($shortCuts as $short) {
512 $value = array();
513 $value['url'] = CRM_Utils_System::url($short['path'], $short['query']);
514 $value['title'] = $short['title'];
515 $values[] = $value;
516 }
517 self::setProperty(self::MAIL, 'templateValues', array('shortCuts' => $values));
518 }
519
520 /**
521 * Create the list of shortcuts for the application and format is as a block
522 *
523 * @return void
524 */
525 private static function setTemplateMenuValues() {
526 $config = CRM_Core_Config::singleton();
527
528 $path = 'navigation';
529 $values = CRM_Core_Menu::getNavigation();
530 if ($values) {
531 self::setProperty(self::MENU, 'templateValues', array('menu' => $values));
532 }
533 }
534
535 /**
536 * Create the event blocks for upcoming events
537 *
538 * @return void
539 */
540 private static function setTemplateEventValues() {
541 $config = CRM_Core_Config::singleton();
542
543 $info = CRM_Event_BAO_Event::getCompleteInfo(date("Ymd"));
544
545 if ($info) {
546 $session = CRM_Core_Session::singleton();
547 // check if registration link should be displayed
548 foreach ($info as $id => $event) {
549 //@todo FIXME - validRegistraionRequest takes eventID not contactID as a param
550 // this is called via an obscure patch from Joomla event block rendering (only)
551 $info[$id]['onlineRegistration'] = CRM_Event_BAO_Event::validRegistrationRequest($event,
552 $session->get('userID')
553 );
554 }
555
556 self::setProperty(self::EVENT, 'templateValues', array('eventBlock' => $info));
557 }
558 }
559
560 /**
561 * Given an id creates a subject/content array
562 *
563 * @param int $id id of the block
564 *
565 * @return array
566 */
567 public static function getContent($id) {
568 // return if upgrade mode
569 $config = CRM_Core_Config::singleton();
570 if ($config->isUpgradeMode()) {
571 return;
572 }
573
574 if (!self::getProperty($id, 'active')) {
575 return NULL;
576 }
577
578 if ($id == self::EVENT &&
579 CRM_Core_Permission::check('view event info')
580 ) {
581 // is CiviEvent enabled?
582 if (!CRM_Core_Permission::access('CiviEvent', FALSE)) {
583 return NULL;
584 }
585 // do nothing
586 }
587 // require 'access CiviCRM' permissons, except for the language switch block
588 elseif (!CRM_Core_Permission::check('access CiviCRM') && $id!=self::LANGSWITCH) {
589 return NULL;
590 }
591 elseif ($id == self::ADD) {
592 $hasAccess = TRUE;
593 if (!CRM_Core_Permission::check('add contacts') &&
594 !CRM_Core_Permission::check('edit groups')
595 ) {
596 $hasAccess = FALSE;
597 }
598 //validate across edit/view - CRM-5666
599 if ($hasAccess) {
600 $hasAccess = CRM_Core_Permission::giveMeAllACLs();
601 }
602 if (!$hasAccess) {
603 return NULL;
604 }
605 }
606
607 self::setTemplateValues($id);
608
609 // Suppress Recent Items block if it's empty - CRM-5188
610 if ($id == self::RECENTLY_VIEWED) {
611 $recent = self::getProperty($id, 'templateValues');
612 if (CRM_Utils_Array::crmIsEmptyArray($recent)) {
613 return NULL;
614 }
615 }
616
617 // Suppress Language switcher if language is inherited from CMS - CRM-9971
618 $config = CRM_Core_Config::singleton();
619 if ($id == self::LANGSWITCH && property_exists($config, "inheritLocale") && $config->inheritLocale) {
620 return NULL;
621 }
622
623 $block = array();
624 $block['name'] = 'block-civicrm';
625 $block['id'] = $block['name'] . '_' . $id;
626 $block['subject'] = self::fetch($id, 'Subject.tpl',
627 array('subject' => self::getProperty($id, 'subject'))
628 );
629 $block['content'] = self::fetch($id, self::getProperty($id, 'template'),
630 self::getProperty($id, 'templateValues')
631 );
632
633
634 return $block;
635 }
636
637 /**
638 * Given an id and a template, fetch the contents
639 *
640 * @param int $id id of the block
641 * @param string $fileName name of the template file
642 * @param array $properties template variables
643 *
644 * @return array
645 */
646 public static function fetch($id, $fileName, $properties) {
647 $template = CRM_Core_Smarty::singleton();
648
649 if ($properties) {
650 $template->assign($properties);
651 }
652
653 return $template->fetch('CRM/Block/' . $fileName);
654 }
655 }