_t('editor UI screen'), 'NAME_PLURAL' => _t('editor UI screens'), 'FIELDS' => array( 'screen_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 user interface screen') ), 'parent_id' => array( 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => true, 'DEFAULT' => '', 'LABEL' => 'Parent id', 'DESCRIPTION' => 'Parent id' ), 'ui_id' => array( 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => 'Ui id', 'DESCRIPTION' => 'Identifier for Ui' ), 'idno' => array( 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD, 'DISPLAY_WIDTH' => 70, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => _t('Screen identifier'), 'DESCRIPTION' => _t('Unique alphanumeric identifier for this screen'), 'BOUNDS_LENGTH' => array(0,255), 'UNIQUE_WITHIN' => array('ui_id') ), 'rank' => array( 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => _t('Sort order'), 'DESCRIPTION' => _t('Sort order'), 'BOUNDS_VALUE' => array(0,65535) ), 'is_default' => array( 'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_SELECT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => _t('Is default screen?'), 'DESCRIPTION' => _t('Indicates if this screen should be used as the default screen when creating a new item.') ), 'color' => array( 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_COLORPICKER, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => _t('Color'), 'DESCRIPTION' => _t('Color to identify the screen with') ), 'icon' => array( 'FIELD_TYPE' => FT_MEDIA, 'DISPLAY_TYPE' => DT_FIELD, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', "MEDIA_PROCESSING_SETTING" => 'ca_icons', 'LABEL' => _t('Icon'), 'DESCRIPTION' => _t('Optional icon identify the screen with') ), 'hier_left' => array( 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => 'Hierarchical index - left bound', 'DESCRIPTION' => 'Left-side boundary for nested set-style hierarchical indexing; used to accelerate search and retrieval of hierarchical record sets.' ), 'hier_right' => array( 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1, 'IS_NULL' => false, 'DEFAULT' => '', 'LABEL' => 'Hierarchical index - right bound', 'DESCRIPTION' => 'Right-side boundary for nested set-style hierarchical indexing; used to accelerate search and retrieval of hierarchical record sets.' ) ) ); class ca_editor_ui_screens extends BundlableLabelableBaseModelWithAttributes { # --------------------------------- # --- 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_editor_ui_screens'; # what is the primary key of the table? protected $PRIMARY_KEY = 'screen_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('ui_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('screen_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 = 'rank'; # ------------------------------------------------------ # Hierarchical table properties # ------------------------------------------------------ protected $HIERARCHY_TYPE = __CA_HIER_TYPE_MULTI_MONO__; protected $HIERARCHY_LEFT_INDEX_FLD = 'hier_left'; protected $HIERARCHY_RIGHT_INDEX_FLD = 'hier_right'; protected $HIERARCHY_PARENT_ID_FLD = 'parent_id'; protected $HIERARCHY_DEFINITION_TABLE = 'ca_editor_uis'; protected $HIERARCHY_ID_FLD = 'ui_id'; 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( ) ); # ------------------------------------------------------ # Labeling # ------------------------------------------------------ protected $LABEL_TABLE_NAME = 'ca_editor_ui_screen_labels'; # ------------------------------------------------------ # $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; static $s_placement_list_cache; // cache for getPlacements() static $s_table_num_cache; // cache for getTableNum() # ---------------------------------------- public function __construct($pn_id=null) { parent::__construct($pn_id); } # ------------------------------------------------------ protected function initLabelDefinitions() { parent::initLabelDefinitions(); $this->BUNDLES['ca_editor_ui_bundle_placements'] = array('type' => 'special', 'repeating' => false, 'label' => _t('Screen content')); $this->BUNDLES['ca_editor_ui_screen_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, $ps_placement_code, $pa_settings, $pn_rank=null, $pa_options=null) { if (!($vn_screen_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; //} unset(ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id]); $t_placement = new ca_editor_ui_bundle_placements(null, is_array($pa_options['additional_settings']) ? $pa_options['additional_settings'] : null); $t_placement->setMode(ACCESS_WRITE); $t_placement->set('screen_id', $vn_screen_id); $t_placement->set('bundle_name', $ps_bundle_name); $t_placement->set('placement_code', $ps_placement_code); $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; } 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_screen_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_editor_ui_bundle_placements($pn_placement_id); if ($t_placement->getPrimaryKey() && ($t_placement->get('screen_id') == $vn_screen_id)) { $t_placement->setMode(ACCESS_WRITE); $t_placement->delete(true); if ($t_placement->numErrors()) { $this->errors = array_merge($this->errors, $t_placement->errors); return false; } unset(ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id]); return true; } return false; } # ------------------------------------------------------ /** * Returns list of placements for the currently loaded screen. * * @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 * @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_editor_ui_bundle_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'] : $this->getTableNum(); $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_READ_ACCESS__)) { // return array(); //} if (!($vn_screen_id = $this->getPrimaryKey())) { if ($pb_return_all_available_if_empty && $ps_table) { return ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id] = $this->getAvailableBundles($ps_table); } // return array(); } if (!$pb_no_cache && isset(ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id]) && ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id]) { return ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id]; } $o_db = $this->getDb(); $qr_res = $o_db->query(" SELECT placement_id, bundle_name, placement_code, settings FROM ca_editor_ui_bundle_placements WHERE screen_id = ? ORDER BY rank ", (int)$vn_screen_id); $va_available_bundles = ($pb_settings_only) ? array() : $this->getAvailableBundles(); $va_placements = array(); if ($qr_res->numRows() > 0) { $t_placement = new ca_editor_ui_bundle_placements(); while($qr_res->nextRow()) { $vs_bundle_name = $qr_res->get('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')); 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 { $va_tmp = explode('.', $vs_bundle_name); $t_instance = $this->_DATAMODEL->getInstanceByTableName($va_tmp[0], true); $va_placements[$vn_placement_id]['display'] = ($t_instance ? $t_instance->getDisplayLabel($vs_bundle_name) : "???"); } } } else { if ($pb_return_all_available_if_empty) { $va_placements = $this->getAvailableBundles($this->getTableNum()); } } ca_editor_ui_screens::$s_placement_list_cache[$vn_screen_id] = $va_placements; return $va_placements; } # ------------------------------------------------------ # 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. * @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->getTableNum(); } if (!is_numeric($pm_table_name_or_num)) { $pm_table_name_or_num = $this->_DATAMODEL->getTableNum($pm_table_name_or_num); } if (!($t_instance = $this->_DATAMODEL->getInstanceByTableNum($pm_table_name_or_num, false))) { return null; } $vs_table = $t_instance->tableName(); $vs_table_display_name = $t_instance->getProperty('NAME_PLURAL'); $t_placement = new ca_editor_ui_bundle_placements(null, array()); $va_defined_bundles = $t_instance->getBundleList(array('includeBundleInfo' => true)); // these are the bundles defined for this type of editor $va_available_bundles = array(); foreach($va_defined_bundles as $vs_bundle => $va_info) { $vs_bundle_proc = preg_replace('!^ca_attribute_!', '', $vs_bundle); switch ($va_info['type']) { case 'intrinsic': $va_field_info = $t_instance->getFieldInfo($vs_bundle); //if (isset($va_field_info['IDENTITY']) && $va_field_info['IDENTITY']) { continue(2); } if (isset($va_field_info['DONT_ALLOW_IN_UI']) && $va_field_info['DONT_ALLOW_IN_UI']) { continue(2); } break; case 'related_table': if (!($t_rel = $this->_DATAMODEL->getInstanceByTableName($vs_bundle, true))) { continue; } $va_path = array_keys($this->_DATAMODEL->getPath($t_instance->tableName(), $vs_bundle)); $va_additional_settings = array( 'restrict_to_relationship_types' => array( 'formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'useRelationshipTypeList' => $va_path[1], 'width' => "275px", 'height' => "75px", 'takesLocale' => false, 'default' => '', 'label' => _t('Restrict to relationship types'), 'description' => _t('Restricts display to items related using the specified relationship type(s). Leave all unselected for no restriction.') ), 'restrict_to_types' => array( 'formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'useList' => $t_rel->getTypeListCode(), 'width' => "275px", 'height' => "75px", 'takesLocale' => false, 'default' => '', 'label' => _t('Restrict to types'), 'description' => _t('Restricts display to items of the specified type(s). Leave all unselected for no restriction.') ), 'dont_include_subtypes_in_type_restriction' => array( 'formatType' => FT_TEXT, 'displayType' => DT_CHECKBOXES, 'width' => "10", 'height' => "1", 'takesLocale' => false, 'default' => '0', 'label' => _t('Do not include sub-types in type restriction'), 'description' => _t('Normally restricting to type(s) automatically includes all sub-(child) types. If this option is checked then the lookup results will include items with the selected type(s) only.') ) ); if ($vs_bundle == 'ca_list_items') { $va_additional_settings['restrict_to_lists'] = array( 'formatType' => FT_TEXT, 'displayType' => DT_SELECT, 'showVocabularies' => true, 'width' => "275px", 'height' => "125px", 'takesLocale' => false, 'default' => '', 'label' => _t('Restrict to list'), 'description' => _t('Restricts display to items from the specified list(s). Leave all unselected for no restriction.') ); } if (in_array($vs_bundle, array('ca_places', 'ca_list_items', 'ca_storage_locations'))) { $va_additional_settings['useHierarchicalBrowser'] = array( 'formatType' => FT_TEXT, 'displayType' => DT_CHECKBOXES, 'width' => "10", 'height' => "1", 'takesLocale' => false, 'default' => '1', 'label' => _t('Use hierarchy browser?'), 'description' => _t('If checked a hierarchical browser will be used to select related items instead of an auto-complete lookup.') ); $va_additional_settings['hierarchicalBrowserHeight'] = array( 'formatType' => FT_TEXT, 'displayType' => DT_FIELD, 'width' => "10", 'height' => "1", 'takesLocale' => false, 'default' => '200px', 'label' => _t('Height of hierarchical browser'), 'description' => _t('Height of hierarchical browser.') ); } if (!$t_rel->hasField('type_id')) { unset($va_additional_settings['restrict_to_types']); } if (sizeof($va_path) == 3) { if ($t_link = $this->_DATAMODEL->getInstanceByTableName($va_path[1], true)) { if (!$t_link->hasField('type_id')) { unset($va_additional_settings['restrict_to_relationship_types']); } } } break; case 'special': if (in_array($vs_bundle, array('hierarchy_location', 'hierarchy_navigation'))) { $va_additional_settings = array( 'open_hierarchy' => array( 'formatType' => FT_NUMBER, 'displayType' => DT_CHECKBOXES, 'width' => "4", 'height' => "1", 'takesLocale' => false, 'default' => '1', 'label' => _t('Open hierarchy browser by default'), 'description' => _t('If checked hierarchy browser will be open when form loads.') ) ); } break; default: $va_additional_settings = array(); break; } $t_placement->setSettingDefinitionsForPlacement($va_additional_settings); $vs_display = "