-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathca_bundle_displays.php
3025 lines (2699 loc) · 131 KB
/
ca_bundle_displays.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/** ---------------------------------------------------------------------
* app/models/ca_bundle_displays.php
* ----------------------------------------------------------------------
* CollectiveAccess
* Open-source collections management software
* ----------------------------------------------------------------------
*
* Software by Whirl-i-Gig (http://www.whirl-i-gig.com)
* Copyright 2010-2018 Whirl-i-Gig
*
* For more information visit http://www.CollectiveAccess.org
*
* This program is free software; you may redistribute it and/or modify it under
* the terms of the provided license as published by Whirl-i-Gig
*
* CollectiveAccess is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* This source code is free and modifiable under the terms of
* GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
* the "license.txt" file for details, or visit the CollectiveAccess web site at
* http://www.CollectiveAccess.org
*
* @package CollectiveAccess
* @subpackage models
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License version 3
*
* ----------------------------------------------------------------------
*/
/**
*
*/
require_once(__CA_LIB_DIR__.'/ModelSettings.php');
require_once(__CA_LIB_DIR__.'/BundlableLabelableBaseModelWithAttributes.php');
require_once(__CA_LIB_DIR__.'/SetUniqueIdnoTrait.php');
require_once(__CA_MODELS_DIR__.'/ca_bundle_displays.php');
require_once(__CA_MODELS_DIR__.'/ca_bundle_display_placements.php');
require_once(__CA_MODELS_DIR__.'/ca_bundle_displays_x_user_groups.php');
require_once(__CA_MODELS_DIR__.'/ca_bundle_display_type_restrictions.php');
require_once(__CA_MODELS_DIR__.'/ca_metadata_elements.php');
require_once(__CA_MODELS_DIR__.'/ca_lists.php');
define('__CA_BUNDLE_DISPLAY_NO_ACCESS__', 0);
define('__CA_BUNDLE_DISPLAY_READ_ACCESS__', 1);
define('__CA_BUNDLE_DISPLAY_EDIT_ACCESS__', 2);
BaseModel::$s_ca_models_definitions['ca_bundle_displays'] = array(
'NAME_SINGULAR' => _t('display list'),
'NAME_PLURAL' => _t('display lists'),
'FIELDS' => array(
'display_id' => array(
'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN,
'IDENTITY' => true, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => false,
'DEFAULT' => '',
'LABEL' => _t('CollectiveAccess id'), 'DESCRIPTION' => _t('Unique numeric identifier used by CollectiveAccess internally to identify this display')
),
'user_id' => array(
'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT,
'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => true,
'DEFAULT' => '',
'DONT_ALLOW_IN_UI' => true,
'LABEL' => 'User id', 'DESCRIPTION' => 'Identifier for User'
),
'is_system' => array(
'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_SELECT,
'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => false,
'DEFAULT' => '',
'LABEL' => _t('Is system display?'), 'DESCRIPTION' => _t('If set, display will be available to all users as part of the system-wide display list.'),
'REQUIRES' => array('is_administrator')
),
'table_num' => array(
'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN,
'DONT_USE_AS_BUNDLE' => true,
'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => false,
'DEFAULT' => '',
'LABEL' => _t('Display type'), 'DESCRIPTION' => _t('Indicates type of item display is used for.'),
'BOUNDS_CHOICE_LIST' => array(
_t('objects') => 57,
_t('object lots') => 51,
_t('entities') => 20,
_t('places') => 72,
_t('occurrences') => 67,
_t('collections') => 13,
_t('storage locations') => 89,
_t('loans') => 133,
_t('movements') => 137,
_t('tours') => 153,
_t('tour stops') => 155,
_t('object representations') => 56,
_t('representation annotations') => 82,
//_t('lists') => 36,
_t('list items') => 33
)
),
'display_code' => array(
'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => true,
'DEFAULT' => '',
'LABEL' => _t('Display code'), 'DESCRIPTION' => _t('Unique alphanumeric identifier for this display.'),
'UNIQUE_WITHIN' => []
//'REQUIRES' => array('is_administrator')
),
'settings' => array(
'FIELD_TYPE' => FT_VARS, 'DISPLAY_TYPE' => DT_OMIT,
'DISPLAY_WIDTH' => 88, 'DISPLAY_HEIGHT' => 15,
'IS_NULL' => false,
'DEFAULT' => '',
'LABEL' => _t('Settings'), 'DESCRIPTION' => _t('Display settings')
),
'access' => array(
'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT,
'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
'IS_NULL' => false,
'DEFAULT' => 0,
'ALLOW_BUNDLE_ACCESS_CHECK' => true,
'BOUNDS_CHOICE_LIST' => array(
_t('Not accessible to public') => 0,
_t('Accessible to public') => 1
),
'LIST' => 'access_statuses',
'LABEL' => _t('Access'), 'DESCRIPTION' => _t('Indicates if display is accessible to the public or not.')
)
)
);
global $_ca_bundle_displays_settings;
$_ca_bundle_displays_settings = array( // global
'show_empty_values' => array(
'formatType' => FT_NUMBER,
'displayType' => DT_CHECKBOXES,
'width' => 4, 'height' => 1,
'takesLocale' => false,
'default' => '1',
'label' => _t('Display empty values?'),
'description' => _t('If checked all values will be displayed, whether there is content for them or not.')
),
'bottom_line' => array(
'formatType' => FT_TEXT,
'displayType' => DT_FIELD,
'width' => 100, 'height' => 4,
'takesLocale' => false,
'default' => '',
'label' => _t('Bottom line format'),
'description' => _t('Format per-page and per-report summary information.')
),
'show_only_in' => array(
'formatType' => FT_TEXT,
'displayType' => DT_SELECT,
'multiple' => 1,
'width' => 100, 'height' => 4,
'takesLocale' => false,
'options' => [
_t('Search/browse (thumbnail view)') => 'search_browse_thumbnail',
_t('Search/browse (full view)') => 'search_browse_full',
_t('Search/browse (list view)') => 'search_browse_list',
_t('Editor summaries') => 'editor_summary',
_t('Editor relationship bundles') => 'editor_relationship_bundle',
_t('Set items bundles') => 'set_item_bundle'
],
'default' => '',
'label' => _t('Show display in'),
'description' => _t('Restrict display to use in specific contexts. If no contexts are selected the display will be shown in all contexts.')
)
);
class ca_bundle_displays extends BundlableLabelableBaseModelWithAttributes {
use SetUniqueIdnoTrait;
# ---------------------------------
# --- Object attribute properties
# ---------------------------------
# Describe structure of content object's properties - eg. database fields and their
# associated types, what modes are supported, et al.
#
# ------------------------------------------------------
# --- Basic object parameters
# ------------------------------------------------------
# what table does this class represent?
protected $TABLE = 'ca_bundle_displays';
# what is the primary key of the table?
protected $PRIMARY_KEY = 'display_id';
# ------------------------------------------------------
# --- Properties used by standard editing scripts
#
# These class properties allow generic scripts to properly display
# records from the table represented by this class
#
# ------------------------------------------------------
# Array of fields to display in a listing of records from this table
protected $LIST_FIELDS = array('display_id');
# When the list of "list fields" above contains more than one field,
# the LIST_DELIMITER text is displayed between fields as a delimiter.
# This is typically a comma or space, but can be any string you like
protected $LIST_DELIMITER = ' ';
# What you'd call a single record from this table (eg. a "person")
protected $NAME_SINGULAR;
# What you'd call more than one record from this table (eg. "people")
protected $NAME_PLURAL;
# List of fields to sort listing of records by; you can use
# SQL 'ASC' and 'DESC' here if you like.
protected $ORDER_BY = array('display_id');
# If you want to order records arbitrarily, add a numeric field to the table and place
# its name here. The generic list scripts can then use it to order table records.
protected $RANK = '';
# ------------------------------------------------------
# Hierarchical table properties
# ------------------------------------------------------
protected $HIERARCHY_TYPE = null;
protected $HIERARCHY_LEFT_INDEX_FLD = null;
protected $HIERARCHY_RIGHT_INDEX_FLD = null;
protected $HIERARCHY_PARENT_ID_FLD = null;
protected $HIERARCHY_DEFINITION_TABLE = null;
protected $HIERARCHY_ID_FLD = null;
protected $HIERARCHY_POLY_TABLE = null;
# ------------------------------------------------------
# Change logging
# ------------------------------------------------------
protected $UNIT_ID_FIELD = null;
protected $LOG_CHANGES_TO_SELF = true;
protected $LOG_CHANGES_USING_AS_SUBJECT = array(
"FOREIGN_KEYS" => array(
),
"RELATED_TABLES" => array(
)
);
# ------------------------------------------------------
# Group-based access control
# ------------------------------------------------------
protected $USERS_RELATIONSHIP_TABLE = 'ca_bundle_displays_x_users';
protected $USER_GROUPS_RELATIONSHIP_TABLE = 'ca_bundle_displays_x_user_groups';
# ------------------------------------------------------
# Labeling
# ------------------------------------------------------
protected $LABEL_TABLE_NAME = 'ca_bundle_display_labels';
# ------------------------------------------------------
# ID numbering
# ------------------------------------------------------
protected $ID_NUMBERING_ID_FIELD = 'display_code'; // name of field containing user-defined identifier
protected $ID_NUMBERING_SORT_FIELD = null; // name of field containing version of identifier for sorting (is normalized with padding to sort numbers properly)
protected $ID_NUMBERING_CONTEXT_FIELD = null; // name of field to use value of for "context" when checking for duplicate identifier values; if not set identifer is assumed to be global in scope; if set identifer is checked for uniqueness (if required) within the value of this field
# ------------------------------------------------------
# $FIELDS contains information about each field in the table. The order in which the fields
# are listed here is the order in which they will be returned using getFields()
protected $FIELDS;
# cache for haveAccessToDisplay()
static $s_have_access_to_display_cache = [];
/**
* Settings delegate - implements methods for setting, getting and using 'settings' var field
*/
public $SETTINGS;
static $s_placement_list_cache; // cache for getPlacements()
# ------------------------------------------------------
public function __construct($pn_id=null) {
// Filter list of tables display can be used for to those enabled in current config
BaseModel::$s_ca_models_definitions['ca_bundle_displays']['FIELDS']['table_num']['BOUNDS_CHOICE_LIST'] = caFilterTableList(BaseModel::$s_ca_models_definitions['ca_bundle_displays']['FIELDS']['table_num']['BOUNDS_CHOICE_LIST']);
global $_ca_bundle_displays_settings;
parent::__construct($pn_id);
//
$this->SETTINGS = new ModelSettings($this, 'settings', $_ca_bundle_displays_settings);
}
# ------------------------------------------------------
/**
* @param array $pa_options
* duplicate_subitems
*/
public function duplicate($pa_options=null) {
$vb_we_set_transaction = false;
if (!$this->inTransaction()) {
$this->setTransaction($o_t = new Transaction($this->getDb()));
$vb_we_set_transaction = true;
} else {
$o_t = $this->getTransaction();
}
if ($t_dupe = parent::duplicate($pa_options)) {
$vb_duplicate_subitems = caGetOption('duplicate_subitems', $pa_options, false);
if ($vb_duplicate_subitems) {
// Try to dupe related ca_bundle_display_placements rows
$o_db = $this->getDb();
$qr_res = $o_db->query("
SELECT *
FROM ca_bundle_display_placements
WHERE display_id = ?
", (int)$this->getPrimaryKey());
$va_items = [];
while($qr_res->nextRow()) {
$va_row = $qr_res->getRow();
$va_row['settings'] = caUnserializeForDatabase($va_row['settings']);
$va_items[$qr_res->get('placement_id')] = $va_row;
}
foreach($va_items as $vn_item_id => $va_item) {
$t_item = new ca_bundle_display_placements();
if ($this->inTransaction()) { $t_item->setTransaction($this->getTransaction()); }
$t_item->setMode(ACCESS_WRITE);
$va_item['display_id'] = $t_dupe->getPrimaryKey();
$t_item->set($va_item);
$t_item->insert();
if ($t_item->numErrors()) {
$this->errors = $t_item->errors;
if ($vb_we_set_transaction) { $this->removeTransaction(false);}
return false;
}
}
}
}
if ($vb_we_set_transaction) { $this->removeTransaction(true);}
return $t_dupe;
}
# ------------------------------------------------------
/**
* Override set() to reject changes to user_id for existing rows
*/
public function set($pa_fields, $pm_value="", $pa_options=null) {
if ($this->getPrimaryKey()) {
if (is_array($pa_fields)) {
if (isset($pa_fields['user_id'])) { unset($pa_fields['user_id']); }
if (isset($pa_fields['table_num'])) { unset($pa_fields['table_num']); }
} else {
if ($pa_fields === 'user_id') { return false; }
if ($pa_fields === 'table_num') { return false; }
}
}
return parent::set($pa_fields, $pm_value, $pa_options);
}
# ------------------------------------------------------
public function __destruct() {
unset($this->SETTINGS);
}
# ------------------------------------------------------
protected function initLabelDefinitions($pa_options=null) {
parent::initLabelDefinitions($pa_options);
$this->BUNDLES['ca_users'] = array('type' => 'special', 'repeating' => true, 'label' => _t('User access'));
$this->BUNDLES['ca_user_groups'] = array('type' => 'special', 'repeating' => true, 'label' => _t('Group access'));
$this->BUNDLES['ca_bundle_display_placements'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Display list contents'));
$this->BUNDLES['settings'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Display settings'));
$this->BUNDLES['ca_bundle_display_type_restrictions'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Type restrictions'));
}
# ------------------------------------------------------
# Display settings
# ------------------------------------------------------
/**
* Add bundle placement to currently loaded display
*
* @param string $ps_bundle_name Name of bundle to add (eg. ca_objects.idno, ca_objects.preferred_labels.name)
* @param array $pa_settings Placement settings array; keys should be valid setting names
* @param int $pn_rank Optional value that determines sort order of bundles in the display. If omitted, placement is added to the end of the display.
* @param array $pa_options Optional array of options. Supports the following options:
* user_id = if specified then add will fail if specified user does not have edit access for the display
* @return int Returns placement_id of newly created placement on success, false on error
*/
public function addPlacement($ps_bundle_name, $pa_settings, $pn_rank=null, $pa_options=null) {
if (!($vn_display_id = $this->getPrimaryKey())) { return null; }
unset(ca_bundle_displays::$s_placement_list_cache[$vn_display_id]);
$pn_user_id = isset($pa_options['user_id']) ? $pa_options['user_id'] : null;
if ($pn_user_id && !$this->haveAccessToDisplay($pn_user_id, __CA_BUNDLE_DISPLAY_EDIT_ACCESS__)) {
return null;
}
$t_placement = new ca_bundle_display_placements(null, is_array($pa_options['additional_settings']) ? $pa_options['additional_settings'] : null);
$t_placement->setMode(ACCESS_WRITE);
if ($this->inTransaction()) { $t_placement->setTransaction($this->getTransaction()); }
$t_placement->set('display_id', $vn_display_id);
$t_placement->set('bundle_name', trim($ps_bundle_name));
$t_placement->set('rank', $pn_rank);
if (is_array($pa_settings)) {
foreach($pa_settings as $vs_key => $vs_value) {
$t_placement->setSetting($vs_key, $vs_value);
}
}
$t_placement->insert();
if ($t_placement->numErrors()) {
$this->errors = array_merge($this->errors, $t_placement->errors);
return false;
}
// flush sort cache as modifying display will change values
CompositeCache::flush('sorts');
return $t_placement->getPrimaryKey();
}
# ------------------------------------------------------
/**
* Removes bundle placement from display
*
* @param int $pn_placement_id Placement_id of placement to remove
* @param array $pa_options Optional array of options. Supports the following options:
* user_id = if specified then remove will fail if specified user does not have edit access for the display
* @return bool Returns true on success, false on error
*/
public function removePlacement($pn_placement_id, $pa_options=null) {
if (!($vn_display_id = $this->getPrimaryKey())) { return null; }
$pn_user_id = isset($pa_options['user_id']) ? $pa_options['user_id'] : null;
if ($pn_user_id && !$this->haveAccessToDisplay($pn_user_id, __CA_BUNDLE_DISPLAY_EDIT_ACCESS__)) {
return null;
}
$t_placement = new ca_bundle_display_placements($pn_placement_id);
if ($t_placement->getPrimaryKey() && ($t_placement->get('display_id') == $vn_display_id)) {
$t_placement->setMode(ACCESS_WRITE);
if ($this->inTransaction()) { $t_placement->setTransaction($this->getTransaction()); }
$t_placement->delete(true);
if ($t_placement->numErrors()) {
$this->errors = array_merge($this->errors, $t_placement->errors);
return false;
}
unset(ca_bundle_displays::$s_placement_list_cache[$vn_display_id]);
// flush sort cache as modifying display will change values
CompositeCache::flush('sorts');
return true;
}
return false;
}
# ------------------------------------------------------
/**
* Returns list of placements for the currently loaded display.
*
* @param array $pa_options Optional array of options. Supports the following options:
* noCache = if set to true then the returned list if always generated directly from the database, otherwise it is returned from the cache if possible. Set this to true if you expect the cache may be stale. Default is false.
* returnAllAvailableIfEmpty = if set to true then the list of all available bundles will be returned if the currently loaded display has no placements, or if there is no display loaded
* table = if using the returnAllAvailableIfEmpty option and you expect a list of available bundles to be returned if no display is loaded, you must specify the table the bundles are intended for use with with this option. Either the table name or number may be used.
* user_id = if specified then placements are only returned if the user has at least read access to the display
* settingsOnly = if true the settings forms are omitted and only setting values are returned. [Default is false]
* omitEditingInfo = don't include data required for inline in-spreadsheet editing. [Default is false]
* @return array List of placements in display order. Array is keyed on bundle name. Values are arrays with the following keys:
* placement_id = primary key of ca_bundle_display_placements row - a unique id for the placement
* bundle_name = bundle name (a code - not for display)
* settings = array of placement settings. Keys are setting names.
* display = display string for bundle
*/
public function getPlacements($pa_options=null) {
$pb_no_cache = (isset($pa_options['noCache'])) ? (bool)$pa_options['noCache'] : false;
$pb_settings_only = (isset($pa_options['settingsOnly'])) ? (bool)$pa_options['settingsOnly'] : false;
$pb_return_all_available_if_empty = (isset($pa_options['returnAllAvailableIfEmpty']) && !$pb_settings_only) ? (bool)$pa_options['returnAllAvailableIfEmpty'] : false;
$ps_table = (isset($pa_options['table'])) ? $pa_options['table'] : null;
$pn_user_id = isset($pa_options['user_id']) ? $pa_options['user_id'] : null;
$pb_omit_editing_info = caGetOption('omitEditingInfo', $pa_options, false);
$ps_hierarchical_delimiter = caGetOption('hierarchicalDelimiter', $pa_options, null);
if ($pn_user_id && !$this->haveAccessToDisplay($pn_user_id, __CA_BUNDLE_DISPLAY_READ_ACCESS__)) {
return [];
}
if (!($vn_display_id = $this->getPrimaryKey())) {
if ($pb_return_all_available_if_empty && $ps_table) {
return ca_bundle_displays::$s_placement_list_cache[$vn_display_id] = $this->getAvailableBundles($ps_table);
}
return [];
}
$vs_cache_key = $vn_display_id.'/'.($pb_settings_only ? 1 : 0);
if (!$pb_no_cache && isset(ca_bundle_displays::$s_placement_list_cache[$vs_cache_key]) && ca_bundle_displays::$s_placement_list_cache[$vs_cache_key]) {
return ca_bundle_displays::$s_placement_list_cache[$vs_cache_key];
}
$o_db = $this->getDb();
$t_list = new ca_lists();
if ($this->inTransaction()) { $t_list->setTransaction($this->getTransaction()); }
$qr_res = $o_db->query("
SELECT placement_id, bundle_name, settings
FROM ca_bundle_display_placements
WHERE
display_id = ?
ORDER BY `rank`
", (int)$vn_display_id);
$va_available_bundles = ($pb_settings_only) ? [] : $this->getAvailableBundles(null, $pa_options);
$va_placements = [];
if ($qr_res->numRows() > 0) {
$vs_subject_table = Datamodel::getTableName($this->get('table_num'));
$t_subject = Datamodel::getInstanceByTableNum($this->get('table_num'), true);
$t_placement = new ca_bundle_display_placements();
if ($this->inTransaction()) { $t_placement->setTransaction($this->getTransaction()); }
$t_user = new ca_users($pn_user_id);
while($qr_res->nextRow()) {
$vs_bundle_name = $qr_res->get('bundle_name');
$va_bundle_name = explode(".", $vs_bundle_name);
$vb_user_can_edit = $t_subject->isSaveable(caGetOption('request', $pa_options, null), $vs_bundle_name);
$va_placements[$vn_placement_id = (int)$qr_res->get('placement_id')] = $qr_res->getRow();
$va_placements[$vn_placement_id]['settings'] = $va_settings = caUnserializeForDatabase($qr_res->get('settings'));
$va_placements[$vn_placement_id]['allowEditing'] = $vb_user_can_edit;
if (!$pb_settings_only) {
$t_placement->setSettingDefinitionsForPlacement($va_available_bundles[$vs_bundle_name]['settings']);
$va_placements[$vn_placement_id]['display'] = $va_available_bundles[$vs_bundle_name]['display'];
$va_placements[$vn_placement_id]['settingsForm'] = $t_placement->getHTMLSettingForm(array('id' => $vs_bundle_name.'_'.$vn_placement_id, 'settings' => $va_settings));
} else {
$t_instance = Datamodel::getInstanceByTableName($va_bundle_name[0], true);
$va_placements[$vn_placement_id]['display'] = ($t_instance ? $t_instance->getDisplayLabel($vs_bundle_name) : "???");
}
if (!$pb_omit_editing_info) {
if ($va_bundle_name[0] == $vs_subject_table) {
// Only primary fields are inline-editable
// Check if it is one of the types of fields that is inline editable
if ($va_bundle_name[1] === 'preferred_labels') {
//
// Preferred labels are always inline editable
//
$va_placements[$vn_placement_id]['allowInlineEditing'] = $vb_user_can_edit;
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_FIELD;
} elseif(in_array($va_bundle_name[1], ['created', 'modified'])) {
//
// created and modified dates are not editable
//
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['allowEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
} elseif ($t_subject->hasField($va_bundle_name[1])) {
//
// Intrinsics are always editable, except for primary key and type_id
//
if (in_array($va_bundle_name[1], [$t_subject->getTypeFieldName(), $t_subject->primaryKey()])) {
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['allowEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
} elseif ($vs_edit_bundle = $t_subject->getFieldInfo($va_bundle_name[1], 'RESULTS_EDITOR_BUNDLE')) {
$va_placements[$vn_placement_id]['allowEditing'] = $vb_user_can_edit;
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
} else {
if(isset($va_bundle_name[1])){
// Do not allow in-line editing if the intrinsic element is identifier and
// a). is not editable (editable = 0 in multipart_id_numbering.conf)
// b). consists of multiple elements
if($va_bundle_name[1] == $t_subject->getProperty('ID_NUMBERING_ID_FIELD')) {
// check if identifier is editable
$vb_id_editable = $t_subject->opo_idno_plugin_instance->isFormatEditable($vs_subject_table);
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['allowEditing'] = $vb_id_editable && $vb_user_can_edit;
} else {
$va_placements[$vn_placement_id]['allowInlineEditing'] = $vb_user_can_edit;
}
}
switch($t_subject->getFieldInfo($va_bundle_name[1], 'DISPLAY_TYPE')) {
case 'DT_SELECT':
if ($vs_list_code = $t_subject->getFieldInfo($va_bundle_name[1], 'LIST')) {
$vb_use_item_values = true;
} else {
$vs_list_code = $t_subject->getFieldInfo($va_bundle_name[1], 'LIST_CODE');
}
if ($vs_list_code && ($t_list->numItemsInList($vs_list_code) <= 500)) {
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_SELECT;
if (!is_array($va_list_items = $t_list->getItemsForList($vs_list_code))) {
break;
}
$va_list_items = caExtractValuesByUserLocale($va_list_items);
$va_list_item_labels = [];
foreach($va_list_items as $vn_item_id => $va_list_item) {
$va_list_item_labels[$vb_use_item_values ? $va_list_item['item_value'] : $vn_item_id] = $va_list_item['name_plural'];
}
$va_placements[$vn_placement_id]['inlineEditingListValues'] = array_values($va_list_item_labels);
$va_placements[$vn_placement_id]['inlineEditingListValueMap'] = array_flip($va_list_item_labels);
} else {
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_FIELD;
}
break;
default:
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_FIELD;
break;
}
}
} elseif ($t_subject->hasElement($va_bundle_name[1])) {
// Attributes are editable for certain types
$vn_data_type = ca_metadata_elements::getElementDatatype($va_bundle_name[1]);
if (ca_bundle_displays::attributeTypeSupportsInlineEditing($vn_data_type)) {
switch($vn_data_type) {
default:
$va_placements[$vn_placement_id]['allowInlineEditing'] = $vb_user_can_edit;
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_FIELD;
break;
case __CA_ATTRIBUTE_VALUE_LIST__:
if ($t_element = ca_metadata_elements::getInstance($va_bundle_name[1])) {
switch($t_element->getSetting('render')) {
case 'select':
case 'yes_no_checkboxes':
case 'radio_buttons':
case 'checklist':
case 'lookup':
case 'horiz_hierbrowser':
case 'horiz_hierbrowser_with_search':
case 'vert_hierbrowser':
if ($t_list->numItemsInList($t_element->get("list_id")) > 500) {
// don't send very large lists
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
} else {
$va_placements[$vn_placement_id]['allowInlineEditing'] = $vb_user_can_edit;
$va_placements[$vn_placement_id]['inlineEditingType'] = DT_SELECT;
$va_list_values = $t_list->getItemsForList($t_element->get("list_id"), array('labelsOnly' => true));
$qr_list_items = caMakeSearchResult('ca_list_items', array_keys($va_list_values));
$va_list_item_labels = [];
while($qr_list_items->nextHit()) {
$va_list_item_labels[$vb_use_item_values ? $qr_list_items->get('ca_list_items.item_value') : $qr_list_items->get('ca_list_items.item_id')] = $qr_list_items->get('ca_list_items.hierarchy.preferred_labels.name_plural', ['delimiter' => $ps_hierarchical_delimiter]);
}
asort($va_list_item_labels);
$va_placements[$vn_placement_id]['inlineEditingListValues'] = array_values($va_list_item_labels);
$va_placements[$vn_placement_id]['inlineEditingListValueMap'] = array_flip($va_list_item_labels);
}
break;
default: // if it's a render setting we don't know about it's not editable
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
break;
}
}
break;
}
} else {
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
}
} else {
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
}
} else {
// Related bundles are never inline-editable (for now)
$va_placements[$vn_placement_id]['allowInlineEditing'] = false;
$va_placements[$vn_placement_id]['inlineEditingType'] = null;
// representation media bundles aren't editable at all
if (($va_bundle_name[0] == 'ca_object_representations') && ($va_bundle_name[1] == 'media')) {
$va_placements[$vn_placement_id]['allowEditing'] = false;
}
}
}
}
} else {
if ($pb_return_all_available_if_empty) {
$va_placements = $this->getAvailableBundles($this->get('table_num'));
}
}
return ca_bundle_displays::$s_placement_list_cache[$vs_cache_key] = $va_placements;
}
# ------------------------------------------------------
/**
* Returns list of bundle displays subject to options
*
* @param array $pa_options Optional array of options. Supported options are:
* table = If set, list is restricted to displays that pertain to the specified table. You can pass a table name or number. If omitted displays for all tables will be returned.
* user_id = Restricts returned displays to those accessible by the current user. If omitted then all displays, regardless of access are returned.
* restrictToTypes = Restricts returned displays to those bound to the specified type. Default is to not restrict by type.
* access = Restricts returned displays to those with at least the specified access level for the specified user. If user_id is omitted then this option has no effect. If user_id is set and this option is omitted, then displays where the user has at least read access will be returned.
* @return array Array of displays keyed on display_id and then locale_id. Keys for the per-locale value array include: display_id, display_code, user_id, table_num, label_id, name (display name of display), locale_id (locale of display name), bundle_display_content_type (display name of content this display pertains to)
*/
public function getBundleDisplays($pa_options=null) {
if (!is_array($pa_options)) { $pa_options = []; }
$pm_table_name_or_num = caGetOption('table', $pa_options, null);
$pn_user_id = caGetOption('user_id', $pa_options, null);
$pn_user_access = caGetOption('access', $pa_options, null);
$pa_access = caGetOption('checkAccess', $pa_options, null);
$pa_restrict_to_types = caGetOption('restrictToTypes', $pa_options, null, ['castTo' => 'array']);
$pa_restrict_to_types = array_filter($pa_restrict_to_types, function($v) { return ($v == '*') ? false : (bool)$v; });
$pb_system_only = caGetOption('systemOnly', $pa_options, false);
if ($pm_table_name_or_num && !($vn_table_num = Datamodel::getTableNum($pm_table_name_or_num))) { return []; }
$o_db = $this->getDb();
$va_params = [];
$va_wheres = ['((bdl.is_preferred = 1) OR (bdl.is_preferred is null))'];
if ($vn_table_num > 0) {
$va_wheres[] = "(bd.table_num = ".intval($vn_table_num).")";
}
if ($pm_table_name_or_num && is_array($pa_restrict_to_types) && sizeof($pa_restrict_to_types) && is_array($va_ancestors = caGetAncestorsForItemID($pa_restrict_to_types, ['includeSelf' => true])) && sizeof($va_ancestors)) {
$va_wheres[] = "(cbdtr.type_id IS NULL OR cbdtr.type_id IN (?) OR (cbdtr.include_subtypes = 1 AND cbdtr.type_id IN (?)))";
$va_params[] = $pa_restrict_to_types;
$va_params[] = $va_ancestors;
}
if (is_array($pa_access) && (sizeof($pa_access))) {
$pa_access = array_map("intval", $pa_access);
$va_wheres[] = "(bd.access IN (?))";
$va_params[] = $pa_access;
}
$va_access_wheres = [];
if ($pn_user_id) {
$t_user = Datamodel::getInstanceByTableName('ca_users', true);
$t_user->load($pn_user_id);
if ($t_user->getPrimaryKey()) {
$vs_access_sql = ($pn_user_access > 0) ? " AND (access >= ".intval($pn_user_access).")" : "";
if (is_array($va_groups = $t_user->getUserGroups()) && sizeof($va_groups)) {
$vs_sql = "(
(bd.user_id = ".intval($pn_user_id).") OR
(bd.display_id IN (
SELECT display_id
FROM ca_bundle_displays_x_user_groups
WHERE
group_id IN (".join(',', array_keys($va_groups)).") {$vs_access_sql}
)
)
)";
} else {
$vs_sql = "(bd.user_id = {$pn_user_id})";
}
$vs_sql .= " OR (bd.display_id IN (
SELECT display_id
FROM ca_bundle_displays_x_users
WHERE
user_id = {$pn_user_id} {$vs_access_sql}
)
)";
$va_access_wheres[] = "({$vs_sql})";
}
}
if (($pn_user_access == __CA_BUNDLE_DISPLAY_READ_ACCESS__) || $pb_system_only) {
$va_access_wheres[] = "(bd.is_system = 1)";
}
if (sizeof($va_access_wheres)) {
$va_wheres[] = "(".join(" OR ", $va_access_wheres).")";
}
// get displays
$qr_res = $o_db->query($vs_sql = "
SELECT
bd.display_id, bd.display_code, bd.user_id, bd.table_num, bd.settings,
bdl.label_id, bdl.name, bdl.locale_id, u.fname, u.lname, u.email,
l.language, l.country
FROM ca_bundle_displays bd
LEFT JOIN ca_bundle_display_labels AS bdl ON bd.display_id = bdl.display_id
LEFT JOIN ca_locales AS l ON bdl.locale_id = l.locale_id
LEFT JOIN ca_bundle_display_type_restrictions AS cbdtr ON bd.display_id = cbdtr.display_id
INNER JOIN ca_users AS u ON bd.user_id = u.user_id
".(sizeof($va_wheres) ? 'WHERE ' : '')."
".join(' AND ', $va_wheres)."
ORDER BY -cbdtr.display_id DESC, bdl.name ASC
", $va_params);
$va_displays = [];
$va_type_name_cache = [];
while($qr_res->nextRow()) {
$vn_table_num = $qr_res->get('table_num');
if (!isset($va_type_name_cache[$vn_table_num]) || !($vs_display_type = $va_type_name_cache[$vn_table_num])) {
$vs_display_type = $va_type_name_cache[$vn_table_num] = $this->getBundleDisplayTypeName($vn_table_num, array('number' => 'plural'));
}
$va_displays[$qr_res->get('display_id')][$qr_res->get('locale_id')] = array_merge($qr_res->getRow(), array('bundle_display_content_type' => $vs_display_type));
$va_displays[$qr_res->get('display_id')][$qr_res->get('locale_id')]['settings'] = caUnserializeForDatabase($va_displays[$qr_res->get('display_id')][$qr_res->get('locale_id')]['settings']);
}
return $va_displays;
}
# ------------------------------------------------------
/**
* Return available displays as HTML <select> drop-down menu
*
* @param string $ps_select_name Name attribute for <select> form element
* @param array $pa_attributes Optional array of attributes to embed in HTML <select> tag. Keys are attribute names and values are attribute values.
* @param array $pa_options Optional array of options. Supported options include:
* Supports all options supported by caHTMLSelect() and ca_bundle_displays::getBundleDisplays() + the following:
* addDefaultDisplay = if true, the "default" display is included at the head of the list; this is simply a display called "default" that is assumed to be handled by your code; the default is not to add the default value (false)
* addDefaultDisplayIfEmpty = same as 'addDefaultDisplay' except that the default value is only added if the display list is empty
* dontIncludeSubtypesInTypeRestriction = don't automatically include subtypes of a type when calculating type restrictions. [Default is true]
* context = context to filter display list for. [Default is null – no filtering performed]
* @return string HTML code defining <select> drop-down
*/
public function getBundleDisplaysAsHTMLSelect($ps_select_name, $pa_attributes=null, $pa_options=null) {
if (!is_array($pa_options)) { $pa_options = []; }
if (!isset($pa_options['dontIncludeSubtypesInTypeRestriction'])) { $pa_options['dontIncludeSubtypesInTypeRestriction'] = true; }
$va_available_displays = caExtractValuesByUserLocale($this->getBundleDisplays($pa_options));
$va_content = [];
if (
(isset($pa_options['addDefaultDisplay']) && $pa_options['addDefaultDisplay'])
||
(isset($pa_options['addDefaultDisplayIfEmpty']) && ($pa_options['addDefaultDisplayIfEmpty']) && (!sizeof($va_available_displays)))
) {
$va_content[_t('Default')] = 0;
}
$ps_context = caGetOption('context', $pa_options, null);
foreach($va_available_displays as $vn_display_id => $va_info) {
if ($ps_context && is_array($va_info['settings']['show_only_in']) && sizeof($va_info['settings']['show_only_in']) && !in_array($ps_context, $va_info['settings']['show_only_in'])) { continue; }
$va_content[$va_info['name']] = $vn_display_id;
}
if (sizeof($va_content) == 0) { return ''; }
return caHTMLSelect($ps_select_name, $va_content, $pa_attributes, $pa_options);
}
# ------------------------------------------------------
/**
* Returns name of type of content (synonymous with the table name for the content) currently loaded bundle display contains for display. Will return name in singular number unless the 'number' option is set to 'plural'
*
* @param int $pn_table_num Table number to return name for. If omitted then the name for the content type contained by the current bundle display will be returned. Use this parameter if you want to force a content type without having to load a bundle display.
* @param array $pa_options Optional array of options. Supported options are:
* number = Set to 'plural' to return plural version of name; set to 'singular' [default] to return the singular version
* @return string The name of the type of content or null if $pn_table_num is not set to a valid table and no form is loaded.
*/
public function getBundleDisplayTypeName($pm_table_name_or_num=null, $pa_options=null) {
if (!$pm_table_name_or_num && !($pm_table_name_or_num = $this->get('table_num'))) { return null; }
if (!($vn_table_num = Datamodel::getTableNum($pm_table_name_or_num))) { return null; }
$t_instance = Datamodel::getInstanceByTableNum($vn_table_num, true);
if (!$t_instance) { return null; }
return (isset($pa_options['number']) && ($pa_options['number'] == 'plural')) ? $t_instance->getProperty('NAME_PLURAL') : $t_instance->getProperty('NAME_SINGULAR');
}
# ------------------------------------------------------
/**
* Determines if user has access to a display at a specified access level.
*
* @param int $pn_user_id user_id of user to check display access for
* @param int $pn_user_access type of access required. Use __CA_BUNDLE_DISPLAY_READ_ACCESS__ for read-only access or __CA_BUNDLE_DISPLAY_EDIT_ACCESS__ for editing (full) access
* @param int $pn_display_id The id of the display to check. If omitted then currently loaded display will be checked.
* @return bool True if user has access, false if not
*/
public function haveAccessToDisplay($pn_user_id, $pn_user_access, $pn_display_id=null) {
if ($pn_display_id) {
$vn_display_id = $pn_display_id;
$t_disp = new ca_bundle_displays($vn_display_id);
if ($this->inTransaction()) { $t_disp->setTransaction($this->getTransaction()); }
$vn_display_user_id = $t_disp->get('user_id');
} else {
$vn_display_user_id = $this->get('user_id');
$t_disp = $this;
}
if(!$vn_display_id && !($vn_display_id = $t_disp->getPrimaryKey())) {
return true; // new display
}
if (isset(ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access])) {
return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access];
}
if (($vn_display_user_id == $pn_user_id)) { // owners have all access
return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access] = true;
}
if ((bool)$t_disp->get('is_system') && ($pn_user_access == __CA_BUNDLE_DISPLAY_READ_ACCESS__)) { // system displays are readable by all
return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access] = true;
}
$o_db = $this->getDb();
$qr_res = $o_db->query("
SELECT dxg.display_id
FROM ca_bundle_displays_x_user_groups dxg
INNER JOIN ca_user_groups AS ug ON dxg.group_id = ug.group_id
INNER JOIN ca_users_x_groups AS uxg ON uxg.group_id = ug.group_id
WHERE
(dxg.access >= ?) AND (uxg.user_id = ?) AND (dxg.display_id = ?)
", (int)$pn_user_access, (int)$pn_user_id, (int)$vn_display_id);
if ($qr_res->numRows() > 0) { return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access] = true; }
$qr_res = $o_db->query("
SELECT dxu.display_id
FROM ca_bundle_displays_x_users dxu
INNER JOIN ca_users AS u ON dxu.user_id = u.user_id
WHERE
(dxu.access >= ?) AND (u.user_id = ?) AND (dxu.display_id = ?)
", (int)$pn_user_access, (int)$pn_user_id, (int)$vn_display_id);
if ($qr_res->numRows() > 0) { return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access] = true; }
return ca_bundle_displays::$s_have_access_to_display_cache[$vn_display_id.'/'.$pn_user_id.'/'.$pn_user_access] = false;
}
# ------------------------------------------------------
# Settings
# ------------------------------------------------------
/**
* Reroutes calls to method implemented by settings delegate to the delegate class
*/
public function __call($ps_name, $pa_arguments) {
if (method_exists($this->SETTINGS, $ps_name)) {
return call_user_func_array(array($this->SETTINGS, $ps_name), $pa_arguments);
}
die($this->tableName()." does not implement method {$ps_name}");
}
# ------------------------------------------------------
# Bundles
# ------------------------------------------------------
/**
* Returns HTML bundle for adding/editing/deleting placements from a display
*
* @param object $po_request The current request
* @param $ps_form_name The name of the HTML form this bundle will be part of
* @return string HTML for bundle
*/
public function getBundleDisplayHTMLFormBundle($po_request, $ps_form_name, $ps_placement_code, $pa_options=null) {
if (!$this->haveAccessToDisplay($po_request->getUserID(), __CA_BUNDLE_DISPLAY_EDIT_ACCESS__)) {
return null;
}
$o_view = new View($po_request, $po_request->getViewsDirectoryPath().'/bundles/');
$o_view->setVar('lookup_urls', caJSONLookupServiceUrl($po_request, Datamodel::getTableName($this->get('table_num'))));
$o_view->setVar('t_display', $this);
$o_view->setVar('placement_code', $ps_placement_code);
$o_view->setVar('id_prefix', $ps_form_name);
return $o_view->render('ca_bundle_display_placements.php');
}
# ------------------------------------------------------
# Support methods for display setup UI
# ------------------------------------------------------
/**
* Returns all available bundle display placements - those data bundles that can be displayed for the given content type, in other words.
* The returned value is a list of arrays; each array contains a 'bundle' specifier than can be passed got Model::get() or SearchResult::get() and a display name
*
* @param mixed $pm_table_name_or_num The table name or number specifying the content type to fetch bundles for. If omitted the content table of the currently loaded display will be used.
* @param array $pa_options Support options are
* no_cache = if set caching of underlying data required to generate list is disabled. This is required in certain situations such as during installation. Only set this if you suspect stale data is being used to generate the list. Eg. if you've been changing metadata attributes in the same request in which you call this method. Default is false.
* no_tooltips = if set no tooltips for available bundles will be emitted. Default is false - tooltips will be emitted.
* format = specifies label format for bundles. Valid values are "simple" (just the name of the element) or "full" (name of element, name of type of item element pertains to and alternate label, if defined). Default is "full"
* @return array And array of bundles keyed on display label. Each value is an array with these keys:
* bundle = The bundle name (eg. ca_objects.idno)
* display = Display label for each available bundle
* description = Description of bundle
*
* Will return null if table name or number is invalid.
*/
public function getAvailableBundles($pm_table_name_or_num=null, $pa_options=null) {
if (!$pm_table_name_or_num) { $pm_table_name_or_num = $this->get('table_num'); }
$pm_table_name_or_num = Datamodel::getTableNum($pm_table_name_or_num);
if (!$pm_table_name_or_num) { return null; }
$vb_show_tooltips = (isset($pa_options['no_tooltips']) && (bool)$pa_options['no_tooltips']) ? false : true;
$vs_format = (isset($pa_options['format']) && in_array($pa_options['format'], array('simple', 'full'))) ? $pa_options['format'] : 'full';
$t_instance = Datamodel::getInstanceByTableNum($pm_table_name_or_num, false);
$vs_table = $t_instance->tableName();
$vs_table_display_name = $t_instance->getProperty('NAME_PLURAL');