/**
  * Saves the content of a form editing new or existing records. It returns the same form + status messages rendered into the current view, inherited from ActionController
  *
  * @param array $pa_options Array of options passed through to _initView and saveBundlesForScreen()
  */
 public function Save($pa_options = null)
 {
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     list($t_subject, $t_ui, $vn_parent_id, $vn_above_id) = $this->_initView(array_merge($pa_options, array('loadSubject' => true)));
     if (!$t_subject) {
         $this->postError(1220, _t('Invalid table %1', $this->ops_table_name), "BaseInterstitalController->Edit()");
         return false;
     }
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     //
     // Is record of correct type?
     //
     $va_restrict_to_types = null;
     if ($t_subject->getAppConfig()->get('perform_type_access_checking')) {
         $va_restrict_to_types = caGetTypeRestrictionsForUser($this->ops_table_name, array('access' => __CA_BUNDLE_ACCESS_EDIT__));
     }
     if (is_array($va_restrict_to_types) && !in_array($t_subject->get('type_id'), $va_restrict_to_types)) {
         $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2560?r=' . urlencode($this->request->getFullUrlPath()));
         return;
     }
     $pn_placement_id = $this->request->getParameter('placement_id', pInteger);
     // placement_id of bundle that launched interstitial editor
     $ps_primary_table = $this->request->getParameter('primary', pString);
     $pn_primary_id = $this->request->getParameter('primary_id', pInteger);
     // Make sure request isn't empty
     if (!sizeof($_POST)) {
         $va_response = array('status' => 20, 'id' => null, 'table' => $t_subject->tableName(), 'type_id' => null, 'display' => null, 'errors' => array(_t("Cannot save using empty request. Are you using a bookmark?") => _t("Cannot save using empty request. Are you using a bookmark?")));
         $this->view->setVar('response', $va_response);
         $this->render('interstitial/interstitial_result_json.php');
         return;
     }
     // Set type name for display
     if (!($vs_type_name = $t_subject->getTypeName())) {
         $vs_type_name = $t_subject->getProperty('NAME_SINGULAR');
     }
     # trigger "BeforeSaveItem" hook
     $this->opo_app_plugin_manager->hookBeforeSaveItem(array('id' => null, 'table_num' => $t_subject->tableNum(), 'table_name' => $t_subject->tableName(), 'instance' => $t_subject, 'is_insert' => true));
     $t_placement = new ca_editor_ui_bundle_placements($pn_placement_id);
     $pa_bundle_settings = $t_placement->getSettings();
     $va_opts = array_merge($pa_options, array('ui_instance' => $t_ui));
     $vb_save_rc = $t_subject->saveBundlesForScreen($this->request->getParameter('screen', pString), $this->request, $va_opts);
     $this->view->setVar('t_ui', $t_ui);
     $vs_message = _t("Saved changes to %1", $vs_type_name);
     //
     // Regenerate display template for bundle that launched the interstitial editor so it will reflect any changes
     //
     $vs_related_table = $t_placement->getEditorType();
     $vs_template = caGetBundleDisplayTemplate($t_subject, $vs_related_table, $pa_bundle_settings);
     $qr_rel_items = caMakeSearchResult($t_subject->tableName(), array($t_subject->getPrimaryKey()));
     //
     // Handle case of self relationships where we need to figure out which direction things are going in
     //
     $va_bundle_values = array_shift(caProcessRelationshipLookupLabel($qr_rel_items, $t_subject, array('template' => $vs_template, 'primaryIDs' => array($ps_primary_table => array($pn_primary_id)))));
     if ($t_subject->hasField('type_id')) {
         if (method_exists($t_subject, "isSelfRelationship") && $t_subject->isSelfRelationship()) {
             $vn_left_id = $t_subject->get($t_subject->getLeftTableFieldName());
             $vn_right_id = $t_subject->get($t_subject->getRightTableFieldName());
             $va_bundle_values['relationship_typename'] = $t_subject->getRelationshipTypename($vn_left_id == $pn_primary_id ? 'ltol' : 'rtol');
         } else {
             $va_bundle_values['relationship_typename'] = $t_subject->getRelationshipTypename($t_subject->getLeftTableFieldName() == $vs_related_table ? 'rtol' : 'ltor');
         }
         $va_bundle_values['relationship_type_code'] = $t_subject->getRelationshipTypeCode();
     }
     //
     // Report errors
     //
     $va_errors = $this->request->getActionErrors();
     // all errors from all sources
     $va_general_errors = $this->request->getActionErrors('general');
     // just "general" errors - ones that are not attached to a specific part of the form
     if (sizeof($va_errors) - sizeof($va_general_errors) > 0) {
         $va_error_list = array();
         $vb_no_save_error = false;
         foreach ($va_errors as $o_e) {
             $va_error_list[$o_e->getErrorDescription()] = $o_e->getErrorDescription() . "\n";
             switch ($o_e->getErrorNumber()) {
                 case 1100:
                     // duplicate/invalid idno
                     if (!$vn_subject_id) {
                         // can't save new record if idno is not valid (when updating everything but idno is saved if it is invalid)
                         $vb_no_save_error = true;
                     }
                     break;
             }
         }
     } else {
         $this->opo_result_context->invalidateCache();
     }
     $this->opo_result_context->saveContext();
     # trigger "SaveItem" hook
     $this->opo_app_plugin_manager->hookSaveItem(array('id' => $vn_subject_id, 'table_num' => $t_subject->tableNum(), 'table_name' => $t_subject->tableName(), 'instance' => $t_subject, 'is_insert' => true));
     $vn_id = $t_subject->getPrimaryKey();
     $va_response = array('status' => sizeof($va_error_list) ? 10 : 0, 'id' => $vn_id, 'table' => $t_subject->tableName(), 'type_id' => method_exists($t_subject, "getTypeID") ? $t_subject->getTypeID() : null, 'display' => 'relation', 'bundleDisplay' => $va_bundle_values, 'errors' => $va_error_list);
     $this->view->setVar('response', $va_response);
     $this->render('interstitial/interstitial_result_json.php');
 }
 public function savePlacementsFromHTMLForm($po_request, $ps_form_prefix, $ps_placement_code)
 {
     if ($vs_bundles = $po_request->getParameter("{$ps_placement_code}{$ps_form_prefix}displayBundleList", pString)) {
         $va_bundles = explode(';', $vs_bundles);
         $t_screen = new ca_editor_ui_screens($this->getPrimaryKey());
         $va_placements = $t_screen->getPlacements(array('user_id' => $po_request->getUserID()));
         // remove deleted bundles
         foreach ($va_placements as $vn_placement_id => $va_bundle_info) {
             if (!in_array($va_bundle_info['bundle_name'] . '_' . $va_bundle_info['placement_id'], $va_bundles)) {
                 $t_screen->removePlacement($va_bundle_info['placement_id'], array('user_id' => $po_request->getUserID()));
                 if ($t_screen->numErrors()) {
                     $this->errors = $t_screen->errors;
                     return false;
                 }
             }
         }
         $va_locale_list = ca_locales::getLocaleList(array('index_by_code' => true));
         $va_available_bundles = $t_screen->getAvailableBundles();
         foreach ($va_bundles as $vn_i => $vs_bundle) {
             // get settings
             if (preg_match('!^(.*)_([\\d]+)$!', $vs_bundle, $va_matches)) {
                 $vn_placement_id = (int) $va_matches[2];
                 $vs_bundle = $va_matches[1];
             } else {
                 $vn_placement_id = null;
             }
             $vs_bundle_proc = str_replace(".", "_", $vs_bundle);
             $va_settings = array();
             foreach ($_REQUEST as $vs_key => $vs_val) {
                 if (preg_match("!^{$vs_bundle_proc}_([\\d]+)_(.*)\$!", $vs_key, $va_matches)) {
                     // is this locale-specific?
                     if (preg_match('!(.*)_([a-z]{2}_[A-Z]{2})$!', $va_matches[2], $va_locale_matches)) {
                         $vn_locale_id = isset($va_locale_list[$va_locale_matches[2]]) ? (int) $va_locale_list[$va_locale_matches[2]]['locale_id'] : 0;
                         // NOTE: we set keys for both locale_id (which how other placement-using editor like ca_search_forms and
                         // ca_bundle_displays do) *AND* the locale code (eg. "en_US"). This is because the settings created in profile and
                         // in pre v1.1 systems are keyed by code, not locale_id. There's nothing wrong with using code - it's just as unique as the locale_id
                         // and it's convenient to use both interchangeably in any event.
                         //
                         $va_settings[(int) $va_matches[1]][$va_locale_matches[1]][$vn_locale_id] = $va_settings[(int) $va_matches[1]][$va_locale_matches[1]][$va_locale_matches[2]] = $vs_val;
                     } else {
                         $va_settings[(int) $va_matches[1]][$va_matches[2]] = $vs_val;
                     }
                 }
             }
             if ($vn_placement_id === 0) {
                 $t_screen->addPlacement($vs_bundle, $vs_bundle . ($vn_i + 1), $va_settings[$vn_placement_id], $vn_i + 1, array('user_id' => $po_request->getUserID(), 'additional_settings' => $va_available_bundles[$vs_bundle]['settings']));
                 if ($t_screen->numErrors()) {
                     $this->errors = $t_screen->errors;
                     return false;
                 }
             } else {
                 $t_placement = new ca_editor_ui_bundle_placements($vn_placement_id, $va_available_bundles[$vs_bundle]['settings']);
                 $t_placement->setMode(ACCESS_WRITE);
                 $t_placement->set('rank', $vn_i + 1);
                 if (is_array($va_settings[$vn_placement_id])) {
                     foreach ($t_placement->getAvailableSettings() as $vs_setting => $va_setting_info) {
                         $vs_val = isset($va_settings[$vn_placement_id][$vs_setting]) ? $va_settings[$vn_placement_id][$vs_setting] : null;
                         $t_placement->setSetting($vs_setting, $vs_val);
                     }
                 }
                 $t_placement->update();
                 if ($t_placement->numErrors()) {
                     $this->errors = $t_placement->errors;
                     return false;
                 }
             }
         }
     }
     return true;
 }
 /**
  * Returns a list of ui id, screen id and placement id for a given setting key (editor_code/screen_idno/placement_code)
  * @param string $ps_key
  * @return array|bool
  */
 public static function resolveHideIfSelectedKey($ps_key)
 {
     if (CompositeCache::contains($ps_key, 'ListAttrHideIfSelected')) {
         return CompositeCache::fetch($ps_key, 'ListAttrHideIfSelected');
     }
     $va_tmp = explode('/', $ps_key);
     if (!sizeof($va_tmp) == 3) {
         return false;
     }
     // ui
     $t_ui = new ca_editor_uis();
     if (!$t_ui->load(array('editor_code' => $va_tmp[0]))) {
         return false;
     }
     // screen
     $t_screen = new ca_editor_ui_screens();
     if (!$t_screen->load(array('ui_id' => $t_ui->getPrimaryKey(), 'idno' => $va_tmp[1]))) {
         return false;
     }
     // placement
     $t_placement = new ca_editor_ui_bundle_placements();
     if (!$t_placement->load(array('screen_id' => $t_screen->getPrimaryKey(), 'placement_code' => $va_tmp[2]))) {
         return false;
     }
     $va_ret = array($t_screen->getPrimaryKey(), $t_placement->getPrimaryKey());
     CompositeCache::save($ps_key, $va_ret, 'ListAttrHideIfSelected');
     return $va_ret;
 }
 /**
  * 
  */
 public function loadBundles()
 {
     list($vn_subject_id, $t_subject) = $this->_initView();
     if (!$this->_checkAccess($t_subject)) {
         return false;
     }
     $ps_bundle_name = $this->request->getParameter("bundle", pString);
     $pn_placement_id = $this->request->getParameter("placement_id", pInteger);
     $pn_start = (int) $this->request->getParameter("start", pInteger);
     if (!($pn_limit = $this->request->getParameter("limit", pInteger))) {
         $pn_limit = null;
     }
     $t_placement = new ca_editor_ui_bundle_placements($pn_placement_id);
     $this->response->addContent(json_encode($t_subject->getBundleFormValues($ps_bundle_name, "{$pn_placement_id}", $t_placement->get('settings'), array('start' => $pn_start, 'limit' => $pn_limit, 'request' => $this->request, 'contentOnly' => true))));
 }
 /**
  * Returns content for a bundle or the inspector. Used to dynamically and selectively
  * reload an editing form.
  */
 public function reload()
 {
     list($vn_subject_id, $t_subject) = $this->_initView();
     if (!$this->_checkAccess($t_subject)) {
         return false;
     }
     $ps_bundle = $this->request->getParameter("bundle", pString);
     $pn_placement_id = $this->request->getParameter("placement_id", pInteger);
     switch ($ps_bundle) {
         case '__inspector__':
             $this->response->addContent($this->info(array($t_subject->primaryKey() => $vn_subject_id, 'type_id' => $this->request->getParameter("type_id", pInteger))));
             break;
         default:
             $t_placement = new ca_editor_ui_bundle_placements($pn_placement_id);
             if (!$t_placement->getPrimaryKey()) {
                 $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath()));
                 return;
             }
             if ($t_placement->get('bundle_name') != $ps_bundle) {
                 $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath()));
                 return;
             }
             $this->response->addContent($t_subject->getBundleFormHTML($ps_bundle, $pn_placement_id, $t_placement->get('settings'), array('request' => $this->request, 'contentOnly' => true), $vs_label));
             break;
     }
 }