MOON
Server: Apache
System: Linux nserver.cafsindia.com 4.18.0-553.104.1.lve.el8.x86_64 #1 SMP Tue Feb 10 20:07:30 UTC 2026 x86_64
User: cafsindia (1002)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: /home/cafsindia/lead_cafsinfotech_in/public/legacy/include/SubPanel/SubPanelTiles.php
<?php
if (!defined('sugarEntry') || !sugarEntry) {
    die('Not A Valid Entry Point');
}
/**
 *
 * SugarCRM Community Edition is a customer relationship management program developed by
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
 *
 * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
 * Copyright (C) 2011 - 2018 SalesAgility Ltd.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by the
 * Free Software Foundation with the addition of the following permission added
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along with
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 *
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
 * reasonably feasible for technical reasons, the Appropriate Legal Notices must
 * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
 */

require_once('include/SubPanel/SubPanel.php');
require_once('include/SubPanel/SubPanelTilesTabs.php');
require_once('include/SubPanel/SubPanelDefinitions.php');

/**
 * Subpanel tiles
 * @api
 */
#[\AllowDynamicProperties]
class SubPanelTiles
{
    public $id;
    public $module;
    public $focus;
    public $start_on_field;
    public $layout_manager;
    public $layout_def_key;
    public $show_tabs = false;

    /**
     * @var \SuiteCRM\SubPanel\SubPanelRowCounter
     */
    protected $rowCounter;

    public $subpanel_definitions;

    public $hidden_tabs=array(); //consumer of this class can array of tabs that should be hidden. the tab name
    //should be the array.

    public function __construct(&$focus, $layout_def_key='', $layout_def_override = '')
    {
        $this->focus = $focus;
        $this->id = $focus->id;
        $this->module = $focus->module_dir;
        $this->layout_def_key = $layout_def_key;
        $this->subpanel_definitions=new SubPanelDefinitions($focus, $layout_def_key, $layout_def_override);
        $this->rowCounter = new \SuiteCRM\SubPanel\SubPanelRowCounter($focus);
    }

    /*
     * Return the current selected or requested subpanel tab
     * @return	string	The identifier for the selected subpanel tab (e.g., 'Other')
     */
    public function getSelectedGroup()
    {
        global $current_user;

        if (isset($_REQUEST['subpanelTabs'])) {
            $_SESSION['subpanelTabs'] = $_REQUEST['subpanelTabs'];
        }

        // include/tabConfig.php in turn includes the customized file at custom/include/tabConfig.php
        require 'include/tabConfig.php';

        $subpanelTabsPref = $current_user->getPreference('subpanel_tabs');
        if (!isset($subpanelTabsPref)) {
            $subpanelTabsPref = $GLOBALS['sugar_config']['default_subpanel_tabs'];
        }
        if (!empty($GLOBALS['tabStructure']) && (!empty($_SESSION['subpanelTabs']) || !empty($sugar_config['subpanelTabs']) || !empty($subpanelTabsPref))) {
            // Determine selected group
            if (!empty($_REQUEST['subpanel'])) {
                $selected_group = $_REQUEST['subpanel'];
            } elseif (!empty($_COOKIE[$this->module.'_sp_tab'])) {
                $selected_group = $_COOKIE[$this->module.'_sp_tab'];
            } elseif (!empty($_SESSION['parentTab']) && !empty($GLOBALS['tabStructure'][$_SESSION['parentTab']]) && in_array($this->module, $GLOBALS['tabStructure'][$_SESSION['parentTab']]['modules'])) {
                $selected_group = $_SESSION['parentTab'];
            } else {
                $selected_group = '';
                foreach ($GLOBALS['tabStructure'] as $mainTab => $group) {
                    if (in_array($this->module, $group['modules'])) {
                        $selected_group = $mainTab;
                        break;
                    }
                }
                if (!$selected_group) {
                    $selected_group = 'All';
                }
            }
        } else {
            $selected_group = '';
        }
        return $selected_group;
    }

    /*
     * Determine which subpanels should be shown within the selected tab group (e.g., 'Other');
     * @param boolean $showTabs		True if we should call the code to render each visible tab
     * @param string $selectedGroup	The requested tab group
     * @return array Visible tabs
     */
    public function getTabs($showTabs = true, $selectedGroup='')
    {
        global $current_user;

        //get all the "tabs" - this actually means all the subpanels available for display within a tab
        $tabs = $this->subpanel_definitions->get_available_tabs();

        if (!empty($selectedGroup)) {
            // Bug #44344 : Custom relationships under same module only show once in subpanel tabs
            // use object property instead new object to have ability run unit test (can override subpanel_definitions)
            $objSubPanelTilesTabs = new SubPanelTilesTabs($this->focus);
            $tabs = $objSubPanelTilesTabs->getTabs($tabs, $showTabs, $selectedGroup);
            unset($objSubPanelTilesTabs);
            return $tabs;
        } else {
            // see if user current user has custom subpanel layout
            $objSubPanelTilesTabs = new SubPanelTilesTabs($this->focus);
            $tabs = $objSubPanelTilesTabs->applyUserCustomLayoutToTabs($tabs);

            /* Check if the preference is set now,
             * because there's no point in executing this code if
             * we aren't going to render anything.
             */
            $subpanelLinksPref = $current_user->getPreference('subpanel_links');
            if (!isset($subpanelLinksPref)) {
                $subpanelLinksPref = $GLOBALS['sugar_config']['default_subpanel_links'];
            }

            if ($showTabs && $subpanelLinksPref) {
                require_once('include/SubPanel/SugarTab.php');
                $sugarTab = new SugarTab();

                $displayTabs = array();

                foreach ($tabs as $tab) {
                    $displayTabs []= array('key'=>$tab, 'label'=>translate($this->subpanel_definitions->layout_defs['subpanel_setup'][$tab]['title_key']));
                }
                $sugarTab->setup(array(), array(), $displayTabs);
                $sugarTab->display();
            }
        }
        return $tabs;
    }
    public function display($showContainer = true, $forceTabless = false)
    {
        global $layout_edit_mode, $sugar_version, $sugar_config, $current_user, $app_strings, $modListHeader;

        if (isset($layout_edit_mode) && $layout_edit_mode) {
            return;
        }

        $template = new Sugar_Smarty();
        $template_header = "";
        $template_body = "";
        $template_footer = "";

        $tabs = array();
        $tabs_properties = array();
        $tab_names = array();

        $module_sub_panels = [];

        $default_div_display = 'inline';
        if (!empty($sugar_config['hide_subpanels_on_login'])) {
            if (!isset($_SESSION['visited_details'][$this->focus->module_dir])) {
                SugarApplication::setCookie($this->focus->module_dir . '_divs', '', 0, null, null, isSSL(), true);
                unset($_COOKIE[$this->focus->module_dir . '_divs']);
                $_SESSION['visited_details'][$this->focus->module_dir] = true;
            }
            $default_div_display = 'none';
        }
        $div_cookies = get_sub_cookies($this->focus->module_dir . '_divs');


        if (empty($_REQUEST['subpanels'])) {
            $selected_group = $forceTabless?'':$this->getSelectedGroup();
            $usersLayout = $current_user->getPreference('subpanelLayout', $this->focus->module_dir);

            // we need to use some intelligence here when restoring the user's layout, as new modules with new subpanels might have been installed since the user's layout was recorded
            // this means that we can't just restore the old layout verbatim as the new subpanels would then go walkabout
            // so we need to do a merge while attempting as best we can to preserve the sense of the specified order
            // this is complicated by the different ordering schemes used in the two sources for the panels: the user's layout uses an ordinal layout, the panels from getTabs have an explicit ordering driven by the 'order' parameter
            // it's not clear how to best reconcile these two schemes; so we punt on it, and add all new panels to the end of the user's layout. At least this will give them a clue that something has changed...
            // we also now check for tabs that have been removed since the user saved their preferences.

            $tabs = $this->getTabs($showContainer, $selected_group) ;

            if (!empty($usersLayout)) {
                $availableTabs = $tabs ;
                $tabs = array_intersect($usersLayout, $availableTabs) ; // remove any tabs that have been removed since the user's layout was saved
                foreach (array_diff($availableTabs, $usersLayout) as $tab) {
                    $tabs [] = $tab;
                }
            }
        } else {
            $tabs = explode(',', $_REQUEST['subpanels']);
        }

        // Display the group header. this section is executed only if the tabbed interface is being used.
        $current_key = '';
        if (! empty($this->show_tabs)) {
            require_once('include/tabs.php');
            $tab_panel = new SugarWidgetTabs($tabs, $current_key, 'showSubPanel');
            $template_header .= get_form_header('Related', '', false);
            $template_header .= $tab_panel->display();
        }

        if (empty($GLOBALS['relationships'])) {
            if (!class_exists('Relationship')) {
                require('modules/Relationships/Relationship.php');
            }
            $rel= BeanFactory::newBean('Relationships');
            $rel->load_relationship_meta();
        }

        foreach ($tabs as $t => $tab) {
            // load meta definition of the sub-panel.
            $thisPanel = $this->subpanel_definitions->load_subpanel($tab);
            if ($thisPanel === false) {
                continue;
            }
            // this if-block will try to skip over ophaned subpanels. Studio/MB are being delete unloaded modules completely.
            // this check will ignore subpanels that are collections (activities, history, etc)
            if (!isset($thisPanel->_instance_properties['collection_list']) and isset($thisPanel->_instance_properties['get_subpanel_data'])) {
                // ignore when data source is a function

                if (!isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']])) {
                    if (stripos($thisPanel->_instance_properties['get_subpanel_data'], 'function:') === false) {
                        $GLOBALS['log']->fatal("Bad subpanel definition, it has incorrect value for get_subpanel_data property " .$tab);
                        continue;
                    }
                } else {
                    $rel_name='';
                    if (isset($this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'])) {
                        $rel_name=$this->focus->field_defs[$thisPanel->_instance_properties['get_subpanel_data']]['relationship'];
                    }

                    if (empty($rel_name) or !isset($GLOBALS['relationships'][$rel_name])) {
                        $GLOBALS['log']->fatal("Missing relationship definition " .$rel_name. ". skipping " .$tab ." subpanel");
                        continue;
                    }
                }
            }

            if ($thisPanel->isCollection()) {
                // collect names of sub-panels that may contain items of each module
                $collection_list = $thisPanel->get_inst_prop_value('collection_list');
                if (is_array($collection_list)) {
                    foreach ($collection_list as $data) {
                        if (!empty($data['module'])) {
                            $module_sub_panels[$data['module']][$tab] = true;
                        }
                    }
                }
            } else {
                $module = $thisPanel->get_module_name();
                if (!empty($module)) {
                    $module_sub_panels[$module][$tab] = true;
                }
            }

            $div_display = $default_div_display;

            if (isset($thisPanel->_instance_properties['collapsed'])
                && $thisPanel->_instance_properties['collapsed']) {
                $div_display = 'none';
            }

            if (!empty($sugar_config['hide_subpanels']) || $thisPanel->isDefaultHidden()) {
                $div_display = 'none';
            }

            $cookie_name = $this->module . '_' . $tab . '_v';
            if (isset($div_cookies[$cookie_name])) {
                $div_display = $div_cookies[$cookie_name] === 'false' ? 'none' : '';
            }

            if ($div_display == 'none') {
                $opp_display = 'inline';
                $tabs_properties[$t]['expanded_subpanels'] = false;
            } else {
                $opp_display = 'none';
                $tabs_properties[$t]['expanded_subpanels'] = true;
            }

            if (!empty($this->layout_def_key)) {
                $layout_def_key = $this->layout_def_key;
            } else {
                $layout_def_key = '';
            }

            if (empty($this->show_tabs)) {
                ///
                /// Legacy Support for subpanels
                $show_icon_html = SugarThemeRegistry::current()->getImage('advanced_search', 'border="0" align="absmiddle"', null, null, '.gif', translate('LBL_SHOW'));
                $hide_icon_html = SugarThemeRegistry::current()->getImage('basic_search', 'border="0" align="absmiddle"', null, null, '.gif', translate('LBL_HIDE'));

                $tabs_properties[$t]['show_icon_html'] = $show_icon_html;
                $tabs_properties[$t]['hide_icon_html'] = $hide_icon_html;

                $max_min = "<a name=\"$tab\"> </a><span id=\"show_link_".$tab."\" style=\"display: $opp_display\"><a href='#' class='utilsLink' onclick=\"current_child_field = '".$tab."';showSubPanel('".$tab."',null,true,'".$layout_def_key."');document.getElementById('show_link_".$tab."').style.display='none';document.getElementById('hide_link_".$tab."').style.display='';return false;\">"
                    . "" . $show_icon_html . "</a></span>";
                $max_min .= "<span id=\"hide_link_".$tab."\" style=\"display: $div_display\"><a href='#' class='utilsLink' onclick=\"hideSubPanel('".$tab."');document.getElementById('hide_link_".$tab."').style.display='none';document.getElementById('show_link_".$tab."').style.display='';return false;\">"
                    . "" . $hide_icon_html . "</a></span>";
                $tabs_properties[$t]['title'] = $thisPanel->get_title();
                $tabs_properties[$t]['module_name'] = $thisPanel->get_module_name();
                $tabs_properties[$t]['get_form_header']  = get_form_header($thisPanel->get_title(), $max_min, false, false);
            }

            $tabs_properties[$t]['cookie_name'] = $cookie_name;
            $tabs_properties[$t]['div_display'] = $div_display;
            $tabs_properties[$t]['opp_display'] = $opp_display;

            $tabs_properties[$t]['subpanel_body'] = '';
            $tabs_properties[$t]['buttons'] = '';

            // We only preload this subpanel's contents if it's expanded
            if ($tabs_properties[$t]['expanded_subpanels']) {
                // Get Subpanel
                include_once('include/SubPanel/SubPanel.php');
                $subpanel_object = new SubPanel($this->module, $_REQUEST['record'], $tab, $thisPanel, $layout_def_key);

                $arr = array();
                // TODO: Remove x-template:
                $tabs_properties[$t]['subpanel_body'] = $subpanel_object->ProcessSubPanelListView(
                    'include/SubPanel/tpls/SubPanelDynamic.tpl',
                    $arr
                );

                // Get subpanel buttons
                $tabs_properties[$t]['buttons'] = $this->get_buttons($thisPanel, $subpanel_object->subpanel_query);
            } elseif ($current_user->getPreference('count_collapsed_subpanels')) {
                $subPanelDef = $this->subpanel_definitions->layout_defs['subpanel_setup'][$tab];
                $count = (int)$this->rowCounter->getSubPanelRowCount($subPanelDef);

                $extraClass = '';
                if ($count === 0) {
                    $countStr = $count.'';
                } elseif ($count > 0) {
                    $countStr = $count.'';
                    $tabs_properties[$t]['collapsed_override'] = 1;
                } else {
                    $countStr = '...';
                    $extraClass = ' incomplete';
                }

                $tabs_properties[$t]['title'] .= ' (<span class="subPanelCountHint' . $extraClass . '" data-subpanel="' . $tab . '" data-module="' . $layout_def_key . '" data-record="' . $_REQUEST['record'] . '">' . $countStr . '</span>)';
            }


            array_push($tab_names, $tab);
        }

        $tab_names = '["' . implode('","', $tab_names) . '"]';

        if (!isset($module_sub_panels)) {
            $module_sub_panels = [];
        }
        $module_sub_panels = array_map('array_keys', $module_sub_panels);
        $module_sub_panels = json_encode($module_sub_panels);

        $template->assign('layout_def_key', $this->layout_def_key);
        $template->assign('show_subpanel_tabs', $this->show_tabs);
        $template->assign('subpanel_tabs', $tabs);
        $template->assign('subpanel_tabs_properties', $tabs_properties);
        $template->assign('module_sub_panels', $module_sub_panels);
        $template->assign('sugar_config', $sugar_config);
        $template->assign('REQUEST', $_REQUEST);
        $template->assign('GLOBALS', $GLOBALS);
        $template->assign('selected_group', $selected_group);
        $template->assign('tab_names', $tab_names);
        $template->assign('module_sub_panels', $module_sub_panels);
        $template->assign('module', $this->module);
        $template->assign('APP', $app_strings);

        $template_body = $template->fetch('include/SubPanel/tpls/SubPanelTiles.tpl');

        return $template_header . $template_body . $template_footer;
    }

    public function getLayoutManager()
    {
        require_once('include/generic/LayoutManager.php');
        if ($this->layout_manager == null) {
            $this->layout_manager = new LayoutManager();
        }
        return $this->layout_manager;
    }

    /**
     * @param aSubPanel $thisPanel
     * @param $panel_query
     * @return string
     */
    public function get_buttons($thisPanel, $panel_query=null)
    {
        $subpanel_def = $thisPanel->get_buttons();
        $layout_manager = $this->getLayoutManager();

        //for action button at the top of each subpanel
        // bug#51275: smarty widget to help provide the action menu functionality as it is currently sprinkled throughout the app with html
        $buttons = array();
        $widget_contents = '';
        foreach ($subpanel_def as $widget_data) {
            $widget_data['action'] = $_REQUEST['action'];
            $widget_data['module'] =  $thisPanel->get_inst_prop_value('module');
            $widget_data['focus'] = $this->focus;
            $widget_data['subpanel_definition'] = $thisPanel;
            $widget_contents .= '<td class="buttons">' . "\n";

            if (empty($widget_data['widget_class'])) {
                $buttons[] = "widget_class not defined for top subpanel buttons";
            } else {
                $button = $layout_manager->widgetDisplay($widget_data);
                if ($button) {
                    $buttons[] = $button;
                }
            }
        }
        require_once('include/Smarty/plugins/function.sugar_action_menu.php');
        $widget_contents = smarty_function_sugar_action_menu(
            [
                'buttons' => $buttons,
                'class' => 'clickMenu fancymenu',
                'flat' => $thisPanel->get_inst_prop_value('flat')
            ],
            $this->xTemplate
        );
        return $widget_contents;
    }

    /**
     * @param string $html_text
     * @param aSubPanel $thisPanel
     * @return string
     */
    public function getCheckbox($html_text, $thisPanel)
    {
        $template = new Sugar_Smarty();

        if ($thisPanel->get_inst_prop_value('select_link_top')) {
            $html_text .= $template->fetch('include/SubPanel/tpls/SubPanelCheckbox.tpl');
        }

        return $html_text;
    }
}