[原]iTop自定義修改相關時間字段的實現要點記錄

[gzg@operation itop]$ cd /var/www/html/itop [gzg@operation itop]$ mkdir yh [gzg@operation itop]$ cd yh [gzg@operation itop]$ touch upticketdates.php

開發簡要說明:

字典文件位置: itop/env-production/dictionaries/zh-cn.dict.php 'Class:UserRequest/Attribute:resolutiondate' => '解決時間', 'Class:UserRequest/Attribute:resolutiondate+' => '',

 

iTop的底層數據支撐框架爲CMDB

一個數據模型類的繼承層次爲(如:UserRequest):

UserRequest < Ticket < _Ticket < cmdbAbstractObject < CMDBObject < DBObject

這些類的文件位置是:

  • UserRequest => O:\itop\env-production\itop-request-mgmt-itil\model.itop-request-mgmt-itil.php
  • Ticket => O:\itop\env-production\itop-tickets\model.itop-tickets.php
  • _Ticket => O:\itop\env-toolkit\itop-tickets\main.itop-tickets.php
  • cmdbAbstractObject => O:\itop\application\cmdbabstract.class.inc.php
  • CMDBObject => O:\itop\core\cmdbobject.class.inc.php
  • DBObject => O:\itop\core\dbobject.class.php

DBObject安裝註釋中的說明: "Class dbObject: the root of persistent classes" 它是“可持久化”的“數據模型類”的“根類”,而DBObject中操作數據庫依靠的的更底層的CMDBSource(itop/core/cmdbsource.class.inc.php) CMDBSource中的數據操作則依靠“mysqli”

self::$m_oMysqli = new mysqli(self::$m_sDBHost, self::$m_sDBUser, self::$m_sDBPwd);

例如其 DBUpdate() 方法中的兩行代碼: $sSQL = $oFilter->MakeUpdateQuery($aChanges); CMDBSource::Query($sSQL);

引入三個文件後,可以使用 MetaModel, 裝載更新數據記錄

require_once('../approot.inc.php');
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/application/startup.inc.php');

類MetaModel定義位於: itop/core/metamodel.class.php

靜態方法MetaModel::GetObject可以裝載指定數據類 GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false, $aModifierProperties = null) 參數說明: $sClass:數據類名,例如表“itopticket”的類名爲“Ticket”,可以使用基類裝載子類,也可以用子類直接load $iKey:數據行的id $bMustBeFound:該id的數據行是否必須存在, 默認值爲false,未找到返回null,如果設置爲true,未找到拋出異常;MySQLException $bAllowAllData:是否load全部字段?? $aModifierProperties:可修改字段數組?? 使用舉例: $data = MetaModel::GetObject('Ticket',1296); getclass($data); // UserRequest, 這是一條request $data->get('resolutiondate'); // 獲取解決時間 $data->Set('resolutiondate','2019-12-19 12:33:34'); // 設置解決時間 $data->DBUpdate(); // 更新數據庫

最後更新時間的修改

Ticket的三個子類 UserRequest,Problem,Incident 都覆蓋了基類的OnUpdate方法,其中主要是做了更新追蹤記錄,設置最後更新時間 因此想要覆蓋更新這個字段,只能繞開 數據模型類,幸運的是這個字段是在 基類表 Ticket中,因此可以使用CMDBSource直接修改數據庫中的字段值, 從而實現最後更新時間的修改。

CMDBSource::query("update itop_ticket set last_update='$last_update' where id = $ticket_id"); 

 

整個過程實現源碼:


<?php 
require_once('../approot.inc.php');
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/application/startup.inc.php');

// "http://192.168.0.105/itop/pages/UI.php?c[menu]=UserRequest:OpenRequests"
$tbls = array('UserRequest'=>'itop_ticket_request','Incident'=>'itop_ticket_incident','Problem'=>'itop_ticket_problem');
$baseFlds = array('start_date','end_date','close_date');
$extFlds = array('assignment_date','resolution_date');
$ticket_id=$start_date=$end_date=$assignment_date=$close_date=$resolution_date=$last_update="";
$error_msg = $msg= '';
$btn='';
/** this function , just for example */
function __update(){
    $t=MetaModel::GetObject('Ticket',1296);
    $rd=$t->Get('resolution_date');
    $t->Set('resolution_date','2019-12-19 12:33:34');
    $t->DBUpdate();
    // direct access
    $ds = CMDBSource::query("update itop_ticket set start_date='2012-12-12 12:12:12' where id =1295"); 
    // print $ds;  // this will display:  1;
}
function pm($name){
    return $_POST[$name];
}
function has_pm($name){
    return array_key_exists($name,$_POST);
}
/** startup script */
if ($_SERVER["REQUEST_METHOD"] == "POST"){    
    try{
        $ticket_id=pm('ticket_id');
        //echo("<pre>ticket_id=[$ticket_id]</pre>");
        if(strlen($ticket_id)==0){            
            $error_msg='請輸入id!';
        }else{
            $data = MetaModel::GetObject('Ticket',$ticket_id, false);
            $dataClass = get_class($data); // ex: UserRequest
            //echo("data loaded=$data");    
            if(!$data){
                echo("<script>var oDateLoaded = false;</script>");
                $error_msg='數據未找到,該ID並不存在!';
                goto END;
            }
            
            if(has_pm('btn_load')){
                $btn = 'btn_load';            
                if($data){
                    $start_date = $data->get('start_date');
                    $end_date=$data->get('end_date');
                    $assignment_date=$data->get('assignment_date');
                    $close_date=$data->get('close_date');
                    $resolution_date=$data->get('resolution_date');
                    $last_update=$data->get('last_update');
                    echo("<script>var oDateLoaded = true;</script>");
                    $msg="已成功查詢到數據!";
                }else{
                    $error_msg = "Ticket id=[" + $ticket_id +"] 未找到!";
                }
            }else{ /** btn_save */            
                $btn = 'btn_save';
                $start_date = pm('start_date');
                $end_date=pm('end_date');
                $assignment_date=pm('assignment_date');
                $close_date=pm('close_date');
                $resolution_date=pm('resolution_date');
                $last_update=pm('last_update');
                if($start_date)$data->set('start_date',$start_date);
                if($end_date)$data->set('end_date',$end_date);
                if($assignment_date)$data->set('assignment_date',$assignment_date);
                if($close_date)$data->set('close_date',$close_date);
                if($resolution_date)$data->set('resolution_date',$resolution_date);
                if($last_update)$data->set('last_update',$last_update);
                //不起作用!!$data->onUpdate=function(){};
                $data->DBUpdate();
                //
                if($last_update){                    
                    CMDBSource::query("update itop_ticket set last_update='$last_update' where id = $ticket_id"); 
                }
                //
                echo("<script>var oDateLoaded = true;</script>");
                $msg = "ok, 保存成功了! 您可以繼續修改當前記錄。";
            }
        }
    }catch(Exception $ex){
         $error_msg = $ex->getMessage();
    }
}else{ /** GET */
    echo("<script>var oDateLoaded = false;</script>");    
} /** end of HTTP method */

END:
  echo ''

?>

<div class="form" id="pane_up_ticket_dates">
    <style scoped="scoped">
        .grid-x, .button-group{
            display: flex; margin:8px;
        }
        .button-group.align-center{
            justify-content: center;
        }
        .msg-info{
            color: lightblue;
            font-size: 1.2em;
        }
    </style>
    <form method="post" action="../yh/up_ticket_dates.php" name="form_up_ticket_dates" id='form_up_ticket_dates' ">
        <h2>[請首先輸入id並查詢]</h2>        
        
        <div class="grid-x">        
        <label>事件ID[形如:1298]:<input type="number" name="ticket_id" value="<?php echo $ticket_id; ?>"></label>
        <button name="btn_load">查詢</button>
        </div>
        <hr/><p class="msg-info">
        <?php if($msg){ ?>            
            <?php echo $msg ?>        
        <?php } ?>
        </p><hr/>
        <br/><br/>
        <div class="grid-x">
        <label>起始日期:<input type="datetime" name="start_date" value="<?php echo $start_date; ?>"></label>
        </div>
        <div class="grid-x">
        <label>結束日期:<input type="datetime" name="end_date" value="<?php echo $end_date; ?>"></label>
        </div>
        <div class="grid-x">
        <label>指派日期:<input type="datetime" name="assignment_date" value="<?php echo $assignment_date; ?>"></label>
        </div class="grid-x">
        <div class="grid-x">
        <label>關閉日期:<input type="datetime" name="close_date" value="<?php echo $close_date; ?>"></label>
        </div>
        <div class="grid-x">
        <label>解決日期:<input type="datetime" name="resolution_date" value="<?php echo $resolution_date; ?>"></label>
        </div>
        <div class="grid-x">
        <label>最後更新:<input type="datetime" name="last_update" value="<?php echo $last_update; ?>"></label>
        </div>
        <div  class="grid-x button-group align-center">
        <button name="btn_reset">清除</button><div style="width:5em;"></div> <button name="btn_save" >更新</button>
        </div>
    </form>
    <br/>
    
    <div id="error_pad" style="color:red;">
    <?php if($error_msg){ ?>
        <?php echo($error_msg); ?>
    <?php } ?>
    </div>
    
    <script>
        $(function(){
            var pane= $('#pane_up_ticket_dates'), frm= pane.find('form'),url=frm.attr('action'), ppad = $('.ui-layout-content');
            var errBox= pane.find('#error_pad'), msgBox = pane.find('.msg-info');
            if(!oDateLoaded){
                pane.find('button[name="btn_save"]').attr("disabled",true);
            }
            frm.find('button').on('click',function(){
                var btn=$(this), btnName=btn.attr('name');
                if(btnName=='btn_reset'){
                    oDateLoaded = false;
                    frm.find('input').val(''); errBox.html('');
                    return false;
                }
                if(btnName === 'btn_save' && !oDateLoaded){
                    var msg="請首先查詢,然後修改保存!";
                    errBox.html(msg);
                    alert(msg);
                    return false;
                }
                msgBox.html('請稍等......');
                var ps = frm.serialize() + "&" + btnName + "=";
                $.ajax({url: url,data: ps,type: 'post', dataType:'html'}).done(function(rep,textStatus,jqXHR){
                    ppad.html(rep);
                }).fail(function (jqXHR, textStatus, errorThrown) {
                    ppad.html(jqXHR.responseText);
                });
          //.always(hbusy);
                return false;
            });
        });
    </script>
</div>

 

二、插入到管理菜單組,實現功能界面動態裝載到iTop界面的右側工作區域。

1,實現MyWebPageMenuNode

想要添加自己定義的菜單,就要用到iTop的應用菜單類ApplicationMenu,這個類的實現位於itop/application/menunode.class.inc.php

首先找到WebPageMenuNode這個類,由於需要實現ajax動態裝載,我們不能直接使用這個類,複製一份本類的源碼,改名爲MyWebPageMenuNode,對其GetHyperlink方法稍作修改

class MyWebPageMenuNode extends MenuNode
{
    protected $sHyperlink;
    
    /**
     * Create a menu item that points to any web page (not only UI.php)
     * @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
     * @param string $sHyperlink URL to the page to load. Use relative URL if you want to keep the application portable !
     * @param integer $iParentIndex ID of the parent menu
     * @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
     * @param string $sEnableClass Name of class of object
     * @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
     * @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
     * @return MenuNode
     */
    public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
    {
        parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
        $this->sHyperlink = $sHyperlink;
        $this->aReflectionProperties['url'] = $sHyperlink;
    }

    public function GetHyperlink($aExtraParams)
    {
        $aExtraParams['c[menu]'] = $this->GetMenuId();
           //return $this->AddParams( $this->sHyperlink, $aExtraParams);
        $link=$this->AddParams( $this->sHyperlink, $aExtraParams);
       return "javascript:openMyPages('$link')";
    }
    
    public function RenderContent(WebPage $oPage, $aExtraParams = array())
    {
        assert(false); // Shall never be called, the external web page will handle the display by itself
    }
}

 

2,修改ApplicationMenu類,添加自定義方法

/**
     * ----------------------------------------------------------------------------------------------------------------------------
     * ----        定製菜單
     * ----------------------------------------------------------------------------------------------------------------------------
     */
    static public function AddMyMenu($oPage){
        //public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
        //AdminTools
        $link="../yh/up_ticket_dates.php";
        //$link= "../pages/UI.php?c[menu]=UpTicketDates:Modify";
        $mi = new MyWebPageMenuNode('UpTicketDates',$link,0);
        self::InsertMenu($mi,1,20);
        $oPage->add_ready_script('window.openMyPages=function(link){$(".ui-layout-content").load(link);};');
    }

在這個方法中,實現了兩個功能,創建一個新的菜單項, 然後在頁面中註冊了點擊菜單時需要用到的js函數(注意:js函數名稱和上面自定義類中的名稱呼應)。

3,修改DisplayMenu方法,調用上面的自定義方法:

static public function DisplayMenu($oPage, $aExtraParams)
    {
        self::LoadAdditionalMenus();        
        // Sort the root menu based on the rank
        usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
        // 添加自定義菜單
        self::AddMyMenu($oPage);
        //
        $iAccordion = 0;
        $iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
        foreach(self::$aRootMenus as $aMenu)
        {
            $oMenuNode = self::GetMenuNode($aMenu['index']);
            if (!$oMenuNode->IsEnabled()) continue; // Don't display a non-enabled menu
            $oPage->AddToMenu('<h3>'.$oMenuNode->GetTitle().'</h3>');
            $oPage->AddToMenu('<div>');
            $aChildren = self::GetChildren($aMenu['index']);
            if (count($aChildren) > 0)
            {
                $oPage->AddToMenu('<ul>');
                $bActive = self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
                $oPage->AddToMenu('</ul>');
                if ($bActive)
                {
                    //$oPage->add_ready_script("$('#accordion').accordion('activate', $iAccordion);");
                    // $oPage->add_ready_script("$('#accordion').accordion('option', {collapsible: true});"); // Make it auto-collapsible once it has been opened properly
                    $oPage->add_ready_script("$('#accordion').accordion('option', {collapsible: true, active: $iAccordion});"); // Make it auto-collapsible once it has been opened properly
                }
            }
            $oPage->AddToMenu('</div>');
            $iAccordion++;
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章