function build()
 {
     $basepath = "custom/Extension/modules";
     $this->activitiesToAdd = false;
     // and mark all as built so that the next time we come through we'll know and won't build again
     foreach ($this->relationships as $name => $relationship) {
         $definition = $relationship->getDefinition();
         // activities will always appear on the rhs only - lhs will be always be this module in MB
         if (strtolower($definition['rhs_module']) == 'activities') {
             $this->activitiesToAdd = true;
             $relationshipName = $definition['relationship_name'];
             foreach (self::$activities as $activitiesSubModuleLower => $activitiesSubModuleName) {
                 $definition['rhs_module'] = $activitiesSubModuleName;
                 $definition['for_activities'] = true;
                 $definition['relationship_name'] = $relationshipName . '_' . $activitiesSubModuleLower;
                 $this->relationships[$definition['relationship_name']] = RelationshipFactory::newRelationship($definition);
             }
             unset($this->relationships[$name]);
         }
     }
     $GLOBALS['log']->info(get_class($this) . "->build(): installing relationships");
     $MBModStrings = $GLOBALS['mod_strings'];
     $adminModStrings = return_module_language('', 'Administration');
     // required by ModuleInstaller
     foreach ($this->relationships as $name => $relationship) {
         $relationship->setFromStudio();
         $GLOBALS['mod_strings'] = $MBModStrings;
         $installDefs = parent::build($basepath, "<basepath>", array($name => $relationship));
         // and mark as built so that the next time we come through we'll know and won't build again
         $relationship->setReadonly();
         $this->relationships[$name] = $relationship;
         // now install the relationship - ModuleInstaller normally only does this as part of a package load where it installs the relationships defined in the manifest. However, we don't have a manifest or a package, so...
         // If we were to chose to just use the Extension mechanism, without using the ModuleInstaller install_...() methods, we must :
         // 1)   place the information for each side of the relationship in the appropriate Ext directory for the module, which means specific $this->save...() methods for DeployedRelationships, and
         // 2)   we must also manually add the relationship into the custom/application/Ext/TableDictionary/tabledictionary.ext.php file as install_relationship doesn't handle that (install_relationships which requires the manifest however does)
         //      Relationships must be in tabledictionary.ext.php for the Admin command Rebuild Relationships to reliably work:
         //      Rebuild Relationships looks for relationships in the modules vardefs.php, in custom/modules/<modulename>/Ext/vardefs/vardefs.ext.php, and in modules/TableDictionary.php and custom/application/Ext/TableDictionary/tabledictionary.ext.php
         //      if the relationship is not defined in one of those four places it could be deleted during a rebuilt, or during a module installation (when RebuildRelationships.php deletes all entries in the Relationships table)
         // So instead of doing this, we use common save...() methods between DeployedRelationships and UndeployedRelationships that will produce installDefs,
         // and rather than building a full manifest file to carry them, we manually add these installDefs to the ModuleInstaller, and then
         // individually call the appropriate ModuleInstaller->install_...() methods to take our relationship out of our staging area and expand it out to the individual module Ext areas
         $GLOBALS['mod_strings'] = $adminModStrings;
         require_once 'ModuleInstall/ModuleInstaller.php';
         $mi = new ModuleInstaller();
         $mi->id_name = 'custom' . $name;
         // provide the moduleinstaller with a unique name for this relationship - normally this value is set to the package key...
         $mi->installdefs = $installDefs;
         $mi->base_dir = $basepath;
         $mi->silent = true;
         VardefManager::clearVardef();
         $mi->install_relationships();
         $mi->install_languages();
         $mi->install_vardefs();
         $mi->install_layoutdefs();
     }
     // now clear all caches so that our changes are visible
     require_once 'modules/Administration/QuickRepairAndRebuild.php';
     $rac = new RepairAndClear();
     $rac->repairAndClearAll(array('clearAll'), array($GLOBALS['mod_strings']['LBL_ALL_MODULES']), true, false);
     $GLOBALS['mod_strings'] = $MBModStrings;
     // finally, restore the ModuleBuilder mod_strings
     // save out the updated definitions so that we keep track of the change in built status
     $this->save();
     $GLOBALS['log']->info(get_class($this) . "->build(): finished relationship installation");
 }
 protected function getRelateFieldDefinition($sourceModule, $relationshipName, $vnameLabel = '')
 {
     $vardef = array();
     $vardef['name'] = $relationshipName . "_name";
     // must end in _name for the QuickSearch code in TemplateHandler->createQuickSearchCode
     $vardef['type'] = 'relate';
     $vardef['source'] = 'non-db';
     if (!empty($vnameLabel)) {
         $vardef['vname'] = 'LBL_' . strtoupper($relationshipName . '_FROM_' . $vnameLabel) . '_TITLE';
     } else {
         $vardef['vname'] = 'LBL_' . strtoupper($relationshipName . '_FROM_' . $sourceModule) . '_TITLE';
     }
     $vardef['save'] = true;
     // the magic value to tell SugarBean to save this relate field even though it is not listed in the $relationship_fields array
     // id_name matches the join_key_ column in the relationship table for the sourceModule - that is, the column in the relationship table containing the id of the corresponding field in the source module's table (vardef['table'])
     $vardef['id_name'] = $this->getIDName($sourceModule);
     // link cannot match id_name otherwise the $bean->$id_name value set from the POST is overwritten by the Link object created by this 'link' entry
     $vardef['link'] = $relationshipName;
     // the name of the link field that points to the relationship - required for the save to function
     $vardef['table'] = $this->getTablename($sourceModule);
     $vardef['module'] = $sourceModule;
     require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php';
     $parsedModuleName = AbstractRelationships::parseDeployedModuleName($sourceModule);
     // now determine the appropriate 'rname' field for this relate
     // the 'rname' points to the field in source module that contains the displayable name for the record
     // usually this is 'name' but sometimes it is not...
     $vardef['rname'] = 'name';
     if (isset($parsedModuleName['packageName'])) {
         require_once 'modules/ModuleBuilder/MB/ModuleBuilder.php';
         $mb = new ModuleBuilder();
         $module = $mb->getPackageModule($parsedModuleName['packageName'], $parsedModuleName['moduleName']);
         if (in_array('file', array_keys($module->config['templates']))) {
             $vardef['rname'] = 'document_name';
         }
     } else {
         switch (strtolower($sourceModule)) {
             case 'prospects':
                 $vardef['rname'] = 'account_name';
                 break;
             case 'documents':
                 $vardef['rname'] = 'document_name';
                 break;
             case 'kbdocuments':
                 $vardef['rname'] = 'kbdocument_name';
                 break;
             case 'leads':
             case 'contacts':
                 // special handling as these modules lack a name column in the database; instead 'name' refers to a non-db field that concatenates first_name and last_name
                 // luckily, the relate field mechanism can handle this with an equivalent additional db_concat_fields entry
                 $vardef['rname'] = 'name';
                 $vardef['db_concat_fields'] = array(0 => 'first_name', 1 => 'last_name');
                 break;
             default:
                 // now see if we have any module inheriting from the 'file' template - records in file-type modules are named by the document_name field, not the usual 'name' field
                 $object = $GLOBALS['beanList'][$sourceModule];
                 require_once $GLOBALS['beanFiles'][$object];
                 $bean = new $object();
                 if (isset($GLOBALS['dictionary'][$object]['templates']) && in_array('file', $GLOBALS['dictionary'][$object]['templates'])) {
                     $vardef['rname'] = 'document_name';
                 }
         }
     }
     return $vardef;
 }
Beispiel #3
0
 function getProvidedSubpanels()
 {
     $this->providedSubpanels = array();
     $subpanelDir = $this->getModuleDir() . '/metadata/subpanels/';
     if (file_exists($subpanelDir)) {
         $f = dir($subpanelDir);
         require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php';
         while ($g = $f->read()) {
             // sanity check to confirm that this is a usable subpanel...
             if (substr($g, 0, 1) != '.' && AbstractRelationships::validSubpanel($subpanelDir . $g)) {
                 $subname = str_replace('.php', '', $g);
                 $this->providedSubpanels[$subname] = $subname;
             }
         }
     }
     return $this->providedSubpanels;
 }
 /**
  * gets a list of subpanels provided to other modules
  *
  *
  */
 function getProvidedSubpanels()
 {
     require_once 'modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php';
     $this->providedSubpanels = array();
     $subpanelDir = 'modules/' . $this->module . '/metadata/subpanels/';
     foreach (array($subpanelDir, "custom/{$subpanelDir}") as $dir) {
         if (is_dir($dir)) {
             foreach (scandir($dir) as $fileName) {
                 // sanity check to confirm that this is a usable subpanel...
                 if (substr($fileName, 0, 1) != '.' && substr(strtolower($fileName), -4) == ".php" && AbstractRelationships::validSubpanel("{$dir}/{$fileName}")) {
                     $subname = str_replace('.php', '', $fileName);
                     $this->providedSubpanels[$subname] = $subname;
                 }
             }
         }
     }
     return $this->providedSubpanels;
 }
 function add($rel)
 {
     // convert old format definition to new format
     if (!isset($rel['lhs_module'])) {
         $rel['lhs_module'] = $this->moduleName;
     }
     $definition = AbstractRelationships::convertFromOldFormat($rel);
     if (!isset($definition['relationship_type'])) {
         $definition['relationship_type'] = 'many-to-many';
     }
     // get relationship object from RelationshipFactory
     $relationship = RelationshipFactory::newRelationship($definition);
     // add relationship to the set of relationships
     $this->implementation->add($relationship);
     $this->updateRelationshipVariable();
     return $relationship;
 }
 protected function getRelateFieldDefinition($sourceModule, $relationshipName, $vnameLabel = '')
 {
     $vardef = array();
     $vardef['name'] = $this->getValidDBName($relationshipName . "_name");
     // must end in _name for the QuickSearch code in TemplateHandler->createQuickSearchCode
     $vardef['type'] = 'relate';
     $vardef['source'] = 'non-db';
     if (!empty($vnameLabel)) {
         $vardef['vname'] = 'LBL_' . strtoupper($relationshipName . '_FROM_' . $vnameLabel) . '_TITLE';
     } else {
         $vardef['vname'] = 'LBL_' . strtoupper($relationshipName . '_FROM_' . $sourceModule) . '_TITLE';
     }
     $vardef['save'] = true;
     // the magic value to tell SugarBean to save this relate field even though it is not listed in the $relationship_fields array
     // id_name matches the join_key_ column in the relationship table for the sourceModule - that is, the column in the relationship table containing the id of the corresponding field in the source module's table (vardef['table'])
     $vardef['id_name'] = $this->getIDName($sourceModule);
     // link cannot match id_name otherwise the $bean->$id_name value set from the POST is overwritten by the Link object created by this 'link' entry
     $vardef['link'] = $this->getValidDBName($relationshipName);
     // the name of the link field that points to the relationship - required for the save to function
     $vardef['table'] = $this->getTablename($sourceModule);
     $vardef['module'] = $sourceModule;
     $module = null;
     switch (strtolower($sourceModule)) {
         case 'prospects':
             $bean = BeanFactory::getBean($this->definition['rhs_module']);
             $fields = array_keys($bean->field_name_map);
             if (in_array('name', $fields)) {
                 $vardef['rname'] = 'name';
             } else {
                 $vardef['rname'] = 'account_name';
             }
             break;
         case 'documents':
             $vardef['rname'] = 'document_name';
             break;
         case 'kbdocuments':
             $vardef['rname'] = 'kbdocument_name';
             break;
         default:
             $module = $sourceModule;
             $vardef['rname'] = 'name';
             break;
     }
     if ($module) {
         $class = BeanFactory::getBean($module);
         $tplconfig = array();
         if (!$class) {
             $parsedModuleName = AbstractRelationships::parseDeployedModuleName($sourceModule);
             if (isset($parsedModuleName['packageName'])) {
                 // added relationship to yet non-deployed module
                 require_once 'modules/ModuleBuilder/MB/ModuleBuilder.php';
                 $mb = new ModuleBuilder();
                 $module = $mb->getPackageModule($parsedModuleName['packageName'], $parsedModuleName['moduleName']);
                 $tplconfig = array_keys($module->config['templates']);
             } else {
                 throw new \RuntimeException('Module does not exist as a bean and no template found in its config');
             }
         }
         if (is_subclass_of($class, 'File') || in_array('file', $tplconfig)) {
             $vardef['rname'] = 'document_name';
         } elseif (is_subclass_of($class, 'Person') || in_array('person', $tplconfig)) {
             $vardef['rname'] = 'full_name';
             $vardef['db_concat_fields'] = array(0 => 'first_name', 1 => 'last_name');
         } elseif ($class && $class->getFieldDefinition('name')) {
             $vardef['rname'] = 'name';
         }
     }
     return $vardef;
 }
 private function updateUndeployedLayout($relationship, $actionAdd = true)
 {
     // many-to-many relationships don't have fields so if we have a many-to-many we can just skip this...
     if ($relationship->getType() == MB_MANYTOMANY) {
         return false;
     }
     $successful = true;
     $layoutAdditions = $relationship->buildFieldsToLayouts();
     require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php';
     foreach ($layoutAdditions as $deployedModuleName => $fieldName) {
         foreach (array(MB_EDITVIEW, MB_DETAILVIEW) as $view) {
             $parsedName = AbstractRelationships::parseDeployedModuleName($deployedModuleName);
             if (isset($parsedName['packageName'])) {
                 $GLOBALS['log']->debug(get_class($this) . ": " . ($actionAdd ? "adding" : "removing") . " {$fieldName} on {$view} layout for undeployed module {$parsedName['moduleName']} in package {$parsedName['packageName']}");
                 $parser = new GridLayoutMetaDataParser($view, $parsedName['moduleName'], $parsedName['packageName']);
                 if ($actionAdd ? $parser->addField(array('name' => $fieldName)) : $parser->removeField($fieldName)) {
                     $parser->handleSave(false);
                 } else {
                     $GLOBALS['log']->debug(get_class($this) . ": couldn't " . ($actionAdd ? "add" : "remove") . " {$fieldName} on {$view} layout for undeployed module {$deployedModuleName}");
                     $successful = false;
                 }
             }
         }
     }
     return $successful;
 }
 function build()
 {
     $modulesToBuild = array();
     if (!isset($this->relationships[$this->newRelationshipName])) {
         $GLOBALS['log']->fatal("Could not find a relationship by the name of {$this->newRelationshipName}, you will have to quick repair and rebuild to get the new relationship added.");
     } else {
         $newRel = $this->relationships[$this->newRelationshipName];
         $newRelDef = $newRel->getDefinition();
         $modulesToBuild[$newRelDef['rhs_module']] = true;
         $modulesToBuild[$newRelDef['lhs_module']] = true;
     }
     $basepath = "custom/Extension/modules";
     $this->activitiesToAdd = false;
     // and mark all as built so that the next time we come through we'll know and won't build again
     foreach ($this->relationships as $name => $relationship) {
         if ($relationship->readonly()) {
             continue;
         }
         $definition = $relationship->getDefinition();
         // activities will always appear on the rhs only - lhs will be always be this module in MB
         if (strtolower($definition['rhs_module']) == 'activities') {
             $this->activitiesToAdd = true;
             $relationshipName = $definition['relationship_name'];
             foreach (self::$activities as $activitiesSubModuleLower => $activitiesSubModuleName) {
                 $definition['rhs_module'] = $activitiesSubModuleName;
                 $definition['for_activities'] = true;
                 $definition['relationship_name'] = $relationshipName . '_' . $activitiesSubModuleLower;
                 $this->relationships[$definition['relationship_name']] = RelationshipFactory::newRelationship($definition);
             }
             unset($this->relationships[$name]);
         }
     }
     $GLOBALS['log']->info(get_class($this) . "->build(): installing relationships");
     $MBModStrings = $GLOBALS['mod_strings'];
     $adminModStrings = return_module_language('', 'Administration');
     // required by ModuleInstaller
     foreach ($this->relationships as $name => $relationship) {
         if ($relationship->readonly()) {
             continue;
         }
         $relationship->setFromStudio();
         $GLOBALS['mod_strings'] = $MBModStrings;
         $installDefs = parent::build($basepath, "<basepath>", array($name => $relationship));
         // and mark as built so that the next time we come through we'll know and won't build again
         $relationship->setReadonly();
         $this->relationships[$name] = $relationship;
         // now install the relationship - ModuleInstaller normally only does this as part of a package load where it installs the relationships defined in the manifest. However, we don't have a manifest or a package, so...
         // If we were to chose to just use the Extension mechanism, without using the ModuleInstaller install_...() methods, we must :
         // 1)   place the information for each side of the relationship in the appropriate Ext directory for the module, which means specific $this->save...() methods for DeployedRelationships, and
         // 2)   we must also manually add the relationship into the custom/application/Ext/TableDictionary/tabledictionary.ext.php file as install_relationship doesn't handle that (install_relationships which requires the manifest however does)
         //      Relationships must be in tabledictionary.ext.php for the Admin command Rebuild Relationships to reliably work:
         //      Rebuild Relationships looks for relationships in the modules vardefs.php, in custom/modules/<modulename>/Ext/vardefs/vardefs.ext.php, and in modules/TableDictionary.php and custom/application/Ext/TableDictionary/tabledictionary.ext.php
         //      if the relationship is not defined in one of those four places it could be deleted during a rebuilt, or during a module installation (when RebuildRelationships.php deletes all entries in the Relationships table)
         // So instead of doing this, we use common save...() methods between DeployedRelationships and UndeployedRelationships that will produce installDefs,
         // and rather than building a full manifest file to carry them, we manually add these installDefs to the ModuleInstaller, and then
         // individually call the appropriate ModuleInstaller->install_...() methods to take our relationship out of our staging area and expand it out to the individual module Ext areas
         $GLOBALS['mod_strings'] = $adminModStrings;
         require_once 'ModuleInstall/ModuleInstaller.php';
         $mi = new ModuleInstaller();
         $mi->id_name = 'custom' . $name;
         // provide the moduleinstaller with a unique name for this relationship - normally this value is set to the package key...
         $mi->installdefs = $installDefs;
         $mi->base_dir = $basepath;
         $mi->silent = true;
         VardefManager::clearVardef();
         $mi->install_relationships();
         $mi->install_languages();
         $mi->install_vardefs();
         $mi->install_layoutdefs();
         $mi->install_extensions();
         $mi->install_client_files();
     }
     $GLOBALS['mod_strings'] = $MBModStrings;
     // finally, restore the ModuleBuilder mod_strings
     // Anything that runs in-process needs to reload their vardefs
     $GLOBALS['reload_vardefs'] = true;
     // save out the updated definitions so that we keep track of the change in built status
     // sending false so we don't rebuild relationshsips for a third time.
     $this->save(false);
     $mi = new ModuleInstaller();
     $mi->silent = true;
     $mi->rebuild_relationships($modulesToBuild);
     // now clear all caches so that our changes are visible
     require_once 'modules/Administration/QuickRepairAndRebuild.php';
     $rac = new RepairAndClear();
     $rac->module_list = $modulesToBuild;
     $rac->clearJsFiles();
     $rac->clearVardefs();
     $rac->clearJsLangFiles();
     $rac->clearLanguageCache();
     $rac->rebuildExtensions(array_keys($modulesToBuild));
     $rac->clearVardefs();
     foreach ($rac->module_list as $moduleName => $ignore) {
         // Now rebuild the vardefs in memory
         $bean = BeanFactory::newBean($moduleName);
         VardefManager::loadVardef($bean->module_dir, $bean->object_name, true, array('bean' => $bean));
     }
     foreach (array_keys($modulesToBuild) as $module) {
         unset($GLOBALS['dictionary'][BeanFactory::getObjectName($module)]);
     }
     SugarRelationshipFactory::rebuildCache();
     MetaDataManager::refreshLanguagesCache(array($GLOBALS['current_language']));
     MetaDataManager::refreshSectionCache(array(MetaDataManager::MM_RELATIONSHIPS));
     MetaDataManager::refreshModulesCache(array_keys($modulesToBuild));
     $GLOBALS['log']->info(get_class($this) . "->build(): finished relationship installation");
 }