diff --git a/datamodels/2.x/itop-portal-base/portal/src/Helper/ApplicationHelper.php b/datamodels/2.x/itop-portal-base/portal/src/Helper/ApplicationHelper.php deleted file mode 100644 index 5b4625d65..000000000 --- a/datamodels/2.x/itop-portal-base/portal/src/Helper/ApplicationHelper.php +++ /dev/null @@ -1,1431 +0,0 @@ - - */ -class ApplicationHelper -{ - const FORM_ENUM_DISPLAY_MODE_COSY = 'cosy'; - const FORM_ENUM_DISPLAY_MODE_COMPACT = 'compact'; - const FORM_DEFAULT_DISPLAY_MODE = self::FORM_ENUM_DISPLAY_MODE_COSY; - const FORM_DEFAULT_ALWAYS_SHOW_SUBMIT = false; - - /** - * Loads classes from the base portal - * - * @deprecated Since 2.7.0 - * - * @param string $sScannedDir Directory to load the files from - * @param string $sFilePattern Pattern of files to load - * @param string $sType Type of files to load, used only in the Exception message, can be anything - * - * @throws \Exception - */ - public static function LoadClasses($sScannedDir, $sFilePattern, $sType) - { - @trigger_error( - sprintf( - 'Usage of legacy LoadClasses is deprecated. You should rely on autoloading (and therefore follow PSR4).', - __FILE__ - ), - E_USER_DEPRECATED - ); - - // Loading classes from base portal - foreach (scandir($sScannedDir) as $sFile) - { - if (strpos($sFile, $sFilePattern) !== false && file_exists($sFilepath = $sScannedDir.'/'.$sFile)) - { - try - { - require_once $sFilepath; - } - catch (Exception $e) - { - throw new Exception('Error while trying to load '.$sType.' '.$sFile); - } - } - } - } - - /** - * Loads controllers from the base portal - * - * @param string $sScannedDir Directory to load the controllers from - * - * @throws \Exception - */ -// public static function LoadControllers($sScannedDir = null) -// { -// if ($sScannedDir === null) -// { -// $sScannedDir = __DIR__.'/../controllers'; -// } -// -// // Loading controllers from base portal (those from modules have already been loaded by module.xxx.php files) -// self::LoadClasses($sScannedDir, 'controller.class.inc.php', 'controller'); -// } - - /** - * Loads routers from the base portal - * - * @param string $sScannedDir Directory to load the routers from - * - * @throws \Exception - */ -// public static function LoadRouters($sScannedDir = null) -// { -// if ($sScannedDir === null) -// { -// $sScannedDir = __DIR__.'/../routers'; -// } -// -// // Loading routers from base portal (those from modules have already been loaded by module.xxx.php files) -// self::LoadClasses($sScannedDir, 'router.class.inc.php', 'router'); -// } - - /** - * Loads bricks from the base portal - * - * @param string $sScannedDir Directory to load the bricks from - * - * @throws \Exception - */ -// public static function LoadBricks($sScannedDir = null) -// { -// if ($sScannedDir === null) -// { -// $sScannedDir = __DIR__.'/../Brick'; -// } -// -// // Loading bricks from base portal (those from modules have already been loaded by module.xxx.php files) -// self::LoadClasses($sScannedDir, 'brick.php', 'brick'); -// } - - /** - * Loads form managers from the base portal - * - * @param string $sScannedDir Directory to load the managers from - * - * @throws \Exception - */ -// public static function LoadFormManagers($sScannedDir = null) -// { -// if ($sScannedDir === null) -// { -// $sScannedDir = __DIR__.'/../forms'; -// } -// -// // Loading form managers from base portal (those from modules have already been loaded by module.xxx.php files) -// self::LoadClasses($sScannedDir, 'formmanager.class.inc.php', 'brick'); -// } - - /** - * Registers routes in the Silex Application from all declared Router classes - * - * @param \Silex\Application $oApp - * - * @throws \Exception - */ -// public static function RegisterRoutes(Application $oApp) -// { -// $aAllRoutes = array(); -// -// foreach (get_declared_classes() as $sPHPClass) -// { -// if (is_subclass_of($sPHPClass, 'Combodo\\iTop\\Portal\\Router\\AbstractRouter')) -// { -// try -// { -// // Registering to Silex Application -// $sPHPClass::RegisterAllRoutes($oApp); -// -// // Registering them together so we can access them from everywhere -// foreach ($sPHPClass::GetRoutes() as $aRoute) -// { -// $aAllRoutes[$aRoute['bind']] = $aRoute; -// } -// } -// catch (Exception $e) -// { -// throw new Exception('Error while trying to register routes'); -// } -// } -// } -// -// $oApp['combodo.portal.instance.routes'] = $aAllRoutes; -// } - - /** - * Returns all registered routes for the current portal instance - * - * @param \Silex\Application $oApp - * @param boolean $bNamesOnly If set to true, function will return only the routes' names, not the objects - * - * @return array - */ -// public static function GetRoutes(Application $oApp, $bNamesOnly = false) -// { -// return ($bNamesOnly) ? array_keys($oApp['combodo.portal.instance.routes']) : $oApp['combodo.portal.instance.routes']; -// } - - /** - * Registers an exception handler that will intercept controllers exceptions and display them in a nice template. - * Note : It is only active when $oApp['debug'] is false - * - * @param Application $oApp - */ - public static function RegisterExceptionHandler(Application $oApp) - { - // Intercepting fatal errors and exceptions - ErrorHandler::register(); - ExceptionHandler::register(($oApp['debug'] === true)); - - // Intercepting manually aborted request - if (1 || !$oApp['debug']) - { - $oApp->error(function (Exception $oException /*, Request $oRequest*/) use ($oApp) { - $iErrorCode = ($oException instanceof HttpException) ? $oException->getStatusCode() : 500; - - $aData = array( - 'exception' => $oException, - 'code' => $iErrorCode, - 'error_title' => '', - 'error_message' => $oException->getMessage() - ); - - switch ($iErrorCode) - { - case 404: - $aData['error_title'] = Dict::S('Error:HTTP:404'); - break; - default: - $aData['error_title'] = Dict::S('Error:HTTP:500'); - break; - } - - IssueLog::Error($aData['error_title'].' : '.$aData['error_message']); - - if ($oApp['request_stack']->getCurrentRequest()->isXmlHttpRequest()) - { - $oResponse = $oApp->json($aData, $iErrorCode); - } - else - { - // Preparing debug trace - $aSteps = array(); - foreach ($oException->getTrace() as $aStep) - { - // - Default file name - if (!isset($aStep['file'])) - { - $aStep['file'] = ''; - } - $aFileParts = explode('\\', $aStep['file']); - // - Default line number - if (!isset($aStep['line'])) - { - $aStep['line'] = 'unknown'; - } - // - Default class name - if (isset($aStep['class']) && isset($aStep['function']) && isset($aStep['type'])) - { - $aClassParts = explode('\\', $aStep['class']); - $sClassName = $aClassParts[count($aClassParts) - 1]; - $sClassFQ = $aStep['class']; - - $aArgsAsString = array(); - foreach ($aStep['args'] as $arg) - { - if (is_array($arg)) - { - $aArgsAsString[] = 'array(...)'; - } - elseif (is_object($arg)) - { - $aArgsAsString[] = 'object('.get_class($arg).')'; - } - else - { - $aArgsAsString[] = $arg; - } - } - - $sFunctionCall = $sClassName.$aStep['type'].$aStep['function'].'('.implode(', ', - $aArgsAsString).')'; - } - else - { - $sClassName = null; - $sClassFQ = null; - $sFunctionCall = null; - } - - $aSteps[] = array( - 'file_fq' => $aStep['file'], - 'file_name' => $aFileParts[count($aFileParts) - 1], - 'line' => $aStep['line'], - 'class_name' => $sClassName, - 'class_fq' => $sClassFQ, - 'function_call' => $sFunctionCall, - ); - } - - $aData['debug_trace_steps'] = $aSteps; - - $oResponse = $oApp['twig']->render('itop-portal-base/portal/templates/errors/layout.html.twig', - $aData); - } - - return $oResponse; - }); - } - } - - /** - * Loads the portal instance configuration from its module design into the Silex application - * - * @param \Silex\Application $oApp - * - * @throws Exception - */ -// public static function LoadPortalConfiguration(Application $oApp) -// { -// try -// { -// // Loading file -// if (!defined('PORTAL_ID')) -// { -// throw new Exception('Cannot load module design, Portal ID is not defined'); -// } -// $oDesign = new ModuleDesign(PORTAL_ID); -// -// // Parsing file -// // - Default values -// $aPortalConf = array( -// 'properties' => array( -// 'id' => PORTAL_ID, -// 'name' => 'Page:DefaultTitle', -// 'logo' => (file_exists(MODULESROOT.'branding/portal-logo.png')) ? utils::GetAbsoluteUrlModulesRoot().'branding/portal-logo.png' : '../images/logo-itop-dark-bg.svg', -// 'themes' => array( -// 'bootstrap' => 'itop-portal-base/portal/web/css/bootstrap-theme-combodo.scss', -// 'portal' => 'itop-portal-base/portal/web/css/portal.scss', -// 'others' => array(), -// ), -// 'templates' => array( -// 'layout' => 'itop-portal-base/portal/templates/layout.html.twig', -// 'home' => 'itop-portal-base/portal/templates/home/layout.html.twig' -// ), -// 'urlmaker_class' => null, -// 'triggers_query' => null, -// 'attachments' => array( -// 'allow_delete' => true -// ), -// 'allowed_portals' => array( -// 'opening_mode' => null, -// ), -// ), -// 'portals' => array(), -// 'forms' => array(), -// 'ui_extensions' => array( -// 'css_files' => array(), -// 'css_inline' => null, -// 'js_files' => array(), -// 'js_inline' => null, -// 'html' => array(), -// ), -// 'bricks' => array(), -// 'bricks_total_width' => 0, -// ); -// // - Global portal properties -// foreach ($oDesign->GetNodes('/module_design/properties/*') as $oPropertyNode) -// { -// switch ($oPropertyNode->nodeName) -// { -// case 'name': -// case 'urlmaker_class': -// case 'triggers_query': -// $aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText($aPortalConf['properties'][$oPropertyNode->nodeName]); -// break; -// case 'logo': -// $aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText($aPortalConf['properties'][$oPropertyNode->nodeName]); -// break; -// case 'themes': -// case 'templates': -// foreach ($oPropertyNode->GetNodes('template|theme') as $oSubNode) -// { -// if (!$oSubNode->hasAttribute('id') || $oSubNode->GetText(null) === null) -// { -// throw new DOMFormatException('Tag '.$oSubNode->nodeName.' must have a "id" attribute as well as a value', -// null, null, $oSubNode); -// } -// -// $sNodeId = $oSubNode->getAttribute('id'); -// switch ($oSubNode->nodeName) -// { -// case 'theme': -// switch ($sNodeId) -// { -// case 'bootstrap': -// case 'portal': -// case 'custom': -// $aPortalConf['properties']['themes'][$sNodeId] = $oSubNode->GetText(null); -// break; -// default: -// $aPortalConf['properties']['themes']['others'][] = $oSubNode->GetText(null); -// break; -// } -// break; -// case 'template': -// switch ($sNodeId) -// { -// case 'layout': -// case 'home': -// $aPortalConf['properties']['templates'][$sNodeId] = $oSubNode->GetText(null); -// break; -// default: -// throw new DOMFormatException('Value "'.$sNodeId.'" is not handled for template[@id]', -// null, null, $oSubNode); -// break; -// } -// break; -// } -// } -// break; -// case 'attachments': -// foreach ($oPropertyNode->GetNodes('*') as $oSubNode) -// { -// switch ($oSubNode->nodeName) -// { -// case 'allow_delete': -// $sValue = $oSubNode->GetText(); -// // If the text is null, we keep the default value -// // Else we set it -// if ($sValue !== null) -// { -// $aPortalConf['properties']['attachments'][$oSubNode->nodeName] = ($sValue === 'true') ? true : false; -// } -// break; -// } -// } -// break; -// case 'allowed_portals': -// foreach ($oPropertyNode->GetNodes('*') as $oSubNode) -// { -// switch ($oSubNode->nodeName) -// { -// case 'opening_mode': -// $sValue = $oSubNode->GetText(); -// // If the text is null, we keep the default value -// // Else we set it -// if ($sValue !== null) -// { -// $aPortalConf['properties']['allowed_portals'][$oSubNode->nodeName] = ($sValue === 'self') ? 'self' : 'tab'; -// } -// break; -// } -// } -// break; -// } -// } -// // - Rectifying portal logo url -// $sLogoUri = $aPortalConf['properties']['logo']; -// if (!preg_match('/^http/', $sLogoUri)) -// { -// // We prefix it with the server base url -// $sLogoUri = utils::GetAbsoluteUrlAppRoot().'env-'.utils::GetCurrentEnvironment().'/'.$sLogoUri; -// } -// $aPortalConf['properties']['logo'] = $sLogoUri; -// // - User allowed portals -// $aPortalConf['portals'] = UserRights::GetAllowedPortals(); -// // - Bricks -// $aPortalConf = static::LoadBricksConfiguration($oApp, $oDesign) + $aPortalConf; -// // - Forms -// $aPortalConf['forms'] = static::LoadFormsConfiguration($oApp, $oDesign); -// // - Scopes -// static::LoadScopesConfiguration($oApp, $oDesign); -// // - Lifecycle -// static::LoadLifecycleConfiguration($oApp, $oDesign); -// // - Presentation lists -// $aPortalConf['lists'] = static::LoadListsConfiguration($oApp, $oDesign); -// // - UI extensions -// $aPortalConf['ui_extensions'] = static::LoadUIExtensions($oApp); -// // - Action rules -// static::LoadActionRulesConfiguration($oApp, $oDesign); -// // - Setting UrlMakerClass -// if ($aPortalConf['properties']['urlmaker_class'] !== null) -// { -// ApplicationContext::SetUrlMakerClass($aPortalConf['properties']['urlmaker_class']); -// } -// // - Generating CSS files -// $aImportPaths = array($oApp['combodo.portal.base.absolute_path'].'css/'); -// foreach ($aPortalConf['properties']['themes'] as $key => $value) -// { -// if (!is_array($value)) -// { -// $aPortalConf['properties']['themes'][$key] = $oApp['combodo.absolute_url'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$value, -// $aImportPaths); -// } -// else -// { -// $aValues = array(); -// foreach ($value as $sSubvalue) -// { -// $aValues[] = $oApp['combodo.absolute_url'].utils::GetCSSFromSASS('env-'.utils::GetCurrentEnvironment().'/'.$sSubvalue, -// $aImportPaths); -// } -// $aPortalConf['properties']['themes'][$key] = $aValues; -// } -// } -// -// $oApp['combodo.portal.instance.conf'] = $aPortalConf; -// } -// catch (Exception $e) -// { -// throw new Exception('Error while parsing portal configuration file : '.$e->getMessage()); -// } -// } - - /** - * Loads the current user and stores it in the Silex application so we can use it wherever in the application - * - * @param \Silex\Application $oApp - * - * @throws \Exception - */ -// public static function LoadCurrentUser(Application $oApp) -// { -// // User -// $oUser = UserRights::GetUserObject(); -// if ($oUser === null) -// { -// throw new Exception('Could not load connected user.'); -// } -// -// $oApp['combodo.current_user'] = $oUser; -// -// // Contact -// $sContactPhotoUrl = $oApp['combodo.portal.base.absolute_url'].'img/user-profile-default-256px.png'; -// // - Checking if we can load the contact -// try -// { -// $oContact = UserRights::GetContactObject(); -// } -// catch (Exception $e) -// { -// $oAllowedOrgSet = $oUser->Get('allowed_org_list'); -// if ($oAllowedOrgSet->Count() > 0) -// { -// throw new Exception('Could not load contact related to connected user. (Tip: Make sure the contact\'s organization is among the user\'s allowed organizations)'); -// } -// else -// { -// throw new Exception('Could not load contact related to connected user.'); -// } -// } -// // - Retrieving picture -// if ($oContact) -// { -// if (MetaModel::IsValidAttCode(get_class($oContact), 'picture')) -// { -// $oImage = $oContact->Get('picture'); -// if (is_object($oImage) && !$oImage->IsEmpty()) -// { -// $sContactPhotoUrl = $oImage->GetDownloadURL(get_class($oContact), $oContact->GetKey(), 'picture'); -// } -// else -// { -// $sContactPhotoUrl = MetaModel::GetAttributeDef(get_class($oContact), -// 'picture')->Get('default_image'); -// } -// } -// } -// $oApp['combodo.current_contact.photo_url'] = $sContactPhotoUrl; -// } - - /** - * Loads the brick's security from the OQL queries to profiles arrays - * - * @param \Combodo\iTop\Portal\Brick\AbstractBrick $oBrick - * - * @throws \Exception - */ - public static function LoadBrickSecurity(AbstractBrick $oBrick) - { - try - { - // Allowed profiles - if ($oBrick->GetAllowedProfilesOql() !== null && $oBrick->GetAllowedProfilesOql() !== '') - { - $oSearch = DBObjectSearch::FromOQL($oBrick->GetAllowedProfilesOql()); - $oSet = new DBObjectSet($oSearch); - while ($oProfile = $oSet->Fetch()) - { - $oBrick->AddAllowedProfile($oProfile->Get('name')); - } - } - - // Denied profiles - if ($oBrick->GetDeniedProfilesOql() !== null && $oBrick->GetDeniedProfilesOql() !== '') - { - $oSearch = DBObjectSearch::FromOQL($oBrick->GetDeniedProfilesOql()); - $oSet = new DBObjectSet($oSearch); - while ($oProfile = $oSet->Fetch()) - { - $oBrick->AddDeniedProfile($oProfile->Get('name')); - } - } - } - catch (Exception $e) - { - throw new Exception('Error while loading security from '.$oBrick->GetId().' brick'); - } - } - - /** - * Finds an AbstractBrick loaded in the $oApp instance configuration from its ID. - * - * @param \Silex\Application $oApp - * @param string $sBrickId - * - * @return \Combodo\iTop\Portal\Brick\PortalBrick - * - * @throws \Exception - */ -// public static function GetLoadedBrickFromId(Application $oApp, $sBrickId) -// { -// foreach ($oApp['combodo.portal.instance.conf']['bricks'] as $oBrick) -// { -// if ($oBrick->GetId() === $sBrickId) -// { -// return $oBrick; -// } -// } -// -// throw new Exception('Brick with id = "'.$sBrickId.'" was not found among loaded bricks.'); -// } - - /** - * Return the form properties for the $sClassname in $sMode. - * - * If not found, tries to find one from the closest parent class. - * Else returns a default form based on zlist 'details' - * - * @param Application $oApp - * @param string $sClass Object class to find a form for - * @param string $sMode Form mode to find (view|edit|create) - * - * @return array - * - * @throws \CoreException - */ - public static function GetLoadedFormFromClass($aForms, $sClass, $sMode) - { - - // We try to find the form for that class - if (isset($aForms[$sClass]) && isset($aForms[$sClass][$sMode])) - { - $aForm = $aForms[$sClass][$sMode]; - } - // If not found, we try find one from the closest parent class - else - { - $bFound = false; - foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_EXCLUDELEAF, false) as $sParentClass) - { - if (isset($aForms[$sParentClass]) && isset($aForms[$sParentClass][$sMode])) - { - $aForm = $aForms[$sParentClass][$sMode]; - $bFound = true; - break; - } - } - - // If we have still not found one, we return a default form - if (!$bFound) - { - $aForm = static::GenerateDefaultFormForClass($sClass); - } - } - - return $aForm; - } - - /** - * Return the attribute list for the $sClassname in $sList. - * - * If not found, tries to find one from the closest parent class. - * Else returns a default attribute list based on zlist 'list' - * - * @param array $aLists - * @param string $sClass Object class to find a list for - * @param string $sList List name to find - * - * @return string[] Array of attribute codes - * - * @throws \CoreException - */ - public static function GetLoadedListFromClass($aLists, $sClass, $sList = 'default') - { - $aFoundList = null; - $aAttCodes = array(); - - // We try to find the list for that class - if (isset($aLists[$sClass]) && isset($aLists[$sClass][$sList])) - { - $aFoundList = $aLists[$sClass][$sList]; - } - // Else we try to found the default list for that class - elseif (isset($aLists[$sClass]) && isset($aLists[$sClass]['default'])) - { - $aFoundList = $aLists[$sClass]['default']; - } - // If not found, we try find one from the closest parent class - else - { - foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) - { - // Trying to find the right list - if (isset($aLists[$sParentClass]) && isset($aLists[$sParentClass][$sList])) - { - $aFoundList = $aLists[$sParentClass][$sList]; - break; - } - // Or the default list - elseif (isset($aLists[$sParentClass]) && isset($aLists[$sParentClass]['default'])) - { - $aFoundList = $aLists[$sParentClass]['default']; - break; - } - } - } - - // If found, we flatten the list to keep only the attribute codes (not the rank) - if ($aFoundList !== null) - { - foreach ($aFoundList as $aItem) - { - $aAttCodes[] = $aItem['att_code']; - } - } - else - { - $aAttCodes = MetaModel::FlattenZList(MetaModel::GetZListItems($sClass, 'list')); - } - - return $aAttCodes; - } - - /** - * Loads the bricks configuration from the module design XML and returns it as an hash array containing : - * - 'brick' => array of PortalBrick objects - * - 'bricks_total_width' => an integer used to create the home page grid - * - * @param \Silex\Application $oApp - * @param \ModuleDesign $oDesign - * - * @return array - * - * @throws \Exception - */ -// protected static function LoadBricksConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $aPortalConf = array( -// 'bricks' => array(), -// 'bricks_total_width' => 0, -// 'bricks_home_count' => 0, -// 'bricks_navigation_menu_count' => 0 -// ); -// -// foreach ($oDesign->GetNodes('/module_design/bricks/brick') as $oBrickNode) -// { -// $sBrickClass = $oBrickNode->getAttribute('xsi:type'); -// try -// { -// if (class_exists($sBrickClass)) -// { -// /** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */ -// $oBrick = new $sBrickClass(); -// $oBrick->LoadFromXml($oBrickNode); -// static::LoadBrickSecurity($oBrick); -// -// // Checking brick security -// if ($oBrick->GetActive() && $oBrick->IsGrantedForProfiles(UserRights::ListProfiles())) -// { -// $aPortalConf['bricks'][] = $oBrick; -// $aPortalConf['bricks_total_width'] += $oBrick->GetWidth(); -// if ($oBrick->GetVisibleHome()) -// { -// $aPortalConf['bricks_home_count']++; -// } -// if ($oBrick->GetVisibleNavigationMenu()) -// { -// $aPortalConf['bricks_navigation_menu_count']++; -// } -// } -// } -// else -// { -// throw new DOMFormatException('Unknown brick class "'.$sBrickClass.'" from xsi:type attribute', null, -// null, $oBrickNode); -// } -// } -// catch (DOMFormatException $e) -// { -// throw new Exception('Could not create brick ('.$sBrickClass.') from XML because of a DOM problem : '.$e->getMessage()); -// } -// catch (Exception $e) -// { -// throw new Exception('Could not create brick ('.$sBrickClass.') from XML : '.$oBrickNode->Dump().' '.$e->getMessage()); -// } -// } -// // - Sorting bricks by rank -// $aPortalConf['bricks_ordering'] = array(); -// // - Home -// $aPortalConf['bricks_ordering']['home'] = $aPortalConf['bricks']; -// usort($aPortalConf['bricks_ordering']['home'], function (PortalBrick $a, PortalBrick $b) { -// return $a->GetRankHome() > $b->GetRankHome(); -// }); -// // - Navigation menu -// $aPortalConf['bricks_ordering']['navigation_menu'] = $aPortalConf['bricks']; -// usort($aPortalConf['bricks_ordering']['navigation_menu'], function (PortalBrick $a, PortalBrick $b) { -// return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu(); -// }); -// -// return $aPortalConf; -// } - - /** - * Loads the forms configuration from the module design XML and returns it as an array containing : - * - => array( - * 'view'|'edit'|'create' => array( - * 'fields_type' => 'custom_list'|'twig'|'zlist', - * 'fields' => - * ), - * ... - * ), - * ... - * - * @param \Silex\Application $oApp - * @param \ModuleDesign $oDesign - * - * @return array - * - * @throws \Exception - */ -// protected static function LoadFormsConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $aForms = array(); -// -// foreach ($oDesign->GetNodes('/module_design/forms/form') as $oFormNode) -// { -// try -// { -// // Parsing form id -// if ($oFormNode->getAttribute('id') === '') -// { -// throw new DOMFormatException('form tag must have an id attribute', null, null, $oFormNode); -// } -// -// // Parsing form object class -// if ($oFormNode->GetUniqueElement('class')->GetText() !== null) -// { -// // Parsing class -// $sFormClass = $oFormNode->GetUniqueElement('class')->GetText(); -// -// // Parsing properties -// $aFormProperties = array( -// 'display_mode' => static::FORM_DEFAULT_DISPLAY_MODE, -// 'always_show_submit' => static::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT, -// ); -// if ($oFormNode->GetOptionalElement('properties') !== null) -// { -// foreach ($oFormNode->GetOptionalElement('properties')->childNodes as $oPropertyNode) -// { -// switch ($oPropertyNode->nodeName) -// { -// case 'display_mode': -// $aFormProperties['display_mode'] = $oPropertyNode->GetText(static::FORM_DEFAULT_DISPLAY_MODE); -// break; -// case 'always_show_submit': -// $aFormProperties['always_show_submit'] = ($oPropertyNode->GetText('false') === 'true') ? true : false; -// break; -// } -// } -// } -// -// // Parsing availables modes for that form (view, edit, create, apply_stimulus) -// $aFormStimuli = array(); -// if (($oFormNode->GetOptionalElement('modes') !== null) && ($oFormNode->GetOptionalElement('modes')->GetNodes('mode')->length > 0)) -// { -// $aModes = array(); -// foreach ($oFormNode->GetOptionalElement('modes')->GetNodes('mode') as $oModeNode) -// { -// if ($oModeNode->getAttribute('id') !== '') -// { -// $aModes[] = $oModeNode->getAttribute('id'); -// } -// else -// { -// throw new DOMFormatException('Mode tag must have an id attribute', null, null, -// $oFormNode); -// } -// -// // If apply_stimulus mode, checking if stimuli are defined -// if ($oModeNode->getAttribute('id') === 'apply_stimulus') -// { -// $oStimuliNode = $oModeNode->GetOptionalElement('stimuli'); -// // if stimuli are defined, we overwrite the form that could have been set by the generic form -// if ($oStimuliNode !== null) -// { -// foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode) -// { -// $sStimulusCode = $oStimulusNode->getAttribute('id'); -// -// // Removing default form is present (in case the default forms were parsed before the current one (from current or parent class)) -// if (isset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode])) -// { -// unset($aForms[$sFormClass]['apply_stimulus'][$sStimulusCode]); -// } -// -// $aFormStimuli[] = $oStimulusNode->getAttribute('id'); -// } -// } -// } -// } -// } -// else -// { -// // If no mode was specified, we set it all but stimuli as it would have no sense that every transition forms -// // have as many fields displayed as a regular edit form for example. -// $aModes = array('view', 'edit', 'create'); -// } -// -// // Parsing fields -// $aFields = array( -// 'id' => $oFormNode->getAttribute('id'), -// 'type' => null, -// 'properties' => $aFormProperties, -// 'fields' => null, -// 'layout' => null -// ); -// // ... either enumerated fields ... -// if ($oFormNode->GetOptionalElement('fields') !== null) -// { -// $aFields['type'] = 'custom_list'; -// $aFields['fields'] = array(); -// -// foreach ($oFormNode->GetOptionalElement('fields')->GetNodes('field') as $oFieldNode) -// { -// $sFieldId = $oFieldNode->getAttribute('id'); -// if ($sFieldId !== '') -// { -// $aField = array(); -// // Parsing field options like read_only, hidden and mandatory -// if ($oFieldNode->GetOptionalElement('read_only')) -// { -// $aField['readonly'] = ($oFieldNode->GetOptionalElement('read_only')->GetText('true') === 'true') ? true : false; -// } -// if ($oFieldNode->GetOptionalElement('mandatory')) -// { -// $aField['mandatory'] = ($oFieldNode->GetOptionalElement('mandatory')->GetText('true') === 'true') ? true : false; -// } -// if ($oFieldNode->GetOptionalElement('hidden')) -// { -// $aField['hidden'] = ($oFieldNode->GetOptionalElement('hidden')->GetText('true') === 'true') ? true : false; -// } -// -// $aFields['fields'][$sFieldId] = $aField; -// } -// else -// { -// throw new DOMFormatException('Field tag must have an id attribute', null, null, -// $oFormNode); -// } -// } -// } -// // ... or the default zlist -// else -// { -// $aFields['type'] = 'zlist'; -// $aFields['fields'] = 'details'; -// } -// -// // Parsing presentation -// if ($oFormNode->GetOptionalElement('twig') !== null) -// { -// // Extracting the twig template and removing the first and last lines (twig tags) -// $sXml = $oDesign->saveXML($oFormNode->GetOptionalElement('twig')); -// $sXml = preg_replace('/^.+\n/', '', $sXml); -// $sXml = preg_replace('/\n.+$/', '', $sXml); -// -// $aFields['layout'] = array( -// 'type' => (preg_match('/\{\{|\{\#|\{\%/', $sXml) === 1) ? 'twig' : 'xhtml', -// 'content' => $sXml -// ); -// } -// -// // Adding form for each class / mode -// foreach ($aModes as $sMode) -// { -// // Initializing current class if necessary -// if (!isset($aForms[$sFormClass])) -// { -// $aForms[$sFormClass] = array(); -// } -// -// if ($sMode === 'apply_stimulus') -// { -// // Iterating over current class and child classes to fill stimuli forms -// foreach (MetaModel::EnumChildClasses($sFormClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) -// { -// // Initializing child class if necessary -// if (!isset($aForms[$sChildClass][$sMode])) -// { -// $aForms[$sChildClass][$sMode] = array(); -// } -// -// // If stimuli are implicitly defined (empty tag), we define all those that have not already been by other forms. -// $aChildStimuli = $aFormStimuli; -// if (empty($aChildStimuli)) -// { -// // Stimuli already declared -// $aDeclaredStimuli = array(); -// if (array_key_exists($sChildClass, $aForms) && array_key_exists('apply_stimulus', -// $aForms[$sChildClass])) -// { -// $aDeclaredStimuli = array_keys($aForms[$sChildClass]['apply_stimulus']); -// } -// // All stimuli -// $aDatamodelStimuli = array_keys(MetaModel::EnumStimuli($sChildClass)); -// // Missing stimuli -// $aChildStimuli = array_diff($aDatamodelStimuli, $aDeclaredStimuli); -// } -// -// foreach ($aChildStimuli as $sFormStimulus) -// { -// // Setting form if not defined OR if it was defined by a parent (abstract) class -// if (!isset($aForms[$sChildClass][$sMode][$sFormStimulus]) || !empty($aFormStimuli)) -// { -// $aForms[$sChildClass][$sMode][$sFormStimulus] = $aFields; -// $aForms[$sChildClass][$sMode][$sFormStimulus]['id'] = 'apply_stimulus-'.$sChildClass.'-'.$sFormStimulus; -// } -// } -// } -// } -// elseif (!isset($aForms[$sFormClass][$sMode])) -// { -// $aForms[$sFormClass][$sMode] = $aFields; -// } -// else -// { -// throw new DOMFormatException('There is already a form for the class "'.$sFormClass.'" in "'.$sMode.'"', -// null, null, $oFormNode); -// } -// } -// } -// else -// { -// throw new DOMFormatException('Class tag must be defined', null, null, $oFormNode); -// } -// } -// catch (DOMFormatException $e) -// { -// throw new Exception('Could not create from [id="'.$oFormNode->getAttribute('id').'"] from XML because of a DOM problem : '.$e->getMessage()); -// } -// catch (Exception $e) -// { -// throw new Exception('Could not create from from XML : '.$oFormNode->Dump().' '.$e->getMessage()); -// } -// } -// -// return $aForms; -// } - - /** - * Loads the scopes configuration from the module design XML - * - * @param \Silex\Application $oApp - * @param ModuleDesign $oDesign - */ -// public static function LoadScopesConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $oApp['scope_validator']->Init($oDesign->GetNodes('/module_design/classes/class')); -// } - - /** - * Loads the lifecycle configuration from the module design XML - * - * @param \Silex\Application $oApp - * @param ModuleDesign $oDesign - */ -// protected static function LoadLifecycleConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $oApp['lifecycle_validator']->Init($oDesign->GetNodes('/module_design/classes/class')); -// } - - /** - * Loads the context helper from the module design XML - * - * @param \Silex\Application $oApp - * @param ModuleDesign $oDesign - */ -// protected static function LoadActionRulesConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $oApp['context_manipulator']->Init($oDesign->GetNodes('/module_design/action_rules/action_rule')); -// } - - /** - * Loads the classes lists from the module design XML. They are mainly used when searching an external key but - * could be used more extensively later - * - * @param \Silex\Application $oApp - * @param ModuleDesign $oDesign - * - * @return array - * @throws \DOMFormatException - */ -// protected static function LoadListsConfiguration(Application $oApp, ModuleDesign $oDesign) -// { -// $iDefaultItemRank = 0; -// $aClassesLists = array(); -// -// // Parsing XML file -// // - Each classes -// foreach ($oDesign->GetNodes('/module_design/classes/class') as $oClassNode) -// { -// $aClassLists = array(); -// $sClassId = $oClassNode->getAttribute('id'); -// if ($sClassId === null) -// { -// throw new DOMFormatException('Class tag must have an id attribute', null, null, $oClassNode); -// } -// -// // - Each lists -// foreach ($oClassNode->GetNodes('./lists/list') as $oListNode) -// { -// $aListItems = array(); -// $sListId = $oListNode->getAttribute('id'); -// if ($sListId === null) -// { -// throw new DOMFormatException('List tag of "'.$sClassId.'" class must have an id attribute', null, -// null, $oListNode); -// } -// -// // - Each items -// foreach ($oListNode->GetNodes('./items/item') as $oItemNode) -// { -// $sItemId = $oItemNode->getAttribute('id'); -// if ($sItemId === null) -// { -// throw new DOMFormatException('Item tag of "'.$sItemId.'" list must have an id attribute', null, -// null, $oItemNode); -// } -// -// $aItem = array( -// 'att_code' => $sItemId, -// 'rank' => $iDefaultItemRank -// ); -// -// $oRankNode = $oItemNode->GetOptionalElement('rank'); -// if ($oRankNode !== null) -// { -// $aItem['rank'] = $oRankNode->GetText($iDefaultItemRank); -// } -// -// $aListItems[] = $aItem; -// } -// // - Sorting list items by rank -// usort($aListItems, function ($a, $b) { -// return $a['rank'] > $b['rank']; -// }); -// $aClassLists[$sListId] = $aListItems; -// } -// -// // - Adding class only if it has at least one list -// if (!empty($aClassLists)) -// { -// $aClassesLists[$sClassId] = $aClassLists; -// } -// } -// -// return $aClassesLists; -// } - - /** - * Loads portal UI extensions - * - * @param \Silex\Application $oApp - * - * @return array - */ -// protected static function LoadUIExtensions(Application $oApp) -// { -// $aUIExtensions = array( -// 'css_files' => array(), -// 'css_inline' => null, -// 'js_files' => array(), -// 'js_inline' => null, -// 'html' => array(), -// ); -// $aUIExtensionHooks = array( -// iPortalUIExtension::ENUM_PORTAL_EXT_UI_BODY, -// iPortalUIExtension::ENUM_PORTAL_EXT_UI_NAVIGATION_MENU, -// iPortalUIExtension::ENUM_PORTAL_EXT_UI_MAIN_CONTENT, -// ); -// -// /** @var iPortalUIExtension $oExtensionInstance */ -// foreach (MetaModel::EnumPlugins('iPortalUIExtension') as $oExtensionInstance) -// { -// // Adding CSS files -// $aImportPaths = array($oApp['combodo.portal.base.absolute_path'].'css/'); -// foreach($oExtensionInstance->GetCSSFiles($oApp) as $sCSSFile) -// { -// // Removing app root url as we need to pass a path on the file system (relative to app root) -// $sCSSFilePath = str_replace(utils::GetAbsoluteUrlAppRoot(), '', $sCSSFile); -// // Compiling SCSS file -// $sCSSFileCompiled = $oApp['combodo.absolute_url'].utils::GetCSSFromSASS($sCSSFilePath, -// $aImportPaths); -// -// if(!in_array($sCSSFileCompiled, $aUIExtensions['css_files'])) -// { -// $aUIExtensions['css_files'][] = $sCSSFileCompiled; -// } -// } -// -// // Adding CSS inline -// $sCSSInline = $oExtensionInstance->GetCSSInline($oApp); -// if ($sCSSInline !== null) -// { -// $aUIExtensions['css_inline'] .= "\n\n".$sCSSInline; -// } -// -// // Adding JS files -// $aUIExtensions['js_files'] = array_merge($aUIExtensions['js_files'], -// $oExtensionInstance->GetJSFiles($oApp)); -// -// // Adding JS inline -// $sJSInline = $oExtensionInstance->GetJSInline($oApp); -// if ($sJSInline !== null) -// { -// // Note: Semi-colon is to prevent previous script that would have omitted it. -// $aUIExtensions['js_inline'] .= "\n\n;\n".$sJSInline; -// } -// -// // Adding HTML for each hook -// foreach ($aUIExtensionHooks as $sUIExtensionHook) -// { -// $sFunctionName = 'Get'.$sUIExtensionHook.'HTML'; -// $sHTML = $oExtensionInstance->$sFunctionName($oApp); -// if ($sHTML !== null) -// { -// if (!array_key_exists($sUIExtensionHook, $aUIExtensions['html'])) -// { -// $aUIExtensions['html'][$sUIExtensionHook] = ''; -// } -// $aUIExtensions['html'][$sUIExtensionHook] .= "\n\n".$sHTML; -// } -// } -// } -// -// return $aUIExtensions; -// } - -// public static function LoadSessionMessages(Application $oApp) -// { -// $aAllMessages = array(); -// if ((array_key_exists('obj_messages', $_SESSION)) && (!empty($_SESSION['obj_messages']))) -// { -// foreach ($_SESSION['obj_messages'] as $sMessageKey => $aMessageObjectData) -// { -// $aObjectMessages = array(); -// $aRanks = array(); -// foreach ($aMessageObjectData as $sMessageId => $aMessageData) -// { -// $sMsgClass = 'alert alert-'; -// switch ($aMessageData['severity']) -// { -// case 'info': -// $sMsgClass .= 'info'; -// break; -// case 'error': -// $sMsgClass .= 'danger'; -// break; -// case 'ok': -// default: -// $sMsgClass .= 'success'; -// break; -// } -// $aObjectMessages[] = array('cssClass' => $sMsgClass, 'message' => $aMessageData['message']); -// $aRanks[] = $aMessageData['rank']; -// } -// unset($_SESSION['obj_messages'][$sMessageKey]); -// array_multisort($aRanks, $aObjectMessages); -// foreach ($aObjectMessages as $aObjectMessage) -// { -// $aAllMessages[] = $aObjectMessage; -// } -// } -// } -// $oApp['combodo.current_user.session_messages'] = $aAllMessages; -// } - - /** - * Generate the form data for the $sClass. - * Form will look like the "Properties" tab of a $sClass object in the console. - * - * @param string $sClass - * @param bool $bAddLinksets - * - * @return array - */ - protected static function GenerateDefaultFormForClass($sClass, $bAddLinksets = false) - { - $aForm = array( - 'id' => strtolower($sClass)."-default-".uniqid(), - 'type' => 'custom_list', - 'properties' => array( - 'display_mode' => static::FORM_DEFAULT_DISPLAY_MODE, - 'always_show_submit' => static::FORM_DEFAULT_ALWAYS_SHOW_SUBMIT, - ), - 'fields' => array(), - 'layout' => array( - 'type' => 'xhtml', - 'content' => '', - ), - ); - - // Generate layout - $sContent = ""; - - // - Retrieve zlist details - $aDetailsList = MetaModel::GetZListItems($sClass, 'details'); - $aDetailsStruct = cmdbAbstractObject::ProcessZlist($aDetailsList, array(), 'UI:PropertiesTab', 'col1', ''); - $aPropertiesStruct = $aDetailsStruct['UI:PropertiesTab']; - - // Count cols (not linksets) - $iColCount = 0; - foreach($aPropertiesStruct as $sColId => $aColFieldsets) - { - if(substr($sColId, 0, 1) !== '_') - { - foreach($aColFieldsets as $sFieldsetName => $aAttCodes) - { - if(substr($sFieldsetName, 0, 1) !== '_') - { - $iColCount++; - break; - } - } - } - } - // If no cols, return a default form with all fields one after another - if($iColCount === 0) - { - return array( - 'id' => 'default', - 'type' => 'zlist', - 'fields' => 'details', - 'layout' => null - ); - } - // Warning, this might not be great when 12 modulo $iColCount is greater than 0. - $sColCSSClass = 'col-sm-'.floor(12/$iColCount); - - $sLinksetsHTML = ""; - $sRowHTML = "
\n"; - foreach($aPropertiesStruct as $sColId => $aColFieldsets) - { - $sColsHTML = "\t
\n"; - foreach($aColFieldsets as $sFieldsetName => $aAttCodes) - { - // Add fieldset, not linkset - if(substr($sFieldsetName, 0, 1) !== '_') - { - $sFieldsetHTML = "\t\t
\n"; - $sFieldsetHTML .= "\t\t\t".htmlentities(Dict::S($sFieldsetName), ENT_QUOTES, 'UTF-8')."\n"; - - foreach($aAttCodes as $sAttCode) - { - $sFieldsetHTML .= "\t\t\t
\n"; - } - - $sFieldsetHTML .= "\t\t
\n"; - - // Add to col - $sColsHTML .= $sFieldsetHTML; - } - elseif($bAddLinksets) - { - foreach($aAttCodes as $sAttCode) - { - $sLinksetsHTML .= "
\n"; - } - } - } - $sColsHTML .= "\t
\n"; - - // Add col to row - $sRowHTML .= $sColsHTML; - } - $sRowHTML .= "
\n"; - - // Add row to twig - $sContent .= $sRowHTML; - // Add linksets to twig - $sContent .= $sLinksetsHTML; - - $aForm['layout']['content'] = $sContent; - - return $aForm; - } - -}