function __construct($view, $moduleName) { // BEGIN ASSERTIONS if (!isset($this->_fileVariables[$view])) { sugar_die(get_class($this) . ": View {$view} is not supported"); } if (!isset($GLOBALS['beanList'][$moduleName])) { sugar_die(get_class($this) . ": Modulename {$moduleName} is not a Deployed Module"); } // END ASSERTIONS $this->_view = strtolower($view); $this->_moduleName = $moduleName; $module = new StudioModule($moduleName); $fielddefs = $module->getFields(); $loaded = null; foreach (array(MB_BASEMETADATALOCATION, MB_CUSTOMMETADATALOCATION, MB_WORKINGMETADATALOCATION, MB_HISTORYMETADATALOCATION) as $type) { $this->_sourceFilename = $this->getFileName($view, $moduleName, $type); if (null !== ($layout = $this->_loadFromFile($this->_sourceFilename))) { // merge in the fielddefs from this layout $this->_mergeFielddefs($fielddefs, $layout); $loaded = $layout; } } if ($loaded === null) { switch ($view) { case MB_QUICKCREATE: // Special handling for QuickCreates - if we don't have a QuickCreate definition in the usual places, then use an EditView $loaded = $this->_loadFromFile($this->getFileName(MB_EDITVIEW, $this->_moduleName, MB_BASEMETADATALOCATION)); if ($loaded === null) { throw new Exception(get_class($this) . ": cannot convert from EditView to QuickCreate for Module {$this->_moduleName} - definitions for EditView are missing"); } // Now change the array index $temp = $loaded[GridLayoutMetaDataParser::$variableMap[MB_EDITVIEW]]; unset($loaded[GridLayoutMetaDataParser::$variableMap[MB_EDITVIEW]]); $loaded[GridLayoutMetaDataParser::$variableMap[MB_QUICKCREATE]] = $temp; // finally, save out our new definition so that we have a base record for the history to work from $this->_sourceFilename = self::getFileName(MB_QUICKCREATE, $this->_moduleName, MB_CUSTOMMETADATALOCATION); $this->_saveToFile($this->_sourceFilename, $loaded); $this->_mergeFielddefs($fielddefs, $loaded); break; default: } if ($loaded === null) { throw new Exception(get_class($this) . ": view definitions for View {$this->_view} and Module {$this->_moduleName} are missing"); } } $this->_viewdefs = $loaded; // Set the original Viewdefs - required to ensure we don't lose fields from the base layout // Check the base location first, then if nothing is there (which for example, will be the case for some QuickCreates, and some mobile layouts - see above) // we need to check the custom location where the derived layouts will be foreach (array(MB_BASEMETADATALOCATION, MB_CUSTOMMETADATALOCATION) as $type) { $sourceFilename = $this->getFileName($view, $moduleName, $type); if (null !== ($layout = $this->_loadFromFile($sourceFilename))) { $this->_originalViewdefs = $layout; break; } } $this->_fielddefs = $fielddefs; $this->_history = new History($this->getFileName($view, $moduleName, MB_HISTORYMETADATALOCATION)); }
/** * @ticket 39407 */ public function testRemoveFieldFromLayoutsDocumentsException() { $SM = new StudioModule("Documents"); try { $SM->removeFieldFromLayouts("aFieldThatDoesntExist"); $this->assertTrue(true); } catch (Exception $e) { $this->assertTrue(false, "Studio module threw exception :" . $e->getMessage()); } }
function getLayouts() { $layouts = parent::getLayouts(); //The Documents popup view is not customizable unset($layouts[translate('LBL_POPUP')]); return $layouts; }
function getModule() { $normalModules = parent::getModule(); if (isset($normalModules[translate('LBL_RELATIONSHIPS')])) { unset($normalModules[translate('LBL_RELATIONSHIPS')]); } return $normalModules; }
function uninstall_relationships($include_studio_relationships = false) { $relationships = array(); //Find and remove studio created relationships. global $beanList, $beanFiles, $dictionary; //Load up the custom relationship definitions. if (file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')) { include 'custom/application/Ext/TableDictionary/tabledictionary.ext.php'; } //Find all the relatioships/relate fields involving this module. $rels_to_remove = array(); foreach ($beanList as $mod => $bean) { //Some modules like cases have a bean name that doesn't match the object name $bean = BeanFactory::getObjectName($mod); VardefManager::loadVardef($mod, $bean); //We can skip modules that are in this package as they will be removed anyhow if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields'])) { $field_defs = $dictionary[$bean]['fields']; foreach ($field_defs as $field => $def) { //Weed out most fields first if (isset($def['type'])) { //Custom relationships created in the relationship editor if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']])) { $rel_name = $def['relationship']; $rel_def = $dictionary[$rel_name]['relationships'][$rel_name]; //Check against mods to be removed. foreach ($this->modulesInPackage as $removed_mod) { if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod) { $dictionary[$rel_name]['from_studio'] = true; $relationships[$rel_name] = $dictionary[$rel_name]; } } } //Custom "relate" fields created in studio also need to be removed if ($def['type'] == 'relate' && isset($def['module'])) { foreach ($this->modulesInPackage as $removed_mod) { if ($def['module'] == $removed_mod) { require_once 'modules/ModuleBuilder/Module/StudioModule.php'; $studioMod = new StudioModule($mod); $studioMod->removeFieldFromLayouts($field); if (isset($def['custom_module'])) { require_once 'modules/DynamicFields/DynamicField.php'; require_once $beanFiles[$bean]; $seed = new $bean(); $df = new DynamicField($mod); $df->setup($seed); //Need to load the entire field_meta_data for some field types $field_obj = $df->getFieldWidget($mod, $field); $field_obj->delete($df); } } } } } } } } $this->uninstall_relationship(null, $relationships); if (isset($this->installdefs['relationships'])) { $relationships = $this->installdefs['relationships']; $this->log(translate('LBL_MI_UN_RELATIONSHIPS')); foreach ($relationships as $relationship) { // remove the metadata entry $filename = basename($relationship['meta_data']); $pathname = file_exists("custom/metadata/{$filename}") ? "custom/metadata/{$filename}" : "metadata/{$filename}"; if (isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables']) { $this->uninstall_relationship($pathname); } if (file_exists($pathname)) { unlink($pathname); } } } if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php")) { unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"); } Relationship::delete_cache(); $this->rebuild_tabledictionary(); }
/** * This returns an UNFILTERED list of custom relationships by module name. You will have to filter the relationships * by the modules being exported after calling this method * @param string $moduleName * @param bool $lhs Return relationships where $moduleName - left module in join. * @return mixed Array or false when module name is wrong. */ protected function getCustomRelationshipsByModuleName($moduleName, $lhs = false) { if (BeanFactory::getBeanName($moduleName) === false) { return false; } $result = array(); $relation = null; $module = new StudioModule($moduleName); /* @var $rel DeployedRelationships */ $rel = $module->getRelationships(); $relList = $rel->getRelationshipList(); foreach ($relList as $relationshipName) { $relation = $rel->get($relationshipName); if ($relation->getFromStudio()) { if ($lhs && $relation->getLhsModule() != $moduleName) { continue; } $result[$relationshipName] = $relation; } } return $result; }
/** * Gets the metadata from various non module locations as a fallback. If * no metadata file is found, will log an error and return an empty set of * viewdefs. * * @param string $marker The property to set when metadata is found * @return array */ public function getFallbackMetadata($marker = 'loadedMetadataFile') { // Prepare the return $viewdefs = array(); // Get our module type $sm = new StudioModule($this->_moduleName); $template = $sm->getType(); // Build an array of files to search defs for $files = array(); if (!$this->_viewClient !== 'base') { // This is the OOTB file for this module in the base client $files[] = $this->getMetadataFilename(MB_BASEMETADATALOCATION, null, 'base'); } // This is the metadata file for this module type $files[] = $this->getMetadataFilename('', $template, 'base'); if ($template !== 'basic') { // This is the metadata file for basic modules $files[] = $this->getMetadataFilename('', 'basic', 'base'); } // Used for logging $found = false; // Loop and set foreach ($files as $file) { if (file_exists($file)) { require $file; if (!empty($viewdefs)) { // This needs to be done in the event we have a SugarObject template file in use $viewdefs = MetaDataFiles::getModuleMetaDataDefsWithReplacements($this->bean, $viewdefs); if (isset($viewdefs[$this->_moduleName])) { $this->{$marker} = $file; $found = true; break; } } } } // If we found nothing, log it if (!$found) { $GLOBALS['log']->error("Could not find a filter file for {$this->_moduleName}"); } return $viewdefs; }
function processStudio($ajax) { $this->ajax->addCrumb(translate('LBL_STUDIO'), 'ModuleBuilder.main("studio")'); if (!isset($this->editModule)) { //Studio Select Module Page $this->generateStudioModuleButtons(); $this->question = translate('LBL_QUESTION_EDIT'); $this->title = translate('LBL_STUDIO'); global $current_user; if (is_admin($current_user)) { $this->actions = "<input class=\"button\" type=\"button\" id=\"exportBtn\" name=\"exportBtn\" onclick=\"ModuleBuilder.getContent('module=ModuleBuilder&action=exportcustomizations');\" value=\"" . translate('LBL_BTN_EXPORT') . '">'; } $this->help = 'studioHelp'; } else { $module = new StudioModule($this->editModule); $this->ajax->addCrumb($module->name, !empty($this->view) ? 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view_module=' . $this->editModule . '")' : ''); switch ($this->view) { case 'layouts': //Studio Select Layout page $this->buttons = $module->getLayouts(); $this->title = $module->name . " " . translate('LBL_LAYOUTS'); $this->question = translate('LBL_QUESTION_LAYOUT'); $this->help = 'layoutsHelp'; $this->ajax->addCrumb(translate('LBL_LAYOUTS'), ''); break; case 'subpanels': //Studio Select Subpanel page. $this->buttons = $module->getSubpanels(); $this->title = $module->name . " " . translate('LBL_SUBPANELS'); $this->question = translate('LBL_QUESTION_SUBPANEL'); $this->ajax->addCrumb(translate('LBL_SUBPANELS'), ''); $this->help = 'subpanelHelp'; break; case 'search': //Studio Select Search Layout page. $this->buttons = $module->getSearch(); $this->title = $module->name . " " . translate('LBL_SEARCH'); $this->question = translate('LBL_QUESTION_SEARCH'); $this->ajax->addCrumb(translate('LBL_LAYOUTS'), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view=layouts&view_module=' . $this->editModule . '")'); $this->ajax->addCrumb(translate('LBL_SEARCH'), ''); $this->help = 'searchHelp'; break; default: //Studio Edit Module Page $this->buttons = $module->getModule(); $this->question = translate('LBL_QUESTION_MODULE'); $this->title = translate('LBL_EDIT') . " " . $module->name; $this->help = 'moduleHelp'; } } }
/** * @ticket 50977 * * @dataProvider providerGetType */ public function testGetTypeFunction($module, $type) { $SM = new StudioModule($module); $this->assertEquals($type, $SM->getType(), 'Failed asserting that module:' . $module . ' is of type:' . $type); }
/** * Sets up the class vars for the file information * @return bool * @throws Exception */ protected function setupSubpanelViewDefFileInfo() { $client = $this->getViewClient(); $this->sidecarSubpanelName = $this->getSidecarSubpanelViewName($this->loadedModule, $this->linkName); if ($client !== 'base') { $layoutFiles[] = "modules/{$this->loadedModule}/clients/base/layouts/subpanels/subpanels.php"; } // check if there is an override $layoutFiles = array("modules/{$this->loadedModule}/clients/{$client}/layouts/subpanels/subpanels.php"); foreach ($layoutFiles as $file) { @(include $file); } $extension = "custom/modules/{$this->loadedModule}/Ext/clients/{$client}/layouts/subpanels/subpanels.ext.php"; if (SugarAutoLoader::fileExists($extension)) { @(include $extension); } $overrideSubpanelName = null; $overrideSubpanelFileName = null; if (!empty($viewdefs[$this->loadedModule][$client]['layout']['subpanels']['components'])) { $components = $viewdefs[$this->loadedModule][$client]['layout']['subpanels']['components']; foreach ($components as $key => $component) { if (empty($component['override_subpanel_list_view'])) { continue; } if (is_array($component['override_subpanel_list_view']) && $component['override_subpanel_list_view']['link'] == $this->linkName) { $this->loadedSubpanelName = $component['override_subpanel_list_view']['view']; $path = "modules/{$this->_moduleName}/clients/{$client}" . "/views/{$this->loadedSubpanelName}/{$this->loadedSubpanelName}.php"; $this->loadedSubpanelFileName = file_exists("custom/{$path}") ? "custom/{$path}" : $path; $this->sidecarFile = "custom/modules/{$this->_moduleName}/clients/{$client}" . "/views/{$this->sidecarSubpanelName}/{$this->sidecarSubpanelName}.php"; $this->overrideArrayKey = $key; return true; } // handle revenuelineitems' subpanel-for-opportunities if (!empty($component['context']['link']) && $component['context']['link'] == $this->linkName) { $overrideSubpanelName = $component['override_subpanel_list_view']; $overrideSubpanelFileName = "modules/{$this->_moduleName}/clients/{$client}" . "/views/{$overrideSubpanelName}/{$overrideSubpanelName}.php"; break; } } } $subpanelFile = "modules/{$this->_moduleName}/clients/{$client}" . "/views/{$this->sidecarSubpanelName}/{$this->sidecarSubpanelName}.php"; $defaultSubpanelFile = "modules/{$this->_moduleName}/clients/base/views/subpanel-list/subpanel-list.php"; $this->loadedSubpanelName = $this->sidecarSubpanelName; $studioModule = new StudioModule($this->_moduleName); $defaultTemplate = $studioModule->getType(); $defaultTemplateSubpanelFile = "include/SugarObjects/templates/{$defaultTemplate}/clients/base/views/subpanel-list/subpanel-list.php"; $baseTemplateSubpanelFile = "include/SugarObjects/templates/basic/clients/base/views/subpanel-list/subpanel-list.php"; // using includes because require_once causes an empty array if (file_exists('custom/' . $subpanelFile)) { $this->loadedSubpanelFileName = 'custom/' . $subpanelFile; } elseif (file_exists($subpanelFile)) { $this->loadedSubpanelFileName = $subpanelFile; } elseif (!empty($overrideSubpanelName) && file_exists($overrideSubpanelFileName)) { $this->loadedSubpanelFileName = $overrideSubpanelFileName; $this->loadedSubpanelName = $overrideSubpanelName; } elseif (file_exists($defaultSubpanelFile)) { $this->loadedSubpanelFileName = $defaultSubpanelFile; $this->loadedSubpanelName = 'subpanel-list'; } elseif (file_exists($defaultTemplateSubpanelFile)) { $this->loadedSubpanelFileName = $defaultTemplateSubpanelFile; $this->loadedSubpanelName = 'subpanel-list'; } elseif (file_exists($baseTemplateSubpanelFile)) { $this->loadedSubpanelFileName = $baseTemplateSubpanelFile; $this->loadedSubpanelName = 'subpanel-list'; } else { throw new Exception("No metadata file found for subpanel: {$this->loadedSubpanelName}"); } $this->sidecarFile = "custom/" . $subpanelFile; }
function getLayouts() { $layouts = parent::getLayouts(); $layouts = array_merge(array(translate("LBL_CONVERTLEAD", "Leads") => array('name' => translate("LBL_CONVERTLEAD", "Leads"), 'action' => "module=Leads&action=Editconvert&to_pdf=1", 'imageTitle' => 'icon_ConvertLead', 'help' => 'layoutsBtn', 'size' => '48')), $layouts); return $layouts; }