/**
  * Gets the new path and filename for this view
  *
  * @param string $view The view name to get the filename for
  * @return string
  */
 public function getNewFileName($view)
 {
     // Clean up client to mobile for wireless clients
     $client = $this->client == 'wireless' ? 'mobile' : $this->client;
     if ($this->deployed) {
         // Deployed will always use the full key_module name for custom modules
         $module = $this->getNormalizedModuleName();
         $newname = MetaDataFiles::getDeployedFileName($view, $module, $this->type, $client);
     } else {
         $newname = MetaDataFiles::getUndeployedFileName($view, $this->module, $this->package, $this->type, $client);
     }
     // If this is a history file then add the timestamp back on
     if ($this->timestamp) {
         $newname .= '_' . $this->timestamp;
     }
     return $newname;
 }
 /**
  * Converts the legacy Grid metadata to Sidecar style
  */
 public function convertLegacyViewDefsToSidecar()
 {
     if (empty($this->legacyViewdefs)) {
         return;
     }
     // If this module is undeployed and doesn't have a base set of metadata,
     // we should just end things right now. It's not you, it's me.
     if (!$this->deployed && $this->package) {
         // This is the marker that decides our fate
         $found = false;
         // The undeployed implementation uses history then working, where
         // working translates to the base file and history translates to
         // working.
         $types = array(MB_HISTORYMETADATALOCATION, MB_WORKINGMETADATALOCATION);
         // Check each type for file existence. This is done similarly to the
         // implementation, without the overhead of constructing that object
         // or the parser just yet.
         foreach ($types as $type) {
             $file = MetaDataFiles::getUndeployedFileName($this->viewtype, $this->module, $this->package, $type, $this->client);
             if (file_exists($file)) {
                 $found = true;
                 break;
             }
         }
         // If neither of the files we needed are found, bail now since without
         // these the upgrade process breaks
         if (!$found) {
             $this->logUpgradeStatus("Required {$this->client} {$this->viewtype} metadata for {$this->module} is missing... aborting merge upgrade");
             return;
         }
     }
     $this->logUpgradeStatus('Converting ' . $this->client . ' ' . $this->viewtype . ' view defs for ' . $this->module);
     // Holds merged defs and final defs
     $newdefs = $tempdefs = $finaldefs = array();
     // This needs to be called before the parser is instantiated to prevent
     // custom metadata from being created from basic module template
     $defaultDefs = $this->loadDefaultMetadata();
     // Get the parser now that default metadata has been fetched
     $parser = ParserFactory::getParser($this->viewtype, $this->module, $this->package, null, $this->client);
     // Get the fields that are on the default defs panels since we may need
     // those as well
     $defaultDefsFields = $parser->getFieldsFromPanels($defaultDefs['panels']);
     // Go through merge views, add fields added to detail view to base panel
     // and fields added to edit view not in detail view or hidden panel
     $customFields = array();
     foreach ($this->legacyViewdefs as $lViewtype => $data) {
         // We will need a parser no matter what
         if ($this->sidecar) {
             $legacyParser = ParserFactory::getParser($lViewtype, $this->module, $this->package, null, $this->client);
         } else {
             $legacyParser = ParserFactory::getParser($lViewtype, $this->module, $this->package);
         }
         // Step 1, handle tabDef changes
         $hasTabDefCustomizations = $this->hasTabDefCustomizations($lViewtype);
         // Tabdefs holds tab def customizations. If there are tab customizations
         // then the defaultDefs need to be derived from the customize layout
         // instead of the default viewdef
         $tabdefs = array();
         if ($hasTabDefCustomizations) {
             // Used for converting tab names. Tabs and panels need to match
             // and that matching gets handled here and in handleConversion
             $c = 0;
             // pull out the tab definitions from the originals, put them into the Canonical Form
             foreach ($data['templateMeta']['tabDefs'] as $tabName => $tabContent) {
                 // Handle panel labels for matching later
                 $panelNames = $this->getConvertedPanelName($tabName, $c);
                 $tabName = $panelNames['label'];
                 // Save these for later to prevent conflict with new panels later
                 $tabdefs[$tabName] = array('newTab' => $tabContent['newTab'], 'panelDefault' => $tabContent['panelDefault']);
                 // Increment the counter
                 $c++;
             }
             // Intermediate step here needed for tabdef customizations... what is
             // needed is to convert the old panels to new style, then inject the
             // defaultDef header panel into the newly converted panel set before
             // continuing on
             $headerPanel = $defaultDefs['panels'][0];
             $defaultDefs = $this->handleConversion($data, 'panels', true);
             array_unshift($defaultDefs['panels'], $headerPanel);
         }
         // TemplateMeta needs to be added if it isn't, to both the default defs
         // and the parser viewdefs
         if (isset($data['templateMeta'])) {
             if (!isset($defaultDefs['templateMeta'])) {
                 $defaultDefs['templateMeta'] = $data['templateMeta'];
             } else {
                 $defaultDefs['templateMeta'] = array_merge($defaultDefs['templateMeta'], $data['templateMeta']);
             }
             if (!isset($parser->_viewdefs['templateMeta'])) {
                 $parser->_viewdefs['templateMeta'] = $defaultDefs['templateMeta'];
             } else {
                 $parser->_viewdefs['templateMeta'] = array_merge($parser->_viewdefs['templateMeta'], $defaultDefs['templateMeta']);
             }
         }
         // Make a header fields array so that fields that may be in legacy
         // defs can be plucked out
         $headerFields = array();
         foreach ($defaultDefs['panels'][0]['fields'] as $hField) {
             // Handle array type fields first
             if (is_array($hField)) {
                 // But only if there is a name element of the array
                 if (isset($hField['name'])) {
                     // First set from the name of the field we are on
                     $headerFields[$hField['name']] = $hField['name'];
                     // Now if there are fields for this field (fieldset), grab those too
                     if (isset($hField['fields']) && is_array($hField['fields'])) {
                         foreach ($hField['fields'] as $hFieldName) {
                             // Some modules have header field fieldset defs that are arrays
                             if (is_array($hFieldName) && isset($hFieldName['name'])) {
                                 $headerFields[$hFieldName['name']] = $hFieldName['name'];
                             } else {
                                 $headerFields[$hFieldName] = $hFieldName;
                             }
                         }
                     }
                 }
             } else {
                 // This will be a string, take it as is
                 $headerFields[$hField] = $hField;
             }
         }
         // Step 2, convert panels if there are any to handle
         if (!empty($data['panels'])) {
             // Add spans fields as needed
             $maxSpan = $parser->getMaxSpan();
             // Need to send the entire data array as we need templateData.maxColumns
             $data = $this->addSpansToFields($data, $maxSpan);
             $legacyPanelFields = $legacyParser->getFieldsFromPanels($data['panels']);
             foreach ($legacyPanelFields as $fieldname => $fielddef) {
                 // Handle removal of fields from customFields (legacy defs) as needed
                 $skip = false;
                 if (empty($fieldname) || !$this->isValidField($fieldname)) {
                     // Definitely skip keeping empty and invalid field names.
                     $skip = true;
                 } else {
                     // Is this field already in the customFields collection?
                     $cf = isset($customFields[$fieldname]);
                     // Or perhaps it is explicitly in the removeFields array?
                     $rf = isset($this->removeFields[$fieldname]);
                     // Or maybe it is in the headerFields array?
                     $hf = isset($headerFields[$fieldname]);
                     // If this field is any of the arrays above, skip it
                     if ($cf || $rf || $hf) {
                         $skip = true;
                     }
                 }
                 if ($skip) {
                     continue;
                 }
                 $customFields[$fieldname] = array('data' => $fielddef, 'source' => $lViewtype);
             }
         }
         // Handle field conversion and renames from previous versions
         $customFields = $this->applyFieldConversionPatches($customFields);
         // Grab our twitter conversion flag early since twitter_id could be
         // an array as a field
         $convertTwitter = $this->needsTwitterConversion();
         // Handle unsetting of header fields from non header panels and handle
         // email1 <=> email conversion
         foreach ($defaultDefs['panels'] as $panelIndex => $panel) {
             foreach ($panel['fields'] as $fieldIndex => $fieldName) {
                 // Turn a field name into a string for searching convenience
                 if (is_array($fieldName)) {
                     $lookupFieldName = isset($fieldName['name']) ? $fieldName['name'] : null;
                 } else {
                     $lookupFieldName = $fieldName;
                 }
                 // Handle fields that are not meant to be here, like header
                 // fields, but only if we are not in the header panel
                 if ($panelIndex > 0) {
                     if (isset($lookupFieldName) && isset($headerFields[$lookupFieldName])) {
                         // Remove this field from the defs and move on
                         unset($defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex]);
                         continue;
                     }
                 }
                 // Delete 'team_name' from the layout if module doesn't implement team-security, otherwise leave it;
                 // the field is a part of 'basic' template by default, but module may not implement team-security
                 if (isset($lookupFieldName) && $lookupFieldName == 'team_name' && !$this->isValidField($fieldName)) {
                     unset($defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex]);
                 }
                 // Hack email field into submission
                 if (isset($lookupFieldName) && $lookupFieldName == 'email1') {
                     if (is_array($fieldName)) {
                         $fieldName['name'] = 'email';
                         $defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex] = $fieldName;
                     } else {
                         $defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex] = 'email';
                     }
                 }
                 // Handle twitter_id to twitter renaming
                 if (isset($lookupFieldName) && $lookupFieldName == 'twitter_id' && $convertTwitter) {
                     // If twitter is already on the defaults, remove twitter_id entirely,
                     // otherwise rename twitter_id
                     if (isset($defaultDefsFields['twitter'])) {
                         unset($defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex]);
                     } elseif (is_array($fieldName)) {
                         $fieldName['name'] = 'twitter';
                         $defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex] = $fieldName;
                     } else {
                         $defaultDefs['panels'][$panelIndex]['fields'][$fieldIndex] = 'twitter';
                     }
                 }
             }
             // Reset the array indexes
             $defaultDefs['panels'][$panelIndex]['fields'] = array_values($defaultDefs['panels'][$panelIndex]['fields']);
         }
         // End email1 => email hack
         // Make sure the array pointer for the panels is back at the start.
         // This is needed to allow canonical conversion to pick up the right
         // header panel
         reset($defaultDefs['panels']);
         $origFields = array();
         // replace viewdefs with defaults, since parser's viewdefs can be already customized by other parts
         // of the upgrade
         $parser->_viewdefs['panels'] = $parser->convertFromCanonicalForm($defaultDefs['panels'], $parser->_fielddefs);
         // get field list
         $origData = $parser->getFieldsFromPanels($defaultDefs['panels'], $parser->_fielddefs);
         // Go through existing fields and remove those not in the new data
         foreach ($origData as $fname => $fielddef) {
             if (!$this->isValidField($fname)) {
                 continue;
             }
             if (is_array($fielddef) && !empty($fielddef['fields'])) {
                 // fieldsets - iterate over each field
                 $setExists = false;
                 if (!empty($customFields[$fielddef['name']])) {
                     $setExists = true;
                 } else {
                     foreach ($fielddef['fields'] as $setfielddef) {
                         if (!is_array($setfielddef)) {
                             $setfname = $setfielddef;
                         } else {
                             // skip weird nameless ones
                             if (empty($setfielddef['name'])) {
                                 continue;
                             }
                             $setfname = $setfielddef['name'];
                         }
                         // if we have one field - we take all set
                         if (isset($customFields[$setfname])) {
                             $setExists = true;
                             break;
                         }
                     }
                 }
                 if ($setExists) {
                     $origFields[$fielddef['name']] = $fielddef;
                     // if fields exist, we take all the set as existing fields
                     foreach ($fielddef['fields'] as $setfielddef) {
                         if (!is_array($setfielddef)) {
                             $setfname = $setfielddef;
                         } else {
                             // skip werid nameless ones
                             if (empty($setfielddef['name'])) {
                                 continue;
                             }
                             $setfname = $setfielddef['name'];
                         }
                         $origFields[$setfname] = $fielddef;
                     }
                 } else {
                     // else we delete the set but only if it isn't a header field
                     if (!isset($headerFields[$fname])) {
                         $parser->removeField($fname);
                     }
                 }
             } else {
                 // if it's a regular field, check against existing field in new data
                 if (!isset($customFields[$fname]) && !isset($headerFields[$fname])) {
                     // not there - remove it
                     $parser->removeField($fname);
                 } else {
                     // otherwise - keep as existing
                     $origFields[$fname] = $fielddef;
                 }
             }
         }
         // now go through new fields and add those not in original data
         // $customFields is legacy defs, $origFields are Sugar7 OOTB defs
         foreach ($customFields as $fieldname => $data) {
             if (isset($origFields[$fieldname])) {
                 // If the field is special, massage it into latest format being
                 // sure to maintain its current position in the layout
                 if ($this->isSpecialField($fieldname)) {
                     $fielddata = $this->convertFieldData($fieldname, $data['data']);
                     $this->updateField($parser, $fieldname, $fielddata);
                 }
             } else {
                 $fielddata = $this->convertFieldData($fieldname, $data['data']);
                 // FIXME: hack since addField cuts field defs
                 if ($this->isSpecialField($fieldname) && empty($parser->_originalViewDef[$fielddata['name']])) {
                     $parser->_originalViewDef[$fielddata['name']] = $fielddata;
                 }
                 $parser->addField($fielddata, $this->getPanelName($parser->_viewdefs['panels'], $data['source']));
             }
         }
         // Convert the panels array to something useful
         $panels = $parser->convertToCanonicalForm($parser->_viewdefs['panels'], $parser->_fielddefs);
         // Add back in tabDefs on the panels if there are any
         if (!empty($tabdefs)) {
             foreach ($panels as $key => $panel) {
                 if (!empty($panel['label']) && isset($tabdefs[$panel['label']])) {
                     $panels[$key]['newTab'] = $tabdefs[$panel['label']]['newTab'];
                     $panels[$key]['panelDefault'] = $tabdefs[$panel['label']]['panelDefault'];
                 }
             }
         }
         // There needs to be two different arrays here to allow for non-recursive
         // but nested array merges. This allows for detail views to be upgraded
         // first followed by edit views while still maintaining tab definitions
         // for detail views
         if (empty($newdefs['panels'])) {
             $newdefs = $parser->_viewdefs;
             $newdefs['panels'] = $panels;
         } else {
             $tempdefs = $parser->_viewdefs;
             $tempdefs['panels'] = $panels;
         }
         // After all iterations, this will be the final, merged layout def
         $finaldefs = $this->mergeLayoutDefs($newdefs, $tempdefs);
     }
     //Finally re-add any fields that are on the OOB sidecar view but not on the OOB Legacy views
     $finaldefs = $this->addNewFieldsToLayout($finaldefs);
     $this->sidecarViewdefs[$this->getNormalizedModuleName()][$this->client]['view'][MetaDataFiles::getName($this->viewtype)] = $finaldefs;
 }
 public function getFileName($view, $moduleName, $packageName, $type = MB_BASEMETADATALOCATION, $client = null)
 {
     if ($client === null) {
         $client = $this->_viewClient;
     }
     return MetaDataFiles::getUndeployedFileName($view, $moduleName, $packageName, $type, $client);
 }